BeagleBoard xM, UART1 RTS line not working

Having trouble getting UART1 running on the Beagleboard-xM (rev C).
UART1 pins are on expansion connector P9 which is the 2x14 header. I
have gotten the TXD RXD and CTS signals of UART1 to all work
correctly, but the RTS signal will not function at all.

RTS is an output and should be either at 0V or 1.8V. The docs say
UART1 RTS sppears on P9 pin 10, and it is mux mode 0. I am building
the 3.1.4 RCN-EE kernel from source, so I have added the appropriate
OMAP3_MUX macro calls to the "omap_board_mux board_mux" array, so that
the muxing of the processor pins is set. UART1 RTS is mux mode 0
anyways so it should just work by default.

I have spent a fair amount of time on this and my conclusion is there
is either a
bug in the kernel driver for the UART RTS handling code, or the
documentation on the Beagleboard xM is inaccurate and RTS is not
really on P9 pin 10 at mux mode 0.

Can anyone assist, or point me to the right place to get assistance
with this? You can also email me at epj -at- newpointtech (dot) com.
Thank you.

You could have a bad solder connection on the connector. Have you tried probing the pad on the PCB?

Gerald

Yes, I’ve probed the soldered pin on the BB-xM directly. I’ve actually tried two Beagleboard-xM boards, and both exhibit the same behavior.

Yes I probed the pad directly (rather than the connector) and I’ve even tried two different Beagleboards, with the same result. Note that when I say UART1 I really mean the UART corresponding to /dev/ttyO1. The BB documentation talks about /dev/ttyO1 as being UART2. I know I have the right UART because the TXD RXD and CTS pins are all working; I’m only having trouble with the RTS pin.

Here’s the code I added to mux the UART1 pins, found in arch/arm/omap2-mach/board-omap3beagle.c:
static struct omap_board_mux board_mux[] __initdata = {
/* configure the DM3730 processor pads for /dev/ttyO1. /
OMAP3_MUX(MCBSP3_FSX,OMAP_MUX_MODE1 | OMAP_PIN_INPUT), /
uart_rx /
OMAP3_MUX(UART2_TX,OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), /
uart_tx /
OMAP3_MUX(UART2_CTS,OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), /
uart_cts /
OMAP3_MUX(UART2_RTS,OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), /
uart_rts */
{ .reg_offset = OMAP_MUX_TERMINATOR },
};

Here’s a snippet of my Linux application code to set the RTS line from user space:
fd = open("/dev/ttyO1",O_RDWR);
int ioctl_arg;
int status = ioctl(fd,TIOCMGET,&ioctl_arg);
if (enable_RTS) {
ioctl_arg |= TIOCM_RTS;
} else {

ioctl_arg &= ~(int)TIOCM_RTS;

}
status = ioctl(fd,TIOCMSET,&ioctl_arg);
/* now probe the RTS pin, before closing the port */
I know the above code normally works because we do this all the time in Linux with standard PC computers running Linux.

But when I probe connector P9 pin 10 (the RTS signal), it is always grounded at 0VDC. In fact, I even tried putting an external pullup resistor (10k ohm) to 1.8VDC, thinking that maybe the RTS output pin from the DM3730 is some kind of an open-collector/open-drain output. But even with the pullup resistor, the signal at P9 pin 10 is always grounded at 0VDC (regardless of whether RTS is asserted or deasserted in software). So the RTS pin (P9 pin 10) is somehow electrically connected to ground internally by the DM3730, regardless of the RTS software setting in the Linux kernel.

I double checked everything a hundred times at this point, and it all points to a bug somewhere, either in hardware, the kernel driver, or the documentation.

Where in the kernel source tree is the RTS handling for the OMAP3 processor serial ports handled? I looked around the kernel tree but it is quite a maze and hard to actually find the logic that is setting the OMAP3 registers to set/clear RTS. If I can find this code, I can add some kernel debug so I can see if the code is even being reached, and if so, what is it doing to the OMAP3 registers. I can then compare what it’s doing with what the DM3730 TRM says it should be doing.

Again, any help is greatly appreciated. We have an order for 200 of these units, but we must have this UART working, and it must support RTS/CTS flow control.
-Eric

You need to check your pin muxing and mkae sure it is set up correctly. You cam also check here https://groups.google.com/forum/?fromgroups#!searchin/beagleboard/RTS

Gerald

Believe me I’ve checked the 4 linus that control the pin muxing a hundred times, and it is set up correct according to the documentation. See my above post for what I’ve set the pin muxing to. The RTS signal for its pin is mux mode 0 anyways, which is the default. I’ve even looked through the kernel source macros to see if the DM3730 register that controls the muxing of processor pin “AB25” is correct (and it is correct at address 0x48002174 high-order 16 bits). This address corresponds correctly to the one shown the DM3730 TRM (sprugn4o.pdf) on page 2465 in table 13-4.

