1 /***************************************************************************//**
2 * @file
3 * @brief Liquid Crystal Display (LCD) Peripheral API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "em_lcd.h"
32 #if defined(LCD_COUNT) && (LCD_COUNT > 0)
33 #include "sl_assert.h"
34 #include "em_bus.h"
35 #include "em_gpio.h"
36
37 #include <stddef.h>
38
39 /***************************************************************************//**
40 * @addtogroup lcd LCD - Liquid Crystal Display
41 * @brief Liquid Crystal Display (LCD) Peripheral API
42 * @details
43 * This module contains functions to control the LDC peripheral of Silicon
44 * Labs 32-bit MCUs and SoCs. The LCD driver can drive up to 8x36 segmented
45 * LCD directly. The animation feature makes it possible to have active
46 * animations without the CPU intervention.
47 * @{
48 ******************************************************************************/
49
50 /** Frame counter uses a maximum of 5 bits (FCTOP[5:0]). */
51 #define LCD_FRAME_COUNTER_VAL_MAX 64
52
53 /***************************************************************************//**
54 * @brief
55 * Initialize the Liquid Crystal Display (LCD) controller.
56 *
57 * @details
58 * Configures the LCD controller. You must enable
59 * it afterwards, potentially configuring Frame Control and interrupts first
60 * according to requirements.
61 *
62 * @param[in] lcdInit
63 * A pointer to the initialization structure which configures the LCD controller.
64 *
65 ******************************************************************************/
LCD_Init(const LCD_Init_TypeDef * lcdInit)66 void LCD_Init(const LCD_Init_TypeDef *lcdInit)
67 {
68 uint32_t dispCtrl = LCD->DISPCTRL;
69
70 EFM_ASSERT(lcdInit != (void *) 0);
71
72 /* Disable the controller before reconfiguration. */
73 LCD_Enable(false);
74 #if defined(_SILICON_LABS_32B_SERIES_2)
75 LCD_ReadyWait();
76 #endif
77
78 #if defined(_SILICON_LABS_32B_SERIES_2)
79 /* Initialize LCD registers to hardware reset state. */
80 LCD_Reset();
81 #endif
82
83 #if defined(_SILICON_LABS_32B_SERIES_2)
84 LCD->CTRL &= ~_LCD_CTRL_PRESCALE_MASK;
85 LCD->CTRL |= lcdInit->clockPrescaler << _LCD_CTRL_PRESCALE_SHIFT;
86 #endif
87
88 /* Make sure the other bit fields don't get affected (i.e., voltage boost). */
89 dispCtrl &= ~(0
90 #if defined(LCD_DISPCTRL_MUXE)
91 | _LCD_DISPCTRL_MUXE_MASK
92 #endif
93 | _LCD_DISPCTRL_MUX_MASK
94 | _LCD_DISPCTRL_BIAS_MASK
95 | _LCD_DISPCTRL_WAVE_MASK
96 #if defined(_LCD_DISPCTRL_VLCDSEL_MASK)
97 | _LCD_DISPCTRL_VLCDSEL_MASK
98 #endif
99 #if defined(_LCD_DISPCTRL_CONCONF_MASK)
100 | _LCD_DISPCTRL_CONCONF_MASK
101 #endif
102 #if defined(_LCD_DISPCTRL_MODE_MASK)
103 | _LCD_DISPCTRL_MODE_MASK
104 #endif
105 #if defined(_LCD_DISPCTRL_CHGRDST_MASK)
106 | _LCD_DISPCTRL_CHGRDST_MASK
107 #endif
108 );
109
110 /* Configure the controller according to the initialization structure. */
111 dispCtrl |= lcdInit->mux; /* Also configures MUXE. */
112 dispCtrl |= lcdInit->bias;
113 dispCtrl |= lcdInit->wave;
114 #if defined(_SILICON_LABS_32B_SERIES_0)
115 dispCtrl |= lcdInit->vlcd;
116 dispCtrl |= lcdInit->contrast;
117 #else
118 dispCtrl |= (lcdInit->chargeRedistribution);
119 #endif
120
121 /* Update the display controller. */
122 LCD->DISPCTRL = dispCtrl;
123
124 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
125 LCD_ModeSet(lcdInit->mode);
126 LCD->FRAMERATE = lcdInit->frameRateDivider;
127 LCD_ContrastSet(lcdInit->contrastLevel);
128 #endif
129
130 /* Enable the controller if needed. */
131 if (lcdInit->enable) {
132 LCD_Enable(true);
133 }
134 }
135
136 #if defined(_SILICON_LABS_32B_SERIES_0)
137 /***************************************************************************//**
138 * @brief
139 * Select a source for VLCD.
140 *
141 * @param[in] vlcd
142 * Select a source for the VLCD voltage.
143 ******************************************************************************/
LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)144 void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd)
145 {
146 uint32_t dispctrl = LCD->DISPCTRL;
147
148 /* Select VEXT or VDD */
149 dispctrl &= ~_LCD_DISPCTRL_VLCDSEL_MASK;
150 switch (vlcd) {
151 case lcdVLCDSelVExtBoost:
152 dispctrl |= LCD_DISPCTRL_VLCDSEL_VEXTBOOST;
153 break;
154 case lcdVLCDSelVDD:
155 dispctrl |= LCD_DISPCTRL_VLCDSEL_VDD;
156 break;
157 default:
158 break;
159 }
160
161 LCD->DISPCTRL = dispctrl;
162 }
163 #endif
164
165 /***************************************************************************//**
166 * @brief
167 * Configure Update Control.
168 *
169 * @param[in] ud
170 * Configures the LCD update method.
171 ******************************************************************************/
LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)172 void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud)
173 {
174 #if defined(_SILICON_LABS_32B_SERIES_2)
175 LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
176 LCD_ReadyWait();
177 LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
178 LCD_Enable(true);
179 #else
180 LCD->CTRL = (LCD->CTRL & ~_LCD_CTRL_UDCTRL_MASK) | ud;
181 #endif
182 }
183
184 /***************************************************************************//**
185 * @brief
186 * Initialize the LCD Frame Counter.
187 *
188 * @param[in] fcInit
189 * A pointer to the Frame Counter initialization structure.
190 ******************************************************************************/
LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef * fcInit)191 void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit)
192 {
193 EFM_ASSERT(fcInit != (void *) 0);
194
195 /* Verify that the FC Top Counter is within limits. */
196 EFM_ASSERT(fcInit->top < LCD_FRAME_COUNTER_VAL_MAX);
197
198 #if defined(_SILICON_LABS_32B_SERIES_2)
199 uint32_t bacfg = LCD->BACFG;
200
201 /* Reconfigure the frame count configuration. */
202 bacfg &= ~(_LCD_BACFG_FCTOP_MASK
203 | _LCD_BACFG_FCPRESC_MASK);
204 bacfg |= (fcInit->top << _LCD_BACFG_FCTOP_SHIFT);
205 bacfg |= fcInit->prescale;
206
207 /* Set the Blink and Animation Control Register. */
208 LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
209 LCD_ReadyWait();
210 LCD->BACFG = bacfg;
211 LCD_Enable(true);
212 #else
213 uint32_t bactrl = LCD->BACTRL;
214
215 /* Reconfigure the frame count configuration. */
216 bactrl &= ~(_LCD_BACTRL_FCTOP_MASK
217 | _LCD_BACTRL_FCPRESC_MASK);
218 bactrl |= (fcInit->top << _LCD_BACTRL_FCTOP_SHIFT);
219 bactrl |= fcInit->prescale;
220
221 /* Set the Blink and Animation Control Register. */
222 LCD->BACTRL = bactrl;
223 #endif
224
225 LCD_FrameCountEnable(fcInit->enable);
226 }
227
228 /***************************************************************************//**
229 * @brief
230 * Configure the LCD controller Animation feature.
231 *
232 * @param[in] animInit
233 * A pointer to the LCD Animation initialization structure.
234 ******************************************************************************/
LCD_AnimInit(const LCD_AnimInit_TypeDef * animInit)235 void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit)
236 {
237 uint32_t bactrl = LCD->BACTRL;
238
239 EFM_ASSERT(animInit != (void *) 0);
240
241 /* Set initial Animation Register Values. */
242 LCD->AREGA = animInit->AReg;
243 LCD->AREGB = animInit->BReg;
244
245 /* Configure the Animation Shift and Logic. */
246 bactrl &= ~(_LCD_BACTRL_AREGASC_MASK
247 | _LCD_BACTRL_AREGBSC_MASK
248 | _LCD_BACTRL_ALOGSEL_MASK
249 #if defined(_LCD_BACTRL_ALOC_MASK)
250 | _LCD_BACTRL_ALOC_MASK
251 #endif
252 );
253
254 bactrl |= (animInit->AShift << _LCD_BACTRL_AREGASC_SHIFT);
255 bactrl |= (animInit->BShift << _LCD_BACTRL_AREGBSC_SHIFT);
256 bactrl |= animInit->animLogic;
257 #if defined(_LCD_BACTRL_ALOC_MASK)
258 bactrl |= animInit->startSeg;
259 #endif
260
261 /* Reconfigure. */
262 LCD->BACTRL = bactrl;
263
264 /* Enable. */
265 LCD_AnimEnable(animInit->enable);
266 }
267
268 #if defined(_SILICON_LABS_32B_SERIES_0)
269 /***************************************************************************//**
270 * @brief
271 * Enables updating this range of LCD segment lines.
272 *
273 * @param[in] segmentRange
274 * A range of 4 LCD segment lines to enable or disable for all enabled COM
275 * lines.
276 *
277 * @param[in] enable
278 * Boolean true to enable segment updates, false to disable updates.
279 ******************************************************************************/
LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange,bool enable)280 void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segmentRange, bool enable)
281 {
282 if (enable) {
283 LCD->SEGEN |= segmentRange;
284 } else {
285 LCD->SEGEN &= ~((uint32_t)segmentRange);
286 }
287 }
288 #endif
289
290 #if defined(_SILICON_LABS_32B_SERIES_2)
291 /***************************************************************************//**
292 * @brief
293 * Enables a given LCD segment line.
294 *
295 * @param[in] seg_nbr
296 * Segment line number.
297 *
298 * @param[in] enable
299 * Boolean true to enable a segment, false to disable.
300 ******************************************************************************/
LCD_SegmentEnable(uint32_t seg_nbr,bool enable)301 void LCD_SegmentEnable(uint32_t seg_nbr, bool enable)
302 {
303 /* Series 2 parts support up to 20 segment lines. */
304 /* Except for xG26 which supports up to 40 segment lines. and xG28 which supports up to 28 segment lines. */
305 EFM_ASSERT(seg_nbr < (int)LCD_SEGMENT_LINES_MAX);
306
307 #if defined(_GPIO_LCDSEGH_MASK)
308 if (enable) {
309 if (seg_nbr > 31) {
310 GPIO->LCDSEGH_SET = 1 << (seg_nbr - 32);
311 } else {
312 GPIO->LCDSEGL_SET = 1 << (seg_nbr);
313 }
314 } else {
315 if (seg_nbr > 31) {
316 GPIO->LCDSEGH_CLR = 1 << (seg_nbr - 32);
317 } else {
318 GPIO->LCDSEGL_CLR = 1 << (seg_nbr);
319 }
320 }
321 #else /* defined(_GPIO_LCDSEGH_MASK) */
322 if (enable) {
323 GPIO->LCDSEG_SET = 1 << seg_nbr;
324 } else {
325 GPIO->LCDSEG_CLR = 1 << seg_nbr;
326 }
327 #endif /* defined(_GPIO_LCDSEGH_MASK) */
328 }
329 #endif
330
331 #if defined(_SILICON_LABS_32B_SERIES_2)
332 /***************************************************************************//**
333 * @brief
334 * Enables a given LCD COM line.
335 *
336 * @param[in] com
337 * COM line number.
338 *
339 * @param[in] enable
340 * Boolean true to enable a COM , false to disable.
341 ******************************************************************************/
LCD_ComEnable(uint8_t com,bool enable)342 void LCD_ComEnable(uint8_t com, bool enable)
343 {
344 /* Series 2 parts support up to 4 COM lines except for xG28, which supports up to 8 COM lines. */
345 EFM_ASSERT(com < LCD_COM_LINES_MAX);
346
347 if (com < LCD_COM_NUM) {
348 if (enable) {
349 GPIO->LCDCOM_SET = 1 << com;
350 } else {
351 GPIO->LCDCOM_CLR = 1 << com;
352 }
353 }
354 #if defined(LCD_OCTAPLEX) && (LCD_OCTAPLEX == 1)
355 else {
356 /* On xG28, SEG lines shall be configured as COM lines */
357 /* for COM support above 4 COM lines */
358 #if defined(_GPIO_LCDSEGH_MASK)
359 if (enable) {
360 if ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART > 31) {
361 GPIO->LCDSEGH_SET = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART - 32);
362 } else {
363 GPIO->LCDSEGL_SET = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART);
364 }
365 } else {
366 if ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART > 31) {
367 GPIO->LCDSEGH_CLR = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART - 32);
368 } else {
369 GPIO->LCDSEGL_CLR = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART);
370 }
371 }
372 }
373 #else /* defined(_GPIO_LCDSEGH_MASK) */
374 if (enable) {
375 GPIO->LCDSEG_SET = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART);
376 } else {
377 GPIO->LCDSEG_CLR = 1 << ((com - LCD_COM_NUM) + LCD_SEGASCOM_SEGSTART);
378 }
379 }
380 #endif /* defined(_GPIO_LCDSEGH_MASK) */
381 #endif /* defined(LCD_OCTAPLEX) && (LCD_OCTAPLEX == 1) */
382 }
383 #endif
384
385 #if defined(_SILICON_LABS_32B_SERIES_2)
386 /***************************************************************************//**
387 * @brief
388 * Set a given DMA mode operation.
389 *
390 * @param[in] mode
391 * DMA mode.
392 ******************************************************************************/
LCD_DmaModeSet(LCD_DmaMode_Typedef mode)393 void LCD_DmaModeSet(LCD_DmaMode_Typedef mode)
394 {
395 LCD->BIASCTRL_CLR = _LCD_BIASCTRL_DMAMODE_MASK;
396 LCD->BIASCTRL |= mode;
397 }
398 #endif
399
400 /***************************************************************************//**
401 * @brief
402 * Turn on or clear a segment.
403 *
404 * @note
405 * For the Gecko Family, the maximum configuration is (COM-lines x Segment-Lines) 4x40.
406 * For the Tiny Gecko Family, the maximum configuration is 8x20 or 4x24.
407 * For the Giant Gecko Family, the maximum configuration is 8x36 or 4x40.
408 * For the Series 2 Family, the maximum configuration is 4x20.
409 * For the Series 2 xG28, the maximum configuration is 8x24 or 4x28.
410 *
411 * @param[in] com
412 * A COM line to change.
413 *
414 * @param[in] bit
415 * A bit index indicating which field to change.
416 *
417 * @param[in] enable
418 * True will set segment, false will clear segment.
419 ******************************************************************************/
LCD_SegmentSet(int com,int bit,bool enable)420 void LCD_SegmentSet(int com, int bit, bool enable)
421 {
422 #if defined(_SILICON_LABS_32B_SERIES_2)
423 /* Series 2 parts support up to 4 COM lines except for xG26 and xG28, which supports up to 8 COM lines. */
424 EFM_ASSERT(com < (int)LCD_COM_LINES_MAX);
425
426 /* Series 2 parts support up to 20 segment lines. */
427 /* Except for xG26 which supports up to 40 segment lines. and xG28 which supports up to 28 segment lines. */
428 EFM_ASSERT(bit < (int)LCD_SEGMENT_LINES_MAX);
429
430 /* Use a bitband access for atomic bit set/clear of the segment. */
431 switch (com) {
432 case 0:
433 #if defined(_LCD_SEGD0H_MASK)
434 if (bit < 32) {
435 BUS_RegBitWrite(&(LCD->SEGD0), bit, enable);
436 } else {
437 bit -= 32;
438 BUS_RegBitWrite(&(LCD->SEGD0H), bit, enable);
439 }
440 #else
441 BUS_RegBitWrite(&(LCD->SEGD0), bit, enable);
442 #endif
443 break;
444
445 case 1:
446 #if defined(_LCD_SEGD1H_MASK)
447 if (bit < 32) {
448 BUS_RegBitWrite(&(LCD->SEGD1), bit, enable);
449 } else {
450 bit -= 32;
451 BUS_RegBitWrite(&(LCD->SEGD1H), bit, enable);
452 }
453 #else
454 BUS_RegBitWrite(&(LCD->SEGD1), bit, enable);
455 #endif
456 break;
457
458 case 2:
459 #if defined(_LCD_SEGD2H_MASK)
460 if (bit < 32) {
461 BUS_RegBitWrite(&(LCD->SEGD2), bit, enable);
462 } else {
463 bit -= 32;
464 BUS_RegBitWrite(&(LCD->SEGD2H), bit, enable);
465 }
466 #else
467 BUS_RegBitWrite(&(LCD->SEGD2), bit, enable);
468 #endif
469 break;
470
471 case 3:
472 #if defined(_LCD_SEGD3H_MASK)
473 if (bit < 32) {
474 BUS_RegBitWrite(&(LCD->SEGD3), bit, enable);
475 } else {
476 bit -= 32;
477 BUS_RegBitWrite(&(LCD->SEGD3H), bit, enable);
478 }
479 #else
480 BUS_RegBitWrite(&(LCD->SEGD3), bit, enable);
481 #endif
482 break;
483
484 #if defined(_LCD_SEGD4_MASK)
485 case 4:
486 #if defined(_LCD_SEGD4H_MASK)
487 if (bit < 32) {
488 BUS_RegBitWrite(&(LCD->SEGD4), bit, enable);
489 } else {
490 bit -= 32;
491 BUS_RegBitWrite(&(LCD->SEGD4H), bit, enable);
492 }
493 #else
494 BUS_RegBitWrite(&(LCD->SEGD4), bit, enable);
495 #endif
496 break;
497 #endif
498
499 #if defined(_LCD_SEGD5_MASK)
500 case 5:
501 #if defined(_LCD_SEGD5H_MASK)
502 if (bit < 32) {
503 BUS_RegBitWrite(&(LCD->SEGD5), bit, enable);
504 } else {
505 bit -= 32;
506 BUS_RegBitWrite(&(LCD->SEGD5H), bit, enable);
507 }
508 #else
509 BUS_RegBitWrite(&(LCD->SEGD5), bit, enable);
510 #endif
511 break;
512 #endif
513
514 #if defined(_LCD_SEGD6_MASK)
515 case 6:
516 #if defined(_LCD_SEGD6H_MASK)
517 if (bit < 32) {
518 BUS_RegBitWrite(&(LCD->SEGD6), bit, enable);
519 } else {
520 bit -= 32;
521 BUS_RegBitWrite(&(LCD->SEGD6H), bit, enable);
522 }
523 #else
524 BUS_RegBitWrite(&(LCD->SEGD6), bit, enable);
525 #endif
526 break;
527 #endif
528
529 #if defined(_LCD_SEGD7_MASK)
530 case 7:
531 #if defined(_LCD_SEGD7H_MASK)
532 if (bit < 32) {
533 BUS_RegBitWrite(&(LCD->SEGD7), bit, enable);
534 } else {
535 bit -= 32;
536 BUS_RegBitWrite(&(LCD->SEGD7H), bit, enable);
537 }
538 #else
539 BUS_RegBitWrite(&(LCD->SEGD7), bit, enable);
540 #endif
541 break;
542 #endif
543
544 default:
545 EFM_ASSERT(0);
546 break;
547 }
548 #else
549 #if defined(_LCD_SEGD7L_MASK)
550 /* Tiny Gecko and Giant Gecko Families support up to 8 COM lines. */
551 EFM_ASSERT(com < 8);
552 #else
553 /* Gecko Family supports up to 4 COM lines. */
554 EFM_ASSERT(com < 4);
555 #endif
556
557 #if defined(_LCD_SEGD0H_MASK)
558 EFM_ASSERT(bit < 40);
559 #else
560 /* Tiny Gecko Family supports only "low" segment registers. */
561 EFM_ASSERT(bit < 32);
562 #endif
563
564 /* Use a bitband access for atomic bit set/clear of the segment. */
565 switch (com) {
566 case 0:
567 if (bit < 32) {
568 BUS_RegBitWrite(&(LCD->SEGD0L), bit, enable);
569 }
570 #if defined(_LCD_SEGD0H_MASK)
571 else {
572 bit -= 32;
573 BUS_RegBitWrite(&(LCD->SEGD0H), bit, enable);
574 }
575 #endif
576 break;
577 case 1:
578 if (bit < 32) {
579 BUS_RegBitWrite(&(LCD->SEGD1L), bit, enable);
580 }
581 #if defined(_LCD_SEGD1H_MASK)
582 else {
583 bit -= 32;
584 BUS_RegBitWrite(&(LCD->SEGD1H), bit, enable);
585 }
586 #endif
587 break;
588 case 2:
589 if (bit < 32) {
590 BUS_RegBitWrite(&(LCD->SEGD2L), bit, enable);
591 }
592 #if defined(_LCD_SEGD2H_MASK)
593 else {
594 bit -= 32;
595 BUS_RegBitWrite(&(LCD->SEGD2H), bit, enable);
596 }
597 #endif
598 break;
599 case 3:
600 if (bit < 32) {
601 BUS_RegBitWrite(&(LCD->SEGD3L), bit, enable);
602 }
603 #if defined(_LCD_SEGD3H_MASK)
604 else {
605 bit -= 32;
606 BUS_RegBitWrite(&(LCD->SEGD3H), bit, enable);
607 }
608 #endif
609 break;
610 #if defined(_LCD_SEGD4L_MASK)
611 case 4:
612 if (bit < 32) {
613 BUS_RegBitWrite(&(LCD->SEGD4L), bit, enable);
614 }
615 #if defined(_LCD_SEGD4H_MASK)
616 else {
617 bit -= 32;
618 BUS_RegBitWrite(&(LCD->SEGD4H), bit, enable);
619 }
620 #endif
621 break;
622 #endif
623 #if defined(_LCD_SEGD5L_MASK)
624 case 5:
625 if (bit < 32) {
626 BUS_RegBitWrite(&(LCD->SEGD5L), bit, enable);
627 }
628 #if defined(_LCD_SEGD5H_MASK)
629 else {
630 bit -= 32;
631 BUS_RegBitWrite(&(LCD->SEGD5H), bit, enable);
632 }
633 #endif
634 break;
635 #endif
636 case 6:
637 #if defined(_LCD_SEGD6L_MASK)
638 if (bit < 32) {
639 BUS_RegBitWrite(&(LCD->SEGD6L), bit, enable);
640 }
641 #if defined(_LCD_SEGD6H_MASK)
642 else {
643 bit -= 32;
644 BUS_RegBitWrite(&(LCD->SEGD6H), bit, enable);
645 }
646 #endif
647 break;
648 #endif
649 #if defined(_LCD_SEGD7L_MASK)
650 case 7:
651 if (bit < 32) {
652 BUS_RegBitWrite(&(LCD->SEGD7L), bit, enable);
653 }
654 #if defined(_LCD_SEGD7H_MASK)
655 else {
656 bit -= 32;
657 BUS_RegBitWrite(&(LCD->SEGD7H), bit, enable);
658 }
659 #endif
660 break;
661 #endif
662
663 default:
664 EFM_ASSERT(0);
665 break;
666 }
667 #endif
668 }
669
670 /***************************************************************************//**
671 * @brief
672 * Update 0-31 lowest segments on a given COM-line in one operation
673 * according to the bit mask.
674 *
675 * @param[in] com
676 * Indicates a COM line to update.
677 *
678 * @param[in] mask
679 * A bit mask for segments 0-31.
680 *
681 * @param[in] bits
682 * A bit pattern for segments 0-31.
683 ******************************************************************************/
LCD_SegmentSetLow(int com,uint32_t mask,uint32_t bits)684 void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
685 {
686 #if defined(_SILICON_LABS_32B_SERIES_2)
687 uint32_t segData;
688
689 /* Series 2 parts support up to 4 COM lines except for xG26 and xG28, which supports up to 8 COM lines. */
690 EFM_ASSERT(com < (int)LCD_COM_LINES_MAX);
691
692 /* Series 2 parts support up to 20 segment lines. */
693 /* Except for xG26 which supports up to 40 segment lines. and xG28 which supports up to 28 segment lines. */
694 EFM_ASSERT(!(mask & (~_LCD_SEGD0_MASK)));
695 EFM_ASSERT(!(bits & (~_LCD_SEGD0_MASK)));
696
697 switch (com) {
698 case 0:
699 segData = LCD->SEGD0;
700 segData &= ~(mask);
701 segData |= (mask & bits);
702 LCD->SEGD0 = segData;
703 break;
704
705 case 1:
706 segData = LCD->SEGD1;
707 segData &= ~(mask);
708 segData |= (mask & bits);
709 LCD->SEGD1 = segData;
710
711 break;
712 case 2:
713 segData = LCD->SEGD2;
714 segData &= ~(mask);
715 segData |= (mask & bits);
716 LCD->SEGD2 = segData;
717 break;
718
719 case 3:
720 segData = LCD->SEGD3;
721 segData &= ~(mask);
722 segData |= (mask & bits);
723 LCD->SEGD3 = segData;
724 break;
725
726 #if defined(_LCD_SEGD4_MASK)
727 case 4:
728 segData = LCD->SEGD4;
729 segData &= ~(mask);
730 segData |= (mask & bits);
731 LCD->SEGD4 = segData;
732 break;
733 #endif
734
735 #if defined(_LCD_SEGD5_MASK)
736 case 5:
737 segData = LCD->SEGD5;
738 segData &= ~(mask);
739 segData |= (mask & bits);
740 LCD->SEGD5 = segData;
741 break;
742 #endif
743
744 #if defined(_LCD_SEGD6_MASK)
745 case 6:
746 segData = LCD->SEGD6;
747 segData &= ~(mask);
748 segData |= (mask & bits);
749 LCD->SEGD6 = segData;
750 break;
751 #endif
752
753 #if defined(_LCD_SEGD7_MASK)
754 case 7:
755 segData = LCD->SEGD7;
756 segData &= ~(mask);
757 segData |= (mask & bits);
758 LCD->SEGD7 = segData;
759 break;
760 #endif
761
762 default:
763 EFM_ASSERT(0);
764 break;
765 }
766 #else
767 uint32_t segData;
768
769 /* A maximum number of com lines. */
770 #if defined(_LCD_SEGD7L_MASK)
771 EFM_ASSERT(com < 8);
772 #else
773 /* Gecko Family supports up to 4 COM lines. */
774 EFM_ASSERT(com < 4);
775 #endif
776
777 switch (com) {
778 case 0:
779 segData = LCD->SEGD0L;
780 segData &= ~(mask);
781 segData |= (mask & bits);
782 LCD->SEGD0L = segData;
783 break;
784 case 1:
785 segData = LCD->SEGD1L;
786 segData &= ~(mask);
787 segData |= (mask & bits);
788 LCD->SEGD1L = segData;
789 break;
790 case 2:
791 segData = LCD->SEGD2L;
792 segData &= ~(mask);
793 segData |= (mask & bits);
794 LCD->SEGD2L = segData;
795 break;
796 case 3:
797 segData = LCD->SEGD3L;
798 segData &= ~(mask);
799 segData |= (mask & bits);
800 LCD->SEGD3L = segData;
801 break;
802 #if defined(_LCD_SEGD4L_MASK)
803 case 4:
804 segData = LCD->SEGD4L;
805 segData &= ~(mask);
806 segData |= (mask & bits);
807 LCD->SEGD4L = segData;
808 break;
809 #endif
810 #if defined(_LCD_SEGD5L_MASK)
811 case 5:
812 segData = LCD->SEGD5L;
813 segData &= ~(mask);
814 segData |= (mask & bits);
815 LCD->SEGD5L = segData;
816 break;
817 #endif
818 #if defined(_LCD_SEGD6L_MASK)
819 case 6:
820 segData = LCD->SEGD6L;
821 segData &= ~(mask);
822 segData |= (mask & bits);
823 LCD->SEGD6L = segData;
824 break;
825 #endif
826 #if defined(_LCD_SEGD7L_MASK)
827 case 7:
828 segData = LCD->SEGD7L;
829 segData &= ~(mask);
830 segData |= (mask & bits);
831 LCD->SEGD7L = segData;
832 break;
833 #endif
834 default:
835 EFM_ASSERT(0);
836 break;
837 }
838 #endif
839 }
840
841 #if defined(_LCD_SEGD0H_MASK)
842 /***************************************************************************//**
843 * @brief
844 * Update the high (32-39) segments on a given COM-line in one operation.
845 *
846 * @param[in] com
847 * Indicates a COM line to update.
848 *
849 * @param[in] mask
850 * A bit mask for segments 32-39.
851 *
852 * @param[in] bits
853 * A bit pattern for segments 32-39.
854 ******************************************************************************/
LCD_SegmentSetHigh(int com,uint32_t mask,uint32_t bits)855 void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
856 {
857 uint32_t segData;
858
859 #if defined(_LCD_SEGD7H_MASK)
860 EFM_ASSERT(com < 8);
861 #else
862 EFM_ASSERT(com < 4);
863 #endif
864
865 /* A maximum number of com lines. */
866 switch (com) {
867 case 0:
868 segData = LCD->SEGD0H;
869 segData &= ~(mask);
870 segData |= (mask & bits);
871 LCD->SEGD0H = segData;
872 break;
873 case 1:
874 segData = LCD->SEGD1H;
875 segData &= ~(mask);
876 segData |= (mask & bits);
877 LCD->SEGD1H = segData;
878 break;
879 case 2:
880 segData = LCD->SEGD2H;
881 segData &= ~(mask);
882 segData |= (mask & bits);
883 LCD->SEGD2H = segData;
884 break;
885 case 3:
886 segData = LCD->SEGD3H;
887 segData &= ~(mask);
888 segData |= (mask & bits);
889 LCD->SEGD3H = segData;
890 break;
891 #if defined(_LCD_SEGD4H_MASK)
892 case 4:
893 segData = LCD->SEGD4H;
894 segData &= ~(mask);
895 segData |= (mask & bits);
896 LCD->SEGD4H = segData;
897 break;
898 #endif
899 #if defined(_LCD_SEGD5H_MASK)
900 case 5:
901 segData = LCD->SEGD5H;
902 segData &= ~(mask);
903 segData |= (mask & bits);
904 LCD->SEGD5H = segData;
905 break;
906 #endif
907 #if defined(_LCD_SEGD6H_MASK)
908 case 6:
909 segData = LCD->SEGD6H;
910 segData &= ~(mask);
911 segData |= (mask & bits);
912 LCD->SEGD6H = segData;
913 break;
914 #endif
915 #if defined(_LCD_SEGD7H_MASK)
916 case 7:
917 segData = LCD->SEGD7H;
918 segData &= ~(mask);
919 segData |= (mask & bits);
920 LCD->SEGD7H = segData;
921 break;
922 #endif
923 default:
924 break;
925 }
926 }
927 #endif
928
929 /***************************************************************************//**
930 * @brief
931 * Configure the contrast level on the LCD panel.
932 *
933 * @param[in] level
934 * The contrast level in range 0-63.
935 ******************************************************************************/
LCD_ContrastSet(int level)936 void LCD_ContrastSet(int level)
937 {
938 #if defined(_SILICON_LABS_32B_SERIES_0)
939 EFM_ASSERT(level < 32);
940
941 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONLEV_MASK)
942 | (level << _LCD_DISPCTRL_CONLEV_SHIFT);
943
944 #elif defined(_SILICON_LABS_32B_SERIES_1)
945 EFM_ASSERT(level < 64);
946
947 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CONTRAST_MASK)
948 | (level << _LCD_DISPCTRL_CONTRAST_SHIFT);
949 #else
950 EFM_ASSERT(level < 32);
951
952 LCD->BIASCTRL = (LCD->BIASCTRL & ~_LCD_BIASCTRL_VLCD_MASK)
953 | (level << _LCD_BIASCTRL_VLCD_SHIFT);
954 #endif
955 }
956
957 /***************************************************************************//**
958 * @brief
959 * Configure the bias level on the LCD panel.
960 *
961 * @param[in] bias
962 * The bias level.
963 ******************************************************************************/
LCD_BiasSet(LCD_Bias_TypeDef bias)964 void LCD_BiasSet(LCD_Bias_TypeDef bias)
965 {
966 #if defined(_SILICON_LABS_32B_SERIES_2)
967 LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
968 LCD_ReadyWait();
969 #endif
970
971 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_BIAS_MASK) | bias;
972
973 #if defined(_SILICON_LABS_32B_SERIES_2)
974 LCD_Enable(true);
975 #endif
976 }
977
978 #if defined(_SILICON_LABS_32B_SERIES_0)
979 /***************************************************************************//**
980 * @brief
981 * Configure voltage booster
982 *
983 * The resulting voltage level is described in each part number's data sheet
984 *
985 * @param[in] vboost
986 * Voltage boost level
987 ******************************************************************************/
LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)988 void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost)
989 {
990 /* Reconfigure Voltage Boost */
991 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_VBLEV_MASK) | vboost;
992 }
993 #endif
994
995 #if defined(LCD_CTRL_DSC)
996 /***************************************************************************//**
997 * @brief
998 * Configure the bias level for a specific segment line for Direct Segment Control.
999 *
1000 * @note
1001 * When DSC is active, each configuration takes up 4 bits in the corresponding
1002 * Segment Registers (SEGD0L/SEGD1H for Series 0 and 1, SEGDx/SEGDxH for Series 2)
1003 * which defines the bias level.
1004 * For optimal use of this feature, the entire SEGD-registers should be set
1005 * at once in an optimized routine. Therefore, this function shows how to
1006 * correctly configure the bias levels and should be used with care.
1007 *
1008 * @param[in] segmentLine
1009 * A segment line number.
1010 *
1011 * @param[in] biasLevel
1012 * The bias configuration level. This value must be within the constraints
1013 * defined by the LCD_DISPCTRL bias settings. For more information, see the
1014 * applicable Reference Manual and data sheet.
1015 ******************************************************************************/
LCD_BiasSegmentSet(int segmentLine,int biasLevel)1016 void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
1017 {
1018 volatile uint32_t *segmentRegister;
1019 int biasRegister;
1020 int bitShift;
1021
1022 #if defined(_SILICON_LABS_32B_SERIES_2)
1023 if (segmentLine >= (int)LCD_SEG_NUM) {
1024 return;
1025 }
1026
1027 /*
1028 * On Series 2, the following layout is used to configure bias when DSC
1029 * is active:
1030 *
1031 * REGISTERS | ... | 7 .. 4 | 3 .. 0 |
1032 * SEGD0 | ... | seg4 | seg0 |
1033 * SEGD1 | ... | seg5 | seg1 |
1034 * .....
1035 */
1036 biasRegister = segmentLine % 4;
1037 bitShift = (segmentLine / 4) * 4;
1038
1039 #if defined(_GPIO_LCDSEGH_MASK)
1040 switch (biasRegister) {
1041 case 0:
1042 if (bitShift < 32) {
1043 segmentRegister = &LCD->SEGD0;
1044 } else {
1045 segmentRegister = &LCD->SEGD0H;
1046 bitShift -= 32;
1047 }
1048 break;
1049 case 1:
1050 if (bitShift < 32) {
1051 segmentRegister = &LCD->SEGD1;
1052 } else {
1053 segmentRegister = &LCD->SEGD1H;
1054 bitShift -= 32;
1055 }
1056 break;
1057 case 2:
1058 if (bitShift < 32) {
1059 segmentRegister = &LCD->SEGD2;
1060 } else {
1061 segmentRegister = &LCD->SEGD2H;
1062 bitShift -= 32;
1063 }
1064 break;
1065 case 3:
1066 if (bitShift < 32) {
1067 segmentRegister = &LCD->SEGD3;
1068 } else {
1069 segmentRegister = &LCD->SEGD3H;
1070 bitShift -= 32;
1071 }
1072 break;
1073 default:
1074 segmentRegister = NULL;
1075 EFM_ASSERT(0);
1076 break;
1077 }
1078
1079 #else /* defined(_GPIO_LCDSEGH_MASK) */
1080
1081 switch (biasRegister) {
1082 case 0:
1083 segmentRegister = &LCD->SEGD0;
1084 break;
1085 case 1:
1086 segmentRegister = &LCD->SEGD1;
1087 break;
1088 case 2:
1089 segmentRegister = &LCD->SEGD2;
1090 break;
1091 case 3:
1092 segmentRegister = &LCD->SEGD3;
1093 break;
1094 default:
1095 segmentRegister = NULL;
1096 EFM_ASSERT(0);
1097 break;
1098 }
1099 #endif /* defined(_GPIO_LCDSEGH_MASK) */
1100
1101 #else
1102
1103 #if !defined(_LCD_SEGD0H_MASK)
1104 EFM_ASSERT(segmentLine < 20);
1105
1106 /* A bias configuration for 8 segment lines per SEGDnL register. */
1107 biasRegister = segmentLine / 8;
1108 bitShift = (segmentLine % 8) * 4;
1109
1110 switch (biasRegister) {
1111 case 0:
1112 segmentRegister = &LCD->SEGD0L;
1113 break;
1114 case 1:
1115 segmentRegister = &LCD->SEGD1L;
1116 break;
1117 case 2:
1118 segmentRegister = &LCD->SEGD2L;
1119 break;
1120 case 3:
1121 segmentRegister = &LCD->SEGD3L;
1122 break;
1123 default:
1124 segmentRegister = (uint32_t *)0x00000000;
1125 EFM_ASSERT(0);
1126 break;
1127 }
1128 #else
1129 EFM_ASSERT(segmentLine < 40);
1130
1131 /* A bias configuration for 10 segment lines per SEGDn L+H registers. */
1132 biasRegister = segmentLine / 10;
1133 bitShift = (segmentLine % 10) * 4;
1134
1135 switch (biasRegister) {
1136 case 0:
1137 if (bitShift < 32) {
1138 segmentRegister = &LCD->SEGD0L;
1139 } else {
1140 segmentRegister = &LCD->SEGD0H;
1141 bitShift -= 32;
1142 }
1143 break;
1144 case 1:
1145 if (bitShift < 32) {
1146 segmentRegister = &LCD->SEGD1L;
1147 } else {
1148 segmentRegister = &LCD->SEGD1H;
1149 bitShift -= 32;
1150 }
1151 break;
1152 case 2:
1153 if (bitShift < 32) {
1154 segmentRegister = &LCD->SEGD2L;
1155 } else {
1156 segmentRegister = &LCD->SEGD1H;
1157 bitShift -= 32;
1158 }
1159 break;
1160 case 3:
1161 if (bitShift < 32) {
1162 segmentRegister = &LCD->SEGD3L;
1163 } else {
1164 segmentRegister = &LCD->SEGD3H;
1165 bitShift -= 32;
1166 }
1167 break;
1168 default:
1169 segmentRegister = (uint32_t *)0x00000000;
1170 EFM_ASSERT(0);
1171 break;
1172 }
1173 #endif
1174
1175 #endif
1176
1177 /* Configure a new bias setting. */
1178 BUS_RegMaskedWrite(segmentRegister, 0xF << bitShift, biasLevel << bitShift);
1179 }
1180 #endif
1181
1182 #if defined(LCD_CTRL_DSC)
1183 /***************************************************************************//**
1184 * @brief
1185 * Configure the bias level for a specific segment line.
1186 *
1187 * @note
1188 * When DSC is active, each configuration takes up 4 bits in the corresponding
1189 * Segment Registers (SEGD4L/SEGD4H for Series 0 and 1, AREGA/AREGB for
1190 * Series 2) which defines bias level.
1191 * For optimal use of this feature, the entire register set should be set
1192 * at once in a optimized routine. Therefore, this function shows how to
1193 * correctly configure the bias levels and should be used with care.
1194 *
1195 * @param[in] comLine
1196 * A COM line number, between 0 and 7 for Series 0 and 1. For Series 2, max
1197 * is LCD_COM_NUM, defined in device-specific headers.
1198 *
1199 *
1200 * @param[in] biasLevel
1201 * The bias configuration level. This value must be within the constraints
1202 * defined by the LCD_DISPCTRL bias settings.
1203 * For more information, see the appropriate Reference Manual and data sheet.
1204 ******************************************************************************/
LCD_BiasComSet(int comLine,int biasLevel)1205 void LCD_BiasComSet(int comLine, int biasLevel)
1206 {
1207 #if defined(_SILICON_LABS_32B_SERIES_2)
1208 volatile uint32_t *comRegister;
1209 uint32_t biasRegister;
1210 uint32_t bitShift;
1211
1212 if (comLine >= (int)LCD_COM_NUM) {
1213 return;
1214 }
1215
1216 biasRegister = (uint32_t) comLine % 2;
1217 bitShift = (comLine / 2) * 4;
1218
1219 switch (biasRegister) {
1220 case 0:
1221 comRegister = &LCD->AREGA;
1222 break;
1223 case 1:
1224 comRegister = &LCD->AREGB;
1225 break;
1226 default:
1227 comRegister = NULL;
1228 EFM_ASSERT(0);
1229 break;
1230 }
1231
1232 BUS_RegMaskedWrite(comRegister, 0xF << bitShift, biasLevel << bitShift);
1233
1234 #else
1235 int bitShift;
1236 EFM_ASSERT(comLine < 8);
1237
1238 bitShift = comLine * 4;
1239 BUS_RegMaskedWrite(&(LCD->SEGD4L), 0xF << bitShift, biasLevel << bitShift);
1240 #endif
1241 }
1242 #endif
1243
1244 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
1245 /***************************************************************************//**
1246 * @brief
1247 * Configure the mode for the LCD panel.
1248 *
1249 * @param[in] mode
1250 * A mode.
1251 ******************************************************************************/
LCD_ModeSet(LCD_Mode_Typedef mode)1252 void LCD_ModeSet(LCD_Mode_Typedef mode)
1253 {
1254 #if defined(_SILICON_LABS_32B_SERIES_1)
1255 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_MODE_MASK) | mode;
1256 #else
1257 LCD->BIASCTRL = (LCD->BIASCTRL & ~_LCD_BIASCTRL_MODE_MASK) | mode;
1258 #endif
1259 }
1260 #endif
1261
1262 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
1263 /***************************************************************************//**
1264 * @brief
1265 * Configure the charge redistribution cycles for the LCD panel.
1266 *
1267 * @param[in] cycles
1268 * Charge redistribution cycles, range 0-4.
1269 ******************************************************************************/
LCD_ChargeRedistributionCyclesSet(uint8_t cycles)1270 void LCD_ChargeRedistributionCyclesSet(uint8_t cycles)
1271 {
1272 EFM_ASSERT(cycles <= 4);
1273
1274 #if defined(_SILICON_LABS_32B_SERIES_2)
1275 LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
1276 LCD_ReadyWait();
1277 #endif
1278
1279 LCD->DISPCTRL = (LCD->DISPCTRL & ~_LCD_DISPCTRL_CHGRDST_MASK)
1280 | ((uint32_t)cycles << _LCD_DISPCTRL_CHGRDST_SHIFT);
1281
1282 #if defined(_SILICON_LABS_32B_SERIES_2)
1283 LCD_Enable(true);
1284 #endif
1285 }
1286 #endif
1287
1288 /** @} (end addtogroup lcd) */
1289
1290 #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */
1291