Link here

Using Queued Serial

How to use buffered interrupt-driven RS232 or RS485 for highly reliable serial communications on the PDQ Board.

 

Overview of the queued serial links

The QSerial library converts one or both of the serial ports on PDQ Single Board Computer (SBC) to use interrupt-based queued operation instead of the standard polled 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 by the processor's serial hardware but have not yet been processed by the application program. The output and input queues are managed by interrupt routines, thus decoupling the rate of serial data exchange from the response speed of the C-language application program. Compared to polled serial, which requires that the application program service the serial port often enough to ensure that no characters are missed, these interrupt-based serial drivers can increase the reliable throughput of serial transactions. This chapter describes how to use the pre-compiled queued serial library. It's as easy as including a file from your application source code and then invoking an installation function. All of the standard serial routines (such as putchar, getchar, printf and scanf in C) will then operate using the queued serial drivers.

The Freescale 9S12 (HCS12) processor on the PDQ Board contains two hardware serial ports named Serial1 and Serial2. Each of the two serial channels is implemented by a hardware UART (sometimes called a "USART) capable of full duplex RS232 communications, meaning that both transmission and reception can occur simultaneously. In other words, each "local" serial port can both send data to and receive data from a "remote" serial port on the other end of a connecting serial cable. Each channel can also be configured for half duplex communications using the RS485 protocol.

The serial interface is asynchronous, meaning that there is no clock transmitted along with the data. Rather, the transmitter and receiver must be communicating using a known "baud rate", or bit frequency. Both the local and remote serial ports must be configured for the same baud rate. Software-selectable baud rates up to 115,000 baud are supported. Standard attainable baud rates are 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, and 115,200 baud. The default rate for Serial1 and Serial2 is 115,200 baud; you can change it using the operating system's Baud function as defined in the C Function Glossary (A-H).

 

Software device driver functions

A pre-coded library is provided to implement the queued serial driver in either C or Forth, thus simplifying the design of instrument control applications. Both C and Forth source code versions of a demonstration program are provided to illustrate how to use the library in an RS232 multitasking application.

The operating system implements serial input/output (I/O) using three "revectorable" serial primitive routines called Emit, Key, and AskKey (called ?KEY in Forth). Each of these serial primitive routines can be 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 the operation of these three primitives. All of the higher level serial I/O routines invoked within a task will use the specified primitive behavior. The principals of serial I/O and a detailed description of tasks are presented in the Serial Communications Chapter.

The use of the queued serial library is simple. To convert the Serial1 port to use queued operation in a specified task, simply execute the Use_Serial1() function within the task. This initializes two 128-byte buffers, one for outgoing characters (the transmit queue), and one for incoming characters (the receive queue). It writes the execution addresses of queued versions of Emit, Key, and AskKey into the task user area, ATTACHes an queued serial interrupt service routine to the serial port, and enables interrupts. After executing this function, all high level serial I/O routines invoked from that task will use the queued serial driver.

To use two serial ports simultaneously, at least two tasks must be defined in your application, one for each serial port. To convert the Serial2 port to use queued operation, execute the Use_Serial2() function in the task that uses the Serial2 port. After executing this function, all high level serial I/O routines invoked from that task will use the queued serial driver. All of the low level details of managing the queues are handled by the library functions, so the application code is the same as it would be for polled operation. The advantage is that fast bursts of up to 128 incoming characters from the remote will be buffered in the input queue until your application program gets around to processing them; this avoids potential data loss.

To revert to the default polled operation in a task using Serial1, invoke the function named Standard_Serial1(). Similarly, calling Standard_Serial2() reverts to the default polled operation of Serial2 in the invoking task.

The queued serial drivers can be used for both RS232 (full duplex) and RS485 (half duplex) serial communications. Using RS485 is described here; it involves setting a hardware jumper and using the operating system functions RS485Init(), RS485Transmit(), and RS485Receive() (RS485.INIT, RS485.TRANSMIT, and RS485.RECEIVE in Forth) to manage the direction of the data transfer. One common error to be avoided is changing the RS485 direction from transmit to receive before all outgoing characters have been sent to the remote. To avoid this problem, the application program should poll the Transmit_Q_Empty() function after transmitting a line of characters before changing to receive mode. This function returns a true flag when all characters in the transmit queue have been sent out. The application program should wait until Transmit_Q_Empty() returns a true flag, and then should delay one character transmission time (ten times the inverse of the baud rate) to allow the last character to be shifted out before changing to RS485 receive mode.

Both C and Forth demo programs are provided to illustrate how to use the queued serial channels.

Open a new "Queued Serial Demo" project for a downloadable version of this code.

Look for this icon under Project→ New Project:
serial interface (Link to sbc-single-board-computers:freescale-hcs12-9s12-c-language:instrument-control:pdq_qserial.png using /embedded-systems/_media/sbc-single-board-computers/freescale-hcs12-9s12-c-language/instrument-control/pdq_qserial.png)
Queued Serial Demo

The comments in each source code file present an explanation of the program. Simply load the program and run the top level routine to see the queued serial ports in action. To monitor the performance of the second serial port, you can move your serial cable to the Serial2 connector on the PowerDock.

 

Installing the queued serial library software

From the MosaicPlus C environment, C programmers can invoke the queued serial library by including the following line in their source code file:

#include "qserial.h"

Forth programmers can invoke the queued serial library by including the following line 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\qserial.fin"
 

Glossary

C: void Standard_Serial1 ( void )
4th: Standard_Serial1 (– )
Reverts to the default polled (non-queued) operation of Serial1 in the calling task. Locally disables the interrupt enable bits for serial port 1, clears the SERIAL1_RESOURCE variable, and revectors the calling task's serial primitives to point to the default Emit1, Key1, and AskKey1 functions.
C: void Standard_Serial2 ( void )
4th: Standard_Serial2 (– )
Reverts to the default polled (non-queued) operation of Serial2 in the calling task. Locally disables the interrupt enable bits for serial port 2, clears the SERIAL2_RESOURCE variable, and revectors the calling task's serial primitives to point to the default Emit2, Key2, and AskKey2 functions.
C: uint Transmit_Q_Empty ( uint serial_id )
4th: Transmit_Q_Empty (serial_id – flag )
Returns a true flag if the transmit queue of the specified serial port is empty; otherwise returns a false flag. The input parameter is serial_id = 1 for the Serial1 port, or serial_id = 2 for the Serial2 port. When using RS485, a common error to be avoided is changing the RS485 direction from transmit to receive before all outgoing characters have been sent to the remote. To avoid this problem, the application program should poll the Transmit_Q_Empty function after transmitting a line of characters before changing to receive mode. The application program should wait until Transmit_Q_Empty returns a true flag, and then should delay one character transmission time to allow the last character to be shifted out before changing to RS485 receive mode. A character transmission time is approximately ten times the inverse of the baud rate. For example, at 115,200 baud (the default rate), each character takes just under 90 microseconds to be shifted out. Thus passing the parameter 90 to the MicrosecDelay function would allow enough time for the final character to be transmitted after Transmit_Q_Empty indicates that the queue is empty; then the RS485 transmitter can safely be changed to receive mode without disrupting the transmission.
C: void Use_QSerial1 ( void )
4th: Use_QSerial1 (– )
Installs interrupt-driven queued serial I/O on the Serial1 port in the calling task. Initializes the queues, clears the SERIAL1_RESOURCE variable, revectors the calling task's serial primitives to point to the queued versions of Emit, Key, and AskKey functions, ATTACHes the serial interrupt service routine, and globally enables interrupts. After invoking this function, serial I/O operations in the specified task will use queued (buffered) drivers.
C: void Use_QSerial2 ( void )
4th: Use_QSerial2 (– )
Installs interrupt-driven queued serial I/O on the Serial2 port in the calling task. Initializes the queues, clears the SERIAL2_RESOURCE variable, revectors the calling task's serial primitives to point to the queued versions of Emit, Key, and AskKey functions, ATTACHes the serial interrupt service routine, and globally enables interrupts. After invoking this function, serial I/O operations in the specified task will use queued (buffered) drivers.



See also → Serial Communications

 
 
 
Navigation
 
Registration on or use of this site constitutes acceptance of our User Agreement and Privacy Policy. Purchase of Mosaic's products constitutes acceptance of the End User License Agreement, Sales Terms and Conditions, and Life Support policy. Mosaic’s products are not authorized for use as components in life support or medical devices. The material on this site may not be reproduced, distributed, transmitted, cached or otherwise used, except with the prior written permission of Mosaic Industries, Inc. Mosaic and other product names are trademarked and should be capitalized when reproduced. You are encouraged to link to pages of this site.

© Mosaic Industries, Inc. All rights reserved.