串口问题排查-时序异常

问题背景

采用新塘处理器NUC972 使用该芯片所有的串口 UART1~UART10
测试发现串口数据读取异常
采用测试串口终端SSCOM

问题还原步骤

内核已经配置了所有的串口功能,串口PIN复用正常
串口问题排查-时序异常_第1张图片
设备启动可以识别10个串口
~ # ls /dev/ttyS*
/dev/ttyS0 /dev/ttyS10 /dev/ttyS3 /dev/ttyS5 /dev/ttyS7 /dev/ttyS9
/dev/ttyS1 /dev/ttyS2 /dev/ttyS4 /dev/ttyS6 /dev/ttyS8

针对/dev/ttyS9、/dev/ttyS10、/dev/ttyS5进行测试 发现SSCOM读取数据概率性乱码或者读取不到数据

排查问题过程

发送端数据0x61:但是发现有多余的数据0x0D 0x0A
数据乱码:
串口问题排查-时序异常_第2张图片
发送端数据0x61:起始位错位
串口问题排查-时序异常_第3张图片

同时测量接受端,波形如下,出现很多脉冲
串口问题排查-时序异常_第4张图片
有两个问题:
1.发送端的时序出现错位或者多余的数据
2.接收端数据出现脉冲

我的测试代码里只有发送没有读取,接受端的脉冲是哪里来的?

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//根据具体的设备修改
const char default_path[] = "/dev/ttyS10";
// const char default_path[] = "/dev/ttymxc2";

int main(int argc, char *argv[])
{
     
   int fd;
   int res;
   struct termios opt;
   char *path;
   char buf[1024] = "Embedfire tty send test.\n";

   //若无输入参数则使用默认终端设备
   if(argc > 1)
      path = argv[1];
   else
      path = (char *)default_path;

   //获取串口设备描述符
   printf("This is tty/usart demo.\n");
   fd = open(path, O_RDWR);
   if(fd < 0){
     
      printf("Fail to Open %s device\n", path);
      return 0;
   }
   //清空串口接收缓冲区
   tcflush(fd, TCIOFLUSH);
   // 获取串口参数opt
   // tcgetattr(fd, &opt);

   res = ioctl(fd,TCGETS, &opt);

   opt.c_ispeed = opt.c_cflag & (CBAUD | CBAUDEX);
   opt.c_ospeed = opt.c_cflag & (CBAUD | CBAUDEX);

   //输出宏定义的值,方便对比
   printf("Macro B9600 = %#o\n",B9600);
   printf("Macro B115200 = %#o\n",B115200);
   //输出读取到的值
   printf("ioctl TCGETS,opt.c_ospeed = %#o\n", opt.c_ospeed);
   printf("ioctl TCGETS,opt.c_ispeed = %#o\n", opt.c_ispeed);
   printf("ioctl TCGETS,opt.c_cflag = %#x\n", opt.c_cflag);

   speed_t change_speed = B9600;
   if(opt.c_ospeed == B9600)
      change_speed = B115200;

   //设置串口输出波特率
   cfsetospeed(&opt, change_speed);
   //设置串口输入波特率
   cfsetispeed(&opt, change_speed);
   //设置数据位数
   opt.c_cflag &= ~CSIZE;
   opt.c_cflag |= CS8;
   //校验位
   opt.c_cflag &= ~PARENB;
   opt.c_iflag &= ~INPCK;
   //设置停止位
   opt.c_cflag &= ~CSTOPB;

   //更新配置
   // tcsetattr(fd, TCSANOW, &opt);
   res = ioctl(fd,TCSETS, &opt);

   //再次读取
   res = ioctl(fd,TCGETS, &opt);

   opt.c_ispeed = opt.c_cflag & (CBAUD | CBAUDEX);
   opt.c_ospeed = opt.c_cflag & (CBAUD | CBAUDEX);

   printf("ioctl TCGETS after TCSETS\n");

   //输出读取到的值
   printf("ioctl TCGETS,opt.c_ospeed = %#o\n", opt.c_ospeed);
   printf("ioctl TCGETS,opt.c_ispeed = %#o\n", opt.c_ispeed);
   printf("ioctl TCGETS,opt.c_cflag = %#x\n", opt.c_cflag);

   do{
     
      //发送字符串
	  //sleep(1);
      write(fd, buf, strlen(buf));
      //接收字符串
	  sleep(1);
    //  res = read(fd, buf, 1024);
      if(res >0 ){
     
         //给接收到的字符串加结束符
         buf[res] = '\0';
         printf("Receive res = %d bytes data: %x %x\n",res, buf[0],buf[1]);
      }
   }while(res >= 0);

   printf("read error,res = %d",res);

   close(fd);
   return 0;
}

如果修改代码进行read的操作,发现测试CPU发送端(没有write原则上应该是高电平),实际也出现了,有效数据,这个数据是哪里来的?而且同时发现CPU 接收端的时序也出现了错位的现象
串口问题排查-时序异常_第5张图片针对于0x0D 0x0A 问题:发现CPU在传输数据的时候会自动填充0x0D 0x0A 为换行符/r/n
重点排查毛刺问题:
怀疑是硬件走线异常导致出现了毛刺,每次在发送数据的时候RX数据线上都会出现毛刺;