I’ve also searched this forum ad-nauseum for past posts on the RTS signal, but I found nothing related to my issues. Most UART/serial applications will work without CTS/RTS and only need TX and RX data lines. So people who have used the BB-xM’s extra UART before probably wouldn’t have even noticed if RTS was broken.

What I really need is for someone to point me to the right area in the OMAP3 kernel source files where the kernel actually writes to the UART2 hardware register that controls the RTS line when a user-space application does an “ioctl(fd,TIOCMSET,…)”. Then I could put some kernel debug in and see if the kernel is doing what the DM3730 TRM says it should be doing to assert/deassert RTS. This would eliminate a bug in the Linux kernel.

Once I’m satisfied the Linux kernel is doing what it should be doing for RTS, then I can move to the hardware. For example, the UART2 RTS pin also corresponds to GPIO 145 (in mux mode 4). So if I put the pin into mux mode 4, and try to control GPIO 145 from software, does the pin do anything?

Thank you,
-Eric

Hello,

we are developing an application that needs half duplex serial
communication from some UART port, we are trying UART1 and UART2 on
the BeagleBone RevA3. We are using ubuntu for arm.
We need to use the RTS pin to toggle the direction port of the half
duplex communication. We've tried to enable the RTS on both UARTs with
this configuration of pins:

For UART1:
root@omap:/sys/kernel/debug/omap_mux# cat uart1_txd
name: uart1_txd.uart1_txd (0x44e10984/0x984 = 0x0000), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE0
signals: uart1_txd | mmc2_sdwp | NA | i2c1_scl | NA |
pr1_uart0_txd_mux1 | NA | gpio0_15
root@omap:/sys/kernel/debug/omap_mux# cat uart1_rxd
name: uart1_rxd.uart1_rxd (0x44e10980/0x980 = 0x0030), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE0
signals: uart1_rxd | mmc1_sdwp | NA | i2c1_sda | NA |
pr1_uart0_rxd_mux1 | NA | gpio0_14
root@omap:/sys/kernel/debug/omap_mux# cat uart1_rtsn
name: uart1_rtsn.uart1_rtsn (0x44e1097c/0x97c = 0x0030), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE0
signals: uart1_rtsn | NA | d_can0_rx | i2c2_scl | spi1_cs1 | NA | NA |
gpio0_13
root@omap:/sys/kernel/debug/omap_mux# cat uart1_ctsn
name: uart1_ctsn.uart1_ctsn (0x44e10978/0x978 = 0x0000), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE0
signals: uart1_ctsn | NA | d_can0_tx | i2c2_sda | spi1_cs0 | NA | NA |
gpio0_12

For UART2:
root@omap:/sys/kernel/debug/omap_mux# cat spi0_d0
name: spi0_d0.uart2_txd (0x44e10954/0x954 = 0x0001), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE1
signals: spi0_d0 | uart2_txd | i2c2_scl | NA | NA | NA | NA | gpio0_3
root@omap:/sys/kernel/debug/omap_mux# cat spi0_sclk
name: spi0_sclk.uart2_rxd (0x44e10950/0x950 = 0x0031), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE1
signals: spi0_sclk | uart2_rxd | i2c2_sda | NA | NA | NA | NA |
gpio0_2
root@omap:/sys/kernel/debug/omap_mux# cat lcd_data9
name: lcd_data9.uart2_rtsn (0x44e108c4/0x8c4 = 0x002e), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE6
signals: lcd_data9 | gpmc_a13 | NA | mcasp0_fsx | NA | NA | uart2_rtsn

gpio2_15

root@omap:/sys/kernel/debug/omap_mux# cat lcd_data8
name: lcd_data8.uart2_ctsn (0x44e108c0/0x8c0 = 0x0006), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE6
signals: lcd_data8 | gpmc_a12 | NA | mcasp0_aclkx | NA | NA |
uart2_ctsn | gpio2_14

We aren't seeing anything in the RTS pin of any of the 2 ports. (But
the communication works).
Maybe your problem is related to ours.

Thank you very much, we look forward for any help on this issue.

Eric <epj1969@gmail.com> [2012-03-09 12:04:18]:

What I really need is for someone to point me to the right area in the
OMAP3 kernel source files where the kernel actually writes to the UART2
hardware register that controls the RTS line when a user-space application
does an "ioctl(fd,TIOCMSET,...)".

Please guide me? :stuck_out_tongue:

http://lxr.free-electrons.com/source/drivers/tty/serial/omap-serial.c?a=arm#L419

