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