Silicon Laboratories C8051F Service Manual

SOFTWARE UART EXAMPLES
AN115

Relevant Devices

This application note applies to the following devices:
C8051F000, C8051F001, C8051F002, C8051F005, C8051F006, C8051F010, C8051F011, C8051F012, C8051F012, C8051F015, C8051F016, C8051F017, C8051F220, C8051F221, C8051F226, C8051F230, C8051F231, C8051F236.

Introduction

This application note presents a discussion about software UART implementation on C8051Fxxx devices. Two complete examples are given: a C program using the PCA as the baud rate source, and an assembly program using Timer 0 as the baud rate source.

Implementation Options

The essential trade-off to consider when imple­menting a software UART (SW UART) is between hardware usage and speed/efficiency. Designs that utilize more hardware are likely to consume less CPU bandwidth and allow higher bit rates. This trade-off is discussed below.

Baud Rate Sources

An interrupt must be generated for each bit that is transferred; at a full-duplex 115.2 kbps, that’s an interrupt every 4.3 µs. The method of generating these interrupts (baud rate source) determines to a large extent how much overhead the implementa­tion consumes. Available options include: 8-bit timers, 16-bit timers, and the Programmable Counter Array (PCA). Note that for full-duplex operation, two baud rate sources are required (one each for transmit and receive).

Key Features

The two software examples were designed to closely mimic the hardware UART while still pre­serving hardware resources and CPU bandwidth. The following is a list of key features found in both examples:
An interface similar to the hardware UART, with user-level transmit and receive interrupts.
Interrupt or polled mode access support.
Full-duplex communication up to 57.6 kbps using an 18.432 MHz clock source.
State-based, interrupt-driven implementation, requiring minimal CPU overhead.
Minimal hardware usage:
- ‘C’ example uses two PCA modules.
- Assembly example uses Timer 0 in Mode 3.
The use of 8-bit timers allows one of the 16-bit hardware timers to be used for both transmit and receive baud rate generation. Timer 0 offers this capability in Mode 3. Note that when Timer 0 is in this mode, Timer 1 functionality is reduced; how­ever, Timer 1 may still provide baud rate genera­tion for the hardware UART (HW UART). Using 8-bit timers preserves hardware resources, but does introduce some overhead and latency issues. These issues are discussed in Example 2.
An alternative to the above solution is the use of 16-bit auto-reload timers. In this case two of the 16 bit hardware timers are occupied by the SW UART-
-one for transmit and one for receive. Any of the available timers will suffice, but the auto-reload feature on Timer 2 and Timer 3 reduces overhead, and eliminates any interrupt latency issues. Addi­tionally, 16-bit timers support a wider range of baud rates.
Rev. 1.1 12/03 Copyright © 2003 by Silicon Laboratories AN115
AN115
The Programmable Counter Array (PCA) also pro­vides an excellent solution for the SW UART, as demonstrated in the provided ‘C’ example. The PCA consists of a dedicated 16-bit counter/timer and five 16-bit capture/compare modules. Each of these modules may be configured to trigger an interrupt when the PCA counter matches the asso­ciated compare module’s contents. Since the PCA counter runs uninterrupted, this solution avoids the problem of accumulated interrupt latency. The PCA implementation is not available on C8051F2xx devices.

Additional Considerations

Each of the above timer sources may be clocked by SYSCLK or an external signal. In the provided examples, baud rate sources are clocked by SYSCLK, which is derived from an external
18.432 MHz crystal. Any baud rate/crystal fre-
quency combination is allowed, though software overhead limits the maximum baud rate-to­SYSCLK ratio.
START bit detection is also a concern for the SW UART receiver. C8051F00x and C8051F01x devices offer many external interrupt sources, sev­eral of which can be configured to detect falling edges. Both example programs utilize external interrupts for START detection.

Program Structure

In software timer mode, the PCA can generate an interrupt when the PCA counter matches a value in of one of the compare modules. Since the PCA counter runs uninterrupted, the modules can be updated each bit time to accurately produce the next bit time. In addition, the PCA offers a capture function that is useful in START bit detection.
The PCA modules may be routed via the crossbar to external signals. These signals (called CEXn for module n) can be used to trigger PCA counter cap­tures. This feature is exploited in the SW UART receiver. START bit recognition is accomplished with module 0 configured to capture the PCA counter contents upon a falling edge on the RX pin. This function offers two benefits: (1) START bit detection is easily accomplished; and (2) since the capture is performed immediately as the edge is detected, the bit sample timing is immune to inter­rupt latency.

