@whycanservice 请问:目前我用两个线程,一个线程拍照,一个线程gpio 输出控制电机,但是电机转的断断续续(如果只有一个线程跑电机是正常的),看起来好像是调度问题,这种情况怎么解决?
chhjnavy 发布的帖子
-
回复: 如何控制IO输出高速脉冲,控制步进电机加减速?发布在 Linux
-
v851s type-c 转 lightning 接iphone 无法识别设备的问题???发布在 V Series
type-c 转 lightning 接iphone
执行:cat /sys/devices/platform/soc/usbc0/usb_host将 usb 转换成host 模式后,=
lsusb 可以查看到设备号,但是usbmuxd 无法通信,libimobiledevice 也配置了。
执行:
idevicepair pair始终显示:no device 或者offline device
有没有人用过libimobiledevice 来和ios 系统通信????请问usb 还有什么需要配置,才能通信成功
-
回复: v851s 在 eyesee-mpp 中添加一个hello_world sample 的流程发布在 V Series
@cavert121 一般tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample 这个目录下都会有bin 文件,如果没有的话,那就是在当前sample_hello_world 目录下
-
v851s 在 eyesee-mpp 中添加一个hello_world sample 的流程发布在 V Series
1. 为什么要在eyesee-mpp 中添加sample?
1)保持整个openwrt 应用程序编写的完成性;
2)eyesee-mpp 中包含了几乎所有全志视频音频模块的sample 以及 头文件,参考以及头文件调用起来非常方便,而且可以学习各种模块的使用流程;
3)可以直接在make menuconfig 中管理应用程序,是否编译;
4)不需要将交叉编译工具链放到外面,只要按照步骤添加好sample ,就可以直接mm -B 进行编译;2. 以hello_world为例创建sample
路径:tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample
在该路径下创建文件夹: sample_hello_world
在该文件夹下创建三个文件:
sample_hello_world.c#include <stdio.h> void main(void){ printf("hello world!\n"); }sample_hello_world.h
#ifndef __SAMPLE_HELLO_WORLD_H__ #define __SAMPLE_HELLO_WORLD_H__ #ifdef __cplusplus extern "C"{ #endif /* __cplusplus */ // #ifdef __cplusplus } #endif /* __cplusplus */ #endifreadme.txt
Author:navy Time: 2023-04-10 Version:10.0.0.1 sample_g2d 用来演示在 eyesee-mpp 中添加sample 的步骤注意养成良好的习惯:
1)sample 名称和别的sample 保持一直:拥有sample_前缀;
2).h 文件添加 #ifdef __cplusplus 可以兼容让c++ 调用;
3)sample含有 readme.txt ,便于介绍sample用途以及更新情况;3. 在路径:tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample/ 下的 tina.mk 中添加 sample_hello_world 的链接编译规则
ifeq ($(TARGET), sample_hello_world) SRCCS := sample_hello_world/sample_hello_world.c LOCAL_TARGET_BIN := sample_hello_world/sample_hello_world endif4. 在路径:tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/ 下的 tina.mk 中添加sample_hello_world make 规则
ifeq ($(MPPCFG_SAMPLE_HELLO_WORLD),Y) make -C sample -f tina.mk TARGET=sample_hello_world all endif5. 在路径:tina-v853-docker/openwrt/package/allwinner/eyesee-mpp/middleware 下的Makefile 和 config.in 中添加配置文件(添加后就可以在make menuconfig 中看到选项sample_hello_world )
config mpp_sample_hello_world bool "mpp sample hello_world" depends on mpp_sample help mpp sample hello_world.Makefile
ifeq ($(CONFIG_mpp_sample_hello_world),y) MPPCFG_SAMPLE_HELLO_WORLD := Y else MPPCFG_SAMPLE_HELLO_WORLD := N endif export MPPCFG_SAMPLE_HELLO_WORLD6. 编译
1)主目录下:make menuconfigAllwinner > eyesee-mpp > select mpp sample
按空格选中【*】 mpp sample hello_world

2)两种编译方式:
1)) 直接在主目录下make -j1 V=s (全部编译)
2))到配置目录:tina-v853-docker/openwrt/package/allwinner/eyesee-mpp/middleware 下直接mm -B (只编译eyesee-mpp 下的sample)3)将会在路径:tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample/bin/ 下产生sample_hello_world 可执行文件,将其adb push 到开发板./sample_hello_world 执行即可
-
v851s g2d 模块 sample 深究发布在 V Series
1. g2d 模块概述
g2d 主要功能:
1)旋转:支持90、180、270旋转;
2)镜像反转:H / V;
3) scale:放缩
4)格式转换:yuv 转 rgb 等,多种格式相互间转换;
5)透明叠加功能:实现两个rgb图片叠加;
6)矩形填充,等诸多功能;2. g2d 配置
1)源码目录:tina-v853-docker/kernel/linux-4.9/drivers/char/sunxi_g2d2)make kernel_menuconfig 配置
Device Drivers > Character devices > sunxi g2d driver
按空格键选中【*】

