2025年04月26日 09:24

高通uart调试总结

作者 admin, 2020年04月28日 16:12

« 上一篇 - 下一篇 »

admin

配置驱动选项
1.1 首先通过原理图确定其串口号,比如UART1、UART3_HS,同时查看该串口引脚是否有复用功能,比如用作SIM卡引脚。如果有复用,需要在设备树配置中取消复用功能的选项,然后选中串口功能,高通平台设备树路径为:kernel\msm-xxx\arch\arm\boot\dts\qcom或者kernel\msm-xxx\arch\arm64\boot\dts\qcom,这个路径视arm的位数而定。

1.2 编译运行内核,如果UART1驱动加载成功会在/dev目录下产生相应UART设备节点。以高通sdx20为例,系统启动之后在/dev下有两个ttyHSL设备节点:ttyHS0、ttyHSL0。输入命令(cat /proc/tty/driver/msm_serial_hs)可以显示设备节点详细信息,其中通过地址和datasheet对比即可知道UART对应的设备节点。同时通过who命令可查看当前终端tty信息。如果UART设备节点未产生,可在其相应驱动程序xx_probe函数中添加打印,查看xx_probe函数是否被调用,进一步查找原因。


软件回环测试

2.1 如果成功产生了UART设备节点,可通过软件回环测试确认UART驱动程序功能是否正常。比如ttyHS0,我们先将loopback.0值设置为1,打开该UART回环测试:
程序代码 [选择]
echo 1 > /sys/kernel/debug/msm_serial_hs/loopback.0
回环测试程序代码:
uart.c

程序代码 [选择]
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<termios.h>
#include<string.h>
 
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if( tcgetattr( fd,&oldtio)  !=  0) {
        perror("tcgetattr error");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
 
    switch( nBits )
    {
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |= CS8;
            break;
    }
 
    switch( nEvent )
    {
        case 'O':
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD; 
            newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E':
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'N':
            newtio.c_cflag &= ~PARENB;
            break;
    }
 
    switch( nSpeed )
    {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
            break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
            break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        case 460800:
            cfsetispeed(&newtio, B460800);
            cfsetospeed(&newtio, B460800);
            break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
    }
 
    if( nStop == 1){
        newtio.c_cflag &=  ~CSTOPB;
    }else if ( nStop == 2 ){
        newtio.c_cflag |=  CSTOPB;
    }
    newtio.c_cc[VTIME]  = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("set error");
        return -1;
    }
    return 0;
}
 
int main(int argc,char *argv[])
{
    int fd,ret_set,ret_read,ret;
    char buf_read[100];
    char tty[20]="/dev/";
    if(4 == argc)
    {
        strcat(tty,argv[1]);
        fd = open(tty, O_RDWR);
        if(fd == -1)
        {
            printf("Open %s failed! Exit!\n",tty);
            exit(1);
        }
        printf("open %s successfully!\n",tty);
 
        ret_set = set_opt(fd, atoi(argv[2]), 8, 'N', 1);
        if (ret_set == -1)
        {
            printf("Set %s failed! Exit!\n",tty);
            exit(1);
        }
        printf("Set %s successfully!\n",tty);
        printf("Baud rate: %s\n",argv[2]); 
        printf("Data: %s\n",argv[3]);      
        while (1)
        {
            memset(buf_read, 0, sizeof(buf_read));
            ret = write(fd, argv[3], 100);
            if( ret > 0){
                printf("Write data: %s\n",argv[3]);
            }else{
                printf("Write data failed! Exit!\n");
                exit(1);
            }
            ret_read = read(fd, buf_read, 100);
            if(ret_read > 0){
                printf("Read data: %s\n\n", buf_read);
            }
            sleep(3);
        }
            close(fd);
    }else{
        printf("Usage: uart [tty node] [baud rate] [data]\n");
        printf("       Sample: uart ttyHSL1 115200 test\n");
    }
 return 0;
}
Android.mk

程序代码 [选择]
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE := uarttest

LOCAL_SRC_FILES := $(call all-subdir-c-files)

include $(BUILD_EXECUTABLE)

编译得到执行文件uart adb push进去

运行uart进行回环测试:
执行如下命令
程序代码 [选择]
uart ttyHSL1 115200 test可以看到UART1成功收到了发送的 test字符

管脚信号测试
软件回环测试通过之后,查看uart gpio是否ok:tx高电平(uart空闲时tx传输二进制1)、rfr为低电平,rx,cts为输入。如果tx为低电平,那么gpio肯定没有配置好,再次检查gpio配置问题,还有确认硬件线路无误后最可能的原因是TX管脚被其他功能占用。如果以上2步都ok,那么UART应该ok了。再次检查将UART1的RX、TX管脚短接,关闭软件回环,使用uart程序进行自收发测试。关闭软件回环:
程序代码 [选择]
echo 0 > /sys/kernel/debug/msm_serial_hs/loopback.0
将rx和tx短接后,检查步骤如下,如果管脚信号测试通过,则串口功能基本调试成功。此方法的优点是无需上位机串口助手的配合,在串口模块到位之前提前完成接口调试工作。
程序代码 [选择]
adb shell
echo 1 > /sys/kernel/debug/msm_serial_hs/loopback.0 //打开回环开关
cat /sys/kernel/debug/msm_serial_hs/loopback.0  //确保已经打开回环开关了

adb shell
cat /dev/ttyHS0

adb shell
echo "This Is A Test" > /dev/ttyHS0 ->Transfer data