1 /***************************************************************************//**
\r
3 * @brief Liquid Crystal Display (LCD) Peripheral API
\r
5 *******************************************************************************
\r
7 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
\r
8 *******************************************************************************
\r
10 * Permission is granted to anyone to use this software for any purpose,
\r
11 * including commercial applications, and to alter it and redistribute it
\r
12 * freely, subject to the following restrictions:
\r
14 * 1. The origin of this software must not be misrepresented; you must not
\r
15 * claim that you wrote the original software.
\r
16 * 2. Altered source versions must be plainly marked as such, and must not be
\r
17 * misrepresented as being the original software.
\r
18 * 3. This notice may not be removed or altered from any source distribution.
\r
20 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
\r
21 * obligation to support this Software. Silicon Labs is providing the
\r
22 * Software "AS IS", with no express or implied warranties of any kind,
\r
23 * including, but not limited to, any implied warranties of merchantability
\r
24 * or fitness for any particular purpose or warranties against infringement
\r
25 * of any proprietary rights of a third party.
\r
27 * Silicon Labs will not be liable for any consequential, incidental, or
\r
28 * special damages, or any other relief, or for any claim by any third party,
\r
29 * arising from your use of this Software.
\r
31 ******************************************************************************/
\r
35 #if defined(LCD_COUNT) && (LCD_COUNT > 0)
\r
36 #include "em_assert.h"
\r
37 #include "em_bitband.h"
\r
39 /***************************************************************************//**
\r
40 * @addtogroup EM_Library
\r
42 ******************************************************************************/
\r
44 /***************************************************************************//**
\r
46 * @brief Liquid Crystal Display (LCD) Peripheral API
\r
48 ******************************************************************************/
\r
50 /***************************************************************************//**
\r
52 * Initalize Liquid Crystal Display (LCD) controller
\r
55 * This function call will only configure the LCD controller. You must enable
\r
56 * it afterwards, potentially configuring Frame Control and interrupts first
\r
57 * according to requirements.
\r
59 * @param[in] lcdInit
\r
60 * Pointer to initialization structure which configures LCD controller.
\r
62 ******************************************************************************/
\r
63 void LCD_Init(const LCD_Init_TypeDef *lcdInit)
\r
65 uint32_t dispCtrl = LCD->DISPCTRL;
\r
67 EFM_ASSERT(lcdInit != (void *) 0);
\r
69 /* Disable controller before reconfiguration */
\r
72 /* Make sure we don't touch other bit fields (i.e. voltage boost) */
\r
74 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
75 _LCD_DISPCTRL_MUXE_MASK |
\r
77 _LCD_DISPCTRL_MUX_MASK |
\r
78 _LCD_DISPCTRL_BIAS_MASK |
\r
79 _LCD_DISPCTRL_WAVE_MASK |
\r
80 _LCD_DISPCTRL_VLCDSEL_MASK |
\r
81 _LCD_DISPCTRL_CONCONF_MASK);
\r
83 /* Configure controller according to initialization structure */
\r
84 dispCtrl |= lcdInit->mux; /* also configures MUXE */
\r
85 dispCtrl |= lcdInit->bias;
\r
86 dispCtrl |= lcdInit->wave;
\r
87 dispCtrl |= lcdInit->vlcd;
\r
88 dispCtrl |= lcdInit->contrast;
\r
90 /* Update display controller */
\r
91 LCD->DISPCTRL = dispCtrl;
\r
93 /* Enable controller if wanted */
\r
94 if (lcdInit->enable)
\r
101 /***************************************************************************//**
\r
103 * Select source for VLCD
\r
106 * Select source for VLD voltage
\r
107 ******************************************************************************/
\r
108 void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)
\r
110 uint32_t dispctrl = LCD->DISPCTRL;
\r
112 /* Select VEXT or VDD */
\r
113 dispctrl &= ~(_LCD_DISPCTRL_VLCDSEL_MASK);
\r
116 case lcdVLCDSelVExtBoost:
\r
117 dispctrl |= LCD_DISPCTRL_VLCDSEL_VEXTBOOST;
\r
119 case lcdVLCDSelVDD:
\r
120 dispctrl |= LCD_DISPCTRL_VLCDSEL_VDD;
\r
126 LCD->DISPCTRL = dispctrl;
\r
130 /***************************************************************************//**
\r
132 * Configure Update Control
\r
135 * Configures LCD update method
\r
136 ******************************************************************************/
\r
137 void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)
\r
139 LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
\r
143 /***************************************************************************//**
\r
145 * Initialize LCD Frame Counter
\r
147 * @param[in] fcInit
\r
148 * Pointer to Frame Counter initialization structure
\r
149 ******************************************************************************/
\r
150 void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit)
\r
152 uint32_t bactrl = LCD->BACTRL;
\r
154 EFM_ASSERT(fcInit != (void *) 0);
\r
156 /* Verify FC Top Counter to be within limits */
\r
157 EFM_ASSERT(fcInit->top < 64);
\r
159 /* Reconfigure frame count configuration */
\r
160 bactrl &= ~(_LCD_BACTRL_FCTOP_MASK |
\r
161 _LCD_BACTRL_FCPRESC_MASK);
\r
162 bactrl |= (fcInit->top << _LCD_BACTRL_FCTOP_SHIFT);
\r
163 bactrl |= fcInit->prescale;
\r
165 /* Set Blink and Animation Control Register */
\r
166 LCD->BACTRL = bactrl;
\r
168 LCD_FrameCountEnable(fcInit->enable);
\r
172 /***************************************************************************//**
\r
174 * Configures LCD controller Animation feature
\r
176 * @param[in] animInit
\r
177 * Pointer to LCD Animation initialization structure
\r
178 ******************************************************************************/
\r
179 void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit)
\r
181 uint32_t bactrl = LCD->BACTRL;
\r
183 EFM_ASSERT(animInit != (void *) 0);
\r
185 /* Set Animation Register Values */
\r
186 LCD->AREGA = animInit->AReg;
\r
187 LCD->AREGB = animInit->BReg;
\r
189 /* Configure Animation Shift and Logic */
\r
190 bactrl &= ~(_LCD_BACTRL_AREGASC_MASK |
\r
191 _LCD_BACTRL_AREGBSC_MASK |
\r
192 _LCD_BACTRL_ALOGSEL_MASK);
\r
194 bactrl |= (animInit->AShift << _LCD_BACTRL_AREGASC_SHIFT);
\r
195 bactrl |= (animInit->BShift << _LCD_BACTRL_AREGBSC_SHIFT);
\r
196 bactrl |= animInit->animLogic;
\r
198 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
199 bactrl &= ~(_LCD_BACTRL_ALOC_MASK);
\r
201 if(animInit->startSeg == 0)
\r
203 bactrl |= LCD_BACTRL_ALOC_SEG0TO7;
\r
205 else if(animInit->startSeg == 8)
\r
207 bactrl |= LCD_BACTRL_ALOC_SEG8TO15;
\r
212 LCD->BACTRL = bactrl;
\r
215 LCD_AnimEnable(animInit->enable);
\r
219 /***************************************************************************//**
\r
221 * Enables update of this range of LCD segment lines
\r
223 * @param[in] segmentRange
\r
224 * Range of 4 LCD segments lines to enable or disable, for all enabled COM
\r
227 * @param[in] enable
\r
228 * Bool true to enable segment updates, false to disable updates
\r
229 ******************************************************************************/
\r
230 void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange, bool enable)
\r
234 LCD->SEGEN |= segmentRange;
\r
238 LCD->SEGEN &= ~((uint32_t)segmentRange);
\r
243 /***************************************************************************//**
\r
245 * Turn on or clear a segment
\r
248 * On Gecko Family, max configuration is (COM-lines x Segment-Lines) 4x40
\r
249 * On Tiny Family, max configuration is 8x20 or 4x24
\r
250 * On Giant Family, max configuration is 8x36 or 4x40
\r
253 * COM line to change
\r
256 * Bit index of which field to change
\r
258 * @param[in] enable
\r
259 * When true will set segment, when false will clear segment
\r
260 ******************************************************************************/
\r
261 void LCD_SegmentSet(int com, int bit, bool enable)
\r
263 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
264 /* Tiny and Giant Family supports up to 8 COM lines */
\r
265 EFM_ASSERT(com < 8);
\r
267 /* Gecko Family supports up to 4 COM lines */
\r
268 EFM_ASSERT(com < 4);
\r
271 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
272 EFM_ASSERT(bit < 40);
\r
274 /* Tiny Gecko Family supports only "low" segment registers */
\r
275 EFM_ASSERT(bit < 32);
\r
278 /* Use bitband access for atomic bit set/clear of segment */
\r
284 BITBAND_Peripheral(&(LCD->SEGD0L), bit, (unsigned int)enable);
\r
286 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
290 BITBAND_Peripheral(&(LCD->SEGD0H), bit, (unsigned int)enable);
\r
297 BITBAND_Peripheral(&(LCD->SEGD1L), bit, (unsigned int)enable);
\r
299 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
303 BITBAND_Peripheral(&(LCD->SEGD1H), bit, (unsigned int)enable);
\r
310 BITBAND_Peripheral(&(LCD->SEGD2L), bit, (unsigned int)enable);
\r
312 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
316 BITBAND_Peripheral(&(LCD->SEGD2H), bit, (unsigned int)enable);
\r
323 BITBAND_Peripheral(&(LCD->SEGD3L), bit, (unsigned int)enable);
\r
325 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
329 BITBAND_Peripheral(&(LCD->SEGD3H), bit, (unsigned int)enable);
\r
334 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
337 BITBAND_Peripheral(&(LCD->SEGD4L), bit, (unsigned int)enable);
\r
340 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
344 BITBAND_Peripheral(&(LCD->SEGD4H), bit, (unsigned int)enable);
\r
349 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
352 BITBAND_Peripheral(&(LCD->SEGD5L), bit, (unsigned int)enable);
\r
355 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
359 BITBAND_Peripheral(&(LCD->SEGD5H), bit, (unsigned int)enable);
\r
364 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
367 BITBAND_Peripheral(&(LCD->SEGD6L), bit, (unsigned int)enable);
\r
370 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
374 BITBAND_Peripheral(&(LCD->SEGD6H), bit, (unsigned int)enable);
\r
379 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
382 BITBAND_Peripheral(&(LCD->SEGD7L), bit, (unsigned int)enable);
\r
385 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
389 BITBAND_Peripheral(&(LCD->SEGD7H), bit, (unsigned int)enable);
\r
401 /***************************************************************************//**
\r
403 * Updates the 0-31 lowest segments on a given COM-line in one operation,
\r
404 * according to bit mask
\r
407 * Which COM line to update
\r
410 * Bit mask for segments 0-31
\r
413 * Bit pattern for segments 0-31
\r
414 ******************************************************************************/
\r
415 void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
\r
419 /* Maximum number of com lines */
\r
420 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
421 EFM_ASSERT(com < 8);
\r
423 /* Gecko Family supports up to 4 COM lines */
\r
424 EFM_ASSERT(com < 4);
\r
430 segData = LCD->SEGD0L;
\r
431 segData &= ~(mask);
\r
432 segData |= (mask & bits);
\r
433 LCD->SEGD0L = segData;
\r
436 segData = LCD->SEGD1L;
\r
437 segData &= ~(mask);
\r
438 segData |= (mask & bits);
\r
439 LCD->SEGD1L = segData;
\r
442 segData = LCD->SEGD2L;
\r
443 segData &= ~(mask);
\r
444 segData |= (mask & bits);
\r
445 LCD->SEGD2L = segData;
\r
448 segData = LCD->SEGD3L;
\r
449 segData &= ~(mask);
\r
450 segData |= (mask & bits);
\r
451 LCD->SEGD3L = segData;
\r
453 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
455 segData = LCD->SEGD4L;
\r
456 segData &= ~(mask);
\r
457 segData |= (mask & bits);
\r
458 LCD->SEGD4L = segData;
\r
461 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
463 segData = LCD->SEGD5L;
\r
464 segData &= ~(mask);
\r
465 segData |= (mask & bits);
\r
466 LCD->SEGD5L = segData;
\r
469 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
471 segData = LCD->SEGD6L;
\r
472 segData &= ~(mask);
\r
473 segData |= (mask & bits);
\r
474 LCD->SEGD6L = segData;
\r
477 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
479 segData = LCD->SEGD7L;
\r
480 segData &= ~(mask);
\r
481 segData |= (mask & bits);
\r
482 LCD->SEGD7L = segData;
\r
492 #if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
493 /***************************************************************************//**
\r
495 * Updated the high (32-39) segments on a given COM-line in one operation
\r
498 * Which COM line to update
\r
501 * Bit mask for segments 32-39
\r
504 * Bit pattern for segments 32-39
\r
505 ******************************************************************************/
\r
506 void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
\r
510 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
511 EFM_ASSERT(com < 8);
\r
513 #if defined(_EFM32_GECKO_FAMILY)
\r
514 EFM_ASSERT(com < 4);
\r
517 /* Maximum number of com lines */
\r
521 segData = LCD->SEGD0H;
\r
522 segData &= ~(mask);
\r
523 segData |= (mask & bits);
\r
524 LCD->SEGD0H = segData;
\r
527 segData = LCD->SEGD1H;
\r
528 segData &= ~(mask);
\r
529 segData |= (mask & bits);
\r
530 LCD->SEGD1H = segData;
\r
533 segData = LCD->SEGD2H;
\r
534 segData &= ~(mask);
\r
535 segData |= (mask & bits);
\r
536 LCD->SEGD2H = segData;
\r
539 segData = LCD->SEGD3H;
\r
540 segData &= ~(mask);
\r
541 segData |= (mask & bits);
\r
542 LCD->SEGD3H = segData;
\r
544 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
546 segData = LCD->SEGD4H;
\r
547 segData &= ~(mask);
\r
548 segData |= (mask & bits);
\r
549 LCD->SEGD4H = segData;
\r
552 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
554 segData = LCD->SEGD5H;
\r
555 segData &= ~(mask);
\r
556 segData |= (mask & bits);
\r
557 LCD->SEGD5H = segData;
\r
560 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
562 segData = LCD->SEGD6H;
\r
563 segData &= ~(mask);
\r
564 segData |= (mask & bits);
\r
565 LCD->SEGD6H = segData;
\r
568 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
570 segData = LCD->SEGD7H;
\r
571 segData &= ~(mask);
\r
572 segData |= (mask & bits);
\r
573 LCD->SEGD7H = segData;
\r
582 /***************************************************************************//**
\r
584 * Configure contrast level on LCD panel
\r
587 * Contrast level in the range 0-31
\r
588 ******************************************************************************/
\r
589 void LCD_ContrastSet(int level)
\r
591 EFM_ASSERT(level < 32);
\r
593 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONLEV_MASK)
\r
594 | (level << _LCD_DISPCTRL_CONLEV_SHIFT);
\r
598 /***************************************************************************//**
\r
600 * Configure voltage booster
\r
602 * The resulting voltage level is described in each part number's data sheet
\r
604 * @param[in] vboost
\r
605 * Voltage boost level
\r
606 ******************************************************************************/
\r
607 void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)
\r
609 /* Reconfigure Voltage Boost */
\r
610 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_VBLEV_MASK) | vboost;
\r
614 #if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
615 /***************************************************************************//**
\r
617 * Configure bias level for a specific segment line for Direct Segment Control
\r
620 * When DSC is active, each configuration takes up 4 bits in the Segment
\r
621 * Registers (SEGD0L/SEGD1H) which defines bias level.
\r
622 * For optimal use of this feature, the entire SEGD-registers should be set
\r
623 * at once in a optimized routine, so this function is mainly here to
\r
624 * demonstrate how to correctly configure the bias levels, and should be used
\r
627 * @param[in] segmentLine
\r
628 * Segment line number
\r
630 * @param[in] biasLevel
\r
631 * Bias configuration level, 0-4. This value must be within the constraint
\r
632 * defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
\r
633 ******************************************************************************/
\r
634 void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
\r
638 volatile uint32_t *segmentRegister;
\r
640 #if defined(_EFM32_TINY_FAMILY)
\r
641 EFM_ASSERT(segmentLine < 20);
\r
643 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
644 EFM_ASSERT(segmentLine < 40);
\r
646 #if defined(_EFM32_TINY_FAMILY)
\r
647 /* Bias config for 8 segment lines per SEGDnL register */
\r
648 biasRegister = segmentLine / 8;
\r
649 bitShift = (segmentLine % 8) * 4;
\r
651 switch (biasRegister)
\r
654 segmentRegister = &LCD->SEGD0L;
\r
657 segmentRegister = &LCD->SEGD1L;
\r
660 segmentRegister = &LCD->SEGD2L;
\r
663 segmentRegister = &LCD->SEGD3L;
\r
666 segmentRegister = (uint32_t *)0x00000000;
\r
671 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
\r
672 /* Bias config for 10 segment lines per SEGDn L+H registers */
\r
673 biasRegister = segmentLine / 10;
\r
674 bitShift = (segmentLine % 10) * 4;
\r
676 switch (biasRegister)
\r
681 segmentRegister = &LCD->SEGD0L;
\r
685 segmentRegister = &LCD->SEGD0H;
\r
692 segmentRegister = &LCD->SEGD1L;
\r
696 segmentRegister = &LCD->SEGD1H;
\r
703 segmentRegister = &LCD->SEGD2L;
\r
707 segmentRegister = &LCD->SEGD1H;
\r
714 segmentRegister = &LCD->SEGD3L;
\r
718 segmentRegister = &LCD->SEGD3H;
\r
723 segmentRegister = (uint32_t *)0x00000000;
\r
729 /* Configure new bias setting */
\r
730 *segmentRegister = (*segmentRegister & ~(0xF << bitShift)) | (biasLevel << bitShift);
\r
734 /***************************************************************************//**
\r
736 * Configure bias level for a specific segment line
\r
739 * When DSC is active, each configuration takes up 4 bits in the Segment
\r
740 * Registers (SEGD4L/SEGD4H) which defines bias level.
\r
741 * For optimal use of this feature, the entire SEGD-registers should be set
\r
742 * at once in a optimized routine, so this function is mainly here to
\r
743 * demonstrate how to correctly configure the bias levels, and should be used
\r
746 * @param[in] comLine
\r
747 * COM line number, 0-7
\r
749 * @param[in] biasLevel
\r
750 * Bias configuration level, 0-4. This value must be within the constraint
\r
751 * defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
\r
752 ******************************************************************************/
\r
753 void LCD_BiasComSet(int comLine, int biasLevel)
\r
756 EFM_ASSERT(comLine < 8);
\r
758 bitShift = comLine * 4;
\r
759 LCD->SEGD4L = (LCD->SEGD4L & ~(0xF << bitShift)) | (biasLevel << bitShift);
\r
763 /** @} (end addtogroup LCD) */
\r
764 /** @} (end addtogroup EM_Library) */
\r
766 #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */
\r