3)Device Tree 设备树配置
sun8iw21p1.dtsi路径:
tina-v853-docker/kernel/linux-4.9/arch/arm/boot/dts/sun8iw21p1.dtsig2d: g2d@05410000 { compatible = "allwinner,sunxi-g2d"; reg = <0x0 0x05410000 0x0 0xbffff>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk_g2d>; iommus = <&mmu_aw 3 1>; status = "okay"; };status 要设定为“okay” 状态。
4)重新编译内核
mkernel make -j1 V=s pack使用烧录工具PhoenixSuit 将路径:tina-v853-docker/out/v851s/lizard/openwrt/v851s_linux_lizard_uart0.img 下的img 镜像烧录到开发板。
adb shell 打开控制终端查看设备节点G2D:

5)通过G2D 设备节点,对g2d 进行操作
static int SampleG2d_G2dOpen(SAMPLE_G2D_CTX *p_g2d_ctx) { int ret = 0; p_g2d_ctx->mG2dFd = open("/dev/g2d", O_RDWR, 0); if (p_g2d_ctx->mG2dFd < 0) { aloge("fatal error! open /dev/g2d failed"); ret = -1; } return ret; }3. 详解 eyesee-mpp 中g2d sample 具体应用
1)eyesee-mpp 中 g2d sample 编译与执行请参考另一篇帖子
链接文本2)g2d sample 目录

3)运用 g2d 进行rotation,scale,格式转换
具体实现:将 nv21 格式的1920x1080图转换成rgb888 格式并放缩为640x360 大小。具体用到两个功能,格式转换和放缩。
步骤如下:
1))根据1920x1080 nv21 格式以及 640x360 rgb888 格式申请虚拟地址空间以及转换成物理地址(注意:g2d 转换是在物理地址中完成的)1920x1080 nv21 格式空间大小(输入文件):

