Nano102_112 Series BSP  V3.03.002
The Board Support Package for Nano102_112 Series
pwm.c
Go to the documentation of this file.
1 /**************************************************************************/
12 #include "Nano1X2Series.h"
13 
38  uint32_t u32ChannelNum,
39  uint32_t u32Frequency,
40  uint32_t u32DutyCycle)
41 {
42  uint32_t i;
43  uint32_t u32PWM_Clock = SystemCoreClock;
44  uint8_t u8Divider = 1, u8Prescale = 0xFF;
45  uint16_t u16CNR = 0xFFFF;
46 
47  switch ((CLK->CLKSEL1 & (CLK_CLKSEL1_PWM0_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL1_PWM0_CH01_S_Pos + (u32ChannelNum & 2)))
48  {
49  case 0:
50  u32PWM_Clock = __HXT;
51  break;
52  case 1:
53  u32PWM_Clock = __LXT;
54  break;
55  case 2:
56  u32PWM_Clock = SystemCoreClock;
57  break;
58  case 3:
59  if (CLK->PWRCTL & CLK_PWRCTL_HIRC_FSEL_Msk)
60  u32PWM_Clock = __HIRC16M;
61  else
62  u32PWM_Clock = __HIRC12M;
63  break;
64  }
65 
66  for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16
67  {
68  i = (u32PWM_Clock / u32Frequency) / u8Divider;
69  // If target value is larger than CNR * prescale, need to use a larger divider
70  if(i > (0x10000 * 0x100))
71  continue;
72 
73  // CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF
74  u8Prescale = (i + 0xFFFF)/ 0x10000;
75 
76  // u8Prescale must at least be 2, otherwise the output stop
77  if(u8Prescale < 3)
78  u8Prescale = 2;
79 
80  i /= u8Prescale;
81 
82  if(i <= 0x10000)
83  {
84  if(i == 1)
85  u16CNR = 1; // Too fast, and PWM cannot generate expected frequency...
86  else
87  u16CNR = i;
88  break;
89  }
90 
91  }
92  // Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
93  i = u32PWM_Clock / (u8Prescale * u8Divider * u16CNR);
94 
95  u8Prescale -= 1;
96  u16CNR -= 1;
97  // convert to real register value
98  if(u8Divider == 1)
99  u8Divider = 4;
100  else if (u8Divider == 2)
101  u8Divider = 0;
102  else if (u8Divider == 4)
103  u8Divider = 1;
104  else if (u8Divider == 8)
105  u8Divider = 2;
106  else // 16
107  u8Divider = 3;
108 
109  // every two channels share a prescaler
111  pwm->PRES = (pwm->PRES & ~(PWM_PRES_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
112  pwm->CLKSEL = (pwm->CLKSEL & ~(PWM_CLKSEL_CLKSEL0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
113  pwm->CTL |= (PWM_CTL_CH0MOD_Msk << (u32ChannelNum * 8));
114  while((pwm->INTSTS & (PWM_INTSTS_Duty0Syncflag_Msk << u32ChannelNum)) == (PWM_INTSTS_Duty0Syncflag_Msk << u32ChannelNum));
115  if(u32DutyCycle == 0)
116  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY0_CM_Msk;
117  else
118  {
119  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY0_CM_Msk;
120  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= ((u32DutyCycle * (u16CNR + 1) / 100 - 1) << PWM_DUTY0_CM_Pos);
121  }
122  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY0_CN_Msk;
123  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= u16CNR;
124 
125  return(i);
126 }
127 
139  uint32_t u32ChannelNum,
140  uint32_t u32UnitTimeNsec,
141  uint32_t u32CaptureEdge)
142 {
143  uint32_t i;
144  uint32_t u32PWM_Clock = SystemCoreClock;
145  uint8_t u8Divider = 1, u8Prescale = 0xFF;
146  uint16_t u16CNR = 0xFFFF;
147 
148  switch ((CLK->CLKSEL1 & (CLK_CLKSEL1_PWM0_CH01_S_Msk << (u32ChannelNum & 2))) >> (CLK_CLKSEL1_PWM0_CH01_S_Pos + (u32ChannelNum & 2)))
149  {
150  case 0:
151  u32PWM_Clock = __HXT;
152  break;
153  case 1:
154  u32PWM_Clock = __LXT;
155  break;
156  case 2:
157  u32PWM_Clock = SystemCoreClock;
158  break;
159  case 3:
160  if (CLK->PWRCTL & CLK_PWRCTL_HIRC_FSEL_Msk)
161  u32PWM_Clock = __HIRC16M;
162  else
163  u32PWM_Clock = __HIRC12M;
164  break;
165  }
166 
167  for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16
168  {
169  i = ((long long)(u32PWM_Clock / u8Divider) * u32UnitTimeNsec) / 1000000000;
170 
171  // If target value is larger than 0xFF, need to use a larger divider
172  if(i > (0xFF))
173  continue;
174 
175  u8Prescale = i;
176 
177  // u8Prescale must at least be 2, otherwise the output stop
178  if(u8Prescale < 3)
179  u8Prescale = 2;
180 
181  break;
182  }
183 
184  // Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
185  i = (long long) (u8Prescale * u8Divider) * 1000000000 / u32PWM_Clock;
186 
187  u8Prescale -= 1;
188  u16CNR -= 1;
189  // convert to real register value
190  if(u8Divider == 1)
191  u8Divider = 4;
192  else if (u8Divider == 2)
193  u8Divider = 0;
194  else if (u8Divider == 4)
195  u8Divider = 1;
196  else if (u8Divider == 8)
197  u8Divider = 2;
198  else // 16
199  u8Divider = 3;
200 
201  // every two channels share a prescaler
203  pwm->PRES = (pwm->PRES & ~(PWM_PRES_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
204  pwm->CLKSEL = (pwm->CLKSEL & ~(PWM_CLKSEL_CLKSEL0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
205  pwm->CTL |= (PWM_CTL_CH0MOD_Msk << (u32ChannelNum * 8));
206  while((pwm->INTSTS & (PWM_INTSTS_Duty0Syncflag_Msk << u32ChannelNum)) == (PWM_INTSTS_Duty0Syncflag_Msk << u32ChannelNum));
207  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) &= ~PWM_DUTY0_CN_Msk;
208  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * u32ChannelNum) |= u16CNR;
209 
210  return(i);
211 }
212 
220 void PWM_Start (PWM_T *pwm, uint32_t u32ChannelMask)
221 {
222  uint8_t i;
223  uint32_t u32Mask = 0;
224 
225  for (i = 0; i < PWM_CHANNEL_NUM; i++)
226  {
227  if ( u32ChannelMask & (1 << i))
228  u32Mask |= (PWM_CTL_CH0EN_Msk << (i * 8));
229  }
230 
231  pwm->CTL |= u32Mask;
232 }
233 
241 void PWM_Stop (PWM_T *pwm, uint32_t u32ChannelMask)
242 {
243  uint32_t i;
244  for(i = 0; i < PWM_CHANNEL_NUM; i ++)
245  {
246  if(u32ChannelMask & (1 << i))
247  {
248  *(__IO uint32_t *) (&pwm->DUTY0 + 3 * i) &= ~PWM_DUTY0_CN_Msk;
249  }
250  }
251 
252 }
253 
261 void PWM_ForceStop (PWM_T *pwm, uint32_t u32ChannelMask)
262 {
263  uint32_t i;
264  for (i = 0; i < PWM_CHANNEL_NUM; i++)
265  {
266  if ( u32ChannelMask & (1 << i))
267  pwm->CTL &= ~(PWM_CTL_CH0EN_Msk << (i * 8));
268  }
269 }
270 
278 void PWM_EnableADCTrigger (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
279 {
280  pwm->ADTRGEN |= (PWM_ADTRGEN_TRGCH0EN_Msk << u32ChannelNum);
281 }
282 
289 void PWM_DisableADCTrigger (PWM_T *pwm, uint32_t u32ChannelNum)
290 {
291  pwm->ADTRGEN &= ~(PWM_ADTRGEN_TRGCH0EN_Msk << u32ChannelNum);
292 }
293 
301 void PWM_ClearADCTriggerFlag (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
302 {
303  pwm->ADTRGSTS |= (PWM_ADTRGSTS_ADTRG0Flag_Msk << u32ChannelNum);
304 }
305 
314 uint32_t PWM_GetADCTriggerFlag (PWM_T *pwm, uint32_t u32ChannelNum)
315 {
316  return ((pwm->ADTRGSTS & (PWM_ADTRGSTS_ADTRG0Flag_Msk << u32ChannelNum)) >> u32ChannelNum);
317 }
318 
319 
327 void PWM_EnableCapture (PWM_T *pwm, uint32_t u32ChannelMask)
328 {
329  uint8_t i;
330  uint32_t u32Mask = 0;
331 
332  for (i = 0; i < PWM_CHANNEL_NUM; i++)
333  {
334  if ( u32ChannelMask & (1 << i))
335  {
336  u32Mask |= ((PWM_CAPCTL_CAPCH0EN_Msk | PWM_CAPCTL_CAPCH0PADEN_Msk) << (i * 8));
337  }
338  }
339 
340  pwm->CAPCTL |= u32Mask;
341 }
342 
350 void PWM_DisableCapture (PWM_T *pwm, uint32_t u32ChannelMask)
351 {
352  uint8_t i;
353  uint32_t u32CTLMask = 0;
354  uint32_t u32CAPCTLMask = 0;
355 
356 
357  for (i = 0; i < PWM_CHANNEL_NUM; i++)
358  {
359  if ( u32ChannelMask & (1 << i))
360  {
361  u32CTLMask |= (PWM_CTL_CH0EN_Msk << (i * 8));
362  u32CAPCTLMask |= ((PWM_CAPCTL_CAPCH0EN_Msk | PWM_CAPCTL_CAPCH0PADEN_Msk) << (i * 8));
363  }
364  }
365 
366  pwm->CTL &= ~u32CTLMask;
367  pwm->CAPCTL &= ~u32CAPCTLMask;
368 
369 }
370 
378 void PWM_EnableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
379 {
380  pwm->OE |= u32ChannelMask;
381 }
382 
390 void PWM_DisableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
391 {
392  pwm->OE &= ~u32ChannelMask;
393 }
394 
403 void PWM_EnableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
404 {
405  // every two channels shares the same setting
406  u32ChannelNum >>= 1;
407  // set duration
408  pwm->PRES = (pwm->PRES & ~(PWM_PRES_DZ01_Msk << (8 * u32ChannelNum))) | ((u32Duration << PWM_PRES_DZ01_Pos ) << (8 * u32ChannelNum));
409  // enable dead zone
410  pwm->CTL |= (PWM_CTL_DZEN01_Msk << u32ChannelNum);
411 }
412 
419 void PWM_DisableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum)
420 {
421  // every two channels shares the same setting
422  u32ChannelNum >>= 1;
423  // enable dead zone
424  pwm->CTL &= ~(PWM_CTL_DZEN01_Msk << u32ChannelNum);
425 }
426 
437 void PWM_EnableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
438 {
439  // enable capture interrupt
440  pwm->CAPINTEN |= (u32Edge << (u32ChannelNum * 8));
441 }
442 
453 void PWM_DisableCaptureInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
454 {
455  // disable capture interrupt
456  pwm->CAPINTEN &= ~(u32Edge << (u32ChannelNum * 8));
457 }
458 
469 void PWM_ClearCaptureIntFlag (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
470 {
471  // disable capture interrupt flag
472  pwm->CAPINTSTS = (u32Edge + 1) << (u32ChannelNum * 8);
473 }
474 
485 uint32_t PWM_GetCaptureIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
486 {
487  return ((pwm->CAPINTSTS >> (u32ChannelNum * 8)) & (PWM_RISING_FALLING_LATCH_INT_FLAG));
488 }
489 
496 void PWM_ClearDutyIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
497 {
498  // write 1 clear
499  pwm->INTSTS = (PWM_INTEN_TMIE0_Msk << u32ChannelNum);
500 }
501 
510 uint32_t PWM_GetDutyIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
511 {
512  return ((pwm->INTSTS & (PWM_INTEN_TMIE0_Msk << u32ChannelNum)) ? 1 : 0);
513 }
514 
523 void PWM_EnablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
524 {
525  // enable period interrupt
526  pwm->INTEN |= (PWM_INTEN_TMIE0_Msk << u32ChannelNum);
527 }
528 
535 void PWM_DisablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum)
536 {
537  pwm->INTEN &= ~(PWM_INTEN_TMIE0_Msk << u32ChannelNum);
538 }
539 
546 void PWM_ClearPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
547 {
548  // write 1 clear
549  pwm->INTSTS = (PWM_INTSTS_TMINT0_Msk << u32ChannelNum);
550 }
551 
560 uint32_t PWM_GetPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
561 {
562  return ((pwm->INTSTS & (PWM_INTSTS_TMINT0_Msk << u32ChannelNum)) ? 1 : 0);
563 }
564 
578 void PWM_EnablePDMA(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32RisingFirst, uint32_t u32Mode)
579 {
580  if (u32ChannelNum == 0)
581  pwm->CAPCTL = (pwm->CAPCTL & ~(PWM_CAPCTL_PDMACAPMOD0_Msk | PWM_CAPCTL_CH0RFORDER_Msk)) | u32Mode | u32RisingFirst | PWM_CAPCTL_CH0PDMAEN_Msk;
582  else
583  pwm->CAPCTL = (pwm->CAPCTL & ~(PWM_CAPCTL_PDMACAPMOD2_Msk | PWM_CAPCTL_CH2RFORDER_Msk)) | (u32Mode << 16)| (u32RisingFirst << 16)| PWM_CAPCTL_CH2PDMAEN_Msk;
584 }
585 
592 void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
593 {
594  if (u32ChannelNum == 0)
596  else
598 }
599 
600  /* end of group NANO1X2_PWM_EXPORTED_FUNCTIONS */
602  /* end of group NANO1X2_PWM_Driver */
604  /* end of group NANO1X2_Device_Driver */
606 
607 /*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
#define PWM_INTSTS_TMINT0_Msk
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:578
#define PWM_CAPCTL_CAPCH0EN_Msk
void PWM_DisableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable selected channel to trigger ADC.
Definition: pwm.c:289
#define PWM_CAPCTL_CH0PDMAEN_Msk
#define PWM_PRES_DZ01_Msk
uint32_t PWM_GetADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get selected channel trigger ADC flag.
Definition: pwm.c:314
void PWM_ClearADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
This function clear selected channel trigger ADC flag.
Definition: pwm.c:301
void PWM_ForceStop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM generation immediately by clear channel enable bit.
Definition: pwm.c:261
#define PWM_DUTY0_CN_Msk
void PWM_ClearCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function clear capture interrupt flag of selected channel.
Definition: pwm.c:469
#define PWM_INTSTS_Duty0Syncflag_Msk
#define CLK
Pointer to CLK register structure.
#define PWM_CAPCTL_CH0RFORDER_Msk
#define PWM_DUTY0_CM_Msk
__IO uint32_t INTEN
__IO uint32_t CAPINTSTS
#define PWM_CAPCTL_PDMACAPMOD0_Msk
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:138
#define PWM_RISING_FALLING_LATCH_INT_FLAG
Definition: pwm.h:53
#define PWM_CTL_CH0MOD_Msk
__IO uint32_t OE
__IO uint32_t PRES
#define PWM_INTEN_TMIE0_Msk
uint32_t PWM_GetPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get period interrupt of selected channel.
Definition: pwm.c:560
#define PWM_DUTY0_CM_Pos
#define __LXT
#define CLK_PWRCTL_HIRC_FSEL_Msk
#define CLK_CLKSEL1_PWM0_CH01_S_Msk
void PWM_DisableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM capture of selected channels.
Definition: pwm.c:350
void PWM_EnableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
This function enable selected channel to trigger ADC.
Definition: pwm.c:278
__IO uint32_t ADTRGSTS
#define PWM_CTL_DZEN01_Msk
#define __HIRC16M
#define PWM_CTL_CH0EN_Msk
#define __HIRC12M
Nano102/112 peripheral access layer header file. This file contains all the peripheral register's def...
void PWM_DisableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function disable capture interrupt of selected channel.
Definition: pwm.c:453
void PWM_Stop(PWM_T *pwm, uint32_t u32ChannelMask)
This function stop PWM module.
Definition: pwm.c:241
void PWM_DisableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable Dead zone of selected channel.
Definition: pwm.c:419
uint32_t SystemCoreClock
void PWM_EnableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM capture of selected channels.
Definition: pwm.c:327
uint32_t PWM_GetCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get capture interrupt flag of selected channel.
Definition: pwm.c:485
uint32_t PWM_GetDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function get duty interrupt flag of selected channel.
Definition: pwm.c:510
void PWM_EnableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
This function enable capture interrupt of selected channel.
Definition: pwm.c:437
#define PWM_ADTRGSTS_ADTRG0Flag_Msk
#define PWM_INTSTS_PresSyncFlag_Msk
void PWM_DisablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable period interrupt of selected channel.
Definition: pwm.c:535
#define PWM_CLKSEL_CLKSEL0_Msk
void PWM_ClearPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function clear period interrupt of selected channel.
Definition: pwm.c:546
void PWM_EnableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function enables PWM output generation of selected channels.
Definition: pwm.c:378
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_Start(PWM_T *pwm, uint32_t u32ChannelMask)
This function start PWM module.
Definition: pwm.c:220
__IO uint32_t ADTRGEN
__IO uint32_t CAPCTL
#define PWM_CAPCTL_CH2RFORDER_Msk
void PWM_EnableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
This function enable Dead zone of selected channel.
Definition: pwm.c:403
__IO uint32_t CTL
#define PWM_PRES_CP01_Msk
__IO uint32_t CLKSEL
#define PWM_ADTRGEN_TRGCH0EN_Msk
#define PWM_CAPCTL_PDMACAPMOD2_Msk
__IO uint32_t DUTY0
#define CLK_CLKSEL1_PWM0_CH01_S_Pos
#define __HXT
void PWM_ClearDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
This function clears duty interrupt flag of selected channel.
Definition: pwm.c:496
#define PWM_CHANNEL_NUM
Definition: pwm.h:32
__IO uint32_t CAPINTEN
void PWM_DisableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
This function disables PWM output generation of selected channels.
Definition: pwm.c:390
__IO uint32_t INTSTS
#define PWM_CAPCTL_CH2PDMAEN_Msk
void PWM_EnablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
This function enable period interrupt of selected channel.
Definition: pwm.c:523
void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelNum)
This function disable capture PDMA of selected channel.
Definition: pwm.c:592
#define PWM_CAPCTL_CAPCH0PADEN_Msk
#define PWM_PRES_DZ01_Pos