Link here

Implementing Logic-Level Serial Ports
How to add "non-inverted logic-level RS232" ports on the PDQ Board
with an interrupt-based software UART


In addition to the two hardware-UART-controlled RS-232 serial ports available on the PDQ Board, you can implement logic-level, software-controlled serial ports. The following application note provides the software libraries needed to access two logic-level serial ports.

 

Overview of the software UART

A UART (Universal Asynchronous Receiver Transmitter) refers to hardware or software that implements an asynchronous serial protocol. The HCS12 processor has two built-in hardware UARTs that are used to implement the Serial1 and Serial2 ports on the PDQ Single Board Computer (SBC), via RS-232 and RS-485 driver devices. The Soft_UART3 and Soft_UART4 libraries described here convert specific timer-controlled I/O pins into the send and receive lines of additional logic-level serial ports. "Logic-level" implies that rather than the wide bipolar voltage ranges permitted by RS-232 or RS-485, transmitters drive the line to zero volts for a 0 bit, and 5V for a 1 bit, and similarly receivers expect those voltage levels. These I/O (input/output) pins are available on the Digital I/O Header of the PDQ Board. Including the Soft_UART3 library in an application program adds a logic-level serial port called Serial3 on pins PT4(RxD3) (Serial3 receive) and PT5(TxD3) (Serial3 transmit); including the Soft_UART4 library in an application program adds a logic-level serial port called Serial4 on pins PT6(RxD4) (Serial4 receive) and PT7(TxD4) (Serial4 transmit).

The additional Serial3 and Serial4 ports behave identically to hardware UART's like those built in to the HCS12 processor, except with limited baud rates. These UART's use an asynchronous serial protocol sometimes known as "logic-level RS-232", that does not have a clock signal, requires communicating devices to be configured with the same baud rate, and uses 0 to 5 volt signal levels that are not logically inverted, so that transmitters idle at a 5 volt logic high and receivers wait for lines to be pulled low to signal the beginning of a transmission. The logic-level voltages used contrast with standard RS-232 signals which swing to +/-9 volts or more and are logically inverted on the serial cable. Some low-cost sensor and actuator electronics communicate using "logic-level RS-232", and these can be directly connected to the software UART Serial3 and Serial4 pins (although it is always advisable to add over-voltage protection to serial pins, such as a series 1K resistor and parallel clamping diode, to avoid processor damage). To communicate with a standard RS-232 device such as a PC or terminal, an externally mounted RS-232 driver chip such as the Maxim MAX242 is required to logically invert the logic-level UART signals and boost the voltages to the required +/-9 volt levels. To communicate with a USB host, the FTDI USB Logic-Level Serial Adapter or similar may be used.

The software UART ports implement full duplex buffered communications, meaning that the serial port can both send data to and receive data from a "remote" serial port simultaneously. Moreover, the software UART ports are coded to use interrupt-based "queued" operation to process incoming and outgoing characters. A queue is a first-in/first-out buffer that holds outgoing characters waiting to be sent, or incoming characters that have been received but have not yet been processed by the application program. The input and output queues are managed by interrupt routines, decoupling the response speed of the application program from the rate of serial data exchange.

Because the software UART ports are implemented using interrupt-driven software to detect each incoming bit and shape each outgoing edge, interrupts occur more frequently the higher a baud rate is set. The baud rate for using only one of the Serial3 or Serial4 software UART ports is limited to values of 19200 baud or lower; if both ports are used, the maximum baud rate is halved to 9600 baud. The lower the baud rate that is specified during initialization of the software UART ports, the less loading there is on the processor due to servicing their data streams. Both the local and remote serial ports must be configured for the same baud rate, or bit frequency. Standard attainable baud rates are 300, 1200, 2400, 4800, 9600, and 19200 baud.

This page describes how to use the pre-compiled software UART serial libraries. It can be as easy as including a file from your application source code and then inside a particular task invoking the installation function Use_Serial3() or Use_Serial4(). All of the standard serial routines in that task (such as putchar, getchar, printf and scanf in C) will then operate using the corresponding software UART driver.