Y 占 19201080 = 2073600 字节
UV 占 19201080 / 2 = 1036800 字节640x360 rgb888 格式空间大小(输出文件):
RGB 占 6403603 = 691200 字节另外:虚拟地址转换成物理地址使用如下函数:
g2d_getPhyAddrByVirAddr()申请虚拟空间并转换成物理空间完整函数如下:
在文件 tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample/sample_g2d/sample_g2d.c/sample_g2d.c 中static int PrepareFrmBuff(SAMPLE_G2D_CTX *p_g2d_ctx) { SampleG2dConfig *pConfig = NULL; unsigned int size = 0; pConfig = &p_g2d_ctx->mConfigPara; p_g2d_ctx->src_frm_info.frm_width = pConfig->mSrcWidth; p_g2d_ctx->src_frm_info.frm_height = pConfig->mSrcHeight; p_g2d_ctx->dst_frm_info.frm_width = pConfig->mDstWidth; p_g2d_ctx->dst_frm_info.frm_height = pConfig->mDstHeight; size = ALIGN(p_g2d_ctx->src_frm_info.frm_width, 16)*ALIGN(p_g2d_ctx->src_frm_info.frm_height, 16); if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 || pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420) { p_g2d_ctx->src_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size); if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[0]) { aloge("malloc_src_frm_y_mem_failed"); return -1; } p_g2d_ctx->src_frm_info.p_vir_addr[1] = (void *)g2d_allocMem(size/2); if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[1]) { g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]); aloge("malloc_src_frm_c_mem_failed"); return -1; } p_g2d_ctx->src_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[0]); p_g2d_ctx->src_frm_info.p_phy_addr[1] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[1]); } if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888) { size = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height * 3; p_g2d_ctx->dst_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size); if(NULL == p_g2d_ctx->dst_frm_info.p_vir_addr[0]) { if(p_g2d_ctx->src_frm_info.p_vir_addr[0] != NULL) { g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]); } if(p_g2d_ctx->src_frm_info.p_vir_addr[1] != NULL) { g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[1]); } aloge("malloc_dst_frm_y_mem_failed"); return -1; } p_g2d_ctx->dst_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->dst_frm_info.p_vir_addr[0]); } return 0; }2))通过fopen 传菜间两个文件句柄,fd_in fd_out 用来操作输入输出两个文件资源
p_g2d_ctx->fd_in = fopen(p_g2d_ctx->mConfigPara.SrcFile,"r"); if(NULL == p_g2d_ctx->fd_in) { aloge("open src file failed"); ret = -1; goto _err2; } fseek(p_g2d_ctx->fd_in, 0, SEEK_SET); p_g2d_ctx->fd_out = fopen(p_g2d_ctx->mConfigPara.DstFile, "wb"); if (NULL == p_g2d_ctx->fd_out) { aloge("open out file failed"); ret = -1; goto _err2; } fseek(p_g2d_ctx->fd_out, 0, SEEK_SET);3))读出 1920x1080 nv21 图资放入 虚拟空间
read_len = p_g2d_ctx->src_frm_info.frm_width * p_g2d_ctx->src_frm_info.frm_height; if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420|| pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420) { size1 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[0] , 1, read_len, p_g2d_ctx->fd_in); if(size1 != read_len) { aloge("read_y_data_frm_src_file_invalid"); } size2 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[1], 1, read_len /2, p_g2d_ctx->fd_in); if(size2 != read_len/2) { aloge("read_c_data_frm_src_file_invalid"); } fclose(p_g2d_ctx->fd_in); g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[0], read_len); g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[1], read_len/2); }4))打开g2d 初始化,并开始转换
ret = SampleG2d_G2dOpen(p_g2d_ctx); if (ret < 0) { aloge("fatal error! open /dev/g2d fail!"); goto _err2; } ret = SampleG2d_G2dConvert(p_g2d_ctx); if (ret < 0) { aloge("fatal error! g2d convert fail!"); goto _close_g2d; } //具体转化函数: static int SampleG2d_G2dConvert_scale(SAMPLE_G2D_CTX *p_g2d_ctx) { int ret = 0; g2d_blt_h blit; g2d_fmt_enh eSrcFormat, eDstFormat; SampleG2dConfig *pConfig = NULL; pConfig = &p_g2d_ctx->mConfigPara; ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mPicFormat, &eSrcFormat); if(ret!=SUCCESS) { aloge("fatal error! src pixel format[0x%x] is invalid!", pConfig->mPicFormat); return -1; } ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mDstPicFormat, &eDstFormat); if(ret!=SUCCESS) { aloge("fatal error! dst pixel format[0x%x] is invalid!", pConfig->mPicFormat); return -1; } //config blit memset(&blit, 0, sizeof(g2d_blt_h)); if(0 != pConfig->mDstRotate) { aloge("fatal_err: rotation can't be performed when do scaling"); } blit.flag_h = G2D_BLT_NONE_H; // angle rotation used // switch(pConfig->mDstRotate) // { // case 0: // blit.flag_h = G2D_BLT_NONE_H; //G2D_ROT_0, G2D_BLT_NONE_H // break; // case 90: // blit.flag_h = G2D_ROT_90; // break; // case 180: // blit.flag_h = G2D_ROT_180; // break; // case 270: // blit.flag_h = G2D_ROT_270; // break; // default: // aloge("fatal error! rotation[%d] is invalid!", pConfig->mDstRotate); // blit.flag_h = G2D_BLT_NONE_H; // break; // } //blit.src_image_h.bbuff = 1; //blit.src_image_h.color = 0xff; blit.src_image_h.format = eSrcFormat; blit.src_image_h.laddr[0] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[0]; blit.src_image_h.laddr[1] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[1]; blit.src_image_h.laddr[2] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[2]; //blit.src_image_h.haddr[] = blit.src_image_h.width = p_g2d_ctx->src_frm_info.frm_width; blit.src_image_h.height = p_g2d_ctx->src_frm_info.frm_height; blit.src_image_h.align[0] = 0; blit.src_image_h.align[1] = 0; blit.src_image_h.align[2] = 0; blit.src_image_h.clip_rect.x = pConfig->mSrcRectX; blit.src_image_h.clip_rect.y = pConfig->mSrcRectY; blit.src_image_h.clip_rect.w = pConfig->mSrcRectW; blit.src_image_h.clip_rect.h = pConfig->mSrcRectH; blit.src_image_h.gamut = G2D_BT601; blit.src_image_h.bpremul = 0; //blit.src_image_h.alpha = 0xff; blit.src_image_h.mode = G2D_PIXEL_ALPHA; //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA blit.src_image_h.fd = -1; blit.src_image_h.use_phy_addr = 1; //blit.dst_image_h.bbuff = 1; //blit.dst_image_h.color = 0xff; blit.dst_image_h.format = eDstFormat; blit.dst_image_h.laddr[0] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[0]; blit.dst_image_h.laddr[1] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[1]; blit.dst_image_h.laddr[2] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[2]; //blit.dst_image_h.haddr[] = blit.dst_image_h.width = p_g2d_ctx->dst_frm_info.frm_width; blit.dst_image_h.height = p_g2d_ctx->dst_frm_info.frm_height; blit.dst_image_h.align[0] = 0; blit.dst_image_h.align[1] = 0; blit.dst_image_h.align[2] = 0; blit.dst_image_h.clip_rect.x = pConfig->mDstRectX; blit.dst_image_h.clip_rect.y = pConfig->mDstRectY; blit.dst_image_h.clip_rect.w = pConfig->mDstRectW; blit.dst_image_h.clip_rect.h = pConfig->mDstRectH; blit.dst_image_h.gamut = G2D_BT601; blit.dst_image_h.bpremul = 0; //blit.dst_image_h.alpha = 0xff; blit.dst_image_h.mode = G2D_PIXEL_ALPHA; //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA blit.dst_image_h.fd = -1; blit.dst_image_h.use_phy_addr = 1; ret = ioctl(p_g2d_ctx->mG2dFd, G2D_CMD_BITBLT_H, (unsigned long)&blit); if(ret < 0) { aloge("fatal error! bit-block(image) transfer failed[%d]", ret); system("cd /sys/class/sunxi_dump;echo 0x14A8000,0x14A8100 > dump;cat dump"); } return ret; }5))转化完成后将640x360 rgb888 图资通过fd_out句柄存储起来
if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888) { out_len = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height *3; g2d_flushCache((void *)p_g2d_ctx->dst_frm_info.p_vir_addr[0], out_len); fwrite(p_g2d_ctx->dst_frm_info.p_vir_addr[0], 1, out_len, p_g2d_ctx->fd_out); }4. 总结转化步骤
通过步骤3中的模块化分析,可以看出g2d 转化大概分为一下步骤:
1)为打开 iomen 初始化;
2)为src以及dst图资申请虚拟地址空间并转换成物理地址空间;
3)将src图资放入虚拟地址空间,然后自动映射到物理地址空间;
4)打开g2d 设备节点进行转换(最重要的一环,可以通过手册分析具体怎么转换的);
5)将转换好的dst图资保存起来; -
v851s MPP 模块概述以及编译 sample 步骤发布在 V Series
1. MPP 模块概述
MPP 系统控制模块,根据芯片特性,完成硬件各个部件的复位、基本初始化工作,同时负责完成 MPP(Media Process Platform 媒体处理平台)系统各个业务模块的初始化、去初始化以及管MPP 系统各个业务模块的工作状态、提供当前 MPP 系统的版本信息等功能。
应用程序启动 MPP 业务前,必须完成 MPP 系统初始化工作。同理,应用程序退出 MPP 业务后,也要完成 MPP 系统去初始化工作,释放资源。
功能描述
(1)初始化 MPP 组件的运行环境,完成音频输入输出、视频输入输出等硬件设备的初始化配置。
(2)提供绑定组件的接口。
(3)提供媒体内存分配、释放、查询的接口。主要模块缩写:
VI :视频输入模块
VO:视频输出模块
VENC:视频编码模块
VDEC:视频解码模块
AI:音频输入
AO:音频输出
AENC:音频编码模块
ADEC:音频解码模块2. v851s MPP sample
MPP sample 源码目录:
tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sampleMPP sample 配置目录(kconfig、makefile):
tina-v853-docker/openwrt/package/allwinner/eyesee-mpp/middleware/3. 编译一个MPP 模块步骤(以 sample_g2d 为例)
1)make menuconfig 配置配置项,选中sample_g2d
路径:Allwinner > eyesee-mppp > select mpp sample > sample_g2d 空格选中变成 【*】

