0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux系統(tǒng)串口批量產(chǎn)測工具

jf_49670627 ? 來源:jf_49670627 ? 作者:jf_49670627 ? 2023-04-12 11:38 ? 次閱讀

1、說明

本文針對(duì)Linux系統(tǒng)上如何對(duì)各類串口硬件進(jìn)行出廠測試進(jìn)行硬件連接和軟件使用說明,提供的軟件測試工具wchsertest,適用于USB、PCI、PCIe轉(zhuǎn)串口設(shè)備等、同樣也適用于原生ttyS串口。

2、串口測試硬件連接

在測試前,需要制作單獨(dú)的硬件治具,按下表連接信號(hào)線:

1.png

引腳連接示意圖:

?

3、軟件使用方法

(1)插入待測試USB/PCI/PCIe轉(zhuǎn)串口設(shè)備。

(2)以CH342F(USB轉(zhuǎn)2串口芯片)為例,安裝對(duì)應(yīng)VCP廠商驅(qū)動(dòng)程序,進(jìn)入/dev目錄查看出現(xiàn)如下設(shè)備節(jié)點(diǎn):

?

以CH382為例,安裝對(duì)應(yīng)VCP廠商驅(qū)動(dòng)程序,進(jìn)入/dev目錄查看出現(xiàn)如下設(shè)備節(jié)點(diǎn):

?

(3)運(yùn)行軟件,輸入命令格式:

./[可執(zhí)行文件] –D [設(shè)備節(jié)點(diǎn)路徑]

實(shí)例1(測試CH342的UART0):sudo ./serial_port_test -D /dev/ttyCH343USB0

實(shí)例2(測試CH382的UART0):sudo ./serial_port_test -D /dev/ttyWCH0

4、測試錯(cuò)誤碼說明

根據(jù)輸出的錯(cuò)誤碼和終端輸出信息可判斷故障信號(hào)線,下表為錯(cuò)誤碼和說明。

錯(cuò)誤碼 錯(cuò)誤碼說明
0 DTR--DSR線錯(cuò)誤
1 DTR--DCD線錯(cuò)誤
2 RTS--CTS線錯(cuò)誤
3 RTS--RI線錯(cuò)誤
4 TXD--RXD線錯(cuò)誤

5、測試實(shí)例

(1)測試成功實(shí)例

軟件分別以2400bps、9600bps、115200bps各測試一次。

? ?

(2)測試錯(cuò)誤實(shí)例

?

根據(jù)輸出信息可知,DTR—DSR信號(hào)通訊存在錯(cuò)誤,錯(cuò)誤碼: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;
}

