Using other UARTs in Linux

From Platformx Wiki

There are three UARTs available on the PXA271, as described by the PXA27x Developer's Manual:

    Full-Function UART (FFUART) 
    The FFUART supports modem-control capability. The maximum baud rate is 921,600 bps.
    Bluetooth UART (BTUART) 
    The BTUART is a high-speed UART that supports baud rates up to 921,600 bps and can be connected to a Bluetooth module. It supports the functions in the feature list, but supports only two modem control pins (nCTS and nRTS).
    Standard UART (STUART) 
    The STUART supports all functions in the feature list, but does not support modem-control capability. The maximum baud rate is 921,600 bps.


On startup the three UARTs are initalized by the pxa2xx-uart driver:

ttyS0 at MMIO 0x40100000 (irq = 22) is a FFUART
ttyS1 at MMIO 0x40200000 (irq = 21) is a BTUART
ttyS2 at MMIO 0x40700000 (irq = 20) is a STUART

You can find the tty's in the /sys interface at:

/sys/class/tty/ttyS0
/sys/class/tty/ttyS1
/sys/class/tty/ttyS2

Adding /dev entries

The current Linux image only has /dev/ttyS2 (the STUART) added as a /dev entry. To create the /dev/ttySX entries for the other UARTs you have to use mknod.

# Usage: mknod [OPTIONS] NAME TYPE MAJOR MINOR

mknod /dev/ttyS0 char 4 64
mknod /dev/ttyS1 char 4 65

Setting up UARTs

Use stty to setup the baud rates, etc. of the UARTs or to view their current setup:

  • View the current setup of ttyS0 (the FFUART)
    [root@Linux /dev]# stty -F /dev/ttyS0     
    speed 9600 baud;
    -brkint -imaxbel
    
  • Set the baud rate of ttyS0 to 115200
    [root@Linux /dev]# stty -F /dev/ttyS0 115200
    
  • Double check the current setup of ttyS0 (the FFUART)
    [root@Linux /dev]# stty -F /dev/ttyS0 
    speed 115200 baud;
    -brkint -imaxbel
    

    Note you can use stty to setup the baud rate to be just about any standard UART speed up to 460.8kbps. However, you cannot use stty to set the UART to 921.6kbps

    Setting Baud Rate to 921.6kbps

    Because 921,600 bps is not a common standard baud rate programs like stty do not typically support it. A quick work around to this problem is to use a simple C program to set the baud rate manually using the termOptions struct in Linux. The underlying driver knows how to set the baud rate correctly (assuming you're using a patched version of the uart drivers) so you just need to be able to request it.

    Here is a simple C program that can do this for us:

     
    #include <unistd.h>
    #include <stdio.h>
    #include <termios.h>
    #include <sys/fcntl.h>
     
     
    int main( int argc, char *argv[] )
    {
    	struct termios termOptions;
    	char        port[1024];
    	int         ttyFid;
     
    	if( argc == 2 )
    	{
    		// Copy the port from the argument
    		strcpy( port, argv[1] );
    		printf( "Read port name: %s\n", port );
    	}
    	else
    	{
    		// No argument or incorrect number of arguments read:
    		printf( "Usage: setSer /dev/ttySX\n" );
    		return -1;
    	}
     
    	// Open the tty:
    	ttyFid = open( port, O_RDWR );
    	if (ttyFid == -1)
    	{
    		printf( "Error unable to open port: %s\n", port );
    		return -1;
    	}
     
    	// Get the current options:
    	tcgetattr( ttyFid, &termOptions );
    	
    	// Set the input/output speed to 921.6kbps
    	cfsetispeed( &termOptions, B921600 );
    	cfsetospeed( &termOptions, B921600 );
     
    	// Now set the term options (set immediately)
    	tcsetattr( ttyFid, TCSANOW, &termOptions );
     
    	// All done
    	printf( "Done, port speed set on: %s\n", port );
    }

    To compile the program you can use arm-linux-gcc (I had a few problems with arm-linux-g++ with this code):

    arm-linux-gcc main.c -o setSer
    arm-linux-strip setSer
    


    Once you've compiled the program you will need to either add it to your file system (and load the file system onto your platform) or download it somehow. To use simply call the program with the tty you wish to set i.e. setSerial /dev/ttyS2.

    Note, that this code works on x86 desktop platforms just as easily. Also right now there's not too much error checking for the actual setting of the termOptions, so code for reloading the actual termOptions (after pausing to give the driver a chance to set them) and comparing them to your set options might be useful for some people. Also this code doesn't actually close the port it's opened. This doesn't seem to cause any problems, but you might want to add close( ttyFid ); to the last line of the code (unless that doesn't work of course).