1

Input hardware: BeagleBone Black, with some GNU/Linux distro running on it.

What I want to achieve: I want to set some UART peripheral to 921600 baud value, and be able to set the other serial-associated settings (e.g. start/stop bits, parity, data bits, hw flow control, etc).

By far, in Linux, I have found at least three ways of configuring this parameters:

  1. Using struct termios form termios.h header file.
  2. Using struct termios2 from asm/termios.h header file.
  3. Using the stty(1) GNU/Linux utility.

What's the problem:

With the first method I can't use the 921600 baud rate value (there's no define for such higher value, it only goes up to 230400 baud. So this method won't work.

The second method offers me one way to change custom baud rate values, but is also tricky because it doesn't offer some functions like tcgetattr(), tcsendbreak(), tcflush(), and so one. This functions are present in the first-described method, and I can't include both header files termios.h and asm/termios.h because of (1).

The last method also don't work, or at least it doesn't work for all the settings I want to make. This is the current method I'm using, I'm opening the targeted file, I get one file descriptor, to that file descriptor I set the communication parameters (baud (first i set one lower value), parity, start/stop bits, etc) using the first method, and then I use stty(1) utility to change (override) the baud rate value to 921600 (I make a system(...) function call to perform this).

This method won't work if I want to change the HW flow control for example (it won't override that setting, just like happens with the baud value).

What are the solutions?

Is it ok to mix two methods of setting parameters to a UART-communication link like this?

Community
  • 1
  • 1
mariusmmg2
  • 713
  • 18
  • 37

2 Answers2

0

IMHO, using system and stty from a C or C++ program is not the way to go (system is known as a poor security practice at first).

After reading you related questions, my advice would be to only declare in you main module, namespace or class some wrapper functions for all the features you want to use from both termios.h and asm/termios.h.

Then you define them in two different compilation units (c or c++ source files), first dealing with termios.h, the latter with asm/termios.h

If that does not work, the last way would be to carefully merge declarations from termios.h and asm/termios.h in a custom local_termios.h managed in your own sources and include it. This of course leads to non portable code, but anyway as soon as you use asm/termios.h you loose compatibility.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

You may use setserial console utility:

1) Get baud_base value from setserial output

setserial -a /dev/<...>

2) Calculate divisor = baud_base / desired_baud_rate

For example if baud_base = 3000000 (3MHz):

baud_rate = 115200 -> divisor = 26.04 (approximately 26)
baud_rate = 230400 -> divisor = 13.02 (approximately 13)
baud_rate = 921600 -> divisor = 3.26

3.26 is too much to set divisor=3 and too little to set divisor=4.

So, in this case you can't use baud_rate=921600 because of hardware limitations. You may choose divisor=3 (baud_rate=1000000) or divisor=4 (baud_rate=750000). These baud rates are not standart, but possible.

stty -F /dev/<...> 9600 -icrnl -ixon -crtscts -parenb # desired UART settings
setserial /dev/<...> spd_cust  # use custom value for divisor
setserial /dev/<...> divisor 3  # set custom value for divisor
stty -F /dev/<...> 38400 # activate setserial settings
# now baud_rate is (baud_base / divisor)
petrmikheev
  • 342
  • 1
  • 6
  • `setserial` outputs me `Cannot set serial info: Invalid argument` when trying to set the `baud_base` parameter. – mariusmmg2 Jun 15 '16 at 11:37
  • Are you sure that your hardware supports 921600 baud rate? Try `setserial -a /dev/<...>` to see available information about serial port. – petrmikheev Jun 15 '16 at 13:15
  • Likely that baud_base is fixed by hardware, so right way is: 1. See current baud_base by `setserial -a`; 2. Calculate divisor for desired baud_rate; 3. Use `setserial ... spd_cust` and `setserial ... divisor` to set divisor – petrmikheev Jun 15 '16 at 13:33
  • Yes, the hardware supports this baud value (I can set it with `minicom` and `stty` tools). The `baud_base` reported by `setserial` tool is `3000000`. – mariusmmg2 Jun 16 '16 at 10:24
  • I have updated my answer. `stty` suggests a list of standart baud rates. It doesn't mean that your device supports it. – petrmikheev Jun 16 '16 at 13:20
  • Then why the communication is working at around ~`921600`baud (+-2% variation) when I set it at `921600` using `stty`, if the HW doesn't support it? (I measured this using an oscilloscope). – mariusmmg2 Jun 16 '16 at 21:42
  • Well. It means that BeagleBone can variate baud_base. I am sorry, I misunderstood your question. Could you show `stty` command that doesn't work? Does it print some error message? – petrmikheev Jun 17 '16 at 09:14
  • I did the following thing: I opened the `/dev/ttyO2` `UART`-associated file via `open(2)` system call, then I used `struct termios` to make the settings (number of data bits - 8, hardware flow control - off, etc), apply the settings via `tcsetattr(3)` system call, and then, the last step I did is running this command for setting such higher baud: `sudo stty -F /dev/ttyS2 921600` using `system(3)` function call. `stty` won't fail, I executed the command from command line and there was no output, which tells me that everything's fine. – mariusmmg2 Jun 17 '16 at 12:32
  • The only problem is that the `stty` utility will somehow override the settings that I previously made with `struct termios`. And I'm also confused if it's right what I'm just doing, do I violate some of OS security system? I mean, since I `open(2)` some file, I'm expecting that the current process will own that resource, and if some other process gets its hands over it (like `stty` in this case), shouldn't this lead into some undefined behavior? – mariusmmg2 Jun 17 '16 at 12:43
  • Try to call `stty` before `open(2)` – petrmikheev Jun 17 '16 at 13:15