硬件确认电路,485通信电路是硬件做的 在发送数据TX-》差分有效数据时会反馈到RX电路 导致RX电路出现波形,由于485是半双工所以在发送的时候带一帧结束之后再进行数据读取
串口问题排查-时序异常_第6张图片
我们采用的是cat /dev/ttyS6 测,cat本身具有收发回路功能,导致在一帧read没有结束的时候进行发送
出现数据异常(同时我自己实现的串口程序有有问题 重新编写)
重新修改串口程序,部分串口初始化如下;进行测试,测试通过

int open_tty(_UART_INFO_s *tty){
     
	
	uart_fd = open(tty->name, O_RDWR | O_NOCTTY,0);
    if (uart_fd <0)
    {
     
        return -1;
    }

    fcntl(uart_fd, F_SETFL, 0);
    tcgetattr(uart_fd,&tty->otm);

	return 0;
}

int set_tty_speed(_UART_INFO_s *tty){
     
	
    unsigned int speed;

    if( tcgetattr(uart_fd,&tty->ntm) != 0)
    {
     
        printf("SetupSerial [%s] speed\n",tty->name);
        return -1;
    }
    bzero(&tty->ntm, sizeof(tty->ntm));

    switch(tty->baudrate)
    {
     
        case 300:
            speed= B300;
        break;
        case 1200:
            speed= B1200;
        break;
        case 2400:
            speed= B2400;
        break;
        case 4800:
            speed= B4800;
        break;
        case 9600:
            speed= B9600;
        break;
        case 19200:
            speed= B19200;
        break;
        case 38400:
            speed= B38400;
        break;
        case 115200:
            speed= B115200;
        case 230400:
            speed= B230400;
        break;
    }

    cfsetispeed(&tty->ntm, speed);
    cfsetospeed(&tty->ntm, speed);

    tcflush(uart_fd, TCIFLUSH);
    tcsetattr(uart_fd,TCSANOW,&tty->ntm);

    return 0;
}

int set_tty_parity(_UART_INFO_s *ptty){
     

	if( tcgetattr(uart_fd,&ptty->ntm) != 0)
    {
     
        printf("SetupSerial [%s]\n",ptty->name);
        return 1;
    }

    ptty->ntm.c_cflag &= ~CSIZE;
    switch (ptty->datalen)
    {
     
        case 7:
            ptty->ntm.c_cflag |= CS7;
        	break;
        case 8:
            ptty->ntm.c_cflag |= CS8;
        	break;
        default:
            printf("Unsupported data size\n");
        	return 5;
    }


    switch (ptty->parity)
    {
     
        case 0: // non-parity
            ptty->ntm.c_cflag &= ~PARENB;
            ptty->ntm.c_iflag &= ~INPCK;
        	break;

        case 1: // odd-parity
            ptty->ntm.c_cflag |= (PARODD|PARENB);
            ptty->ntm.c_iflag |= INPCK;
        	break;

        case 2: //even-parity
            ptty->ntm.c_cflag |= PARENB;
            ptty->ntm.c_cflag &= ~PARODD;
            ptty->ntm.c_iflag |= INPCK;
        	break;


        default:
            printf("Unsupported parity\n");
        	return 2;
    }

    // stop-bits
    switch (ptty->stopbit)
    {
     
        case 1:
            ptty->ntm.c_cflag &= ~CSTOPB;
        	break;
        case 2:
            ptty->ntm.c_cflag |= CSTOPB;
        	break;
        default:
            printf("Unsupported stop bits\n");
        	return 3;
    }

    ptty->ntm.c_cflag |= (CLOCAL | CREAD | ptty->enable_autoflow);
    ptty->ntm.c_lflag &=~(ICANON | ECHO | ECHOE | ISIG);
    ptty->ntm.c_oflag &=~OPOST;
    ptty->ntm.c_iflag &=~(IXON | ICRNL);

    ptty->ntm.c_cc[VTIME] =1;
    ptty->ntm.c_cc[VMIN] = 255;
    tcflush(uart_fd, TCIFLUSH);
    if (tcsetattr(uart_fd,TCSANOW,&ptty->ntm) != 0)
    {
     
        printf("SetupSerial \n");
        return 4;
    }

    return 0;
}

int uart_init(){
     

	int ret = -1;
	_UART_INFO_s *tty;

	tty = (_UART_INFO_s *)malloc(sizeof(_UART_INFO_s));
    if(tty == NULL)
    {
     
    	printf("malloc memory fail!\n");
        return ret;
    }

	sprintf(tty->name, uart_com);
	tty->baudrate = 9600;
	tty->datalen = 8;
	tty->stopbit = 1;
	tty->enable_autoflow = 0;
	tty->parity = 0;

	ret = open_tty(tty);
	if(ret){
     
		free(tty);
		printf("open ttyS2 fail!\n");
		return ret;
	}

	ret = set_tty_speed(tty);
	if(ret){
     
		free(tty);
		printf("setup ttyS2 speed fail!\n");
		return ret;
	}

	ret = set_tty_parity(tty);
	if(ret){
     
		free(tty);
		printf("setup ttyS2 parity fail!\n");
		return ret;
	}
	
	return ret;
}

void printf_usage(){
     
    printf("usage:\n");
    printf("    eth2uart [port] [com]\n");
    printf("    e.g ./eth2uart 1001 /dev/ttyS0\n");
}

结论

485硬件电路存在反馈时序,在发送的时候 不要进行读取即可
不要使用cat测试 cat具有一帧数据没有结束进行读取的操作

你可能感兴趣的:(嵌入式,笔记,问题处理,物联网,嵌入式,linux,串口通信,乱码)