Implementation

The transmit and receive operations for Example 1 are implemented as two independent state

Example 1: Programmable Counter Array Implementation

Example 1 uses two PCA modules to generate the receive and transmit baud rates (modules 0 and 1, respectively). The modules are configured in soft­ware timer mode to generate baud rate interrupts. An introduction to the PCA can be found in AN007.
2 Rev. 1.1
AN115
Figure 1. T ransmit and Receive State Machines
State 0
: Transmit START bit.
- Drop TX pin as START condition.
- Update Baud Rate source for next bit time.
- Increment state variable.
State 1-9
:Transmit Bit.
- Shift LSB of Transmit Data onto TX pin.
- Shift STOP bit into MSB of Transmit Data.
- Update Baud Rate source for next bit time.
- Increment state variable.
State 10
: STOP bit transmitted.
- Indicate Transmit complete.
- Trigger user-level interrupt if enabled.
- Reset Transmitter to Idle state.
Transmit State Machine
Interrupt Sources
State 0
: Start bit detected.
- Load Baud Rate source f or 3/2 bit time.
- Increment state variable.
State 1-8
: Bit Received.
- Shift value of RX pin into RX shift register.
- Update Baud Rate source for next bit time.
- Increment state variable.
State 9
: Capture STOP bit.
- Indicate Receive complete.
- Trigger user-level interrupt if enabled.
- Reset Receiver to Idle state.
Receive State Machine
Interrupt Sources
1) User (begin TX)
2) Bit Time Generator
1) START detection
2) Bit Time Generator
Figure 2. SW UART Bit Timing
D1D0 D2 D3 D4 D5 D6 D7
START
BIT
MARK
STOP
BIT
BIT TIMES
BIT SAMPLING
SPACE
3/2 Bit-Time 1 Bit-Time
machines in the PCA ISR. The state machines are illustrated in Figure 1.
Receive State Machine
When the SW UART is initialized, the PCA module 0 is configured for negative-edge capture mode. Its input, CEX0, is routed via the crossbar to a GPIO pin (P0.2, SW_RX). With the state machine in State 0, an interrupt is generated when a falling edge is detected on SW_RX. Since the mod­ule is in capture mode, the contents of the PCA counter are loaded into the module 0 capture regis­ters. Note that this value is independent of interrupt latency. Module 0 is switched to software timer
mode after the START bit is detected, and 3/2 bit­time is added to the module 0 capture register. The extra 1/2 bit-time is used only after the start bit is detected, so that sampling will occur during the middle of the next bit period (see Figure 2). When the PCA counter reaches the value held in the module 0 capture registers, the first bit-sampling interrupt (LSB in this case) occurs.
States 1-8 execute on module match interrupts. In each state, bits are sampled from SW_RX and shifted into the RXSHIFT variable. The PCA module 0 contents are updated in each state to pro­vide the next bit-time interrupt (1 bit time is added
Rev. 1.1 3
AN115
1) Read RDR.
2) Clear SRI
SRI
1
0
To Receive
STXBSY
1) Write data to TDR.
2) Set CCF1 to initiate transmit.
3) Set STXBSY
STI
1
0
0
1
To Transmit
Done?
End RX
No
Yes
Done?
NoYes
End TX
Initialization
1) Define SYSCLK and desired BAUD_RATE.
2) Call SW_UART_INIT.
3) Set SES if user-level interrupt support is desired.
4) Set SREN to enable th e SW UART receiver.
5) Call SW_UART_ENABLE.
1) Clear STI
Figure 3. Example 1 User-Level Polled
Mode Interface
to the compare registers). The state variable is also incremented.
State 9 captures the STOP bit, posts SRI, and returns the receiver to Idle state.
Transmit State Machine
A user initiates a transmit by forcing a PCA module 1 interrupt (setting CCF1=1). In State 0, the TX pin is forced low to generate the START condition. The PCA counter is read, and this value plus one bit-time is loaded into to the module 1 capture registers. Note that a few SYSCLKs will pass between the time the START bit is generated and when the PCA counter is read. This is the only instance in Example 1 where interrupt latency affects the bit time. The effect is negligible (worst case ~ 1/16 bit-time for 57.6 kbps and an
18.432 MHz SYSCLK).
States 1-9 are executed on module match inter­rupts. In each state, a bit is shifted out of the LSB of TDR, and a ‘1’ shifted in the MSB of TDR to represent the STOP bit. One bit time is added to the PCA module 1 capture registers to generate the next bit time. After 9 shifts, the data byte + STOP bit have been transmitted. The Transmit Complete indicator (STI) is set, the Transmit Busy indicator (STXBSY) is cleared, and the TX state variable is reset.
procedure for Example 1 is shown in Figure 3.

