1 /**************************************************************************//**
2  * @file     lcd.c
3  * @version  V3.00
4  * @brief    Liquid-Crystal Display(LCD) driver source file
5  *
6  * @copyright SPDX-License-Identifier: Apache-2.0
7  * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
8  *****************************************************************************/
9 #include "NuMicro.h"
10 
11 
12 /** @addtogroup Standard_Driver Standard Driver
13   @{
14 */
15 
16 /** @addtogroup LCD_Driver LCD Driver
17   @{
18 */
19 
20 
21 /// @cond HIDDEN_SYMBOLS
22 
23 /** @addtogroup LCD_EXPORTED_VARIABLES LCD Exported Variables
24   @{
25 */
26 /*---------------------------------------------------------------------------------------------------------*/
27 /* Global file scope (static) variables                                                                    */
28 /*---------------------------------------------------------------------------------------------------------*/
29 static uint32_t g_LCDFrameRate;
30 
31 /**@}*/ /* end of group LCD_EXPORTED_VARIABLES */
32 
33 /// @endcond /* HIDDEN_SYMBOLS */
34 
35 
36 /** @addtogroup LCD_EXPORTED_FUNCTIONS LCD Exported Functions
37   @{
38 */
39 
40 /**
41   * @brief      LCD Initialization routine
42   *
43   * @param[in]  pLCDCfg Specify the LCD property. It includes:
44   *                     u32SrcFreq: Clock source frequency of LCD controller.
45   *                     u32ComDuty: LCD COM duty ratio selection. Valid values are:
46   *                                 - \ref LCD_COM_DUTY_1_1
47   *                                 - \ref LCD_COM_DUTY_1_2
48   *                                 - \ref LCD_COM_DUTY_1_3
49   *                                 - \ref LCD_COM_DUTY_1_4
50   *                                 - \ref LCD_COM_DUTY_1_5
51   *                                 - \ref LCD_COM_DUTY_1_6
52   *                                 - \ref LCD_COM_DUTY_1_7
53   *                                 - \ref LCD_COM_DUTY_1_8
54   *                     u32BiasLevel: LCD Bias level selection. Valid values are:
55   *                                     - \ref LCD_BIAS_LV_1_2
56   *                                     - \ref LCD_BIAS_LV_1_3
57   *                                     - \ref LCD_BIAS_LV_1_4
58   *                     u32Framerate: Specify the target LCD operating frame rate (Hz).
59   *                     u32WaveformType: Specify the LCD waveform type. Valid values are:
60   *                                         - \ref LCD_WAVEFORM_TYPE_A_NORMAL
61   *                                         - \ref LCD_WAVEFORM_TYPE_B_NORMAL
62   *                                         - \ref LCD_WAVEFORM_TYPE_A_INVERSE
63   *                                         - \ref LCD_WAVEFORM_TYPE_B_INVERSE
64   *                     u32IntSrc: Interrupt source selection. Valid values are:
65   *                                 - \ref LCD_DISABLE_ALL_INT
66   *                                 - \ref LCD_FRAME_COUNTING_END_INT
67   *                                 - \ref LCD_FRAME_END_INT
68   *                                 - \ref LCD_CPTOUT_INT
69   *                                 - \ref LCD_ENABLE_ALL_INT
70   *                     u32DrivingMode: LCD operation driving mode selection. Valid values are:
71   *                                 - \ref LCD_LOW_DRIVING_AND_BUF_OFF
72   *                                 - \ref LCD_HIGH_DRIVING_AND_BUF_OFF
73   *                                 - \ref LCD_HIGH_DRIVING_AND_BUF_OFF_AND_PWR_SAVING
74   *                                 - \ref LCD_HIGH_DRIVING_AND_BUF_OFF_AND_PWR_SAVING
75   *                                 - \ref LCD_LOW_DRIVING_AND_BUF_ON_AND_PWR_SAVING
76   *                     u32VSrc: Voltage source selection. Valid values are:
77   *                                 - \ref LCD_VOLTAGE_SOURCE_VLCD
78   *                                 - \ref LCD_VOLTAGE_SOURCE_AVDD
79   *                                 - \ref LCD_VOLTAGE_SOURCE_CP
80   *
81   * @return     The real LCD operating frame rate. Or 0 means LCD_Open failed.
82   *
83   * @details    This function will configure the LCD properties for driving the LCD display well.
84   *             After that, user can perform \ref LCD_ENABLE_DISPLAY() to enable LCD controller for LCD display.
85   */
LCD_Open(S_LCD_CFG_T * pLCDCfg)86 uint32_t LCD_Open(S_LCD_CFG_T *pLCDCfg)
87 {
88     uint32_t u32ComNum, u32FreqLCD, u32FreqDiv;
89 
90     /* Display LCD display first */
91     LCD_DISABLE_DISPLAY();
92 
93     /* Turn all segments off */
94     LCD_SetAllPixels(0);
95 
96     /* Set com and bias */
97     LCD->PCTL = (pLCDCfg->u32ComDuty | pLCDCfg->u32BiasLevel);
98 
99     /* Set waveform type */
100     LCD_WAVEFORM_TYPE(pLCDCfg->u32WaveformType);
101 
102     /* Configure interrupt source */
103     LCD->INTEN = pLCDCfg->u32IntSrc;
104 
105     /* Set driving mode */
106     LCD_DRIVING_MODE(pLCDCfg->u32DrivingMode);
107 
108     /* Select voltage source */
109     LCD_VOLTAGE_SOURCE(pLCDCfg->u32VSrc);
110 
111     /*
112         An example for specify frame rate.
113             If LCD source clock is 32768Hz, COM duty 4.
114             In type-A:
115                 One frame rate 32Hz, frame end event rate 32Hz.
116                     32 = (1/4) * F_LCD * (1/2)
117                     F_LCD = 32 * 4 * 2 = 256 = (32768 / F_Div)
118                     F_Div = (32768 / F_LCD) = 128
119             In type-B:
120                 Each even/odd frame rate 32Hz, frame end event rate 16Hz.
121                     32 = (1/4) * F_LCD
122                     F_LCD = 32 * 4 = (32768 / F_Div)
123                     F_Div = (32768 / F_LCD) = 256
124     */
125     u32ComNum = ((pLCDCfg->u32ComDuty & LCD_PCTL_DUTY_Msk) >> LCD_PCTL_DUTY_Pos) + 1;
126     if((pLCDCfg->u32WaveformType & LCD_PCTL_TYPE_Msk) == LCD_PCTL_TYPE_Msk)
127     {
128         /* In type-B */
129 
130         /* Calculate LCD operation frequency */
131         u32FreqLCD = (pLCDCfg->u32Framerate * u32ComNum);
132 
133         /* Calculate possible freq. divider */
134         u32FreqDiv = (pLCDCfg->u32SrcFreq  / u32FreqLCD);
135 
136         if(u32FreqDiv > 1024)
137         {
138             /* Invalid frame rate */
139             g_LCDFrameRate = 0ul;
140         }
141         else
142         {
143             /* Set freq. divider */
144             LCD_SET_FREQDIV(u32FreqDiv);
145 
146             /* Calculate target frame rate */
147             g_LCDFrameRate = pLCDCfg->u32SrcFreq / (u32ComNum * u32FreqDiv);
148         }
149     }
150     else
151     {
152         /* In type-A */
153 
154         /* Calculate LCD operation frequency */
155         u32FreqLCD = (pLCDCfg->u32Framerate * u32ComNum) * 2;
156 
157         /* Calculate possible freq. divider */
158         u32FreqDiv = (pLCDCfg->u32SrcFreq  / u32FreqLCD);
159 
160         if(u32FreqDiv > 1024)
161         {
162             /* Invalid frame rate */
163             g_LCDFrameRate = 0ul;
164         }
165         else
166         {
167             /* Set freq. divider */
168             LCD_SET_FREQDIV(u32FreqDiv);
169 
170             /* Calculate target frame rate */
171             g_LCDFrameRate = (pLCDCfg->u32SrcFreq  / (u32ComNum * u32FreqDiv)) / 2;
172         }
173     }
174 
175     return g_LCDFrameRate;
176 }
177 
178 /**
179   * @brief      Disable LCD Display
180   *
181   * @param[in]  None
182   *
183   * @return     None
184   *
185   * @details    This function is used to disable LCD display.
186   */
LCD_Close(void)187 void LCD_Close(void)
188 {
189     LCD_DISABLE_DISPLAY();
190 }
191 
192 /**
193   * @brief      Enables a Segment Display
194   *
195   * @param[in]  u32Com      Specify COM number. Valid values are from 0~7.
196   * @param[in]  u32Seg      Specify Segment number. Valid values are from 0~43.
197   * @param[in]  u32OnFlag   0 : Segment not display
198   *                         1 : Segment display
199   *
200   * @return     None
201   *
202   * @details    This function is used to enable specified segment display on the LCD.
203   */
LCD_SetPixel(uint32_t u32Com,uint32_t u32Seg,uint32_t u32OnFlag)204 void LCD_SetPixel(uint32_t u32Com, uint32_t u32Seg, uint32_t u32OnFlag)
205 {
206     uint32_t seg_num = (u32Seg / 4);
207     uint32_t seg_shift = (8 * (u32Seg - (4 * seg_num)));
208 
209     if(seg_num < 11)
210     {
211         if(u32OnFlag)
212         {
213             LCD->DATA[seg_num] |= ((uint32_t)(1 << u32Com) << seg_shift);
214         }
215         else
216         {
217             LCD->DATA[seg_num] &= (~((uint32_t)(1 << u32Com) << seg_shift));
218         }
219     }
220 }
221 
222 /**
223   * @brief      Enable/Disable all LCD segments
224   *
225   * @param[in]  u32OnOff    0 : Disable all segments display
226   *                         1 : Enable all segments display
227   *
228   * @return     None
229   *
230   * @details    This function is used to enable/disable all LCD segments display.
231   */
LCD_SetAllPixels(uint32_t u32OnOff)232 void LCD_SetAllPixels(uint32_t u32OnOff)
233 {
234     uint32_t i, u32Value;
235 
236     if(u32OnOff == 1ul)
237     {
238         u32Value = 0xFFFFFFFFul;
239     }
240     else
241     {
242         u32Value = 0x00000000ul;
243     }
244 
245     for(i = 0; i < 11; i++)
246         LCD->DATA[i] = u32Value;
247 }
248 
249 /**
250   * @brief      Enable LCD Blinking
251   *
252   * @param[in]  u32ms       Blinking period time(unit: ms)
253   *
254   * @return     Real blinking period time(ms)
255   *
256   * @details    This function is used to enable blink display with specified period.
257   */
LCD_EnableBlink(uint32_t u32ms)258 uint32_t LCD_EnableBlink(uint32_t u32ms)
259 {
260     uint32_t u32OneCountPeriod, u32TargetCounts;
261 
262     if((LCD->PCTL & LCD_PCTL_TYPE_Msk) == LCD_PCTL_TYPE_Msk)
263     {
264         /* In type-B */
265         u32OneCountPeriod = (1000 * 2) / g_LCDFrameRate; // ms
266     }
267     else
268     {
269         /* In type-A */
270         u32OneCountPeriod = 1000 / g_LCDFrameRate; // ms
271     }
272 
273     u32TargetCounts = (u32ms / u32OneCountPeriod);
274     if(u32TargetCounts == 0)
275         u32TargetCounts = 1;
276     if(u32TargetCounts > 1024)
277         u32TargetCounts = 1024;
278 
279     LCD_SET_FRAME_COUNTING_VALUE(u32TargetCounts);
280 
281     /* Enable blink display */
282     LCD_BLINKING_ON();
283 
284     return (u32OneCountPeriod * u32TargetCounts);
285 }
286 
287 /**
288   * @brief      Disable LCD Blinking
289   *
290   * @param[in]  None
291   *
292   * @return     None
293   *
294   * @details    This function is used to disable LCD blink display.
295   */
LCD_DisableBlink(void)296 void LCD_DisableBlink(void)
297 {
298     /* Disable blink display */
299     LCD_BLINKING_OFF();
300 }
301 
302 /**
303   * @brief      Enable LCD Interrupt
304   *
305   * @param[in]  IntSrc      Interrupt Source. It could be a combination of
306   *                             \ref LCD_FRAME_COUNTING_END_INT, \ref LCD_FRAME_END_INT and \ref LCD_CPTOUT_INT.
307   *
308   * @return     None
309   *
310   * @details    This function is used to enable the specific LCD interrupt.
311   */
LCD_EnableInt(uint32_t u32IntSrc)312 void LCD_EnableInt(uint32_t u32IntSrc)
313 {
314     LCD->INTEN |= (u32IntSrc);
315 }
316 
317 /**
318   * @brief      Disable LCD Interrupt
319   *
320   * @param[in]  IntSrc      Interrupt Source. It could be a combination of
321   *                             \ref LCD_FRAME_COUNTING_END_INT, \ref LCD_FRAME_END_INT and \ref LCD_CPTOUT_INT.
322   *
323   * @return     None
324   *
325   * @details    This function is used to disable the specific LCD interrupt.
326   */
LCD_DisableInt(uint32_t u32IntSrc)327 void LCD_DisableInt(uint32_t u32IntSrc)
328 {
329     LCD->INTEN &= ~(u32IntSrc);
330 }
331 
332 
333 /**@}*/ /* end of group LCD_EXPORTED_FUNCTIONS */
334 
335 /**@}*/ /* end of group LCD_Driver */
336 
337 /**@}*/ /* end of group Standard_Driver */
338