Mizar32/UART

From Wikibooks, open books for an open world
< Mizar32
Jump to: navigation, search

Contents

Introduction [edit]

The Universal Asynchronous Receiver Transmitter circuit or simple UART (pronounced "you art") is one of the more common interfaces to communicate serially. Some computers, such as the IBM PC, used an integrated circuit called a UART to convert characters to and from asynchronous serial form. For serial we mean that data is transmitted one bit at a time.

This circuit was at the base of Recommended Standard - 232 (RS-232 in short) that also defined the physical external COM port in IBM PC. The latest revision to RS-232 is the EIA RS-232 that was done in 1997.

In recent years, the PC has lost the RS-232 port (maybe only externally), replacing it in favour of the USB, but RS-232 is still in wide use including many variants, from RS-485 used in the industry to SpaceWire used in the Space Station. In its simpler forms, it is currently widely adopted in the embedded industry.

To understand a bit more the UART circuit and the RS-232 let’s give a look to the past. Serial transmission is very old, born with the first Teleprinters (TTYs). The teleprinters was in use from 1914 to recent times, with the last company manufacturing TTY closed in 1990, while last use is reported for air lines bulletin in recent years and most of the terms used come from the TTY world. Mark and Space for example are terms describing logic levels in teleprinter circuits. The baud rate, or Symbol rate, is the speed of a serial connection and is based on multiples of the rates for electromechanical teleprinters.

Today, although it is becoming less common in personal computers, it remains one of the most common peripherals found on micro-controllers (MCU) and is used for communication with external devices and systems, to talk with on-board serial devices or to make links between boards, between boxes or between embedded boards and PCs with an RS-232 port.

RS-232 globally specifies:

  • wiring
  • signal voltages
  • signal functions
  • signal timing
  • protocol for information exchange
  • UART configuration

With a micro-controller oriented view we will go now to examine all the above points.

The UART is a full duplex communication channel, in asyncronous mode each line is indipendend of each other in terms of its main function. The RX pin can practically receive data regardless of the TX pin’s activity and vice versa.

Usually the UART wires from the micro-controller are labelled TX, RX, GND (for transmit, receive and ground) in 3 wire configuration (without flow control implemented) and 5 wires TX, RX, GND, RTS, CTS, with hardware flow control, where RTS stay for Request To Send and CTS for Clear To Send.

AVR32 with its 3 UART use 3 pin configuration for two of them, and 5 pin configuration for the third UART (da verificare). However CTS and RTS may not be used where present or implemented in SW where missing in hardware.

The signal is described as a positive voltage to communicate the logic value 0 called a “Mark”, and a negative voltage to communicate the logic value 1, called a “Space”.

This signals are usually too weak in current and voltage as get out from the micro-controller and the standard specify that should be used voltages from ±5V to ±15V with length of wire of 10 meters, so how to interface to the UART lines, that output ±3V with very low current?

A TTL to RS-232 levels shifter converter(like the MAX232) is used to pump the voltage from ±3V to ±15V in 3 or 5 wires configuration.

Regarding the signal timing, is measured in Baud, one baud in binary communication correspond to 1 bit, so at 9600 baud rate, we have 9600 bits per second with a time frame to describe each bit of 104 μs 1/9600. Often the clock will run at 16 times the baud rate to allow the receiver to do centre sampling.

The data exchange protocol is very simple.

The packet begins with start bit, which is a logic 0, being transmitted/received first. In the software side, this bit is important as we can poll the RX pin for this bit to signal that a packet of data is coming. The data bits or the payload may or may not have a parity bit, then the packets end with a logic 1, one or two stop bit.

0 start)
XXXXXXX (7 or 8 bit of data)
X 1 optional bit of parity
1 one ot two stop bits

To be noted is that the byte is sent reversed, so we should read it from right to left.

Regarding configuration parameters, a common configuration (usually stored in a register) is 9600/8n1 that means for the serial port: 9600 baud, 8 bits data, no parity bit, 1 stop bit. Obviously both UART should be configured in the same way in order to communicate.

Hardware view [edit]

