ARM - 海思 - HI35XX串口调试
转自: https://blog.csdn.net/li_wen01/article/details/86529523
我测试使用的是海思HI3520DV400设备,它总共有三个串口,官方提供的SDK只使能了UART0,也就是调试串口。如果要使用UART1或是UART2,用户需要自己手动设置。
一)使能串口
最直接的方式就是将设备树中对应uart的status修改为 status = "okay"。
海思实际加载的串口驱动是PL011,menuconfig查看配置Device Drivers > Character devices > Serial drivers中的ARM AMBA PL011 serial port support 和 Support for console on AMBA serial port是否有选择上。
重新编译内核烧入,在/dev 下可以查看是否有串口设备ttyAMA0~2。
(二)查看串口配置
可以使用linux的stty命令查看串口的配置参数。比如:stty -F /dev/ttyAMA0 -a
1 2 3 4 5 6 7 8 9 10 11 12 13 | /dev # stty -F /dev/ttyAMA0 -a speed 115200 baud;stty: /dev/ttyAMA0 line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ^J; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt -echoctl echoke /dev # |
同样可以使用stty命令设置串口参数,比如:stty -F /dev/ttyAMA0 ispeed 115200 ospeed 115200 cs8
(三)查看串口数据收发
一般调试串口,我们可以将TX与RT接在一起,自己发数据给自己接收,看数据是否正常。也可以使用cat 查看串口数据或是echo发送数据。
发送数据:
echo "test 1234567890" > /dev/ttyAMA0
接收数据:
cat /dev/ttyAMA0
(四)查看串口硬件分配:
串口的硬件分配状态,比如IO和中断使用情况可以在/proc/tty/driver下的ttyAMA 种查看:
1 2 3 4 5 6 7 | /proc/tty/driver # ls ttyAMA usbserial /proc/tty/driver # cat ttyAMA serinfo:1.0 driver revision: 0: uart:PL011 rev2 mmio:0x12080000 irq:38 tx:119786 rx:254 RTS|DTR|DSR|CD|RI 1: uart:PL011 rev2 mmio:0x12090000 irq:39 tx:48102 rx:0 CTS|DSR|CD|RI 2: uart:PL011 rev2 mmio:0x120A0000 irq:40 tx:8620 rx:55014 CTS|DSR|CD|RI |
(五)注意
如果串口的配置和数据的收发命令都能够正常,但是串口的引脚没有电平变化,这个可能是串口的复用功能没有设置,需要设置一下GPIO复用为串口功能。复用功能可以在设备树dts中设置,也可以使用海思的himm命令直接设置:
1 2 | himm 0x120f0100 0x01 #UART2_RXD himm 0x120f0104 0x01 #UART2_TXD |
问题更新:
(1)海思uart1只能发送数据,不能正常接收数据问题
【问题背景】:设备树中正常启动uart1,配置uart1的TX, RX两个GPIO口复用为串口功能,能正常看到串口设备/dev/ttyAMA1;使用命令初始化串口1:stty -F /dev/ttyAMA1 ispeed 115200 ospeed 115200 cs8
【问题现象】:uart1只能发送数据,不能读取数据。
执行 echo "test 1234567890" > /dev/ttyAMA1 可以查看到串口1有成功发送数据出去。
周期向uart1发送数据,在海思端使用:cat /dev/ttyAMA1 查看串口数据接收情况,发发现接收不到数据。
于此同时,数据直接RT接收到数据之后,又通过RT把全部数据发送出去了。在应用层接收不到串口的数据。
我在海思3520DV300 和HI3520DV400上测试,都是只有uart1出现该问题,uart0和uart2正常。
但是如果海思端使用microcom(busybox自带命令工具) 工具来查看数据,又能正常的收到数据。查看命令为:microcom -s 115200 /dev/ttyCOM2
【问题原因】:串口没有正确的初始化。海思的uart1 如果只设置串口波特率和位数奇偶数等信息是不能正常运行。还需要设置串口的其它属性,也就是结构体struct termios里的参数 。这里需要使用程序来初始化。
【解决方案】:使用应用程序初始化uart1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | /************************************************************************************************ *****Describe: This program is writen to operate HI35xx serial devices. ***** *****Email: lishuangliang@outlook.com ***** *****Author: shuang liang li ***** *****Date: 2018-09-30 ***** *************************************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<termios.h> #include<errno.h> #include<string.h> #include <signal.h> //宏定义 #define HI_FALSE -1 #define HI_TRUE 0 #ifdef debugprintf #define debugpri(mesg, args...) fprintf(stderr, "[HI Serial print:%s:%d:] " mesg "\n", __FILE__, __LINE__, ##args) #else #define debugpri(mesg, args...) #endif int HiSerfd; void HI_Serial_Close( int fd); void Hi_sigsegv( int dummy) { if (HiSerfd > 0) HI_Serial_Close(HiSerfd); fprintf (stderr, "Hi Serial Caught SIGSEGV, Abort!\n" ); fclose (stderr); abort (); } void Hi_sigterm( int dummy) { if (HiSerfd > 0) HI_Serial_Close(HiSerfd); fprintf (stderr, "Hi Serial Caught SIGTERM, Abort!\n" ); fclose (stderr); exit (0); } void Hi_init_signals( void ) { struct sigaction sa; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGSEGV); sigaddset(&sa.sa_mask, SIGTERM); sigaddset(&sa.sa_mask, SIGPIPE); sa.sa_handler = Hi_sigsegv; sigaction(SIGSEGV, &sa, NULL); sa.sa_handler = Hi_sigterm; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); } int HI_Serial_Usage( void ) { printf ( "Usage:\n" ); printf ( "\tmyhicom [-d] <HiSerialDevice> [-s] get netdeviece info [-rw] read or wite select\n" ); printf ( "\tmyhicom [-h] for more usage\n" ); printf ( "\tmyhicom [-v] the verson of the sofware\n" ); printf ( "\tExample:\n\tmyhicom -d /dev/ttyAMA1 -s 115200 -w HiSerial:HelloWorld\n" ); } /* *Function: HI_Serial_Open(int fd,char* ComDevice) *Param: fd:file descirbe handle Serial Device: /dev/ttyAMA1 /dev/ttyAMA2 *Output: Ok or Fail */ int HI_Serial_Open( char * HiSerDevice) { int fd; fd = open(HiSerDevice, O_RDWR|O_NOCTTY|O_NDELAY); if (HI_FALSE == fd) { perror ( "HiSerial Can't Open Serial HiSerDevice" ); return (HI_FALSE); } //恢复串口为阻塞状态 if (fcntl(fd, F_SETFL, 0) < 0) { debugpri( "fcntl failed!\n" ); return (HI_FALSE); } else { debugpri( "fcntl=%d\n" ,fcntl(fd, F_SETFL,0)); } //测试是否为终端设备 if (0 == isatty(STDIN_FILENO)) { debugpri( "standard input is not a terminal device\n" ); return (HI_FALSE); } else { debugpri( "isatty success!\n" ); } printf ( "fd->open=%d\n" ,fd); return fd; } /* *Function: HI_Serial_Close(int fd) *Param: fd:file descirbe handle *Output: Null */ void HI_Serial_Close( int fd) { if (fd > 0) close(fd); return ; } /* *Function: HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity) *Param1: fd: file descirbe handle *Param2: speed: select the Serial speed.115200,19200,9600... *Param3: flow_ctrl: if use flow control *Param4: databits: data bit select *Param5: stopbits: stopbits select *Param5: parity: partiy select *Output: Ok or Fail */ int HI_Serial_Set( int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity) { int i; int status; int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300}; int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300}; struct termios options; if ( tcgetattr( fd,&options) != 0) { perror ( "SetupSerial 1" ); return (HI_FALSE); } //set buater rate for ( i= 0; i < sizeof (speed_arr) / sizeof ( int ); i++) { if (speed == name_arr[i]) { cfsetispeed(&options, speed_arr[i]); cfsetospeed(&options, speed_arr[i]); } } //set control model options.c_cflag |= CLOCAL; options.c_cflag |= CREAD; //set flow control switch (flow_ctrl) { case 0 : //none options.c_cflag &= ~CRTSCTS; break ; case 1 : //use hard ware options.c_cflag |= CRTSCTS; break ; case 2 : //use sofware options.c_cflag |= IXON | IXOFF | IXANY; break ; } //select data bit options.c_cflag &= ~CSIZE; switch (databits) { case 5 : options.c_cflag |= CS5; break ; case 6 : options.c_cflag |= CS6; break ; case 7 : options.c_cflag |= CS7; break ; case 8: options.c_cflag |= CS8; break ; default : fprintf (stderr, "Unsupported data size\n" ); return (HI_FALSE); } //select parity bit switch (parity) { case 'n' : case 'N' : options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break ; case 'o' : case 'O' : options.c_cflag |= (PARODD | PARENB); options.c_iflag |= INPCK; break ; case 'e' : case 'E' : options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break ; case 's' : case 'S' : options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break ; default : fprintf (stderr, "Unsupported parity\n" ); return (HI_FALSE); } // set stopbit switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break ; case 2: options.c_cflag |= CSTOPB; break ; default : fprintf (stderr, "Unsupported stop bits\n" ); return (HI_FALSE); } //set raw data output options.c_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //options.c_lflag &= ~(ISIG | ICANON); //set wait time options.c_cc[VTIME] = 1; options.c_cc[VMIN] = 1; tcflush(fd,TCIFLUSH); //set the attribute to HiSerial device if (tcsetattr(fd,TCSANOW,&options) != 0) { perror ( "com set error!\n" ); return (HI_FALSE); } return (HI_TRUE); } /* *Function: HI_Serial_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity) *Param: ... *Output: HI_TRUE or HI_FALSE */ int HI_Serial_Init( int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity) { int err; //设置串口数据帧格式 if (HI_Serial_Set(fd,speed,flow_ctrl,databits,stopbits,parity) == HI_FALSE) { return HI_FALSE; } else { return HI_TRUE; } } /* *Function: HI_Serial_Send(int fd, char *send_buf,int data_len) *Param1: fd:file descirbe handle *Param2: send_buf:Data to be send *Param2: data_len:Data len *Output: Data send len or HI_FALSE */ int HI_Serial_Send( int fd, char *send_buf, int data_len) { int len = 0; len = write(fd,send_buf,data_len); if (len == data_len ) { debugpri( "send data is %s\n" ,send_buf); return len; } else { tcflush(fd,TCOFLUSH); return HI_FALSE; } } /* *Function: HI_Serial_Recv(int fd, char *rcv_buf,int data_len) *Param1: fd:file descirbe handle *Param2: rcv_buf:receive Data *Param2: data_len:receive Data len *Output: Receive Data len or HI_FALSE */ int HI_Serial_Recv( int fd, char *rcv_buf, int data_len) { int len,fs_sel; fd_set fs_read; struct timeval time ; FD_ZERO(&fs_read); FD_SET(fd,&fs_read); time .tv_sec = 30; time .tv_usec = 0; //select fdset fs_sel = select(fd+1,&fs_read,NULL,NULL,& time ); if (fs_sel) { len = read(fd,rcv_buf,data_len); debugpri( "HiSeral Receive Data = %s len = %d fs_sel = %d\n" ,rcv_buf,len,fs_sel); return len; } else { debugpri( "Hiserial haven't data receive!" ); return HI_FALSE; } } int main ( int argc, char *argv[] ) { int cmd; int len; //extern char *optarg; //extern int optind, opterr, optopt; char HiSerialDev[32]= "/dev/ttyAMA1" ; char sendbuf[1024]={0}; char recvbuf[1024]={0}; int SerialSpeed = 115200; Hi_init_signals(); if (argc == 1) { HI_Serial_Usage(); exit (0); } else { while ((cmd = getopt(argc, argv, ":d:s:rw:hv" )) != -1) { switch (cmd) { case 'h' : HI_Serial_Usage(); break ; case 'v' : printf ( "myHicom --Verson V1.0.0\n" ); break ; case 'd' : //printf("catch -d %s \n",optarg); memset (HiSerialDev,0, sizeof (HiSerialDev)); sprintf (HiSerialDev, "%s" ,optarg); printf ( "myHicom HiSerialDev %s\n" ,optarg); break ; case 's' : SerialSpeed = atoi (optarg); printf ( "myHicom speed %d\n" ,SerialSpeed); break ; case 'r' : debugpri( "myHicom read\n" ); HiSerfd = HI_Serial_Open(HiSerialDev); HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1, 'N' ); while (1) { len = HI_Serial_Recv(HiSerfd, recvbuf, sizeof (recvbuf)); if (len > 0) { recvbuf[len] = '\0' ; printf ( "Hiserial receive data: %s\n" ,recvbuf); memset (recvbuf,0, sizeof (recvbuf)); //break; } else { debugpri( "Hiserial haven't data receive \n" ); } sleep(2); }; break ; case 'w' : debugpri( "myHicom write %s\n" ,optarg); HiSerfd = HI_Serial_Open(HiSerialDev); printf ( "fd = %d device = %s speed = %d\n" ,HiSerfd,HiSerialDev,SerialSpeed); HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1, 'N' ); sprintf (sendbuf, "%s\n" ,optarg); HI_Serial_Send(HiSerfd, sendbuf, strlen (sendbuf)+1); if (HiSerfd > 0) HI_Serial_Close(HiSerfd); break ; case ':' : printf ( "option: -%c missing argument. -h for help.\n" ,( char )optopt); break ; case '?' : printf ( "Unknown option: -%c\n" ,( char )optopt); break ; default : exit (0); } } } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!