Nano100BN Series BSP  V3.03.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 
227 void 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 
248 void 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 
268 void 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 
285 void 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 
308 void 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 
334 void PWM_EnableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
335 {
336  pwm->OE |= u32ChannelMask;
337 }
338 
346 void PWM_DisableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
347 {
348  pwm->OE &= ~u32ChannelMask;
349 }
350 
359 void 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 
375 void 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 
393 void PWM_EnableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
394 {
395  // enable capture interrupt
396  pwm->CAPINTEN |= (u32Edge << (u32ChannelNum * 8));
397 }
398 
409 void PWM_DisableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
410 {
411  // disable capture interrupt
412  pwm->CAPINTEN &= ~(u32Edge << (u32ChannelNum * 8));
413 }
414 
425 void 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 
441 uint32_t PWM_GetCaptureIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
442 {
443  return ((pwm->CAPINTSTS >> (u32ChannelNum * 8)) & (PWM_RISING_FALLING_LATCH_INT_FLAG));
444 }
445 
454 void 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 
466 void PWM_DisablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum)
467 {
468  pwm->INTEN &= ~(PWM_INTEN_TMIE0_Msk << u32ChannelNum);
469 }
470 
477 void PWM_ClearPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
478 {
479  // write 1 clear
480  pwm->INTSTS = (PWM_INTSTS_TMINT0_Msk << u32ChannelNum);
481 }
482 
491 uint32_t PWM_GetPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
492 {
493  return ((pwm->INTSTS & (PWM_INTSTS_TMINT0_Msk << u32ChannelNum)) ? 1 : 0);
494 }
495 
509 void 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 
523 void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
524 {
525  if (u32ChannelNum == 0)
527  else
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. ***/
uint32_t SystemCoreClock
#define PWM_DUTY_CM_Msk
void PWM_EnableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM output generation of selected channels.
Definition: pwm.c:334
#define CLK_CLKSEL2_PWM1_CH01_S_Pos
#define CLK_CLKSEL2_PWM1_CH01_S_Msk
#define PWM_CLKSEL_CLKSEL0_Msk
void PWM_DisablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable period interrupt of selected channel.
Definition: pwm.c:466
uint32_t PWM_GetPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get period interrupt of selected channel.
Definition: pwm.c:491
#define PWM_CTL_CH0MOD_Msk
#define PWM_CAPCTL_PDMACAPMOD2_Msk
#define CLK_CLKSEL1_PWM0_CH01_S_Pos
#define CLK
Pointer to CLK register structure.
#define PWM_INTSTS_PRESSYNC_Msk
__IO uint32_t INTEN
__IO uint32_t CAPINTSTS
#define PWM_CAPCTL_PDMACAPMOD0_Msk
void PWM_ForceStop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM generation immediately by clear channel enable bit.
Definition: pwm.c:268
__IO uint32_t OE
#define PWM_DUTY_CN_Msk
__IO uint32_t PRES
Nano100 series peripheral access layer header file. This file contains all the peripheral register's ...
#define PWM_CAPCTL_CH2PDMAEN_Msk
void PWM_EnableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM capture of selected channels.
Definition: pwm.c:285
#define PWM_CTL_DZEN01_Msk
void PWM_Stop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM module.
Definition: pwm.c:248
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_DisableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function disable capture interrupt of selected channel.
Definition: pwm.c:409
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
void PWM_DisableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM output generation of selected channels.
Definition: pwm.c:346
#define PWM_DUTY_CM_Pos
void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable capture PDMA of selected channel.
Definition: pwm.c:523
#define __HIRC12M
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
#define PWM_CAPCTL_CH0PDMAEN_Msk
#define PWM_INTEN_TMIE0_Msk
#define CLK_CLKSEL1_PWM0_CH01_S_Msk
#define PWM_CHANNEL_NUM
Definition: pwm.h:32
#define PWM_PRES_DZ01_Msk
#define __HXT
#define __LXT
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
#define PWM_CAPCTL_CH2RFORDER_Msk
uint32_t PWM_GetCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get capture interrupt flag of selected channel.
Definition: pwm.c:441
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
#define PWM_RISING_FALLING_LATCH_INT_FLAG
Definition: pwm.h:53
#define PWM_PRES_DZ01_Pos
void PWM_ClearPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function clear period interrupt of selected channel.
Definition: pwm.c:477
#define PWM_INTSTS_DUTY0SYNC_Msk
#define PWM_PRES_CP01_Msk
__IO uint32_t CAPCTL
__IO uint32_t CTL
#define PWM_INTSTS_TMINT0_Msk
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 CLKSEL
#define PWM_CTL_CH0EN_Msk
#define PWM_CAPCTL_CAPCH0PADEN_Msk
__IO uint32_t DUTY0
#define PWM_CAPCTL_CH0RFORDER_Msk
#define PWM_CAPCTL_CAPCH0EN_Msk
__IO uint32_t CAPINTEN
void PWM_DisableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM capture of selected channels.
Definition: pwm.c:308
void PWM_Start(PWM_T *pwm, uint32_t u32ChannelMask)
This function start PWM module.
Definition: pwm.c:227
__IO uint32_t INTSTS
void PWM_DisableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable Dead zone of selected channel.
Definition: pwm.c:375
#define PWM0
Pointer to PWM0 register structure.