Xmega Application Note | |||||
This single file shows how to implement a software uart using Timer0 and external interrupt 0.
Note that the RX_PIN must be the external interrupt 0 pin on your AVR of choice. The TX_PIN can be chosen to be any suitable pin. Note that this code is intended to run from an internal 8 MHz clock source.
Copyright (c) 2010, Atmel Corporation All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The name of ATMEL may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Definition in file sw_usart.c.
#include "sw_usart.h"
Go to the source code of this file.
Functions | |
ISR (SW_USART_TX_COMP_VECT) | |
Timer2 interrupt service routine. | |
ISR (SW_USART_RX_COMP_VECT) | |
Timer0 interrupt service routine. | |
ISR (INT0_vect) | |
External interrupt service routine. | |
void | SW_USART_init (void) |
Function to initialize the software UART. | |
void | SW_USART_PutChar (const uint8_t c) |
Send a unsigned char. | |
uint8_t | SW_USART_RX_Buffer_GetByte (void) |
Get byte from the RX buffer. | |
void | SW_USART_RX_Buffer_PutByte (uint8_t rx_byte) |
Function to put byte in RX buffer. | |
void | SW_USART_Set_Baudrate (uint32_t new_baud) |
Set new baudrate. | |
uint8_t | SW_USART_Test_Hit (void) |
Function to check if data is pending in the buffer. | |
uint8_t | SW_USART_Tx_Ready (void) |
Function to check if transmitter is busy. |
ISR | ( | SW_USART_TX_COMP_VECT | ) |
Timer2 interrupt service routine.
Timer2 will ensure that bits are written at the correct instants in time.
If state should be something else, the variable is set to IDLE. IDLE is regarded as a safe state/mode.
Definition at line 150 of file sw_usart.c.
References IDLE, SW_USART_CLR_TX_PIN, SW_USART_SET_TX_PIN, SW_USART_TX_DISABLE_TIMER_INTERRUPT, SwUartTXBitCount, SwUartTXData, SwUsartTXState, TRANSMIT, and TRANSMIT_STOP_BIT.
00151 { 00152 /* Start bit has already been sent, process the byte and stop bit. */ 00153 switch (SwUsartTXState) { 00154 00155 /* Transmit byte in TX buffer. */ 00156 case TRANSMIT: 00157 00158 /* If the complete byte is not transmitted, send next bit.*/ 00159 if( SwUartTXBitCount < 8 ) { 00160 if( SwUartTXData & 0x01 ){ 00161 SW_USART_SET_TX_PIN(); 00162 }else{ 00163 SW_USART_CLR_TX_PIN(); 00164 } 00165 00166 /* Rightshift the tx byte to be ready for the next bit transmit. */ 00167 SwUartTXData = SwUartTXData >> 1; 00168 SwUartTXBitCount++; 00169 } 00170 00171 /* Send stop bit if complete byte have been sent. */ 00172 else { 00173 SW_USART_SET_TX_PIN(); 00174 SwUsartTXState = TRANSMIT_STOP_BIT; 00175 } 00176 break; 00177 00178 /* Stop bit has been sent, go to idle and disable this interrupt. */ 00179 case TRANSMIT_STOP_BIT: 00180 SW_USART_TX_DISABLE_TIMER_INTERRUPT(); 00181 SwUsartTXState = IDLE; 00182 break; 00183 00184 /* Unknown state. This indicates an error, but this should never occur. 00185 * Set state to IDLE to be able to continue operation. 00186 */ 00187 default: 00188 SW_USART_TX_DISABLE_TIMER_INTERRUPT(); 00189 SwUsartTXState = IDLE; 00190 } 00191 }
ISR | ( | SW_USART_RX_COMP_VECT | ) |
Timer0 interrupt service routine.
Timer0 will ensure that bits are read at the correct instants in time.
If state should be something else, the variable is set to IDLE. IDLE is regarded as a safe state/mode.
Definition at line 98 of file sw_usart.c.
References IDLE, SW_USART_EXT_IFR, SW_USART_GET_RX_PIN, SW_USART_RX_Buffer_PutByte(), SW_USART_RX_DISABLE_PRESCALER, SW_USART_RX_DISABLE_TIMER_INTERRUPT, SW_USART_RX_ENABLE_EXTERNAL0_INTERRUPT, SwUartRXBitCount, SwUartRXData, and SwUsartRXState.
00099 { 00100 /* Get state of RX pin. */ 00101 uint8_t rx_pinstate = SW_USART_GET_RX_PIN(); 00102 00103 /* If 8 bit have not been received, capture and add bit to input byte.*/ 00104 if( SwUartRXBitCount < 8 ) { 00105 00106 /* Rightshift due to receiving LSB first.*/ 00107 SwUartRXData = (SwUartRXData>>1); 00108 00109 /* If a logical 1 is read on the pin, add this to the MSB 00110 * of the input byte. 00111 */ 00112 if(rx_pinstate != 0 ){ 00113 SwUartRXData |= 0x80; 00114 } 00115 00116 SwUartRXBitCount++; 00117 } 00118 00119 /* Complete byte received, send stop byte. 00120 * Store the received byte in the buffer. 00121 * Disable this interrupt for bit receiving and enable 00122 * pin change interrupt for detecting start bit. 00123 */ 00124 else{ 00125 /* If STOP bit is detected, add byte to buffer. If STOP was not 00126 * detected, discard the byte and reset receiver. 00127 */ 00128 if(rx_pinstate != 0 ){ 00129 SW_USART_RX_Buffer_PutByte(SwUartRXData); 00130 } 00131 SwUsartRXState = IDLE; 00132 SW_USART_RX_DISABLE_TIMER_INTERRUPT(); 00133 SW_USART_RX_DISABLE_PRESCALER(); 00134 SW_USART_EXT_IFR |= (1 << INTF0); 00135 SW_USART_RX_ENABLE_EXTERNAL0_INTERRUPT(); 00136 } 00137 }
ISR | ( | INT0_vect | ) |
External interrupt service routine.
The falling edge in the beginning of the start bit will trig this interrupt. The state will be changed to RECEIVE, and the timer interrupt will be set to trig one and a half bit period from the falling edge. At that instant the code should sample the first data bit.
Definition at line 68 of file sw_usart.c.
References INTERRUPT_EXEC_CYCL, RECEIVE, SW_USART_RX_CLEAR_TIMER_INTERRUPT, SW_USART_RX_COMPARE, SW_USART_RX_DISABLE_EXTERNAL0_INTERRUPT, SW_USART_RX_DISABLE_PRESCALER, SW_USART_RX_DISABLE_TIMER_INTERRUPT, SW_USART_RX_ENABLE_PRESCALER, SW_USART_RX_ENABLE_TIMER_INTERRUPT, SW_USART_RX_TIMER, SwUartRXBitCount, SwUartTICKS2WAITONE, and SwUsartRXState.
00069 { 00070 SwUsartRXState = RECEIVE; /* Change state */ 00071 SW_USART_RX_DISABLE_EXTERNAL0_INTERRUPT(); /* Disable interrupt during the data bits. */ 00072 00073 SW_USART_RX_DISABLE_TIMER_INTERRUPT(); /* Disable timer to change its registers. */ 00074 SW_USART_RX_DISABLE_PRESCALER(); /* Reset prescaler counter. */ 00075 00076 SW_USART_RX_TIMER = INTERRUPT_EXEC_CYCL; /* Clear counter register. Include time to run interrupt rutine. */ 00077 SW_USART_RX_COMPARE = SwUartTICKS2WAITONE; /* Count one and a half period into the future. */ 00078 SW_USART_RX_ENABLE_PRESCALER(); /* Start prescaler clock. */ 00079 00080 SwUartRXBitCount = 0; /* Clear received bit counter. */ 00081 SW_USART_RX_CLEAR_TIMER_INTERRUPT(); /* Clear interrupt bits */ 00082 SW_USART_RX_ENABLE_TIMER_INTERRUPT(); /* Enable timer0 interrupt on again */ 00083 00084 }
void SW_USART_init | ( | void | ) |
Function to initialize the software UART.
This function will set up pins to transmit and receive on. Control of Timer0 and External interrupt 0.
Definition at line 200 of file sw_usart.c.
References IDLE, SW_USART_EXT_ICR, SW_USART_EXT_IFR, SW_USART_RX_COMPARE, SW_USART_RX_CTRL, SW_USART_RX_DISABLE_TIMER_INTERRUPT, SW_USART_RX_ENABLE_EXTERNAL0_INTERRUPT, SW_USART_RX_PIN, SW_USART_RX_PRESCALE, SW_USART_SET_TX_PIN, SW_USART_TRX_DDR, SW_USART_TRX_PORT, SW_USART_TX_COMPARE, SW_USART_TX_CTRL, SW_USART_TX_DISABLE_TIMER_INTERRUPT, SW_USART_TX_PIN, SW_USART_TX_PRESCALE, SwUartTICKS2WAITONE, SwUsartRXState, and SwUsartTXState.
Referenced by cdc_task_init().
00201 { 00202 /* Setup the TRX PORT for the Soft UART. 00203 * RX_PIN is input, tri-stated. 00204 * TX_PIN is output, set high to IDLE state. 00205 */ 00206 SW_USART_TRX_PORT |= ( 1 << SW_USART_RX_PIN ); 00207 SW_USART_TRX_DDR |= ( 1 << SW_USART_TX_PIN ); 00208 SW_USART_SET_TX_PIN(); 00209 00210 /* Disable all TX and RX interrupts. */ 00211 SW_USART_RX_DISABLE_TIMER_INTERRUPT(); 00212 SW_USART_TX_DISABLE_TIMER_INTERRUPT(); 00213 00214 /* Initialize the RX Timer to CTC mode. 00215 * This will clear the timer on compare match, and the counter start 00216 * at bottom again. The compare value is equal to on bit length. 00217 */ 00218 SW_USART_RX_PRESCALE = 0x00; 00219 SW_USART_RX_CTRL = 0x02; 00220 SW_USART_RX_COMPARE = SwUartTICKS2WAITONE; 00221 00222 /* Initialize the TX Timer to CTC mode. 00223 * This will clear the timer on compare match, and the counter start 00224 * at bottom again. The compare value is equal to on bit length. 00225 */ 00226 SW_USART_TX_PRESCALE = 0x00; 00227 SW_USART_TX_CTRL = 0x02; 00228 SW_USART_TX_COMPARE = SwUartTICKS2WAITONE; 00229 00230 /* Initialize the RX external interrupt for sensing the start bit. 00231 * This will trigger on the falling edge of the IO pin. 00232 * Clear any pending interrupts and enable the interrupt. 00233 */ 00234 SW_USART_EXT_ICR |= ( 1 << ISC01 ); 00235 SW_USART_EXT_IFR |= (1 << INTF0 ); 00236 SW_USART_RX_ENABLE_EXTERNAL0_INTERRUPT(); 00237 00238 /* Set TRX states initially to IDLE. */ 00239 SwUsartRXState = IDLE; 00240 SwUsartTXState = IDLE; 00241 }
void SW_USART_PutChar | ( | const uint8_t | c | ) |
Send a unsigned char.
This function sends a unsigned char on the TX_PIN using the timer2 isr.
c | char to transmit. |
void |
Definition at line 255 of file sw_usart.c.
References IDLE, SW_USART_CLR_TX_PIN, SW_USART_TX_CLEAR_TIMER_INTERRUPT, SW_USART_TX_COMPARE, SW_USART_TX_DISABLE_PRESCALER, SW_USART_TX_ENABLE_PRESCALER, SW_USART_TX_ENABLE_TIMER_INTERRUPT, SW_USART_TX_TIMER, SwUartTICKS2WAITONE, SwUartTXBitCount, SwUartTXData, SwUsartTXState, and TRANSMIT.
Referenced by cdc_task().
00256 { 00257 /* Wait until the TX is not busy or the communication will fail */ 00258 while( SwUsartTXState != IDLE ){ 00259 } 00260 00261 /* Disable the clock to the timer and set the compare value to one bit length. */ 00262 SW_USART_TX_DISABLE_PRESCALER(); 00263 SW_USART_TX_COMPARE = SwUartTICKS2WAITONE; 00264 00265 /* Change state to indicate that the TX is busy. */ 00266 SwUsartTXState = TRANSMIT; 00267 00268 /* Set intial bitcount value and copy byte into the TX buffer. */ 00269 SwUartTXData = c; 00270 SwUartTXBitCount = 0; 00271 00272 /* Clear the timer counter value and clear any pending interrupts. */ 00273 SW_USART_TX_TIMER = 0; 00274 SW_USART_TX_CLEAR_TIMER_INTERRUPT(); 00275 00276 /* Start the timer, set pin value to transmit start bit and enable interrupt. */ 00277 SW_USART_TX_ENABLE_PRESCALER(); 00278 SW_USART_CLR_TX_PIN(); 00279 SW_USART_TX_ENABLE_TIMER_INTERRUPT(); 00280 }
uint8_t SW_USART_RX_Buffer_GetByte | ( | void | ) |
Get byte from the RX buffer.
Byte | from buffer |
Definition at line 336 of file sw_usart.c.
References AVR_ENTER_CRITICAL_REGION, AVR_LEAVE_CRITICAL_REGION, SW_USART_BUFFER_SIZE, SW_USART_RX_Buffer, SW_USART_RX_Num, and SW_USART_RX_Tail.
Referenced by cdc_task().
00337 { 00338 uint8_t ret_byte = 0; 00339 00340 /* Check if there is any bytes in the buffer. */ 00341 if(SW_USART_RX_Num > 0){ 00342 ret_byte = SW_USART_RX_Buffer[SW_USART_RX_Tail]; 00343 00344 /* Enter a critical region as the value might be changed in an interrupt. */ 00345 AVR_ENTER_CRITICAL_REGION(); 00346 00347 /* Decrease number of bytes left in buffer. */ 00348 SW_USART_RX_Num--; 00349 00350 /* Leave the critical region and restore SREG register. */ 00351 AVR_LEAVE_CRITICAL_REGION(); 00352 00353 /* Increase the tail pointer and wrap around if necessary. */ 00354 SW_USART_RX_Tail++; 00355 if(SW_USART_RX_Tail >= SW_USART_BUFFER_SIZE){ 00356 SW_USART_RX_Tail = 0; 00357 } 00358 } 00359 return ret_byte; 00360 }
void SW_USART_RX_Buffer_PutByte | ( | uint8_t | rx_byte | ) |
Function to put byte in RX buffer.
rx_byte | to put into buffer. |
Definition at line 310 of file sw_usart.c.
References SW_USART_BUFFER_SIZE, SW_USART_RX_Buffer, SW_USART_RX_Head, and SW_USART_RX_Num.
Referenced by ISR().
00311 { 00312 /* Check if buffer is full. The byte will be lost if the buffer is full.*/ 00313 if(SW_USART_RX_Num < SW_USART_BUFFER_SIZE ){ 00314 SW_USART_RX_Buffer[SW_USART_RX_Head] = rx_byte; 00315 00316 /* Increase the number of bytes in buffer and the pointer. */ 00317 SW_USART_RX_Num++; 00318 SW_USART_RX_Head++; 00319 00320 /* Check if we should wrap around. */ 00321 if(SW_USART_RX_Head >= SW_USART_BUFFER_SIZE){ 00322 SW_USART_RX_Head = 0; 00323 } 00324 } 00325 }
void SW_USART_Set_Baudrate | ( | uint32_t | new_baud | ) |
Set new baudrate.
new_baud | The new baudrate to set. |
Definition at line 369 of file sw_usart.c.
Referenced by cdc_set_line_coding().
uint8_t SW_USART_Test_Hit | ( | void | ) |
Function to check if data is pending in the buffer.
true | if data is pending, false otherwise |
Definition at line 287 of file sw_usart.c.
References SW_USART_RX_Num.
Referenced by cdc_task().
00288 { 00289 return (SW_USART_RX_Num > 0); 00290 }
uint8_t SW_USART_Tx_Ready | ( | void | ) |
Function to check if transmitter is busy.
true | if ready, false otherwise. |
Definition at line 297 of file sw_usart.c.
References IDLE, and SwUsartTXState.
00298 { 00299 return ( SwUsartTXState == IDLE ); 00300 }
Generated on Mon Jan 18 09:26:10 2010 for AVR1907 Xplain USB Gateway by ![]() |