NANO100_BSP V3.04.002
The Board Support Package for Nano100BN Series
pwm.c
Go to the documentation of this file.
1/**************************************************************************/
12#include "Nano100Series.h"
13
38 uint32_t u32ChannelNum,
39 uint32_t u32Frequency,
40 uint32_t u32DutyCycle)
41{
42 uint32_t i;
43 uint32_t u32ClkSrc;
44 uint32_t u32PWM_Clock = SystemCoreClock;
45 uint8_t u8Divider = 1, u8Prescale = 0xFF;
46 uint16_t u16CNR = 0xFFFF;
47
48 if(pwm == PWM0)
49 u32ClkSrc = (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM0_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL1_PWM0_CH01_S_Pos + (u32ChannelNum & 2));
50
51 else
52 u32ClkSrc = (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM1_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL2_PWM1_CH01_S_Pos + (u32ChannelNum & 2));
53
54 switch (u32ClkSrc)
55 {
56 case 0:
57 u32PWM_Clock = __HXT;
58 break;
59 case 1:
60 u32PWM_Clock = __LXT;
61 break;
62 case 2:
63 u32PWM_Clock = SystemCoreClock;
64 break;
65 case 3:
66 u32PWM_Clock = __HIRC12M;
67 break;
68 }
69
70 for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16
71 {
72 i = (u32PWM_Clock / u32Frequency) / u8Divider;
73 // If target value is larger than CNR * prescale, need to use a larger divider
74 if(i > (0x10000 * 0x100))
75 continue;
76
77 // CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF
78 u8Prescale = (i + 0xFFFF)/ 0x10000;
79
80 // u8Prescale must at least be 2, otherwise the output stop
81 if(u8Prescale < 3)
82 u8Prescale = 2;
83
84 i /= u8Prescale;
85
86 if(i <= 0x10000)
87 {
88 if(i == 1)
89 u16CNR = 1; // Too fast, and PWM cannot generate expected frequency...
90 else
91 u16CNR = i;
92 break;
93 }
94
95 }
96 // Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
97 i = u32PWM_Clock / (u8Prescale * u8Divider * u16CNR);
98
99 u8Prescale -= 1;
100 u16CNR -= 1;
101 // convert to real register value
102 if(u8Divider == 1)
103 u8Divider = 4;
104 else if (u8Divider == 2)
105 u8Divider = 0;
106 else if (u8Divider == 4)
107 u8Divider = 1;
108 else if (u8Divider == 8)
109 u8Divider = 2;
110 else // 16
111 u8Divider = 3;
112
113 // every two channels share a prescaler
115 pwm->PRES = (pwm->PRES & ~(PWM_PRES_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
116 pwm->CLKSEL = (pwm->CLKSEL & ~(PWM_CLKSEL_CLKSEL0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
117 pwm->CTL |= (PWM_CTL_CH0MOD_Msk << (u32ChannelNum * 8));
118 while((pwm->INTSTS & (PWM_INTSTS_DUTY0SYNC_Msk << u32ChannelNum)) == (PWM_INTSTS_DUTY0SYNC_Msk << u32ChannelNum));
119 if(u32DutyCycle == 0)
120 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY_CM_Msk;
121 else
122 {
123 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY_CM_Msk;
124 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= ((u32DutyCycle * (u16CNR + 1) / 100 - 1) << PWM_DUTY_CM_Pos);
125 }
126 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY_CN_Msk;
127 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= u16CNR;
128
129 return(i);
130}
131
143 uint32_t u32ChannelNum,
144 uint32_t u32UnitTimeNsec,
145 uint32_t u32CaptureEdge)
146{
147 uint32_t i;
148 uint32_t u32ClkSrc;
149 uint32_t u32PWM_Clock = SystemCoreClock;
150 uint8_t u8Divider = 1, u8Prescale = 0xFF;
151 uint16_t u16CNR = 0xFFFF;
152
153 if(pwm == PWM0)
154 u32ClkSrc = (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM0_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL1_PWM0_CH01_S_Pos + (u32ChannelNum & 2));
155 else
156 u32ClkSrc = (CLK->CLKSEL2 & (CLK_CLKSEL2_PWM1_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL2_PWM1_CH01_S_Pos + (u32ChannelNum & 2));
157
158 switch (u32ClkSrc)
159 {
160 case 0:
161 u32PWM_Clock = __HXT;
162 break;
163 case 1:
164 u32PWM_Clock = __LXT;
165 break;
166 case 2:
167 u32PWM_Clock = SystemCoreClock;
168 break;
169 case 3:
170 u32PWM_Clock = __HIRC12M;
171 break;
172 }
173
174 for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16
175 {
176 i = ((long long)(u32PWM_Clock / u8Divider) * u32UnitTimeNsec) / 1000000000;
177
178 // If target value is larger than 0xFF, need to use a larger divider
179 if(i > (0xFF))
180 continue;
181
182 u8Prescale = i;
183
184 // u8Prescale must at least be 2, otherwise the output stop
185 if(u8Prescale < 3)
186 u8Prescale = 2;
187
188 break;
189 }
190
191 // Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
192 i = (long long) (u8Prescale * u8Divider) * 1000000000 / u32PWM_Clock;
193
194 u8Prescale -= 1;
195 u16CNR -= 1;
196 // convert to real register value
197 if(u8Divider == 1)
198 u8Divider = 4;
199 else if (u8Divider == 2)
200 u8Divider = 0;
201 else if (u8Divider == 4)
202 u8Divider = 1;
203 else if (u8Divider == 8)
204 u8Divider = 2;
205 else // 16
206 u8Divider = 3;
207
208 // every two channels share a prescaler
210 pwm->PRES = (pwm->PRES & ~(PWM_PRES_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
211 pwm->CLKSEL = (pwm->CLKSEL & ~(PWM_CLKSEL_CLKSEL0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
212 pwm->CTL |= (PWM_CTL_CH0MOD_Msk << (u32ChannelNum * 8));
213 while((pwm->INTSTS & (PWM_INTSTS_DUTY0SYNC_Msk << u32ChannelNum)) == (PWM_INTSTS_DUTY0SYNC_Msk << u32ChannelNum));
214 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY_CN_Msk;
215 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= u16CNR;
216
217 return(i);
218}
219
227void PWM_Start (PWM_T *pwm, uint32_t u32ChannelMask)
228{
229 uint8_t i;
230 uint32_t u32Mask = 0;
231
232 for (i = 0; i < PWM_CHANNEL_NUM; i++)
233 {
234 if ( u32ChannelMask & (1 << i))
235 u32Mask |= (PWM_CTL_CH0EN_Msk << (i * 8));
236 }
237
238 pwm->CTL |= u32Mask;
239}
240
248void PWM_Stop (PWM_T *pwm, uint32_t u32ChannelMask)
249{
250 uint32_t i;
251 for(i = 0; i < PWM_CHANNEL_NUM; i ++)
252 {
253 if(u32ChannelMask & (1 << i))
254 {
255 *(__IO uint32_t *) (&pwm->DUTY0 + 3 * i) &= ~PWM_DUTY_CN_Msk;
256 }
257 }
258
259}
260
268void PWM_ForceStop (PWM_T *pwm, uint32_t u32ChannelMask)
269{
270 uint32_t i;
271 for (i = 0; i < PWM_CHANNEL_NUM; i++)
272 {
273 if ( u32ChannelMask & (1 << i))
274 pwm->CTL &= ~(PWM_CTL_CH0EN_Msk << (i * 8));
275 }
276}
277
285void PWM_EnableCapture (PWM_T *pwm, uint32_t u32ChannelMask)
286{
287 uint8_t i;
288 uint32_t u32Mask = 0;
289
290 for (i = 0; i < PWM_CHANNEL_NUM; i++)
291 {
292 if ( u32ChannelMask & (1 << i))
293 {
294 u32Mask |= ((PWM_CAPCTL_CAPCH0EN_Msk | PWM_CAPCTL_CAPCH0PADEN_Msk) << (i * 8));
295 }
296 }
297
298 pwm->CAPCTL |= u32Mask;
299}
300
308void PWM_DisableCapture (PWM_T *pwm, uint32_t u32ChannelMask)
309{
310 uint8_t i;
311 uint32_t u32CTLMask = 0;
312 uint32_t u32CAPCTLMask = 0;
313
314 for (i = 0; i < PWM_CHANNEL_NUM; i++)
315 {
316 if ( u32ChannelMask & (1 << i))
317 {
318 u32CTLMask |= (PWM_CTL_CH0EN_Msk << (i * 8));
319 u32CAPCTLMask |= ((PWM_CAPCTL_CAPCH0EN_Msk | PWM_CAPCTL_CAPCH0PADEN_Msk) << (i * 8));
320 }
321 }
322
323 pwm->CTL &= ~u32CTLMask;
324 pwm->CAPCTL &= ~u32CAPCTLMask;
325}
326
334void PWM_EnableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
335{
336 pwm->OE |= u32ChannelMask;
337}
338
346void PWM_DisableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
347{
348 pwm->OE &= ~u32ChannelMask;
349}
350
359void PWM_EnableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
360{
361 // every two channels shares the same setting
362 u32ChannelNum >>= 1;
363 // set duration
364 pwm->PRES = (pwm->PRES & ~(PWM_PRES_DZ01_Msk << (8 * u32ChannelNum))) | ((u32Duration << PWM_PRES_DZ01_Pos ) << (8 * u32ChannelNum));
365 // enable dead zone
366 pwm->CTL |= (PWM_CTL_DZEN01_Msk << u32ChannelNum);
367}
368
375void PWM_DisableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum)
376{
377 // every two channels shares the same setting
378 u32ChannelNum >>= 1;
379 // enable dead zone
380 pwm->CTL &= ~(PWM_CTL_DZEN01_Msk << u32ChannelNum);
381}
382
393void PWM_EnableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
394{
395 // enable capture interrupt
396 pwm->CAPINTEN |= (u32Edge << (u32ChannelNum * 8));
397}
398
409void PWM_DisableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
410{
411 // disable capture interrupt
412 pwm->CAPINTEN &= ~(u32Edge << (u32ChannelNum * 8));
413}
414
425void PWM_ClearCaptureIntFlag (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
426{
427 // disable capture interrupt flag
428 pwm->CAPINTSTS = (u32Edge + 1) << (u32ChannelNum * 8);
429}
430
441uint32_t PWM_GetCaptureIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
442{
443 return ((pwm->CAPINTSTS >> (u32ChannelNum * 8)) & (PWM_RISING_FALLING_LATCH_INT_FLAG));
444}
445
454void PWM_EnablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
455{
456 // enable period interrupt
457 pwm->INTEN |= (PWM_INTEN_TMIE0_Msk << u32ChannelNum);
458}
459
466void PWM_DisablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum)
467{
468 pwm->INTEN &= ~(PWM_INTEN_TMIE0_Msk << u32ChannelNum);
469}
470
477void PWM_ClearPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
478{
479 // write 1 clear
480 pwm->INTSTS = (PWM_INTSTS_TMINT0_Msk << u32ChannelNum);
481}
482
491uint32_t PWM_GetPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
492{
493 return ((pwm->INTSTS & (PWM_INTSTS_TMINT0_Msk << u32ChannelNum)) ? 1 : 0);
494}
495
509void PWM_EnablePDMA(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32RisingFirst, uint32_t u32Mode)
510{
511 if (u32ChannelNum == 0)
512 pwm->CAPCTL = (pwm->CAPCTL & ~(PWM_CAPCTL_PDMACAPMOD0_Msk | PWM_CAPCTL_CH0RFORDER_Msk)) | u32Mode | u32RisingFirst | PWM_CAPCTL_CH0PDMAEN_Msk;
513 else
514 pwm->CAPCTL = (pwm->CAPCTL & ~(PWM_CAPCTL_PDMACAPMOD2_Msk | PWM_CAPCTL_CH2RFORDER_Msk)) | (u32Mode << 16)| (u32RisingFirst << 16)| PWM_CAPCTL_CH2PDMAEN_Msk;
515}
516
523void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
524{
525 if (u32ChannelNum == 0)
526 pwm->CAPCTL &= ~PWM_CAPCTL_CH0PDMAEN_Msk;
527 else
528 pwm->CAPCTL &= ~PWM_CAPCTL_CH2PDMAEN_Msk;
529}
530 /* end of group NANO100_PWM_EXPORTED_FUNCTIONS */
532 /* end of group NANO100_PWM_Driver */
534 /* end of group NANO100_Device_Driver */
536
537/*** (C) COPYRIGHT 2013-2014 Nuvoton Technology Corp. ***/
Nano100 series peripheral access layer header file. This file contains all the peripheral register's ...
#define PWM_CAPCTL_PDMACAPMOD0_Msk
#define PWM_INTEN_TMIE0_Msk
#define PWM_CAPCTL_CH0RFORDER_Msk
#define PWM_DUTY_CM_Pos
#define PWM_PRES_CP01_Msk
#define PWM_CLKSEL_CLKSEL0_Msk
#define PWM_PRES_DZ01_Msk
#define PWM_INTSTS_DUTY0SYNC_Msk
#define PWM_CAPCTL_PDMACAPMOD2_Msk
#define PWM_CAPCTL_CH2RFORDER_Msk
#define PWM_CAPCTL_CAPCH0EN_Msk
#define PWM_CAPCTL_CH0PDMAEN_Msk
#define PWM_CTL_CH0MOD_Msk
#define PWM_CTL_CH0EN_Msk
#define PWM_CTL_DZEN01_Msk
#define PWM_PRES_DZ01_Pos
#define PWM_INTSTS_TMINT0_Msk
#define PWM_INTSTS_PRESSYNC_Msk
#define PWM_CAPCTL_CAPCH0PADEN_Msk
#define PWM_CAPCTL_CH2PDMAEN_Msk
#define CLK_CLKSEL1_PWM0_CH01_S_Pos
#define CLK_CLKSEL2_PWM1_CH01_S_Msk
#define CLK_CLKSEL1_PWM0_CH01_S_Msk
#define CLK_CLKSEL2_PWM1_CH01_S_Pos
#define CLK
Pointer to CLK register structure.
#define PWM0
Pointer to PWM0 register structure.
#define PWM_RISING_FALLING_LATCH_INT_FLAG
Definition: pwm.h:53
#define PWM_CHANNEL_NUM
Definition: pwm.h:32
void PWM_ForceStop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM generation immediately by clear channel enable bit.
Definition: pwm.c:268
void PWM_Stop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM module.
Definition: pwm.c:248
void PWM_EnableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM capture of selected channels.
Definition: pwm.c:285
void PWM_EnablePDMA(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32RisingFirst, uint32_t u32Mode)
This function enable capture PDMA of selected channel.
Definition: pwm.c:509
void PWM_EnableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
This function enable Dead zone of selected channel.
Definition: pwm.c:359
void PWM_ClearCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function clear capture interrupt flag of selected channel.
Definition: pwm.c:425
uint32_t PWM_ConfigCaptureChannel(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32UnitTimeNsec, uint32_t u32CaptureEdge)
This function config PWM capture and get the nearest unit time.
Definition: pwm.c:142
void PWM_DisablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable period interrupt of selected channel.
Definition: pwm.c:466
void PWM_DisableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function disable capture interrupt of selected channel.
Definition: pwm.c:409
uint32_t PWM_ConfigOutputChannel(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Frequency, uint32_t u32DutyCycle)
This function config PWM generator and get the nearest frequency in edge aligned auto-reload mode.
Definition: pwm.c:37
void PWM_DisableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM capture of selected channels.
Definition: pwm.c:308
void PWM_EnablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
This function enable period interrupt of selected channel.
Definition: pwm.c:454
void PWM_DisableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable Dead zone of selected channel.
Definition: pwm.c:375
void PWM_DisableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM output generation of selected channels.
Definition: pwm.c:346
void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable capture PDMA of selected channel.
Definition: pwm.c:523
void PWM_Start(PWM_T *pwm, uint32_t u32ChannelMask)
This function start PWM module.
Definition: pwm.c:227
void PWM_ClearPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function clear period interrupt of selected channel.
Definition: pwm.c:477
void PWM_EnableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM output generation of selected channels.
Definition: pwm.c:334
uint32_t PWM_GetCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get capture interrupt flag of selected channel.
Definition: pwm.c:441
uint32_t PWM_GetPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get period interrupt of selected channel.
Definition: pwm.c:491
void PWM_EnableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function enable capture interrupt of selected channel.
Definition: pwm.c:393
__IO uint32_t CTL
__IO uint32_t CAPINTSTS
__IO uint32_t DUTY0
__IO uint32_t INTEN
__IO uint32_t CLKSEL
__IO uint32_t CAPINTEN
__IO uint32_t OE
__IO uint32_t PRES
__IO uint32_t INTSTS
__IO uint32_t CAPCTL
#define __HXT
uint32_t SystemCoreClock
#define __LXT
#define __HIRC12M