Linux系统串口批量产测工具

电子说

1.3w人已加入

描述

1、说明

本文针对Linux系统上如何对各类串口硬件进行出厂测试进行硬件连接和软件使用说明,提供的软件测试工具wchsertest,适用于USB、PCI、PCIe转串口设备等、同样也适用于原生ttyS串口。

2、串口测试硬件连接

在测试前,需要制作单独的硬件治具,按下表连接信号线:

usb

引脚连接示意图:

usb

usb

3、软件使用方法

(1)插入待测试USB/PCI/PCIe转串口设备。

(2)以CH342F(USB转2串口芯片)为例,安装对应VCP厂商驱动程序,进入/dev目录查看出现如下设备节点:

usbusb

以CH382为例,安装对应VCP厂商驱动程序,进入/dev目录查看出现如下设备节点:

usbusb

(3)运行软件,输入命令格式:

./[可执行文件] –D [设备节点路径]

实例1(测试CH342的UART0):sudo ./serial_port_test -D /dev/ttyCH343USB0

实例2(测试CH382的UART0):sudo ./serial_port_test -D /dev/ttyWCH0

4、测试错误码说明

根据输出的错误码和终端输出信息可判断故障信号线,下表为错误码和说明。

错误码 错误码说明
0 DTR--DSR线错误
1 DTR--DCD线错误
2 RTS--CTS线错误
3 RTS--RI线错误
4 TXD--RXD线错误

5、测试实例

(1)测试成功实例

软件分别以2400bps、9600bps、115200bps各测试一次。

usbusbusbusb

(2)测试错误实例

usbusb

根据输出信息可知,DTR—DSR信号通讯存在错误,错误码:0。

6、wchsertest工具源码

/*
 * serial port factory test utility.
 *
 * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd.
 * Web:     http://wch.cn
 * Author:  WCH 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define termios asmtermios
#include 
#undef termios
#include 

#define DTR_ON	    1
#define DTR_OFF	    0
#define RTS_ON	    1
#define RTS_OFF	    0
#define BUF_SIZE    64
#define DTR_ON_CMD  0x0
#define DTR_OFF_CMD 0x1
#define RTS_ON_CMD  0x2
#define RTS_OFF_CMD 0x3

extern int ioctl(int d, int request, ...);

static const char *device = "/dev/ttyCH343USB0";
static int hardflow = 0;
static int verbose = 0;
static FILE *fp;

static const struct option lopts[] = {
	{ "device", required_argument, 0, 'D' },
	{ NULL, 0, 0, 0 },
};

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DSvf]
", prog);
	puts("  -D --device    tty device to use
");
	exit(1);
}

static void parse_opts(int argc, char *argv[])
{
	int c;

	while (1) {
		c = getopt_long(argc, argv, "D:S:h", lopts, NULL);
		if (c == -1) {
			break;
		}
		switch (c) {
		case 'D':
			if (optarg != NULL)
				device = optarg;
			break;
		case 'h':
		default:
			print_usage(argv[0]);
			break;
		}
	}
}

/**
 * libtty_setcustombaudrate - set baud rate of tty device
 * @fd: device handle
 * @speed: baud rate to set
 *
 * The function return 0 if success, or -1 if fail.
 */
static int libtty_setcustombaudrate(int fd, int baudrate)
{
	struct termios2 tio;

	if (ioctl(fd, TCGETS2, &tio)) {
		perror("TCGETS2");
		return -1;
	}

	tio.c_cflag &= ~CBAUD;
	tio.c_cflag |= BOTHER;
	tio.c_ispeed = baudrate;
	tio.c_ospeed = baudrate;

	if (ioctl(fd, TCSETS2, &tio)) {
		perror("TCSETS2");
		return -1;
	}

	if (ioctl(fd, TCGETS2, &tio)) {
		perror("TCGETS2");
		return -1;
	}

	return 0;
}

/**
 * libtty_setopt - config tty device
 * @fd: device handle
 * @speed: baud rate to set
 * @databits: data bits to set
 * @stopbits: stop bits to set
 * @parity: parity to set
 * @hardflow: hardflow to set
 *
 * The function return 0 if success, or -1 if fail.
 */
