1 /*!
2     \file    gd32f4xx_ctc.c
3     \brief   CTC driver
4 
5     \version 2016-08-15, V1.0.0, firmware for GD32F4xx
6     \version 2018-12-12, V2.0.0, firmware for GD32F4xx
7     \version 2020-09-30, V2.1.0, firmware for GD32F4xx
8     \version 2022-03-09, V3.0.0, firmware for GD32F4xx
9 */
10 
11 /*
12     Copyright (c) 2022, GigaDevice Semiconductor Inc.
13 
14     Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16 
17     1. Redistributions of source code must retain the above copyright notice, this
18        list of conditions and the following disclaimer.
19     2. Redistributions in binary form must reproduce the above copyright notice,
20        this list of conditions and the following disclaimer in the documentation
21        and/or other materials provided with the distribution.
22     3. Neither the name of the copyright holder nor the names of its contributors
23        may be used to endorse or promote products derived from this software without
24        specific prior written permission.
25 
26     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37 
38 #include "gd32f4xx_ctc.h"
39 
40 #define CTC_FLAG_MASK            ((uint32_t)0x00000700U)
41 
42 /* CTC register bit offset */
43 #define CTC_TRIMVALUE_OFFSET     ((uint32_t)8U)
44 #define CTC_TRIM_VALUE_OFFSET    ((uint32_t)8U)
45 #define CTC_REFCAP_OFFSET        ((uint32_t)16U)
46 #define CTC_LIMIT_VALUE_OFFSET   ((uint32_t)16U)
47 
48 /*!
49     \brief    reset CTC clock trim controller
50     \param[in]  none
51     \param[out] none
52     \retval     none
53 */
ctc_deinit(void)54 void ctc_deinit(void)
55 {
56     /* reset CTC */
57     rcu_periph_reset_enable(RCU_CTCRST);
58     rcu_periph_reset_disable(RCU_CTCRST);
59 }
60 
61 /*!
62     \brief    enable CTC trim counter
63     \param[in]  none
64     \param[out] none
65     \retval     none
66 */
ctc_counter_enable(void)67 void ctc_counter_enable(void)
68 {
69     CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
70 }
71 
72 /*!
73     \brief    disable CTC trim counter
74     \param[in]  none
75     \param[out] none
76     \retval     none
77 */
ctc_counter_disable(void)78 void ctc_counter_disable(void)
79 {
80     CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
81 }
82 
83 /*!
84     \brief    configure the IRC48M trim value
85     \param[in]  ctc_trim_value: 8-bit IRC48M trim value
86       \arg        0x00 - 0x3F
87     \param[out] none
88     \retval     none
89 */
ctc_irc48m_trim_value_config(uint8_t trim_value)90 void ctc_irc48m_trim_value_config(uint8_t trim_value)
91 {
92     /* clear TRIMVALUE bits */
93     CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
94     /* set TRIMVALUE bits */
95     CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
96 }
97 
98 /*!
99     \brief    generate software reference source sync pulse
100     \param[in]  none
101     \param[out] none
102     \retval     none
103 */
ctc_software_refsource_pulse_generate(void)104 void ctc_software_refsource_pulse_generate(void)
105 {
106     CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
107 }
108 
109 /*!
110     \brief    configure hardware automatically trim mode
111     \param[in]  hardmode:
112                 only one parameter can be selected which is shown as below:
113       \arg        CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
114       \arg        CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
115     \param[out] none
116     \retval     none
117 */
ctc_hardware_trim_mode_config(uint32_t hardmode)118 void ctc_hardware_trim_mode_config(uint32_t hardmode)
119 {
120     CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
121     CTC_CTL0 |= (uint32_t)hardmode;
122 }
123 
124 /*!
125     \brief    configure reference signal source polarity
126     \param[in]  polarity:
127                 only one parameter can be selected which is shown as below:
128       \arg        CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
129       \arg        CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
130     \param[out] none
131     \retval     none
132 */
ctc_refsource_polarity_config(uint32_t polarity)133 void ctc_refsource_polarity_config(uint32_t polarity)
134 {
135     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
136     CTC_CTL1 |= (uint32_t)polarity;
137 }
138 
139 /*!
140     \brief    select USBFS or USBHS SOF signal
141     \param[in]  usbsof:
142       \arg        CTC_USBSOFSEL_USBHS: USBHS SOF signal is selected
143       \arg        CTC_USBSOFSEL_USBFS: USBFS SOF signal is selected
144     \param[out] none
145     \retval     none
146 */
ctc_usbsof_signal_select(uint32_t usbsof)147 void ctc_usbsof_signal_select(uint32_t usbsof)
148 {
149     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_USBSOFSEL);
150     CTC_CTL1 |= (uint32_t)usbsof;
151 }
152 
153 /*!
154     \brief    select reference signal source
155     \param[in]  refs:
156                 only one parameter can be selected which is shown as below:
157       \arg        CTC_REFSOURCE_GPIO: GPIO is selected
158       \arg        CTC_REFSOURCE_LXTAL: LXTAL is selected
159       \arg        CTC_REFSOURCE_USBSOF: USBSOF is selected
160     \param[out] none
161     \retval     none
162 */
ctc_refsource_signal_select(uint32_t refs)163 void ctc_refsource_signal_select(uint32_t refs)
164 {
165     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
166     CTC_CTL1 |= (uint32_t)refs;
167 }
168 
169 /*!
170     \brief    configure reference signal source prescaler
171     \param[in]  prescaler:
172                 only one parameter can be selected which is shown as below:
173       \arg        CTC_REFSOURCE_PSC_OFF: reference signal not divided
174       \arg        CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
175       \arg        CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
176       \arg        CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
177       \arg        CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
178       \arg        CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
179       \arg        CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
180       \arg        CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
181     \param[out] none
182     \retval     none
183 */
ctc_refsource_prescaler_config(uint32_t prescaler)184 void ctc_refsource_prescaler_config(uint32_t prescaler)
185 {
186     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
187     CTC_CTL1 |= (uint32_t)prescaler;
188 }
189 
190 /*!
191     \brief    configure clock trim base limit value
192     \param[in]  limit_value: 8-bit clock trim base limit value
193       \arg        0x00 - 0xFF
194     \param[out] none
195     \retval     none
196 */
ctc_clock_limit_value_config(uint8_t limit_value)197 void ctc_clock_limit_value_config(uint8_t limit_value)
198 {
199     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
200     CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
201 }
202 
203 /*!
204     \brief    configure CTC counter reload value
205     \param[in]  reload_value: 16-bit CTC counter reload value
206       \arg        0x0000 - 0xFFFF
207     \param[out] none
208     \retval     none
209 */
ctc_counter_reload_value_config(uint16_t reload_value)210 void ctc_counter_reload_value_config(uint16_t reload_value)
211 {
212     CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
213     CTC_CTL1 |= (uint32_t)reload_value;
214 }
215 
216 /*!
217     \brief    read CTC counter capture value when reference sync pulse occurred
218     \param[in]  none
219     \param[out] none
220     \retval     the 16-bit CTC counter capture value
221 */
ctc_counter_capture_value_read(void)222 uint16_t ctc_counter_capture_value_read(void)
223 {
224     uint16_t capture_value = 0U;
225     capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP) >> CTC_REFCAP_OFFSET);
226     return (capture_value);
227 }
228 
229 /*!
230     \brief    read CTC trim counter direction when reference sync pulse occurred
231     \param[in]  none
232     \param[out] none
233     \retval     FlagStatus: SET or RESET
234       \arg        SET: CTC trim counter direction is down-counting
235       \arg        RESET: CTC trim counter direction is up-counting
236 */
ctc_counter_direction_read(void)237 FlagStatus ctc_counter_direction_read(void)
238 {
239     if(RESET != (CTC_STAT & CTC_STAT_REFDIR)) {
240         return SET;
241     } else {
242         return RESET;
243     }
244 }
245 
246 /*!
247     \brief    read CTC counter reload value
248     \param[in]  none
249     \param[out] none
250     \retval     the 16-bit CTC counter reload value
251 */
ctc_counter_reload_value_read(void)252 uint16_t ctc_counter_reload_value_read(void)
253 {
254     uint16_t reload_value = 0U;
255     reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
256     return (reload_value);
257 }
258 
259 /*!
260     \brief    read the IRC48M trim value
261     \param[in]  none
262     \param[out] none
263     \retval     the 8-bit IRC48M trim value
264 */
ctc_irc48m_trim_value_read(void)265 uint8_t ctc_irc48m_trim_value_read(void)
266 {
267     uint8_t trim_value = 0U;
268     trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
269     return (trim_value);
270 }
271 
272 /*!
273     \brief    enable the CTC interrupt
274     \param[in]  interrupt: CTC interrupt enable
275                 one or more parameters can be selected which are shown as below:
276       \arg        CTC_INT_CKOK: clock trim OK interrupt enable
277       \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
278       \arg        CTC_INT_ERR: error interrupt enable
279       \arg        CTC_INT_EREF: expect reference interrupt enable
280     \param[out] none
281     \retval     none
282 */
ctc_interrupt_enable(uint32_t interrupt)283 void ctc_interrupt_enable(uint32_t interrupt)
284 {
285     CTC_CTL0 |= (uint32_t)interrupt;
286 }
287 
288 /*!
289     \brief    disable the CTC interrupt
290     \param[in]  interrupt: CTC interrupt enable source
291                 one or more parameters can be selected which are shown as below:
292       \arg        CTC_INT_CKOK: clock trim OK interrupt enable
293       \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
294       \arg        CTC_INT_ERR: error interrupt enable
295       \arg        CTC_INT_EREF: expect reference interrupt enable
296     \param[out] none
297     \retval     none
298 */
ctc_interrupt_disable(uint32_t interrupt)299 void ctc_interrupt_disable(uint32_t interrupt)
300 {
301     CTC_CTL0 &= (uint32_t)(~interrupt);
302 }
303 
304 /*!
305     \brief    get CTC interrupt flag
306     \param[in]  int_flag: the CTC interrupt flag
307                 only one parameter can be selected which is shown as below:
308       \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
309       \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
310       \arg        CTC_INT_FLAG_ERR: error interrupt
311       \arg        CTC_INT_FLAG_EREF: expect reference interrupt
312       \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
313       \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
314       \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
315     \param[out] none
316     \retval     FlagStatus: SET or RESET
317 */
ctc_interrupt_flag_get(uint32_t int_flag)318 FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
319 {
320     uint32_t interrupt_flag = 0U, intenable = 0U;
321 
322     /* check whether the interrupt is enabled */
323     if(RESET != (int_flag & CTC_FLAG_MASK)) {
324         intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
325     } else {
326         intenable = CTC_CTL0 & int_flag;
327     }
328 
329     /* get interrupt flag status */
330     interrupt_flag = CTC_STAT & int_flag;
331 
332     if(interrupt_flag && intenable) {
333         return SET;
334     } else {
335         return RESET;
336     }
337 }
338 
339 /*!
340     \brief    clear CTC interrupt flag
341     \param[in]  int_flag: the CTC interrupt flag
342                 only one parameter can be selected which is shown as below:
343       \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
344       \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
345       \arg        CTC_INT_FLAG_ERR: error interrupt
346       \arg        CTC_INT_FLAG_EREF: expect reference interrupt
347       \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
348       \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
349       \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
350     \param[out] none
351     \retval     none
352 */
ctc_interrupt_flag_clear(uint32_t int_flag)353 void ctc_interrupt_flag_clear(uint32_t int_flag)
354 {
355     if(RESET != (int_flag & CTC_FLAG_MASK)) {
356         CTC_INTC |= CTC_INTC_ERRIC;
357     } else {
358         CTC_INTC |= int_flag;
359     }
360 }
361 
362 /*!
363     \brief    get CTC flag
364     \param[in]  flag: the CTC flag
365                 only one parameter can be selected which is shown as below:
366       \arg        CTC_FLAG_CKOK: clock trim OK flag
367       \arg        CTC_FLAG_CKWARN: clock trim warning flag
368       \arg        CTC_FLAG_ERR: error flag
369       \arg        CTC_FLAG_EREF: expect reference flag
370       \arg        CTC_FLAG_CKERR: clock trim error bit
371       \arg        CTC_FLAG_REFMISS: reference sync pulse miss
372       \arg        CTC_FLAG_TRIMERR: trim value error bit
373     \param[out] none
374     \retval     FlagStatus: SET or RESET
375 */
ctc_flag_get(uint32_t flag)376 FlagStatus ctc_flag_get(uint32_t flag)
377 {
378     if(RESET != (CTC_STAT & flag)) {
379         return SET;
380     } else {
381         return RESET;
382     }
383 }
384 
385 /*!
386     \brief    clear CTC flag
387     \param[in]  flag: the CTC flag
388                 only one parameter can be selected which is shown as below:
389       \arg        CTC_FLAG_CKOK: clock trim OK flag
390       \arg        CTC_FLAG_CKWARN: clock trim warning flag
391       \arg        CTC_FLAG_ERR: error flag
392       \arg        CTC_FLAG_EREF: expect reference flag
393       \arg        CTC_FLAG_CKERR: clock trim error bit
394       \arg        CTC_FLAG_REFMISS: reference sync pulse miss
395       \arg        CTC_FLAG_TRIMERR: trim value error bit
396     \param[out] none
397     \retval     none
398 */
ctc_flag_clear(uint32_t flag)399 void ctc_flag_clear(uint32_t flag)
400 {
401     if(RESET != (flag & CTC_FLAG_MASK)) {
402         CTC_INTC |= CTC_INTC_ERRIC;
403     } else {
404         CTC_INTC |= flag;
405     }
406 }
407