我测试使用的是海思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
-
/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 种查看:
-
/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命令直接设置:
-
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。
下面串口程序来源于:https://blog.csdn.net/dosthing/article/details/82951207 ;在我的开发板上测试正常。
-
/************************************************************************************************
-
*****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;
-
}
<li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-thumbsup"></use> </svg><span class="name">点赞</span> <span class="count"></span> </a></li> <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-Collection-G"></use> </svg><span class="name">收藏</span></a></li> <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-fenxiang"></use> </svg>分享</a></li> <!--打赏开始--> <!--打赏结束--> <li class="tool-item tool-more"> <a> <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg> </a> <ul class="more-box"> <li class="item"><a class="article-report">文章举报</a></li> </ul> </li> </ul> </div> </div> <div class="person-messagebox"> <div class="left-message"><a href="https://blog.csdn.net/li_wen01"> <img src="https://profile.csdnimg.cn/3/0/D/3_li_wen01" class="avatar_pic" username="li_wen01"> <img src="https://g.csdnimg.cn/static/user-reg-year/2x/4.png" class="user-years"> </a></div> <div class="middle-message"> <div class="title"><span class="tit"><a href="https://blog.csdn.net/li_wen01" data-report-click="{"mod":"popu_379"}" target="_blank">li_wen01</a></span> <span class="flag expert"> <a href="https://blog.csdn.net/home/help.html#classicfication" target="_blank"> <svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-blogexpert"></use> </svg> 博客专家 </a> </span> </div> <div class="text"><span>发布了164 篇原创文章</span> · <span>获赞 243</span> · <span>访问量 65万+</span></div> </div> <div class="right-message"> <a href="https://bbs.csdn.net/topics/395527769" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板 </a> <a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a> </div> </div> </div>