Program Interface

The SW UART supports both polled and interrupt­driven interfacing. Polled support is configured by disabling user-level interrupts (SES=0). The trans­mit and receive indicators (STI and SRI, respec­tively) can then be polled for transfer completions. The initialization and polled mode programming
4 Rev. 1.1
The initialization routine, SW_UART_INIT, con­figures the PCA, interrupts, and state variables for
AN115
Figure 4. Example 1 User-Level
Interrupt Mode Interface
Exit ISR
STI || SRI 1) Re-trigger IE7
1
0
1) Read RDR.
2) Clear SRI
SRI
1
0
IE7 Interrupt
STI
1) Clear STI
2) Write new data to TDR
3) Set CCF1 to initate transmit.
4) Set STXBSY
Clear IE7 Interrupt
Flag
1
0
Figure 5. Example 1 Test
Configuration
P0.0 (HW_TX)
P0.3 (SW_RX)
P0.1 (HW_RX)
P0.2 (SW_TX)
use in the SW UART. The SW_UART_ENABLE routine enables the SW UART. The SREN bit must be set to enable the receiver. Note that the TIME_COUNT constant is calculated by the soft­ware from the BAUD_RATE and SYSCLK con­stants.
If user-level interrupt support is enabled (SES=1), an IE7 interrupt is generated each time a transmit or receive is completed. As with the hardware UART, user software must check the transmit/ receive complete flags to determine the source of the interrupt. In the event that a transmit and receive are completed simultaneously, the user software will receive only one interrupt. The IE7 ISR must be capable of handling this situation. T w o options are available: (1) service both transmit and receive in the same ISR execution, or (2) service one (STI or SRI) and force an interrupt so that the ISR is called again to service the other. The second option is recommended to minimize ISR execution time.
Test code is provided to interface the SW UART with the HW UART. Connect jumper wires as shown in Figure 5.
To use the software in interrupt mode, set SES=1. The programming procedure for interrupt mode is shown in Figure 4.
The test code routines configure and enable the HW UART in Mode 1 using Timer 1 as the baud rate source. Timer 1 is also configured. Different baud rates and crystals may be tested by changing the BAUD_RATE and SYSCLK constants. Both HW and SW UART baud rate counts are calculated by the software from these constants. The testing routines transmit 15 characters in both directions.
Rev. 1.1 5
AN115
T o test the SW UART in polled mode, comment the line
; INTERRUPT_TEST();
and uncomment the line
POLLED_TEST();
Reverse the above steps to test the SW UART in interrupt mode. Uncomment the line
INTERRUPT_TEST();
And comment the line
; POLLED_TEST();
The longest states in Example 2 require 113 SYSCLKs (TX States 1-9). For an 18.432 MHz crystal, a SW UART transmit or receive operation will require a worst case 6 µs per bit transferred (113*T
bandwidth for a transmit or receive (70% for full­duplex). For the Example 1 software compiled with the Keil compiler, the full-duplex overhead may be approximated by the following equation:
FD Overhead(%) ~ = BAUD_RATE/81,000
SYSCLK
). At 57.6 kbps, that’s ~35% of CPU
With Timer 0 in Mode 3, Timer 1 may not set the TF1 flag, generate an interrupt, or be clocked by external signals. However, Timer 1 may still oper­ate as a baud rate generator for the HW UART if configured in Mode 2 (8-bit timer w/auto-reload). While Timer 0 is in Mode 3, Timer 1 may be enabled/disabled through its mode settings. Timer 1 is disabled in Mode 3, and enabled in all other modes.
With Timer 1 as the HW UART baud rate source, this solution is perhaps the most efficient use of hardware resources. The downside is increased software overhead (relative to the 16-bit timer solu­tion). Timer 0 Mode 3 does not offer auto-reload capabilities; the manual timer reload requires a 16­bit move in each interrupt service routine (ISR) iteration. In addition, interrupt latency will affect the bit-time accuracy. A correction constant can be factored into the timer preload values to compen­sate for typical interrupt latency, but variations in interrupt latency are unaccounted for.
Slower baud rates may require more than 8-bits of timer counts for each bit time. With SYSCLK at
18.432 MHz and Timer 0 in SYSCLK/1 mode, baud rates below 72 kbps require more than 256 timer counts. Available options include:
Per the above equation, baud rates above 80 kbps are not supported for full duplex operation. The overhead penalty is only incurred while the SW UART is performing a transfer. The code listing begins on page 10.

