?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 6

Line No. Rev Author Line
1 6 kaklik /*! \file uartsw2.c \brief Software Interrupt-driven UART Driver. */
2 //*****************************************************************************
3 //
4 // File Name : 'uartsw2.c'
5 // Title : Software Interrupt-driven UART Driver
6 // Author : Pascal Stang - Copyright (C) 2002-2004
7 // Created : 7/20/2002
8 // Revised : 4/27/2004
9 // Version : 0.6
10 // Target MCU : Atmel AVR Series (intended for the ATmega16 and ATmega32)
11 // Editor Tabs : 4
12 //
13 // This code is distributed under the GNU Public License
14 // which can be found at http://www.gnu.org/licenses/gpl.txt
15 //
16 //*****************************************************************************
17  
18 #include <avr/io.h>
19 #include <avr/interrupt.h>
20  
21 #include "global.h"
22 #include "timer.h"
23 #include "uartsw2.h"
24  
25 // Program ROM constants
26  
27 // Global variables
28  
29 // uartsw transmit status and data variables
30 static volatile u08 UartswTxBusy;
31 static volatile u08 UartswTxData;
32 static volatile u08 UartswTxBitNum;
33  
34 // baud rate common to transmit and receive
35 static volatile u08 UartswBaudRateDiv;
36  
37 // uartsw receive status and data variables
38 static volatile u08 UartswRxBusy;
39 static volatile u08 UartswRxData;
40 static volatile u08 UartswRxBitNum;
41 // receive buffer
42 static cBuffer uartswRxBuffer; ///< uartsw receive buffer
43 // automatically allocate space in ram for each buffer
44 static char uartswRxData[UARTSW_RX_BUFFER_SIZE];
45  
46 // functions
47  
48 //! enable and initialize the software uart
49 void uartswInit(void)
50 {
51 // initialize the buffers
52 uartswInitBuffers();
53 // initialize the ports
54 sbi(UARTSW_TX_DDR, UARTSW_TX_PIN);
55 #ifdef UARTSW_INVERT
56 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
57 #else
58 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
59 #endif
60 cbi(UARTSW_RX_DDR, UARTSW_RX_PIN);
61 cbi(UARTSW_RX_PORT, UARTSW_RX_PIN);
62 // initialize baud rate
63 uartswSetBaudRate(9600);
64  
65 // setup the transmitter
66 UartswTxBusy = FALSE;
67 // disable OC2 interrupt
68 cbi(TIMSK, OCIE2);
69 // attach TxBit service routine to OC2
70 timerAttach(TIMER2OUTCOMPARE_INT, uartswTxBitService);
71  
72 // setup the receiver
73 UartswRxBusy = FALSE;
74 // disable OC0 interrupt
75 cbi(TIMSK, OCIE0);
76 // attach RxBit service routine to OC0
77 timerAttach(TIMER0OUTCOMPARE_INT, uartswRxBitService);
78 // INT2 trigger on rising/falling edge
79 #ifdef UARTSW_INVERT
80 sbi(MCUCSR, ISC2); // rising edge
81 #else
82 cbi(MCUCSR, ISC2); // falling edge
83 #endif
84 // enable INT2 interrupt
85 sbi(GICR, INT2);
86  
87 // turn on interrupts
88 sei();
89 }
90  
91 //! create and initialize the uart buffers
92 void uartswInitBuffers(void)
93 {
94 // initialize the UART receive buffer
95 bufferInit(&uartswRxBuffer, uartswRxData, UARTSW_RX_BUFFER_SIZE);
96 }
97  
98 //! turns off software UART
99 void uartswOff(void)
100 {
101 // disable interrupts
102 cbi(TIMSK, OCIE2);
103 cbi(TIMSK, OCIE0);
104 cbi(GICR, INT2);
105 // detach the service routines
106 timerDetach(TIMER2OUTCOMPARE_INT);
107 timerDetach(TIMER0OUTCOMPARE_INT);
108 }
109  
110 void uartswSetBaudRate(u32 baudrate)
111 {
112 u16 div;
113  
114 // set timer prescaler
115 if( baudrate > (F_CPU/64L*256L) )
116 {
117 // if the requested baud rate is high,
118 // set timer prescalers to div-by-64
119 timer2SetPrescaler(TIMERRTC_CLK_DIV64);
120 timer0SetPrescaler(TIMER_CLK_DIV64);
121 div = 64;
122 }
123 else
124 {
125 // if the requested baud rate is low,
126 // set timer prescalers to div-by-256
127 timer2SetPrescaler(TIMERRTC_CLK_DIV256);
128 timer0SetPrescaler(TIMER_CLK_DIV256);
129 div = 256;
130 }
131  
132 // calculate division factor for requested baud rate, and set it
133 //UartswBaudRateDiv = (u08)(((F_CPU/64L)+(baudrate/2L))/(baudrate*1L));
134 //UartswBaudRateDiv = (u08)(((F_CPU/256L)+(baudrate/2L))/(baudrate*1L));
135 UartswBaudRateDiv = (u08)(((F_CPU/div)+(baudrate/2L))/(baudrate*1L));
136 }
137  
138 //! returns the receive buffer structure
139 cBuffer* uartswGetRxBuffer(void)
140 {
141 // return rx buffer pointer
142 return &uartswRxBuffer;
143 }
144  
145 void uartswSendByte(u08 data)
146 {
147 // wait until uart is ready
148 while(UartswTxBusy);
149 // set busy flag
150 UartswTxBusy = TRUE;
151 // save data
152 UartswTxData = data;
153 // set number of bits (+1 for stop bit)
154 UartswTxBitNum = 9;
155  
156 // set the start bit
157 #ifdef UARTSW_INVERT
158 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
159 #else
160 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
161 #endif
162 // schedule the next bit
163 outb(OCR2, inb(TCNT2) + UartswBaudRateDiv);
164 // enable OC2 interrupt
165 sbi(TIMSK, OCIE2);
166 }
167  
168 //! gets a byte (if available) from the uart receive buffer
169 u08 uartswReceiveByte(u08* rxData)
170 {
171 // make sure we have a receive buffer
172 if(uartswRxBuffer.size)
173 {
174 // make sure we have data
175 if(uartswRxBuffer.datalength)
176 {
177 // get byte from beginning of buffer
178 *rxData = bufferGetFromFront(&uartswRxBuffer);
179 return TRUE;
180 }
181 else
182 {
183 // no data
184 return FALSE;
185 }
186 }
187 else
188 {
189 // no buffer
190 return FALSE;
191 }
192 }
193  
194 void uartswTxBitService(void)
195 {
196 if(UartswTxBitNum)
197 {
198 // there are bits still waiting to be transmitted
199 if(UartswTxBitNum > 1)
200 {
201 // transmit data bits (inverted, LSB first)
202 #ifdef UARTSW_INVERT
203 if( !(UartswTxData & 0x01) )
204 #else
205 if( (UartswTxData & 0x01) )
206 #endif
207 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
208 else
209 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
210 // shift bits down
211 UartswTxData = UartswTxData>>1;
212 }
213 else
214 {
215 // transmit stop bit
216 #ifdef UARTSW_INVERT
217 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
218 #else
219 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
220 #endif
221 }
222 // schedule the next bit
223 outb(OCR2, inb(OCR2) + UartswBaudRateDiv);
224 // count down
225 UartswTxBitNum--;
226 }
227 else
228 {
229 // transmission is done
230 // clear busy flag
231 UartswTxBusy = FALSE;
232 // disable OC2 interrupt
233 cbi(TIMSK, OCIE2);
234 }
235 }
236  
237 void uartswRxBitService(void)
238 {
239 // this function runs on either:
240 // - a rising edge interrupt
241 // - Timer 0 output compare
242 if(!UartswRxBusy)
243 {
244 // UART was not previously busy,
245 // this must be is a start bit
246  
247 // disable INT2 interrupt
248 cbi(GICR, INT2);
249 // schedule data bit sampling 1.5 bit periods from now
250 outb(OCR0, inb(TCNT0) + UartswBaudRateDiv + UartswBaudRateDiv/2);
251 // clear OC0 interrupt flag
252 sbi(TIFR, OCF0);
253 // enable OC0 interrupt
254 sbi(TIMSK, OCIE0);
255 // set busy flag
256 UartswRxBusy = TRUE;
257 // reset bit counter
258 UartswRxBitNum = 0;
259 // reset data
260 UartswRxData = 0;
261 }
262 else
263 {
264 // start bit has already been received
265 // we're in the data bits
266  
267 // shift data byte to make room for new bit
268 UartswRxData = UartswRxData>>1;
269  
270 // sample the data line
271 #ifdef UARTSW_INVERT
272 if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
273 #else
274 if( (inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
275 #endif
276 {
277 // serial line is marking
278 // record '1' bit
279 UartswRxData |= 0x80;
280 }
281  
282 // increment bit counter
283 UartswRxBitNum++;
284 // schedule next bit sample
285 outb(OCR0, inb(OCR0) + UartswBaudRateDiv);
286  
287 // check if we have a full byte
288 if(UartswRxBitNum >= 8)
289 {
290 // save data in receive buffer
291 bufferAddToEnd(&uartswRxBuffer, UartswRxData);
292 // disable OC0 interrupt
293 cbi(TIMSK, OCIE0);
294 // clear INT2 interrupt flag
295 sbi(GIFR, INTF2);
296 // enable INT interrupt
297 sbi(GICR, INT2);
298 // clear busy flag
299 UartswRxBusy = FALSE;
300 }
301 }
302 }
303  
304 SIGNAL(SIG_INTERRUPT2)
305 {
306 // run RxBit service routine
307 uartswRxBitService();
308 }
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3