1 /*!
2     \file    gd32l23x_ctc.c
3     \brief   CTC 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_ctc.h"
36 
37 #define CTC_FLAG_MASK            ((uint32_t)0x00000700U)
38 
39 /* CTC register bit offset */
40 #define CTC_TRIMVALUE_OFFSET     ((uint32_t)8U)
41 #define CTC_TRIM_VALUE_OFFSET    ((uint32_t)8U)
42 #define CTC_REFCAP_OFFSET        ((uint32_t)16U)
43 #define CTC_LIMIT_VALUE_OFFSET   ((uint32_t)16U)
44 
45 /*!
46     \brief      reset CTC clock trim controller
47     \param[in]  none
48     \param[out] none
49     \retval     none
50 */
ctc_deinit(void)51 void ctc_deinit(void)
52 {
53     /* reset CTC */
54     rcu_periph_reset_enable(RCU_CTCRST);
55     rcu_periph_reset_disable(RCU_CTCRST);
56 }
57 
58 /*!
59     \brief      enable CTC trim counter
60     \param[in]  none
61     \param[out] none
62     \retval     none
63 */
ctc_counter_enable(void)64 void ctc_counter_enable(void)
65 {
66     CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
67 }
68 
69 /*!
70     \brief      disable CTC trim counter
71     \param[in]  none
72     \param[out] none
73     \retval     none
74 */
ctc_counter_disable(void)75 void ctc_counter_disable(void)
76 {
77     CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
78 }
79 
80 /*!
81     \brief      configure the IRC48M trim value
82     \param[in]  ctc_trim_value: 8-bit IRC48M trim value
83       \arg        0x00 - 0x3F
84     \param[out] none
85     \retval     none
86 */
ctc_irc48m_trim_value_config(uint8_t trim_value)87 void ctc_irc48m_trim_value_config(uint8_t trim_value)
88 {
89     /* clear TRIMVALUE bits */
90     CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
91     /* set TRIMVALUE bits */
92     CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
93 }
94 
95 /*!
96     \brief      generate software reference source sync pulse
97     \param[in]  none
98     \param[out] none
99     \retval     none
100 */
ctc_software_refsource_pulse_generate(void)101 void ctc_software_refsource_pulse_generate(void)
102 {
103     CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
104 }
105 
106 /*!
107     \brief      configure hardware automatically trim mode
108     \param[in]  hardmode:
109                 only one parameter can be selected which is shown as below:
110       \arg        CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
111       \arg        CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
112     \param[out] none
113     \retval     none
114 */
ctc_hardware_trim_mode_config(uint32_t hardmode)115 void ctc_hardware_trim_mode_config(uint32_t hardmode)
116 {
117     CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
118     CTC_CTL0 |= (uint32_t)hardmode;
119 }
120 
121 /*!
122     \brief      configure reference signal source polarity
123     \param[in]  polarity:
124                 only one parameter can be selected which is shown as below:
125       \arg        CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
126       \arg        CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
127     \param[out] none
128     \retval     none
129 */
ctc_refsource_polarity_config(uint32_t polarity)130 void ctc_refsource_polarity_config(uint32_t polarity)
131 {
132     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
133     CTC_CTL1 |= (uint32_t)polarity;
134 }
135 
136 /*!
137     \brief      select reference signal source
138     \param[in]  refs:
139                 only one parameter can be selected which is shown as below:
140       \arg        CTC_REFSOURCE_GPIO: GPIO is selected
141       \arg        CTC_REFSOURCE_LXTAL: LXTAL is selected
142       \arg        CTC_REFSOURCE_USBSOF: USBD_SOF is selected
143     \param[out] none
144     \retval     none
145 */
ctc_refsource_signal_select(uint32_t refs)146 void ctc_refsource_signal_select(uint32_t refs)
147 {
148     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
149     CTC_CTL1 |= (uint32_t)refs;
150 }
151 
152 /*!
153     \brief      configure reference signal source prescaler
154     \param[in]  prescaler:
155                 only one parameter can be selected which is shown as below:
156       \arg        CTC_REFSOURCE_PSC_OFF: reference signal not divided
157       \arg        CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
158       \arg        CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
159       \arg        CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
160       \arg        CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
161       \arg        CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
162       \arg        CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
163       \arg        CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
164     \param[out] none
165     \retval     none
166 */
ctc_refsource_prescaler_config(uint32_t prescaler)167 void ctc_refsource_prescaler_config(uint32_t prescaler)
168 {
169     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
170     CTC_CTL1 |= (uint32_t)prescaler;
171 }
172 
173 /*!
174     \brief      configure clock trim base limit value
175     \param[in]  limit_value: 8-bit clock trim base limit value
176       \arg        0x00 - 0xFF
177     \param[out] none
178     \retval     none
179 */
ctc_clock_limit_value_config(uint8_t limit_value)180 void ctc_clock_limit_value_config(uint8_t limit_value)
181 {
182     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
183     CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
184 }
185 
186 /*!
187     \brief      configure CTC counter reload value
188     \param[in]  reload_value: 16-bit CTC counter reload value
189       \arg        0x0000 - 0xFFFF
190     \param[out] none
191     \retval     none
192 */
ctc_counter_reload_value_config(uint16_t reload_value)193 void ctc_counter_reload_value_config(uint16_t reload_value)
194 {
195     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
196     CTC_CTL1 |= (uint32_t)reload_value;
197 }
198 
199 /*!
200     \brief      read CTC counter capture value when reference sync pulse occurred
201     \param[in]  none
202     \param[out] none
203     \retval     the 16-bit CTC counter capture value
204 */
ctc_counter_capture_value_read(void)205 uint16_t ctc_counter_capture_value_read(void)
206 {
207     uint16_t capture_value = 0U;
208     capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP) >> CTC_REFCAP_OFFSET);
209     return (capture_value);
210 }
211 
212 /*!
213     \brief      read CTC trim counter direction when reference sync pulse occurred
214     \param[in]  none
215     \param[out] none
216     \retval     FlagStatus: SET or RESET
217       \arg        SET: CTC trim counter direction is down-counting
218       \arg        RESET: CTC trim counter direction is up-counting
219 */
ctc_counter_direction_read(void)220 FlagStatus ctc_counter_direction_read(void)
221 {
222     if(RESET != (CTC_STAT & CTC_STAT_REFDIR)) {
223         return SET;
224     } else {
225         return RESET;
226     }
227 }
228 
229 /*!
230     \brief      read CTC counter reload value
231     \param[in]  none
232     \param[out] none
233     \retval     the 16-bit CTC counter reload value
234 */
ctc_counter_reload_value_read(void)235 uint16_t ctc_counter_reload_value_read(void)
236 {
237     uint16_t reload_value = 0U;
238     reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
239     return (reload_value);
240 }
241 
242 /*!
243     \brief      read the IRC48M trim value
244     \param[in]  none
245     \param[out] none
246     \retval     the 8-bit IRC48M trim value
247 */
ctc_irc48m_trim_value_read(void)248 uint8_t ctc_irc48m_trim_value_read(void)
249 {
250     uint8_t trim_value = 0U;
251     trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
252     return (trim_value);
253 }
254 
255 /*!
256     \brief      enable the CTC interrupt
257     \param[in]  interrupt: CTC interrupt enable
258                 one or more parameters can be selected which are shown as below:
259       \arg        CTC_INT_CKOK: clock trim OK interrupt enable
260       \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
261       \arg        CTC_INT_ERR: error interrupt enable
262       \arg        CTC_INT_EREF: expect reference interrupt enable
263     \param[out] none
264     \retval     none
265 */
ctc_interrupt_enable(uint32_t interrupt)266 void ctc_interrupt_enable(uint32_t interrupt)
267 {
268     CTC_CTL0 |= (uint32_t)interrupt;
269 }
270 
271 /*!
272     \brief      disable the CTC interrupt
273     \param[in]  interrupt: CTC interrupt enable source
274                 one or more parameters can be selected which are shown as below:
275       \arg        CTC_INT_CKOK: clock trim OK interrupt enable
276       \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
277       \arg        CTC_INT_ERR: error interrupt enable
278       \arg        CTC_INT_EREF: expect reference interrupt enable
279     \param[out] none
280     \retval     none
281 */
ctc_interrupt_disable(uint32_t interrupt)282 void ctc_interrupt_disable(uint32_t interrupt)
283 {
284     CTC_CTL0 &= (uint32_t)(~interrupt);
285 }
286 
287 /*!
288     \brief      get CTC interrupt flag
289     \param[in]  int_flag the CTC interrupt flag
290                 only one parameter can be selected which is shown as below:
291       \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
292       \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
293       \arg        CTC_INT_FLAG_ERR: error interrupt
294       \arg        CTC_INT_FLAG_EREF: expect reference interrupt
295       \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
296       \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
297       \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
298     \param[out] none
299     \retval     FlagStatus: SET or RESET
300 */
ctc_interrupt_flag_get(uint32_t int_flag)301 FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
302 {
303     uint32_t interrupt_flag = 0U, intenable = 0U;
304 
305     /* check whether the interrupt is enabled */
306     if(RESET != (int_flag & CTC_FLAG_MASK)) {
307         intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
308     } else {
309         intenable = CTC_CTL0 & int_flag;
310     }
311 
312     /* get interrupt flag status */
313     interrupt_flag = CTC_STAT & int_flag;
314 
315     if(interrupt_flag && intenable) {
316         return SET;
317     } else {
318         return RESET;
319     }
320 }
321 
322 /*!
323     \brief      clear CTC interrupt flag
324     \param[in]  int_flag: the CTC interrupt flag
325                 only one parameter can be selected which is shown as below:
326       \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
327       \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
328       \arg        CTC_INT_FLAG_ERR: error interrupt
329       \arg        CTC_INT_FLAG_EREF: expect reference interrupt
330       \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
331       \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
332       \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
333     \param[out] none
334     \retval     none
335 */
ctc_interrupt_flag_clear(uint32_t int_flag)336 void ctc_interrupt_flag_clear(uint32_t int_flag)
337 {
338     if(RESET != (int_flag & CTC_FLAG_MASK)) {
339         CTC_INTC |= CTC_INTC_ERRIC;
340     } else {
341         CTC_INTC |= int_flag;
342     }
343 }
344 
345 /*!
346     \brief      get CTC flag
347     \param[in]  flag: the CTC flag
348                 only one parameter can be selected which is shown as below:
349       \arg        CTC_FLAG_CKOK: clock trim OK flag
350       \arg        CTC_FLAG_CKWARN: clock trim warning flag
351       \arg        CTC_FLAG_ERR: error flag
352       \arg        CTC_FLAG_EREF: expect reference flag
353       \arg        CTC_FLAG_CKERR: clock trim error bit
354       \arg        CTC_FLAG_REFMISS: reference sync pulse miss
355       \arg        CTC_FLAG_TRIMERR: trim value error bit
356     \param[out] none
357     \retval     FlagStatus: SET or RESET
358 */
ctc_flag_get(uint32_t flag)359 FlagStatus ctc_flag_get(uint32_t flag)
360 {
361     if(RESET != (CTC_STAT & flag)) {
362         return SET;
363     } else {
364         return RESET;
365     }
366 }
367 
368 /*!
369     \brief      clear CTC flag
370     \param[in]  flag: the CTC flag
371                 only one parameter can be selected which is shown as below:
372       \arg        CTC_FLAG_CKOK: clock trim OK flag
373       \arg        CTC_FLAG_CKWARN: clock trim warning flag
374       \arg        CTC_FLAG_ERR: error flag
375       \arg        CTC_FLAG_EREF: expect reference flag
376       \arg        CTC_FLAG_CKERR: clock trim error bit
377       \arg        CTC_FLAG_REFMISS: reference sync pulse miss
378       \arg        CTC_FLAG_TRIMERR: trim value error bit
379     \param[out] none
380     \retval     none
381 */
ctc_flag_clear(uint32_t flag)382 void ctc_flag_clear(uint32_t flag)
383 {
384     if(RESET != (flag & CTC_FLAG_MASK)) {
385         CTC_INTC |= CTC_INTC_ERRIC;
386     } else {
387         CTC_INTC |= flag;
388     }
389 }
390