segmentlcd.c

Go to the documentation of this file.
00001 /**************************************************************************/
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <stdlib.h>
00038 #include <stdbool.h>
00039 #include "em_device.h"
00040 #include "em_cmu.h"
00041 #include "em_gpio.h"
00042 
00043 #include "segmentlcd.h"
00044 
00045 /**************************************************************************/
00067 typedef struct
00068 {
00069   uint8_t com[14]; 
00070   uint8_t bit[14]; 
00071 } CHAR_TypeDef;
00072 
00073 
00074 /**************************************************************************/
00077 typedef struct
00078 {
00079   uint8_t com[7]; 
00080   uint8_t bit[7]; 
00081 } NUMBER_TypeDef;
00082 
00083 /**************************************************************************/
00086 typedef struct
00087 {
00088   uint8_t com[5]; 
00089   uint8_t bit[5]; 
00090 } EM_TypeDef;
00091 
00092 /**************************************************************************/
00095 typedef struct
00096 {
00097   uint8_t com[8]; 
00098   uint8_t bit[8]; 
00099 } ARING_TypeDef;
00100 
00101 /**************************************************************************/
00104 typedef struct
00105 {
00106   uint8_t com[4]; 
00107   uint8_t bit[4]; 
00108 } BATTERY_TypeDef;
00109 
00110 /**************************************************************************/
00113 typedef struct
00114 {
00115   CHAR_TypeDef    Text[7];      
00116   NUMBER_TypeDef  Number[4];    
00117   EM_TypeDef      EMode;        
00118   ARING_TypeDef   ARing;        
00119   BATTERY_TypeDef Battery;      
00120 } MCU_DISPLAY;
00121 
00122 /**************************************************************************/
00125 static const MCU_DISPLAY EFM_Display = EFM_DISPLAY_DEF;
00126 
00127 
00128 /**************************************************************************/
00134 static const uint16_t EFM_Alphabet[] = {
00135   0x0000, /* space */
00136   0x1100, /* ! */
00137   0x0280, /* " */
00138   0x0000, /* # */
00139   0x0000, /* $ */
00140   0x0602, /* % */
00141   0x0000, /* & */
00142   0x0020, /* ' */
00143   0x0039, /* ( */
00144   0x000f, /* ) */
00145   0x0000, /* * */
00146   0x1540, /* + */
00147   0x2000, /* , */
00148   0x0440, /* - */
00149   0x1000, /* . */
00150   0x2200, /* / */
00151 
00152   0x003f, /* 0 */
00153   0x0006, /* 1 */
00154   0x045b, /* 2 */
00155   0x044f, /* 3 */
00156   0x0466, /* 4 */
00157   0x046d, /* 5 */
00158   0x047d, /* 6 */
00159   0x0007, /* 7 */
00160   0x047f, /* 8 */
00161   0x046f, /* 9 */
00162 
00163   0x0000, /* : */
00164   0x0000, /* ; */
00165   0x0a00, /* < */
00166   0x0000, /* = */
00167   0x2080, /* > */
00168   0x0000, /* ? */
00169   0xffff, /* @ */
00170 
00171   0x0477, /* A */
00172   0x0a79, /* B */
00173   0x0039, /* C */
00174   0x20b0, /* D */
00175   0x0079, /* E */
00176   0x0071, /* F */
00177   0x047d, /* G */
00178   0x0476, /* H */
00179   0x0006, /* I */
00180   0x000e, /* J */
00181   0x0a70, /* K */
00182   0x0038, /* L */
00183   0x02b6, /* M */
00184   0x08b6, /* N */
00185   0x003f, /* O */
00186   0x0473, /* P */
00187   0x083f, /* Q */
00188   0x0c73, /* R */
00189   0x046d, /* S */
00190   0x1101, /* T */
00191   0x003e, /* U */
00192   0x2230, /* V */
00193   0x2836, /* W */
00194   0x2a80, /* X */
00195   0x046e, /* Y */
00196   0x2209, /* Z */
00197 
00198   0x0039, /* [ */
00199   0x0880, /* backslash */
00200   0x000f, /* ] */
00201   0x0001, /* ^ */
00202   0x0008, /* _ */
00203   0x0100, /* ` */
00204 
00205   0x1058, /* a */
00206   0x047c, /* b */
00207   0x0058, /* c */
00208   0x045e, /* d */
00209   0x2058, /* e */
00210   0x0471, /* f */
00211   0x0c0c, /* g */
00212   0x0474, /* h */
00213   0x0004, /* i */
00214   0x000e, /* j */
00215   0x0c70, /* k */
00216   0x0038, /* l */
00217   0x1454, /* m */
00218   0x0454, /* n */
00219   0x045c, /* o */
00220   0x0473, /* p */
00221   0x0467, /* q */
00222   0x0450, /* r */
00223   0x0c08, /* s */
00224   0x0078, /* t */
00225   0x001c, /* u */
00226   0x2010, /* v */
00227   0x2814, /* w */
00228   0x2a80, /* x */
00229   0x080c, /* y */
00230   0x2048, /* z */
00231 
00232   0x0000,
00233 };
00234 
00235 /**************************************************************************/
00240 static const uint16_t EFM_Numbers[] = {
00241   0x003f, /* 0 */
00242   0x0006, /* 1 */
00243   0x005b, /* 2 */
00244   0x004f, /* 3 */
00245   0x0066, /* 4 */
00246   0x006d, /* 5 */
00247   0x007d, /* 6 */
00248   0x0007, /* 7 */
00249   0x007f, /* 8 */
00250   0x006f, /* 9 */
00251   0x0077, /* A */
00252   0x007c, /* b */
00253   0x0039, /* C */
00254   0x005e, /* d */
00255   0x0079, /* E */
00256   0x0071, /* F */
00257   0x0040  /* - */
00258 };
00259 
00261 /* sign is last element of the table  */
00262 static const uint16_t signIndex = sizeof(EFM_Numbers)/sizeof(uint16_t) - 1 ;
00263 
00264 static const LCD_Init_TypeDef lcdInit = LCD_INIT_DEF;
00268 /**************************************************************************/
00271 void SegmentLCD_AllOff(void)
00272 {
00273   /* Turn on low segments */
00274   LCD_ALL_SEGMENTS_OFF();
00275 }
00276 
00277 
00278 /**************************************************************************/
00281 void SegmentLCD_AllOn(void)
00282 {
00283   LCD_ALL_SEGMENTS_ON();
00284 }
00285 
00286 
00287 /**************************************************************************/
00290 void SegmentLCD_AlphaNumberOff(void)
00291 {
00292   LCD_ALPHA_NUMBER_OFF();
00293   return;
00294 }
00295 
00296 
00297 /**************************************************************************/
00302 void SegmentLCD_ARing(int anum, int on)
00303 {
00304   uint32_t com, bit;
00305 
00306   com = EFM_Display.ARing.com[anum];
00307   bit = EFM_Display.ARing.bit[anum];
00308 
00309   if (on)
00310   {
00311     LCD_SegmentSet(com, bit, true);
00312   }
00313   else
00314   {
00315     LCD_SegmentSet(com, bit, false);
00316   }
00317 }
00318 
00319 
00320 /**************************************************************************/
00324 void SegmentLCD_Battery(int batteryLevel)
00325 {
00326   uint32_t com, bit;
00327   int      i, on;
00328 
00329   for (i = 0; i < 4; i++)
00330   {
00331     if (i < batteryLevel)
00332     {
00333       on = 1;
00334     }
00335     else
00336     {
00337       on = 0;
00338     }
00339     com = EFM_Display.Battery.com[i];
00340     bit = EFM_Display.Battery.bit[i];
00341 
00342     if (on)
00343     {
00344       LCD_SegmentSet(com, bit, true);
00345     }
00346     else
00347     {
00348       LCD_SegmentSet(com, bit, false);
00349     }
00350   }
00351 }
00352 
00353 
00354 /**************************************************************************/
00357 void SegmentLCD_Disable(void)
00358 {
00359   /* Disable LCD */
00360   LCD_Enable(false);
00361 
00362   /* Make sure CTRL register has been updated */
00363   LCD_SyncBusyDelay(LCD_SYNCBUSY_CTRL);
00364 
00365   /* Turn off LCD clock */
00366   CMU_ClockEnable(cmuClock_LCD, false);
00367 
00368   /* Turn off voltage boost if enabled */
00369   CMU->LCDCTRL = 0;
00370 }
00371 
00372 
00373 /**************************************************************************/
00378 void SegmentLCD_EnergyMode(int em, int on)
00379 {
00380   uint32_t com, bit;
00381 
00382   com = EFM_Display.EMode.com[em];
00383   bit = EFM_Display.EMode.bit[em];
00384 
00385   if (on)
00386   {
00387     LCD_SegmentSet(com, bit, true);
00388   }
00389   else
00390   {
00391     LCD_SegmentSet(com, bit, false);
00392   }
00393 }
00394 
00395 
00396 /**************************************************************************/
00400 void SegmentLCD_Init(bool useBoost)
00401 {
00402 
00403   /* Ensure LE modules are accessible */
00404   CMU_ClockEnable(cmuClock_CORELE, true);
00405 
00406   /* Enable LFRCO as LFACLK in CMU (will also enable oscillator if not enabled) */
00407   CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
00408 
00409   /* LCD Controller Prescaler  */
00410   CMU_ClockDivSet(cmuClock_LCDpre, LCD_CMU_CLK_PRE);
00411 
00412   /* Frame Rate */
00413   CMU_LCDClkFDIVSet(LCD_CMU_CLK_DIV);
00414 
00415   /* Enable clock to LCD module */
00416   CMU_ClockEnable(cmuClock_LCD, true);
00417 
00418   LCD_DISPLAY_ENABLE();
00419 
00420   /* Disable interrupts */
00421   LCD_IntDisable(0xFFFFFFFF);
00422 
00423   /* Initialize and enable LCD controller */
00424   LCD_Init(&lcdInit);
00425 
00426   /* Enable all display segments */
00427   LCD_SEGMENTS_ENABLE();
00428 
00429   /* Enable boost if necessary */
00430   if (useBoost)
00431   {
00432     LCD_VBoostSet(LCD_BOOST_LEVEL);
00433     LCD_VLCDSelect(lcdVLCDSelVExtBoost);
00434     CMU->LCDCTRL |= CMU_LCDCTRL_VBOOSTEN;
00435   }
00436 
00437   /* Turn all segments off */
00438   SegmentLCD_AllOff();
00439 
00440   LCD_SyncBusyDelay(0xFFFFFFFF);
00441 }
00442 
00443 
00444 /**************************************************************************/
00450 void SegmentLCD_LowerHex( uint32_t num )
00451 {
00452   int       i;
00453   char      str[7];
00454   uint32_t  nibble;
00455 
00456   SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 0);
00457 
00458   for ( i=6; i>=0; i-- )
00459   {
00460     nibble = num & 0xF;
00461 
00462     if ( nibble < 10 )
00463       str[i] = nibble + '0';
00464     else if ( nibble == 11 )
00465       str[i] = 'b';
00466     else if ( nibble == 13 )
00467       str[i] = 'd';
00468     else
00469       str[i] = (nibble - 10) + 'A';
00470 
00471     num >>= 4;
00472   }
00473 
00474   SegmentLCD_Write(str);
00475 }
00476 
00477 /**************************************************************************/
00481 void SegmentLCD_LowerNumber( int num )
00482 {
00483   int i;
00484   char str[7];
00485 
00486   SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 0);
00487 
00488   if ( ( num > 9999999 ) || ( num < -9999999 ) )
00489   {
00490     SegmentLCD_Write("Ovrflow");
00491     return;
00492   }
00493 
00494   if ( num < 0 )
00495   {
00496     SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 1);
00497     num = -num;
00498   }
00499 
00500   for ( i=6; i>=0; i-- )
00501   {
00502     if ( ( i < 6 ) && ( num == 0 ) )
00503     {
00504       str[i] = ' ';
00505     }
00506     else
00507     {
00508       str[i] = (num % 10) + '0';
00509       num /= 10;
00510     }
00511   }
00512 
00513   SegmentLCD_Write(str);
00514 }
00515 
00516 
00517 /**************************************************************************/
00521 void SegmentLCD_Number(int value)
00522 {
00523   int      i, com, bit, digit, div, neg;
00524   uint16_t bitpattern;
00525   uint16_t num;
00526 
00527   /* Parameter consistancy check */
00528   if (value >= 9999)
00529   {
00530     value = 9999;
00531   }
00532   if (value <= -1000)
00533   {
00534     value = -999;
00535   }
00536   if (value < 0)
00537   {
00538     value = abs(value);
00539     neg   = 1;
00540   }
00541   else
00542   {
00543     neg = 0;
00544   }
00545 
00546   /* If an update is in progress we must block, or there might be tearing */
00547   LCD_SyncBusyDelay(0xFFFFFFFF);
00548 
00549   /* Freeze updates to avoid partial refresh of display */
00550   LCD_FreezeEnable(true);
00551 
00552   /* Turn off all number LCD segments */
00553   SegmentLCD_NumberOff();
00554 
00555   /* Extract useful digits */
00556   div = 1;
00557   for (digit = 0; digit < 4; digit++)
00558   {
00559     num = (value / div) % 10;
00560     if ((neg == 1) && (digit == 3)) num = signIndex;
00561     /* Get number layout of display */
00562     bitpattern = EFM_Numbers[num];
00563     for (i = 0; i < 7; i++)
00564     {
00565       bit = EFM_Display.Number[digit].bit[i];
00566       com = EFM_Display.Number[digit].com[i];
00567       if (bitpattern & (1 << i))
00568       {
00569         LCD_SegmentSet(com, bit, true);
00570       }
00571     }
00572     div = div * 10;
00573   }
00574   /* Sync LCD registers to LE domain */
00575   LCD_FreezeEnable(false);
00576 }
00577 
00578 
00579 /**************************************************************************/
00582 void SegmentLCD_NumberOff(void)
00583 {
00584   /* Turn off all number segments */
00585   LCD_NUMBER_OFF();
00586   return;
00587 }
00588 
00589 
00590 /**************************************************************************/
00595 void SegmentLCD_Symbol(lcdSymbol s, int on)
00596 {
00597   int com = 0;
00598   int bit = 0;
00599 
00600   switch (s)
00601   {
00602   case LCD_SYMBOL_GECKO:
00603     com = LCD_SYMBOL_GECKO_COM;
00604     bit = LCD_SYMBOL_GECKO_SEG;
00605     break;
00606   case LCD_SYMBOL_ANT:
00607     com = LCD_SYMBOL_ANT_COM;
00608     bit = LCD_SYMBOL_ANT_SEG;
00609     break;
00610   case LCD_SYMBOL_PAD0:
00611     com = LCD_SYMBOL_PAD0_COM;
00612     bit = LCD_SYMBOL_PAD0_SEG;
00613     break;
00614   case LCD_SYMBOL_PAD1:
00615     com = LCD_SYMBOL_PAD1_COM;
00616     bit = LCD_SYMBOL_PAD1_SEG;
00617     break;
00618   case LCD_SYMBOL_EFM32:
00619     com = LCD_SYMBOL_EFM32_COM;
00620     bit = LCD_SYMBOL_EFM32_SEG;
00621     break;
00622   case LCD_SYMBOL_MINUS:
00623     com = LCD_SYMBOL_MINUS_COM;
00624     bit = LCD_SYMBOL_MINUS_SEG;
00625     break;
00626   case LCD_SYMBOL_COL3:
00627     com = LCD_SYMBOL_COL3_COM;
00628     bit = LCD_SYMBOL_COL3_SEG;
00629     break;
00630   case LCD_SYMBOL_COL5:
00631     com = LCD_SYMBOL_COL5_COM;
00632     bit = LCD_SYMBOL_COL5_SEG;
00633     break;
00634   case LCD_SYMBOL_COL10:
00635     com = LCD_SYMBOL_COL10_COM;
00636     bit = LCD_SYMBOL_COL10_SEG;
00637     break;
00638 #ifdef LCD_SYMBOL_DEGC_SEG
00639   case LCD_SYMBOL_DEGC:
00640     com = LCD_SYMBOL_DEGC_COM;
00641     bit = LCD_SYMBOL_DEGC_SEG;
00642     break;
00643 #endif
00644 #ifdef LCD_SYMBOL_DEGF_SEG
00645   case LCD_SYMBOL_DEGF:
00646     com = LCD_SYMBOL_DEGF_COM;
00647     bit = LCD_SYMBOL_DEGF_SEG;
00648     break;
00649 #endif
00650 #ifdef LCD_SYMBOL_DP2_SEG
00651   case LCD_SYMBOL_DP2:
00652     com = LCD_SYMBOL_DP2_COM;
00653     bit = LCD_SYMBOL_DP2_SEG;
00654     break;
00655 #endif
00656 #ifdef LCD_SYMBOL_DP3_SEG
00657   case LCD_SYMBOL_DP3:
00658     com = LCD_SYMBOL_DP3_COM;
00659     bit = LCD_SYMBOL_DP3_SEG;
00660     break;
00661 #endif
00662 #ifdef LCD_SYMBOL_DP4_SEG
00663   case LCD_SYMBOL_DP4:
00664     com = LCD_SYMBOL_DP4_COM;
00665     bit = LCD_SYMBOL_DP4_SEG;
00666     break;
00667 #endif
00668 #ifdef LCD_SYMBOL_DP5_SEG
00669   case LCD_SYMBOL_DP5:
00670     com = LCD_SYMBOL_DP5_COM;
00671     bit = LCD_SYMBOL_DP5_SEG;
00672     break;
00673 #endif
00674   case LCD_SYMBOL_DP6:
00675     com = LCD_SYMBOL_DP6_COM;
00676     bit = LCD_SYMBOL_DP6_SEG;
00677     break;
00678   case LCD_SYMBOL_DP10:
00679     com = LCD_SYMBOL_DP10_COM;
00680     bit = LCD_SYMBOL_DP10_SEG;
00681     break;
00682 #ifdef LCD_SYMBOL_AM_SEG
00683   case LCD_SYMBOL_AM:
00684     com = LCD_SYMBOL_AM_COM;
00685     bit = LCD_SYMBOL_AM_SEG;
00686     break;
00687 #endif
00688 #ifdef LCD_SYMBOL_PM_SEG
00689   case LCD_SYMBOL_PM:
00690     com = LCD_SYMBOL_PM_COM;
00691     bit = LCD_SYMBOL_PM_SEG;
00692     break;
00693 #endif
00694 #ifdef LCD_SYMBOL_MICROAMP_SEG
00695   case LCD_SYMBOL_MICROAMP:
00696     com = LCD_SYMBOL_MICROAMP_COM;
00697     bit = LCD_SYMBOL_MICROAMP_SEG;
00698     break;
00699 #endif
00700 #ifdef LCD_SYMBOL_MILLIAMP_SEG
00701   case LCD_SYMBOL_MILLIAMP:
00702     com = LCD_SYMBOL_MILLIAMP_COM;
00703     bit = LCD_SYMBOL_MILLIAMP_SEG;
00704     break;
00705 #endif
00706 
00707   }
00708   if (on)
00709   {
00710     LCD_SegmentSet(com, bit, true);
00711   }
00712   else
00713   {
00714     LCD_SegmentSet(com, bit, false);
00715   }
00716 }
00717 
00718 
00719 /**************************************************************************/
00723 void SegmentLCD_UnsignedHex(uint16_t value)
00724 {
00725   int      num, i, com, bit, digit;
00726   uint16_t bitpattern;
00727 
00728   /* Parameter consistancy check */
00729   if (value >= 0xffff)
00730   {
00731     value = 0xffff;
00732   }
00733 
00734   /* If an update is in progress we must block, or there might be tearing */
00735   LCD_SyncBusyDelay(0xFFFFFFFF);
00736 
00737   /* Freeze updates to avoid partial refresh of display */
00738   LCD_FreezeEnable(true);
00739 
00740   /* Turn off all number LCD segments */
00741   SegmentLCD_NumberOff();
00742 
00743   for (digit = 0; digit < 4; digit++)
00744   {
00745     num        = (value >> (4 * digit)) & 0x0f;
00746     bitpattern = EFM_Numbers[num];
00747     for (i = 0; i < 7; i++)
00748     {
00749       bit = EFM_Display.Number[digit].bit[i];
00750       com = EFM_Display.Number[digit].com[i];
00751       if (bitpattern & (1 << i))
00752       {
00753         LCD_SegmentSet(com, bit, true);
00754       }
00755     }
00756   }
00757 
00758   /* Sync LCD registers to LE domain */
00759   LCD_FreezeEnable(false);
00760 }
00761 
00762 
00763 /**************************************************************************/
00767 void SegmentLCD_Write(char *string)
00768 {
00769   int      data, length, index;
00770   uint16_t bitfield;
00771   uint32_t com, bit;
00772   int      i;
00773 
00774   length = strlen(string);
00775   index  = 0;
00776 
00777   /* If an update is in progress we must block, or there might be tearing */
00778   LCD_SyncBusyDelay(0xFFFFFFFF);
00779 
00780   /* Freeze LCD to avoid partial updates */
00781   LCD_FreezeEnable(true);
00782 
00783   /* Turn all segments off */
00784   SegmentLCD_AlphaNumberOff();
00785 
00786   /* Fill out all characters on display */
00787   for (index = 0; index < 7; index++)
00788   {
00789     if (index < length)
00790     {
00791       data = (int) *string;
00792     }
00793     else           /* Padding with space */
00794     {
00795       data = 0x20; /* SPACE */
00796     }
00797     /* Defined letters currently starts at "SPACE" - ASCII 0x20; */
00798     data = data - 0x20;
00799     /* Get font for this letter */
00800     bitfield = EFM_Alphabet[data];
00801 
00802     for (i = 0; i < 14; i++)
00803     {
00804       bit = EFM_Display.Text[index].bit[i];
00805       com = EFM_Display.Text[index].com[i];
00806 
00807       if (bitfield & (1 << i))
00808       {
00809         /* Turn on segment */
00810         LCD_SegmentSet(com, bit, true);
00811       }
00812     }
00813     string++;
00814   }
00815   /* Enable update */
00816   LCD_FreezeEnable(false);
00817 }