2)到配置目录下编译
MPP sample 配置目录(kconfig、makefile):
tina-v853-docker/openwrt/package/allwinner/eyesee-mpp/middleware/执行:
mm -B将会在源码目录(上面已给出)的bin 文件夹下产生可执行文件以及配置文件(如果bin 文件夹下没产生,请到源码sample 下查看)

3)将其adb push 到v851s开发板中
执行:./sample_vi_g2d -path sample_vi_g2d.confg2d 具体作用,请看源码code 中的 readme.txt 以及 g2d 手册
4. 其他sample 同理
注意:
1)执行某个sample 一定要先在make menuconfig 中选中
2)其他 sample 可能有依赖文件或者lib,通过错误提示,在make menuconfig 按“/” 搜索,然后选中即可
3)想知道每个sample 的具体含义,多看readme.txt 以及 官方手册 -
v851s gpio 应用程序编写发布在 V Series
1. 查看硬件电路图SCH_Schematic1_2022-11-23 ,查找合适的gpio 作为使用pin
在这里我们选取 GPIOH14(注意目前开发使用这个pin 作为触摸屏的pin脚,需要将触摸屏connect断开) ,因为 可以通过排插使用杜邦线将其引出,用于连接别的设备。
电路图pdf路径:Yuzukilizard/Hardware/Schematic/SCH_Schematic1_2022-11-23.pdf

