【发布时间】:2017-01-22 18:33:21
【问题描述】:
我正在尝试使用此处提供的示例开发 LIN 总线主控器:
https://github.com/trainman419/linux-lin/tree/master/misc/tty_lin_master
本质上,这会通过串行端口发送 LIN 协议消息。
我稍微更改了代码以简化低级功能测试。我想看看 LIN 分析器是否能正确解码非常原始的 LIN 消息,但我遇到了与串行端口有关的奇怪问题。我正在通过 /dev/ttymxc4 (RS-232) 接口发送几个连续的字符,但我在数据包传输的中间某处看到随机暂停。有趣的是,这个暂停从某个值开始,我捕获了 8.6 毫秒,然后逐渐缩小,直到它消失......但随后又开始了。
基本上,如果您查看 main,我实际上只是通过 RS-232 发送 10 个字符...
如果有人有任何想法,这是代码:
/*
* UART-LIN master implementation
*/
#define USE_TERMIOS2
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h> /* clock_nanosleep */
#include <getopt.h>
#ifndef USE_TERMIOS2
#include <linux/serial.h> /* struct struct_serial */
#include <termios.h>
#else /*USE_TERMIOS2*/
#include <asm/ioctls.h>
#include <asm/termbits.h>
#endif /*USE_TERMIOS2*/
#include "lin_common.h"
#define LIN_HDR_SIZE 2
struct sllin_tty {
int tty_fd;
#ifndef USE_TERMIOS2
struct termios tattr_orig;
struct termios tattr;
struct serial_struct sattr;
#else /*USE_TERMIOS2*/
struct termios2 tattr_orig;
struct termios2 tattr;
#endif /*USE_TERMIOS2*/
};
struct sllin_tty sllin_tty_data;
struct sllin sllin_data = {
.tty = &sllin_tty_data,
};
/* ------------------------------------------------------------------------ */
#ifndef USE_TERMIOS2
static int tty_set_baudrate(struct sllin_tty *tty, int baudrate)
{
/* Set "non-standard" baudrate in serial_struct struct */
tty->sattr.flags &= (~ASYNC_SPD_MASK);
tty->sattr.flags |= (ASYNC_SPD_CUST);
tty->sattr.custom_divisor = (tty->sattr.baud_base + baudrate / 2) / baudrate;
if (ioctl(tty->tty_fd, TIOCSSERIAL, &tty->sattr) < 0)
{
perror("ioctl TIOCSSERIAL");
return -1;
}
return 0;
}
static int tty_flush(struct sllin_tty *tty, int queue_selector)
{
return tcflush(tty->tty_fd, queue_selector);
}
#else /*USE_TERMIOS2*/
static int tty_set_baudrate(struct sllin_tty *tty, int baudrate)
{
tty->tattr.c_ospeed = baudrate;
tty->tattr.c_ispeed = baudrate;
tty->tattr.c_cflag &= ~CBAUD;
tty->tattr.c_cflag |= BOTHER;
if(ioctl(tty->tty_fd, TCSETS2, &tty->tattr)) {
perror("ioctl TIOCSSERIAL");
return -1;
}
return 0;
}
static int tty_flush(struct sllin_tty *tty, int queue_selector)
{
return ioctl(tty->tty_fd, TCFLSH, queue_selector);
}
#endif /*USE_TERMIOS2*/
static int tty_set_mode(struct sllin_tty *tty, int baudrate)
{
if(!isatty(tty->tty_fd)) {
fprintf(stderr, "Not a terminal.\n");
return -1;
}
/* Flush input and output queues. */
if (tty_flush(tty, TCIOFLUSH) != 0) {
perror("tcflush");
return -1;;
}
#ifndef USE_TERMIOS2
/* Save settings for later restoring */
if (tcgetattr(tty->tty_fd, &tty->tattr_orig) < 0) {
perror("tcgetattr");
return -1;
}
/* Save settings into global variables for later use */
if (tcgetattr(tty->tty_fd, &tty->tattr) < 0) {
perror("tcgetattr");
return -1;
}
/* Save settings into global variables for later use */
if (ioctl(tty->tty_fd, TIOCGSERIAL, &tty->sattr) < 0) {
perror("ioctl TIOCGSERIAL");
}
#else /*USE_TERMIOS2*/
/* Save settings for later restoring */
if (ioctl(tty->tty_fd, TCGETS2, &tty->tattr_orig) < 0) {
perror("ioctl TCGETS2");
return -1;
}
/* Save settings into global variables for later use */
if (ioctl(tty->tty_fd, TCGETS2, &tty->tattr) < 0) {
perror("ioctl TCGETS2");
return -1;
}
#endif /*USE_TERMIOS2*/
/* 8 data bits */
/* Enable receiver */
/* Ignore CD (local connection) */
tty->tattr.c_cflag = CS8 | CREAD | CLOCAL;
tty->tattr.c_iflag = 0;
tty->tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
tty->tattr.c_lflag = 0;
tty->tattr.c_cc[VINTR] = '\0';
tty->tattr.c_cc[VQUIT] = '\0';
tty->tattr.c_cc[VERASE] = '\0';
tty->tattr.c_cc[VKILL] = '\0';
tty->tattr.c_cc[VEOF] = '\0';
tty->tattr.c_cc[VTIME] = '\0';
tty->tattr.c_cc[VMIN] = 1;
tty->tattr.c_cc[VSWTC] = '\0';
tty->tattr.c_cc[VSTART] = '\0';
tty->tattr.c_cc[VSTOP] = '\0';
tty->tattr.c_cc[VSUSP] = '\0';
tty->tattr.c_cc[VEOL] = '\0';
tty->tattr.c_cc[VREPRINT] = '\0';
tty->tattr.c_cc[VDISCARD] = '\0';
tty->tattr.c_cc[VWERASE] = '\0';
tty->tattr.c_cc[VLNEXT] = '\0';
tty->tattr.c_cc[VEOL2] = '\0';
#ifndef USE_TERMIOS2
/* Set TX, RX speed to 38400 -- this value allows
to use custom speed in struct struct_serial */
cfsetispeed(&tty->tattr, B38400);
cfsetospeed(&tty->tattr, B38400);
if (tcsetattr(tty->tty_fd, TCSANOW, &tty->tattr) == -1) {
perror("tcsetattr()");
return -1;
}
#else /*USE_TERMIOS2*/
/* Set new parameters with previous speed and left */
/* tty_set_baudrate() to do the rest */
if(ioctl(tty->tty_fd, TCSETS2, &tty->tattr)) {
perror("ioctl TIOCSSERIAL");
return -1;
}
#endif /*USE_TERMIOS2*/
/* Set real speed */
tty_set_baudrate(tty, baudrate);
return 0;
}
int sllin_open(struct sllin *sl, const char *dev_fname, int baudrate)
{
int fd;
sl->lin_baud = baudrate;
/* Calculate baudrate for sending LIN break */
sl->lin_break_baud = (sl->lin_baud * 2) / 3;
fd = open(dev_fname, O_RDWR);
if (fd < 0) {
perror("open()");
return -1;
}
sl->tty->tty_fd = fd;
return tty_set_mode(sl->tty, sl->lin_baud);
}
int main()
{
struct sllin *sl = &sllin_data;
char *dev_fname = "/dev/ttymxc4";
int lin_baudrate = 19200;
int lin_id = 1;
if (sllin_open(sl, dev_fname, lin_baudrate) < 0) {
fprintf (stderr, "sllin_open open failed\n");
exit(EXIT_FAILURE);
}
fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
printf("Press enter to terminate.\n\n");
while(1) {
char c;
tty_flush(sl->tty, TCIOFLUSH);
unsigned int buff[10] = {1,2,3,4,5,6,7,8,9,10};
// debug
write(sl->tty->tty_fd, &buff[0], 1);
write(sl->tty->tty_fd, &buff[1], 1);
write(sl->tty->tty_fd, &buff[2], 1);
write(sl->tty->tty_fd, &buff[3], 1);
write(sl->tty->tty_fd, &buff[4], 1);
write(sl->tty->tty_fd, &buff[5], 1);
write(sl->tty->tty_fd, &buff[6], 1);
write(sl->tty->tty_fd, &buff[7], 1);
write(sl->tty->tty_fd, &buff[8], 1);
write(sl->tty->tty_fd, &buff[9], 1);
// debug
sleep(1);
if (read(fileno(stdin), &c, 1) > 0)
break;
}
return EXIT_SUCCESS;
}
【问题讨论】:
-
这可能与芯片的FIFO(en.wikipedia.org/wiki/16550_UART#The_16550_FIFO)有关吗? 10 不是标准尺寸之一,这可能会导致延迟。
-
我正在使用 Gateworks Ventana GW5100 gateworks.com/product/item/ventana-gw5100-network-processor
标签: linux serial-port embedded-linux uart