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