Example 2: 8-Bit Timer Implementation

In Example1 the SW UART uses Timer0 in Mode 3. In this mode, Timer 0 is split into two 8­bit timers: one is used for transmitting and one for receiving. TL0 is used as the receive timer; TH0 is used as the transmit timer.
6 Rev. 1.1
1) Use Timer 0 in SYSCLK/12 mode. Slower baud rates may be achieved with 8 bits, but standard baud rate/SYSCLK combinations are more difficult to obtain.
2) Use Timer 0 in SYSCLK/1 mode, and keep an upper timer byte manually in the timer ISR. Note that this method will generate an interrupt every 256 SYSCLKs for each transmit and receive, regardless of the baud rate (an interrupt each time the lower 8-bits overflow). The Example 2 soft­ware demonstrates option #2.

Program Structure

The transmit and receive operations for Example 2 are implemented as two independent state
AN115
machines in the Timer 0 and Timer 1 ISRs (see Figure 1 on page 3). The Timer 0 ISR is used to manage the receive state machine; the Timer 1 ISR manages the transmit state machine. The /INT0 ISR starts the receive state machine, but is disabled when the receive state is non-zero.
The SW UART receiver captures the START bit using an external interrupt source, /INT0, config­ured for active-low edge-sensitive input. The /INT0 interrupt is enabled when waiting for a START bit, and disabled during transfers. /INT0 is routed to the GPIO pins via the crossbar. Details on crossbar configuration can be found in AN001.
Since all timer loading is performed manually in the ISR, interrupt latency must be compensated for. A ‘slop constant’ is subtracted from each timer pre­load value to adjust for this interrupt latency and code executed between the timer overflow and the operation of reloading the new timer values. These constants are independent of the SYSCLK fre­quency or baud rate; however, they do not account for variations in interrupt latency.

Implementation

NOTE: For this discussion, assume the baud rate is slow enough that the 8-bit timers are not sufficient. The direct RAM bytes labeled BCRHI and BCTHI are used to manually keep the upper bytes for the receive and transmit timers, respectively.
Transmit State Machine
When the SW UART is initialized and enabled, the TX interrupt is set pending but still disabled. The user initiates the transfer by enabling the transmit interrupt (Note that TH0, the upper byte of Timer 0, generates the TX interrupts).
In State 0, the TX pin is asserted low to produce the START condition, and the timer is loaded with 1 bit time to produce the next interrupt.
mov TH0, #-LOW(TX_BT);
Notice that BCTHI is loaded with the unsigned bit­time high byte, but TH0 is loaded with the negative of the bit-time low byte. This is because Timer 0 (as all hardware timers) is an up-counter, while BCTHI counts down. TH0 will overflow and gen­erate an interrupt as it overflows from 0xFF to 0x00; BCTHI is decremented upon each interrupt, and indicates a bit time when it equals zero.
For States 1-9, one state is executed each time BCTHI reaches zero. In each State, the LSB of the Transmit data register (TDR) is shifted onto the TX pin. The TX timer is loaded with 1 bit time, and a ‘1’ is shifted into the MSB of TDR to represent the STOP bit in State 9 (TDR should hold 0xFF after the transfer is complete).
State 10 sets the Transmit Complete indicator (STI), clears the Transmit Busy indicator (STXBSY), and triggers an IE7 interrupt if user­level interrupt support is enabled.
Receive State Machine
In State 0, /INT0 is used as the RX input (config­ured falling-edge active, HIGH priority). An /INT0 interrupt means a START condition has been detected. The /INT0 ISR loads the RX timer (TL0 + BCRHI) with 3/2 bit-time (see Figure 2). BCRHI is decremented each time TL0 overflows.
States 1-8 execute when BCRHI reaches zero. In each state, the SW_RX pin is sampled and shifted into the LSB of the RXSHIFT variable. The RX timer is also reloaded to generate the next sampling time. State 9 captures the STOP bit, but framing error detection is not provided (the STOP bit polar­ity is not checked). If user-level interrupts are enabled, this state enables and triggers the IE7 interrupt.

