20080319 release: CV support
[avr_serial_lcd.git] / serial_lcd.c
1 /*****************************************************************************\r
2 ** FILE IDENTIFICATION\r
3 **\r
4 **   Name:          serial_lcd.cpp\r
5 **   Purpose:       USART driven HD44780 LCD Driver\r
6 **   Programmer:    Kevin Rosenberg <kevin@rosenberg.net>\r
7 **                    (AVR Freaks member kmr)\r
8 **   Date Started:  Dec 2007\r
9 **\r
10 **   Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
11 **\r
12 ** Compilers supported:\r
13 **   - WinAVR-20071221 (includes avr-libc 1.6 required for proper _delay_us)\r
14 **   - IAR AVR 4.30 and 5.10\r
15 **   - Imagecraft AVR 7.16\r
16 **   - Codevision AVR 2.02.06\r
17 **\r
18 ** LICENSE\r
19 **   See accompaning LICENSE file\r
20 **\r
21 ** CHANGES\r
22 **   See accompaning CHANGES file for modifications log from original\r
23 ******************************************************************************/\r
24 \r
25 #include "serial_lcd.h"\r
26 \r
27 #if defined(__GNUC__)\r
28 FUSES = {\r
29   .low = SUT1, \r
30   .high = (unsigned char) (DWEN & WDTON & RSTDISBL & BODLEVEL1 & BODLEVEL2),\r
31   .extended = EFUSE_DEFAULT,\r
32 };\r
33 #endif\r
34   \r
35 // Number of PWM brightness levels supported\r
36 #define LED_BRIGHTNESS_LEVELS 8\r
37 \r
38 ////// LCD Commands ///////\r
39 // Turn on power to the display, no cursor\r
40 #define LCD_ON  0x0C\r
41 // Clear display command\r
42 #define LCD_CLR 0x01\r
43 // Set 4 data bits \r
44 #define LCD_4_Bit 0x20 \r
45 // Set 8 data bits \r
46 #define LCD_8_Bit 0x30 \r
47 // Set number of lines \r
48 #define LCD_4_Line 0x08 \r
49 // Set 8 data bits\r
50 #define DATA_8  0x30\r
51 // Set character font \r
52 #define LCD_Font 0x04 \r
53 // Turn the cursor on \r
54 #define LCD_CURSOR_ON 0x02 \r
55 // Turn on cursor blink \r
56 #define LCD_CURSOR_BLINK 0x01 \r
57 \r
58 ////// Serial command codes ///////\r
59 // ASCII control code to set brightness level\r
60 // Next byte is brightness ranging from 0 (no backlight) to 255 (max backlight)\r
61 #define LED_SET_BRIGHTNESS 0xFB\r
62 // ASCII control code turns on LED\r
63 #define LED_SW_ON 0xFC\r
64 // ASCII control code turns off LED\r
65 #define LED_SW_OFF 0xFD\r
66 // Character generator RAM command\r
67 #define REG_MODE 0xFE\r
68 \r
69 // Circular buffer for UART RX\r
70 #define UART_RX_BUFFER_SIZE 48\r
71 #if defined(__IMAGECRAFT__)\r
72 #pragma data:noinit\r
73 volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE];\r
74 #pragma data:data\r
75 #else\r
76 NO_INIT_DECLARE(volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE]);\r
77 #endif\r
78 \r
79 // PWM Patterns (8-brightness levels)\r
80 static FLASH_DECLARE(const unsigned char ledPwmPatterns[]) =\r
81 {\r
82   0x10, // 0b00010000  0\r
83   0x11, // 0b00010001  1\r
84   0x4A, // 0b01001010  2\r
85   0x55, // 0b01010101  3\r
86   0x5D, // 0b01011101  4\r
87   0xEE, // 0b11101110  5\r
88   0x7F, // 0b11110111  6\r
89   0xFF, // 0b11111111  7\r
90 };\r
91 \r
92 // register variables\r
93 #if defined(__IMAGECRAFT__)\r
94 #pragma global_register ledPwmCount:20 sUartRxHead:21 sUartRxTail:22 ledPwmCycling:23\r
95 unsigned char ledPwmCount, sUartRxHead, sUartRxTail, ledPwmCycling;\r
96 \r
97 #elif defined(__CODEVISIONAVR__)\r
98 #pragma regalloc-\r
99 register unsigned char ledPwmCount, sUartRxHead, sUartRxTail, ledPwmCycling;\r
100 #pragma regalloc+\r
101 \r
102 // Use avr_compat register variables\r
103 #else\r
104 REGISTER_VAR(unsigned char ledPwmCount, "r4", 15);\r
105 REGISTER_VAR(unsigned char sUartRxHead, "r5", 14);\r
106 REGISTER_VAR(unsigned char sUartRxTail, "r6", 13);\r
107 REGISTER_VAR(unsigned char ledPwmCycling, "r7", 12);\r
108 #endif\r
109 \r
110 #define ledPwmPattern GPIOR0\r
111 #if defined(REGISTER_BIT)\r
112 #define BIT_led_on REGISTER_BIT(GPIOR1,0)\r
113 #define BACKLIGHT_STATUS() BIT_led_on\r
114 #define BACKLIGHT_OFF() BIT_led_on = 0\r
115 #define BACKLIGHT_ON() BIT_led_on = 1\r
116 #else\r
117 #define BACKLIGHT_STATUS() (GPIOR1 & 0x01)\r
118 #define BACKLIGHT_OFF() GPIOR1 &=~ ~0x01\r
119 #define BACKLIGHT_ON() GPIOR1 |= 0x01\r
120 #endif\r
121 \r
122 // Function declarations\r
123 void LcdWriteCmd (unsigned char);\r
124 void LcdWriteData (unsigned char);\r
125 unsigned char LcdBusyWait (void);\r
126 static unsigned char WaitRxChar (void);\r
127 \r
128 // ImageCraft/Codevision don't support inline functions, so use preprocessor\r
129 #if defined(__IMAGECRAFT__) || defined(__CODEVISIONAVR__)\r
130 #define LedTimerStop() TCCR0B = 0\r
131 // Start with 256 prescaler\r
132 #define LedTimerStart() TCCR0B = (1<<CS02)\r
133 \r
134 #else\r
135 // Using a platform that has proper inline functions\r
136 INLINE_FUNC_DECLARE(static void LedTimerStop (void));\r
137 static inline void LedTimerStop (void) {\r
138   TCCR0B = 0;\r
139 }\r
140 \r
141 INLINE_FUNC_DECLARE(static void LedTimerStart (void));\r
142 static inline void LedTimerStart (void) {\r
143   TCCR0B = (1<<CS02); // Start with 256 prescaler\r
144 }\r
145 #endif\r
146 \r
147 INLINE_FUNC_DECLARE(static void LedPwmInit (void));\r
148 static inline void LedPwmInit (void) {\r
149   // setup PWM to run at 1.25ms per interrupt.\r
150   // This allows 8 levels of brightness at minimum of 100Hz flicker rate.\r
151   TCCR0A = (1<<WGM01);  // CTC mode\r
152   TCCR0B = 0;           // timer off\r
153   OCR0A = 72;           // 1.25ms with CLK/256 prescaler @ 14.7456MHz\r
154   TIMSK = (1<<OCIE0A);  // Turn on timer0 COMPA intr (all other timer intr off)\r
155   LED_PORT &= ~(1<<LED_PIN); // Ensure LED is off during initialization\r
156   LED_DIR |= (1<<LED_PIN);   // Ensure LED is output direction\r
157   BACKLIGHT_OFF();       // note that LED is off\r
158   ledPwmPattern = 0xFF; // maximum brightness\r
159 }\r
160 \r
161 \r
162 INLINE_FUNC_DECLARE(static void LedPwmSetBrightness (unsigned char brightness));\r
163 static inline void LedPwmSetBrightness (unsigned char brightness) {\r
164   unsigned char ledPwmPos;\r
165 \r
166   if (brightness == 0) { // turn backlight off for 0 brightness\r
167     if (BACKLIGHT_STATUS()) {\r
168       LedTimerStop();\r
169       ledPwmPattern = 0;\r
170       ledPwmCycling = 0;\r
171       LED_PORT &= ~(1<<LED_PIN);\r
172     }\r
173     return;\r
174   }\r
175 \r
176   ledPwmPos = (brightness * (LED_BRIGHTNESS_LEVELS-1) + (unsigned int) 127) >> 8;\r
177   // Below is probably not required, but ensures we don't exceed array\r
178   if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1)\r
179     ledPwmPos = LED_BRIGHTNESS_LEVELS - 1;\r
180 \r
181   ledPwmPattern = PGM_READ_BYTE (&ledPwmPatterns[ledPwmPos]);\r
182   ledPwmCount = 0;\r
183   ledPwmCycling = ledPwmPattern;\r
184   if (ledPwmPos >= LED_BRIGHTNESS_LEVELS-1) { // maximum brightness\r
185     // don't need PWM for continuously on\r
186     if (BACKLIGHT_STATUS()) {\r
187       LedTimerStop();\r
188       LED_PORT |= (1<<LED_PIN);\r
189     }\r
190   } else {\r
191     if (BACKLIGHT_STATUS()) {\r
192       LedTimerStart();\r
193     }\r
194   }\r
195 }\r
196 \r
197 INLINE_FUNC_DECLARE(static void LedPwmSwitchOff (void));\r
198 static inline void LedPwmSwitchOff (void) {\r
199   LED_PORT &= ~(1<<LED_PIN);\r
200   BACKLIGHT_OFF();\r
201   LedTimerStop();\r
202 }\r
203 \r
204 INLINE_FUNC_DECLARE(static void LedPwmSwitchOn (void));\r
205 static inline void LedPwmSwitchOn (void) {\r
206   BACKLIGHT_ON();\r
207   if (ledPwmPattern == 0xFF) { // maximum brightness, no need for PWM\r
208     LedTimerStop();\r
209     LED_PORT |= (1<<LED_PIN); // keep LED on at all times\r
210   } else {\r
211     LedTimerStart();\r
212   }\r
213 }\r
214 \r
215 // Actual baud rate = 9600 BAUD, (0.0% error) @ 14.7456MHz\r
216 // Actual baud rate = 19.2K BAUD, (0.0% error) @ 14.7456MHz\r
217 // Actual baud rate = 38.4K BAUD, (0.0% error) @ 14.7456MHz\r
218 // Actual baud rate = 115.2K BAUD, (0.0% error) @ 14.7456MHz\r
219 #define BAUD_4800 191\r
220 #define BAUD_9600 95\r
221 #define BAUD_14400 63\r
222 #define BAUD_19200 47\r
223 #define BAUD_28800 31\r
224 #define BAUD_38400 23\r
225 #define BAUD_57600 15\r
226 #define BAUD_76800 11\r
227 #define BAUD_115200 7\r
228 \r
229 FLASH_DECLARE(static const unsigned char BaudLookupTable[])\r
230 = {BAUD_115200, BAUD_38400, BAUD_19200, BAUD_9600};\r
231 \r
232 INLINE_FUNC_DECLARE(static unsigned char GetUsartBaud (void));\r
233 static inline unsigned char GetUsartBaud (void) {\r
234   // Get BAUD rate jumper settings\r
235   unsigned char BaudSelectJumpersValue  = BAUD_PIN_REG;\r
236   // Mask off unwanted bits\r
237   BaudSelectJumpersValue &= (1<<BAUD_J2) | (1<<BAUD_J1);\r
238   // BAUD_J2 = PD.3, BAUD_J1 = PD.2\r
239   // This is two bits too far to the left and the array index will\r
240   // increment by 4, instead of 1.\r
241   // Shift BAUD_J2 & BAUD_J1 right by two bit positions for proper array indexing\r
242   BaudSelectJumpersValue = (BaudSelectJumpersValue >> BAUD_J1);\r
243 \r
244   return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]);\r
245 }\r
246 \r
247 \r
248 INLINE_FUNC_DECLARE(static void UsartInit (void));\r
249 static inline void UsartInit(void) {\r
250   // Initialize USART\r
251   UCSRB = 0; // Disable while setting baud rate\r
252   UCSRA = 0;\r
253   UCSRC = (1<<UCSZ1) | (1<<UCSZ0); // 8 bit data\r
254   UBRRL = GetUsartBaud (); // Set baud rate\r
255   UBRRH = 0; // Set baud rate hi\r
256   UCSRB = (1<<RXEN)|(1<<RXCIE); // RXEN = Enable\r
257   sUartRxHead = 0; // register variable, need to explicitly zero\r
258   sUartRxTail = 0; // register variable, need to explicitly zero\r
259 \r
260 #if USE_CTS\r
261   CTS_PORT |= (1<<CTS_PIN);  // bring signal high\r
262   CTS_DIR |= (1<<CTS_PIN);   // CTS is active low\r
263 #endif\r
264 }\r
265 \r
266 #if defined(__IMAGECRAFT__) || defined(__CODEVISIONAVR__)\r
267 // Clock cycle = 67nS @ 14.7456MHz\r
268 // Delay resolution ~ 1uS @ 14.7456MHz\r
269 // So this function is only accurate at near above frequency\r
270 void _delay_us (unsigned int d) {\r
271   while (d-- != 0);\r
272 #if defined(__IMAGECRAFT__)\r
273   asm("nop");\r
274 #elif defined(__CODEVISIONAVR__)\r
275   #asm("nop")\r
276 #endif\r
277 }\r
278 #endif\r
279 \r
280 \r
281 INLINE_FUNC_DECLARE(static void LcdInit (void));\r
282 static inline void LcdInit (void) {\r
283   // Set BAUD_J2:BAUD_J1 PULL-UPS active\r
284   LCD_CONTROL_PORT = (1<<BAUD_J2) | (1<<BAUD_J1);\r
285   // Set LCD_control BAUD_J2:BAUD_J1 to inputs\r
286   LCD_CONTROL_DIR = 0xF2;\r
287 \r
288   _delay_us(15000);\r
289   LCD_CONTROL_PORT |= (1<<LCD_RS); // Set LCD_RS HIGH\r
290 \r
291   // Initialize the LCD Data AVR I/O\r
292   LCD_DATA_DIR = 0xFF; // Set LCD_DATA_PORT as all outputs\r
293   LCD_DATA_PORT = 0x00; // Set LCD_DATA_PORT to logic low\r
294 \r
295   // Initialize the LCD controller\r
296   LCD_CONTROL_PORT &= ~(1<<LCD_RS);\r
297   LcdWriteData (DATA_8);\r
298 \r
299   _delay_us(4100);\r
300   LcdWriteData (DATA_8);\r
301 \r
302   _delay_us(100);\r
303   LcdWriteData (DATA_8);\r
304   LCD_CONTROL_PORT |= (1<<LCD_RS);\r
305 \r
306   // The display will be out into 8 bit data mode here\r
307   LcdWriteCmd (LCD_8_Bit | LCD_4_Line); // Set 8 bit data, 4 display lines\r
308   LcdWriteCmd (LCD_ON); // Power up the display\r
309   LcdWriteCmd (LCD_CLR); // Power up the display\r
310 }\r
311 \r
312 MAIN_FUNC() {\r
313   MCUSR = 0; // clear all reset flags\r
314 \r
315 #if defined(__CODEVISIONAVR__)\r
316       #asm("wdr");\r
317 #else\r
318       wdt_reset();\r
319 #endif\r
320   WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
321   WDTCSR = (1<<WDE)|(1<<WDP3)|(1<<WDP0); // 1024K cycles, 8.0sec\r
322   MCUCR &= ~((1<<SM1)|(1<<SM0)); // use idle sleep mode\r
323 \r
324   LedPwmInit ();\r
325   LcdInit ();\r
326 \r
327   // Initialize the AVR USART\r
328   UsartInit ();\r
329 \r
330 #if defined(__CODEVISIONAVR__)\r
331       #asm("sei");\r
332 #else\r
333   sei();\r
334 #endif\r
335   while (1) {\r
336     unsigned char tail = sUartRxTail; // explicitly set order of volatile access\r
337     if (tail != sUartRxHead) { // Check if UART RX buffer has a character\r
338       unsigned char rx_byte = WaitRxChar();\r
339 \r
340       // avoid use of switch statement as ImageCraft and GCC produce signifcantly\r
341       // more code for a switch statement than a sequence of if/else if\r
342       if (rx_byte == LED_SW_OFF) {\r
343         LedPwmSwitchOff();\r
344       } else if (rx_byte == LED_SW_ON) {\r
345         LedPwmSwitchOn();\r
346       } else if (rx_byte == LED_SET_BRIGHTNESS) {\r
347         rx_byte = WaitRxChar();  // read next byte which will be brightness\r
348         LedPwmSetBrightness(rx_byte);\r
349       } else if (rx_byte == REG_MODE) {\r
350         LcdWriteCmd (WaitRxChar()); // Send LCD command character\r
351       } else {\r
352         LcdWriteData (rx_byte); // Send LCD data character\r
353       }\r
354     } else {\r
355       // No characters waiting in RX buffer\r
356 \r
357 #if defined(__CODEVISIONAVR__)\r
358       #asm("cli");\r
359 #else\r
360       cli();\r
361 #endif\r
362 #if defined(__CODEVISIONAVR__)\r
363       #asm("wdr");\r
364 #else\r
365       wdt_reset();\r
366 #endif\r
367       MCUSR &= ~(1<<WDRF); // clear any watchdog interrupt flags\r
368       WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
369       WDTCSR &= ~(1<<WDE); // watchdog timer off\r
370 #if defined(__CODEVISIONAVR__)\r
371       #asm("sei");\r
372 #else\r
373       sei();\r
374 #endif\r
375 \r
376       sleep_enable();\r
377 #if defined(__CODEVISIONAVR__)\r
378       #asm("sleep");\r
379 #else\r
380       sleep_cpu();\r
381 #endif\r
382       sleep_disable();\r
383 \r
384 #if defined(__CODEVISIONAVR__)\r
385       #asm("cli");\r
386 #else\r
387       cli();\r
388 #endif\r
389 #if defined(__CODEVISIONAVR__)\r
390       #asm("wdr");\r
391 #else\r
392       wdt_reset();\r
393 #endif\r
394       WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
395       WDTCSR &= ~(1<<WDCE);\r
396 #if defined(__CODEVISIONAVR__)\r
397       #asm("sei");\r
398 #else\r
399       sei();\r
400 #endif\r
401     }\r
402   }\r
403   MAIN_FUNC_LAST();\r
404 }\r
405 \r
406 void LcdWriteCmd (unsigned char Cmd) {\r
407   LcdBusyWait();\r
408   LCD_DATA_PORT = Cmd;  // BusyWait leaves RS low in "Register mode"\r
409 #if defined(__CODEVISIONAVR__)\r
410   #asm("nop");\r
411 #else\r
412    NOP();\r
413 #endif\r
414   LCD_CONTROL_PORT |= (1<<LCD_E);\r
415 #if defined(__CODEVISIONAVR__)\r
416   #if CONSERVATIVE_ENABLE_DURATION\r
417     #asm("nop")\r
418     #asm("nop")\r
419     #asm("nop")\r
420     #asm("nop")\r
421     #asm("nop")\r
422     #asm("nop")\r
423     #asm("nop")\r
424   #else\r
425     #asm("nop")\r
426     #asm("nop")\r
427     #asm("nop")\r
428     #asm("nop")\r
429   #endif\r
430 #else\r
431   ENABLE_WAIT();\r
432 #endif\r
433   LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
434 #if defined(__CODEVISIONAVR__)\r
435   #asm("nop");\r
436 #else\r
437    NOP();\r
438 #endif\r
439   LCD_CONTROL_PORT |= (1<<LCD_RS); // Set display to "Character mode"\r
440 }\r
441 \r
442 void LcdWriteData (unsigned char c) {\r
443   LcdBusyWait();\r
444   LCD_CONTROL_PORT |= (1<<LCD_RS); // Set display to "Character Mode"\r
445   LCD_DATA_PORT = c;\r
446 #if defined(__CODEVISIONAVR__)\r
447   #asm("nop");\r
448 #else\r
449    NOP();\r
450 #endif\r
451   LCD_CONTROL_PORT |= (1<<LCD_E);\r
452 #if defined(__CODEVISIONAVR__)\r
453   #if CONSERVATIVE_ENABLE_DURATION\r
454     #asm("nop")\r
455     #asm("nop")\r
456     #asm("nop")\r
457     #asm("nop")\r
458     #asm("nop")\r
459     #asm("nop")\r
460     #asm("nop")\r
461   #else\r
462     #asm("nop")\r
463     #asm("nop")\r
464     #asm("nop")\r
465     #asm("nop")\r
466   #endif\r
467 #else\r
468   ENABLE_WAIT();\r
469 #endif\r
470   LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
471 }\r
472 \r
473 unsigned char LcdBusyWait (void) {\r
474   unsigned char LCDStatus;\r
475   LCD_DATA_DIR = 0x00; // Set LCD data port to inputs\r
476   LCD_CONTROL_PORT &= ~(1<<LCD_RS); // Set display to "Register mode"\r
477   LCD_CONTROL_PORT |= (1<<LCD_RW); // Put the display in the read mode\r
478 #if defined(__CODEVISIONAVR__)\r
479   #asm("nop");\r
480 #else\r
481    NOP();\r
482 #endif\r
483   do {\r
484 #if defined(__CODEVISIONAVR__)\r
485       #asm("wdr");\r
486 #else\r
487       wdt_reset();\r
488 #endif\r
489     LCD_CONTROL_PORT |= (1<<LCD_E);\r
490 #if defined(__CODEVISIONAVR__)\r
491   #if CONSERVATIVE_ENABLE_DURATION\r
492     #asm("nop")\r
493     #asm("nop")\r
494     #asm("nop")\r
495     #asm("nop")\r
496     #asm("nop")\r
497     #asm("nop")\r
498     #asm("nop")\r
499   #else\r
500     #asm("nop")\r
501     #asm("nop")\r
502     #asm("nop")\r
503     #asm("nop")\r
504   #endif\r
505 #else\r
506   ENABLE_WAIT();\r
507 #endif\r
508     LCDStatus = LCD_DATA_PIN_REG;\r
509     LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
510   } while (LCDStatus & (1<<LCD_BUSY));\r
511   LCD_CONTROL_PORT &= ~(1<<LCD_RW); // Put display in write mode\r
512   LCD_DATA_DIR = 0xFF; // Set LCD data port to outputs\r
513   return (LCDStatus);\r
514 }\r
515 \r
516 #if defined(__IMAGECRAFT__)\r
517 #pragma interrupt_handler usart_rx_handler:iv_USART0_RXC\r
518 void usart_rx_handler(void)\r
519 #else\r
520 ISR(USART_RX_vect)\r
521 #endif\r
522 {\r
523   unsigned char rx = UDR;\r
524   // Calculate next buffer position.\r
525   unsigned char tmphead = sUartRxHead;\r
526   if (tmphead == UART_RX_BUFFER_SIZE-1)\r
527     tmphead = 0;\r
528   else\r
529     tmphead++;\r
530   // store in buffer if there is room\r
531   if (tmphead != sUartRxTail) {\r
532     sUartRxHead = tmphead;         // Store new index.\r
533     sUartRxBuf[tmphead] = rx;\r
534   }\r
535 #if USE_CTS\r
536   // check if buffer is now full, if so switch CTS to inactive\r
537   if (tmphead == UART_RX_BUFFER_SIZE-1)\r
538     tmphead = 0;\r
539   else\r
540     tmphead++;\r
541   // CTS active if still room in buffer\r
542   if (tmphead != sUartRxTail) {\r
543     CTS_PORT |= (1<<CTS_PIN);\r
544   } else {\r
545     // no room left in buffer, so make CTS inactive\r
546     CTS_PORT &= ~(1<<CTS_PIN);\r
547   }\r
548 #endif\r
549 }\r
550 \r
551 static unsigned char WaitRxChar (void) {\r
552   // waits for next RX character, then return it\r
553   unsigned char tail;\r
554   do {\r
555     tail = sUartRxTail; // explicitly set order of volatile variable access\r
556 #if defined(__CODEVISIONAVR__)\r
557       #asm("wdr");\r
558 #else\r
559       wdt_reset();\r
560 #endif\r
561   } while (sUartRxHead == tail); // while buffer is empty\r
562 \r
563 #if USE_CTS\r
564   // turn off interrupts so that if UART char ready to be stored, then storage\r
565   // will occur after CTS pin is set active. This allows UART ISR to set\r
566   //  CTS inactive if byte fills buffer after we remove current byte\r
567 #if defined(__CODEVISIONAVR__)\r
568   #asm("cli");\r
569 #else\r
570   cli();\r
571 #endif\r
572 #endif\r
573 \r
574   // increment tail position\r
575   if (tail == UART_RX_BUFFER_SIZE-1)\r
576     sUartRxTail = 0;\r
577   else\r
578     sUartRxTail++;\r
579 \r
580 #if USE_CTS\r
581   CTS_PORT |= (1<<CTS_PIN); // Ensure CTS is active since just removed a byte\r
582 #if defined(__CODEVISIONAVR__)\r
583   #asm("sei");\r
584 #else\r
585   sei();   // Allow UART ISR to read character and change potentially change CTS\r
586 #endif\r
587 #endif\r
588 \r
589   return sUartRxBuf[sUartRxTail];\r
590 }\r
591 \r
592 #if defined(__IMAGECRAFT__)\r
593 #pragma interrupt_handler timer0_compa_handler:iv_TIMER0_COMPA\r
594 void timer0_compa_handler(void)\r
595 #elif defined(__CODEVISIONAVR__)\r
596 interrupt [TIM0_COMPA] void timer0_compa_handler(void)\r
597 #else\r
598   ISR(TIMER0_COMPA_vect)\r
599 #endif\r
600 {\r
601 #if defined(__CODEVISIONAVR__)\r
602   #asm("sei");\r
603 #else\r
604   sei(); // Okay to allow USART interrupts while controlling LED PWM\r
605 #endif\r
606 \r
607   // Set current LED state based on cycling variable\r
608   if (ledPwmCycling & 0x01) {\r
609     LED_PORT |= (1<<LED_PIN);\r
610   } else {\r
611     LED_PORT &= ~(1<<LED_PIN);\r
612   }\r
613 \r
614   // Update cycling variable for next interrupt\r
615   if (ledPwmCount >= LED_BRIGHTNESS_LEVELS-1) {\r
616     ledPwmCount = 0;\r
617     ledPwmCycling = ledPwmPattern;\r
618   } else {\r
619     ledPwmCount++;\r
620     ledPwmCycling >>= 1;\r
621   }\r
622 }\r