Loading...
海思HI35XX串口调试
简星 发布于 07/27 16:34 浏览 199

我测试使用的是海思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。

串口程序:

/************************************************************************************************
*****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;  
    //设置串口[数据帧](https://www.ebaina.com/resources/240000028176 "数据帧")格式  
    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;
}   

原文链接:https://blog.csdn.net/li_wen01/article/details/86529523

*本文仅代表作者观点,不代表易百纳技术社区立场。系作者授权易百纳技术社区发表,未经许可不得转载。

点赞1
收藏1
分享

精彩评论

内容存在敏感词
确定要删除此文章、专栏、评论吗?
确定
取消