The Mizar32 has two serial ports available on the bus connectors, UART0 on the right bus and UART1 on the left bus. UART0 has just data (TXD, RXD) and hardware flow control (CTS, RTS) signals, while UART1 also has modem control signals (DSR, DTR, DCD, RI).

In the Atmel documents, these are called "USART"s because they can also be programmed into synchronous mode to work as additional SPI ports.

Bus pins [edit]

Signal GPIO Bus pin eLua name
UART0_RX PA0 BUS4 pin 3 pio.PA_0
UART0_TX PA1 BUS4 pin 4 pio.PA_1
UART0_RTS PA3 BUS4 pin 5 pio.PA_3
UART0_CTS PA4 BUS4 pin 6 pio.PA_4
UART1_RX PA5 BUS3 pin 3 pio.PA_5
UART1_TX PA6 BUS3 pin 4 pio.PA_6
UART1_DCD PB23 BUS3 pin 5 pio.PB_23
UART1_DSR PB24 BUS3 pin 6 pio.PB_24
UART1_DTR PB25 BUS3 pin 7 pio.PB_25
UART1_RI PB26 BUS3 pin 8 pio.PB_26
UART1_CTS PA9 BUS3 pin 9 pio.PA_9
UART1_RTS PA8 BUS3 pin 10 pio.PA_8

On Mizar32 pre-v1.3.2, BUS4 connector is called P5 and BUS3 is called P2.

RS232/RS485 serial add-on board [edit]

The add-on serial board has two banks of switches, DIP1 and DIP2 to select between RS232 and RS485 modes.

RS232 mode [edit]

If all switches of DIP1 are up and all of DIP2 down, it converts the bus signals to RS232 levels on its female DB9 connector J7. This connector is configured as DCE equipment, which is the opposite of a PC serial port, so a cable to communicate with a PC should connect the same pins at each end; a null modem cable is not required. Connecting other DCE equipment to it, like a modem or GPS receiver, requires interchanging of TX and RX, for example with a null modem cable.

Note that in the 1.1.1 version of the serial port the CTS and RTS pins were swapped over by mistake, so to get the right connections here you need to modify either the board or the cable. However, hardware flow control is not yet working in eLua so it makes no difference; see issue #29.

Signal Bus pin UART module
rev. 1.0
DB-9F pin
UART module
rev. 1.1.1
DB-9F pin
UART0_RX P5 pin 3 Pin 3 (input) Pin 3 (input)
UART0_TX P5 pin 4 Pin 2 (output) Pin 2 (output)
UART0_RTS P5 pin 5 Pin 8 (output) Pin 7 (output)
UART0_CTS P5 pin 6 Pin 7 (input) Pin 8 (input)
GND Various Pin 5 Pin 5

RS485 mode [edit]

If all switches of DIP1 are down and all of DIP2 up, the board's DB9 connector is disabled and RS485 signals appear on the four screw terminals.

This interface allows up to 32 RS485 devices to be connected to the same wires with a cable length of up to 1200m at 100 kbit/sec.

Currently, RS485 mode is not supported in eLua; see issue #77.

eLua view [edit]

Simple I/O [edit]

By default, UART0 is used for the Lua console (configured at 115200 baud, 8 data bits, 1 stop bit, no parity) and Lua's default input and output files are the console, so functions like "print()" and "io.write()" can be used to output characters on the serial port (with, and without, a trailing CR-LF newline sequence, respectively)

-- Greet the user
io.write( "What's your name? " )     -- Issue a prompt (with no trailing newline)
name = io.read()                     -- Read a line of input and store it in "name"
print( "Hello, " .. name .. "!" )    -- Salute them

Low-level I/O [edit]

UART0 can also be accessed (and UART1 must be accessed) using the lower-level uart eLua module, which gives a higher degree of control over the UART's behaviour.

The following example sets a different baud rate on UART0 and spits out a prompt character twice a second until a character is received in reply. To do this, it uses the uart.setup() function and the optional timeout parameter of the uart.getchar() function.

