/***************************************************************************//** * @file em_lcd.h * @brief Liquid Crystal Display (LCD) peripheral API * @version 4.0.0 ******************************************************************************* * @section License * (C) Copyright 2014 Silicon Labs, http://www.silabs.com ******************************************************************************* * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no * obligation to support this Software. Silicon Labs is providing the * Software "AS IS", with no express or implied warranties of any kind, * including, but not limited to, any implied warranties of merchantability * or fitness for any particular purpose or warranties against infringement * of any proprietary rights of a third party. * * Silicon Labs will not be liable for any consequential, incidental, or * special damages, or any other relief, or for any claim by any third party, * arising from your use of this Software. * ******************************************************************************/ #ifndef __SILICON_LABS_EM_LCD_H_ #define __SILICON_LABS_EM_LCD_H_ #include "em_device.h" #if defined(LCD_COUNT) && (LCD_COUNT > 0) #include #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * @addtogroup EM_Library * @{ ******************************************************************************/ /***************************************************************************//** * @addtogroup LCD * @{ ******************************************************************************/ /******************************************************************************* ******************************** ENUMS ************************************ ******************************************************************************/ /** MUX setting */ typedef enum { /** Static (segments can be multiplexed with LCD_COM[0]) */ lcdMuxStatic = LCD_DISPCTRL_MUX_STATIC, /** Duplex / 1/2 Duty cycle (segments can be multiplexed with LCD_COM[0:1]) */ lcdMuxDuplex = LCD_DISPCTRL_MUX_DUPLEX, /** Triplex / 1/3 Duty cycle (segments can be multiplexed with LCD_COM[0:2]) */ lcdMuxTriplex = LCD_DISPCTRL_MUX_TRIPLEX, /** Quadruplex / 1/4 Duty cycle (segments can be multiplexed with LCD_COM[0:3]) */ lcdMuxQuadruplex = LCD_DISPCTRL_MUX_QUADRUPLEX, #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]) */ lcdMuxSextaplex = LCD_DISPCTRL_MUXE_MUXE | LCD_DISPCTRL_MUX_DUPLEX, /** Octaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]) */ lcdMuxOctaplex = LCD_DISPCTRL_MUXE_MUXE | LCD_DISPCTRL_MUX_QUADRUPLEX #endif } LCD_Mux_TypeDef; /** Bias setting */ typedef enum { /** Static (2 levels) */ lcdBiasStatic = LCD_DISPCTRL_BIAS_STATIC, /** 1/2 Bias (3 levels) */ lcdBiasOneHalf = LCD_DISPCTRL_BIAS_ONEHALF, /** 1/3 Bias (4 levels) */ lcdBiasOneThird = LCD_DISPCTRL_BIAS_ONETHIRD, #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) /** 1/4 Bias (5 levels) */ lcdBiasOneFourth = LCD_DISPCTRL_BIAS_ONEFOURTH, #endif } LCD_Bias_TypeDef; /** Wave type */ typedef enum { /** Low power optimized waveform output */ lcdWaveLowPower = LCD_DISPCTRL_WAVE_LOWPOWER, /** Regular waveform output */ lcdWaveNormal = LCD_DISPCTRL_WAVE_NORMAL } LCD_Wave_TypeDef; /** VLCD Voltage Source */ typedef enum { /** VLCD Powered by VDD */ lcdVLCDSelVDD = LCD_DISPCTRL_VLCDSEL_VDD, /** VLCD Powered by external VDD / Voltage Boost */ lcdVLCDSelVExtBoost = LCD_DISPCTRL_VLCDSEL_VEXTBOOST } LCD_VLCDSel_TypeDef; /** Contrast Configuration */ typedef enum { /** Contrast is adjusted relative to VDD (VLCD) */ lcdConConfVLCD = LCD_DISPCTRL_CONCONF_VLCD, /** Contrast is adjusted relative to Ground */ lcdConConfGND = LCD_DISPCTRL_CONCONF_GND } LCD_ConConf_TypeDef; /** Voltage Boost Level - Datasheets document setting for each part number */ typedef enum { lcdVBoostLevel0 = LCD_DISPCTRL_VBLEV_LEVEL0, /**< Voltage boost LEVEL0 */ lcdVBoostLevel1 = LCD_DISPCTRL_VBLEV_LEVEL1, /**< Voltage boost LEVEL1 */ lcdVBoostLevel2 = LCD_DISPCTRL_VBLEV_LEVEL2, /**< Voltage boost LEVEL2 */ lcdVBoostLevel3 = LCD_DISPCTRL_VBLEV_LEVEL3, /**< Voltage boost LEVEL3 */ lcdVBoostLevel4 = LCD_DISPCTRL_VBLEV_LEVEL4, /**< Voltage boost LEVEL4 */ lcdVBoostLevel5 = LCD_DISPCTRL_VBLEV_LEVEL5, /**< Voltage boost LEVEL5 */ lcdVBoostLevel6 = LCD_DISPCTRL_VBLEV_LEVEL6, /**< Voltage boost LEVEL6 */ lcdVBoostLevel7 = LCD_DISPCTRL_VBLEV_LEVEL7 /**< Voltage boost LEVEL7 */ } LCD_VBoostLevel_TypeDef; /** Frame Counter Clock Prescaler, FC-CLK = FrameRate (Hz) / this factor */ typedef enum { /** Prescale Div 1 */ lcdFCPrescDiv1 = LCD_BACTRL_FCPRESC_DIV1, /** Prescale Div 2 */ lcdFCPrescDiv2 = LCD_BACTRL_FCPRESC_DIV2, /** Prescale Div 4 */ lcdFCPrescDiv4 = LCD_BACTRL_FCPRESC_DIV4, /** Prescale Div 8 */ lcdFCPrescDiv8 = LCD_BACTRL_FCPRESC_DIV8 } LCD_FCPreScale_TypeDef; /** Segment selection */ typedef enum { /** Select segment lines 0 to 3 */ lcdSegment0_3 = (1 << 0), /** Select segment lines 4 to 7 */ lcdSegment4_7 = (1 << 1), /** Select segment lines 8 to 11 */ lcdSegment8_11 = (1 << 2), /** Select segment lines 12 to 15 */ lcdSegment12_15 = (1 << 3), /** Select segment lines 16 to 19 */ lcdSegment16_19 = (1 << 4), /** Select segment lines 20 to 23 */ lcdSegment20_23 = (1 << 5), #if defined(_EFM32_TINY_FAMILY) /** Select all segment lines */ lcdSegmentAll = (0x003f) #endif #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) /** Select segment lines 24 to 27 */ lcdSegment24_27 = (1 << 6), /** Select segment lines 28 to 31 */ lcdSegment28_31 = (1 << 7), /** Select segment lines 32 to 35 */ lcdSegment32_35 = (1 << 8), /** Select segment lines 36 to 39 */ lcdSegment36_39 = (1 << 9), /** Select all segment lines */ lcdSegmentAll = (0x03ff) #endif } LCD_SegmentRange_TypeDef; /** Update Data Control */ typedef enum { /** Regular update, data transfer done immediately */ lcdUpdateCtrlRegular = LCD_CTRL_UDCTRL_REGULAR, /** Data transfer done at Frame Counter event */ lcdUpdateCtrlFCEvent = LCD_CTRL_UDCTRL_FCEVENT, /** Data transfer done at Frame Start */ lcdUpdateCtrlFrameStart = LCD_CTRL_UDCTRL_FRAMESTART } LCD_UpdateCtrl_TypeDef; /** Animation Shift operation; none, left or right */ typedef enum { /** No shift */ lcdAnimShiftNone = _LCD_BACTRL_AREGASC_NOSHIFT, /** Shift segment bits left */ lcdAnimShiftLeft = _LCD_BACTRL_AREGASC_SHIFTLEFT, /** Shift segment bits right */ lcdAnimShiftRight = _LCD_BACTRL_AREGASC_SHIFTRIGHT } LCD_AnimShift_TypeDef; /** Animation Logic Control, how AReg and BReg should be combined */ typedef enum { /** Use bitwise logic AND to mix animation register A (AREGA) and B (AREGB) */ lcdAnimLogicAnd = LCD_BACTRL_ALOGSEL_AND, /** Use bitwise logic OR to mix animation register A (AREGA) and B (AREGB) */ lcdAnimLogicOr = LCD_BACTRL_ALOGSEL_OR } LCD_AnimLogic_TypeDef; /******************************************************************************* ******************************* STRUCTS *********************************** ******************************************************************************/ /** LCD Animation Configuration */ typedef struct { /** Enable Animation at end of initialization */ bool enable; /** Initial Animation Register A Value */ uint32_t AReg; /** Shift operation of Animation Register A */ LCD_AnimShift_TypeDef AShift; /** Initial Animation Register B Value */ uint32_t BReg; /** Shift operation of Animation Register B */ LCD_AnimShift_TypeDef BShift; /** A and B Logical Operation to use for mixing and outputting resulting segments */ LCD_AnimLogic_TypeDef animLogic; #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) /** Number of first segment to animate. Options are 0 or 8 for Giant/Leopard. End is startSeg+7 */ int startSeg; #endif } LCD_AnimInit_TypeDef; /** LCD Frame Control Initialization */ typedef struct { /** Enable at end */ bool enable; /** Frame Counter top value */ uint32_t top; /** Frame Counter clock prescaler */ LCD_FCPreScale_TypeDef prescale; } LCD_FrameCountInit_TypeDef; /** LCD Controller Initialization structure */ typedef struct { /** Enable controller at end of initialization */ bool enable; /** Mux configuration */ LCD_Mux_TypeDef mux; /** Bias configuration */ LCD_Bias_TypeDef bias; /** Wave configuration */ LCD_Wave_TypeDef wave; /** VLCD Select */ LCD_VLCDSel_TypeDef vlcd; /** Contrast Configuration */ LCD_ConConf_TypeDef contrast; } LCD_Init_TypeDef; /** Default config for LCD init structure, enables 160 segments */ #define LCD_INIT_DEFAULT \ { true, \ lcdMuxQuadruplex, \ lcdBiasOneThird, \ lcdWaveLowPower, \ lcdVLCDSelVDD, \ lcdConConfVLCD \ } /******************************************************************************* ***************************** PROTOTYPES ********************************** ******************************************************************************/ void LCD_Init(const LCD_Init_TypeDef *lcdInit); void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd); void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud); void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit); void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit); void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segment, bool enable); void LCD_SegmentSet(int com, int bit, bool enable); void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits); #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits); #endif void LCD_ContrastSet(int level); void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost); #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) void LCD_BiasSegmentSet(int segment, int biasLevel); void LCD_BiasComSet(int com, int biasLevel); #endif __STATIC_INLINE void LCD_Enable(bool enable); __STATIC_INLINE void LCD_AnimEnable(bool enable); __STATIC_INLINE void LCD_BlinkEnable(bool enable); __STATIC_INLINE void LCD_BlankEnable(bool enable); __STATIC_INLINE void LCD_FrameCountEnable(bool enable); __STATIC_INLINE int LCD_AnimState(void); __STATIC_INLINE int LCD_BlinkState(void); __STATIC_INLINE void LCD_FreezeEnable(bool enable); __STATIC_INLINE uint32_t LCD_SyncBusyGet(void); __STATIC_INLINE void LCD_SyncBusyDelay(uint32_t flags); __STATIC_INLINE uint32_t LCD_IntGet(void); __STATIC_INLINE uint32_t LCD_IntGetEnabled(void); __STATIC_INLINE void LCD_IntSet(uint32_t flags); __STATIC_INLINE void LCD_IntEnable(uint32_t flags); __STATIC_INLINE void LCD_IntDisable(uint32_t flags); __STATIC_INLINE void LCD_IntClear(uint32_t flags); #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) __STATIC_INLINE void LCD_DSCEnable(bool enable); #endif /***************************************************************************//** * @brief * Enable or disable LCD controller * * @param[in] enable * If true, enables LCD controller with current configuration, if false * disables LCD controller. CMU clock for LCD must be enabled for correct * operation. ******************************************************************************/ __STATIC_INLINE void LCD_Enable(bool enable) { if (enable) { LCD->CTRL |= LCD_CTRL_EN; } else { LCD->CTRL &= ~(LCD_CTRL_EN); } } /***************************************************************************//** * @brief * Enables or disables LCD Animation feature * * @param[in] enable * Boolean true enables animation, false disables animation ******************************************************************************/ __STATIC_INLINE void LCD_AnimEnable(bool enable) { if (enable) { LCD->BACTRL |= LCD_BACTRL_AEN; } else { LCD->BACTRL &= ~(LCD_BACTRL_AEN); } } /***************************************************************************//** * @brief * Enables or disables LCD blink * * @param[in] enable * Boolean true enables blink, false disables blink ******************************************************************************/ __STATIC_INLINE void LCD_BlinkEnable(bool enable) { if (enable) { LCD->BACTRL |= LCD_BACTRL_BLINKEN; } else { LCD->BACTRL &= ~(LCD_BACTRL_BLINKEN); } } /***************************************************************************//** * @brief * Disables all segments, while keeping segment state * * @param[in] enable * Boolean true clears all segments, boolean false restores all segment lines ******************************************************************************/ __STATIC_INLINE void LCD_BlankEnable(bool enable) { if (enable) { LCD->BACTRL |= LCD_BACTRL_BLANK; } else { LCD->BACTRL &= ~(LCD_BACTRL_BLANK); } } /***************************************************************************//** * @brief * Enables or disables LCD Frame Control * * @param[in] enable * Boolean true enables frame counter, false disables frame counter ******************************************************************************/ __STATIC_INLINE void LCD_FrameCountEnable(bool enable) { if (enable) { LCD->BACTRL |= LCD_BACTRL_FCEN; } else { LCD->BACTRL &= ~(LCD_BACTRL_FCEN); } } /***************************************************************************//** * @brief * Returns current animation state * * @return * Animation state, in range 0-15 ******************************************************************************/ __STATIC_INLINE int LCD_AnimState(void) { return (int)(LCD->STATUS & _LCD_STATUS_ASTATE_MASK) >> _LCD_STATUS_ASTATE_SHIFT; } /***************************************************************************//** * @brief * Returns current blink state * * @return * Return value is 1 if segments are enabled, 0 if disabled ******************************************************************************/ __STATIC_INLINE int LCD_BlinkState(void) { return (int)(LCD->STATUS & _LCD_STATUS_BLINK_MASK) >> _LCD_STATUS_BLINK_SHIFT; } /***************************************************************************//** * @brief * When set, LCD registers will not be updated until cleared, * * @param[in] enable * When enable is true, update is stopped, when false all registers are * updated ******************************************************************************/ __STATIC_INLINE void LCD_FreezeEnable(bool enable) { if (enable) { LCD->FREEZE = LCD_FREEZE_REGFREEZE_FREEZE; } else { LCD->FREEZE = LCD_FREEZE_REGFREEZE_UPDATE; } } /***************************************************************************//** * @brief * Returns SYNCBUSY bits, indicating which registers have pending updates * * @return * Bit fields for LCD registers which have pending updates ******************************************************************************/ __STATIC_INLINE uint32_t LCD_SyncBusyGet(void) { return(LCD->SYNCBUSY); } /***************************************************************************//** * @brief * Polls LCD SYNCBUSY flags, until flag has been cleared * * @param[in] flags * Bit fields for LCD registers that shall be updated before we continue ******************************************************************************/ __STATIC_INLINE void LCD_SyncBusyDelay(uint32_t flags) { while (LCD->SYNCBUSY & flags) ; } /***************************************************************************//** * @brief * Get pending LCD interrupt flags * * @return * Pending LCD interrupt sources. Returns a set of interrupt flags OR-ed * together for multiple interrupt sources in the LCD module (LCD_IFS_nnn). ******************************************************************************/ __STATIC_INLINE uint32_t LCD_IntGet(void) { return(LCD->IF); } /***************************************************************************//** * @brief * Get enabled and pending LCD interrupt flags. * * @details * Useful for handling more interrupt sources in the same interrupt handler. * * @note * The event bits are not cleared by the use of this function. * * @return * Pending and enabled LCD interrupt sources. * The return value is the bitwise AND combination of * - the OR combination of enabled interrupt sources in LCD_IEN_nnn * register (LCD_IEN_nnn) and * - the bitwise OR combination of valid interrupt flags of the LCD module * (LCD_IF_nnn). ******************************************************************************/ __STATIC_INLINE uint32_t LCD_IntGetEnabled(void) { uint32_t tmp = 0U; /* Store LCD->IEN in temporary variable in order to define explicit order * of volatile accesses. */ tmp = LCD->IEN; /* Bitwise AND of pending and enabled interrupts */ return LCD->IF & tmp; } /***************************************************************************//** * @brief * Set one or more pending LCD interrupts from SW. * * @param[in] flags * LCD interrupt sources to set to pending. Use a set of interrupt flags * OR-ed together to set multiple interrupt sources for the LCD module * (LCD_IFS_nnn). ******************************************************************************/ __STATIC_INLINE void LCD_IntSet(uint32_t flags) { LCD->IFS = flags; } /***************************************************************************//** * @brief * Enable LCD interrupts * * @param[in] flags * LCD interrupt sources to enable. Use a set of interrupt flags OR-ed * together to set multiple interrupt sources for the LCD module * (LCD_IFS_nnn). ******************************************************************************/ __STATIC_INLINE void LCD_IntEnable(uint32_t flags) { LCD->IEN |= flags; } /***************************************************************************//** * @brief * Disable LCD interrupts * * @param[in] flags * LCD interrupt sources to disable. Use a set of interrupt flags OR-ed * together to disable multiple interrupt sources for the LCD module * (LCD_IFS_nnn). ******************************************************************************/ __STATIC_INLINE void LCD_IntDisable(uint32_t flags) { LCD->IEN &= ~(flags); } /***************************************************************************//** * @brief * Clear one or more interrupt flags * * @param[in] flags * LCD interrupt sources to clear. Use a set of interrupt flags OR-ed * together to clear multiple interrupt sources for the LCD module * (LCD_IFS_nnn). ******************************************************************************/ __STATIC_INLINE void LCD_IntClear(uint32_t flags) { LCD->IFC = flags; } #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) /***************************************************************************//** * @brief * Enable or disable LCD Direct Segment Control * * @param[in] enable * If true, enables LCD controller Direct Segment Control * Segment and COM line bias levels needs to be set explicitly with the * LCD_BiasSegmentSet() and LCD_BiasComSet() function calls. ******************************************************************************/ __STATIC_INLINE void LCD_DSCEnable(bool enable) { if (enable) { LCD->CTRL |= LCD_CTRL_DSC; } else { LCD->CTRL &= ~(LCD_CTRL_DSC); } } #endif /** @} (end addtogroup LCD) */ /** @} (end addtogroup EM_Library) */ #ifdef __cplusplus } #endif #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */ #endif /* __SILICON_LABS_EM_LCD_H_ */