2. 计算gpio IO 号
在 Linux 系统中,GPIO 通常由 Pinctrl 系统进行管理。Linux 定义了 Pinctrl 框架,统一了各大 SoC 厂商的 Pin 管理方式,避免了各大厂商自行实现自己的 Pin 管理系统,是一个非常有用的功能。
每个gpio 都对应一个IO 号:
PH14: 7 * 32 + 14 = 238
PH13: 7 * 32 + 13 = 237
PH12: 7 * 32 + 12 = 236
PH11: 7 * 32 + 11 = 2353. 通过sysfs操作gpio 导出gpio 节点
通过终端操作手动导出:
echo 238 > /sys/class/gpio/export查看导出的gpio节点
cd /sys/class/gpio可以看到gpio238
如果通过应用程序导出,code 如下:
#include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #define GPIOH14 238 #define XGPIO_HIGH 1 #define XGPIO_LOW 0 /**************************************************************** * Constants ****************************************************************/ #define SYSFS_GPIO_DIR "/sys/class/gpio" #define POLL_TIMEOUT (3 * 1000) /* 3 seconds */ #define MAX_BUF 64 /**************************************************************** * gpio_export ****************************************************************/ int gpio_export(unsigned int gpio) { int fd, len; char buf[MAX_BUF]; fd = open(SYSFS_GPIO_DIR"/export", O_WRONLY); printf("open device ==================fd = %d\n", fd); if (fd < 0) { printf("gpio/export\n"); return fd; } len = snprintf(buf, sizeof(buf), "%d", gpio); write(fd, buf, len); close(fd); return 0; }根据IO 号导出gpio 节点是很重要的一个环节,接下来就可以通过gpio 节点,对gpio 进行操作。
4 .接下来设置gpio 的输出状态,对其设置高低电平
完整code 如下:
#include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #include "gpioAPIs.h" /**************************************************************** * Constants ****************************************************************/ #define SYSFS_GPIO_DIR "/sys/class/gpio" #define POLL_TIMEOUT (3 * 1000) /* 3 seconds */ #define MAX_BUF 64 /**************************************************************** * gpio_export ****************************************************************/ int gpio_export(unsigned int gpio) { int fd, len; char buf[MAX_BUF]; fd = open(SYSFS_GPIO_DIR"/export", O_WRONLY); printf("open device ==================fd = %d\n", fd); if (fd < 0) { printf("gpio/export\n"); return fd; } len = snprintf(buf, sizeof(buf), "%d", gpio); write(fd, buf, len); close(fd); return 0; } /**************************************************************** * gpio_unexport ****************************************************************/ int gpio_unexport(unsigned int gpio) { int fd, len; char buf[MAX_BUF]; fd = open(SYSFS_GPIO_DIR"/unexport", O_WRONLY); if (fd < 0) { printf("gpio/export\n"); return fd; } len = snprintf(buf, sizeof(buf), "%d", gpio); write(fd, buf, len); close(fd); return 0; } /**************************************************************** * gpio_set_dir ****************************************************************/ int gpio_set_dir(unsigned int gpio, unsigned int out_flag) { int fd, len; char buf[MAX_BUF]; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/direction", gpio); fd = open(buf, O_WRONLY); if (fd < 0) { printf("gpio/direction\n"); return fd; } if (out_flag) write(fd, "out", 4); else write(fd, "in", 3); close(fd); return 0; } /**************************************************************** * gpio_set_value ****************************************************************/ int gpio_set_value(unsigned int gpio, unsigned int value) { int fd, len; char buf[MAX_BUF]; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", gpio); fd = open(buf, O_RDWR ); if (fd < 0) { printf("gpio/set-value\n"); return fd; } if (value) write(fd, "1", 2); else write(fd, "0", 2); close(fd); return 0; } /**************************************************************** * gpio_get_value ****************************************************************/ int gpio_get_value(unsigned int gpio, unsigned int *value) { int fd, len; char buf[MAX_BUF]; char ch; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", gpio); fd = open(buf, O_RDWR ); if (fd < 0) { printf("gpio/get-value\n"); return fd; } read(fd, &ch, 1); if (ch != '0') { *value = 1; } else { *value = 0; } close(fd); return 0; } /**************************************************************** * gpio_set_edge ****************************************************************/ int gpio_set_edge(unsigned int gpio, char *edge) { int fd, len; char buf[MAX_BUF]; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/edge", gpio); fd = open(buf, O_WRONLY); if (fd < 0) { printf("gpio/set-edge\n"); return fd; } write(fd, edge, strlen(edge) + 1); close(fd); return 0; } /**************************************************************** * gpio_fd_open ****************************************************************/ int gpio_fd_open(unsigned int gpio) { int fd, len; char buf[MAX_BUF]; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR"/gpio%d/value", gpio); fd = open(buf, O_RDONLY | O_NONBLOCK ); if (fd < 0) { printf("gpio/fd_open\n"); } return fd; } /**************************************************************** * gpio_fd_close ****************************************************************/ int gpio_fd_close(int fd) { return close(fd); } void gpio_init() { gpio_export(GPIOH14); gpio_set_dir(GPIOH14, 0); //gpio_set_edge(GPIOH14, "rising"); } void gpio_uninit() { gpio_unexport(GPIOH14); } void mian(void) { gpio_init(); //将gpio238 设定为高电平输出 gpio_set_value(GPIOH14, XGPIO_HIGH ); //将gpio238 设定为低电平输出 gpio_set_value(GPIOH14, XGPIO_LOW); } -
v851s uart3 设置成普通串口收发发布在 V Series
由于UART0 被设定为系统dubug 输出(简单来说就是将ttyS0 设定为console),所以使用UART3 作为普通的串口,进行与别的设备通信。
1. 查看硬件电路图SCH_Schematic1_2022-11-23,查看uart3 的TX RX pin 脚
电路图pdf路径:Yuzukilizard/Hardware/Schematic/SCH_Schematic1_2022-11-23.pdf
从图中可以看出TX = PE12 RX = PE13 。PE12 PE13 可以通过排插用杜邦线接出,排插电路图如下:

