采用新塘处理器NUC972 使用该芯片所有的串口 UART1~UART10
测试发现串口数据读取异常
采用测试串口终端SSCOM
内核已经配置了所有的串口功能,串口PIN复用正常
设备启动可以识别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
数据乱码:
发送端数据0x61:起始位错位
同时测量接受端,波形如下,出现很多脉冲
有两个问题:
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 接收端的时序也出现了错位的现象
针对于0x0D 0x0A 问题:发现CPU在传输数据的时候会自动填充0x0D 0x0A 为换行符/r/n
重点排查毛刺问题:
怀疑是硬件走线异常导致出现了毛刺,每次在发送数据的时候RX数据线上都会出现毛刺;
硬件确认电路,485通信电路是硬件做的 在发送数据TX-》差分有效数据时会反馈到RX电路 导致RX电路出现波形,由于485是半双工所以在发送的时候带一帧结束之后再进行数据读取
我们采用的是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具有一帧数据没有结束进行读取的操作