The Software UART libraries are available in Mosaic IDE Plus revisions later than 1300. Contact Mosaic Industries if you have an earlier version of Mosaic IDE Plus and would like to make use of the Software UART library.
 

Software UART hardware connections

If connecting a software UART port to a "logic-level RS-232" peripheral device, use the PORTT pins on the PDQ Board digital I/O header shown below for Serial3 or Serial4. It is good design practice to implement over-voltage protection (i.e. a series resistor and clamping diode circuitry) on I/O pins that connect directly to the processor such as those used for the software UART ports.

  • PT4(RxD3) (Serial3 receiver pin accepting incoming data): PDQ Board Digital I/O header pin 20
  • PT5(TxD3) (Serial3 transmitter pin sending outgoing data): PDQ Board Digital I/O header pin 19.
  • PT6(RxD4) (Serial4 receiver pin accepting incoming data): PDQ Board Digital I/O header pin 18
  • PT7(TxD4) (Serial4 transmitter pin sending outgoing data): PDQ Board Digital I/O header pin 17.
PDQ Digital Field Header
Signal Pins Signal
GND —1 2— +5V
PM5 —3 4— PM4
PM3 —5 6— PM2
PM1 —7 8— PM0
PP7 —9 10— PP6
PP5 —11 12— PP4
PP3 —13 14— PP2
PP1 —15 16— PP0
(TxD4) PT7 —17 18— PT6 (RxD4)
(TxD3) PT5 —19 20— PT4 (RxD3)
PT3 —21 22— PT2
PT1 —23 24— PT0

If connecting to a standard RS-232 device that uses inverted logic swinging at positive and negative voltage levels, then an RS232 driver chip such as the Maxim MAX242 must be installed to buffer and level-translate the Serial3 and Serial4 signals.

Warning: Connecting a standard RS-232 peripheral device directly to logic-level serial pins will irreversibly damage the PDQ Board.

Please contact Mosaic Industries if you need advice about how to interface the software UART ports to a peripheral device.

 

Software device driver functions

The pre-coded software UART libraries are provided to implement the Serial3 and Serial4 logic-level serial ports in either C or Forth, thus simplifying the design of instrument control applications.

 

Simplest method: Use_Serial3() or Use_Serial4() does all the work

The PDQ Board's operating system implements serial I/O (input/output) using three "revectorable" serial primitive routines named Emit(), Key(), and AskKey() (called ?KEY in Forth). These serial primitive routines are revectored by storing the execution address of an appropriate function into a specified location in a task area. Each task defined by the application program has its own vectors that specify how these three primitives operate. All of the higher level serial I/O routines (such as getchar() or printf()) invoked within a task will use the specified primitive behavior. The principles of serial I/O and a detailed description of tasks are presented in the Serial Communications Chapter.

The use of the software UART libraries is simple. To use the Serial3 logic-level serial port in a specified task, simply execute the Use_Serial3() function within the task; similarly, execute Use_Serial4() to cause C input and output functions within that task to use Serial4. These functions each initialize a 220 byte struct in common RAM that includes two 96-byte first-in/first buffers (or queues), one for outgoing characters (the transmit buffer), and one for incoming characters (the receive buffer). The Use_Serial3() function writes the execution addresses of Emit3(), Key3() and AskKey3() into the task user area, ATTACHes the relevant interrupt service routines to the enhanced capture timer chananels 4 and 5 (for pins PT4(RxD3) and PT5(TxD3)), and enables interrupts. After executing this function, all high level serial I/O routines invoked from that task will use the Serial3 port. The Use_Serial4() function does the same with the relevant enhanced capture timer channels for Serial4.

With this approach, a task must be defined in your application to support the use of each software UART port, as each task has only one set of serial IO primitives to be revectored to a particular port.

 

Explicit use of the queued serial primitive functions

In many applications, the programmer may wish to avoid using an additional task to communicate on a software UART port, thereby conserving common RAM (each task uses over 1 Kbyte of common RAM) and simplifying the use of multiple ports by a single application.

