]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_EFMG890F128_IAR/lcd/lcdcontroller.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / CORTEX_EFMG890F128_IAR / lcd / lcdcontroller.c
1 /**************************************************************************//**\r
2  * @file\r
3  * @brief LCD Controller driver\r
4  * @author Energy Micro AS\r
5  * @version 1.0.1\r
6  ******************************************************************************\r
7  * @section License\r
8  * <b>(C) Copyright 2009 Energy Micro AS, http://www.energymicro.com</b>\r
9  ******************************************************************************\r
10  *\r
11  * This source code is the property of Energy Micro AS. The source and compiled\r
12  * code may only be used on Energy Micro "EFM32" microcontrollers.\r
13  *\r
14  * This copyright notice may not be removed from the source code nor changed.\r
15  *\r
16  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no\r
17  * obligation to support this Software. Energy Micro AS is providing the\r
18  * Software "AS IS", with no express or implied warranties of any kind,\r
19  * including, but not limited to, any implied warranties of merchantability\r
20  * or fitness for any particular purpose or warranties against infringement\r
21  * of any proprietary rights of a third party.\r
22  *\r
23  * Energy Micro AS will not be liable for any consequential, incidental, or\r
24  * special damages, or any other relief, or for any claim by any third party,\r
25  * arising from your use of this Software.\r
26  *\r
27  *****************************************************************************/\r
28 #include "FreeRTOS.h"\r
29 #include "task.h"\r
30 \r
31 #include <stdio.h>\r
32 #include <string.h>\r
33 #include <stdlib.h>\r
34 #include "efm32.h"\r
35 #include "lcdcontroller.h"\r
36 #include "lcddisplay.h"\r
37 \r
38 /** Counts every n'th frame */\r
39 int frameCounter = 0;\r
40 \r
41 /**************************************************************************//**\r
42  * @brief LCD Interrupt Handler, triggers on frame counter, every n'th frame\r
43  *****************************************************************************/\r
44 void LCD_IRQHandler(void)\r
45 {\r
46   LCD_TypeDef *lcd = LCD;\r
47 \r
48   /* clear interrupt */\r
49   lcd->IFC = 0xFFFFFFFF;\r
50   frameCounter++;\r
51 }\r
52 \r
53 /**************************************************************************//**\r
54  * @brief Enables a segment on the LCD display\r
55  * @param lcd Pointer to LCD register block\r
56  * @param com COM segment number\r
57  * @param bitvalue Bit value for segment\r
58  *****************************************************************************/\r
59 static void LCD_enableSegment(LCD_TypeDef * lcd, int com, int bitvalue)\r
60 {\r
61   switch (com)\r
62   {\r
63   case 0:\r
64     lcd->SEGD0L |= bitvalue;\r
65     break;\r
66   case 1:\r
67     lcd->SEGD1L |= bitvalue;\r
68     break;\r
69   case 2:\r
70     lcd->SEGD2L |= bitvalue;\r
71     break;\r
72   case 3:\r
73     lcd->SEGD3L |= bitvalue;\r
74     break;\r
75   case 4:\r
76     lcd->SEGD0H |= bitvalue;\r
77     break;\r
78   case 5:\r
79     lcd->SEGD1H |= bitvalue;\r
80     break;\r
81   case 6:\r
82     lcd->SEGD2H |= bitvalue;\r
83     break;\r
84   case 7:\r
85     lcd->SEGD3H |= bitvalue;\r
86     break;\r
87   }\r
88 }\r
89 \r
90 /**************************************************************************//**\r
91  * @brief Disables a segment on the LCD Display\r
92  * @param lcd Pointer to LCD register structure\r
93  * @param com COM segment number\r
94  * @param bitvalue Bit value for segment\r
95  *****************************************************************************/\r
96 static void LCD_disableSegment(LCD_TypeDef * lcd, int com, int bitvalue)\r
97 {\r
98   switch (com)\r
99   {\r
100   case 0:\r
101     lcd->SEGD0L &= ~bitvalue;\r
102     break;\r
103   case 1:\r
104     lcd->SEGD1L &= ~bitvalue;\r
105     break;\r
106   case 2:\r
107     lcd->SEGD2L &= ~bitvalue;\r
108     break;\r
109   case 3:\r
110     lcd->SEGD3L &= ~bitvalue;\r
111     break;\r
112   case 4:\r
113     lcd->SEGD0H &= ~bitvalue;\r
114     break;\r
115   case 5:\r
116     lcd->SEGD1H &= ~bitvalue;\r
117     break;\r
118   case 6:\r
119     lcd->SEGD2H &= ~bitvalue;\r
120     break;\r
121   case 7:\r
122     lcd->SEGD3H &= ~bitvalue;\r
123     break;\r
124   }\r
125 }\r
126 \r
127 /**************************************************************************//**\r
128  * @brief Write number on numeric part on LCD display\r
129  * @param lcd Pointer to LCD control block\r
130  * @param value Numeric value to put on display, in range -999 to +9999\r
131  *****************************************************************************/\r
132 void LCD_Number(LCD_TypeDef *lcd, int value)\r
133 {\r
134   int      num, i, com, bit, digit, div, neg;\r
135   uint16_t bitpattern;\r
136 \r
137   /* Parameter consistancy check */\r
138   if (value >= 9999)\r
139   {\r
140     value = 9999;\r
141   }\r
142   if (value <= -1000)\r
143   {\r
144     value = -999;\r
145   }\r
146   if (value < 0)\r
147   {\r
148     value = abs(value);\r
149     neg   = 1;\r
150   }\r
151   else\r
152   {\r
153     neg = 0;\r
154   }\r
155   /* Extract useful digits */\r
156   div = 1;\r
157   for (digit = 0; digit < 4; digit++)\r
158   {\r
159     num = (value / div) % 10;\r
160     if ((neg == 1) && (digit == 3)) num = 10;\r
161     bitpattern = EM_Numbers[num];\r
162     for (i = 0; i < 7; i++)\r
163     {\r
164       bit = EFMDisplay.Number[digit].bit[i];\r
165       com = EFMDisplay.Number[digit].com[i];\r
166       if (bitpattern & (1 << i))\r
167       {\r
168         LCD_enableSegment(lcd, com, 1 << bit);\r
169       }\r
170       else\r
171       {\r
172         LCD_disableSegment(lcd, com, 1 << bit);\r
173       }\r
174     }\r
175     div = div * 10;\r
176   }\r
177 }\r
178 \r
179 /**************************************************************************//**\r
180  * @brief Turn all segments on numeric display off\r
181  * @param lcd Pointer to LCD register structure\r
182  *****************************************************************************/\r
183 void LCD_NumberOff(LCD_TypeDef *lcd)\r
184 {\r
185   int digit, i, bit, com;\r
186 \r
187   /* Turn off all segments */\r
188   for (digit = 0; digit < 4; digit++)\r
189   {\r
190     for (i = 0; i < 7; i++)\r
191     {\r
192       bit = EFMDisplay.Number[digit].bit[i];\r
193       com = EFMDisplay.Number[digit].com[i];\r
194       LCD_disableSegment(lcd, com, 1 << bit);\r
195     }\r
196   }\r
197   return;\r
198 }\r
199 \r
200 \r
201 /**************************************************************************//**\r
202  * @brief Write text on LCD display\r
203  * @param lcd Pointer to LCD register structure\r
204  * @param string Text string to show on display\r
205  *****************************************************************************/\r
206 void LCD_Write(LCD_TypeDef *lcd, char *string)\r
207 {\r
208   int      data, length, index;\r
209   uint16_t bitfield;\r
210   uint32_t value;\r
211   uint32_t com, bit;\r
212   int      i;\r
213 \r
214   length = strlen(string);\r
215   index  = 0;\r
216   /* fill out all characters on display */\r
217   for (index = 0; index < 7; index++)\r
218   {\r
219     if (index < length)\r
220     {\r
221       data = (int) *string;\r
222     }\r
223     else           /* padding with space */\r
224     {\r
225       data = 0x20; /* SPACE */\r
226     }\r
227     /* defined letters currently starts at "SPACE" - 0x20; */\r
228     data     = data - 0x20;\r
229     bitfield = EM_alphabet[data];\r
230 \r
231 \r
232     for (i = 0; i < 14; i++)\r
233     {\r
234       bit   = EFMDisplay.Text[index].bit[i];\r
235       com   = EFMDisplay.Text[index].com[i];\r
236       value = (1 << bit);\r
237 \r
238       if (bitfield & (1 << i))\r
239       {\r
240         /* Turn on segment */\r
241         LCD_enableSegment(lcd, com, value);\r
242       }\r
243       else\r
244       {\r
245         /* Turn off segment */\r
246         LCD_disableSegment(lcd, com, value);\r
247       }\r
248     }\r
249     string++;\r
250   }\r
251   while (lcd->SYNCBUSY) ;\r
252 }\r
253 \r
254 /**************************************************************************//**\r
255  * @brief LCD Disable all segments\r
256  * @param lcd Pointer to LCD register block\r
257  *****************************************************************************/\r
258 void LCD_AllOff(LCD_TypeDef *lcd)\r
259 {\r
260   lcd->SEGD0L = 0x00000000;\r
261   lcd->SEGD0H = 0x00000000;\r
262   lcd->SEGD1L = 0x00000000;\r
263   lcd->SEGD1H = 0x00000000;\r
264   lcd->SEGD2L = 0x00000000;\r
265   lcd->SEGD2H = 0x00000000;\r
266   lcd->SEGD3L = 0x00000000;\r
267   lcd->SEGD3H = 0x00000000;\r
268   while (lcd->SYNCBUSY) ;\r
269 }\r
270 \r
271 /**************************************************************************//**\r
272  * @brief LCD Enable all segments\r
273  * @param lcd Pointer to LCD register block\r
274  *****************************************************************************/\r
275 void LCD_AllOn(LCD_TypeDef *lcd)\r
276 {\r
277   lcd->SEGD0L = 0xffffffff;\r
278   lcd->SEGD0H = 0xffffffff;\r
279   lcd->SEGD1L = 0xffffffff;\r
280   lcd->SEGD1H = 0xffffffff;\r
281   lcd->SEGD2L = 0xffffffff;\r
282   lcd->SEGD2H = 0xffffffff;\r
283   lcd->SEGD3L = 0xffffffff;\r
284   lcd->SEGD3H = 0xffffffff;\r
285   while (lcd->SYNCBUSY) ;\r
286 }\r
287 \r
288 /**************************************************************************//**\r
289  * @brief LCD Light up or shut off Energy Mode indicator\r
290  * @param lcd Pointer to LCD register block\r
291  * @pararm em Energy Mode numer 0 to 4\r
292  * @param on Zero is off, non-zero is on\r
293  *****************************************************************************/\r
294 void LCD_EnergyMode(LCD_TypeDef *lcd, int em, int on)\r
295 {\r
296   uint32_t com, bitvalue;\r
297 \r
298   com      = EFMDisplay.EMode.com[em];\r
299   bitvalue = 1 << EFMDisplay.EMode.bit[em];\r
300 \r
301   if (on)\r
302   {\r
303     LCD_enableSegment(lcd, com, bitvalue);\r
304   }\r
305   else\r
306   {\r
307     LCD_disableSegment(lcd, com, bitvalue);\r
308   }\r
309 }\r
310 \r
311 /**************************************************************************//**\r
312  * @brief LCD Light up or shut off Ring of Indicators\r
313  * @param lcd Pointer to LCD register block\r
314  * @param anum "Segment number" on "Ring", range 0 - 7\r
315  * @param on Zero is off, non-zero is on\r
316  *****************************************************************************/\r
317 void LCD_ARing(LCD_TypeDef *lcd, int anum, int on)\r
318 {\r
319   uint32_t com, bitvalue;\r
320 \r
321   com      = EFMDisplay.ARing.com[anum];\r
322   bitvalue = 1 << EFMDisplay.ARing.bit[anum];\r
323 \r
324   if (on)\r
325   {\r
326     LCD_enableSegment(lcd, com, bitvalue);\r
327   }\r
328   else\r
329   {\r
330     LCD_disableSegment(lcd, com, bitvalue);\r
331   }\r
332 }\r
333 \r
334 /**************************************************************************//**\r
335  * @brief LCD Light up or shut off various symbols on LCD Display\r
336  * @param lcd Pointer to LCD register block\r
337  * @param s Which symbol to turn on or off\r
338  * @param on Zero is off, non-zero is on\r
339  *****************************************************************************/\r
340 void LCD_Symbol(LCD_TypeDef *lcd, lcdSymbol s, int on)\r
341 {\r
342   int com, bit;\r
343 \r
344   switch (s)\r
345   {\r
346   case LCD_SYMBOL_GECKO:\r
347     com = 3; bit = 8;\r
348     break;\r
349   case LCD_SYMBOL_ANT:\r
350     com = 3; bit = 1;\r
351     break;\r
352   case LCD_SYMBOL_PAD0:\r
353     com = 1; bit = 8;\r
354     break;\r
355   case LCD_SYMBOL_PAD1:\r
356     com = 2; bit = 8;\r
357     break;\r
358   case LCD_SYMBOL_AM:\r
359     com = 4; bit = 0;\r
360     break;\r
361   case LCD_SYMBOL_PM:\r
362     com = 4; bit = 3;\r
363     break;\r
364   case LCD_SYMBOL_EFM32:\r
365     com = 0; bit = 8;\r
366     break;\r
367   case LCD_SYMBOL_MINUS:\r
368     com = 0; bit = 9;\r
369     break;\r
370   case LCD_SYMBOL_COL3:\r
371     com = 0; bit = 16;\r
372     break;\r
373   case LCD_SYMBOL_COL5:\r
374     com = 0; bit = 24;\r
375     break;\r
376   case LCD_SYMBOL_COL10:\r
377     com = 4; bit = 7;\r
378     break;\r
379   case LCD_SYMBOL_DP2:\r
380     com = 4; bit = 2;\r
381     break;\r
382   case LCD_SYMBOL_DP3:\r
383     com = 5; bit = 2;\r
384     break;\r
385   case LCD_SYMBOL_DP4:\r
386     com = 6; bit = 2;\r
387     break;\r
388   case LCD_SYMBOL_DP5:\r
389     com = 7; bit = 2;\r
390     break;\r
391   case LCD_SYMBOL_DP6:\r
392     com = 0; bit = 21;\r
393     break;\r
394   case LCD_SYMBOL_DP10:\r
395     com = 4; bit = 5;\r
396     break;\r
397   }\r
398   if (on)\r
399   {\r
400     LCD_enableSegment(lcd, com, 1 << bit);\r
401   }\r
402   else\r
403   {\r
404     LCD_disableSegment(lcd, com, 1 << bit);\r
405   }\r
406 }\r
407 \r
408 /**************************************************************************//**\r
409  * @brief LCD Light up or shut off Battery Indicator\r
410  * @param lcd Pointer to LCD register block\r
411  * @param batteryLevel Battery Level, 0 to 4 (0 turns all off)\r
412  *****************************************************************************/\r
413 void LCD_Battery(LCD_TypeDef *lcd, int batteryLevel)\r
414 {\r
415   uint32_t com, bitvalue;\r
416   int      i, on;\r
417 \r
418   for (i = 0; i < 4; i++)\r
419   {\r
420     if (i < batteryLevel)\r
421     {\r
422       on = 1;\r
423     }\r
424     else\r
425     {\r
426       on = 0;\r
427     }\r
428     com      = EFMDisplay.Battery.com[i];\r
429     bitvalue = 1 << EFMDisplay.Battery.bit[i];\r
430 \r
431     if (on)\r
432     {\r
433       LCD_enableSegment(lcd, com, bitvalue);\r
434     }\r
435     else\r
436     {\r
437       LCD_disableSegment(lcd, com, bitvalue);\r
438     }\r
439   }\r
440 }\r
441 \r
442 /**************************************************************************//**\r
443  * @brief LCD Initialization routine for EFM32 DVK display\r
444  * @param lcd Pointer to LCD register block\r
445  *****************************************************************************/\r
446 void LCD_Init(LCD_TypeDef *lcd)\r
447 {\r
448   CMU_TypeDef *cmu = CMU;\r
449 \r
450   /* Enable LFXO oscillator */\r
451   cmu->OSCENCMD |= CMU_OSCENCMD_LFXOEN;\r
452   while (!(cmu->STATUS & CMU_STATUS_LFXORDY)) ;\r
453 \r
454   /* Enable LCD clock in CMU */\r
455   cmu->LFACLKEN0 |= CMU_LFACLKEN0_LCD;\r
456 \r
457   /* Select LFXO for LCD */\r
458   cmu->LFCLKSEL = CMU_LFCLKSEL_LFA_LFXO | CMU_LFCLKSEL_LFB_LFXO;\r
459 \r
460   /* LCD Controller Prescaler (divide by 1) */\r
461   /* CLKlcd = 0.25 kHz */\r
462   cmu->LFAPRESC0 &= ~_CMU_LFAPRESC0_LCD_MASK;\r
463   cmu->LFAPRESC0 |= _CMU_LFAPRESC0_LCD_DIV128 << _CMU_LFAPRESC0_LCD_SHIFT;\r
464 \r
465   /* Set up interrupt handler */\r
466   lcd->IEN = 0;\r
467   while (lcd->SYNCBUSY) ;\r
468 \r
469   /* Clear pending interrupts */\r
470   lcd->IFC = ~0;\r
471   /* Enable interrupt */\r
472   NVIC_EnableIRQ(LCD_IRQn);\r
473   lcd->IEN = LCD_IEN_FC;\r
474 \r
475   /* Frame rate is 32Hz, 0.25Khz LFCLK128, QUADRUPLEX mode, FDIV=0 */\r
476   lcd->DISPCTRL = LCD_DISPCTRL_MUX_QUADRUPLEX |\r
477                   LCD_DISPCTRL_BIAS_ONETHIRD |\r
478                   LCD_DISPCTRL_WAVE_LOWPOWER |\r
479                   LCD_DISPCTRL_CONLEV_MAX |\r
480                   LCD_DISPCTRL_VLCDSEL_VDD |\r
481                   LCD_DISPCTRL_VBLEV_3V00;\r
482 \r
483   /* No voltage boost, framerate 32Hz */\r
484   cmu->LCDCTRL = 0;\r
485 \r
486   /* Turn all segments off */\r
487   LCD_AllOff(lcd);\r
488 \r
489   /* Enable all segment registers */\r
490   lcd->SEGEN = 0x000003FF;\r
491   lcd->CTRL  = LCD_CTRL_EN | LCD_CTRL_UDCTRL_FRAMESTART;\r
492   while (lcd->SYNCBUSY) ;\r
493 \r
494   /* Configure LCD to give a frame counter interrupt every 8th frame. */\r
495   lcd->BACTRL = LCD_BACTRL_FCEN | (7 << _LCD_BACTRL_FCTOP_SHIFT) | (0 << _LCD_BACTRL_FCPRESC_SHIFT);\r
496   while (lcd->SYNCBUSY) ;\r
497   lcd->IFC = LCD_IFC_FC;\r
498   lcd->IEN = LCD_IEN_FC;\r
499 }\r
500 \r
501 \r
502 /**************************************************************************//**\r
503  * @brief Disables LCD controller\r
504  * @param lcd Pointer to LCD register block\r
505  *****************************************************************************/\r
506 void LCD_Disable(LCD_TypeDef *lcd)\r
507 {\r
508   CMU_TypeDef *cmu = CMU;\r
509 \r
510   /* Turn off interrupts */\r
511   lcd->IEN = 0x00000000;\r
512   lcd->IFC = LCD_IFC_FC;\r
513   NVIC_DisableIRQ(LCD_IRQn);\r
514   /* Disable LCD */\r
515   lcd->CTRL = 0;\r
516   /* Turn off LCD clock */\r
517   cmu->LFACLKEN0 &= ~(CMU_LFACLKEN0_LCD);\r
518   /* Turn off voltage boost if enabled */\r
519   cmu->LCDCTRL = 0;\r
520 }\r
521 \r
522 /**************************************************************************//**\r
523  * @brief LCD scrolls a text over the display, sort of "polled printf"\r
524  * @param lcd Pointer to LCD register block\r
525  *****************************************************************************/\r
526 void LCD_ScrollText(LCD_TypeDef *lcd, char *scrolltext)\r
527 {\r
528   int  i, len;\r
529   char buffer[8];\r
530 \r
531   buffer[7] = 0x00;\r
532   len       = strlen(scrolltext);\r
533   if (len < 7) return;\r
534   for (i = 0; i < (len - 7); i++)\r
535   {\r
536     memcpy(buffer, scrolltext + i, 7);\r
537     LCD_Write(lcd, buffer);\r
538     vTaskDelay(100/portTICK_RATE_MS);\r
539   }\r
540 }\r
541 \r
542 \r