2. 由于pin脚复用原因,我们需要查看pin 脚复用情况
pin 脚复用手册V851SE_PINOUT_V0.1.xlsx路径:
Yuzukilizard/Hardware/Datasheets/V851SE_PINOUT_V0.1.xlsx

记住PE12 PE13 用作UART3-TX UART3-RX 是function7 ,这个很重要,一会我们在board.dts 文件中需要用到。
3. 配置设备树文件 board.dts
设备树文件通过of 文件解析出属性,进一步被应用(原理此处不再介绍)。board.dts 路径:tina-v853-docker/device/config/chips/v851s/configs/lizard/board.dts
在设备树中搜索UART 找到UART3 相关配置
&uart0 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&uart0_pins_active>; pinctrl-1 = <&uart0_pins_sleep>; status = "okay"; }; &uart1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&uart1_pins_active>; pinctrl-1 = <&uart1_pins_sleep>; status = "disabled"; }; &uart2 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&uart2_pins_active>; pinctrl-1 = <&uart2_pins_sleep>; status = "disabled"; }; &uart3 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&uart3_pins_active>; pinctrl-1 = <&uart3_pins_sleep>; status = "okay"; }; &pio { uart0_pins_active: uart0@0 { allwinner,pins = "PH9", "PH10"; allwinner,function = "uart0"; allwinner,muxsel = <5>; allwinner,drive = <1>; allwinner,pull = <1>; }; uart0_pins_sleep: uart0@1 { allwinner,pins = "PH9", "PH10"; allwinner,function = "gpio_in"; allwinner,muxsel = <0>; }; uart1_pins_active: uart1@0 { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,muxsel = <4>; allwinner,drive = <1>; allwinner,pull = <1>; }; uart1_pins_sleep: uart1@1 { allwinner,pins = "PG6", "PG7"; allwinner,function = "gpio_in"; allwinner,muxsel = <0>; }; uart2_pins_active: uart2@0 { allwinner,pins = "PA8", "PA9"; allwinner,function = "uart2"; allwinner,muxsel = <6>; allwinner,drive = <1>; allwinner,pull = <1>; }; uart2_pins_sleep: uart2@1 { allwinner,pins = "PA8", "PA9"; allwinner,function = "gpio_in"; allwinner,muxsel = <0>; }; uart3_pins_active: uart3@0 { allwinner,pins = "PE12", "PE13"; allwinner,function = "uart3"; allwinner,muxsel = <7>; allwinner,drive = <1>; allwinner,pull = <1>; }; uart3_pins_sleep: uart3@1 { allwinner,pins = "PE12", "PE13"; allwinner,function = "gpio_in"; allwinner,muxsel = <0>; };1)将uart3 设定为 status = "okay";
2)将uart3 pin 脚设为 allwinner,pins = "PE12", "PE13";
3)将uart3 pin复用为function7 :allwinner,muxsel = <7>;修改完成后,重新编译img
make -j1 V=s pack使用烧录软件:PhoenixSuit ,具体烧录方法参考:https://dongshanpi.com/YuzukiHD-Lizard/03-1_FlashSystem/#usb
烧录后,通过adb shell 进入终端,就可以查看到设备节点:/dev/ttyS3 ,通过open 设备终端,就可以进行read write 操作。
4. 通过设备节点 /dev/ttyS3 进行收发操作
1)写应用程序
#include <stdio.h> /*标准输入输出定义*/ #include <stdlib.h> /*标准函数库定义*/ #include <unistd.h> /*Unix标准函数定义*/ #include <sys/types.h> #include <sys/stat.h> /*六文件控制定义*/ #include <fcntl.h> /*PX终端控制定义*/ #include <termios.h> #include <errno.h> #include <string.h> enum parameter_type { PT_PROGRAM_NAME = 0, PT_DEV_NAME, PT_CYCLE, PT_NUM }; #define DBG(string, args...) \ do { \ printf("%s, %s()%u---",__FILE__,__FUNCTION__,__LINE__); \ printf(string, ##args); \ printf("\n"); \ } while (0) void usage(void) { printf("You should input as: \n"); printf("\t select_test [/dev/name] [Cyclee Cnt]\n"); } int OpenDev(char *name) { int fd = open(name, O_RDWR ); if (-1 == fd) DBG("Can not OPen(%s)!", name); return fd; } /* * @brief 设置串口通信速率 * @param fd 类型 int打开串口的文件句柄长 * @param speed 类型 int 串口速度 * @return void */ void set_speed(int fd, int speed) { int i; int status; struct termios Opt = {0}; int speed_arr[] = {B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {230400,115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) break; } tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arr[i]); cfsetospeed(&Opt, speed_arr[i]); Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/ Opt.c_oflag &= ~OPOST; /*Output*/ status = tcsetattr(fd, TCSANOW, &Opt); if (status != 0) { DBG("tcsetattr fd"); return; } tcflush(fd, TCIOFLUSH); } /** *@brief 设置串口数据位,停止位和效验位 *@param fd 类型 int 打开的串口文件句柄 *@param databits 类 型 int 数 据位 取值 为 7 或者8 *@param stopbits 类 型 int 停 止位 取值为 1 或者2 *@param parity 类型 int 效验类型 取值为N,E,O,,S */ int set_Parity(int fd,int databits,int stopbits,int parity) { struct termios options; if ( tcgetattr( fd,&options) != 0) { perror("SetupSerial 1"); return -1; } options.c_cflag &= ~CSIZE; switch (databits) /*设置数据位数*/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return -1; } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* */ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB;break; default: fprintf(stderr,"Unsupported parity\n"); return -1; } /* 设置停止位*/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return -1; } /* Set input parity option */ if (parity != 'n') options.c_iflag |= INPCK; tcflush(fd,TCIFLUSH); options.c_cc[VTIME] = 150; /* 15 seconds*/ options.c_cc[VMIN] = 0; /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3"); return -1; } return 0; } void str_print(char *buf, int len) { int i; for (i=0; i<len; i++) { if (i%10 == 0) printf("\n"); printf("0x%02x ", buf[i]); } printf("\n"); } int main(int argc, char **argv) { int i = 0; int fd = 0; int cnt = 0; char buf[256]; char buf_s[4]; int ret; fd_set rd_fdset; struct timeval dly_tm; // delay time in select() if (argc != PT_NUM) { usage(); return -1; } sscanf(argv[PT_CYCLE], "%d", &cnt); if (cnt == 0) cnt = 0xFFFF; fd = OpenDev(argv[PT_DEV_NAME]); if (fd < 0) return -1; set_speed(fd,19200); if (set_Parity(fd,8,1,'N') == -1) { printf("Set Parity Error\n"); exit (0); } printf("Select(%s), Cnt %d. \n", argv[PT_DEV_NAME], cnt); while (i<cnt) { FD_ZERO(&rd_fdset); FD_SET(fd, &rd_fdset); dly_tm.tv_sec = 5; dly_tm.tv_usec = 0; memset(buf, 0, 256); ret = select(fd+1, &rd_fdset, NULL, NULL, &dly_tm); DBG("select() return %d, fd = %d", ret, fd); if (ret == 0) continue; if (ret < 0) { printf("select(%s) return %d. [%d]: %s \n", argv[PT_DEV_NAME], ret, errno, strerror(errno)); continue; } i++; ret = read(fd, buf, 256); printf("Cnt%d: read(%s) return %d.\n", i, argv[PT_DEV_NAME], ret); str_print(buf, ret); buf_s[0] = 0x55; buf_s[1] = 0xAA; buf_s[2] = 0x55; buf_s[3] = 0xAA; write(fd, buf_s, 256); DBG("send over %d\n"); } close(fd); return 0; }2) 编写makefile
#CROSS_COMPILE = arm-linux- #CROSS_COMPILE = arm-linux-gnueabihf- CROSS_COMPILE=/home/xxx/v851s/Yuzukilizard/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi- # CPU = cortex-a7 # FPU = fpv4-sp-d16 AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump RANLIB = $(CROSS_COMPILE)ranlib SIZE = $(CROSS_COMPILE)size TOP_DIR = $(shell pwd) CFLAGS_inc_path += -I$(TOP_DIR) EXE = UARTTest # CFLAGS_inc_path += -I$(TOP_DIR)external/jpeg-9a # for H.264 hardware codec #CFLAGS_inc_path += -I$(TOP_DIR)/../../prebuilt/include/cedar # CFLAGS += -std=gnu99 -mthumb -mabi=aapcs-linux -mlittle-endian # CFLAGS += -fdata-sections -ffunction-sections # CFLAGS += -mcpu=$(CPU) -mtune=$(CPU) -mfpu=$(FPU) -mfloat-abi=hard SRC_HAL += ./ LIB_SRC := $(foreach spath, $(SRC_HAL), $(wildcard $(spath)*.c)) OBJECT += $(patsubst %.c,%.o,$(LIB_SRC)) LOCAL_INCLUDE += -I./ #CFLAGS += -O2 -ggdb3 -DNDEBUG CFLAGS += $(LOCAL_INCLUDE) -static # LDFLAGS = -L../../library/arm-linux-gnueabihf # LIBS += -lawh264 -lvdecoder -lcdc_base -lMemAdapter -lVE -lvencoder -lvideoengine all:$(EXE) $(EXE):$(OBJECT) @$(CC) $(OBJECT) -o $(EXE) $(CFLAGS) # @echo -- gcc $(SRCS) -- @echo "Compile target done." @echo "use src files" $(OBJECT): .PHONY:clean clean: @rm -rf *.o $(OBJECT) $(EXE) @echo "Clean done."需注意,将makefile 中的编译工具路径修改为自己的工具路径。
3) make 后,产生可执行文件,adb push 到开发板中进行执行,执行命令:
./UARTTest /dev/ttyS3 44)用杜邦线将PE12 PE13 GND 三根线接到电脑串口(需要串口转换小板子),波特率目前设定19200 ,使用串口工具,向板子随便发送数据,板子接受到数据,就会发送数据到电脑。
-
openwrt 添加 Demo for v853 board 编译 camera 测试软件,出现libunwind库冲突发布在 V Series

编译后安装路径:Z:\tina-v853-open\out\v853\vision\openwrt\build_dir\target\root-v853-vision\usr\lib
解决方法:由于v853_demo 已有自带的libunwind 库,和系统编译进去的有冲突,取消系统自带的库编译即可
make menuconfig----->Libraries
---------> libunwind
按空格切换,将* 取消即可 -
官方镜像烧录(V853开发板工厂测试固件20220630.img),串口UART0无法进入root?发布在 V Series

-
连接 type-c 到 windows ,设备管理器会弹出 android device(如果打开虚拟机ubuntu 可能会导致无法弹出)
-
windows+R 打开cmd 终端,输入adb shell 进入 v853 终端(没有adb 需要安装)
-
输入 ps 查看所有进程,找到camera 进程 sample_virvi2vo
-
kill 1167 杀死sample_virvi2vo进程
-
此时串口终端即可进入root
-
再吃执行 sample_virvi2vo /usr/sample_virvi2vo.conf lcd 重新显示画面
-