To avoid the LOW_FREQUENCY_VALUE issue. Change the 32768 direct value as for it.
Fork of EFM32_SegmentLCD by
segmentlcd.c
- Committer:
- ura_pooh
- Date:
- 2016-12-14
- Revision:
- 7:10a37bbb0698
- Parent:
- 0:559902e88130
File content as of revision 7:10a37bbb0698:
/**************************************************************************//** * @file * @brief EFM32 Segment LCD Display driver * @version 3.20.9 ****************************************************************************** * @section License * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * This file is licensensed under the Silabs License Agreement. See the file * "Silabs_License_Agreement.txt" for details. Before using this software for * any purpose, you must agree to the terms of that agreement. * ******************************************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #include "em_device.h" #include "em_cmu.h" #include "em_gpio.h" #include "device_peripherals.h" #include "segmentlcd.h" /**************************************************************************//** * @brief * Defines each text symbol's segment in terms of COM and BIT numbers, * in a way that we can enumerate each bit for each text segment in the * following bit pattern: * @verbatim * -------0------ * * | \7 |8 /9 | * |5 \ | / |1 * * --6--- ---10-- * * | / | \11 | * |4 /13 |12 \ |2 * * -------3------ * @endverbatim * E.g.: First text character bit pattern #3 (above) is * Segment 1D for Display * Location COM 3, BIT 0 *****************************************************************************/ typedef struct { uint8_t com[14]; /**< LCD COM line (for multiplexing) */ uint8_t bit[14]; /**< LCD bit number */ } CHAR_TypeDef; /**************************************************************************//** * @brief Defines segment COM and BIT fields numeric display *****************************************************************************/ typedef struct { uint8_t com[7]; /**< LCD COM line (for multiplexing) */ uint8_t bit[7]; /**< LCD bit number */ } NUMBER_TypeDef; /**************************************************************************//** * @brief Defines segment COM and BIT fields for Energy Modes on display *****************************************************************************/ typedef struct { uint8_t com[5]; /**< LCD COM line (for multiplexing) */ uint8_t bit[5]; /**< LCD bit number */ } EM_TypeDef; /**************************************************************************//** * @brief Defines segment COM and BIT fields for A-wheel (suited for Anim) *****************************************************************************/ typedef struct { uint8_t com[8]; /**< LCD COM line (for multiplexing) */ uint8_t bit[8]; /**< LCD bit number */ } ARING_TypeDef; /**************************************************************************//** * @brief Defines segment COM and BIT fields for A-wheel (suited for Anim) *****************************************************************************/ typedef struct { uint8_t com[4]; /**< LCD COM line (for multiplexing) */ uint8_t bit[4]; /**< LCD bit number */ } BATTERY_TypeDef; /**************************************************************************//** * @brief Defines prototype for all segments in display *****************************************************************************/ typedef struct { CHAR_TypeDef Text[7]; /**< Text on display */ NUMBER_TypeDef Number[4]; /**< Numbers on display */ EM_TypeDef EMode; /**< Display energy mode */ ARING_TypeDef ARing; /**< Display ring */ BATTERY_TypeDef Battery; /**< Display battery */ } MCU_DISPLAY; /**************************************************************************//** * @brief Working instance of LCD display *****************************************************************************/ static const MCU_DISPLAY EFM_Display = EFM_DISPLAY_DEF; /**************************************************************************//** * @brief * Defines higlighted segments for the alphabet, starting from "blank" (SPACE) * Uses bit pattern as defined for text segments above. * E.g. a capital O, would have bits 0 1 2 3 4 5 => 0x003f defined *****************************************************************************/ static const uint16_t EFM_Alphabet[] = { 0x0000, /* space */ 0x1100, /* ! */ 0x0280, /* " */ 0x0000, /* # */ 0x0000, /* $ */ 0x0602, /* % */ 0x0000, /* & */ 0x0020, /* ' */ 0x0039, /* ( */ 0x000f, /* ) */ 0x0000, /* * */ 0x1540, /* + */ 0x2000, /* , */ 0x0440, /* - */ 0x1000, /* . */ 0x2200, /* / */ 0x003f, /* 0 */ 0x0006, /* 1 */ 0x045b, /* 2 */ 0x044f, /* 3 */ 0x0466, /* 4 */ 0x046d, /* 5 */ 0x047d, /* 6 */ 0x0007, /* 7 */ 0x047f, /* 8 */ 0x046f, /* 9 */ 0x0000, /* : */ 0x0000, /* ; */ 0x0a00, /* < */ 0x0000, /* = */ 0x2080, /* > */ 0x0000, /* ? */ 0xffff, /* @ */ 0x0477, /* A */ 0x0a79, /* B */ 0x0039, /* C */ 0x20b0, /* D */ 0x0079, /* E */ 0x0071, /* F */ 0x047d, /* G */ 0x0476, /* H */ 0x0006, /* I */ 0x000e, /* J */ 0x0a70, /* K */ 0x0038, /* L */ 0x02b6, /* M */ 0x08b6, /* N */ 0x003f, /* O */ 0x0473, /* P */ 0x083f, /* Q */ 0x0c73, /* R */ 0x046d, /* S */ 0x1101, /* T */ 0x003e, /* U */ 0x2230, /* V */ 0x2836, /* W */ 0x2a80, /* X */ 0x046e, /* Y */ 0x2209, /* Z */ 0x0039, /* [ */ 0x0880, /* backslash */ 0x000f, /* ] */ 0x0001, /* ^ */ 0x0008, /* _ */ 0x0100, /* ` */ 0x1058, /* a */ 0x047c, /* b */ 0x0058, /* c */ 0x045e, /* d */ 0x2058, /* e */ 0x0471, /* f */ 0x0c0c, /* g */ 0x0474, /* h */ 0x0004, /* i */ 0x000e, /* j */ 0x0c70, /* k */ 0x0038, /* l */ 0x1454, /* m */ 0x0454, /* n */ 0x045c, /* o */ 0x0473, /* p */ 0x0467, /* q */ 0x0450, /* r */ 0x0c08, /* s */ 0x0078, /* t */ 0x001c, /* u */ 0x2010, /* v */ 0x2814, /* w */ 0x2a80, /* x */ 0x080c, /* y */ 0x2048, /* z */ 0x0000, }; /**************************************************************************//** * @brief * Defines higlighted segments for the numeric display *****************************************************************************/ static const uint16_t EFM_Numbers[] = { 0x003f, /* 0 */ 0x0006, /* 1 */ 0x005b, /* 2 */ 0x004f, /* 3 */ 0x0066, /* 4 */ 0x006d, /* 5 */ 0x007d, /* 6 */ 0x0007, /* 7 */ 0x007f, /* 8 */ 0x006f, /* 9 */ 0x0077, /* A */ 0x007c, /* b */ 0x0039, /* C */ 0x005e, /* d */ 0x0079, /* E */ 0x0071, /* F */ 0x0040 /* - */ }; /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /* sign is last element of the table */ static const uint16_t signIndex = sizeof(EFM_Numbers)/sizeof(uint16_t) - 1 ; static const LCD_Init_TypeDef lcdInit = LCD_INIT_DEF; /** @endcond */ /**************************************************************************//** * @brief Disable all segments *****************************************************************************/ void SegmentLCD_AllOff(void) { /* Turn on low segments */ LCD_ALL_SEGMENTS_OFF(); } /**************************************************************************//** * @brief Enable all segments *****************************************************************************/ void SegmentLCD_AllOn(void) { LCD_ALL_SEGMENTS_ON(); } /**************************************************************************//** * @brief Turn all segments on alpha characters in display off *****************************************************************************/ void SegmentLCD_AlphaNumberOff(void) { LCD_ALPHA_NUMBER_OFF(); return; } /**************************************************************************//** * @brief Light up or shut off Ring of Indicators * @param anum "Segment number" on "Ring", range 0 - 7 * @param on Zero is off, non-zero is on *****************************************************************************/ void SegmentLCD_ARing(int anum, int on) { uint32_t com, bit; com = EFM_Display.ARing.com[anum]; bit = EFM_Display.ARing.bit[anum]; if (on) { LCD_SegmentSet(com, bit, true); } else { LCD_SegmentSet(com, bit, false); } } /**************************************************************************//** * @brief Light up or shut off Battery Indicator * @param batteryLevel Battery Level, 0 to 4 (0 turns all off) *****************************************************************************/ void SegmentLCD_Battery(int batteryLevel) { uint32_t com, bit; int i, on; for (i = 0; i < 4; i++) { if (i < batteryLevel) { on = 1; } else { on = 0; } com = EFM_Display.Battery.com[i]; bit = EFM_Display.Battery.bit[i]; if (on) { LCD_SegmentSet(com, bit, true); } else { LCD_SegmentSet(com, bit, false); } } } /**************************************************************************//** * @brief Disables LCD controller *****************************************************************************/ void SegmentLCD_Disable(void) { /* Disable LCD */ LCD_Enable(false); /* Make sure CTRL register has been updated */ LCD_SyncBusyDelay(LCD_SYNCBUSY_CTRL); /* Turn off LCD clock */ CMU_ClockEnable(cmuClock_LCD, false); /* Turn off voltage boost if enabled */ CMU->LCDCTRL = 0; } /**************************************************************************//** * @brief Light up or shut off Energy Mode indicator * @param em Energy Mode numer 0 to 4 * @param on Zero is off, non-zero is on *****************************************************************************/ void SegmentLCD_EnergyMode(int em, int on) { uint32_t com, bit; com = EFM_Display.EMode.com[em]; bit = EFM_Display.EMode.bit[em]; if (on) { LCD_SegmentSet(com, bit, true); } else { LCD_SegmentSet(com, bit, false); } } /**************************************************************************//** * @brief Get frame rate division value corresponding to mux selection * @param mux enum *****************************************************************************/ uint8_t SegmentLCD_GetFrameRateDiv(LCD_Mux_TypeDef muxSetting) { switch(muxSetting) { /** Static (segments can be multiplexed with LCD_COM[0]) */ case lcdMuxStatic: return 2; /** Duplex / 1/2 Duty cycle (segments can be multiplexed with LCD_COM[0:1]) */ case lcdMuxDuplex: return 4; /** Triplex / 1/3 Duty cycle (segments can be multiplexed with LCD_COM[0:2]) */ case lcdMuxTriplex: return 6; /** Quadruplex / 1/4 Duty cycle (segments can be multiplexed with LCD_COM[0:3]) */ case lcdMuxQuadruplex: return 8; #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) /** Sextaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]) */ case lcdMuxSextaplex: return 12; /** Octaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]) */ case lcdMuxOctaplex: return 16; #endif default: return 1; } } /**************************************************************************//** * @brief Segment LCD Initialization routine for EFM32 STK display * @param useBoost Set to use voltage boost *****************************************************************************/ void SegmentLCD_Init(bool useBoost) { /* Ensure LE modules are accessible */ CMU_ClockEnable(cmuClock_CORELE, true); /* Enable LFRCO as LFACLK in CMU (will also enable oscillator if not enabled) */ CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); /* LCD Controller Prescaler */ /* Calculate value. Approach 50Hz for framerate. */ uint32_t prescaler = (32768 / 32) / SegmentLCD_GetFrameRateDiv(lcdInit.mux); CMU_ClockDivSet(cmuClock_LCDpre, prescaler); /* Frame Rate */ CMU_LCDClkFDIVSet(0); /* Enable clock to LCD module */ CMU_ClockEnable(cmuClock_LCD, true); LCD_DISPLAY_ENABLE(); /* Disable interrupts */ LCD_IntDisable(0xFFFFFFFF); /* Initialize and enable LCD controller */ LCD_Init(&lcdInit); /* Enable all display segments */ LCD_SEGMENTS_ENABLE(); /* Enable boost if necessary */ if (useBoost) { LCD_VBoostSet(LCD_BOOST_LEVEL); LCD_VLCDSelect(lcdVLCDSelVExtBoost); CMU->LCDCTRL |= CMU_LCDCTRL_VBOOSTEN; } /* Turn all segments off */ SegmentLCD_AllOff(); LCD_SyncBusyDelay(0xFFFFFFFF); } /**************************************************************************//** * @brief Write a hexadecimal number on lower alphanumeric part of * Segment LCD display * @param num Hexadecimal number value to put on display, in range 0 * to 0x0FFFFFFF *****************************************************************************/ void SegmentLCD_LowerHex( uint32_t num ) { int i; char str[7]; uint32_t nibble; SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 0); for ( i=6; i>=0; i-- ) { nibble = num & 0xF; if ( nibble < 10 ) str[i] = nibble + '0'; else if ( nibble == 11 ) str[i] = 'b'; else if ( nibble == 13 ) str[i] = 'd'; else str[i] = (nibble - 10) + 'A'; num >>= 4; } SegmentLCD_Write(str); } /**************************************************************************//** * @brief Write number on lower alphanumeric part of Segment LCD display * @param num Numeric value to put on display, in range -9999999 to +9999999 *****************************************************************************/ void SegmentLCD_LowerNumber( int num ) { int i; char str[7]; SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 0); if ( ( num > 9999999 ) || ( num < -9999999 ) ) { SegmentLCD_Write("Ovrflow"); return; } if ( num < 0 ) { SegmentLCD_Symbol(LCD_SYMBOL_MINUS, 1); num = -num; } for ( i=6; i>=0; i-- ) { if ( ( i < 6 ) && ( num == 0 ) ) { str[i] = ' '; } else { str[i] = (num % 10) + '0'; num /= 10; } } SegmentLCD_Write(str); } /**************************************************************************//** * @brief Write number on numeric part on Segment LCD display * @param value Numeric value to put on display, in range -999 to +9999 *****************************************************************************/ void SegmentLCD_Number(int value) { int i, com, bit, digit, div, neg; uint16_t bitpattern; uint16_t num; /* Parameter consistancy check */ if (value >= 9999) { value = 9999; } if (value <= -1000) { value = -999; } if (value < 0) { value = abs(value); neg = 1; } else { neg = 0; } /* If an update is in progress we must block, or there might be tearing */ LCD_SyncBusyDelay(0xFFFFFFFF); /* Freeze updates to avoid partial refresh of display */ LCD_FreezeEnable(true); /* Turn off all number LCD segments */ SegmentLCD_NumberOff(); /* Extract useful digits */ div = 1; for (digit = 0; digit < 4; digit++) { num = (value / div) % 10; if ((neg == 1) && (digit == 3)) num = signIndex; /* Get number layout of display */ bitpattern = EFM_Numbers[num]; for (i = 0; i < 7; i++) { bit = EFM_Display.Number[digit].bit[i]; com = EFM_Display.Number[digit].com[i]; if (bitpattern & (1 << i)) { LCD_SegmentSet(com, bit, true); } } div = div * 10; } /* Sync LCD registers to LE domain */ LCD_FreezeEnable(false); } /**************************************************************************//** * @brief Turn all segments on numeric digits in display off *****************************************************************************/ void SegmentLCD_NumberOff(void) { /* Turn off all number segments */ LCD_NUMBER_OFF(); return; } /**************************************************************************//** * @brief Light up or shut off various symbols on Segment LCD * @param s Which symbol to turn on or off * @param on Zero is off, non-zero is on *****************************************************************************/ void SegmentLCD_Symbol(lcdSymbol s, int on) { int com = 0; int bit = 0; switch (s) { case LCD_SYMBOL_GECKO: com = LCD_SYMBOL_GECKO_COM; bit = LCD_SYMBOL_GECKO_SEG; break; case LCD_SYMBOL_ANT: com = LCD_SYMBOL_ANT_COM; bit = LCD_SYMBOL_ANT_SEG; break; case LCD_SYMBOL_PAD0: com = LCD_SYMBOL_PAD0_COM; bit = LCD_SYMBOL_PAD0_SEG; break; case LCD_SYMBOL_PAD1: com = LCD_SYMBOL_PAD1_COM; bit = LCD_SYMBOL_PAD1_SEG; break; case LCD_SYMBOL_EFM32: com = LCD_SYMBOL_EFM32_COM; bit = LCD_SYMBOL_EFM32_SEG; break; case LCD_SYMBOL_MINUS: com = LCD_SYMBOL_MINUS_COM; bit = LCD_SYMBOL_MINUS_SEG; break; case LCD_SYMBOL_COL3: com = LCD_SYMBOL_COL3_COM; bit = LCD_SYMBOL_COL3_SEG; break; case LCD_SYMBOL_COL5: com = LCD_SYMBOL_COL5_COM; bit = LCD_SYMBOL_COL5_SEG; break; case LCD_SYMBOL_COL10: com = LCD_SYMBOL_COL10_COM; bit = LCD_SYMBOL_COL10_SEG; break; #ifdef LCD_SYMBOL_DEGC_SEG case LCD_SYMBOL_DEGC: com = LCD_SYMBOL_DEGC_COM; bit = LCD_SYMBOL_DEGC_SEG; break; #endif #ifdef LCD_SYMBOL_DEGF_SEG case LCD_SYMBOL_DEGF: com = LCD_SYMBOL_DEGF_COM; bit = LCD_SYMBOL_DEGF_SEG; break; #endif #ifdef LCD_SYMBOL_DP2_SEG case LCD_SYMBOL_DP2: com = LCD_SYMBOL_DP2_COM; bit = LCD_SYMBOL_DP2_SEG; break; #endif #ifdef LCD_SYMBOL_DP3_SEG case LCD_SYMBOL_DP3: com = LCD_SYMBOL_DP3_COM; bit = LCD_SYMBOL_DP3_SEG; break; #endif #ifdef LCD_SYMBOL_DP4_SEG case LCD_SYMBOL_DP4: com = LCD_SYMBOL_DP4_COM; bit = LCD_SYMBOL_DP4_SEG; break; #endif #ifdef LCD_SYMBOL_DP5_SEG case LCD_SYMBOL_DP5: com = LCD_SYMBOL_DP5_COM; bit = LCD_SYMBOL_DP5_SEG; break; #endif case LCD_SYMBOL_DP6: com = LCD_SYMBOL_DP6_COM; bit = LCD_SYMBOL_DP6_SEG; break; case LCD_SYMBOL_DP10: com = LCD_SYMBOL_DP10_COM; bit = LCD_SYMBOL_DP10_SEG; break; #ifdef LCD_SYMBOL_AM_SEG case LCD_SYMBOL_AM: com = LCD_SYMBOL_AM_COM; bit = LCD_SYMBOL_AM_SEG; break; #endif #ifdef LCD_SYMBOL_PM_SEG case LCD_SYMBOL_PM: com = LCD_SYMBOL_PM_COM; bit = LCD_SYMBOL_PM_SEG; break; #endif #ifdef LCD_SYMBOL_MICROAMP_SEG case LCD_SYMBOL_MICROAMP: com = LCD_SYMBOL_MICROAMP_COM; bit = LCD_SYMBOL_MICROAMP_SEG; break; #endif #ifdef LCD_SYMBOL_MILLIAMP_SEG case LCD_SYMBOL_MILLIAMP: com = LCD_SYMBOL_MILLIAMP_COM; bit = LCD_SYMBOL_MILLIAMP_SEG; break; #endif } if (on) { LCD_SegmentSet(com, bit, true); } else { LCD_SegmentSet(com, bit, false); } } /**************************************************************************//** * @brief Write hexadecimal number on numeric part on Segment LCD display * @param value Numeric value to put on display, in range 0x0000-0xFFFF *****************************************************************************/ void SegmentLCD_UnsignedHex(uint16_t value) { int num, i, com, bit, digit; uint16_t bitpattern; /* Parameter consistancy check */ if (value >= 0xffff) { value = 0xffff; } /* If an update is in progress we must block, or there might be tearing */ LCD_SyncBusyDelay(0xFFFFFFFF); /* Freeze updates to avoid partial refresh of display */ LCD_FreezeEnable(true); /* Turn off all number LCD segments */ SegmentLCD_NumberOff(); for (digit = 0; digit < 4; digit++) { num = (value >> (4 * digit)) & 0x0f; bitpattern = EFM_Numbers[num]; for (i = 0; i < 7; i++) { bit = EFM_Display.Number[digit].bit[i]; com = EFM_Display.Number[digit].com[i]; if (bitpattern & (1 << i)) { LCD_SegmentSet(com, bit, true); } } } /* Sync LCD registers to LE domain */ LCD_FreezeEnable(false); } /**************************************************************************//** * @brief Write text on LCD display * @param string Text string to show on display *****************************************************************************/ void SegmentLCD_Write(char *string) { int data, length, index; uint16_t bitfield; uint32_t com, bit; int i; length = strlen(string); index = 0; /* If an update is in progress we must block, or there might be tearing */ LCD_SyncBusyDelay(0xFFFFFFFF); /* Freeze LCD to avoid partial updates */ LCD_FreezeEnable(true); /* Turn all segments off */ SegmentLCD_AlphaNumberOff(); /* Fill out all characters on display */ for (index = 0; index < 7; index++) { if (index < length) { data = (int) *string; } else /* Padding with space */ { data = 0x20; /* SPACE */ } /* Defined letters currently starts at "SPACE" - ASCII 0x20; */ data = data - 0x20; /* Get font for this letter */ bitfield = EFM_Alphabet[data]; for (i = 0; i < 14; i++) { bit = EFM_Display.Text[index].bit[i]; com = EFM_Display.Text[index].com[i]; if (bitfield & (1 << i)) { /* Turn on segment */ LCD_SegmentSet(com, bit, true); } } string++; } /* Enable update */ LCD_FreezeEnable(false); }