-- ynezz

Hi,

That code seems to be ok, in fact it belongs to the linux com port examples, but it also didn’t work for me on FTDI chips.Try it:
tcdrain(fd);

int ioctl_arg;
int status = ioctl(fd,TIOCMGET,&ioctl_arg);
if (enable_RTS) {
ioctl_arg |= TIOCM_RTS;
} else {

ioctl_arg &= ~(int)TIOCM_RTS;

}
status = ioctl(fd,TIOCMSET,&ioctl_arg);
tcdrain(fd);

man tcdrain
tcdrain() waits until all output written to the object referred to by fd has been transmitted.

Good luck,
Daniel

yah… please “guide me”, lol what is that too much to ask here? i haven’t spent hours and hours of my life being a linux kernel hacker, and it would take me hours to go through the learning curve to find the right source file where the MCR register is being set. I don’t know anything about the organization of the the thousands of source files that make up the linux kernel and its drivers. so having another person spend 2 seconds to point me to the right location is a huge help, and then i can do the legwork from there.

regardless, thank you for “guiding” a poor hapless neophyte like myself, because in fact there is a bug in the OMAP serial kernel driver, right in that exact function that your link points to. didn’t you see the bug when you made that link in your post, or were you too busy being offended about having to collaborate with someone else who doesn’t know as much about the linux kernel source tree as you? lol i can see the RTS bug just by inspection, and i have now made the fix to the kernel driver code and RTS is now working for the beagleboard. in fact, RTS never could have worked with the existing code without some kind of fix.

line 436 of the source in your link has the following code:

    mcr |= [up](http://lxr.free-electrons.com/ident?a=arm;i=up)->mcr;

which OR’s in the value of the old MCR register, every time the MCR register is set to a new value. so once any flag is set, it can never be un-set because it constantly keeps the old flags by repeatedly OR’ing them in. this means that RTS is “always set” and it is impossible to un-set it, because of this line of code.

the fix is to only keep the flags from the old register that aren’t being controlled by the “serial_omap_set_mctrl” function, as follows on line 436:
mcr |= up->mcr & ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT1 | UART_MCR_OUT2 | UART_MCR_LOOP);
once you make this change, RTS works as it should.

i’d ask someone to guide me on how to permanently get this change into the kernel sources because i have no idea how that procedure works, but i’d need more “guidance” because i’m not inclined to spend the time it would take to get up to speed with linux kernel check-in procedures. so hopefully the next person who cares about RTS will just find the fix here in this post.

thanks for the help, seriously, it would have taken a lot longer without your link.
-eric

Eric <epj1969@gmail.com> [2012-03-12 06:43:07]:

the fix is to only keep the flags from the old register that aren't being
controlled by the "serial_omap_set_mctrl" function, as follows on line 436:
        mcr |= up->mcr & ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT1 |
UART_MCR_OUT2 | UART_MCR_LOOP);
once you make this change, RTS works as it should.

If I didn't overlooked something, then it seems like a nice catch. The strange
thing is, that the same code is in serial/pxa.c and serial/mfd.c, so it either
means, that it's not faulty at all, those two other platforms work differently
or nobody is using RTS/DTR these days :slight_smile:

i'd ask someone to guide me on how to permanently get this change into the
kernel sources because i have no idea how that procedure works, but i'd
need more "guidance" because i'm not inclined to spend the time it would
take to get up to speed with linux kernel check-in procedures.

Thank god, that not everybody is "not inclined to spend their time" on free
software, otherwise we won't be discussing your issue here today. It's really
that much to at least report it somewhere?

  ynezz@ryba:~/git/linux-2.6-allstable$ less Documentation/SubmittingPatches

and

  ynezz@ryba:~/git/linux-2.6-allstable$ scripts/get_maintainer.pl -f drivers/tty/serial/omap-serial.c

  Alan Cox <alan@linux.intel.com> (maintainer:SERIAL DRIVERS)
  Greg Kroah-Hartman <gregkh@linuxfoundation.org> (supporter:TTY LAYER)
  Grant Likely <grant.likely@secretlab.ca> (maintainer:OPEN FIRMWARE AND...)
  Rob Herring <rob.herring@calxeda.com> (maintainer:OPEN FIRMWARE AND...)
  linux-serial@vger.kernel.org (open list:SERIAL DRIVERS)
  linux-kernel@vger.kernel.org (open list)
  devicetree-discuss@lists.ozlabs.org (open list:OPEN FIRMWARE AND...)

and maybe authors would be interested also (from omap-serial.c header):

  * Authors:
  * Govindraj R <govindraj.raja@ti.com>
  * Thara Gopinath <thara@ti.com>

-- ynezz

