1 /***************************************************************************//**
2  * @file
3  * @brief Liquid Crystal Display (LCD) Peripheral API
4  * @author Energy Micro AS
5  * @version 3.0.0
6  *******************************************************************************
7  * @section License
8  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9  *******************************************************************************
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute it
13  * freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must not
16  *    claim that you wrote the original software.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  *    misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  *
21  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22  * obligation to support this Software. Energy Micro AS is providing the
23  * Software "AS IS", with no express or implied warranties of any kind,
24  * including, but not limited to, any implied warranties of merchantability
25  * or fitness for any particular purpose or warranties against infringement
26  * of any proprietary rights of a third party.
27  *
28  * Energy Micro AS will not be liable for any consequential, incidental, or
29  * special damages, or any other relief, or for any claim by any third party,
30  * arising from your use of this Software.
31  *
32  ******************************************************************************/
33 #include "em_lcd.h"
34 #if defined(LCD_COUNT) && (LCD_COUNT > 0)
35 #include "em_assert.h"
36 #include "em_bitband.h"
37 
38 /***************************************************************************//**
39  * @addtogroup EM_Library
40  * @{
41  ******************************************************************************/
42 
43 /***************************************************************************//**
44  * @addtogroup LCD
45  * @brief Liquid Crystal Display (LCD) Peripheral API
46  * @{
47  ******************************************************************************/
48 
49 /***************************************************************************//**
50  * @brief
51  *   Initalize Liquid Crystal Display (LCD) controller
52  *
53  * @details
54  *   This function call will only configure the LCD controller. You must enable
55  *   it afterwards, potentially configuring Frame Control and interrupts first
56  *   according to requirements.
57  *
58  * @param[in] lcdInit
59  *   Pointer to initialization structure which configures LCD controller.
60  *
61  ******************************************************************************/
LCD_Init(const LCD_Init_TypeDef * lcdInit)62 void LCD_Init(const LCD_Init_TypeDef *lcdInit)
63 {
64   uint32_t dispCtrl = LCD->DISPCTRL;
65 
66   EFM_ASSERT(lcdInit != (void *) 0);
67 
68   /* Disable controller before reconfiguration */
69   LCD_Enable(false);
70 
71   /* Make sure we don't touch other bit fields (i.e. voltage boost) */
72   dispCtrl &= ~(
73 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
74     _LCD_DISPCTRL_MUXE_MASK |
75 #endif
76     _LCD_DISPCTRL_MUX_MASK |
77     _LCD_DISPCTRL_BIAS_MASK |
78     _LCD_DISPCTRL_WAVE_MASK |
79     _LCD_DISPCTRL_VLCDSEL_MASK |
80     _LCD_DISPCTRL_CONCONF_MASK);
81 
82   /* Configure controller according to initialization structure */
83   dispCtrl |= lcdInit->mux; /* also configures MUXE */
84   dispCtrl |= lcdInit->bias;
85   dispCtrl |= lcdInit->wave;
86   dispCtrl |= lcdInit->vlcd;
87   dispCtrl |= lcdInit->contrast;
88 
89   /* Update display controller */
90   LCD->DISPCTRL = dispCtrl;
91 
92   /* Enable controller if wanted */
93   if (lcdInit->enable)
94   {
95     LCD_Enable(true);
96   }
97 }
98 
99 
100 /***************************************************************************//**
101  * @brief
102  *   Select source for VLCD
103  *
104  * @param[in] vlcd
105  *   Select source for VLD voltage
106  ******************************************************************************/
LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)107 void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)
108 {
109   uint32_t dispctrl = LCD->DISPCTRL;
110 
111   /* Select VEXT or VDD */
112   dispctrl &= ~(_LCD_DISPCTRL_VLCDSEL_MASK);
113   switch (vlcd)
114   {
115   case lcdVLCDSelVExtBoost:
116     dispctrl |= LCD_DISPCTRL_VLCDSEL_VEXTBOOST;
117     break;
118   case lcdVLCDSelVDD:
119     dispctrl |= LCD_DISPCTRL_VLCDSEL_VDD;
120     break;
121   default:
122     break;
123   }
124 
125   LCD->DISPCTRL = dispctrl;
126 }
127 
128 
129 /***************************************************************************//**
130  * @brief
131  *   Configure Update Control
132  *
133  * @param[in] ud
134  *   Configures LCD update method
135  ******************************************************************************/
LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)136 void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)
137 {
138   LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
139 }
140 
141 
142 /***************************************************************************//**
143  * @brief
144  *   Initialize LCD Frame Counter
145  *
146  * @param[in] fcInit
147  *   Pointer to Frame Counter initialization structure
148  ******************************************************************************/
LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef * fcInit)149 void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit)
150 {
151   uint32_t bactrl = LCD->BACTRL;
152 
153   EFM_ASSERT(fcInit != (void *) 0);
154 
155   /* Verify FC Top Counter to be within limits */
156   EFM_ASSERT(fcInit->top < 64);
157 
158   /* Reconfigure frame count configuration */
159   bactrl &= ~(_LCD_BACTRL_FCTOP_MASK |
160               _LCD_BACTRL_FCPRESC_MASK);
161   bactrl |= (fcInit->top << _LCD_BACTRL_FCTOP_SHIFT);
162   bactrl |= fcInit->prescale;
163 
164   /* Set Blink and Animation Control Register */
165   LCD->BACTRL = bactrl;
166 
167   LCD_FrameCountEnable(fcInit->enable);
168 }
169 
170 
171 /***************************************************************************//**
172  * @brief
173  *   Configures LCD controller Animation feature
174  *
175  * @param[in] animInit
176  *   Pointer to LCD Animation initialization structure
177  ******************************************************************************/
LCD_AnimInit(const LCD_AnimInit_TypeDef * animInit)178 void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit)
179 {
180   uint32_t bactrl = LCD->BACTRL;
181 
182   EFM_ASSERT(animInit != (void *) 0);
183 
184   /* Set Animation Register Values */
185   LCD->AREGA = animInit->AReg;
186   LCD->AREGB = animInit->BReg;
187 
188   /* Configure Animation Shift and Logic */
189   bactrl &= ~(_LCD_BACTRL_AREGASC_MASK |
190               _LCD_BACTRL_AREGBSC_MASK |
191               _LCD_BACTRL_ALOGSEL_MASK);
192 
193   bactrl |= (animInit->AShift << _LCD_BACTRL_AREGASC_SHIFT);
194   bactrl |= (animInit->BShift << _LCD_BACTRL_AREGBSC_SHIFT);
195   bactrl |= animInit->animLogic;
196 
197 #if defined(_EFM32_GIANT_FAMILY)
198   if(animInit->startSeg == 0)
199   {
200     bactrl |= LCD_BACTRL_ALOC_SEG0TO7;
201   }
202   else if(animInit->startSeg == 8)
203   {
204     bactrl |= LCD_BACTRL_ALOC_SEG8TO15;
205   }
206 #endif
207 
208   /* Reconfigure */
209   LCD->BACTRL = bactrl;
210 
211   /* Enable */
212   LCD_AnimEnable(animInit->enable);
213 }
214 
215 
216 /***************************************************************************//**
217  * @brief
218  *   Enables update of this range of LCD segment lines
219  *
220  * @param[in] segmentRange
221  *   Range of 4 LCD segments lines to enable or disable, for all enabled COM
222  *   lines
223  *
224  * @param[in] enable
225  *   Bool true to enable segment updates, false to disable updates
226  ******************************************************************************/
LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange,bool enable)227 void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange, bool enable)
228 {
229   if (enable)
230   {
231     LCD->SEGEN |= segmentRange;
232   }
233   else
234   {
235     LCD->SEGEN &= ~((uint32_t)segmentRange);
236   }
237 }
238 
239 
240 /***************************************************************************//**
241  * @brief
242  *   Turn on or clear a segment
243  *
244  * @note
245  *    On Gecko Family, max configuration is (COM-lines x Segment-Lines) 4x40
246  *    On Tiny Family, max configuration is 8x20 or 4x24
247  *    On Giant Family, max configuration is 8x36 or 4x40
248  *
249  * @param[in] com
250  *   COM line to change
251  *
252  * @param[in] bit
253  *   Bit index of which field to change
254  *
255  * @param[in] enable
256  *   When true will set segment, when false will clear segment
257  ******************************************************************************/
LCD_SegmentSet(int com,int bit,bool enable)258 void LCD_SegmentSet(int com, int bit, bool enable)
259 {
260 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
261   /* Tiny and Giant Family supports up to 8 COM lines */
262   EFM_ASSERT(com < 8);
263 #else
264   /* Gecko Family supports up to 4 COM lines */
265   EFM_ASSERT(com < 4);
266 #endif
267 
268 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
269   EFM_ASSERT(bit < 40);
270 #else
271   /* Tiny Gecko Family supports only "low" segment registers */
272   EFM_ASSERT(bit < 32);
273 #endif
274 
275   /* Use bitband access for atomic bit set/clear of segment */
276   switch (com)
277   {
278   case 0:
279     if (bit < 32)
280     {
281       BITBAND_Peripheral(&(LCD->SEGD0L), bit, (unsigned int)enable);
282     }
283 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
284     else
285     {
286       bit -= 32;
287       BITBAND_Peripheral(&(LCD->SEGD0H), bit, (unsigned int)enable);
288     }
289 #endif
290     break;
291   case 1:
292     if (bit < 32)
293     {
294       BITBAND_Peripheral(&(LCD->SEGD1L), bit, (unsigned int)enable);
295     }
296 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
297     else
298     {
299       bit -= 32;
300       BITBAND_Peripheral(&(LCD->SEGD1H), bit, (unsigned int)enable);
301     }
302 #endif
303     break;
304   case 2:
305     if (bit < 32)
306     {
307       BITBAND_Peripheral(&(LCD->SEGD2L), bit, (unsigned int)enable);
308     }
309 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
310     else
311     {
312       bit -= 32;
313       BITBAND_Peripheral(&(LCD->SEGD2H), bit, (unsigned int)enable);
314     }
315 #endif
316     break;
317   case 3:
318     if (bit < 32)
319     {
320       BITBAND_Peripheral(&(LCD->SEGD3L), bit, (unsigned int)enable);
321     }
322 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
323     else
324     {
325       bit -= 32;
326       BITBAND_Peripheral(&(LCD->SEGD3H), bit, (unsigned int)enable);
327     }
328 #endif
329     break;
330   case 4:
331 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
332     if (bit < 32)
333     {
334       BITBAND_Peripheral(&(LCD->SEGD4L), bit, (unsigned int)enable);
335     }
336 #endif
337 #if defined(_EFM32_GIANT_FAMILY)
338     else
339     {
340       bit -= 32;
341       BITBAND_Peripheral(&(LCD->SEGD4H), bit, (unsigned int)enable);
342     }
343 #endif
344     break;
345   case 5:
346 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
347     if (bit < 32)
348     {
349       BITBAND_Peripheral(&(LCD->SEGD5L), bit, (unsigned int)enable);
350     }
351 #endif
352 #if defined(_EFM32_GIANT_FAMILY)
353     else
354     {
355       bit -= 32;
356       BITBAND_Peripheral(&(LCD->SEGD5H), bit, (unsigned int)enable);
357     }
358 #endif
359     break;
360   case 6:
361 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
362     if (bit < 32)
363     {
364       BITBAND_Peripheral(&(LCD->SEGD6L), bit, (unsigned int)enable);
365     }
366 #endif
367 #if defined(_EFM32_GIANT_FAMILY)
368     else
369     {
370       bit -= 32;
371       BITBAND_Peripheral(&(LCD->SEGD6H), bit, (unsigned int)enable);
372     }
373 #endif
374     break;
375   case 7:
376 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
377     if (bit < 32)
378     {
379       BITBAND_Peripheral(&(LCD->SEGD7L), bit, (unsigned int)enable);
380     }
381 #endif
382 #if defined(_EFM32_GIANT_FAMILY)
383     else
384     {
385       bit -= 32;
386       BITBAND_Peripheral(&(LCD->SEGD7H), bit, (unsigned int)enable);
387     }
388 #endif
389     break;
390 
391   default:
392     EFM_ASSERT(0);
393     break;
394   }
395 }
396 
397 
398 /***************************************************************************//**
399  * @brief
400  *   Updates the 0-31 lowest segments on a given COM-line in one operation,
401  *   according to bit mask
402  *
403  * @param[in] com
404  *   Which COM line to update
405  *
406  * @param[in] mask
407  *   Bit mask for segments 0-31
408  *
409  * @param[in] bits
410  *   Bit pattern for segments 0-31
411  ******************************************************************************/
LCD_SegmentSetLow(int com,uint32_t mask,uint32_t bits)412 void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
413 {
414   uint32_t segData;
415 
416   /* Maximum number of com lines */
417 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
418   EFM_ASSERT(com < 8);
419 #else
420   /* Gecko Family supports up to 4 COM lines */
421   EFM_ASSERT(com < 4);
422 #endif
423 
424   switch (com)
425   {
426   case 0:
427     segData     = LCD->SEGD0L;
428     segData    &= ~(mask);
429     segData    |= (mask & bits);
430     LCD->SEGD0L = segData;
431     break;
432   case 1:
433     segData     = LCD->SEGD1L;
434     segData    &= ~(mask);
435     segData    |= (mask & bits);
436     LCD->SEGD1L = segData;
437     break;
438   case 2:
439     segData     = LCD->SEGD2L;
440     segData    &= ~(mask);
441     segData    |= (mask & bits);
442     LCD->SEGD2L = segData;
443     break;
444   case 3:
445     segData     = LCD->SEGD3L;
446     segData    &= ~(mask);
447     segData    |= (mask & bits);
448     LCD->SEGD3L = segData;
449     break;
450 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
451   case 4:
452     segData     = LCD->SEGD4L;
453     segData    &= ~(mask);
454     segData    |= (mask & bits);
455     LCD->SEGD4L = segData;
456     break;
457 #endif
458 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
459   case 5:
460     segData     = LCD->SEGD5L;
461     segData    &= ~(mask);
462     segData    |= (mask & bits);
463     LCD->SEGD5L = segData;
464     break;
465 #endif
466 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
467   case 6:
468     segData     = LCD->SEGD6L;
469     segData    &= ~(mask);
470     segData    |= (mask & bits);
471     LCD->SEGD6L = segData;
472     break;
473 #endif
474 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
475   case 7:
476     segData     = LCD->SEGD7L;
477     segData    &= ~(mask);
478     segData    |= (mask & bits);
479     LCD->SEGD7L = segData;
480     break;
481 #endif
482   default:
483     EFM_ASSERT(0);
484     break;
485   }
486 }
487 
488 
489 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY)
490 /***************************************************************************//**
491  * @brief
492  *   Updated the high (32-39) segments on a given COM-line in one operation
493  *
494  * @param[in] com
495  *   Which COM line to update
496  *
497  * @param[in] mask
498  *   Bit mask for segments 32-39
499  *
500  * @param[in] bits
501  *   Bit pattern for segments 32-39
502  ******************************************************************************/
LCD_SegmentSetHigh(int com,uint32_t mask,uint32_t bits)503 void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
504 {
505   uint32_t segData;
506 
507 #if defined(_EFM32_GIANT_FAMILY)
508   EFM_ASSERT(com < 8);
509 #endif
510 #if defined(_EFM32_GECKO_FAMILY)
511   EFM_ASSERT(com < 4);
512 #endif
513 
514   /* Maximum number of com lines */
515   switch (com)
516   {
517   case 0:
518     segData     = LCD->SEGD0H;
519     segData    &= ~(mask);
520     segData    |= (mask & bits);
521     LCD->SEGD0H = segData;
522     break;
523   case 1:
524     segData     = LCD->SEGD1H;
525     segData    &= ~(mask);
526     segData    |= (mask & bits);
527     LCD->SEGD1H = segData;
528     break;
529   case 2:
530     segData     = LCD->SEGD2H;
531     segData    &= ~(mask);
532     segData    |= (mask & bits);
533     LCD->SEGD2H = segData;
534     break;
535   case 3:
536     segData     = LCD->SEGD3H;
537     segData    &= ~(mask);
538     segData    |= (mask & bits);
539     LCD->SEGD3H = segData;
540     break;
541 #if defined(_EFM32_GIANT_FAMILY)
542   case 4:
543     segData     = LCD->SEGD4H;
544     segData    &= ~(mask);
545     segData    |= (mask & bits);
546     LCD->SEGD4H = segData;
547     break;
548 #endif
549 #if defined(_EFM32_GIANT_FAMILY)
550   case 5:
551     segData     = LCD->SEGD5H;
552     segData    &= ~(mask);
553     segData    |= (mask & bits);
554     LCD->SEGD5H = segData;
555     break;
556 #endif
557 #if defined(_EFM32_GIANT_FAMILY)
558   case 6:
559     segData     = LCD->SEGD6H;
560     segData    &= ~(mask);
561     segData    |= (mask & bits);
562     LCD->SEGD6H = segData;
563     break;
564 #endif
565 #if defined(_EFM32_GIANT_FAMILY)
566   case 7:
567     segData     = LCD->SEGD7H;
568     segData    &= ~(mask);
569     segData    |= (mask & bits);
570     LCD->SEGD7H = segData;
571     break;
572 #endif
573   default:
574     break;
575   }
576 }
577 #endif
578 
579 /***************************************************************************//**
580  * @brief
581  *   Configure contrast level on LCD panel
582  *
583  * @param[in] level
584  *   Contrast level in the range 0-31
585  ******************************************************************************/
LCD_ContrastSet(int level)586 void LCD_ContrastSet(int level)
587 {
588   EFM_ASSERT(level < 32);
589 
590   LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONLEV_MASK)
591                   | (level << _LCD_DISPCTRL_CONLEV_SHIFT);
592 }
593 
594 
595 /***************************************************************************//**
596  * @brief
597  *   Configure voltage booster
598  *
599  * The resulting voltage level is described in each part number's data sheet
600  *
601  * @param[in] vboost
602  *   Voltage boost level
603  ******************************************************************************/
LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)604 void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)
605 {
606   /* Reconfigure Voltage Boost */
607   LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_VBLEV_MASK) | vboost;
608 }
609 
610 
611 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
612 /***************************************************************************//**
613  * @brief
614  *   Configure bias level for a specific segment line for Direct Segment Control
615  *
616  * @note
617  *   When DSC is active, each configuration takes up 4 bits in the Segment
618  *   Registers (SEGD0L/SEGD1H) which defines bias level.
619  *   For optimal use of this feature, the entire SEGD-registers should be set
620  *   at once in a optimized routine, so this function is mainly here to
621  *   demonstrate how to correctly configure the bias levels, and should be used
622  *   with care.
623  *
624  * @param[in] segmentLine
625  *   Segment line number
626  *
627  * @param[in] biasLevel
628  *   Bias configuration level, 0-4. This value must be within the constraint
629  *   defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
630  ******************************************************************************/
LCD_BiasSegmentSet(int segmentLine,int biasLevel)631 void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
632 {
633   int               biasRegister;
634   int               bitShift;
635   volatile uint32_t *segmentRegister;
636 
637 #if defined(_EFM32_TINY_FAMILY)
638   EFM_ASSERT(segmentLine < 20);
639 #endif
640 #if defined(_EFM32_GIANT_FAMILY)
641   EFM_ASSERT(segmentLine < 40);
642 #endif
643 #if defined(_EFM32_TINY_FAMILY)
644   /* Bias config for 8 segment lines per SEGDnL register */
645   biasRegister = segmentLine / 8;
646   bitShift     = (segmentLine % 8) * 4;
647 
648   switch (biasRegister)
649   {
650   case 0:
651     segmentRegister = &LCD->SEGD0L;
652     break;
653   case 1:
654     segmentRegister = &LCD->SEGD1L;
655     break;
656   case 2:
657     segmentRegister = &LCD->SEGD2L;
658     break;
659   case 3:
660     segmentRegister = &LCD->SEGD3L;
661     break;
662   default:
663     segmentRegister = (uint32_t *)0x00000000;
664     EFM_ASSERT(0);
665     break;
666   }
667 #endif
668 #if defined(_EFM32_GIANT_FAMILY)
669   /* Bias config for 10 segment lines per SEGDn L+H registers */
670   biasRegister = segmentLine / 10;
671   bitShift     = (segmentLine % 10) * 4;
672 
673   switch (biasRegister)
674   {
675   case 0:
676     if (bitShift < 32)
677     {
678       segmentRegister = &LCD->SEGD0L;
679     }
680     else
681     {
682       segmentRegister = &LCD->SEGD0H;
683       bitShift       -= 32;
684     }
685     break;
686   case 1:
687     if (bitShift < 32)
688     {
689       segmentRegister = &LCD->SEGD1L;
690     }
691     else
692     {
693       segmentRegister = &LCD->SEGD1H;
694       bitShift       -= 32;
695     }
696     break;
697   case 2:
698     if (bitShift < 32)
699     {
700       segmentRegister = &LCD->SEGD2L;
701     }
702     else
703     {
704       segmentRegister = &LCD->SEGD1H;
705       bitShift       -= 32;
706     }
707     break;
708   case 3:
709     if (bitShift < 32)
710     {
711       segmentRegister = &LCD->SEGD3L;
712     }
713     else
714     {
715       segmentRegister = &LCD->SEGD3H;
716       bitShift       -= 32;
717     }
718     break;
719   default:
720     segmentRegister = (uint32_t *)0x00000000;
721     EFM_ASSERT(0);
722     break;
723   }
724 #endif
725 
726   /* Configure new bias setting */
727   *segmentRegister = (*segmentRegister & ~(0xF << bitShift)) | (biasLevel << bitShift);
728 }
729 
730 
731 /***************************************************************************//**
732  * @brief
733  *   Configure bias level for a specific segment line
734  *
735  * @note
736  *   When DSC is active, each configuration takes up 4 bits in the Segment
737  *   Registers (SEGD4L/SEGD4H) which defines bias level.
738  *   For optimal use of this feature, the entire SEGD-registers should be set
739  *   at once in a optimized routine, so this function is mainly here to
740  *   demonstrate how to correctly configure the bias levels, and should be used
741  *   with care.
742  *
743  * @param[in] comLine
744  *   COM line number, 0-7
745  *
746  * @param[in] biasLevel
747  *   Bias configuration level, 0-4. This value must be within the constraint
748  *   defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
749  ******************************************************************************/
LCD_BiasComSet(int comLine,int biasLevel)750 void LCD_BiasComSet(int comLine, int biasLevel)
751 {
752   int bitShift;
753   EFM_ASSERT(comLine < 8);
754 
755   bitShift    = comLine * 4;
756   LCD->SEGD4L = (LCD->SEGD4L & ~(0xF << bitShift)) | (biasLevel << bitShift);
757 }
758 #endif
759 
760 /** @} (end addtogroup LCD) */
761 /** @} (end addtogroup EM_Library) */
762 
763 #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */
764