UART 500k baud

How can I set the speed of ttyO4 to exactly 500k baud? If I use
stty -F /dev/ttyO4 500000
then the baud rate is actually 533333.

I’m trying to communicate with an AtMega328 (basically an Arduino), and the baud rate is exactly 500000. For HW reasons, 500k is ideal, and I do not wish to change it.

When I was doing this on the Raspberry Pi on ttyAMA0, I needed to add
`
init_uart_clock=8000000

`
to /boot/config.txt, so that the UART clock would be fast enough to allow 500k baud.

Is there something similar I need to do on the BBB to get exactly 500k baud?

After reading part of the TRM, it looks like it might be possible, but I need some help implementing it.

See TRM sections:
19.3.8 (in regard to the UART clock setup)

19.5.1 (in regard to the UART related registers)

The UART clock runs at 48MHz. There are two divisors available; 13 and 16. After that, you use a prescaler to get the right baud rate.

According to 19.3.8:

  1. UART 16x mode (≤230.4 Kbits/s), UART16x ≤460Kbits/s if MDR3[1] is set
  2. UART 16x mode with autobauding (≥1200 bits/s and ≤115.2 Kbits/s) if MDR3[1] is not set
  3. UART 13x mode (≥460.8 Kbits/s) if MDR3[1] is not set

It looks like in 16x mode, the highest rated speed is <= 460k, but it’s possible to get exactly 3m (16 divisor, and no prescaler, I assume), so this almost certainly isn’t correct (unless I’m missing something). This is probably just because any common UART speed over 460k with a 16x divisor isn’t possible without a large error.

It looks like the divisor is determined by MDR1[2:0], and the prescaler is stored in DL (DLH and DLL).

I think what I need is a divisor of 16, and a prescaler of 6. 48000000 / 16 / 6 = 500000.

Can somebody please help me configure it? Through the terminal would be fine, but ultimately I’m programming in C (compiled with gcc), so that would be even better.

Sounds like something that would need to be mangled in the driver, have
a read of the uart driver source code and see how it sets up the baud
rate. It might possibly expose an interface somewhere to do it.

Cheers,
Jack.

Sounds like something that would need to be mangled in the driver, have
a read of the uart driver source code and see how it sets up the baud
rate. It might possibly expose an interface somewhere to do it.

Cheers,
Jack.

Sounds like something that would need to be mangled in the driver, have
a read of the uart driver source code and see how it sets up the baud
rate. It might possibly expose an interface somewhere to do it.

Cheers,
Jack.

[snip]

Sounds like something that would need to be mangled in the driver, have
a read of the uart driver source code and see how it sets up the baud
rate. It might possibly expose an interface somewhere to do it.

  The logic for all this is in drivers/tty/serial/omap-serial.c:
serial_omap_set_termios() and friends. In older kernels you had to hack
serial_omap_get_divisor() to return the right thing (i.e. 16) for
non-standard baud rates or you would see the behaviour that Matthew
is getting.

  Some judicious pr_notice()s in that file should reveal what is going
on, though, and from there hardwiring 500kbaud to work right should be
relatively simple - I used to keep having to do it for my own favourite
baud rate, 1M, and never had a problem.

  However, if you are up to latest & greatest, 3.11rc1 seems to have
code which should make

cfsetispeed(t, B500000);
cfsetospee(t, B500000);
tcsetattr(fd, TCSANOW, &t)

  "just work". I've not tested it though ..

Richard.

It looks like in function
`
serial_omap_get_divisor

is where a change needs to be made.
if (baud > OMAP_MODE13X_SPEED && baud != 3000000)

`
should be

`
if (baud > OMAP_MODE13X_SPEED && (baud % 500000))

`
which would allow 500k, 1m, 1.5m, and 3m. Right?

So, where is this file? Is it part of the Kernel source code? Do I need to figure out how to get the source code, and compile the kernel? Is there a way this change can be submitted to the code maintainers, have it officially implemented, and have it be in an update?

I’m fairly new to Linux (about 6 months), and I’m still learning a lot. What do you recommend I do?

And in function
`
serial_omap_set_termios

`

`
if (baud > 230400 && baud != 3000000)

`

should beif (baud > 230400 && (baud % 500000))

It looks like in function
>
serial_omap_get_divisor
>
is where a change needs to be made.
>
if(baud >OMAP_MODE13X_SPEED &&baud !=3000000)
>
should be
>
if(baud >OMAP_MODE13X_SPEED &&(baud %500000))
>
which would allow 500k, 1m, 1.5m, and 3m. Right?

So, where is this file? Is it part of the Kernel source code?

  It is.

Do I need
to figure out how to get the source code, and compile the kernel?

  Yes (or get someone to do it for you, of course).

  You could also just drive the UART yourself from userspace and
toggle the registers directly via mmap()ing /dev/mem, but that will
be slow and there is going to be a problem if the kernel tries to
poke those registers too - eg. because it wants to suspend your
UART.

Is
there a way this change can be submitted to the code maintainers, have
it officially implemented, and have it be in an update?

  I think it's been fixed in 3.11rc1, so I believe that's already been
done (though someone should correct me if I'm wrong?)

I'm fairly new to Linux (about 6 months), and I'm still learning a lot.
What do you recommend I do?

  If I were you, I'd learn how to build a kernel and fix it in your
tree. but depending on how you got your distribution, it could be
quite a lot of work.

Richard.

So how do I upgrade to 3.11rc1 to take advantage of it? I’m using a BBB with what OS came on it. “uname -r” prints “3.8.13”. I’ve done “opkg update” and “opkg upgrade”, but that’s about it.

I found drivers/tty/serial/omap-serial.c from 3.11, and it looks like it does indeed have the support!

You "should" just be able to pull a kernel - I use Tony Lindgren's
tree:

git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git

  omap-for-v3.11/fixes seems to boot for me on Beagle xM at present,
but support for DM3730 is dodgy at present (I have a wierd "USB PHYs
disappearing problem to debug) and I don't know what the status of
BBB is, but the AM335x support is a right old mess.

  If I were you, I would hack the kernel you are currently using
and wait for support to improve. If you're on BBB, I think this is
some variant of 3.8.

  beagleboard.org points you to the Angstrom build instructions:
<http://www.angstrom-distribution.org/building-angstrom> .

  If you're not terribly technical, this may be beyond you, but it
is probably worth having a go with the angstrom autobuilder, in
case it happens to do what you want - I'm afraid I've not had
great luck with it in the past, but that was some time ago ..

Richard.

The kernel you're looking to build is at [1]. The instructions on how to
build it are all on that page page. I would initially build and replace
the kernel on your board and check it boots. Then start hacking :slight_smile:

I wouldn't try going to 3.11-rcX just yet, the BBB is not fully
supported and you will run into a lot of problems. Easiest way is to
stick with the supported 3.8 and make custom changes locally until the
supported kernel is uprevved to 3.11 or higher (tip: this won't be any
time soon).

[1] https://github.com/beagleboard/kernel/tree/3.8

[snip]

[1] https://github.com/beagleboard/kernel/tree/3.8

Aha! So that is where it is - many thanks for the pointer :slight_smile:

Richard.