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 #ifndef EM_LCD_H
32 #define EM_LCD_H
33 
34 #include "em_device.h"
35 
36 #if defined(LCD_COUNT) && (LCD_COUNT > 0)
37 #include <stdint.h>
38 #include <stdbool.h>
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /***************************************************************************//**
45  * @addtogroup lcd
46  * @{
47  ******************************************************************************/
48 
49 /*******************************************************************************
50  ********************************   DEFINES   **********************************
51  ******************************************************************************/
52 
53 /** Default Clock Prescaler. */
54 #define LCD_DEFAULT_CLOCK_PRESCALER 64
55 /** Default LCD Frame Rate Divisor. */
56 #define LCD_DEFAULT_FRAME_RATE_DIV  4
57 /** Default LCD Contrast. */
58 #define LCD_DEFAULT_CONTRAST        15
59 
60 #if defined(_SILICON_LABS_32B_SERIES_2)
61 /** Maximum common lines of LCD. */
62 #if defined(LCD_OCTAPLEX) && (LCD_OCTAPLEX == 1)
63 #define LCD_COM_LINES_MAX           (LCD_COM_NUM + LCD_SEGASCOM_NUM)
64 #else
65 #define LCD_COM_LINES_MAX           LCD_COM_NUM
66 #endif
67 /** Maximum segment lines of LCD. */
68 #define LCD_SEGMENT_LINES_MAX       LCD_SEG_NUM
69 #endif
70 
71 /*******************************************************************************
72  ********************************   ENUMS   ************************************
73  ******************************************************************************/
74 
75 /** MUX setting. */
76 typedef enum {
77   /** Static (segments can be multiplexed with LCD_COM[0]). */
78   lcdMuxStatic     = LCD_DISPCTRL_MUX_STATIC,
79   /** Duplex / 1/2 Duty cycle (segments can be multiplexed with LCD_COM[0:1]). */
80   lcdMuxDuplex     = LCD_DISPCTRL_MUX_DUPLEX,
81   /** Triplex / 1/3 Duty cycle (segments can be multiplexed with LCD_COM[0:2]). */
82   lcdMuxTriplex    = LCD_DISPCTRL_MUX_TRIPLEX,
83   /** Quadruplex / 1/4 Duty cycle (segments can be multiplexed with LCD_COM[0:3]). */
84   lcdMuxQuadruplex = LCD_DISPCTRL_MUX_QUADRUPLEX,
85 #if defined(LCD_DISPCTRL_MUXE_MUXE)
86   /** Sextaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]). */
87   lcdMuxSextaplex  = LCD_DISPCTRL_MUXE_MUXE | LCD_DISPCTRL_MUX_DUPLEX,
88   /** Octaplex / 1/8 Duty cycle (segments can be multiplexed with LCD_COM[0:7]). */
89   lcdMuxOctaplex   = LCD_DISPCTRL_MUXE_MUXE | LCD_DISPCTRL_MUX_QUADRUPLEX
90 #elif defined(LCD_DISPCTRL_MUX_SEXTAPLEX)
91   /** Sextaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]). */
92   lcdMuxSextaplex  = LCD_DISPCTRL_MUX_SEXTAPLEX,
93   /** Octaplex / 1/8 Duty cycle (segments can be multiplexed with LCD_COM[0:7]). */
94   lcdMuxOctaplex   = LCD_DISPCTRL_MUX_OCTAPLEX,
95 #endif
96 } LCD_Mux_TypeDef;
97 
98 /** Wave type. */
99 typedef enum {
100 #if defined(_SILICON_LABS_32B_SERIES_2)
101   /** Low power optimized waveform output. */
102   lcdWaveLowPower = LCD_DISPCTRL_WAVE_TYPEB,
103   /** Regular waveform output */
104   lcdWaveNormal   = LCD_DISPCTRL_WAVE_TYPEA
105 #else
106   /** Low power optimized waveform output. */
107   lcdWaveLowPower = LCD_DISPCTRL_WAVE_LOWPOWER,
108   /** Regular waveform output */
109   lcdWaveNormal   = LCD_DISPCTRL_WAVE_NORMAL
110 #endif
111 } LCD_Wave_TypeDef;
112 
113 /** Bias setting. */
114 typedef enum {
115   /** Static (2 levels). */
116   lcdBiasStatic    = LCD_DISPCTRL_BIAS_STATIC,
117   /** 1/2 Bias (3 levels). */
118   lcdBiasOneHalf   = LCD_DISPCTRL_BIAS_ONEHALF,
119   /** 1/3 Bias (4 levels). */
120   lcdBiasOneThird  = LCD_DISPCTRL_BIAS_ONETHIRD,
121 #if defined(LCD_DISPCTRL_BIAS_ONEFOURTH)
122   /** 1/4 Bias (5 levels). */
123   lcdBiasOneFourth = LCD_DISPCTRL_BIAS_ONEFOURTH,
124 #endif
125 } LCD_Bias_TypeDef;
126 
127 #if defined(_SILICON_LABS_32B_SERIES_0)
128 /** VLCD Voltage Source. */
129 typedef enum {
130   /** VLCD Powered by VDD. */
131   lcdVLCDSelVDD       = LCD_DISPCTRL_VLCDSEL_VDD,
132   /** VLCD Powered by external VDD / Voltage Boost. */
133   lcdVLCDSelVExtBoost = LCD_DISPCTRL_VLCDSEL_VEXTBOOST
134 } LCD_VLCDSel_TypeDef;
135 #endif
136 
137 /** Contrast Configuration. */
138 #if defined(_SILICON_LABS_32B_SERIES_0)
139 typedef enum {
140   /** Contrast is adjusted relative to VDD (VLCD). */
141   lcdConConfVLCD = LCD_DISPCTRL_CONCONF_VLCD,
142   /** Contrast is adjusted relative to Ground. */
143   lcdConConfGND  = LCD_DISPCTRL_CONCONF_GND
144 } LCD_ConConf_TypeDef;
145 #endif
146 
147 #if defined(_SILICON_LABS_32B_SERIES_0)
148 /** Voltage Boost Level - Data sheets document setting for each part number. */
149 typedef enum {
150   lcdVBoostLevel0 = LCD_DISPCTRL_VBLEV_LEVEL0, /**< Voltage boost LEVEL0. */
151   lcdVBoostLevel1 = LCD_DISPCTRL_VBLEV_LEVEL1, /**< Voltage boost LEVEL1. */
152   lcdVBoostLevel2 = LCD_DISPCTRL_VBLEV_LEVEL2, /**< Voltage boost LEVEL2. */
153   lcdVBoostLevel3 = LCD_DISPCTRL_VBLEV_LEVEL3, /**< Voltage boost LEVEL3. */
154   lcdVBoostLevel4 = LCD_DISPCTRL_VBLEV_LEVEL4, /**< Voltage boost LEVEL4. */
155   lcdVBoostLevel5 = LCD_DISPCTRL_VBLEV_LEVEL5, /**< Voltage boost LEVEL5. */
156   lcdVBoostLevel6 = LCD_DISPCTRL_VBLEV_LEVEL6, /**< Voltage boost LEVEL6. */
157   lcdVBoostLevel7 = LCD_DISPCTRL_VBLEV_LEVEL7  /**< Voltage boost LEVEL7. */
158 } LCD_VBoostLevel_TypeDef;
159 #endif
160 
161 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
162 /** Mode of operation. */
163 typedef enum {
164 #if defined(_SILICON_LABS_32B_SERIES_1)
165   lcdModeNoExtCap = LCD_DISPCTRL_MODE_NOEXTCAP, /**< No external capacitor. */
166   lcdModeStepDown = LCD_DISPCTRL_MODE_STEPDOWN, /**< External cap with resistor string. */
167   lcdModeCpIntOsc = LCD_DISPCTRL_MODE_CPINTOSC, /**< External cap and internal oscillator. */
168 #elif defined(_SILICON_LABS_32B_SERIES_2)
169   lcdModeStepDown   = LCD_BIASCTRL_MODE_STEPDOWN,   /**< External cap with resistor string. */
170   lcdModeChargePump = LCD_BIASCTRL_MODE_CHARGEPUMP, /**< External cap and internal oscillator. */
171 #endif
172 } LCD_Mode_Typedef;
173 #endif
174 
175 /** Frame Counter Clock Prescaler, FC-CLK = FrameRate (Hz) / this factor. */
176 typedef enum {
177 #if defined(_SILICON_LABS_32B_SERIES_2)
178   /** Prescale Div 1. */
179   lcdFCPrescDiv1 = LCD_BACFG_FCPRESC_DIV1,
180   /** Prescale Div 2. */
181   lcdFCPrescDiv2 = LCD_BACFG_FCPRESC_DIV2,
182   /** Prescale Div 4. */
183   lcdFCPrescDiv4 = LCD_BACFG_FCPRESC_DIV4,
184   /** Prescale Div 8. */
185   lcdFCPrescDiv8 = LCD_BACFG_FCPRESC_DIV8
186 #else
187   /** Prescale Div 1. */
188   lcdFCPrescDiv1 = LCD_BACTRL_FCPRESC_DIV1,
189   /** Prescale Div 2. */
190   lcdFCPrescDiv2 = LCD_BACTRL_FCPRESC_DIV2,
191   /** Prescale Div 4. */
192   lcdFCPrescDiv4 = LCD_BACTRL_FCPRESC_DIV4,
193   /** Prescale Div 8. */
194   lcdFCPrescDiv8 = LCD_BACTRL_FCPRESC_DIV8
195 #endif
196 } LCD_FCPreScale_TypeDef;
197 
198 #if defined(_SILICON_LABS_32B_SERIES_0)
199 /** Segment selection. */
200 typedef enum {
201   /** Select segment lines 0 to 3. */
202   lcdSegment0_3   = (1 << 0),
203   /** Select segment lines 4 to 7. */
204   lcdSegment4_7   = (1 << 1),
205   /** Select segment lines 8 to 11. */
206   lcdSegment8_11  = (1 << 2),
207   /** Select segment lines 12 to 15. */
208   lcdSegment12_15 = (1 << 3),
209   /** Select segment lines 16 to 19. */
210   lcdSegment16_19 = (1 << 4),
211   /** Select segment lines 20 to 23. */
212   lcdSegment20_23 = (1 << 5),
213 #if defined(_LCD_SEGD0L_MASK) && (_LCD_SEGD0L_MASK == 0x00FFFFFFUL)
214   /** Select all segment lines. */
215   lcdSegmentAll   = (0x003f)
216 #elif defined(_LCD_SEGD0H_MASK) && (_LCD_SEGD0H_MASK == 0x000000FFUL)
217   /** Select segment lines 24 to 27. */
218   lcdSegment24_27 = (1 << 6),
219   /** Select segment lines 28 to 31. */
220   lcdSegment28_31 = (1 << 7),
221   /** Select segment lines 32 to 35. */
222   lcdSegment32_35 = (1 << 8),
223   /** Select segment lines 36 to 39. */
224   lcdSegment36_39 = (1 << 9),
225   /** Select all segment lines. */
226   lcdSegmentAll   = (0x03ff)
227 #endif
228 } LCD_SegmentRange_TypeDef;
229 #endif
230 
231 /** Update Data Control. */
232 typedef enum {
233   /** Regular update, data transfer done immediately. */
234   lcdUpdateCtrlRegular      = LCD_CTRL_UDCTRL_REGULAR,
235   /** Data transfer done at Frame Counter event. */
236   lcdUpdateCtrlFCEvent      = LCD_CTRL_UDCTRL_FCEVENT,
237   /** Data transfer done at Frame Start.  */
238   lcdUpdateCtrlFrameStart   = LCD_CTRL_UDCTRL_FRAMESTART,
239 #if defined(_SILICON_LABS_32B_SERIES_2)
240   /** Data transfer done at Display Counter event.  */
241   lcdUpdateCtrlDisplayEvent = LCD_CTRL_UDCTRL_DISPLAYEVENT
242 #endif
243 } LCD_UpdateCtrl_TypeDef;
244 
245 #if defined(_SILICON_LABS_32B_SERIES_2)
246 /** Auto Load address which will start the synchronization from CLK_BUS to CLK_PER. */
247 typedef enum {
248   /** Starts synchronizing registers after a write to BACTRL. */
249   lcdLoadAddrNone   = 0,
250   /** Starts synchronizing registers after a write to BACTRL. */
251   lcdLoadAddrBactrl = LCD_UPDATECTRL_LOADADDR_BACTRLWR,
252   /** Starts synchronizing registers after a write to AREGA. */
253   lcdLoadAddrAregA  = LCD_UPDATECTRL_LOADADDR_AREGAWR,
254   /** Starts synchronizing registers after a write to AREGB. */
255   lcdLoadAddrAregB  = LCD_UPDATECTRL_LOADADDR_AREGBWR,
256   /** Starts synchronizing registers after a write to SEGD0. */
257   lcdLoadAddrSegd0  = LCD_UPDATECTRL_LOADADDR_SEGD0WR,
258   /** Starts synchronizing registers after a write to SEGD1. */
259   lcdLoadAddrSegd1  = LCD_UPDATECTRL_LOADADDR_SEGD1WR,
260   /** Starts synchronizing registers after a write to SEGD2. */
261   lcdLoadAddrSegd2  = LCD_UPDATECTRL_LOADADDR_SEGD2WR,
262   /** Starts synchronizing registers after a write to SEGD3. */
263   lcdLoadAddrSegd3  = LCD_UPDATECTRL_LOADADDR_SEGD3WR,
264 #if defined(LCD_UPDATECTRL_LOADADDR_SEGD4WR)
265   /** Starts synchronizing registers after a write to SEGD4. */
266   lcdLoadAddrSegd4  = LCD_UPDATECTRL_LOADADDR_SEGD4WR,
267 #endif
268 #if defined(LCD_UPDATECTRL_LOADADDR_SEGD5WR)
269   /** Starts synchronizing registers after a write to SEGD5. */
270   lcdLoadAddrSegd5  = LCD_UPDATECTRL_LOADADDR_SEGD5WR,
271 #endif
272 #if defined(LCD_UPDATECTRL_LOADADDR_SEGD6WR)
273   /** Starts synchronizing registers after a write to SEGD6. */
274   lcdLoadAddrSegd6  = LCD_UPDATECTRL_LOADADDR_SEGD6WR,
275 #endif
276 #if defined(LCD_UPDATECTRL_LOADADDR_SEGD7WR)
277   /** Starts synchronizing registers after a write to SEGD7. */
278   lcdLoadAddrSegd7  = LCD_UPDATECTRL_LOADADDR_SEGD7WR,
279 #endif
280 } LCD_LoadAddr_TypeDef;
281 #endif
282 
283 /** Animation Shift operation; none, left or right. */
284 typedef enum {
285   /** No shift. */
286   lcdAnimShiftNone  = _LCD_BACTRL_AREGASC_NOSHIFT,
287   /** Shift segment bits left. */
288   lcdAnimShiftLeft  = _LCD_BACTRL_AREGASC_SHIFTLEFT,
289   /** Shift segment bits right. */
290   lcdAnimShiftRight = _LCD_BACTRL_AREGASC_SHIFTRIGHT
291 } LCD_AnimShift_TypeDef;
292 
293 /** Animation Logic Control, how AReg and BReg should be combined. */
294 typedef enum {
295   /** Use bitwise logic AND to mix animation register A (AREGA) and B (AREGB). */
296   lcdAnimLogicAnd = LCD_BACTRL_ALOGSEL_AND,
297   /** Use bitwise logic OR to mix animation register A (AREGA) and B (AREGB).  */
298   lcdAnimLogicOr  = LCD_BACTRL_ALOGSEL_OR
299 } LCD_AnimLogic_TypeDef;
300 
301 #if defined(_LCD_BACTRL_ALOC_MASK)
302 /** Animation Location, set the LCD segments which animation applies to. */
303 typedef enum {
304   /** Animation appears on segments 0 to 7. */
305   lcdAnimLocSeg0To7  = LCD_BACTRL_ALOC_SEG0TO7,
306   /** Animation appears on segments 8 to 15.  */
307   lcdAnimLocSeg8To15 = LCD_BACTRL_ALOC_SEG8TO15
308 } LCD_AnimLoc_TypeDef;
309 #endif
310 
311 #if defined(_LCD_DISPCTRL_CHGRDST_MASK)
312 /** Charge redistribution control. */
313 typedef enum {
314   /** Disable charge redistribution. */
315   lcdChargeRedistributionDisable    = LCD_DISPCTRL_CHGRDST_DISABLE,
316   /** Use 1 prescaled low frequency clock cycle for charge redistribution. */
317   lcdChargeRedistributionEnable     = LCD_DISPCTRL_CHGRDST_ONE,
318   /** Use 2 prescaled low frequency clock cycle for charge redistribution. */
319   lcdChargeRedistributionTwoCycle   = LCD_DISPCTRL_CHGRDST_TWO,
320   /** Use 3 prescaled low frequency clock cycle for charge redistribution. */
321   lcdChargeRedistributionThreeCycle = LCD_DISPCTRL_CHGRDST_THREE,
322   /** Use 4 prescaled low frequency clock cycle for charge redistribution. */
323   lcdChargeRedistributionFourCycle  = LCD_DISPCTRL_CHGRDST_FOUR
324 } LCD_ChargeRedistribution_TypeDef;
325 #endif
326 
327 #if defined(_SILICON_LABS_32B_SERIES_2)
328 /** DMA mode of operation. */
329 typedef enum {
330   lcdDmaModeDisable      = LCD_BIASCTRL_DMAMODE_DMADISABLE,   /**< No DMA requests are generated. */
331   lcdDmaModeFrameCounterEvent   = LCD_BIASCTRL_DMAMODE_DMAFC, /**< DMA request on frame counter event. */
332   lcdDmaModeDisplayEvent = LCD_BIASCTRL_DMAMODE_DMADISPLAY    /**< DMA request on display counter event. */
333 } LCD_DmaMode_Typedef;
334 #endif
335 
336 /*******************************************************************************
337  *******************************   STRUCTS   ***********************************
338  ******************************************************************************/
339 
340 /** LCD Animation Configuration. */
341 typedef struct {
342   /** Enable Animation at end of initialization. */
343   bool                  enable;
344   /** Initial Animation Register A Value. */
345   uint32_t              AReg;
346   /** Shift operation of Animation Register A. */
347   LCD_AnimShift_TypeDef AShift;
348   /** Initial Animation Register B Value. */
349   uint32_t              BReg;
350   /** Shift operation of Animation Register B. */
351   LCD_AnimShift_TypeDef BShift;
352   /** A and B Logical Operation to use for mixing and outputting resulting segments. */
353   LCD_AnimLogic_TypeDef animLogic;
354 #if defined(_LCD_BACTRL_ALOC_MASK)
355   /** Number of first segment to animate. */
356   LCD_AnimLoc_TypeDef   startSeg;
357 #endif
358 } LCD_AnimInit_TypeDef;
359 
360 /** LCD Frame Control Initialization. */
361 typedef struct {
362   /** Enable at end. */
363   bool                   enable;
364   /** Frame Counter top value. */
365   uint32_t               top;
366   /** Frame Counter clock prescaler. */
367   LCD_FCPreScale_TypeDef prescale;
368 } LCD_FrameCountInit_TypeDef;
369 
370 /** LCD Controller Initialization structure. */
371 typedef struct {
372   /** Enable controller at end of initialization. */
373   bool                enable;
374   /** Mux configuration. */
375   LCD_Mux_TypeDef     mux;
376   /** Bias configuration. */
377   LCD_Bias_TypeDef    bias;
378   /** Wave configuration. */
379   LCD_Wave_TypeDef    wave;
380 #if defined(_SILICON_LABS_32B_SERIES_0)
381   /** VLCD Select. */
382   LCD_VLCDSel_TypeDef vlcd;
383   /** Contrast Configuration. */
384   LCD_ConConf_TypeDef contrast;
385 #endif
386 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
387   /** Mode of operation. */
388   LCD_Mode_Typedef                      mode;
389   /** Charge redistribution cycles. */
390   LCD_ChargeRedistribution_TypeDef      chargeRedistribution;
391   /** Frame rate divider. */
392   uint8_t                               frameRateDivider;
393   /** Contrast level. */
394   int                                   contrastLevel;
395 #if defined(_SILICON_LABS_32B_SERIES_2)
396   /** Clock Prescaler. */
397   uint32_t                              clockPrescaler;
398 #endif
399 #endif
400 } LCD_Init_TypeDef;
401 
402 /** Default configuration for LCD initialization structure, enables 160 segments.  */
403 #if defined(_SILICON_LABS_32B_SERIES_0)
404 #define LCD_INIT_DEFAULT \
405   {                      \
406     true,                \
407     lcdMuxQuadruplex,    \
408     lcdBiasOneThird,     \
409     lcdWaveLowPower,     \
410     lcdVLCDSelVDD,       \
411     lcdConConfVLCD,      \
412   }
413 #endif
414 
415 #if defined(_SILICON_LABS_32B_SERIES_1)
416 #define LCD_INIT_DEFAULT           \
417   {                                \
418     true,                          \
419     lcdMuxOctaplex,                \
420     lcdBiasOneFourth,              \
421     lcdWaveLowPower,               \
422     lcdModeNoExtCap,               \
423     lcdChargeRedistributionEnable, \
424     LCD_DEFAULT_FRAME_RATE_DIV,    \
425     LCD_DEFAULT_CONTRAST           \
426   }
427 #endif
428 
429 #if defined(_SILICON_LABS_32B_SERIES_2)
430 #define LCD_INIT_DEFAULT           \
431   {                                \
432     true,                          \
433     lcdMuxQuadruplex,              \
434     lcdBiasOneFourth,              \
435     lcdWaveLowPower,               \
436     lcdModeStepDown,               \
437     lcdChargeRedistributionEnable, \
438     LCD_DEFAULT_FRAME_RATE_DIV,    \
439     LCD_DEFAULT_CONTRAST,          \
440     LCD_DEFAULT_CLOCK_PRESCALER    \
441   }
442 #endif
443 
444 /*******************************************************************************
445  *****************************   PROTOTYPES   **********************************
446  ******************************************************************************/
447 
448 void LCD_Init(const LCD_Init_TypeDef *lcdInit);
449 #if defined(_SILICON_LABS_32B_SERIES_0)
450 void LCD_VLCDSelect(LCD_VLCDSel_TypeDef vlcd);
451 #endif
452 void LCD_UpdateCtrl(LCD_UpdateCtrl_TypeDef ud);
453 void LCD_FrameCountInit(const LCD_FrameCountInit_TypeDef *fcInit);
454 void LCD_AnimInit(const LCD_AnimInit_TypeDef *animInit);
455 
456 #if defined(_SILICON_LABS_32B_SERIES_0)
457 void LCD_SegmentRangeEnable(LCD_SegmentRange_TypeDef segment, bool enable);
458 #endif
459 #if defined(_SILICON_LABS_32B_SERIES_2)
460 void LCD_SegmentEnable(uint32_t seg_nbr, bool enable);
461 void LCD_ComEnable(uint8_t com, bool enable);
462 void LCD_DmaModeSet(LCD_DmaMode_Typedef mode);
463 #endif
464 void LCD_SegmentSet(int com, int bit, bool enable);
465 void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits);
466 #if defined(_LCD_SEGD0H_MASK)
467 void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits);
468 #endif
469 void LCD_ContrastSet(int level);
470 void LCD_BiasSet(LCD_Bias_TypeDef bias);
471 #if defined(_SILICON_LABS_32B_SERIES_0)
472 void LCD_VBoostSet(LCD_VBoostLevel_TypeDef vboost);
473 #endif
474 #if defined(LCD_CTRL_DSC)
475 void LCD_BiasSegmentSet(int segment, int biasLevel);
476 void LCD_BiasComSet(int com, int biasLevel);
477 #endif
478 #if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LABS_32B_SERIES_2)
479 void LCD_ModeSet(LCD_Mode_Typedef mode);
480 void LCD_ChargeRedistributionCyclesSet(uint8_t cycles);
481 #endif
482 
483 #if defined(_SILICON_LABS_32B_SERIES_2)
484 /***************************************************************************//**
485  * @brief
486  *    Wait for load synchronization completion.
487  *
488  * @note
489  *    Doing any writes to HV registers will not go through and will cause a
490  *    bus fault.
491  ******************************************************************************/
LCD_LoadBusyWait(void)492 __STATIC_INLINE void LCD_LoadBusyWait(void)
493 {
494   while (LCD->STATUS & _LCD_STATUS_LOADBUSY_MASK) ;
495 }
496 #endif
497 
498 #if defined(_SILICON_LABS_32B_SERIES_2)
499 /***************************************************************************//**
500  * @brief
501  *    Wait for the LCD to complete resetting or disabling procedure.
502  ******************************************************************************/
LCD_ReadyWait(void)503 __STATIC_INLINE void LCD_ReadyWait(void)
504 {
505   while ((LCD->SWRST & _LCD_SWRST_RESETTING_MASK)
506          || (LCD->EN & _LCD_EN_DISABLING_MASK)
507          || (LCD->STATUS & _LCD_STATUS_LOADBUSY_MASK)) {
508     // Wait for all synchronizations to finish
509   }
510 }
511 #endif
512 
513 /***************************************************************************//**
514  * @brief
515  *   Enable or disable LCD controller.
516  *
517  * @param[in] enable
518  *   If true, enables LCD controller with current configuration. If false,
519  *   disables LCD controller. Enable CMU clock for LCD for correct
520  *   operation.
521  ******************************************************************************/
LCD_Enable(bool enable)522 __STATIC_INLINE void LCD_Enable(bool enable)
523 {
524 #if defined(_SILICON_LABS_32B_SERIES_2)
525   if (enable) {
526     LCD->EN_SET = LCD_EN_EN;
527   } else {
528     /* Wait for internal synchronization completion. */
529     LCD_LoadBusyWait();
530 
531     LCD->EN_CLR = LCD_EN_EN;
532     while (LCD->EN & _LCD_EN_DISABLING_MASK) {
533     }
534   }
535 #else
536 
537 #if defined(LCD_HAS_SET_CLEAR)
538   if (enable) {
539     LCD->CTRL_SET = LCD_CTRL_EN;
540   } else {
541     LCD->CTRL_CLR = LCD_CTRL_EN;
542   }
543 #else
544   if (enable) {
545     LCD->CTRL |= LCD_CTRL_EN;
546   } else {
547     LCD->CTRL &= ~LCD_CTRL_EN;
548   }
549 #endif // LCD_HAS_SET_CLEAR
550 
551 #endif // _SILICON_LABS_32B_SERIES_2
552 }
553 
554 #if defined(_SILICON_LABS_32B_SERIES_2)
555 /***************************************************************************//**
556  * @brief
557  *   Reset the LCD.
558  ******************************************************************************/
LCD_Reset(void)559 __STATIC_INLINE void LCD_Reset(void)
560 {
561   LCD->SWRST_SET = LCD_SWRST_SWRST;
562 
563   /* Wait for reset to complete. */
564   while ((LCD->SWRST & _LCD_SWRST_RESETTING_MASK)) {
565   }
566 }
567 #endif
568 
569 /***************************************************************************//**
570  * @brief
571  *   Enable or disable LCD Animation feature.
572  *
573  * @param[in] enable
574  *   Boolean true enables animation, false disables animation.
575  ******************************************************************************/
LCD_AnimEnable(bool enable)576 __STATIC_INLINE void LCD_AnimEnable(bool enable)
577 {
578 #if defined(LCD_HAS_SET_CLEAR)
579   if (enable) {
580     LCD->BACTRL_SET = LCD_BACTRL_AEN;
581   } else {
582     LCD->BACTRL_CLR = LCD_BACTRL_AEN;
583   }
584 #else
585   if (enable) {
586     LCD->BACTRL |= LCD_BACTRL_AEN;
587   } else {
588     LCD->BACTRL &= ~LCD_BACTRL_AEN;
589   }
590 #endif
591 }
592 
593 /***************************************************************************//**
594  * @brief
595  *   Enable or disable the LCD blink.
596  *
597  * @param[in] enable
598  *   Boolean true enables blink, false disables blink.
599  ******************************************************************************/
LCD_BlinkEnable(bool enable)600 __STATIC_INLINE void LCD_BlinkEnable(bool enable)
601 {
602 #if defined(LCD_HAS_SET_CLEAR)
603   if (enable) {
604     LCD->BACTRL_SET = LCD_BACTRL_BLINKEN;
605   } else {
606     LCD->BACTRL_CLR = LCD_BACTRL_BLINKEN;
607   }
608 #else
609   if (enable) {
610     LCD->BACTRL |= LCD_BACTRL_BLINKEN;
611   } else {
612     LCD->BACTRL &= ~LCD_BACTRL_BLINKEN;
613   }
614 #endif
615 }
616 
617 /***************************************************************************//**
618  * @brief
619  *   Disable all segments while keeping segment state.
620  *
621  * @param[in] enable
622  *   Boolean true clears all segments, boolean false restores all segment lines.
623  ******************************************************************************/
LCD_BlankEnable(bool enable)624 __STATIC_INLINE void LCD_BlankEnable(bool enable)
625 {
626 #if defined(LCD_HAS_SET_CLEAR)
627   if (enable) {
628     LCD->BACTRL_SET = LCD_BACTRL_BLANK;
629   } else {
630     LCD->BACTRL_CLR = LCD_BACTRL_BLANK;
631   }
632 #else
633   if (enable) {
634     LCD->BACTRL |= LCD_BACTRL_BLANK;
635   } else {
636     LCD->BACTRL &= ~LCD_BACTRL_BLANK;
637   }
638 #endif
639 }
640 
641 /***************************************************************************//**
642  * @brief
643  *   Enable or disable LCD Frame counter.
644  *
645  * @param[in] enable
646  *   Boolean true enables frame counter, false disables frame counter.
647  ******************************************************************************/
LCD_FrameCountEnable(bool enable)648 __STATIC_INLINE void LCD_FrameCountEnable(bool enable)
649 {
650 #if defined(_SILICON_LABS_32B_SERIES_2)
651   /* Ensure no internal sync is in progress. */
652   LCD_LoadBusyWait();
653 #endif
654 
655 #if defined(LCD_HAS_SET_CLEAR)
656   if (enable) {
657     LCD->BACTRL_SET = LCD_BACTRL_FCEN;
658   } else {
659     LCD->BACTRL_CLR = LCD_BACTRL_FCEN;
660   }
661 #else
662   if (enable) {
663     LCD->BACTRL |= LCD_BACTRL_FCEN;
664   } else {
665     LCD->BACTRL &= ~LCD_BACTRL_FCEN;
666   }
667 #endif
668 }
669 
670 #if defined(_SILICON_LABS_32B_SERIES_2)
671 /***************************************************************************//**
672  * @brief
673  *   Enable or disable the LCD Display counter.
674  *
675  * @param[in] enable
676  *   Boolean true enables display counter, false disables display counter.
677  ******************************************************************************/
LCD_DisplayCountEnable(bool enable)678 __STATIC_INLINE void LCD_DisplayCountEnable(bool enable)
679 {
680   /* Ensure no internal sync is in progress. */
681   LCD_LoadBusyWait();
682 
683   if (enable) {
684     LCD->BACTRL_SET = LCD_BACTRL_DISPLAYCNTEN;
685   } else {
686     LCD->BACTRL_CLR = LCD_BACTRL_DISPLAYCNTEN;
687   }
688 }
689 #endif
690 
691 /***************************************************************************//**
692  * @brief
693  *   Return the current animation state.
694  *
695  * @return
696  *   Animation state, in range 0-15.
697  ******************************************************************************/
LCD_AnimState(void)698 __STATIC_INLINE int LCD_AnimState(void)
699 {
700   return (int)(LCD->STATUS & _LCD_STATUS_ASTATE_MASK) >> _LCD_STATUS_ASTATE_SHIFT;
701 }
702 
703 /***************************************************************************//**
704  * @brief
705  *   Return the current blink state.
706  *
707  * @return
708  *   Return value is 1 if segments are enabled, 0 if disabled.
709  ******************************************************************************/
LCD_BlinkState(void)710 __STATIC_INLINE int LCD_BlinkState(void)
711 {
712   return (int)(LCD->STATUS & _LCD_STATUS_BLINK_MASK) >> _LCD_STATUS_BLINK_SHIFT;
713 }
714 
715 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
716 /***************************************************************************//**
717  * @brief
718  *   When set, LCD registers will not be updated until cleared.
719  *
720  * @param[in] enable
721  *   When enable is true, update is stopped; when false, all registers are
722  *   updated.
723  ******************************************************************************/
LCD_FreezeEnable(bool enable)724 __STATIC_INLINE void LCD_FreezeEnable(bool enable)
725 {
726   if (enable) {
727     LCD->FREEZE = LCD_FREEZE_REGFREEZE_FREEZE;
728   } else {
729     LCD->FREEZE = LCD_FREEZE_REGFREEZE_UPDATE;
730   }
731 }
732 #endif
733 
734 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
735 /***************************************************************************//**
736  * @brief
737  *   Return SYNCBUSY bits, indicating which registers have pending updates.
738  *
739  * @return
740  *   Bit fields for LCD registers that have pending updates.
741  ******************************************************************************/
LCD_SyncBusyGet(void)742 __STATIC_INLINE uint32_t LCD_SyncBusyGet(void)
743 {
744   return LCD->SYNCBUSY;
745 }
746 #endif
747 
748 #if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
749 /***************************************************************************//**
750  * @brief
751  *   Poll LCD SYNCBUSY flags until the flag has been cleared.
752  *
753  * @param[in] flags
754  *   Bit fields for LCD registers that will be updated before we continue.
755  ******************************************************************************/
LCD_SyncBusyDelay(uint32_t flags)756 __STATIC_INLINE void LCD_SyncBusyDelay(uint32_t flags)
757 {
758   while (LCD->SYNCBUSY & flags) ;
759 }
760 #endif
761 
762 #if defined(_SILICON_LABS_32B_SERIES_2)
763 /***************************************************************************//**
764  * @brief
765  *   Start the synchronization process.
766  *
767  * @param[in] autoload
768  *   Flag indicating if the synchronization is started manually with CMD.LOAD
769  *   (false) or if the synchronization is managed automatically by Auto Load
770  *   (true).
771  *
772  * @param[in] load_addr
773  *   Address which will start the synchronization from CLK_BUS to CLK_PER
774  *   when Auto Load is selected. This argument has no effect if 'autoload' is
775  *   false.
776  ******************************************************************************/
LCD_SyncStart(bool autoload,LCD_LoadAddr_TypeDef load_addr)777 __STATIC_INLINE void LCD_SyncStart(bool autoload, LCD_LoadAddr_TypeDef load_addr)
778 {
779   /* Ensure no synchronization in progress. */
780   LCD_LoadBusyWait();
781 
782   if (autoload) {
783     LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
784     LCD_ReadyWait();
785     LCD->UPDATECTRL_CLR = _LCD_UPDATECTRL_LOADADDR_MASK;
786     LCD->UPDATECTRL |= load_addr;
787     LCD->UPDATECTRL_SET = LCD_UPDATECTRL_AUTOLOAD;
788     LCD_Enable(true);
789   } else {
790     /* Start synchronization from HV registers to CLK_PER domain. */
791     LCD->CMD = LCD_CMD_LOAD;
792   }
793 }
794 #endif
795 
796 #if defined(_SILICON_LABS_32B_SERIES_2)
797 /***************************************************************************//**
798  * @brief
799  *   Stop the synchronization process.
800  *
801  * @param[in] autoload
802  *   Flag indicating if the synchronization is stopped manually with CMD.CLEAR
803  *   (false) or if the synchronization managed by Auto Load is disabled (true).
804  ******************************************************************************/
LCD_SyncStop(bool autoload)805 __STATIC_INLINE void LCD_SyncStop(bool autoload)
806 {
807   if (autoload) {
808     /* Autoload cannot be disabled if synchronization in progress. */
809     LCD_LoadBusyWait();
810 
811     LCD->UPDATECTRL_CLR = LCD_UPDATECTRL_AUTOLOAD;
812     LCD->UPDATECTRL_CLR = _LCD_UPDATECTRL_LOADADDR_MASK;
813   } else {
814     LCD->CMD = LCD_CMD_CLEAR;
815   }
816 }
817 #endif
818 
819 /***************************************************************************//**
820  * @brief
821  *    Get pending LCD interrupt flags.
822  *
823  * @return
824  *   Pending LCD interrupt sources. Returns a set of interrupt flags OR-ed
825  *   together for multiple interrupt sources in the LCD module (LCD_IFS_nnn).
826  ******************************************************************************/
LCD_IntGet(void)827 __STATIC_INLINE uint32_t LCD_IntGet(void)
828 {
829   return LCD->IF;
830 }
831 
832 /***************************************************************************//**
833  * @brief
834  *   Get enabled and pending LCD interrupt flags.
835  *
836  * @details
837  *   Useful for handling more interrupt sources in the same interrupt handler.
838  *
839  * @note
840  *   Event bits are not cleared by the use of this function.
841  *
842  * @return
843  *   Pending and enabled LCD interrupt sources.
844  *   Return value is the bitwise AND combination of
845  *   - the OR combination of enabled interrupt sources in LCD_IEN_nnn
846  *   register (LCD_IEN_nnn) and
847  *   - the bitwise OR combination of valid interrupt flags of LCD module
848  *   (LCD_IF_nnn).
849  ******************************************************************************/
LCD_IntGetEnabled(void)850 __STATIC_INLINE uint32_t LCD_IntGetEnabled(void)
851 {
852   uint32_t ien;
853 
854   /* Store the LCD->IEN in temporary variable to define the explicit order
855    * of volatile accesses. */
856   ien = LCD->IEN;
857 
858   /* Bitwise AND of pending and enabled interrupts */
859   return LCD->IF & ien;
860 }
861 
862 /***************************************************************************//**
863  * @brief
864  *    Set one or more pending LCD interrupts from SW.
865  *
866  * @param[in] flags
867  *   LCD interrupt sources to set to pending. Use a set of interrupt flags
868  *   OR-ed together to set multiple interrupt sources for the LCD module
869  *   (LCD_IFS_nnn).
870  ******************************************************************************/
LCD_IntSet(uint32_t flags)871 __STATIC_INLINE void LCD_IntSet(uint32_t flags)
872 {
873 #if defined(_SILICON_LABS_32B_SERIES_2)
874 #if defined(LCD_HAS_SET_CLEAR)
875   LCD->IF_SET = flags;
876 #else
877   LCD->IF |= flags;
878 #endif // LCD_HAS_SET_CLEAR
879 #else
880   LCD->IFS = flags;
881 #endif
882 }
883 
884 /***************************************************************************//**
885  * @brief
886  *    Enable LCD interrupts.
887  *
888  * @param[in] flags
889  *   LCD interrupt sources to enable. Use a set of interrupt flags OR-ed
890  *   together to set multiple interrupt sources for LCD module
891  *   (LCD_IFS_nnn).
892  ******************************************************************************/
LCD_IntEnable(uint32_t flags)893 __STATIC_INLINE void LCD_IntEnable(uint32_t flags)
894 {
895 #if defined(LCD_HAS_SET_CLEAR)
896   LCD->IEN_SET = flags;
897 #else
898   LCD->IEN |= flags;
899 #endif
900 }
901 
902 /***************************************************************************//**
903  * @brief
904  *    Disable LCD interrupts.
905  *
906  * @param[in] flags
907  *   LCD interrupt sources to disable. Use a set of interrupt flags OR-ed
908  *   together to disable multiple interrupt sources for LCD module
909  *   (LCD_IFS_nnn).
910  ******************************************************************************/
LCD_IntDisable(uint32_t flags)911 __STATIC_INLINE void LCD_IntDisable(uint32_t flags)
912 {
913 #if defined(LCD_HAS_SET_CLEAR)
914   LCD->IEN_CLR = flags;
915 #else
916   LCD->IEN &= ~flags;
917 #endif
918 }
919 
920 /***************************************************************************//**
921  * @brief
922  *   Clear one or more interrupt flags.
923  *
924  * @param[in] flags
925  *   LCD interrupt sources to clear. Use a set of interrupt flags OR-ed
926  *   together to clear multiple interrupt sources for LCD module
927  *   (LCD_IFS_nnn).
928  ******************************************************************************/
LCD_IntClear(uint32_t flags)929 __STATIC_INLINE void LCD_IntClear(uint32_t flags)
930 {
931 #if defined(_SILICON_LABS_32B_SERIES_2)
932 #if defined(LCD_HAS_SET_CLEAR)
933   LCD->IF_CLR = flags;
934 #else
935   LCD->IF &= ~flags;
936 #endif // LCD_HAS_SET_CLEAR
937 #else
938   LCD->IFC = flags;
939 #endif
940 }
941 
942 #if defined(LCD_CTRL_DSC)
943 /***************************************************************************//**
944  * @brief
945  *   Enable or disable LCD Direct Segment Control.
946  *
947  * @param[in] enable
948  *   If true, enables LCD controller Direct Segment Control
949  *   Segment and COM line bias levels need to be set explicitly with
950  *   LCD_BiasSegmentSet() and LCD_BiasComSet() function calls respectively.
951  ******************************************************************************/
LCD_DSCEnable(bool enable)952 __STATIC_INLINE void LCD_DSCEnable(bool enable)
953 {
954 #if defined(_SILICON_LABS_32B_SERIES_2)
955   LCD_Enable(false); /* Ensure LCD disabled before writing WSTATIC fields. */
956   LCD_ReadyWait();
957 #endif
958 
959 #if defined(LCD_HAS_SET_CLEAR)
960   if (enable) {
961     LCD->CTRL_SET = LCD_CTRL_DSC;
962   } else {
963     LCD->CTRL_CLR = LCD_CTRL_DSC;
964   }
965 #else
966   if (enable) {
967     LCD->CTRL |= LCD_CTRL_DSC;
968   } else {
969     LCD->CTRL &= ~LCD_CTRL_DSC;
970   }
971 #endif
972 
973 #if defined(_SILICON_LABS_32B_SERIES_2)
974   LCD_Enable(true);
975 #endif
976 }
977 
978 #endif
979 
980 /** @} (end addtogroup lcd) */
981 
982 #ifdef __cplusplus
983 }
984 #endif
985 
986 #endif /* defined(LCD_COUNT) && (LCD_COUNT > 0) */
987 
988 #endif /* EM_LCD_H */
989