From: rketcham <Ric...@gm...> - 2009-03-04 16:54:50
|
Hello, I'm trying to employ RTS and CTS through the BTUART. Unfortunately, it looks like something is amiss. When I write to the serial port, the RTS line is always brought low regardless if RTSCTS has been set or not. Also, I don't have to be sending anything for RTS to be driven low; I just have to open the port. Is this normal operation? I wouldn't think so... After observing these two features I tried communicating with my external device anyway. The external device would see RTS driven low and respond with driving CTS low but the serial driver never sees CTS change and so gets hung up waiting to send the data. I tried doing this myself by disabling RTSCTS, driving RTS low manually (ioctl) and waiting for CTS to be driven low in a while loop. However, the ioctl never returns with CTS as other than 0. Is there a known problem with the serial driver that causes this? Is there a simple way for me to fix this without getting into driver programming? If not, do you have any advice on what I need to edit? My buildroot revision is 1633. I have RTS on the Gumstix connected to RTS on my external device. I also have CTS on the Gumstix connected to CTS on my external device. Thanks, Rich Here is my code for setting up the serial port _fileDescriptor = open(devicePath.c_str(), O_RDWR | O_NOCTTY);//Open the port if (_fileDescriptor== -1) //Opening of port failed { fprintf(stderr,"open_port: Unable to open %s.\n", devicePath.c_str()); } int databits = 8;//Number of data bytes in packet. //Initialize to the default value. int BAUD = B115200; //115200 bits per sec int DATABITS = CS8;//8 data bits per packet int STOPBITS = ~CSTOPB; //1 stop bit int PARITY = 0; // 0 parity int PARITYON = ~PARENB;//Parity is not enabled. int status = 0; //Assume the port is set with the new comm settings. //Get the current options for the port... tcgetattr(_fileDescriptor, &_options); //Sellect the baud rate. switch(baudRate) { //115200: //Most likely according to the SDK. case baudRate_115200: BAUD = B115200; break; case baudRate_2400: BAUD = B2400; break; case baudRate_4800: BAUD = B4800; break; case baudRate_9600: BAUD = B9600; break; case baudRate_19200: BAUD = B19200; break; case baudRate_38400: BAUD = B38400; break; case baudRate_57600: BAUD = B57600; break; default: BAUD = B115200; //Default to the baud in the SDK } cfsetospeed(&_options, BAUD); cfsetispeed(&_options, BAUD); //Assign the number of data bits. switch(databits) { case 8: DATABITS = CS8; break; case 7: DATABITS = CS7; break; case 6: DATABITS = CS6; break; //Not likely but available. case 5: DATABITS = CS5; break; //Not likely but available. default: DATABITS = CS8; //Default to SDK value } _options.c_cflag &= ~CSIZE; /* Mask the character size bits */ _options.c_cflag |= DATABITS;/* Select 8 data bits */ //Assign the number of stop bits. switch(stopBits) { case stopBits__1_0: STOPBITS = ~CSTOPB;//Not 2 --> 1 stop bit _options.c_cflag &= STOPBITS;// stop bits break; case stopBits__2_0: STOPBITS = CSTOPB; //2 stop bits _options.c_cflag |= STOPBITS;// stop bits break; default: STOPBITS = ~CSTOPB; //Default to SDK value _options.c_cflag &= STOPBITS;// stop bits } //Set parity. switch(parity) { case parity_none: //No parity. PARITYON = ~PARENB; _options.c_cflag &=PARITYON; PARITY = 0; //Doesn't matter break; case parity_odd://Odd parity. PARITYON = PARENB; _options.c_cflag |=PARITYON; PARITY = PARODD; _options.c_cflag |= PARITY;//Odd Parity break; case parity_even://Even parity. PARITYON = PARENB; _options.c_cflag |=PARITYON; PARITY = ~PARODD; _options.c_cflag &= PARITY;//Even Parity break; default: //Default setting doesn't have parity checking. PARITYON = ~PARENB;//No parity _options.c_cflag &=PARITYON; PARITY = 0;//Doesn't matter } //set for non-canonical (raw processing, no echo, etc.) _options.c_iflag = IGNPAR; // ignore parity check close_port(int _options.c_oflag = 0; // raw output _options.c_lflag = 0; // raw input //Time-Outs -- won't work with NDELAY option in the call to open _options.c_cc[VMIN] = 0; // block reading until RX x characers. If x = 0, it is non-blocking. _options.c_cc[VTIME] = 1; // Inter-Character Timer -- i.e. timeout= x*.1 s //Set local mode and enable the receiver _options.c_cflag |= (CLOCAL | CREAD); _options.c_cflag |= CRTSCTS; //Turn on flow control //_options.c_cflag &= ~CRTSCTS; //Turn off flow control //Purge serial port buffers Purge(); //Set the new options for the port... status=tcsetattr(_fileDescriptor, TCSANOW, &_options); if (status != 0) //For error message printf("Setting com port didn't work!\n"); //else //printf("Setting com port did work!\n"); //Get the current options for theRead port... tcgetattr(_fileDescriptor, &_options); //Purge serial port buffers Purge(); -- View this message in context: http://www.nabble.com/Serial-Driver%2C-BTUART%2C--RTS-is-always-driven-low-and-CTS-is-never-seen-tp22334238p22334238.html Sent from the Gumstix mailing list archive at Nabble.com. |
From: Dave H. <dhy...@gm...> - 2009-03-04 17:10:43
|
Hi Rich, > I'm trying to employ RTS and CTS through the BTUART. Unfortunately, it looks > like something is amiss. When I write to the serial port, the RTS line is > always brought low regardless if RTSCTS has been set or not. Also, I don't > have to be sending anything for RTS to be driven low; I just have to open > the port. Is this normal operation? I wouldn't think so... > > After observing these two features I tried communicating with my external > device anyway. The external device would see RTS driven low and respond with > driving CTS low but the serial driver never sees CTS change and so gets hung > up waiting to send the data. I tried doing this myself by disabling RTSCTS, > driving RTS low manually (ioctl) and waiting for CTS to be driven low in a > while loop. However, the ioctl never returns with CTS as other than 0. > > Is there a known problem with the serial driver that causes this? Is there a > simple way for me to fix this without getting into driver programming? If > not, do you have any advice on what I need to edit? > > My buildroot revision is 1633. I have RTS on the Gumstix connected to RTS on > my external device. I also have CTS on the Gumstix connected to CTS on my > external device. Did you check the mux settings for the pins? If the pin is muxed to be a GPIO pin, for example, the serial driver would never see the CTS signal. -- Dave Hylands Shuswap, BC, Canada http://www.DaveHylands.com/ |
From: rketcham <Ric...@gm...> - 2009-03-04 17:38:54
|
> Did you check the mux settings for the pins? If the pin is muxed to be > a GPIO pin, for example, the serial driver would never see the CTS > signal. > Hi Dave, I have these settings: RTS # cat /proc/gpio/GPIO45 45 AF2 out clear CTS # cat /proc/gpio/GPIO44 44 AF1 in set TX # cat /proc/gpio/GPIO43 43 AF2 out set RX # cat /proc/gpio/GPIO42 42 AF1 in set -- View this message in context: http://www.nabble.com/Serial-Driver%2C-BTUART%2C--RTS-is-always-driven-low-and-CTS-is-never-seen-tp22334238p22335191.html Sent from the Gumstix mailing list archive at Nabble.com. |
From: Dave H. <dhy...@gm...> - 2009-03-05 16:24:48
|
Hi Rich, >> Did you check the mux settings for the pins? If the pin is muxed to be >> a GPIO pin, for example, the serial driver would never see the CTS >> signal. >> > > Hi Dave, > > I have these settings: > > RTS > # cat /proc/gpio/GPIO45 > 45 AF2 out clear > > CTS > # cat /proc/gpio/GPIO44 > 44 AF1 in set > > TX > # cat /proc/gpio/GPIO43 > 43 AF2 out set > > RX > # cat /proc/gpio/GPIO42 > 42 AF1 in set Those look right to me. Perhaps you could try using pxaregs to probe the serial port registers and see what they say. They should be detecting the CTS signal changing, in which case its some type of problem with the driver. -- Dave Hylands Shuswap, BC, Canada http://www.DaveHylands.com/ |
From: rketcham <Ric...@gm...> - 2009-03-05 17:36:31
|
> Those look right to me. > > Perhaps you could try using pxaregs to probe the serial port registers > and see what they say. They should be detecting the CTS signal > changing, in which case its some type of problem with the driver. > Hi Dave, Yea, I found the problem with the CTS line. My wire connecting to the header had become detached. So, that was my fault and it's working now. Unfortunately, I'm still having a problem. It looks like RTS isn't being toggled back to 3.3V after the data has been written. In fact, when the serial port is closed that's when RTS is deasserted and the serial device responds, which is too late to be able to read. Is there something that I'm missing in my settings that isn't allowing the driver to bring RTS back up? Rich -- View this message in context: http://www.nabble.com/Serial-Driver%2C-BTUART%2C--RTS-is-always-driven-low-and-CTS-is-never-seen-tp22334238p22356552.html Sent from the Gumstix mailing list archive at Nabble.com. |
From: rketcham <Ric...@gm...> - 2009-03-17 17:06:52
|
Dave Hylands wrote: > > Those look right to me. > > Perhaps you could try using pxaregs to probe the serial port registers > and see what they say. They should be detecting the CTS signal > changing, in which case its some type of problem with the driver. > Hi Dave, I thought that you would interested to know that I ended up changing tactics. I inserted a cp2101 between the gumstix USB port and my serial device. The driver for the cp2101 handled the flow control lines as expected and I'm now able to communicate with my serial device through Python. This leads me to conclude that the way the serial driver handles flow control is flawed. My buildroot version is 1633. Perhaps this problem has been fixed in later versions or in open embedded. If you have anymore information on this, I would be interesting in hearing about it. Thanks, Rich -- View this message in context: http://www.nabble.com/Serial-Driver%2C-BTUART%2C--RTS-is-always-driven-low-and-CTS-is-never-seen-tp22334238p22563757.html Sent from the Gumstix mailing list archive at Nabble.com. |
From: Dave H. <dhy...@gm...> - 2009-03-17 20:41:23
|
Hi Rich, > I thought that you would interested to know that I ended up changing > tactics. I inserted a cp2101 between the gumstix USB port and my serial > device. The driver for the cp2101 handled the flow control lines as expected > and I'm now able to communicate with my serial device through Python. This > leads me to conclude that the way the serial driver handles flow control is > flawed. Sounds like it. > My buildroot version is 1633. Perhaps this problem has been fixed in later > versions or in open embedded. If you have anymore information on this, I > would be interesting in hearing about it. I haven't got any further information, and I haven't really played with the CTS?RTS stuff other than to disable it. -- Dave Hylands Shuswap, BC, Canada http://www.DaveHylands.com/ |
From: Ned F. <nfo...@wh...> - 2009-03-17 21:08:18
|
Dave Hylands wrote: > Hi Rich, > >> I thought that you would interested to know that I ended up changing >> tactics. I inserted a cp2101 between the gumstix USB port and my serial >> device. The driver for the cp2101 handled the flow control lines as expected >> and I'm now able to communicate with my serial device through Python. This >> leads me to conclude that the way the serial driver handles flow control is >> flawed. > > Sounds like it. > >> My buildroot version is 1633. Perhaps this problem has been fixed in later >> versions or in open embedded. If you have anymore information on this, I >> would be interesting in hearing about it. > > I haven't got any further information, and I haven't really played > with the CTS?RTS stuff other than to disable it. I have used RTS with buildroot (not sure which, using 2.6.20 kernel). It certainly worked after a fashion. I needed it for control of an RS485 transmitter, but the timing was not right (releasing RTS before all the bits were actually transmitted). I had to modify <linux kernel>/drivers/serial/pxa.c to restore some lines that had been removed, as compared to a more standard driver. I think I used 8250.c as a model. -- Ned Forrester nfo...@wh... Oceanographic Systems Lab 508-289-2226 Applied Ocean Physics and Engineering Dept. Woods Hole Oceanographic Institution Woods Hole, MA 02543, USA http://www.whoi.edu/sbl/liteSite.do?litesiteid=7212 http://www.whoi.edu/hpb/Site.do?id=1532 http://www.whoi.edu/page.do?pid=10079 |
From: <pa...@pa...> - 2009-03-18 02:42:46
|
Ned Forrester wrote: > I had to modify > <linux kernel>/drivers/serial/pxa.c > to restore some lines that had been removed, as compared to a more > standard driver. I think I used 8250.c as a model. Interesting... Was this code that explicitly drives RTS/CTS, or code that enables auto-flow-control (AFE) ? I am currently investigating Bluetooth performance problems. With heavy traffic over BNEP it is fairly easy to bring the PXA <-> PBA31308 serial connection out-of-sync. This shows up as "h4_recv: Unknown HCI packet" in /proc/kmsg, and traffic occasionally pauses for a few seconds. Presumably this is caused by UART FIFO overflows. Enabling auto-flow-control with "pxaregs BTMCR 0x2b" makes the connection much more reliable for me. For some reason Linux only sets the AFE bit on the HWUART. Pascal |
From: Ned F. <nfo...@wh...> - 2009-03-18 14:00:34
|
pa...@pa... wrote: > Ned Forrester wrote: >> I had to modify >> <linux kernel>/drivers/serial/pxa.c >> to restore some lines that had been removed, as compared to a more >> standard driver. I think I used 8250.c as a model. > > Interesting... Was this code that explicitly drives RTS/CTS, > or code that enables auto-flow-control (AFE) ? > > I am currently investigating Bluetooth performance problems. > With heavy traffic over BNEP it is fairly easy to bring the > PXA <-> PBA31308 serial connection out-of-sync. > This shows up as "h4_recv: Unknown HCI packet" in /proc/kmsg, > and traffic occasionally pauses for a few seconds. > Presumably this is caused by UART FIFO overflows. > > Enabling auto-flow-control with "pxaregs BTMCR 0x2b" makes > the connection much more reliable for me. For some reason > Linux only sets the AFE bit on the HWUART. I don't think what I was doing will help you very much, but just in case, here is most of the story. I use RTS to enable a transmitter on a multi-drop 2-wire line, similar to RS485. I was trying to restore the "standard" behavior of certain ioctl calls to a serial port that are supposed to return after the transmitted characters have actually been transmitted on the line (that is matching the behavior to that of an x86 Fedora laptop). I used only standard ioctl calls to control the state of RTS. The changes I made to pxa.c are contained in the following patch diff. Note that this patch applies to kernel 2.6.20; I have not paid any attention to changes made in pxa.c since then. So, from examining my commnents, it looks like RTS always followed the ioctl commands, and the changes I made were to ensure that I would know that the TX shift register was really empty, even at the expense of learning it long after the fact. Without the changes, the test ioctl calls returned too soon, causing me to drop RTS before transmission was complete. With the changes, the reulting delays between the end of transmit and when I was able to drop RTS matched the behavior of my laptop running standard issue Fedora. The latter uses a different driver than pxa.c, obviously; I think, but I am not sure, that the driver was 8250.c. ------------- --- pxa.c.orig 2007-02-23 16:28:13.000000000 +0000 +++ pxa.c 2007-07-03 16:08:42.000000000 +0000 @@ -239,11 +239,24 @@ static inline irqreturn_t serial_pxa_irq struct uart_pxa_port *up = dev_id; unsigned int iir, lsr; + /* NCF, 8/7/06, RTS should not be changed unless in CRTSCTS mode, + * the needed info is stored in uart_pxa_port->port.info->flags by + * the serial_core + */ + if ( up->port.info->flags & UIF_CTS_FLOW ) + /* NCF end */ serial_out(up, UART_MCR, serial_in(up, UART_MCR) & ~UART_MCR_RTS); // Clear RTS iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) { //printk(KERN_WARNING "serial_pxa_irq: odd -- interrupt triggered, but no interrupt in IIR: %08x\n",iir); + /* NCF, this was already commented out, but note that + * the rx TIMEOUT interrupt can be withdrawn by the uart + * if an additional character arrives after asserting + * the interrupt line, so it is possible to arrive here + * and have no interrupt pending, there should be data + * in the rx fifo, however + */ } lsr = serial_in(up, UART_LSR); up->lsr = lsr; @@ -252,6 +265,11 @@ static inline irqreturn_t serial_pxa_irq check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); + /* NCF, 8/7/06, RTS should not be changed unless in CRTSCTS mode, + * see above + */ + if ( up->port.info->flags & UIF_CTS_FLOW ) + /* NCF end */ serial_out(up, UART_MCR, serial_in(up, UART_MCR) | UART_MCR_RTS); // Assert RTS return IRQ_HANDLED; } @@ -263,7 +281,21 @@ static unsigned int serial_pxa_tx_empty( unsigned int ret; spin_lock_irqsave(&up->port.lock, flags); - ret = up->lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +/* NCF, 2/23/07,8/8/06, the following line was commented out in favor of + * the next line in 2.6.17, and then removed altogether by 2.6.20, however, + * this causes the actual status reg to be read only during + * recieve_chars, startup and interrupt service; it is not actually read + * when there is no receive and the software buffer is already empty (and + * thus no interrupt service, so restore this line and remove the second, + * this results in a delay for TCSETSW of up to 20-25ms after the last + * stop bit, but at least this is reliable, and matches the delays seen + * for the same function on an x86 PC running RH FC3. + * For some odd reason, even with the second line active, the wait is + * nearly long enough, until two transmissions (or receptions) occur within + * about 1 second, then the delay drops to zero, something else must be + * causing part of the delay */ + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; + //ret = up->lsr * UART_LSR_TEMT ? TIOCSER_TEMT : 0; spin_unlock_irqrestore(&up->port.lock, flags); return ret; @@ -479,12 +511,22 @@ serial_pxa_set_termios(struct uart_port baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); +#if 1 /* NCF 8/8/06, this is all well and good EXCEPT that if the rx fifo + * contains an error (break, frame, etc.), then the interrupt appears + * to be surpessed by the PXA255; this behavior is undocumented. + * If errors are expected, say from tri-stating a half-duplex + * data path, then either set for interrupts on every character or + * maintain valid "mark" on the line until 4 char times have elapsed. + */ if ((up->port.uartclk / quot) < (2400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; else if ((up->port.uartclk / quot) < (230400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; +#else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; +#endif /* * Ok, we're now changing the port state. Do it with ------------- Here is the user space code I used to set/clear RTS. Note that I tested several ways to wait for the end of transmission. static int rts_on( int fd_port ) { int ctl_mask; /* prepare to control request-to-send */ ctl_mask = TIOCM_RTS; /* be sure that RTS is set */ if ( ioctl ( fd_port, TIOCMBIS, &ctl_mask ) == -1 ) { perror ( "Couldn't set RTS in serial.c" ); fflush ( stderr ); return FALSE; } return TRUE; /* return success */ } long baud_rate=WHATEVER; static long timer( struct timeb*, long ); /* private function, generic timer */ struct termios rec_params; /* structure for line characteristics */ #define TX_WAIT_BRK //#define TX_WAIT static int rts_off( int fd_port ) { #if !(defined(TX_WAIT) || defined(TX_WAIT_BRK)) double delay; struct timeb start; #endif #ifdef TX_WAIT int i; #endif int ctl_mask; /* prepare to control request-to-send */ ctl_mask = TIOCM_RTS; /* turn RTS off after buffer empty */ #ifdef TX_WAIT_BRK /* wait for end of xmit, but don't send break (param=neg), * this is probably not portable, there seem to be different * implementations of the parameter: * POSIX: break=param*0.1sec * old: param=0 -> break=.25sec * I suppose there is a way to force posix, and I bet * negative params are implementation dependent * this seems to make the same variable wait time as * does TCGETS, below */ if ( ioctl ( fd_port, TCSBRK, -1 ) == -1 ) { perror ( "Couldn't wait for TX empty in serial.c" ); fflush ( stderr ); return FALSE; } #elif defined(TX_WAIT) /* get the current values of all the receiver characteristics */ if ( ioctl ( fd_port, TCGETS, &rec_params ) == -1 ) { perror ( "Couldn't get receiver parameters in serial.c" ); fflush ( stderr ); return FALSE; } /* write the new parameters to the port, with wait * for all characters to transmit, this call seems to * block until the wait has expired, so no need to * test for changes to take effect, however, the return * seems to be 4 to 15 msec after the actual end of xmit; * this is quick (0.5ms) if nothing else is happening, but * receiver activity seems to make the time long */ if ( ioctl ( fd_port, TCSETSW, &rec_params ) == -1 ) { perror ("Couldn't set receiver params in serial.c"); fflush ( stderr ); return FALSE; } #else /* since the ioctl wait takes so long, try just timing * the transmission based on baud rate, dangerous */ delay = 10.0 /*bits/char*/ * (double)strlen(string) / (double)baud_rate; /* convert to milliseconds */ delay *= 1000.0; timer ( &start, 0L ); /* when this should be 1.5ms, it is usually 0-1ms, but * sometimes very long (10s of ms) */ while ( timer( &start, (long)delay ) ); #endif /* turn RTS off */ if ( ioctl ( fd_port, TIOCMBIC, &ctl_mask ) == -1 ) { perror ( "Couldn't clear RTS in serial.c" ); fflush ( stderr ); return FALSE; } return TRUE; /* return success */ } -- Ned Forrester nfo...@wh... Oceanographic Systems Lab 508-289-2226 Applied Ocean Physics and Engineering Dept. Woods Hole Oceanographic Institution Woods Hole, MA 02543, USA http://www.whoi.edu/ http://www.whoi.edu/sbl/liteSite.do?litesiteid=7212 http://www.whoi.edu/hpb/Site.do?id=1532 http://www.whoi.edu/page.do?pid=10079 |
From: <pa...@pa...> - 2009-03-05 17:35:31
|
rketcham wrote: > When I write to the serial port, the RTS line is > always brought low regardless if RTSCTS has been set or not. Since you are trying to control CRTSCTS with tcsetattr(), you might want to check whether your kernel contains this patch: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=2276f03b745c297733e41470dde7f32bdd4b52af My understanding is that without the patch, CRTSCTS is ignored; and with the patch, enabling CRTSCTS causes RTS and CTS to be handled by the "auto-flow" feature of the PXA serial hardware. But I haven't looked at the other layers of the linux serial driver, so I could be wrong here. > I tried doing this myself by disabling RTSCTS, > driving RTS low manually (ioctl) and waiting for CTS to be driven low in a > while loop. If you suspect a problem in the driver, try controlling RTS and reading CTS with /proc/gpio/ rather than with ioctl(). Also, if you have a recent kernel, check that "pxaregs CKEN_7" is enabled. Pascal |