5

I've got a simple program setting the baud rate for a serial (RS232) port. I'm setting the input and output rates independently using the cfsetospeed() and cfsetispeed() functions. As per the man page, this should be possible provided I use these functions and an appropriate constant:

cfsetispeed() sets the input baud rate stored in the termios structure to speed, which must be specified as one of the Bnnn constants listed above for cfsetospeed(). If the input baud rate is set to zero, the input baud rate will be equal to the output baud rate.

cfsetospeed() sets the output baud rate stored in the termios structure pointed to by termios_p to speed, which must be one of these constants: ... B600 ... B19200

My issue here is that whatever I set second (input or output) seems to be the final value for both. I'm trying to set two independent speeds.

CODE:

int main() {
    int fd, ret;
    char buf[100] = {0};
    char buf2[100] = {0};
    struct termios options;

    // Open the serial-USB device driver
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
    if(fd < 0){
      perror("open_port: Unable to open port - ");
      return 1;
    }

    tcgetattr(fd, &options);  //Get the current settings

    cfsetospeed(&options, B9600);   //Set input speed as 9600 Baud Rate
    cfsetispeed(&options, B19200);  //Set output speed as 19200 Baud Rate

    ret= tcsetattr(fd, TCSANOW, &options); //Get the return to make sure it worked

    sleep(3); // Just for kicks, let it "settle"

    tcgetattr(fd, &options);    //Read back the values

    getBRate(buf, cfgetispeed(&options));
    getBRate(buf2, cfgetospeed(&options));

    printf("return code was: %d, ispeed %s, ospeed %s\n", ret, buf, buf2);

    //Clean up 
    memset(buf, '0', 100);
    memset(buf2, '0', 100);
    close(fd);

    return 0;
}   

My getBRate() function is just a simple (ugly) switch to return a string version of the baud rate:

void getBRate(char rate[], speed_t brate)
{

    switch(brate) {
        case B0: strcpy(rate,"none"); break;
        case B50: strcpy(rate,"50 Baud");break;
        case B110: strcpy(rate,"110 Baud");break;
        case B134: strcpy(rate,"134 Baud");break;
        case B150: strcpy(rate,"150 Baud");break;
        case B200: strcpy(rate,"200 Baud");break;
        case B300: strcpy(rate,"300 Baud");break;
        case B600: strcpy(rate,"600 Baud");break;
        case B1200: strcpy(rate,"1200 Baud");break;
        case B1800: strcpy(rate,"1800 Baud");break;
        case B2400: strcpy(rate,"2400 Baud");break;
        case B4800: strcpy(rate,"4800 Baud");break;
        case B9600: strcpy(rate,"9600 Baud");break;
        case B19200: strcpy(rate,"19200 Baud");break;
        default: strcpy(rate, "No valid baud found\n");break;
    }
    return;
}

The output here will be:

return code was: 0, ispeed 19200 Baud, ospeed 19200 Baud

If I reverse the two "set" lines like so:

cfsetispeed(&options, B19200);  //Set output speed as 19200 Baud Rate
cfsetospeed(&options, B9600);   //Set input speed as 9600 Baud Rate

My output will change to:

return code was: 0, ispeed 9600 Baud, ospeed 9600 Baud

Any ideas?

EDIT:
Since the question came up, this code will be run on a board using a Coldfire 528X (either 5280 or 5282). Regardless, the RX and TX should be able to have different rates as per the reference manual for the UART:

23.3.4 UART Clock Select Registers (UCSRn)
The UCSRs select an external clock on the DTIN input (divided by 1 or 16) or a prescaled internal bus clock as the clocking source for the transmitter and receiver. See Section 23.4.1, “Transmitter/Receiver Clock Source.” The transmitter and receiver can use different clock sources.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • 6
    In all the chips I have dealt with, the serial port hardware actually only has a single baud rate generator, and therefore has no possible way to handle different Tx and Rx baud rates. – TJD Oct 16 '12 at 17:22
  • @TJD - Strange if that is the case that there's no error thrown in trying to set two different rates for Tx/Rx. _a_ rate took, but the command (setting two different rates) technically failed. – Mike Oct 16 '12 at 17:28
  • but there's not exactly a point where an error occurs. Each time you call to set the rate, it successfully does (but just applies it to both). So you're left with whatever rate you last set. – TJD Oct 16 '12 at 17:43
  • 1
    @sehe - I'm not quite sure I follow your argument. Yes, the `/dev/ttyUSB0` represents a single serial device, but if what I am communicating to has different "I" vs. "O" baud rate requirements I would have need to set them differently. I assume that's the whole point of having both these interfaces available... if just because there was only "one" serial cable there should be only 1 baud rate, then why be able to specify `cfsetIspeed` vs. `cfsetOspeed`? – Mike Oct 16 '12 at 18:51
  • Have you tried that on a real serial port like /dev/ttyS0? What device is at the other end of the cable? – ott-- Oct 16 '12 at 19:03
  • @ott-- My computer doesn't have a true RS232 port, so I can't test serial<->serial. I've got an x86 processor box (PC) attached to a USB to serial converter, on the other end the RS232 cable is attached to the input port of a board with a Coldfire 5280 processor (Not a PC, just a board with various I/O on it). – Mike Oct 16 '12 at 19:10
  • @sehe: One serial cable with separate Tx and Rx signals. While physically possible to operate at different baud rates, I think TJD is accurate in saying most hardware is designed to use the same rate for both transmit and receive. – tomlogic Oct 16 '12 at 21:05
  • To expand on @TJD's first comment, I agree that typically a UART/USART/SCC has a single baud rate generator. On modern chips this clock signal is used by both the Tx and Rx logic. But I looked at the venerable 8250 data sheet, and the baud rate generator is only hardwired to the transmitter, but is also exposed on a pin. The receiver's clock is from an input pin. So you could have different Tx & Rx baud rates if another baud rate generator could be connected to this pin. However most circuit-board designers simply routed the built-in generator output back to the receiver's clock pin. – sawdust Oct 17 '12 at 08:56

1 Answers1

0

For now I'll accept @TJD's answer as fact In all the chips I have dealt with, the serial port hardware actually only has a single baud rate generator, and therefore has no possible way to handle different Tx and Rx baud rates.

As to the fact that I'm not seeing any errors, it's because at least one of the requested operations of tcsetattr() did succeed as this page states:

The tcsetattr() function returns successfully if it was able to perform any of the requested actions, even if some of the requested actions could not be performed.

So for now, I'm guessing the hardware doesn't have the capability to support this, but I'm getting a successful return from the set function because it set one of the two things I requested.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • @TJD answer is surely correct. I have also never seen any UART hardware implementations that have different tx/rx baud rates. If you need this functionality for some obscure reason, I suggest two USB<>serial adaptors and a special cable that takes the tx line from one adaptor and the rx line from the other. Tx to one port and rx from the other. – Martin James Oct 16 '12 at 20:55