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 ,使用串口工具,向板子随便发送数据,板子接受到数据,就会发送数据到电脑。
-
@chhjnavy 感谢谢谢帖子,对于入门非常有用,万丈高楼平地起
-
请问,nanopi neo的板子,如何修改串口设置? 我在公司 提供的内核代码中没有找到board.dts文件,只有sun8i-h3-nanopi-neo.dtsi文件,但该文件内容非常少。
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号