1 /**************************************************************************//**
2  * @file     timer_pwm.c
3  * @version  V3.01
4  * @brief    Timer PWM Controller(Timer PWM) driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
8  *****************************************************************************/
9 #include "NuMicro.h"
10 
11 
12 /** @addtogroup Standard_Driver Standard Driver
13   @{
14 */
15 
16 /** @addtogroup TIMER_PWM_Driver TIMER PWM Driver
17   @{
18 */
19 
20 /** @addtogroup TIMER_PWM_EXPORTED_FUNCTIONS TIMER PWM Exported Functions
21   @{
22 */
23 
24 /**
25   * @brief      Configure TPWM Output Frequency and Duty Cycle
26   *
27   * @param[in]  timer           The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
28   * @param[in]  u32Frequency    Target generator frequency.
29   * @param[in]  u32DutyCycle    Target generator duty cycle percentage. Valid range are between 0~100. 10 means 10%, 20 means 20%...
30   *
31   * @return     Nearest frequency clock in nano second
32   *
33   * @details    This API is used to configure TPWM output frequency and duty cycle in up count type and auto-reload operation mode.
34   * @note       This API is only available if Timer PWM counter clock source is from TMRx_CLK.
35   */
TPWM_ConfigOutputFreqAndDuty(TIMER_T * timer,uint32_t u32Frequency,uint32_t u32DutyCycle)36 uint32_t TPWM_ConfigOutputFreqAndDuty(TIMER_T *timer, uint32_t u32Frequency, uint32_t u32DutyCycle)
37 {
38     uint32_t u32PWMClockFreq, u32TargetFreq;
39     uint32_t u32Prescaler = 0x100UL, u32Period, u32CMP;
40 
41     if ((timer == TIMER0) || (timer == TIMER1))
42     {
43         u32PWMClockFreq = CLK_GetPCLK0Freq();
44     }
45     else
46     {
47         u32PWMClockFreq = CLK_GetPCLK1Freq();
48     }
49 
50     /* Calculate u8PERIOD and u8PSC */
51     for (u32Prescaler = 1; u32Prescaler <= 0x100UL; u32Prescaler++)
52     {
53         u32Period = (u32PWMClockFreq / u32Prescaler) / u32Frequency;
54 
55         /* If target u32Period is larger than 0x10000, need to use a larger prescaler */
56         if (u32Period > 0x10000UL)
57             continue;
58 
59         break;
60     }
61 
62     if (u32Prescaler == 0x101UL)
63     {
64         u32Prescaler = 0x100UL;
65         u32Period = 0x10000UL;
66     }
67 
68     /* Store return value here 'cos we're gonna change u32Prescaler & u32Period to the real value to fill into register */
69     u32TargetFreq = (u32PWMClockFreq / u32Prescaler) / u32Period;
70 
71     /* Set PWM to auto-reload mode */
72     timer->PWMCTL = (timer->PWMCTL & ~TIMER_PWMCTL_CNTMODE_Msk) | (TPWM_AUTO_RELOAD_MODE << TIMER_PWMCTL_CNTMODE_Pos);
73 
74     /* Convert to real register value */
75     TPWM_SET_PRESCALER(timer, (u32Prescaler - 1UL));
76 
77     TPWM_SET_PERIOD(timer, (u32Period - 1UL));
78 
79     if (u32DutyCycle)
80     {
81         u32CMP = (u32DutyCycle * u32Period) / 100UL;
82     }
83     else
84     {
85         u32CMP = 0UL;
86     }
87 
88     TPWM_SET_CMPDAT(timer, u32CMP);
89     return (u32TargetFreq);
90 }
91 
92 /**
93   * @brief      Enable TPWM Counter
94   *
95   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
96   *
97   * @return     None
98   *
99   * @details    This function is used to enable TPWM generator and start counter counting.
100   */
TPWM_EnableCounter(TIMER_T * timer)101 void TPWM_EnableCounter(TIMER_T *timer)
102 {
103     timer->PWMCTL |= TIMER_PWMCTL_CNTEN_Msk;
104 }
105 
106 /**
107   * @brief      Disable TPWM Generator
108   *
109   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
110   *
111   * @return     None
112   *
113   * @details This function is used to disable TPWM counter immediately by clear CNTEN (TIMERx_PWMCTL[0]) bit.
114   */
TPWM_DisableCounter(TIMER_T * timer)115 void TPWM_DisableCounter(TIMER_T *timer)
116 {
117     timer->PWMCTL &= ~TIMER_PWMCTL_CNTEN_Msk;
118 }
119 
120 /**
121   * @brief      Enable TPWM Trigger ADC/DAC/PDMA/LPADC
122   *
123   * @param[in]  timer           The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
124   * @param[in]  u32TargetMask   The mask of modules (EADC/DAC/PDMA/LPADC) trigger by TPWM, the combination of:
125   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGDAC_Msk
126   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGEADC_Msk
127   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGPDMA_Msk
128   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGLPADC_Msk
129   * @param[in]  u32Condition    The condition to trigger EADC/DAC/PDMA/LPADC. It could be one of following conditions:
130   *                                 - \ref TPWM_TRIGGER_AT_PERIOD_POINT
131   *                                 - \ref TPWM_TRIGGER_AT_COMPARE_POINT
132   *                                 - \ref TPWM_TRIGGER_AT_PERIOD_OR_COMPARE_POINT
133   * @return     None
134   *
135   * @details    This function is used to enable specified counter event to trigger ADC/DAC/PDMA/LPADC.
136   */
TPWM_EnableTrigger(TIMER_T * timer,uint32_t u32TargetMask,uint32_t u32Condition)137 void TPWM_EnableTrigger(TIMER_T *timer, uint32_t u32TargetMask, uint32_t u32Condition)
138 {
139     timer->PWMTRGCTL &= ~(TIMER_PWMTRGCTL_PWMTRGDAC_Msk | TIMER_PWMTRGCTL_PWMTRGEADC_Msk | TIMER_PWMTRGCTL_PWMTRGPDMA_Msk | TIMER_PWMTRGCTL_PWMTRGLPADC_Msk | TIMER_PWMTRGCTL_TRGSEL_Msk);
140     timer->PWMTRGCTL |= (u32TargetMask) | (u32Condition);
141 }
142 
143 /**
144   * @brief      Disable Trigger ADC/DAC/PDMA/LPADC
145   *
146   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
147   * @param[in]  u32TargetMask   The mask of modules (EADC/DAC/PDMA/LPADC) trigger by TPWM, the combination of:
148   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGDAC_Msk
149   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGEADC_Msk
150   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGPDMA_Msk
151   *                                 - \ref TIMER_PWMTRGCTL_PWMTRGLPADC_Msk
152   *
153   * @return     None
154   *
155   * @details    This function is used to disable counter event to trigger ADC/DAC/PDMA/LPADC.
156   */
TPWM_DisableTrigger(TIMER_T * timer,uint32_t u32TargetMask)157 void TPWM_DisableTrigger(TIMER_T *timer, uint32_t u32TargetMask)
158 {
159     timer->PWMTRGCTL &= ~(u32TargetMask);
160 }
161 
162 /**
163   * @brief      Enable Interrupt Flag Accumulator
164   * @param[in]  timer           The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
165   * @param[in]  u32IntFlagCnt   Interrupt flag counter. Valid values are between 0~65535.
166   * @param[in]  u32IntAccSrc    Interrupt flag accumulator source selection.
167   *                                 - \ref TPWM_IFA_PERIOD_POINT
168   *                                 - \ref TPWM_IFA_COMPARE_UP_COUNT_POINT
169   * @return     None
170   * @details    This function is used to enable interrupt flag accumulator.
171   */
TPWM_EnableAcc(TIMER_T * timer,uint32_t u32IntFlagCnt,uint32_t u32IntAccSrc)172 void TPWM_EnableAcc(TIMER_T *timer, uint32_t u32IntFlagCnt, uint32_t u32IntAccSrc)
173 {
174     timer->PWMIFA = (((timer)->PWMIFA & ~(TIMER_PWMIFA_IFACNT_Msk | TIMER_PWMIFA_IFASEL_Msk | TIMER_PWMIFA_STPMOD_Msk))
175                      | (TIMER_PWMIFA_IFAEN_Msk | (u32IntFlagCnt << TIMER_PWMIFA_IFACNT_Pos) | (u32IntAccSrc << TIMER_PWMIFA_IFASEL_Pos)));
176 }
177 
178 /**
179   * @brief      Disable Interrupt Flag Accumulator
180   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
181   * @return     None
182   * @details    This function is used to disable interrupt flag accumulator.
183   */
TPWM_DisableAcc(TIMER_T * timer)184 void TPWM_DisableAcc(TIMER_T *timer)
185 {
186     timer->PWMIFA &= ~TIMER_PWMIFA_IFAEN_Msk;
187 }
188 
189 /**
190   * @brief      Enable Interrupt Flag Accumulator Interrupt Function
191   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
192   * @return     None
193   * @details    This function is used to enable interrupt flag accumulator interrupt.
194   */
TPWM_EnableAccInt(TIMER_T * timer)195 void TPWM_EnableAccInt(TIMER_T *timer)
196 {
197     timer->PWMAINTEN |= TIMER_PWMAINTEN_IFAIEN_Msk;
198 }
199 
200 /**
201   * @brief      Disable Interrupt Flag Accumulator Interrupt Function
202   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
203   * @return     None
204   * @details    This function is used to disable interrupt flag accumulator interrupt.
205   */
TPWM_DisableAccInt(TIMER_T * timer)206 void TPWM_DisableAccInt(TIMER_T *timer)
207 {
208     timer->PWMAINTEN &= ~TIMER_PWMAINTEN_IFAIEN_Msk;
209 }
210 
211 /**
212   * @brief      Clear Interrupt Flag Accumulator Interrupt Flag
213   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
214   * @return     None
215   * @details    This function is used to clear interrupt flag accumulator interrupt.
216   */
TPWM_ClearAccInt(TIMER_T * timer)217 void TPWM_ClearAccInt(TIMER_T *timer)
218 {
219     timer->PWMAINTSTS = TIMER_PWMAINTSTS_IFAIF_Msk;
220 }
221 
222 /**
223   * @brief      Get Interrupt Flag Accumulator Interrupt Flag
224   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
225   * @retval     0   Accumulator interrupt did not occur
226   * @retval     1   Accumulator interrupt occurred
227   * @details    This function is used to get interrupt flag accumulator interrupt.
228   */
TPWM_GetAccInt(TIMER_T * timer)229 uint32_t TPWM_GetAccInt(TIMER_T *timer)
230 {
231     return (((timer)->PWMAINTSTS & TIMER_PWMAINTSTS_IFAIF_Msk)? 1UL : 0UL);
232 }
233 
234 /**
235   * @brief      Enable Accumulator Interrupt Trigger PDMA
236   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
237   * @return     None
238   * @details    This function is used to enable accumulator interrupt trigger PDMA transfer.
239   */
TPWM_EnableAccPDMA(TIMER_T * timer)240 void TPWM_EnableAccPDMA(TIMER_T *timer)
241 {
242     timer->PWMAPDMACTL |= TIMER_PWMAPDMACTL_APDMAEN_Msk;
243 }
244 
245 /**
246   * @brief      Disable Accumulator Interrupt Trigger PDMA
247   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
248   * @return     None
249   * @details    This function is used to disable accumulator interrupt trigger PDMA transfer.
250   */
TPWM_DisableAccPDMA(TIMER_T * timer)251 void TPWM_DisableAccPDMA(TIMER_T *timer)
252 {
253     timer->PWMAPDMACTL &= ~TIMER_PWMAPDMACTL_APDMAEN_Msk;
254 }
255 
256 /**
257   * @brief      Enable Interrupt Flag Accumulator Stop Mode
258   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
259   * @return     None
260   * @details    This function is used to enable interrupt flag accumulator event to stop PWM counting.
261   */
TPWM_EnableAccStopMode(TIMER_T * timer)262 void TPWM_EnableAccStopMode(TIMER_T *timer)
263 {
264     timer->PWMIFA |= TIMER_PWMIFA_STPMOD_Msk;
265 }
266 
267 /**
268   * @brief      Disable Interrupt Flag Accumulator Stop Mode
269   * @param[in]  timer       The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
270   * @return     None
271   * @details    This function is used to disable interrupt flag accumulator event to stop PWM counting.
272   */
TPWM_DisableAccStopMode(TIMER_T * timer)273 void TPWM_DisableAccStopMode(TIMER_T *timer)
274 {
275     timer->PWMIFA &= ~TIMER_PWMIFA_STPMOD_Msk;
276 }
277 
278 /*@}*/ /* end of group TIMER_PWM_EXPORTED_FUNCTIONS */
279 
280 /*@}*/ /* end of group TIMER_PWM_Driver */
281 
282 /*@}*/ /* end of group Standard_Driver */
283 
284 /*** (C) COPYRIGHT 2020 Nuvoton Technology Corp. ***/
285