For example, assume that a single task is already communicating using Serial2 (one of the two built-in RS-232 ports on the PDQ Board). If this same task wants to receive a serial data stream from the Serial3 port, the program can invoke the Init_Serial3() function (it is necessary to invoke this function first) and then repeatedly call Key3() to obtain the incoming data from the Serial3 port. The task can also output data to the Serial3 port by explicitly calling Emit3(). The Serial4 functions may be called directly in the same way by any task after Init_Serial4() has been invoked.

In this case there is no need to set up a second task to use a software UART port, but the C library I/O functions are not available for the software UART port.

 

Installing the software UART libraries

From the MosaicPlus C environment, C programmers can invoke the Software UART libraries by including one or both of the following lines in their source code file:

#include "soft_uart3.h"
#include "soft_uart4.h"

Forth programmers can invoke the Software UART libraries by including one or both of the following lines in their source code file after initializing the memory map using DEFAULT.MAP (or another custom memory map initialization):

#include "C:\MosaicPlus\forth\libraries\firmware\6.02\soft_uart3.fin"
#include "C:\MosaicPlus\forth\libraries\firmware\6.02\soft_uart4.fin"
 

Glossary

The software UART libraries are available in Mosaic IDE Plus revisions later than 1300. Contact Mosaic Industries if you have an earlier version of Mosaic IDE Plus and would like to make use of the Software UART ports.


 
AskKey3
AskKey4

C

int AskKey3( void );
int AskKey4( void );

Forth

AskKey3 ( -- int )
AskKey4 ( -- int )

A version of AskKey (?Key in Forth) that uses a software UART port. Checks whether there are any characters in the input queue for the numbered port. Returns a true flag (nonzero) if there is at least one character in the input queue, otherwise returns a false flag (0).


 
Emit3
Emit4

C

void Emit3( uwchar c );
void Emit4( uwchar c );

Forth

Emit3 ( char -- )
Emit4 ( char -- )

A version of Emit that uses a software UART port. Writes a character into the numbered port's transmit queue. The interrupt routine posted by, i.e., Init_Serial3() or Use_Serial3() begins transmitting the character to the numbered port's transmit pin as soon as the previous character is done transmitting. If there is no room in the queue when Emit3 or Emit4 are invoked, this routine calls Pause to allow other tasks to run while waiting for space to be made available by the transmission of the next character. This ensures that no outgoing characters are lost.


 
Init_Serial3
Init_Serial4

C

void Init_Serial3( int baud_over_100 );
void Init_Serial4( int baud_over_100 );

Forth

Init_Serial3 ( baud_over_100 -- )
Init_Serial4 ( baud_over_100 -- )

Initializes an interrupt-driven buffered logic-level serial port on the two PORTT Enhanced Capture/Timer pins associated with the numbered port. Sets the baud rate (bit frequency) to the value specified by the input parameter, times 100. See Serial3_Baud() for more information on the baud rate parameter. Standard attainable baud rates are 300, 1200, 2400, 4800, 9600, and 19200 baud. The lower the specified baud rate, the less loading there is on the processor due to servicing the software UART data streams. Baud rates above 19200 are not attainable; 9600 baud is a recommended rate that does not put too much serial interrupt servicing burden on the processor for a single software UART port. If both ports are used, the maximum attainable baud rate is 9600, and 4800 baud is recommended. Both the local and remote serial ports must be configured for the same baud rate.

For the numbered port this function: disables parity checking/generation, initializes the queues, ATTACHes and locally enables the serial interrupt service routines, and globally enables interrupts. After calling Init_Serial3() the functions Emit3(), Key3(), and AskKey3() may be explicitly invoked by any task in the application program. Likewise, after calling Init_Serial4() the Serial4 functions may be explicitly invoked by any task in the application program. Init_Serial3() is automatically called by the higher level function Use_Serial3() and Init_Serial4() is automatically called by Use_Serial4(); see their glossary definition for more information.


 
Key3
Key4

C

uwchar Key3( void );
uwchar Key4( void );

Forth

Key3 ( -- int )
Key4 ( -- int )