Program Interface

; Load high byte into BCTHI mov BCTHI, #HIGH(TX_BT); ; Load low byte into TH0
Example 2 supports both polled and interrupt driven interfacing. The initialization ritual and pro­gramming procedure for polled mode is shown in
Rev. 1.1 7
AN115
Figure 6. Example 2 User-Level Polled
Mode Interface
Initialization
1) Define TIME_COUNT according to desired baud rate and SYSCLK.
2) Call SW_UART_INIT .
3) Set SES if user-level interrupt support is desired.
4) Set SREN to enable the SW UART receiver.
5) Call SW_UART_ENABLE.
1) Read RDR.
2) Clear SRI
SRI
1
0
To Receive
STXBSY
1) Write data to TDR.
2) Set ETI to initiate transmit.
3) Set STXBSY
STI
1
0
1) Clear STI
0
1
To Transmit
Done?
End RX
End TX Done?
NoYes
Yes
No
Figure 6. The TIME_COUNT constant must be explicitly defined in this example.
8 Rev. 1.1
AN115
Figure 7. Example 2 User-Level
Interrupt Interface
Exit ISR
STI
1) Re-trigger IE7
1
0
1) Read RDR.
2) Clear SRI
SRI
1
0
IE7 Interrupt
STI
1) Clear STI
2) Write new data to TDR
3) Set ETI to initate transmit.
4) Set STXBSY
SRI
1) Re-trigger IE7
1
0
Clear IE7 Interrupt Flag
0
1
Figure 7 shows the IE7 ISR programming sequence for interrupt mode. Note that the receive operation is serviced first, since it is the most sensitive to latency.
one function and re-triggers itself to service the other.
T est code is provided. To test the polled mode code, in the MAIN routine uncomment the line
ajmp PolledRX_PolledTX
and comment the line
; ajmp InterruptRX_InterruptTX
To run the interrupt mode test code, reverse the above steps. Comment the line
; ajmp PolledRX_PolledTX
and uncomment the line
ajmp InterruptRX_InterruptTX
Adding a jumper wire between SW_GPIO_TX and SW_GPIO_RX provides quick and easy evaluation of the SW UART. Note that this evaluation method is only useful with the interrupt mode test code.
To handle the situation of a transmit and receive completing simultaneously, this example services
With a SYSCLK of 18.432 MHz, the software given in Example 2 operates in full-duplex at a maximum of 57.6 kbps. The code listing begins on page 21.
Rev. 1.1 9
AN115
//-----------------------------------------------------------------------------------­// // Copyright 2003 Cygnal, Inc. // // FILE NAME: AN015_1.c // TARGET DEVICE: C8051F00x, C8051F01x // CREATED ON: 03/10/01 // CREATED BY: JS // // Software UART program, using PCA as baud rate source. // PCA module 0 is used as receive baud rate source and START detector. For START // detection, module 0 is configured in negative-edge capture mode. For all other // SW_UART operations, module 0 is configured as a software timer. Module match // interrupts are used to generate the baud rate. Module 1 generates the transmit // baud rate in software timer mode. // Code assumes an external crystal is attached between the XTAL1 and XTAL2 pins. // The frequency of the external crystal should be defined in the SYSCLK constant. // // INITIALIZATION PROCEDURE: // 1) Define SYSCLK according to external crystal frequency. // 2) Define desired BAUD_RATE. // 3) Call SW_UART_INIT(). // 4) Set SREN to enable SW_UART receiver. // 5) Set SES only if user-level interrupt support is desired. // 6) Call SW_UART_ENABLE(). // // TO TRANSMIT: // 1) Poll STXBSY for zero. // 2) Write data to TDR. // 3) Set CCF1 to initiate transmit. // 4) STI will be set upon transmit completion. An IE7 interrupt is generated if // user-level interrupts are enabled. // // TO RECEIVE: // 1) If in polled mode, poll SRI. If in interrupt mode, check SRI in IE7 Interrupt // Service Routine. // 2) Read data from RDR. // // Test code is included, for both polled and interrupt mode. Test code assumes // the HW_UART pins and SW_UART pins are connected externally: // P0.0 (HW_UART TX) -> P0.3 (SW_UART RX) // P0.1 (HW_UART RX) -> P0.2 (SW_UART TX) // // To use the test code in polled mode, comment out the call to the INTERRUPT_TEST() // at the bottom of the main routine, and uncomment the call to POLLED_TEST(). To // test the interrupt mode, comment out the POLLED_TEST() call and uncomment the // INTERRUPT_TEST() call. // // The test routines configure the HW_UART to operate with Timer 1 as the baud rate // source. The Timer 1 preload values are auto-calculated from the SYSCLK and BAUD_RATE // constants. // //----------------------------------------------------------------------------------­// Includes //----------------------------------------------------------------------------------­#include <c8051f000.h> // SFR declarations
//----------------------------------------------------------------------------------­// Global CONSTANTS
10 Rev. 1.1
AN115
//-----------------------------------------------------------------------------------
#define BAUD_RATE 57600 // User-definable SW_UART baud rate #define SYSCLK 18432000 // System clock derived from
// 18.432MHz XTL
#define TIME_COUNT SYSCLK/BAUD_RATE/4 // Number of PCA counts for one
// bit-time. (PCA configured to count // SYSCLK/4)
#define TH_TIME_COUNT TIME_COUNT*3/2 // 3/2 bit-time, for use after receiving
// a START bit. RX should be LOW for one // bit-time after the edge of the START, // and the first bit sample starts in // the middle of the next bit-time.
#define HW_TIME_COUNT SYSCLK/BAUD_RATE/16 // Time count for HW_UART baud rate
// generation. Auto-calculated from the // SYSCLK and BAUD_RATE constants // defined above.
//----------------------------------------------------------------------------------­//Global VARIABLES //-----------------------------------------------------------------------------------
bit SRI; // SW_UART Receive Complete Indicator bit STI; // SW_UART Transmit Complete Indicator bit STXBSY; // SW_UART TX Busy flag bit SREN; // SW_UART RX Enable bit SES; // SW_UART User-level Interrupt
// Support Enable
sbit SW_RX = P0^2; // SW_UART Receive pin sbit SW_TX = P0^3; // SW_UART Transmit pin
char TDR; // SW_UART TX Data Register char RDR; // SW_UART RX Data Register (latch)
// Test Variables char k, m; // Test indices. char idata SW_BUF[20]; // SW_UART test receive buffer.
bit HW_DONE; // HW transfer complete flag
// (15 characters transmitted.)
bit SW_DONE; // SW transfer complete flag
// (15 characters transmitted.)
//-----------------------------------------------------------------------------------­// Function PROTOTYPES //------------------------------------------------------------------------------------
void SW_UART_INIT(); // SW_UART initialization routine void SW_UART_ENABLE(); // SW_UART enable routine void PCA_ISR(); // SW_UART interrupt service routine void INTERRUPT_TEST(void); // SW_UART test routine (interrupt mode) void POLLED_TEST(void); // SW_UART test routine (polled mode) void USER_ISR(void); // SW_UART test interrupt service
// routine
void HW_UART_INIT(void); // HW_UART initialization and setup
Rev. 1.1 11
Loading...
+ 23 hidden pages