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