?

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • usb
    usb
    +關(guān)注

    關(guān)注

    60

    文章

    7772

    瀏覽量

    262369
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11123

    瀏覽量

    207905
  • PCI
    PCI
    +關(guān)注

    關(guān)注

    4

    文章

    643

    瀏覽量

    129954
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1533

    瀏覽量

    75455
  • PCIe
    +關(guān)注

    關(guān)注

    15

    文章

    1165

    瀏覽量

    81974
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    藍(lán)牙多串口配置工具

    工具是一種多串口配置工具,基于MCF開發(fā),可以將配置信息同時(shí)下發(fā)到多個(gè)串口,支持配置文件信息下發(fā)、文本下發(fā)和十六進(jìn)制下發(fā),一般用于芯片等配置工裝,提高生產(chǎn)效率。 多
    發(fā)表于 03-25 19:22

    【U盤量產(chǎn)問題】常見U盤量產(chǎn)的七大問題

    心中有數(shù)再動(dòng)手。另外量產(chǎn)前要先備份U盤的數(shù)據(jù),因?yàn)橐坏?b class='flag-5'>量產(chǎn)就會(huì)破壞U盤上的所有文件。 2、操作系統(tǒng):因?yàn)?b class='flag-5'>量產(chǎn)工具的讀寫需涉及到硬件方面,所以
    發(fā)表于 06-24 10:54

    串口工具

    串口工具.exe
    發(fā)表于 04-26 16:45 ?37次下載
    <b class='flag-5'>串口</b><b class='flag-5'>工具</b>

    Linux串口編程下載

    linux 中的串口設(shè)備文件存放于/dev 目錄下,其中串口一,串口二對(duì)應(yīng)設(shè)備名依次為/dev/ttyS0、/dev/ttyS1。在linux
    發(fā)表于 11-15 17:39 ?108次下載

    串口程序+串口調(diào)工具

    電子發(fā)燒友網(wǎng)站提供《串口程序+串口調(diào)工具.zip》資料免費(fèi)下載
    發(fā)表于 07-16 11:15 ?8次下載

    串口調(diào)試工具

    串口調(diào)試工具 便于單片機(jī)下載 串口調(diào)試工具 串口調(diào)試工具
    發(fā)表于 11-20 16:35 ?41次下載

    TxtModify Txt文件內(nèi)容批量修改工具

    Txt文件內(nèi)容批量修改工具
    發(fā)表于 02-28 23:03 ?0次下載

    Linux系統(tǒng)EXAR方案擴(kuò)展串口

      本文以Toradex基于NXP i.MX6D/6Q處理器的Apalisi.MX6D/QARM計(jì)算機(jī)模塊,在Linux系統(tǒng)下通過EXAR方案擴(kuò)展8路串口。
    發(fā)表于 09-18 08:40 ?16次下載

    愛特梅爾Linux Android生態(tài)系統(tǒng)工具

    Atmel's Linux Android生態(tài)系統(tǒng)工具支持
    的頭像 發(fā)表于 07-10 00:21 ?3178次閱讀

    串口驅(qū)動(dòng)到Linux驅(qū)動(dòng)模型

    本文通過對(duì)Linux串口驅(qū)動(dòng)的分析。由最上層的C庫。到操作系統(tǒng)系統(tǒng)調(diào)用層的封裝。再到tty子系統(tǒng)的核心。再到一系列線路規(guī)程。再到最底層的硬
    的頭像 發(fā)表于 11-04 14:50 ?2538次閱讀

    Linux系統(tǒng)LPT打印口批量產(chǎn)工具

    該軟件用于在Linux平臺(tái)測試CH35X/CH38X(PCI/PCIe轉(zhuǎn)串并口)的并口各引腳功能是否正常。方便對(duì)設(shè)備進(jìn)行出廠測試。
    的頭像 發(fā)表于 04-12 11:44 ?2529次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>系統(tǒng)</b>LPT打印口<b class='flag-5'>批量產(chǎn)</b>測<b class='flag-5'>工具</b>

    Windows系統(tǒng)串口批量出廠測試工具

    ? WCHUsbSerTest是一款用于WCH USB轉(zhuǎn)串口系列產(chǎn)品出廠測試的工具軟件,方便用戶對(duì)產(chǎn)品進(jìn)行批量化功能測試。
    的頭像 發(fā)表于 04-12 11:48 ?2610次閱讀
    Windows<b class='flag-5'>系統(tǒng)</b><b class='flag-5'>串口</b><b class='flag-5'>批量</b>出廠測試<b class='flag-5'>工具</b>

    安裝Linux系統(tǒng)安裝工具

    安裝_Linux系統(tǒng)安裝工具,可以安裝各類Linux操作系統(tǒng)。通過iso鏡像文件的格式安裝。也可以安裝在U盤上,本人親測通過。 ?
    發(fā)表于 09-11 10:21 ?0次下載

    Banana Pi BPI-W3 RK3588開發(fā)平臺(tái)批量產(chǎn)測軟件,全面批量測試

    Banana Pi BPI-W3 RK3588開發(fā)平臺(tái)批量產(chǎn)測軟件,全面批量測試
    的頭像 發(fā)表于 11-02 09:08 ?1198次閱讀
    Banana Pi BPI-W3 RK3588開發(fā)平臺(tái)<b class='flag-5'>批量產(chǎn)</b>測軟件,全面<b class='flag-5'>批量</b>測試

    linux系統(tǒng)備份與還原工具

    Linux系統(tǒng)備份與還原工具是用于備份和恢復(fù)Linux操作系統(tǒng)工具。在日常使用中,備份和還原是
    的頭像 發(fā)表于 11-23 10:04 ?2181次閱讀