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