A version of Key that uses a software UART port. Waits for and returns the next character in the numbered port's input queue. If there is no character in the queue, this routine calls Pause to allow other tasks to run while waiting. The interrupt routine posted by, i.e., Init_Serial3() or Use_Serial3() adds each incoming character to the input queue as soon as the complete character appears on the receive pin for the numbered port. Note that when the 96-byte serial input buffer is full, each additional incoming character will overwrite the oldest character in the buffer. To avoid losing incoming characters, the application program must service the input queue using Key3() or Key4() before the input buffer overwrites the oldest character.


 
Serial3_Baud
Serial4_Baud

C

void Serial3_Baud( int baud_over_100 );
void Serial4_Baud( int baud_over_100 );

Forth

Serial3_Baud ( baud_over_100 -- )
Serial4_Baud ( baud_over_100 -- )

Sets the baud rate (bit frequency) for the numbered software UART port to the value specified by the input parameter, times 100. Standard attainable baud rates are 300, 1200, 2400, 4800, 9600, and 19200 baud. The lower the specified baud rate, the less loading there is on the processor due to servicing the software UART data streams. The maximum baud rate when using only one of the Serial3 or Serial4 software UART ports is 19200 baud; if both ports are used, the maximum baud rate for each is 9600. Both the local and remote serial ports must be configured for the same baud rate. These functions are automatically invoked by the higher level initialization functions, i.e. Init_Serial3() and Use_Serial3(). Serial3_Baud() and Serial4_Baud() can be used to change the baud rate of a software UART port after it has been initialized.


 
Serial3_Disable
Serial4_Disable

C

void Serial3_Disable( void );
void Serial4_Disable( void );

Forth

Serial3_Disable ( -- )
Serial4_Disable ( -- )

Locally disables the interrupts for the PORTT receive and transmit pins associated with the numbered software UART port so that no more characters can be transmitted or received.


 
Serial3_Disable_Parity
Serial4_Disable_Parity

C

void Serial3_Disable_Parity( void );
void Serial4_Disable_Parity( void );

Forth

Serial3_Disable_Parity ( -- )
Serial4_Disable_Parity ( -- )

Configures the numbered software UART port such that no parity bit is appended to the 8-bit data on each character transmitted, and no parity bit is expected on each incoming character. This function is automatically invoked by the higher level initialization functions, i.e. Serial3_Init_Buffers(), Init_Serial3() and Use_Serial3().


 
Serial3_Enable_Parity
Serial4_Enable_Parity

C

void Serial3_Enable_Parity( void );
void Serial4_Enable_Parity( void );

Forth

Serial3_Enable_Parity ( -- )
Serial4_Enable_Parity ( -- )

Configures the numbered software UART port such that a parity bit is appended to the 8-bit data on each character transmitted, and a parity bit is expected on each incoming character. The level of the outgoing parity bit is set by the function Serial3_Set_Parity_Out_Level() for the numbered port. The parity level of the last incoming character received is observable using the function Serial3_Parity_In() for the numbered port. To be effective, this function must be invoked after the numbered software UART port is initialized.


 
Serial3_Init_Buffers
Serial4_Init_Buffers

C

void Serial3_Init_Buffers( void );
void Serial4_Init_Buffers( void );

Forth

Serial3_Init_Buffers ( -- )
Serial4_Init_Buffers ( -- )

Disables parity and initializes the input and output buffers (queues) and buffer pointers used by the numbered software UART port. This function is automatically called by the higher level initialization functions, i.e. Init_Serial3() and Use_Serial3(); see their glossary definitions.


 
Serial3_Num_Input_Chars
Serial4_Num_Input_Chars

C

int Serial3_Num_Input_Chars( void );
int Serial4_Num_Input_Chars( void );

Forth

Serial3_Num_Input_Chars ( -- int )
Serial4_Num_Input_Chars ( -- int )

Returns the number of characters in the input buffer that have been accepted by the numbered software UART port but that have not yet been removed from the buffer by, i.e. Key3(). Note that when the 96-byte serial input buffer is full, each additional incoming character on the PORTT receive pin for the numbered software UART port will overwrite the oldest character in the buffer. To avoid losing incoming characters, the application program must service the input queue using Key3() or Key4() before the input buffer overwrites the oldest character.


 
Serial3_Num_Output_Chars
Serial4_Num_Output_Chars

C

