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

Powered by WebSVN v2.8.3