1 /*!
2     \file    gd32l23x_slcd.c
3     \brief   SLCD driver
4 
5     \version 2021-08-04, V1.0.0, firmware for GD32L23x
6 */
7 
8 /*
9     Copyright (c) 2021, GigaDevice Semiconductor Inc.
10 
11     Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13 
14     1. Redistributions of source code must retain the above copyright notice, this
15        list of conditions and the following disclaimer.
16     2. Redistributions in binary form must reproduce the above copyright notice,
17        this list of conditions and the following disclaimer in the documentation
18        and/or other materials provided with the distribution.
19     3. Neither the name of the copyright holder nor the names of its contributors
20        may be used to endorse or promote products derived from this software without
21        specific prior written permission.
22 
23     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34 
35 #include "gd32l23x_slcd.h"
36 
37 /*!
38     \brief      reset SLCD register
39     \param[in]  none
40     \param[out] none
41     \retval     none
42 */
slcd_deinit(void)43 void slcd_deinit(void)
44 {
45     /* reset PMU */
46     rcu_periph_reset_enable(RCU_SLCDRST);
47     rcu_periph_reset_disable(RCU_SLCDRST);
48 }
49 
50 /*!
51     \brief      enable SLCD interface
52     \param[in]  none
53     \param[out] none
54     \retval     none
55 */
slcd_enable(void)56 void slcd_enable(void)
57 {
58     SLCD_CTL |= SLCD_CTL_SLCDON;
59 }
60 
61 /*!
62     \brief      disable SLCD interface
63     \param[in]  none
64     \param[out] none
65     \retval     none
66 */
slcd_disable(void)67 void slcd_disable(void)
68 {
69     SLCD_CTL &= ~SLCD_CTL_SLCDON;
70 }
71 
72 /*!
73     \brief      initialize SLCD interface
74     \param[in]  prescaler: the SLCD prescaler
75                 only one parameters can be selected which are shown as below:
76       \arg        SLCD_PRESCALER_x(x=1,2,4,8...32768)
77     \param[in]  divider: the SLCD divider
78                 only one parameters can be selected which are shown as below:
79       \arg        SLCD_DIVIDER_x(x=16,17,18,19...31)
80     \param[in]  duty: the SLCD duty
81                 only one parameters can be selected which are shown as below:
82     \arg        SLCD_DUTY_STATIC: static duty
83     \arg        SLCD_DUTY_1_x(x=2,3,4,8,6): 1/x duty
84     \param[in]  bias: the SLCD voltage bias
85                 only one parameters can be selected which are shown as below:
86     \arg        SLCD_BIAS_1_x(x=2,3,4): 1/x voltage bias
87     \param[out] none
88     \retval     none
89 */
slcd_init(uint32_t prescaler,uint32_t divider,uint32_t duty,uint32_t bias)90 void slcd_init(uint32_t prescaler, uint32_t divider, uint32_t duty, uint32_t bias)
91 {
92     uint32_t reg;
93     /* configure SLCD_CFG register */
94     reg = SLCD_CFG;
95     reg &= ~(SLCD_CFG_PSC | SLCD_CFG_DIV);
96     reg |= prescaler | divider;
97     SLCD_CFG = reg;
98     /* configure SLCD_CTL register */
99     reg = SLCD_CTL;
100     reg &= ~(SLCD_CTL_BIAS | SLCD_CTL_DUTY);
101     reg |= duty | bias;
102     SLCD_CTL = reg;
103 }
104 
105 /*!
106     \brief      enable SLCD enhance mode
107     \param[in]  none
108     \param[out] none
109     \retval     none
110 */
slcd_enhance_mode_enable(void)111 void slcd_enhance_mode_enable(void)
112 {
113     SLCD_CTL |= SLCD_CTL_VODEN;
114 }
115 
116 /*!
117     \brief      disable SLCD enhance mode
118     \param[in]  none
119     \param[out] none
120     \retval     none
121 */
slcd_enhance_mode_disable(void)122 void slcd_enhance_mode_disable(void)
123 {
124     SLCD_CTL &= ~SLCD_CTL_VODEN;
125 }
126 
127 /*!
128     \brief      select SLCD bias voltage
129     \param[in]  bias_voltage: the SLCD voltage bias
130                 only one parameter can be selected which is shown as below:
131       \arg        SLCD_BIAS_1_4: 1/4 voltage bias
132       \arg        SLCD_BIAS_1_2: 1/2 voltage bias
133       \arg        SLCD_BIAS_1_3: 1/3 voltage bias
134     \param[out] none
135     \retval     none
136 */
slcd_bias_voltage_select(uint32_t bias_voltage)137 void slcd_bias_voltage_select(uint32_t bias_voltage)
138 {
139     SLCD_CTL &= ~(SLCD_CTL_BIAS);
140     SLCD_CTL |= bias_voltage;
141 }
142 
143 /*!
144     \brief      select SLCD duty
145     \param[in]  duty: duty select
146                 only one parameter can be selected which is shown as below:
147       \arg        SLCD_DUTY_STATIC: static duty
148       \arg        SLCD_DUTY_1_2: 1/2 duty
149       \arg        SLCD_DUTY_1_3: 1/3 duty
150       \arg        SLCD_DUTY_1_4: 1/4 duty
151       \arg        SLCD_DUTY_1_6: 1/6 duty
152       \arg        SLCD_DUTY_1_8: 1/8 duty
153     \param[out] none
154     \retval     none
155 */
slcd_duty_select(uint32_t duty)156 void slcd_duty_select(uint32_t duty)
157 {
158     SLCD_CTL &= ~(SLCD_CTL_DUTY);
159     SLCD_CTL |= duty;
160 }
161 
162 /*!
163     \brief      configure SLCD input clock
164                 fSLCD = finclk/(pow(2, PRE)* DIV)
165     \param[in]  prescaler: the prescaler factor
166                 only one parameter can be selected which is shown as below:
167       \arg        SLCD_PRESCALER_1: PRE = 0
168       \arg        SLCD_PRESCALER_2: PRE = 1
169       \arg        SLCD_PRESCALER_4: PRE = 2
170       \arg        SLCD_PRESCALER_8: PRE = 3
171       \arg        SLCD_PRESCALER_16: PRE = 4
172       \arg        SLCD_PRESCALER_32: PRE = 5
173       \arg        SLCD_PRESCALER_64: PRE = 6
174       \arg        SLCD_PRESCALER_128: PRE = 7
175       \arg        SLCD_PRESCALER_256: PRE = 8
176       \arg        SLCD_PRESCALER_512: PRE = 9
177       \arg        SLCD_PRESCALER_1024: PRE = 10
178       \arg        SLCD_PRESCALER_2048: PRE = 11
179       \arg        SLCD_PRESCALER_4096: PRE = 12
180       \arg        SLCD_PRESCALER_8192: PRE = 13
181       \arg        SLCD_PRESCALER_16384: PRE = 14
182       \arg        SLCD_PRESCALER_32768: PRE = 15
183     \param[in]  divider: the divider factor
184                 only one parameter can be selected which is shown as below:
185       \arg        SLCD_DIVIDER_x: x= 16..31, DIV = 16..31
186     \param[out] none
187     \retval     none
188 */
slcd_clock_config(uint32_t prescaler,uint32_t divider)189 void slcd_clock_config(uint32_t prescaler, uint32_t divider)
190 {
191     uint32_t reg;
192 
193     /* config the prescaler and the divider */
194     reg = SLCD_CFG;
195     reg &= ~(SLCD_CFG_PSC | SLCD_CFG_DIV);
196     reg |= (prescaler | divider);
197     SLCD_CFG = reg;
198 }
199 
200 /*!
201     \brief      configure SLCD blink mode
202     \param[in]  mode: blink mode
203                 only one parameter can be selected which is shown as below:
204       \arg        SLCD_BLINKMODE_OFF: blink disabled
205       \arg        SLCD_BLINKMODE_SEG0_COM0: blink enabled on SEG[0], COM[0]
206       \arg        SLCD_BLINKMODE_SEG0_ALLCOM: blink enabled on SEG[0], all COM
207       \arg        SLCD_BLINKMODE_ALLSEG_ALLCOM: blink enabled on all SEG and all COM
208     \param[in]  blink_divider: the divider factor
209                 only one parameter can be selected which is shown as below:
210       \arg        SLCD_BLINK_FREQUENCY_DIV8: blink frequency = fSLCD/8
211       \arg        SLCD_BLINK_FREQUENCY_DIV16: blink frequency = fSLCD/16
212       \arg        SLCD_BLINK_FREQUENCY_DIV32: blink frequency = fSLCD/32
213       \arg        SLCD_BLINK_FREQUENCY_DIV64: blink frequency = fSLCD/64
214       \arg        SLCD_BLINK_FREQUENCY_DIV128: blink frequency = fSLCD/128
215       \arg        SLCD_BLINK_FREQUENCY_DIV256: blink frequency = fSLCD/256
216       \arg        SLCD_BLINK_FREQUENCY_DIV512: blink frequency = fSLCD/512
217       \arg        SLCD_BLINK_FREQUENCY_DIV1024: blink frequency = fSLCD/1024
218     \param[out] none
219     \retval     none
220 */
slcd_blink_mode_config(uint32_t mode,uint32_t blink_divider)221 void slcd_blink_mode_config(uint32_t mode, uint32_t blink_divider)
222 {
223     uint32_t reg;
224     reg = SLCD_CFG;
225     reg &= ~(SLCD_CFG_BLKMOD | SLCD_CFG_BLKDIV);
226     reg |= mode | blink_divider;
227     SLCD_CFG = reg;
228 }
229 
230 /*!
231     \brief      configure slcd_contrast_ratio
232     \param[in]  contrast: the slcd contrast
233                 only one parameters can be selected which are shown as below:
234       \arg        SLCD_CONTRAST_LEVEL0:Maximum Voltage = 2.65V
235       \arg        SLCD_CONTRAST_LEVEL1:Maximum Voltage = 2.80V
236       \arg        SLCD_CONTRAST_LEVEL2:Maximum Voltage = 2.92V
237       \arg        SLCD_CONTRAST_LEVEL3:Maximum Voltage = 3.08V
238       \arg        SLCD_CONTRAST_LEVEL4:Maximum Voltage = 3.23V
239       \arg        SLCD_CONTRAST_LEVEL5:Maximum Voltage = 3.37V
240       \arg        SLCD_CONTRAST_LEVEL6:Maximum Voltage = 3.52V
241       \arg        SLCD_CONTRAST_LEVEL7:Maximum Voltage = 3.67V
242     \param[out] none
243     \retval     none
244 */
slcd_contrast_ratio_config(uint32_t contrast_ratio)245 void slcd_contrast_ratio_config(uint32_t contrast_ratio)
246 {
247     uint32_t reg;
248     reg = SLCD_CFG;
249     reg &= ~SLCD_CFG_CONR;
250     reg |= contrast_ratio;
251     SLCD_CFG = reg;
252 }
253 
254 /*!
255     \brief      configure SLCD dead time duration
256     \param[in]  dead_time: configure the length of the dead time between frames
257                 only one parameter can be selected which is shown as below:
258       \arg        SLCD_DEADTIME_PERIOD_0: no dead time
259       \arg        SLCD_DEADTIME_PERIOD_1: 1 phase inserted between couple of frame
260       \arg        SLCD_DEADTIME_PERIOD_2: 2 phase inserted between couple of frame
261       \arg        SLCD_DEADTIME_PERIOD_3: 3 phase inserted between couple of frame
262       \arg        SLCD_DEADTIME_PERIOD_4: 4 phase inserted between couple of frame
263       \arg        SLCD_DEADTIME_PERIOD_5: 5 phase inserted between couple of frame
264       \arg        SLCD_DEADTIME_PERIOD_6: 6 phase inserted between couple of frame
265       \arg        SLCD_DEADTIME_PERIOD_7: 7 phase inserted between couple of frame
266     \param[out] none
267     \retval     none
268 */
slcd_dead_time_config(uint32_t dead_time)269 void slcd_dead_time_config(uint32_t dead_time)
270 {
271     uint32_t reg;
272 
273     /* config dead time duration */
274     reg = SLCD_CFG;
275     reg &= ~(SLCD_CFG_DTD);
276     reg |= dead_time;
277     SLCD_CFG = reg;
278 }
279 
280 /*!
281     \brief      configure SLCD pulse on duration
282     \param[in]  pulseonduration: specifies the slcd pulse on duration
283                 only one parameters can be selected which are shown as below:
284       \arg        SLCD_PULSEON_DURATION_0: pulse on duration = 0
285       \arg        SLCD_PULSEON_DURATION_1: pulse on duration = 1*1/fPRE
286       \arg        SLCD_PULSEON_DURATION_2: pulse on duration = 2*1/fPRE
287       \arg        SLCD_PULSEON_DURATION_3: pulse on duration = 3*1/fPRE
288       \arg        SLCD_PULSEON_DURATION_4: pulse on duration = 4*1/fPRE
289       \arg        SLCD_PULSEON_DURATION_5: pulse on duration = 5*1/fPRE
290       \arg        SLCD_PULSEON_DURATION_6: pulse on duration = 6*1/fPRE
291       \arg        SLCD_PULSEON_DURATION_7: pulse on duration = 7*1/fPRE
292     \param[out] none
293     \retval     none
294 */
slcd_pulse_on_duration_config(uint32_t duration)295 void slcd_pulse_on_duration_config(uint32_t duration)
296 {
297     uint32_t reg;
298     reg = SLCD_CFG;
299     reg &= ~SLCD_CFG_PULSE;
300     reg |= duration;
301     SLCD_CFG = reg;
302 }
303 
304 /*!
305     \brief      select SLCD common/segment pad
306     \param[in]  NewValue: ENABLE or DISABLE
307                 only one parameter can be selected which is shown as below:
308       \arg        ENABLE: LCD_COM[7:4] pad select LCD_SEG[31:28]
309       \arg        DISABLE: LCD_COM[7:4] pad select LCD_COM[7:4]
310     \param[out] none
311     \retval     none
312 */
slcd_com_seg_remap(ControlStatus newvalue)313 void slcd_com_seg_remap(ControlStatus newvalue)
314 {
315     if(ENABLE == newvalue) {
316         SLCD_CTL |= SLCD_CTL_COMS;
317     } else {
318         SLCD_CTL &= ~(SLCD_CTL_COMS);
319     }
320 }
321 
322 /*!
323     \brief      select SLCD voltage source
324     \param[in]  vsrc: specifies the slcd voltage source
325                 only one parameters can be selected which are shown as below:
326       \arg        SLCD_VOLTAGE_INTERNAL
327       \arg        SLCD_VOLTAGE_EXTERNAL
328     \param[out] none
329     \retval     none
330 */
slcd_voltage_source_select(uint8_t voltage_source)331 void slcd_voltage_source_select(uint8_t voltage_source)
332 {
333     if(SLCD_VOLTAGE_INTERNAL == voltage_source) {
334         SLCD_CTL &= ~SLCD_CTL_VSRC;
335     } else {
336         SLCD_CTL |= SLCD_CTL_VSRC;
337     }
338 }
339 
340 /*!
341     \brief      enable or disable permanent high drive
342     \param[in]  newvalue: ENABLE or DISABLE
343                 only one parameter can be selected which is shown as below:
344     \arg          ENBALE: enable permanent high drive
345     \arg          DISBALE: disable permanent high drive
346     \param[out] none
347     \retval     none
348 */
slcd_high_drive_config(ControlStatus newvalue)349 void slcd_high_drive_config(ControlStatus newvalue)
350 {
351     if(ENABLE == newvalue) {
352         SLCD_CFG |= SLCD_CFG_HDEN;
353     } else {
354         SLCD_CFG &= ~(SLCD_CFG_HDEN);
355     }
356 }
357 
358 /*!
359     \brief      write SLCD data register
360     \param[in]  register_number: refer to slcd_data_register_enum
361                 only one parameter can be selected which is shown as below:
362       \arg        SLCD_DATA_REG0: SLCD_DATA register 0
363       \arg        SLCD_DATA_REG1: SLCD_DATA Register 1
364       \arg        SLCD_DATA_REG2: SLCD_DATA register 2
365       \arg        SLCD_DATA_REG3: SLCD_DATA Register 3
366       \arg        SLCD_DATA_REG4: SLCD_DATA register 4
367       \arg        SLCD_DATA_REG5: SLCD_DATA Register 5
368       \arg        SLCD_DATA_REG6: SLCD_DATA register 6
369       \arg        SLCD_DATA_REG7: SLCD_DATA Register 7
370     \param[in]  data: the data write to the register
371     \param[out] none
372     \retval     none
373 */
slcd_data_register_write(slcd_data_register_enum register_number,uint32_t data)374 void slcd_data_register_write(slcd_data_register_enum register_number, uint32_t data)
375 {
376     /* wtite data word to DATA register */
377     SLCD_DATA0_7((uint32_t)register_number) = data;
378 }
379 
380 /*!
381     \brief      update SLCD data request
382     \param[in]  none
383     \param[out] none
384     \retval     none
385 */
slcd_data_update_request(void)386 void slcd_data_update_request(void)
387 {
388     SLCD_STAT |= SLCD_STAT_UPRF;
389 }
390 
391 /*!
392     \brief      get SLCD flags
393     \param[in]  flag: the slcd flags
394                 only one parameter can be selected which is shown as below:
395       \arg        SLCD_FLAG_ON: controller on flag
396       \arg        SLCD_FLAG_SO: start of frame flag
397       \arg        SLCD_FLAG_UPR: update data request flag
398       \arg        SLCD_FLAG_UPD: update data done flag
399       \arg        SLCD_FLAG_VRDY: voltage ready flag
400       \arg        SLCD_FLAG_SYN: SLCD_CFG register synchronization flag
401     \param[out] none
402     \retval     FlagStatus: SET or RESET
403 */
slcd_flag_get(uint32_t flag)404 FlagStatus slcd_flag_get(uint32_t flag)
405 {
406     if(RESET != (SLCD_STAT & flag)) {
407         return SET;
408     } else {
409         return RESET;
410     }
411 }
412 
413 /*!
414     \brief      clear SLCD flags
415     \param[in]  flag: the slcd flags
416                 one or more parameters can be selected which is shown as below:
417       \arg        SLCD_FLAG_SOF: start of frame flag
418       \arg        SLCD_FLAG_UPDF: update done flag
419     \param[out] none
420     \retval     none
421 */
slcd_flag_clear(uint32_t flag)422 void slcd_flag_clear(uint32_t flag)
423 {
424     SLCD_STATC = flag;
425 }
426 
427 /*!
428     \brief      enable SLCD interrupt
429     \param[in]  interrupt: slcd interrupt source
430                 one or more parameters can be selected which is shown as below:
431       \arg        SLCD_INT_SOF: start of frame interrupt
432       \arg        SLCD_INT_UPD: update done interrupt
433     \param[out] none
434     \retval     none
435 */
slcd_interrupt_enable(uint32_t interrupt)436 void slcd_interrupt_enable(uint32_t interrupt)
437 {
438     SLCD_CFG |= interrupt;
439 }
440 
441 /*!
442     \brief      disable SLCD interrupt
443     \param[in]  interrupt: slcd interrupt source
444                 one or more parameters can be selected which is shown as below:
445       \arg        SLCD_INT_SOF: start of frame interrupt
446       \arg        SLCD_INT_UPD: update done interrupt
447     \param[out] none
448     \retval     none
449 */
slcd_interrupt_disable(uint32_t interrupt)450 void slcd_interrupt_disable(uint32_t interrupt)
451 {
452     SLCD_CFG &= ~interrupt;
453 }
454 
455 /*!
456     \brief      get SLCD interrupt flags
457     \param[in]  int_flag: the slcd interrupt flag
458                 only one parameter can be selected which is shown as below:
459       \arg        SLCD_INT_FLAG_SOF: start of frame flag
460       \arg        SLCD_INT_FLAG_UPD: update data done flag
461     \param[out] none
462     \retval     FlagStatus: SET or RESET
463 */
slcd_interrupt_flag_get(uint32_t int_flag)464 FlagStatus slcd_interrupt_flag_get(uint32_t int_flag)
465 {
466     uint32_t val;
467     val = (SLCD_CFG & int_flag);
468     if((RESET != (SLCD_STAT & int_flag)) && (RESET != val)) {
469         return SET;
470     } else {
471         return RESET;
472     }
473 }
474 
475 /*!
476     \brief      clear SLCD interrupt flag
477     \param[in]  int_flag: the slcd interrupt flag
478                 one or more parameters can be selected which is shown as below:
479       \arg        SLCD_INT_FLAG_SOF: start of frame flag
480       \arg        SLCD_INT_FLAG_UPD: update data done flag
481     \param[out] none
482     \retval     none
483 */
slcd_interrupt_flag_clear(uint32_t int_flag)484 void slcd_interrupt_flag_clear(uint32_t int_flag)
485 {
486     SLCD_STATC = int_flag;
487 }
488