int Serial3_Num_Output_Chars( void );
int Serial4_Num_Output_Chars( void );

Forth

Serial3_Num_Output_Chars ( -- int )
Serial4_Num_Output_Chars ( -- int )

Returns the number of characters in the output buffer for the numbered software UART that have been placed there by Emit3() or Emit4() but have not yet been transmitted out the serial line by the interrupt service routine associated with the PORTT transmit pin for the numbered port. Note that when the 96-byte serial output buffer is full, the next call to the Emit function for the numbered port or a higher-level output function like printf() will Pause and wait until a character has been shifted out, making room in the output buffer. This ensures that no outgoing characters are lost.


 
Serial3_Parity_In
Serial4_Parity_In

C

int Serial3_Parity_In( void );
int Serial4_Parity_In( void );

Forth

Serial3_Parity_In ( -- int )
Serial4_Parity_In ( -- int )

If parity is enabled, returns a true flag (nonzero) if the last complete character received by the input interrupt service routine for the numbered software UART port had its parity bit set. Returns a false flag (0) if the last complete character received had its parity bit cleared. Note that the last complete character received is not necessarily the next character in the input queue. This function works only if parity has been enabled by calling, i.e., Serial3_Enable_Parity() after initialization of the numbered software UART port.


 
Serial3_Set_Parity_Out_Level
Serial4_Set_Parity_Out_Level

C

void Serial3_Set_Parity_Out_Level( int desired_level );
void Serial4_Set_Parity_Out_Level( int desired_level );

Forth

Serial3_Set_Parity_Out_Level ( int -- )
Serial4_Set_Parity_Out_Level ( int -- )

After parity has been enabled with, i.e. Serial3_Enable_Parity(), this function sets the desired parity bit that is postpended to outgoing characters on the numbered software UART port. This function has no effect if parity is not enabled on the port.

 
Serial3_Transmitting
Serial4_Transmitting

C

int Serial3_Transmitting( void );
int Serial4_Transmitting( void );

Forth

Serial3_Transmitting ( -- int )
Serial4_Transmitting ( -- int )

Returns a true flag (nonzero) if the interrupt service routine associated with the PORTT output pin for the numbered software UART port is transmitting a character; otherwise returns a false flag (0).


 
Use_Serial3
Use_Serial4

C

void Use_Serial3( int baud_over_100 );
void Use_Serial4( int baud_over_100 );

Forth

Use_Serial3 ( baud_over_100 -- )
Use_Serial4 ( baud_over_100 -- )

This is the highest level software UART function, and in many applications it is the only function that needs to be called to use a software UART port. Calls Init_Serial3() or Init_Serial4() to install and initialize the interrupt routines for the numbered software UART port on the associated PORTT Enhanced Capture/Timer pins for that port. Revectors the calling task's serial primitives to point to the serial functions for the numbered software UART port.

Sets the baud rate (bit frequency) to the value specified by the input parameter, times 100. See Serial3_Baud() for more information on the baud rate parameter. Standard attainable baud rates are 300, 1200, 2400, 4800, 9600, and 19200 baud. The lower the specified baud rate, the less loading there is on the processor due to servicing the software UART data streams. Baud rates above 19200 are not attainable; 9600 baud is a recommended rate that does not put too much serial interrupt servicing burden on the processor. If both ports are used, the maximum attainable baud rate is 9600, and 4800 baud is recommended. Both the local and remote serial ports must be configured for the same baud rate.

For the numbered port this function: disables parity checking/generation, initializes the queues, ATTACHes and locally enables the serial interrupt service routines, globally enables interrupts, and revectors the calling task's serial primitives. After calling Use_Serial3() the high level print and scan functions such as getchar and printf will automatically use the Serial3 port in the specified task, and likewise with Use_Serial4() for Serial4.

 
This page is about: Using Logic-level Interrupt-driven RS-232, Software UART, Additional Serial Ports, Queued Serial Communications, Highly Reliable Serial Communications, No Characters Missed – How to add a third serial port on the PDQ Board using buffered logic level interrupt-driven RS232 implemented using a software UART for highly reliable serial communications. interrupt driven
 
 
Navigation