static int libtty_setopt(int fd, int speed, int databits, int stopbits, char parity, char hardflow)
{
	struct termios newtio;
	struct termios oldtio;
	int i;

	bzero(&newtio, sizeof(newtio));
	bzero(&oldtio, sizeof(oldtio));

	if (tcgetattr(fd, &oldtio) != 0) {
		perror("tcgetattr");
		return -1;
	}
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;

	/* set data bits */
	switch (databits) {
	case 5:
		newtio.c_cflag |= CS5;
		break;
	case 6:
		newtio.c_cflag |= CS6;
		break;
	case 7:
		newtio.c_cflag |= CS7;
		break;
	case 8:
		newtio.c_cflag |= CS8;
		break;
	default:
		fprintf(stderr, "unsupported data size
");
		return -1;
	}

	/* set parity */
	switch (parity) {
	case 'n':
	case 'N':
		newtio.c_cflag &= ~PARENB; /* Clear parity enable */
		newtio.c_iflag &= ~INPCK;  /* Disable input parity check */
		break;
	case 'o':
	case 'O':
		newtio.c_cflag |= (PARODD | PARENB); /* Odd parity instead of even */
		newtio.c_iflag |= INPCK;	     /* Enable input parity check */
		break;
	case 'e':
	case 'E':
		newtio.c_cflag |= PARENB;  /* Enable parity */
		newtio.c_cflag &= ~PARODD; /* Even parity instead of odd */
		newtio.c_iflag |= INPCK;   /* Enable input parity check */
		break;
	default:
		fprintf(stderr, "unsupported parity
");
		return -1;
	}

	/* set stop bits */
	switch (stopbits) {
	case 1:
		newtio.c_cflag &= ~CSTOPB;
		break;
	case 2:
		newtio.c_cflag |= CSTOPB;
		break;
	default:
		perror("unsupported stop bits
");
		return -1;
	}

	if (hardflow)
		newtio.c_cflag |= CRTSCTS;
	else
		newtio.c_cflag &= ~CRTSCTS;

	newtio.c_cc[VTIME] = 10; /* Time-out value (tenths of a second) [!ICANON]. */
	newtio.c_cc[VMIN] = 64; /* Minimum number of bytes read at once [!ICANON]. */

	tcflush(fd, TCIOFLUSH);

	if (tcsetattr(fd, TCSANOW, &newtio) != 0) {
		perror("tcsetattr");
		return -1;
	}

	/* set tty speed */
	if (libtty_setcustombaudrate(fd, speed) != 0) {
		perror("setbaudrate");
		return -1;
	}

	return 0;
}

/**
 * libtty_open - open tty device
 * @devname: the device name to open
 *
 * In this demo device is opened blocked, you could modify it at will.
 */
static int libtty_open(const char *devname)
{
	int fd = open(devname, O_RDWR | O_NOCTTY);
	int flags = 0;

	if (fd < 0) {
		perror("open device failed");
		return -1;
	}

	if (fcntl(fd, F_SETFL, 0) < 0) {
		printf("fcntl failed.
");
		return -1;
	}

	if (isatty(fd) == 0) {
		printf("not tty device.
");
		return -1;
	}

	return fd;
}

/**
 * libtty_close - close tty device
 * @fd: the device handle
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_close(int fd)
{
	return close(fd);
}

/**
 * libtty_tiocmset - modem set
 * @fd: file descriptor of tty device
 * @bDTR: 0 on inactive, other on DTR active
 * @bRTS: 0 on inactive, other on RTS active
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_tiocmset(int fd, char bDTR, char bRTS)
{
	unsigned long controlbits = 0;

	if (bDTR)
		controlbits |= TIOCM_DTR;
	if (bRTS)
		controlbits |= TIOCM_RTS;

	return ioctl(fd, TIOCMSET, &controlbits);
}

/**
 * libtty_tiocmget - modem get
 * @fd: file descriptor of tty device
 * @modembits: pointer to modem status
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_tiocmget_check(int fd, unsigned long *modembits, int cmd)
{
	int ret = 0;

	ret = ioctl(fd, TIOCMGET, modembits);
	if (ret == 0) {
		switch (cmd) {
		case DTR_OFF_CMD: // DTR--DSR/DCD
			if ((*modembits & TIOCM_DSR) != 0) {
				printf("[error code: %d] DTR--DSR ERROR
", 0);
				ret = -1;
			}
			if ((*modembits & TIOCM_CD) != 0) {
				printf("[error code: %d] DTR--DCD ERROR
", 1);
				ret = -1;
			}
			break;
		case DTR_ON_CMD:
			if ((*modembits & TIOCM_DSR) == 0) {
				printf("[error code: %d] DTR--DSR ERROR
", 0);
				ret = -1;
			}
			if ((*modembits & TIOCM_CD) == 0) {
				printf("[error code: %d] DTR--DCD ERROR
", 1);
				ret = -1;
			}
			break;
		case RTS_OFF_CMD: // RTS--CTS/RI
			if ((*modembits & TIOCM_CTS) != 0) {
				printf("[error code: %d] RTS--CTS ERROR
", 2);
				ret = -1;
			}
			if ((*modembits & TIOCM_RI) != 0) {
				printf("[error code: %d] RTS--RI ERROR
", 3);
				ret = -1;
			}
			break;
		case RTS_ON_CMD:
			if ((*modembits & TIOCM_CTS) == 0) {
				printf("[error code: %d] RTS--CTS ERROR
", 2);
				ret = -1;
			}
			if ((*modembits & TIOCM_RI) == 0) {
				printf("[error code: %d] RTS--RI ERROR
", 3);
				ret = -1;
			}
			break;
		default:
			break;
		}
	}
	return ret;
}

static void sig_handler(int signo)
{
	printf("capture sign no:%d
", signo);
	if (fp != NULL) {
		fflush(fp);
		fsync(fileno(fp));
		fclose(fp);
	}
	exit(0);
}

void start_test(int fd)
{
	int ret, i, times, num, nwrite, nread, len;
	int len_w, pos_w, ret1, ret2, ret3;
	int total = 0, off_w, off_r;
	char c;
	unsigned long modemstatus;
	unsigned char buf_write[BUF_SIZE];
	unsigned char buf_read[BUF_SIZE];

	memset(buf_write, 0x00, BUF_SIZE);
	memset(buf_read, 0x00, BUF_SIZE);

	for (times = 0; times < 64; times++) {
		for (i = 0; i < BUF_SIZE; i++)
			buf_write[i] = i + BUF_SIZE * (times % 4);

		/* Send 64 bytes */
        off_w = 0;
        len = BUF_SIZE;
        while (len > 0) {
            nwrite = write(fd, buf_write + off_w, len);
            if (nwrite < 0) {
                perror("write");
                exit(1);
            }
            off_w += nwrite;
            len -= nwrite;
        }
        
		/* Receive and judge */
        off_r = 0;
		while (nwrite > 0) {
			nread = read(fd, buf_read + off_r, nwrite);
            if (nread < 0) {
                printf("read error!
");
				exit(1);
            }
            off_r += nread;
            nwrite -= nread;
		}

		total += nread;

		/* compare the buffer contents */
		if (memcmp(buf_read, buf_write, BUF_SIZE) != 0) {
			printf("[error code: %d] TXD/RXD test error
", 4);
			goto exit;
		}
	}
	printf("TXD/RXD test passed
");

	/* Set DTR invalid */
	if (libtty_tiocmset(fd, DTR_OFF, RTS_OFF) != 0)
		goto exit;
	usleep(10000);
	ret1 = libtty_tiocmget_check(fd, &modemstatus, DTR_OFF_CMD);

	/* Set DTR valid */
	if (libtty_tiocmset(fd, DTR_ON, RTS_OFF) != 0)
		goto exit;
	usleep(10000);
	ret2 = libtty_tiocmget_check(fd, &modemstatus, DTR_ON_CMD);

	/* Set RTS valid */
	if (libtty_tiocmset(fd, DTR_OFF, RTS_ON) != 0)
		goto exit;
	usleep(10000);
	ret3 = libtty_tiocmget_check(fd, &modemstatus, RTS_ON_CMD);

	if ((ret1 || ret2 || ret3) == 0)
		printf("DTR/RTS/DSR/CTS/DCD/RI test passed
");
	printf("
");

exit:
	return;
}

int main(int argc, char *argv[])
{
	int fd, ret, i, num, nwrite, nread;
	int len_w, pos_w, ret1, ret2, ret3, ret4;
	int total = 0, off = 0;
	char c;
	unsigned long modemstatus;
	unsigned char buf_write[BUF_SIZE];
	unsigned char buf_read[BUF_SIZE];

	parse_opts(argc, argv);
	signal(SIGINT, sig_handler);

	fd = libtty_open(device);
	if (fd < 0) {
		printf("libtty_open: %s error.
", device);
		exit(0);
	}

	/* 2400bps test */
	ret = libtty_setopt(fd, 2400, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.
");
		exit(0);
	}
	start_test(fd);

	/* 9600bps test */
	ret = libtty_setopt(fd, 9600, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.
");
		exit(0);
	}
	start_test(fd);

	/* 115200bps test */
	ret = libtty_setopt(fd, 115200, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.
");
		exit(0);
	}
	start_test(fd);

	ret = libtty_close(fd);
	if (ret != 0) {
		printf("libtty_close error.
");
		exit(0);
	}

	return 0;
}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分