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