well it’s a bug in those drivers too then. as i’m sure you know, people don’t write these kinds of drivers from scratch, they cut/paste from other similar drivers. so it’s probably the same buggy code being cut/paste from place to place. there’s no way it can possibly work the way it is now. i think part of the problem is that not many people care about RTS and DTR on an RS-232 port nowadays, they’re usually only used when you have a telephone modem.

and it’s not much at all for me to report it somewhere, and i’d be happy to spend the time to report it if someone would spend a few moments to point me to a FAQ with a simple procedure on how to report the bug, without adding in snarky comments that i’m not interested in bothering with. i don’t really have the time to research how to become a contributor to the omap-serial.c file, and i’m not interested in being poked fun at by the experts when i ask about posting the bug-fix. there are plenty of smart coders who can’t be bothered with the political procedure necessary to become an “insider”, so they can have their posts taken seriously. politics=boring waste of time.

dude i’m not offended by your comment at all-- i know you get a million people on this forum who won’t lift a finger to solve their problem, although it should have been clear from my first post that i’m not in that category. so when the experts “poke fun” at me and assume i’m an idiot, now i’m poking back at the experts. that’s all. peace and no harm no foul. :slight_smile:

-eric

Hello, thank you for your contribution, it has really saved us months
of work.
Can you tell us how to compile and change the serial module to be able
to use your patch?
Where did you get the sources from?

By the way, we are using ubuntu 11.10 for arm, not Angstrom if you
think that may change something.

Thank you!

Eric <epj1969@gmail.com> [2012-03-12 10:50:59]:

well it's a bug in those drivers too then.

Well, according to this patch[1] (actually tested by two guys), I'm really
unsure. It seems to me, that it's just a MCR register set function (as the
name suggests) and the bit fiddling(like clearing) is done in some upper
layer[2,3].

So according to this observations I think, that your fix isn't correct, but
I'm not an expert so don't take my assumptions seriously :slight_smile: Just add some
debug printk()s and find the root cause of the problem.

1. ARM: 6966/1: ep93xx: fix inverted RTS/DTR signals on uart1 - kernel/git/torvalds/linux.git - Linux kernel source tree
2. http://lxr.free-electrons.com/source/drivers/tty/serial/serial_core.c#L125
3. http://lxr.free-electrons.com/source/drivers/tty/serial/serial_core.c#L111

-- ynezz

i am using Ubuntu 11.10 for ARM also. however, the stock ubuntu kernel for ARM lacks a lot of the beagleboard-specific features. so i have replaced the ubuntu stock kernel with the rcn-ee kernel, which is available on github at https://github.com/RobertCNelson/stable-kernel. it looks like they’re up to version 3.2.10 already, whereas i grabbed the kernel a few months ago when the latest was 3.1.4. the change must be made in the omap-serial.c source file-- just follow my notes in the previous post.

Petr mentions that it is possible that my fix works around broken logic in another layer of the kernel, and that the “correct” fix would be made elsewhere. this is possible and he could be correct. i’m no expert in the linux tty/serial subsystem, but my fix makes RTS work correctly, where it didn’t function at all before. at some point i may research how it’s “supposed to be done”, but for now i can move forward with my project here.

-eric

Hi,

We are having some struggles fixing the rts in the beaglebone. As we posted in this thread we are also trying to make it work. We downloaded the latest robert kernel (from https://github.com/RobertCNelson/stable-kernel), modified the omap serial with your change, compiled (using build_kernel.sh) and put it in the sd card with ubuntu 11.10 (http://rcn-ee.net/deb/rootfs/oneiric/ubuntu-11.10-r5-minimal-armel.tar.xz we are using this one. We tried the r6 build and it didn’t boot.) using the script load_uImage.sh, but once we do that the card doesnt boot up any more. We have tried to change some parameters on the system.sh file, but the truth is that we really don’t now what steps we have to take nor what we are doing.
We changed in system.sh to use:
##For TI: OMAP3/4/AM35xx
ZRELADDR=0x80008000

We have wasted too much time in this (and we are really in a hurry) we would appreciate so much if you could send us some detailed instructions on how to fix the RTS problem in the beagle bone, and of course if you know any good source of information so that we know what to do if we encounter a similar problem with the kernel in the future.

Thank you so much!

When you build a new kernel, you also have to install the “modules” in /lib/modules/… maybe that’s why it didn’t boot? I’m not familiar with the load_uImage.sh script, so I don’t know what it’s supposed to do. Unfortunately I don’t really have time to type a complete detailed set of instructions because there is a lot to learn and do to get your own kernel up and running.

You say that after you install the new kernel image “the card doesnt boot up any more”. That could mean anything. What is the error?