1 /**************************************************************************//**
2  * @file     lptmr_pwm.c
3  * @version  V3.01
4  * @brief    LPTMR PWM Controller(LPTMR 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 LPTMR_PWM_Driver LPTMR PWM Driver
17   @{
18 */
19 
20 /** @addtogroup LPTMR_PWM_EXPORTED_FUNCTIONS LPTMR PWM Exported Functions
21   @{
22 */
23 
24 /**
25   * @brief      Configure LPTPWM Output Frequency and Duty Cycle
26   *
27   * @param[in]  lptmr           The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
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 LPTPWM output frequency and duty cycle in up count type and auto-reload operation mode.
34   * @note       This API is only available if LPTMR PWM counter clock source is from TMRx_CLK.
35   */
LPTPWM_ConfigOutputFreqAndDuty(LPTMR_T * lptmr,uint32_t u32Frequency,uint32_t u32DutyCycle)36 uint32_t LPTPWM_ConfigOutputFreqAndDuty(LPTMR_T *lptmr, uint32_t u32Frequency, uint32_t u32DutyCycle)
37 {
38     uint32_t u32PWMClockFreq, u32TargetFreq;
39     uint32_t u32Prescaler = 0x100UL, u32Period, u32CMP;
40     const uint32_t u32ClkTbl[4] = {__HIRC, __MIRC, __LXT, __LIRC};
41     uint32_t u32Src;
42 
43     if (lptmr == LPTMR0)
44     {
45         u32Src = (LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPTMR0SEL_Msk) >> LPSCC_CLKSEL0_LPTMR0SEL_Pos;
46     }
47     else if (lptmr == LPTMR1)
48     {
49         u32Src = (LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPTMR1SEL_Msk) >> LPSCC_CLKSEL0_LPTMR1SEL_Pos;
50     }
51 
52     u32PWMClockFreq = u32ClkTbl[u32Src];
53 
54     /* Calculate u8PERIOD and u8PSC */
55     for (u32Prescaler = 1; u32Prescaler <= 0x100UL; u32Prescaler++)
56     {
57         u32Period = (u32PWMClockFreq / u32Prescaler) / u32Frequency;
58 
59         /* If target u32Period is larger than 0x10000, need to use a larger prescaler */
60         if (u32Period > 0x10000UL)
61             continue;
62 
63         break;
64     }
65 
66     if (u32Prescaler == 0x101UL)
67     {
68         u32Prescaler = 0x100UL;
69         u32Period = 0x10000UL;
70     }
71 
72     /* Store return value here 'cos we're gonna change u32Prescaler & u32Period to the real value to fill into register */
73     u32TargetFreq = (u32PWMClockFreq / u32Prescaler) / u32Period;
74 
75     /* Set PWM to auto-reload mode */
76     lptmr->PWMCTL = (lptmr->PWMCTL & ~LPTMR_PWMCTL_CNTMODE_Msk) | (LPTPWM_AUTO_RELOAD_MODE << LPTMR_PWMCTL_CNTMODE_Pos);
77 
78     /* Convert to real register value */
79     LPTPWM_SET_PRESCALER(lptmr, (u32Prescaler - 1UL));
80 
81     LPTPWM_SET_PERIOD(lptmr, (u32Period - 1UL));
82 
83     if (u32DutyCycle)
84     {
85         u32CMP = (u32DutyCycle * u32Period) / 100UL;
86     }
87     else
88     {
89         u32CMP = 0UL;
90     }
91 
92     LPTPWM_SET_CMPDAT(lptmr, u32CMP);
93     return (u32TargetFreq);
94 }
95 
96 /**
97   * @brief      Enable LPTPWM Counter
98   *
99   * @param[in]  lptmr       The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
100   *
101   * @return     None
102   *
103   * @details    This function is used to enable LPTPWM generator and start counter counting.
104   */
LPTPWM_EnableCounter(LPTMR_T * lptmr)105 void LPTPWM_EnableCounter(LPTMR_T *lptmr)
106 {
107     lptmr->PWMCTL |= LPTMR_PWMCTL_CNTEN_Msk;
108 }
109 
110 /**
111   * @brief      Disable LPTPWM Generator
112   *
113   * @param[in]  lptmr       The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
114   *
115   * @return     None
116   *
117   * @details This function is used to disable LPTPWM counter immediately by clear CNTEN (LPTMRx_PWMCTL[0]) bit.
118   */
LPTPWM_DisableCounter(LPTMR_T * lptmr)119 void LPTPWM_DisableCounter(LPTMR_T *lptmr)
120 {
121     lptmr->PWMCTL &= ~LPTMR_PWMCTL_CNTEN_Msk;
122 }
123 
124 /**
125   * @brief      Enable LPTPWM Trigger LPPDMA
126   *
127   * @param[in]  lptmr           The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1
128   * @param[in]  u32TargetMask   The mask of modules (LPPDMA) trigger by LPTPWM, the combination of:
129   *                                 - \ref LPTMR_PWMTRGCTL_PWMTRGLPPDMA_Msk
130   * @param[in]  u32Condition    The condition to trigger LPPDMA. It could be one of following conditions:
131   *                                 - \ref LPTPWM_TRIGGER_AT_PERIOD_POINT
132   *                                 - \ref LPTPWM_TRIGGER_AT_COMPARE_POINT
133   *                                 - \ref LPTPWM_TRIGGER_AT_PERIOD_OR_COMPARE_POINT
134   * @return     None
135   *
136   * @details    This function is used to enable specified counter event to trigger ADC/DAC/PDMA.
137   */
LPTPWM_EnableTrigger(LPTMR_T * lptmr,uint32_t u32TargetMask,uint32_t u32Condition)138 void LPTPWM_EnableTrigger(LPTMR_T *lptmr, uint32_t u32TargetMask, uint32_t u32Condition)
139 {
140     lptmr->PWMTRGCTL &= ~( LPTMR_PWMTRGCTL_PWMTRGLPPDMA_Msk | LPTMR_PWMTRGCTL_TRGEN_Msk| LPTMR_PWMTRGCTL_TRGSEL_Msk);
141     lptmr->PWMTRGCTL |= (u32TargetMask) | (u32Condition);
142 }
143 
144 /**
145   * @brief      Disable Trigger LPPDMA
146   *
147   * @param[in]  lptmr       The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1
148   * @param[in]  u32TargetMask   The mask of modules (LPPDMA) trigger by LPTPWM, the combination of:
149   *                                 - \ref LPTMR_PWMTRGCTL_PWMTRGLPPDMA_Msk
150   *
151   * @return     None
152   *
153   * @details    This function is used to disable counter event to trigger LPPDMA.
154   */
LPTPWM_DisableTrigger(LPTMR_T * lptmr,uint32_t u32TargetMask)155 void LPTPWM_DisableTrigger(LPTMR_T *lptmr, uint32_t u32TargetMask)
156 {
157     lptmr->PWMTRGCTL &= ~(u32TargetMask);
158 }
159 
160 /**
161   * @brief      Enable Interrupt Flag Accumulator
162   * @param[in]  lptmr           The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
163   * @param[in]  u32IntFlagCnt   Interrupt flag counter. Valid values are between 0~65535.
164   * @param[in]  u32IntAccSrc    Interrupt flag accumulator source selection.
165   *                                 - \ref LPTPWM_IFA_PERIOD_POINT
166   *                                 - \ref LPTPWM_IFA_COMPARE_UP_COUNT_POINT
167   * @return     None
168   * @details    This function is used to enable interrupt flag accumulator.
169   */
LPTPWM_EnableAcc(LPTMR_T * lptmr,uint32_t u32IntFlagCnt,uint32_t u32IntAccSrc)170 void LPTPWM_EnableAcc(LPTMR_T *lptmr, uint32_t u32IntFlagCnt, uint32_t u32IntAccSrc)
171 {
172     lptmr->PWMIFA = (((lptmr)->PWMIFA & ~(LPTMR_PWMIFA_IFACNT_Msk | LPTMR_PWMIFA_IFASEL_Msk | LPTMR_PWMIFA_STPMOD_Msk))
173                      | (LPTMR_PWMIFA_IFAEN_Msk | (u32IntFlagCnt << LPTMR_PWMIFA_IFACNT_Pos) | (u32IntAccSrc << LPTMR_PWMIFA_IFASEL_Pos)));
174 }
175 
176 /**
177   * @brief      Disable Interrupt Flag Accumulator
178   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
179   * @return     None
180   * @details    This function is used to disable interrupt flag accumulator.
181   */
LPTPWM_DisableAcc(LPTMR_T * lptmr)182 void LPTPWM_DisableAcc(LPTMR_T *lptmr)
183 {
184     lptmr->PWMIFA &= ~LPTMR_PWMIFA_IFAEN_Msk;
185 }
186 
187 /**
188   * @brief      Enable Interrupt Flag Accumulator Interrupt Function
189   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
190   * @return     None
191   * @details    This function is used to enable interrupt flag accumulator interrupt.
192   */
LPTPWM_EnableAccInt(LPTMR_T * lptmr)193 void LPTPWM_EnableAccInt(LPTMR_T *lptmr)
194 {
195     lptmr->PWMAINTEN |= LPTMR_PWMAINTEN_IFAIEN_Msk;
196 }
197 
198 /**
199   * @brief      Disable Interrupt Flag Accumulator Interrupt Function
200   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
201   * @return     None
202   * @details    This function is used to disable interrupt flag accumulator interrupt.
203   */
LPTPWM_DisableAccInt(LPTMR_T * lptmr)204 void LPTPWM_DisableAccInt(LPTMR_T *lptmr)
205 {
206     lptmr->PWMAINTEN &= ~LPTMR_PWMAINTEN_IFAIEN_Msk;
207 }
208 
209 /**
210   * @brief      Clear Interrupt Flag Accumulator Interrupt Flag
211   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
212   * @return     None
213   * @details    This function is used to clear interrupt flag accumulator interrupt.
214   */
LPTPWM_ClearAccInt(LPTMR_T * lptmr)215 void LPTPWM_ClearAccInt(LPTMR_T *lptmr)
216 {
217     lptmr->PWMAINTSTS = LPTMR_PWMAINTSTS_IFAIF_Msk;
218 }
219 
220 /**
221   * @brief      Get Interrupt Flag Accumulator Interrupt Flag
222   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
223   * @retval     0   Accumulator interrupt did not occur
224   * @retval     1   Accumulator interrupt occurred
225   * @details    This function is used to get interrupt flag accumulator interrupt.
226   */
LPTPWM_GetAccInt(LPTMR_T * lptmr)227 uint32_t LPTPWM_GetAccInt(LPTMR_T *lptmr)
228 {
229     return (((lptmr)->PWMAINTSTS & LPTMR_PWMAINTSTS_IFAIF_Msk)? 1UL : 0UL);
230 }
231 
232 /**
233   * @brief      Enable Accumulator Interrupt Trigger LPPDMA
234   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
235   * @return     None
236   * @details    This function is used to enable accumulator interrupt trigger PDMA transfer.
237   */
LPTPWM_EnableAccLPPDMA(LPTMR_T * lptmr)238 void LPTPWM_EnableAccLPPDMA(LPTMR_T *lptmr)
239 {
240     lptmr->PWMAPDMACTL |= LPTMR_PWMAPDMACTL_APDMAEN_Msk;
241 }
242 
243 /**
244   * @brief      Disable Accumulator Interrupt Trigger PDMA
245   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
246   * @return     None
247   * @details    This function is used to disable accumulator interrupt trigger PDMA transfer.
248   */
LPTPWM_DisableAccPDMA(LPTMR_T * lptmr)249 void LPTPWM_DisableAccPDMA(LPTMR_T *lptmr)
250 {
251     lptmr->PWMAPDMACTL &= ~LPTMR_PWMAPDMACTL_APDMAEN_Msk;
252 }
253 
254 /**
255   * @brief      Enable Interrupt Flag Accumulator Stop Mode
256   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
257   * @return     None
258   * @details    This function is used to enable interrupt flag accumulator event to stop PWM counting.
259   */
LPTPWM_EnableAccStopMode(LPTMR_T * lptmr)260 void LPTPWM_EnableAccStopMode(LPTMR_T *lptmr)
261 {
262     lptmr->PWMIFA |= LPTMR_PWMIFA_STPMOD_Msk;
263 }
264 
265 /**
266   * @brief      Disable Interrupt Flag Accumulator Stop Mode
267   * @param[in]  lptmr       The pointer of the specified Timer module. It could be LPTMR0, LPTMR1
268   * @return     None
269   * @details    This function is used to disable interrupt flag accumulator event to stop PWM counting.
270   */
LPTPWM_DisableAccStopMode(LPTMR_T * lptmr)271 void LPTPWM_DisableAccStopMode(LPTMR_T *lptmr)
272 {
273     lptmr->PWMIFA &= ~LPTMR_PWMIFA_STPMOD_Msk;
274 }
275 
276 /*@}*/ /* end of group LPTMR_PWM_EXPORTED_FUNCTIONS */
277 
278 /*@}*/ /* end of group LPTMR_PWM_Driver */
279 
280 /*@}*/ /* end of group Standard_Driver */
281 
282 /*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/
283