@whycanservice 请问:目前我用两个线程,一个线程拍照,一个线程gpio 输出控制电机,但是电机转的断断续续(如果只有一个线程跑电机是正常的),看起来好像是调度问题,这种情况怎么解决?
chhjnavy 发布的帖子
-
回复: 如何控制IO输出高速脉冲,控制步进电机加减速?
-
v851s type-c 转 lightning 接iphone 无法识别设备的问题???
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 的流程
@cavert121 一般tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample 这个目录下都会有bin 文件,如果没有的话,那就是在当前sample_hello_world 目录下
-
v851s 在 eyesee-mpp 中添加一个hello_world sample 的流程
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 */ #endif
readme.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 endif
4. 在路径: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 endif
5. 在路径: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_WORLD
6. 编译
1)主目录下:make menuconfig
Allwinner > 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 深究
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 步骤
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.conf
g2d 具体作用,请看源码code 中的 readme.txt 以及 g2d 手册
4. 其他sample 同理
注意:
1)执行某个sample 一定要先在make menuconfig 中选中
2)其他 sample 可能有依赖文件或者lib,通过错误提示,在make menuconfig 按“/” 搜索,然后选中即可
3)想知道每个sample 的具体含义,多看readme.txt 以及 官方手册 -
v851s gpio 应用程序编写
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 设置成普通串口收发
由于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 4
4)用杜邦线将PE12 PE13 GND 三根线接到电脑串口(需要串口转换小板子),波特率目前设定19200 ,使用串口工具,向板子随便发送数据,板子接受到数据,就会发送数据到电脑。
-
openwrt 添加 Demo for v853 board 编译 camera 测试软件,出现libunwind库冲突
编译后安装路径: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?
-
连接 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 重新显示画面
-