segmentlcd.c

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