在测试接收一个 1Mbps 串口数据的驱动上,RK3506 平台有时候启动后会有报错:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[ 23.781504] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.783156] ttyS4: Frame error!
[ 23.783175] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.785058] ttyS4: Frame error!
[ 23.785077] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.786474] ttyS4: Frame error!
[ 23.786483] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.788138] ttyS4: Frame error!
[ 23.788146] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.789813] ttyS4: Frame error!
[ 23.789825] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.791473] ttyS4: Frame error!
[ 23.791483] ttyS4: maybe rx pin is low or baudrate is not correct!
[ 23.793137] ttyS4: Frame error!
|
但这个错误出现几率不高,一旦出现会一直持续报错,断电重启后较大几率会消失。
所以高度怀疑是高波特率通信的电气兼容问题,通过查看内部 UART 时钟发现:
1
2
3
4
5
6
7
8
|
$ sudo cat /sys/kernel/debug/clk/sclk_uart1/clk_rate
24000000
$ sudo cat /sys/kernel/debug/clk/sclk_uart2/clk_rate
24000000
$ sudo cat /sys/kernel/debug/clk/sclk_uart3/clk_rate
24000000
$ sudo cat /sys/kernel/debug/clk/sclk_uart4/clk_rate
16000000
|
串口 uart1-3 都使用的115200波特率,时钟频率比使用1M波特率的 uart4 更高,这就奇怪了,
理论上通信波特率越高,时钟频率应该更高。
而且 uart 是16倍过采样,这种情况下,16M 时钟对于 1Mbps 的通信而言,没有任何余量,
任何电气上的影响延迟都会影响通信。所以怀疑是这个地方的问题。
源码文件在 drivers/tty/serial/8250/8250_dw.c中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
#ifndef CONFIG_ARCH_ROCKCHIP
unsigned long newrate = tty_termios_baud_rate(termios) * 16;
#endif
struct dw8250_data *d = to_dw8250_data(p->private_data);
long rate;
#ifdef CONFIG_ARCH_ROCKCHIP
unsigned int baud = tty_termios_baud_rate(termios);
unsigned int rate_temp, diff;
#endif
int ret;
clk_disable_unprepare(d->clk);
#ifdef CONFIG_ARCH_ROCKCHIP
if (d->clk) {
if (baud <= 115200)
rate = 24000000;
else if (baud == 230400)
rate = baud * 16 * 2;
else if (baud == 1152000)
rate = baud * 16 * 2;
else
rate = baud * 16;
ret = clk_set_rate(d->clk, rate);
rate_temp = clk_get_rate(d->clk);
diff = rate * 20 / 1000;
|
这里可以看到,115200 波特率一下时钟固定为24M,然后针对 230400/1152000 做了特殊处理,其他情况下,时钟频率就只有默认的16倍了,对于过采样而言,没有余量。
修改的话,比较简单,可以考虑将115200到1152000之间,统一做倍频处理:
1
2
3
4
5
6
|
if (baud <= 115200)
rate = 24000000;
else if (baud <= 1152000)
rate = baud * 16 * 2;
else
rate = baud * 16;
|
然后重新构建内核镜像并刷入,经过多次重启和断电测试,报错消失。
虽然可以通过优化电气连接等方法避免,但是某些情况也不是很方便做到,提高时钟频率算是一个
更为合适的做法。