?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 uartsw.c \brief Software Interrupt-driven UART Driver. */
2 //*****************************************************************************
3 //
4 // File Name : 'uartsw.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.1
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 "uartsw.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 u16 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 cbi(UARTSW_RX_DDR, UARTSW_RX_PIN);
56 cbi(UARTSW_RX_PORT, UARTSW_RX_PIN);
57 // initialize baud rate
58 uartswSetBaudRate(9600);
59  
60 // setup the transmitter
61 UartswTxBusy = FALSE;
62 // disable OC1A interrupt
63 cbi(TIMSK, OCIE1A);
64 // attach TxBit service routine to OC1A
65 timerAttach(TIMER1OUTCOMPAREA_INT, uartswTxBitService);
66  
67 // setup the receiver
68 UartswRxBusy = FALSE;
69 // disable OC1B interrupt
70 cbi(TIMSK, OCIE1B);
71 // attach RxBit service routine to OC1B
72 timerAttach(TIMER1OUTCOMPAREB_INT, uartswRxBitService);
73 // attach RxBit service routine to ICP
74 timerAttach(TIMER1INPUTCAPTURE_INT, uartswRxBitService);
75 #ifdef UARTSW_INVERT
76 // trigger on rising edge
77 sbi(TCCR1B, ICES1);
78 #else
79 // trigger on falling edge
80 cbi(TCCR1B, ICES1);
81 #endif
82 // enable ICP interrupt
83 sbi(TIMSK, TICIE1);
84  
85 // turn on interrupts
86 sei();
87 }
88  
89 //! create and initialize the uart buffers
90 void uartswInitBuffers(void)
91 {
92 // initialize the UART receive buffer
93 bufferInit(&uartswRxBuffer, uartswRxData, UARTSW_RX_BUFFER_SIZE);
94 }
95  
96 //! turns off software UART
97 void uartswOff(void)
98 {
99 // disable interrupts
100 cbi(TIMSK, OCIE1A);
101 cbi(TIMSK, OCIE1B);
102 cbi(TIMSK, TICIE1);
103 // detach the service routines
104 timerDetach(TIMER1OUTCOMPAREA_INT);
105 timerDetach(TIMER1OUTCOMPAREB_INT);
106 timerDetach(TIMER1INPUTCAPTURE_INT);
107 }
108  
109 void uartswSetBaudRate(u32 baudrate)
110 {
111 // set timer prescaler
112 timer1SetPrescaler(TIMER_CLK_DIV1);
113 // calculate division factor for requested baud rate, and set it
114 UartswBaudRateDiv = (u16)((F_CPU+(baudrate/2L))/(baudrate*1L));
115 }
116  
117 //! returns the receive buffer structure
118 cBuffer* uartswGetRxBuffer(void)
119 {
120 // return rx buffer pointer
121 return &uartswRxBuffer;
122 }
123  
124 void uartswSendByte(u08 data)
125 {
126 // wait until uart is ready
127 while(UartswTxBusy);
128 // set busy flag
129 UartswTxBusy = TRUE;
130 // save data
131 UartswTxData = data;
132 // set number of bits (+1 for stop bit)
133 UartswTxBitNum = 9;
134  
135 // set the start bit
136 #ifdef UARTSW_INVERT
137 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
138 #else
139 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
140 #endif
141  
142 // schedule the next bit
143 outw(OCR1A, inw(TCNT1) + UartswBaudRateDiv);
144 // enable OC1A interrupt
145 sbi(TIMSK, OCIE1A);
146 }
147  
148 //! gets a byte (if available) from the uart receive buffer
149 u08 uartswReceiveByte(u08* rxData)
150 {
151 // make sure we have a receive buffer
152 if(uartswRxBuffer.size)
153 {
154 // make sure we have data
155 if(uartswRxBuffer.datalength)
156 {
157 // get byte from beginning of buffer
158 *rxData = bufferGetFromFront(&uartswRxBuffer);
159 return TRUE;
160 }
161 else
162 {
163 // no data
164 return FALSE;
165 }
166 }
167 else
168 {
169 // no buffer
170 return FALSE;
171 }
172 }
173  
174 void uartswTxBitService(void)
175 {
176 if(UartswTxBitNum)
177 {
178 // there are bits still waiting to be transmitted
179 if(UartswTxBitNum > 1)
180 {
181 // transmit data bits (inverted, LSB first)
182 #ifdef UARTSW_INVERT
183 if( !(UartswTxData & 0x01) )
184 #else
185 if( (UartswTxData & 0x01) )
186 #endif
187 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
188 else
189 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
190 // shift bits down
191 UartswTxData = UartswTxData>>1;
192 }
193 else
194 {
195 // transmit stop bit
196 #ifdef UARTSW_INVERT
197 cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
198 #else
199 sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);
200 #endif
201 }
202 // schedule the next bit
203 outw(OCR1A, inw(OCR1A) + UartswBaudRateDiv);
204 // count down
205 UartswTxBitNum--;
206 }
207 else
208 {
209 // transmission is done
210 // clear busy flag
211 UartswTxBusy = FALSE;
212 }
213 }
214  
215 void uartswRxBitService(void)
216 {
217 // this function runs on either:
218 // - a rising edge interrupt
219 // - OC1B
220 if(!UartswRxBusy)
221 {
222 // this is a start bit
223 // disable ICP interrupt
224 cbi(TIMSK, TICIE1);
225 // schedule data bit sampling 1.5 bit periods from now
226 outw(OCR1B, inw(TCNT1) + UartswBaudRateDiv + UartswBaudRateDiv/2);
227 // clear OC1B interrupt flag
228 sbi(TIFR, OCF1B);
229 // enable OC1B interrupt
230 sbi(TIMSK, OCIE1B);
231 // set start bit flag
232 UartswRxBusy = TRUE;
233 // reset bit counter
234 UartswRxBitNum = 0;
235 // reset data
236 UartswRxData = 0;
237 }
238 else
239 {
240 // start bit has already been received
241 // we're in the data bits
242  
243 // shift data byte to make room for new bit
244 UartswRxData = UartswRxData>>1;
245  
246 // sample the data line
247 #ifdef UARTSW_INVERT
248 if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
249 #else
250 if( (inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )
251 #endif
252 {
253 // serial line is marking
254 // record '1' bit
255 UartswRxData |= 0x80;
256 }
257  
258 // increment bit counter
259 UartswRxBitNum++;
260 // schedule next bit sample
261 outw(OCR1B, inw(OCR1B) + UartswBaudRateDiv);
262  
263 // check if we have a full byte
264 if(UartswRxBitNum >= 8)
265 {
266 // save data in receive buffer
267 bufferAddToEnd(&uartswRxBuffer, UartswRxData);
268 // disable OC1B interrupt
269 cbi(TIMSK, OCIE1B);
270 // clear ICP interrupt flag
271 sbi(TIFR, ICF1);
272 // enable ICP interrupt
273 sbi(TIMSK, TICIE1);
274 // clear start bit flag
275 UartswRxBusy = FALSE;
276 }
277 }
278 }
279  
280 /*
281 void uartswRxBitService(void)
282 {
283 u16 thisBitTime;
284 u08 bitperiods;
285 u08 i;
286  
287 // bit transition was detected
288 // record bit's edge time
289 thisBitTime = inw(ICR1);
290  
291 cbi(PORTB, 0);
292  
293 if(!UartswRxStartBit)
294 {
295 // this is a start bit
296 // switch to falling-edge trigger
297 cbi(TCCR1B, ICES1);
298 // record bit time
299 UartswRxBitTime = thisBitTime;
300 // set start bit flag
301 UartswRxStartBit = TRUE;
302 // reset bit counter
303 UartswRxBitNum = 0;
304 // reset data
305 UartswRxData = 0;
306 }
307 else
308 {
309 // start bit has already been received
310 // we're in the data bits
311  
312 // how many bit periods since last edge?
313 bitperiods = (thisBitTime - UartswRxBitTime + UartswBaudRateDiv/2)/UartswBaudRateDiv;
314 // set last edge time
315 UartswRxBitTime = thisBitTime;
316  
317 if(bitperiods > 10)
318 {
319 // switch to trigger on rising edge
320 sbi(TCCR1B, ICES1);
321 // clear start bit flag
322 UartswRxStartBit = FALSE;
323 }
324 else
325 {
326  
327  
328 if( inb(TCCR1B) & (1<<ICES1) )
329 {
330 // just triggered on a rising edge
331 // previous bits were zero
332 // shift in the data (data bits are inverted)
333 for(i=0; i<bitperiods; i++)
334 {
335 UartswRxData = UartswRxData<<1;
336 UartswRxData |= 0x01;
337 }
338 // switch to trigger on falling edge
339 cbi(TCCR1B, ICES1);
340 }
341 else
342 {
343 // just triggered on a falling edge
344 // previous bits were one
345 // shift in the data (data bits are inverted)
346 for(i=0; i<bitperiods; i++)
347 {
348 UartswRxData = UartswRxData<<1;
349 }
350 // switch to trigger on rising edge
351 sbi(TCCR1B, ICES1);
352 }
353  
354 // increment bit counter
355 UartswRxBitNum += bitperiods;
356  
357 // check if we have a full byte + start bit
358 if(bitperiods > 8)
359 {
360 // save data in receive buffer
361 bufferAddToEnd(&uartswRxBuffer, UartswRxData);
362 // switch to trigger on rising edge
363 sbi(TCCR1B, ICES1);
364 // clear start bit flag
365 UartswRxStartBit = FALSE;
366 }
367 }
368 }
369  
370 // turn off debug LEDs
371 delay(10);
372 sbi(PORTB, 0);
373 sbi(PORTB, 1);
374 }
375 */
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3