-- Prompt a 9600 baud serial device until we receive a character in reply
uartid = 0          -- Which UART should we be talking on?
timeout = 500000    -- Prompt once every half second
timerid = 0         -- Use timer 0 to measure the timeout
prompt = "U"        -- The prompt character (0x55 : binary 01010101)

uart.setup( uartid, 9600, 8, 0, 1 )    -- Configure the UART
repeat
  uart.write( uartid, prompt )
  reply = uart.getchar( uartid, timeout, timerid )
until reply ~= ""

Hardware flow control [edit]

Note that enabling hardware flow control with

uart.set_flow_control( uartid, uart.FLOW_RTS + uart.FLOW_CTS )

does not work yet. See issue #29.

Input buffer [edit]

When a UART receives a character it will remember it until you ask for its value using uart.getchar(). However, if a second character arrives before you have read the first one, the first one will be forgotten.

You can get round this by enabling a UART buffer, for example:

uart.setup( 1, 115200, 8, 0, 1 )    -- Configure UART 1
uart.set_buffer( 1, 1024 )          -- and give it an input buffer

and this will allow the UART to receive up to 1024 characters and remember them all even if you haven't read the first one yet (the 1025th character will provoke an error message and will be forgotten.

UART buffer sizes must be a power of two, i.e. 1, 2, 4, 8, 16 and so on up to a maximum of 32768 characters.

Some firmware uses UART0 as the eLua console. When this is the case, a buffer is always enabled on this UART.

Lua interrupts [edit]

When input buffering is enabled on a UART, an interrupt is generated every time a character is received. This interrupt saves the character in the buffer you asked for, until your program is ready to read it.

If you use firmware with Lua interrupts (included in the Mizar A and B firmware in the 20120123 release) you can also arrange for your own piece of code to be called every time a character is received.

The following example code quickly flashes the on-board LED every time a character is received:

-- Test UART interrupts handled in Lua.
-- Should flash the onboard LED each time a character is received.

led = pio.PB_29         -- Which PIO pin is the LED connected to?

function uart_handler( resnum )
  -- flash the onboard LED
  pio.pin.setlow( led )
  for i=1,10000 do end  -- for about 1/100th of a second
  pio.pin.sethigh( led )
end

pio.pin.sethigh( led )    -- off
pio.pin.setdir( pio.OUTPUT, led )

uart.setup( 0, 115200, 8, uart.PAR_NONE, 1 )
uart.set_buffer( 0, 1024 )  -- buffer must be enabled for UART IRQs to happen

-- tell eLua which function it should call every time the UART receives
cpu.set_int_handler( cpu.INT_UART_RX, uart_handler )
-- and enable that Lua interrupt
cpu.sei( cpu.INT_UART_RX, 0 )

-- Wait for about ten seconds while the test runs
for i=1,10000000 do end

-- disable the Lua interrupt
cpu.cli( cpu.INT_UART_RX, 0 )
-- and remove our handler function
cpu.set_int_handler( cpu.INT_UART_RX, nil )

The character is received from the UART and placed in the buffer before the Lua interrupt routine is called, so you can immediately read it in your Lua interrupt routine with uart.getchar( 0, 0 ) and act on it immediately.

Baud rate accuracy [edit]

The following table gives the actual baud rates set by eLua for the most commonly used ones:

Want Get Error
300 300 0%
600 600 0%
1200 1200 0%
2400 2400 0%
4800 4799 -0.02%
9600 9604 +0.04%
19200 19186 -0.07%
31250 31250 0%
38400 38372 -0.07%
57600 57692 +0.07%
115200 114583 -0.5%

Hijacking the serial board's TX LED [edit]

If UART0 is not used, the LED on the serial board can toggled by using pio.PA_1 as a generic [PIO] output: a low output value turns this LED off and a high value turns it on.

-- Turn the serial board's TX LED on (a low output lights the LED)
txled = pio.PA_1
pio.pin.setlow( txled )                -- Prepare "off" as the output value
pio.pin.setdir( pio.OUTPUT, txled )    -- Make the pin a GPIO output, disabling serial port 0

Further reading [edit]