Dear folks,

I noticed that the bit timing of the UART in the WR703N / AR9331
device is inaccurate and provide a patch to improve timing accuracy.

I suppose to change
    #define AR933X_UART_MAX_STEP    0xffff
to
    #define AR933X_UART_MAX_STEP    0x3333
in
    linux-3.10.32/drivers/tty/serial/ar933x_uart.c

The maximum value of UART_STEP should be 13107 as suggested by the
AR9331 datasheet.
See section 6.2.3:
    This value should range between 1310-13107 to
    maintain a better than +5% accuracy.
13107 corresponds to 0x3333.

I did a detailed timing analysis using an oscilloscope. I'm using a
different version of picocom which in turn uses termios2 to support
arbitrary baud rates [2]. These are my findings. See [3] for the
screenshots.


Sending ASCII 'U' = 0x55 = 0b01010101
This results in a nice square wave with the start and stop bit. The
bit timing is generated from the 25 MHz internal frequency by a
fractional baud rate generator. This is state of the art to generate
'odd' baud rates as 115200 from 'even' clock rates as 25 MHz.

The setting of UART_CLOCK_SCALE and UART_CLOCK_STEP determine the bit
rate of the UART. These settings are dynamically calculated when
changing the baud rate.

On: BARRIER BREAKER (Bleeding Edge, r39757)
Linux myhost 3.10.32 #1 Fri Feb 28 11:03:52 CET 2014 mips GNU/Linux

Baud 115200
Screenshot 10 - 22

You can see a significant jitter of each bit time. At this baud rate
this is not yet a problem.

Baud 921600
Screenshot 23 - 38

At this baud rate the jitter already accumulated to a significant
portion of the bit time. This can make the connection unreliable.

Baud 500000
Screenshot 39 - 41

The setting of UART_BAUD_STEP is much to high resulting in a jitter
that prevented me from having a reliable loopback connection.

I assume that for

Uart Clock:        25000000
Uart Baud:           500000

the kernel calculates the following value

Uart Scale:              15
Uart Step:            41943

This gist [1] for a user-landed code from the driver.

The granulation of the bit timing is 640 nsec and the UART_STEP is
41943. This value violates the recommendation from the data sheet.

I then applied my proposed change.

New Kernel with patch 104-tty-ar933x_uart-fix-clock-step-max.patch applied
Linux myhost 3.10.32 #1 Fri Feb 28 17:00:25 CET 2014 mips GNU/Linux

115200 Baud
[  182.150000] ar933x_uart_get_scale_step: clk 25000000, baud 115200,
scale 20, step 12683
Screenshot 42
compare to screenshot 10 and see that the jitter is a little smaller.

500000 Baud
[  426.870000] ar933x_uart_get_scale_step: clk 25000000, baud 500000,
scale 4, step 13107
Screenshot 43
As remainder(25E6, 5E5) is 0 there is no jitter with this
configuration. The bit timing is near perfect.

1 MBaud
[  690.900000] ar933x_uart_get_scale_step: clk 25000000, baud 1000000,
scale 1, step 10485
Screenshot 44, 45

2 MBaud
[  804.230000] ar933x_uart_get_scale_step: clk 25000000, baud 2000000,
scale 0, step 10485
Screenshot 46, 47

3 MBaud
The code fails so I propose to work on that ...
[  919.830000] ar933x_uart_get_scale_step: clk 25000000, baud 115200,
scale 20, step 12683

921600 Baud
[  993.680000] ar933x_uart_get_scale_step: clk 25000000, baud 921600,
scale 1, step 9663
Screenshot 48, 49
Finally, for the highest baudrate that is supported by an unpatched
picoterm the timing is nearly perfect, too.

Here is the patch:

Signed-off-by: Alex Aaron Walker <[email protected]>
---
Index: linux-3.10.32/drivers/tty/serial/ar933x_uart.c
===================================================================
--- linux-3.10.32.orig/drivers/tty/serial/ar933x_uart.c 2014-02-28
12:12:03.356386552 +0100
+++ linux-3.10.32/drivers/tty/serial/ar933x_uart.c      2014-02-28
12:15:21.716502356 +0100
@@ -33,7 +33,7 @@
 #define DRIVER_NAME "ar933x-uart"

 #define AR933X_UART_MAX_SCALE  0xff
-#define AR933X_UART_MAX_STEP   0xffff
+#define AR933X_UART_MAX_STEP   0x3333

 #define AR933X_UART_MIN_BAUD   300
 #define AR933X_UART_MAX_BAUD   3000000
@@ -221,6 +221,7 @@
                        *step = tstep;
                }
        }
+       printk("ar933x_uart_get_scale_step: clk %u, baud %u, scale %u,
step %u\n", clk, baud, *scale, *step);
 }

 static void ar933x_uart_set_termios(struct uart_port *port,

--

All feedback welcome

Alex

[1] https://gist.github.com/anonymous/9275937
[2] https://github.com/jmesmon/picocom.git
[3] https://plus.google.com/113941111747937474864/posts/ZnmUHycHXbJ
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to