1 /***************************************************************************//**
\r
3 * @brief Liquid Crystal Display (LCD) Peripheral API
\r
5 *******************************************************************************
\r
7 * <b>(C) Copyright 2015 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
34 #if defined(LCD_COUNT) && (LCD_COUNT > 0)
\r
35 #include "em_assert.h"
\r
38 /***************************************************************************//**
\r
39 * @addtogroup EM_Library
\r
41 ******************************************************************************/
\r
43 /***************************************************************************//**
\r
45 * @brief Liquid Crystal Display (LCD) Peripheral API
\r
47 ******************************************************************************/
\r
49 /***************************************************************************//**
\r
51 * Initalize Liquid Crystal Display (LCD) controller
\r
54 * This function call will only configure the LCD controller. You must enable
\r
55 * it afterwards, potentially configuring Frame Control and interrupts first
\r
56 * according to requirements.
\r
58 * @param[in] lcdInit
\r
59 * Pointer to initialization structure which configures LCD controller.
\r
61 ******************************************************************************/
\r
62 void LCD_Init(const LCD_Init_TypeDef *lcdInit)
\r
64 uint32_t dispCtrl = LCD->DISPCTRL;
\r
66 EFM_ASSERT(lcdInit != (void *) 0);
\r
68 /* Disable controller before reconfiguration */
\r
71 /* Make sure we don't touch other bit fields (i.e. voltage boost) */
\r
73 #if defined(LCD_DISPCTRL_MUXE)
\r
74 | _LCD_DISPCTRL_MUXE_MASK
\r
76 | _LCD_DISPCTRL_MUX_MASK
\r
77 | _LCD_DISPCTRL_BIAS_MASK
\r
78 | _LCD_DISPCTRL_WAVE_MASK
\r
79 | _LCD_DISPCTRL_VLCDSEL_MASK
\r
80 | _LCD_DISPCTRL_CONCONF_MASK);
\r
82 /* Configure controller according to initialization structure */
\r
83 dispCtrl |= lcdInit->mux; /* also configures MUXE */
\r
84 dispCtrl |= lcdInit->bias;
\r
85 dispCtrl |= lcdInit->wave;
\r
86 dispCtrl |= lcdInit->vlcd;
\r
87 dispCtrl |= lcdInit->contrast;
\r
89 /* Update display controller */
\r
90 LCD->DISPCTRL = dispCtrl;
\r
92 /* Enable controller if wanted */
\r
93 if (lcdInit->enable)
\r
100 /***************************************************************************//**
\r
102 * Select source for VLCD
\r
105 * Select source for VLD voltage
\r
106 ******************************************************************************/
\r
107 void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)
\r
109 uint32_t dispctrl = LCD->DISPCTRL;
\r
111 /* Select VEXT or VDD */
\r
112 dispctrl &= ~_LCD_DISPCTRL_VLCDSEL_MASK;
\r
115 case lcdVLCDSelVExtBoost:
\r
116 dispctrl |= LCD_DISPCTRL_VLCDSEL_VEXTBOOST;
\r
118 case lcdVLCDSelVDD:
\r
119 dispctrl |= LCD_DISPCTRL_VLCDSEL_VDD;
\r
125 LCD->DISPCTRL = dispctrl;
\r
129 /***************************************************************************//**
\r
131 * Configure Update Control
\r
134 * Configures LCD update method
\r
135 ******************************************************************************/
\r
136 void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)
\r
138 LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
\r
142 /***************************************************************************//**
\r
144 * Initialize LCD Frame Counter
\r
146 * @param[in] fcInit
\r
147 * Pointer to Frame Counter initialization structure
\r
148 ******************************************************************************/
\r
149 void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit)
\r
151 uint32_t bactrl = LCD->BACTRL;
\r
153 EFM_ASSERT(fcInit != (void *) 0);
\r
155 /* Verify FC Top Counter to be within limits */
\r
156 EFM_ASSERT(fcInit->top < 64);
\r
158 /* Reconfigure frame count configuration */
\r
159 bactrl &= ~(_LCD_BACTRL_FCTOP_MASK
\r
160 | _LCD_BACTRL_FCPRESC_MASK);
\r
161 bactrl |= (fcInit->top << _LCD_BACTRL_FCTOP_SHIFT);
\r
162 bactrl |= fcInit->prescale;
\r
164 /* Set Blink and Animation Control Register */
\r
165 LCD->BACTRL = bactrl;
\r
167 LCD_FrameCountEnable(fcInit->enable);
\r
171 /***************************************************************************//**
\r
173 * Configures LCD controller Animation feature
\r
175 * @param[in] animInit
\r
176 * Pointer to LCD Animation initialization structure
\r
177 ******************************************************************************/
\r
178 void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit)
\r
180 uint32_t bactrl = LCD->BACTRL;
\r
182 EFM_ASSERT(animInit != (void *) 0);
\r
184 /* Set Animation Register Values */
\r
185 LCD->AREGA = animInit->AReg;
\r
186 LCD->AREGB = animInit->BReg;
\r
188 /* Configure Animation Shift and Logic */
\r
189 bactrl &= ~(_LCD_BACTRL_AREGASC_MASK
\r
190 | _LCD_BACTRL_AREGBSC_MASK
\r
191 | _LCD_BACTRL_ALOGSEL_MASK);
\r
193 bactrl |= (animInit->AShift << _LCD_BACTRL_AREGASC_SHIFT);
\r
194 bactrl |= (animInit->BShift << _LCD_BACTRL_AREGBSC_SHIFT);
\r
195 bactrl |= animInit->animLogic;
\r
197 #if defined(LCD_BACTRL_ALOC)
\r
198 bactrl &= ~(_LCD_BACTRL_ALOC_MASK);
\r
200 if(animInit->startSeg == 0)
\r
202 bactrl |= LCD_BACTRL_ALOC_SEG0TO7;
\r
204 else if(animInit->startSeg == 8)
\r
206 bactrl |= LCD_BACTRL_ALOC_SEG8TO15;
\r
211 LCD->BACTRL = bactrl;
\r
214 LCD_AnimEnable(animInit->enable);
\r
218 /***************************************************************************//**
\r
220 * Enables update of this range of LCD segment lines
\r
222 * @param[in] segmentRange
\r
223 * Range of 4 LCD segments lines to enable or disable, for all enabled COM
\r
226 * @param[in] enable
\r
227 * Bool true to enable segment updates, false to disable updates
\r
228 ******************************************************************************/
\r
229 void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange, bool enable)
\r
233 LCD->SEGEN |= segmentRange;
\r
237 LCD->SEGEN &= ~((uint32_t)segmentRange);
\r
242 /***************************************************************************//**
\r
244 * Turn on or clear a segment
\r
247 * On Gecko Family, max configuration is (COM-lines x Segment-Lines) 4x40
\r
248 * On Tiny Family, max configuration is 8x20 or 4x24
\r
249 * On Giant Family, max configuration is 8x36 or 4x40
\r
252 * COM line to change
\r
255 * Bit index of which field to change
\r
257 * @param[in] enable
\r
258 * When true will set segment, when false will clear segment
\r
259 ******************************************************************************/
\r
260 void LCD_SegmentSet(int com, int bit, bool enable)
\r
262 #if defined(_LCD_SEGD7L_MASK)
\r
263 /* Tiny and Giant Family supports up to 8 COM lines */
\r
264 EFM_ASSERT(com < 8);
\r
266 /* Gecko Family supports up to 4 COM lines */
\r
267 EFM_ASSERT(com < 4);
\r
270 #if defined(_LCD_SEGD0H_MASK)
\r
271 EFM_ASSERT(bit < 40);
\r
273 /* Tiny Gecko Family supports only "low" segment registers */
\r
274 EFM_ASSERT(bit < 32);
\r
277 /* Use bitband access for atomic bit set/clear of segment */
\r
283 BUS_RegBitWrite(&(LCD->SEGD0L), bit, enable);
\r
285 #if defined(_LCD_SEGD0H_MASK)
\r
289 BUS_RegBitWrite(&(LCD->SEGD0H), bit, enable);
\r
296 BUS_RegBitWrite(&(LCD->SEGD1L), bit, enable);
\r
298 #if defined(_LCD_SEGD1H_MASK)
\r
302 BUS_RegBitWrite(&(LCD->SEGD1H), bit, enable);
\r
309 BUS_RegBitWrite(&(LCD->SEGD2L), bit, enable);
\r
311 #if defined(_LCD_SEGD2H_MASK)
\r
315 BUS_RegBitWrite(&(LCD->SEGD2H), bit, enable);
\r
322 BUS_RegBitWrite(&(LCD->SEGD3L), bit, enable);
\r
324 #if defined(_LCD_SEGD3H_MASK)
\r
328 BUS_RegBitWrite(&(LCD->SEGD3H), bit, enable);
\r
332 #if defined(_LCD_SEGD4L_MASK)
\r
336 BUS_RegBitWrite(&(LCD->SEGD4L), bit, enable);
\r
338 #if defined(_LCD_SEGD4H_MASK)
\r
342 BUS_RegBitWrite(&(LCD->SEGD4H), bit, enable);
\r
347 #if defined(_LCD_SEGD5L_MASK)
\r
351 BUS_RegBitWrite(&(LCD->SEGD5L), bit, enable);
\r
353 #if defined(_LCD_SEGD5H_MASK)
\r
357 BUS_RegBitWrite(&(LCD->SEGD5H), bit, enable);
\r
363 #if defined(_LCD_SEGD6L_MASK)
\r
366 BUS_RegBitWrite(&(LCD->SEGD6L), bit, enable);
\r
368 #if defined(_LCD_SEGD6H_MASK)
\r
372 BUS_RegBitWrite(&(LCD->SEGD6H), bit, enable);
\r
377 #if defined(_LCD_SEGD7L_MASK)
\r
381 BUS_RegBitWrite(&(LCD->SEGD7L), bit, enable);
\r
383 #if defined(_LCD_SEGD7H_MASK)
\r
387 BUS_RegBitWrite(&(LCD->SEGD7H), bit, enable);
\r
400 /***************************************************************************//**
\r
402 * Updates the 0-31 lowest segments on a given COM-line in one operation,
\r
403 * according to bit mask
\r
406 * Which COM line to update
\r
409 * Bit mask for segments 0-31
\r
412 * Bit pattern for segments 0-31
\r
413 ******************************************************************************/
\r
414 void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
\r
418 /* Maximum number of com lines */
\r
419 #if defined(_LCD_SEGD7L_MASK)
\r
420 EFM_ASSERT(com < 8);
\r
422 /* Gecko Family supports up to 4 COM lines */
\r
423 EFM_ASSERT(com < 4);
\r
429 segData = LCD->SEGD0L;
\r
430 segData &= ~(mask);
\r
431 segData |= (mask & bits);
\r
432 LCD->SEGD0L = segData;
\r
435 segData = LCD->SEGD1L;
\r
436 segData &= ~(mask);
\r
437 segData |= (mask & bits);
\r
438 LCD->SEGD1L = segData;
\r
441 segData = LCD->SEGD2L;
\r
442 segData &= ~(mask);
\r
443 segData |= (mask & bits);
\r
444 LCD->SEGD2L = segData;
\r
447 segData = LCD->SEGD3L;
\r
448 segData &= ~(mask);
\r
449 segData |= (mask & bits);
\r
450 LCD->SEGD3L = segData;
\r
452 #if defined(_LCD_SEGD4L_MASK)
\r
454 segData = LCD->SEGD4L;
\r
455 segData &= ~(mask);
\r
456 segData |= (mask & bits);
\r
457 LCD->SEGD4L = segData;
\r
460 #if defined(_LCD_SEGD5L_MASK)
\r
462 segData = LCD->SEGD5L;
\r
463 segData &= ~(mask);
\r
464 segData |= (mask & bits);
\r
465 LCD->SEGD5L = segData;
\r
468 #if defined(_LCD_SEGD6L_MASK)
\r
470 segData = LCD->SEGD6L;
\r
471 segData &= ~(mask);
\r
472 segData |= (mask & bits);
\r
473 LCD->SEGD6L = segData;
\r
476 #if defined(_LCD_SEGD7L_MASK)
\r
478 segData = LCD->SEGD7L;
\r
479 segData &= ~(mask);
\r
480 segData |= (mask & bits);
\r
481 LCD->SEGD7L = segData;
\r
491 #if defined(_LCD_SEGD0H_MASK)
\r
492 /***************************************************************************//**
\r
494 * Updated the high (32-39) segments on a given COM-line in one operation
\r
497 * Which COM line to update
\r
500 * Bit mask for segments 32-39
\r
503 * Bit pattern for segments 32-39
\r
504 ******************************************************************************/
\r
505 void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
\r
509 #if defined(_LCD_SEGD7H_MASK)
\r
510 EFM_ASSERT(com < 8);
\r
512 EFM_ASSERT(com < 4);
\r
515 /* Maximum number of com lines */
\r
519 segData = LCD->SEGD0H;
\r
520 segData &= ~(mask);
\r
521 segData |= (mask & bits);
\r
522 LCD->SEGD0H = segData;
\r
525 segData = LCD->SEGD1H;
\r
526 segData &= ~(mask);
\r
527 segData |= (mask & bits);
\r
528 LCD->SEGD1H = segData;
\r
531 segData = LCD->SEGD2H;
\r
532 segData &= ~(mask);
\r
533 segData |= (mask & bits);
\r
534 LCD->SEGD2H = segData;
\r
537 segData = LCD->SEGD3H;
\r
538 segData &= ~(mask);
\r
539 segData |= (mask & bits);
\r
540 LCD->SEGD3H = segData;
\r
542 #if defined(_LCD_SEGD4H_MASK)
\r
544 segData = LCD->SEGD4H;
\r
545 segData &= ~(mask);
\r
546 segData |= (mask & bits);
\r
547 LCD->SEGD4H = segData;
\r
550 #if defined(_LCD_SEGD5H_MASK)
\r
552 segData = LCD->SEGD5H;
\r
553 segData &= ~(mask);
\r
554 segData |= (mask & bits);
\r
555 LCD->SEGD5H = segData;
\r
558 #if defined(_LCD_SEGD6H_MASK)
\r
560 segData = LCD->SEGD6H;
\r
561 segData &= ~(mask);
\r
562 segData |= (mask & bits);
\r
563 LCD->SEGD6H = segData;
\r
566 #if defined(_LCD_SEGD7H_MASK)
\r
568 segData = LCD->SEGD7H;
\r
569 segData &= ~(mask);
\r
570 segData |= (mask & bits);
\r
571 LCD->SEGD7H = segData;
\r
580 /***************************************************************************//**
\r
582 * Configure contrast level on LCD panel
\r
585 * Contrast level in the range 0-31
\r
586 ******************************************************************************/
\r
587 void LCD_ContrastSet(int level)
\r
589 EFM_ASSERT(level < 32);
\r
591 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONLEV_MASK)
\r
592 | (level << _LCD_DISPCTRL_CONLEV_SHIFT);
\r
596 /***************************************************************************//**
\r
598 * Configure voltage booster
\r
600 * The resulting voltage level is described in each part number's data sheet
\r
602 * @param[in] vboost
\r
603 * Voltage boost level
\r
604 ******************************************************************************/
\r
605 void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)
\r
607 /* Reconfigure Voltage Boost */
\r
608 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_VBLEV_MASK) | vboost;
\r
612 #if defined(LCD_CTRL_DSC)
\r
613 /***************************************************************************//**
\r
615 * Configure bias level for a specific segment line for Direct Segment Control
\r
618 * When DSC is active, each configuration takes up 4 bits in the Segment
\r
619 * Registers (SEGD0L/SEGD1H) which defines bias level.
\r
620 * For optimal use of this feature, the entire SEGD-registers should be set
\r
621 * at once in a optimized routine, so this function is mainly here to
\r
622 * demonstrate how to correctly configure the bias levels, and should be used
\r
625 * @param[in] segmentLine
\r
626 * Segment line number
\r
628 * @param[in] biasLevel
\r
629 * Bias configuration level, 0-4. This value must be within the constraint
\r
630 * defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
\r
631 ******************************************************************************/
\r
632 void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
\r
636 volatile uint32_t *segmentRegister;
\r
638 #if !defined(_LCD_SEGD0H_MASK)
\r
639 EFM_ASSERT(segmentLine < 20);
\r
641 /* Bias config for 8 segment lines per SEGDnL register */
\r
642 biasRegister = segmentLine / 8;
\r
643 bitShift = (segmentLine % 8) * 4;
\r
645 switch (biasRegister)
\r
648 segmentRegister = &LCD->SEGD0L;
\r
651 segmentRegister = &LCD->SEGD1L;
\r
654 segmentRegister = &LCD->SEGD2L;
\r
657 segmentRegister = &LCD->SEGD3L;
\r
660 segmentRegister = (uint32_t *)0x00000000;
\r
665 EFM_ASSERT(segmentLine < 40);
\r
667 /* Bias config for 10 segment lines per SEGDn L+H registers */
\r
668 biasRegister = segmentLine / 10;
\r
669 bitShift = (segmentLine % 10) * 4;
\r
671 switch (biasRegister)
\r
676 segmentRegister = &LCD->SEGD0L;
\r
680 segmentRegister = &LCD->SEGD0H;
\r
687 segmentRegister = &LCD->SEGD1L;
\r
691 segmentRegister = &LCD->SEGD1H;
\r
698 segmentRegister = &LCD->SEGD2L;
\r
702 segmentRegister = &LCD->SEGD1H;
\r
709 segmentRegister = &LCD->SEGD3L;
\r
713 segmentRegister = &LCD->SEGD3H;
\r
718 segmentRegister = (uint32_t *)0x00000000;
\r
724 /* Configure new bias setting */
\r
725 *segmentRegister = (*segmentRegister & ~(0xF << bitShift)) | (biasLevel << bitShift);
\r
730 #if defined(LCD_CTRL_DSC)
\r
731 /***************************************************************************//**
\r
733 * Configure bias level for a specific segment line
\r
736 * When DSC is active, each configuration takes up 4 bits in the Segment
\r
737 * Registers (SEGD4L/SEGD4H) which defines bias level.
\r
738 * For optimal use of this feature, the entire SEGD-registers should be set
\r
739 * at once in a optimized routine, so this function is mainly here to
\r
740 * demonstrate how to correctly configure the bias levels, and should be used
\r
743 * @param[in] comLine
\r
744 * COM line number, 0-7
\r
746 * @param[in] biasLevel
\r
747 * Bias configuration level, 0-4. This value must be within the constraint
\r
748 * defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
\r
749 ******************************************************************************/
\r
750 void LCD_BiasComSet(int comLine, int biasLevel)
\r
753 EFM_ASSERT(comLine < 8);
\r
755 bitShift = comLine * 4;
\r
756 LCD->SEGD4L = (LCD->SEGD4L & ~(0xF << bitShift)) | (biasLevel << bitShift);
\r
760 /** @} (end addtogroup LCD) */
\r
761 /** @} (end addtogroup EM_Library) */
\r
763 #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */
\r