added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Revision:
0:9b334a45a8ff
Child:
50:a417edff4437
diff -r 000000000000 -r 9b334a45a8ff targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_lcd.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_lcd.c	Thu Oct 01 15:25:22 2015 +0300
@@ -0,0 +1,766 @@
+/***************************************************************************//**
+ * @file em_lcd.c
+ * @brief Liquid Crystal Display (LCD) Peripheral API
+ * @version 3.20.12
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+
+#include "em_lcd.h"
+#if defined(LCD_COUNT) && (LCD_COUNT > 0)
+#include "em_assert.h"
+#include "em_bitband.h"
+
+/***************************************************************************//**
+ * @addtogroup EM_Library
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup LCD
+ * @brief Liquid Crystal Display (LCD) Peripheral API
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ *   Initalize Liquid Crystal Display (LCD) controller
+ *
+ * @details
+ *   This function call will only configure the LCD controller. You must enable
+ *   it afterwards, potentially configuring Frame Control and interrupts first
+ *   according to requirements.
+ *
+ * @param[in] lcdInit
+ *   Pointer to initialization structure which configures LCD controller.
+ *
+ ******************************************************************************/
+void LCD_Init(const LCD_Init_TypeDef *lcdInit)
+{
+  uint32_t dispCtrl = LCD->DISPCTRL;
+
+  EFM_ASSERT(lcdInit != (void *) 0);
+
+  /* Disable controller before reconfiguration */
+  LCD_Enable(false);
+
+  /* Make sure we don't touch other bit fields (i.e. voltage boost) */
+  dispCtrl &= ~(
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    _LCD_DISPCTRL_MUXE_MASK |
+#endif
+    _LCD_DISPCTRL_MUX_MASK |
+    _LCD_DISPCTRL_BIAS_MASK |
+    _LCD_DISPCTRL_WAVE_MASK |
+    _LCD_DISPCTRL_VLCDSEL_MASK |
+    _LCD_DISPCTRL_CONCONF_MASK);
+
+  /* Configure controller according to initialization structure */
+  dispCtrl |= lcdInit->mux; /* also configures MUXE */
+  dispCtrl |= lcdInit->bias;
+  dispCtrl |= lcdInit->wave;
+  dispCtrl |= lcdInit->vlcd;
+  dispCtrl |= lcdInit->contrast;
+
+  /* Update display controller */
+  LCD->DISPCTRL = dispCtrl;
+
+  /* Enable controller if wanted */
+  if (lcdInit->enable)
+  {
+    LCD_Enable(true);
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Select source for VLCD
+ *
+ * @param[in] vlcd
+ *   Select source for VLD voltage
+ ******************************************************************************/
+void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)
+{
+  uint32_t dispctrl = LCD->DISPCTRL;
+
+  /* Select VEXT or VDD */
+  dispctrl &= ~(_LCD_DISPCTRL_VLCDSEL_MASK);
+  switch (vlcd)
+  {
+  case lcdVLCDSelVExtBoost:
+    dispctrl |= LCD_DISPCTRL_VLCDSEL_VEXTBOOST;
+    break;
+  case lcdVLCDSelVDD:
+    dispctrl |= LCD_DISPCTRL_VLCDSEL_VDD;
+    break;
+  default:
+    break;
+  }
+
+  LCD->DISPCTRL = dispctrl;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure Update Control
+ *
+ * @param[in] ud
+ *   Configures LCD update method
+ ******************************************************************************/
+void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)
+{
+  LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Initialize LCD Frame Counter
+ *
+ * @param[in] fcInit
+ *   Pointer to Frame Counter initialization structure
+ ******************************************************************************/
+void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit)
+{
+  uint32_t bactrl = LCD->BACTRL;
+
+  EFM_ASSERT(fcInit != (void *) 0);
+
+  /* Verify FC Top Counter to be within limits */
+  EFM_ASSERT(fcInit->top < 64);
+
+  /* Reconfigure frame count configuration */
+  bactrl &= ~(_LCD_BACTRL_FCTOP_MASK |
+              _LCD_BACTRL_FCPRESC_MASK);
+  bactrl |= (fcInit->top << _LCD_BACTRL_FCTOP_SHIFT);
+  bactrl |= fcInit->prescale;
+
+  /* Set Blink and Animation Control Register */
+  LCD->BACTRL = bactrl;
+
+  LCD_FrameCountEnable(fcInit->enable);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configures LCD controller Animation feature
+ *
+ * @param[in] animInit
+ *   Pointer to LCD Animation initialization structure
+ ******************************************************************************/
+void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit)
+{
+  uint32_t bactrl = LCD->BACTRL;
+
+  EFM_ASSERT(animInit != (void *) 0);
+
+  /* Set Animation Register Values */
+  LCD->AREGA = animInit->AReg;
+  LCD->AREGB = animInit->BReg;
+
+  /* Configure Animation Shift and Logic */
+  bactrl &= ~(_LCD_BACTRL_AREGASC_MASK |
+              _LCD_BACTRL_AREGBSC_MASK |
+              _LCD_BACTRL_ALOGSEL_MASK);
+
+  bactrl |= (animInit->AShift << _LCD_BACTRL_AREGASC_SHIFT);
+  bactrl |= (animInit->BShift << _LCD_BACTRL_AREGBSC_SHIFT);
+  bactrl |= animInit->animLogic;
+
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  bactrl &= ~(_LCD_BACTRL_ALOC_MASK);
+
+  if(animInit->startSeg == 0)
+  {
+    bactrl |= LCD_BACTRL_ALOC_SEG0TO7;
+  }
+  else if(animInit->startSeg == 8)
+  {
+    bactrl |= LCD_BACTRL_ALOC_SEG8TO15;
+  }
+#endif
+
+  /* Reconfigure */
+  LCD->BACTRL = bactrl;
+
+  /* Enable */
+  LCD_AnimEnable(animInit->enable);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Enables update of this range of LCD segment lines
+ *
+ * @param[in] segmentRange
+ *   Range of 4 LCD segments lines to enable or disable, for all enabled COM
+ *   lines
+ *
+ * @param[in] enable
+ *   Bool true to enable segment updates, false to disable updates
+ ******************************************************************************/
+void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange, bool enable)
+{
+  if (enable)
+  {
+    LCD->SEGEN |= segmentRange;
+  }
+  else
+  {
+    LCD->SEGEN &= ~((uint32_t)segmentRange);
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Turn on or clear a segment
+ *
+ * @note
+ *    On Gecko Family, max configuration is (COM-lines x Segment-Lines) 4x40
+ *    On Tiny Family, max configuration is 8x20 or 4x24
+ *    On Giant Family, max configuration is 8x36 or 4x40
+ *
+ * @param[in] com
+ *   COM line to change
+ *
+ * @param[in] bit
+ *   Bit index of which field to change
+ *
+ * @param[in] enable
+ *   When true will set segment, when false will clear segment
+ ******************************************************************************/
+void LCD_SegmentSet(int com, int bit, bool enable)
+{
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  /* Tiny and Giant Family supports up to 8 COM lines */
+  EFM_ASSERT(com < 8);
+#else
+  /* Gecko Family supports up to 4 COM lines */
+  EFM_ASSERT(com < 4);
+#endif
+
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  EFM_ASSERT(bit < 40);
+#else
+  /* Tiny Gecko Family supports only "low" segment registers */
+  EFM_ASSERT(bit < 32);
+#endif
+
+  /* Use bitband access for atomic bit set/clear of segment */
+  switch (com)
+  {
+  case 0:
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD0L), bit, (unsigned int)enable);
+    }
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD0H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 1:
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD1L), bit, (unsigned int)enable);
+    }
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD1H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 2:
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD2L), bit, (unsigned int)enable);
+    }
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD2H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 3:
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD3L), bit, (unsigned int)enable);
+    }
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD3H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 4:
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD4L), bit, (unsigned int)enable);
+    }
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD4H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 5:
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD5L), bit, (unsigned int)enable);
+    }
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD5H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 6:
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD6L), bit, (unsigned int)enable);
+    }
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD6H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+  case 7:
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    if (bit < 32)
+    {
+      BITBAND_Peripheral(&(LCD->SEGD7L), bit, (unsigned int)enable);
+    }
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+    else
+    {
+      bit -= 32;
+      BITBAND_Peripheral(&(LCD->SEGD7H), bit, (unsigned int)enable);
+    }
+#endif
+    break;
+
+  default:
+    EFM_ASSERT(0);
+    break;
+  }
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Updates the 0-31 lowest segments on a given COM-line in one operation,
+ *   according to bit mask
+ *
+ * @param[in] com
+ *   Which COM line to update
+ *
+ * @param[in] mask
+ *   Bit mask for segments 0-31
+ *
+ * @param[in] bits
+ *   Bit pattern for segments 0-31
+ ******************************************************************************/
+void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
+{
+  uint32_t segData;
+
+  /* Maximum number of com lines */
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  EFM_ASSERT(com < 8);
+#else
+  /* Gecko Family supports up to 4 COM lines */
+  EFM_ASSERT(com < 4);
+#endif
+
+  switch (com)
+  {
+  case 0:
+    segData     = LCD->SEGD0L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD0L = segData;
+    break;
+  case 1:
+    segData     = LCD->SEGD1L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD1L = segData;
+    break;
+  case 2:
+    segData     = LCD->SEGD2L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD2L = segData;
+    break;
+  case 3:
+    segData     = LCD->SEGD3L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD3L = segData;
+    break;
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 4:
+    segData     = LCD->SEGD4L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD4L = segData;
+    break;
+#endif
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) 
+  case 5:
+    segData     = LCD->SEGD5L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD5L = segData;
+    break;
+#endif
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 6:
+    segData     = LCD->SEGD6L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD6L = segData;
+    break;
+#endif
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 7:
+    segData     = LCD->SEGD7L;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD7L = segData;
+    break;
+#endif
+  default:
+    EFM_ASSERT(0);
+    break;
+  }
+}
+
+
+#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+/***************************************************************************//**
+ * @brief
+ *   Updated the high (32-39) segments on a given COM-line in one operation
+ *
+ * @param[in] com
+ *   Which COM line to update
+ *
+ * @param[in] mask
+ *   Bit mask for segments 32-39
+ *
+ * @param[in] bits
+ *   Bit pattern for segments 32-39
+ ******************************************************************************/
+void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
+{
+  uint32_t segData;
+
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  EFM_ASSERT(com < 8);
+#endif
+#if defined(_EFM32_GECKO_FAMILY)
+  EFM_ASSERT(com < 4);
+#endif
+
+  /* Maximum number of com lines */
+  switch (com)
+  {
+  case 0:
+    segData     = LCD->SEGD0H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD0H = segData;
+    break;
+  case 1:
+    segData     = LCD->SEGD1H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD1H = segData;
+    break;
+  case 2:
+    segData     = LCD->SEGD2H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD2H = segData;
+    break;
+  case 3:
+    segData     = LCD->SEGD3H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD3H = segData;
+    break;
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 4:
+    segData     = LCD->SEGD4H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD4H = segData;
+    break;
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 5:
+    segData     = LCD->SEGD5H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD5H = segData;
+    break;
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 6:
+    segData     = LCD->SEGD6H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD6H = segData;
+    break;
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  case 7:
+    segData     = LCD->SEGD7H;
+    segData    &= ~(mask);
+    segData    |= (mask & bits);
+    LCD->SEGD7H = segData;
+    break;
+#endif
+  default:
+    break;
+  }
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ *   Configure contrast level on LCD panel
+ *
+ * @param[in] level
+ *   Contrast level in the range 0-31
+ ******************************************************************************/
+void LCD_ContrastSet(int level)
+{
+  EFM_ASSERT(level < 32);
+
+  LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONLEV_MASK)
+                  | (level << _LCD_DISPCTRL_CONLEV_SHIFT);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure voltage booster
+ *
+ * The resulting voltage level is described in each part number's data sheet
+ *
+ * @param[in] vboost
+ *   Voltage boost level
+ ******************************************************************************/
+void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)
+{
+  /* Reconfigure Voltage Boost */
+  LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_VBLEV_MASK) | vboost;
+}
+
+
+#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+/***************************************************************************//**
+ * @brief
+ *   Configure bias level for a specific segment line for Direct Segment Control
+ *
+ * @note
+ *   When DSC is active, each configuration takes up 4 bits in the Segment
+ *   Registers (SEGD0L/SEGD1H) which defines bias level.
+ *   For optimal use of this feature, the entire SEGD-registers should be set
+ *   at once in a optimized routine, so this function is mainly here to
+ *   demonstrate how to correctly configure the bias levels, and should be used
+ *   with care.
+ *
+ * @param[in] segmentLine
+ *   Segment line number
+ *
+ * @param[in] biasLevel
+ *   Bias configuration level, 0-4. This value must be within the constraint
+ *   defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
+ ******************************************************************************/
+void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
+{
+  int               biasRegister;
+  int               bitShift;
+  volatile uint32_t *segmentRegister;
+
+#if defined(_EFM32_TINY_FAMILY)
+  EFM_ASSERT(segmentLine < 20);
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+  EFM_ASSERT(segmentLine < 40);
+#endif
+#if defined(_EFM32_TINY_FAMILY)
+  /* Bias config for 8 segment lines per SEGDnL register */
+  biasRegister = segmentLine / 8;
+  bitShift     = (segmentLine % 8) * 4;
+
+  switch (biasRegister)
+  {
+  case 0:
+    segmentRegister = &LCD->SEGD0L;
+    break;
+  case 1:
+    segmentRegister = &LCD->SEGD1L;
+    break;
+  case 2:
+    segmentRegister = &LCD->SEGD2L;
+    break;
+  case 3:
+    segmentRegister = &LCD->SEGD3L;
+    break;
+  default:
+    segmentRegister = (uint32_t *)0x00000000;
+    EFM_ASSERT(0);
+    break;
+  }
+#endif
+#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) 
+  /* Bias config for 10 segment lines per SEGDn L+H registers */
+  biasRegister = segmentLine / 10;
+  bitShift     = (segmentLine % 10) * 4;
+
+  switch (biasRegister)
+  {
+  case 0:
+    if (bitShift < 32)
+    {
+      segmentRegister = &LCD->SEGD0L;
+    }
+    else
+    {
+      segmentRegister = &LCD->SEGD0H;
+      bitShift       -= 32;
+    }
+    break;
+  case 1:
+    if (bitShift < 32)
+    {
+      segmentRegister = &LCD->SEGD1L;
+    }
+    else
+    {
+      segmentRegister = &LCD->SEGD1H;
+      bitShift       -= 32;
+    }
+    break;
+  case 2:
+    if (bitShift < 32)
+    {
+      segmentRegister = &LCD->SEGD2L;
+    }
+    else
+    {
+      segmentRegister = &LCD->SEGD1H;
+      bitShift       -= 32;
+    }
+    break;
+  case 3:
+    if (bitShift < 32)
+    {
+      segmentRegister = &LCD->SEGD3L;
+    }
+    else
+    {
+      segmentRegister = &LCD->SEGD3H;
+      bitShift       -= 32;
+    }
+    break;
+  default:
+    segmentRegister = (uint32_t *)0x00000000;
+    EFM_ASSERT(0);
+    break;
+  }
+#endif
+
+  /* Configure new bias setting */
+  *segmentRegister = (*segmentRegister & ~(0xF << bitShift)) | (biasLevel << bitShift);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Configure bias level for a specific segment line
+ *
+ * @note
+ *   When DSC is active, each configuration takes up 4 bits in the Segment
+ *   Registers (SEGD4L/SEGD4H) which defines bias level.
+ *   For optimal use of this feature, the entire SEGD-registers should be set
+ *   at once in a optimized routine, so this function is mainly here to
+ *   demonstrate how to correctly configure the bias levels, and should be used
+ *   with care.
+ *
+ * @param[in] comLine
+ *   COM line number, 0-7
+ *
+ * @param[in] biasLevel
+ *   Bias configuration level, 0-4. This value must be within the constraint
+ *   defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
+ ******************************************************************************/
+void LCD_BiasComSet(int comLine, int biasLevel)
+{
+  int bitShift;
+  EFM_ASSERT(comLine < 8);
+
+  bitShift    = comLine * 4;
+  LCD->SEGD4L = (LCD->SEGD4L & ~(0xF << bitShift)) | (biasLevel << bitShift);
+}
+#endif
+
+/** @} (end addtogroup LCD) */
+/** @} (end addtogroup EM_Library) */
+
+#endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */