SAM4SD32 (SAM4S-EK2)
Loading...
Searching...
No Matches
pwm.c
Go to the documentation of this file.
1
33/*
34 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
35 */
36
37#include "pwm.h"
38
40
41#ifdef __cplusplus
42extern "C" {
43#endif
46
57
58#ifndef PWM_WPCR_WPKEY_PASSWD
59# define PWM_WPCR_WPKEY_PASSWD 0x50574D00
60#endif
61
62#ifndef PWM_WPCR_WPCMD_DISABLE_SW_PROT
63# define PWM_WPCR_WPCMD_DISABLE_SW_PROT (PWM_WPCR_WPCMD(0))
64#endif
65
66#ifndef PWM_WPCR_WPCMD_ENABLE_SW_PROT
67# define PWM_WPCR_WPCMD_ENABLE_SW_PROT (PWM_WPCR_WPCMD(1))
68#endif
69
70#ifndef PWM_WPCR_WPCMD_ENABLE_HW_PROT
71# define PWM_WPCR_WPCMD_ENABLE_HW_PROT (PWM_WPCR_WPCMD(2))
72#endif
73
74#define PWM_CLOCK_DIV_MAX 256
75#define PWM_CLOCK_PRE_MAX 11
76
87static uint32_t pwm_clocks_generate(uint32_t ul_frequency, uint32_t ul_mck)
88{
89 uint32_t ul_divisors[PWM_CLOCK_PRE_MAX] =
90 {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 };
91 uint32_t ul_pre = 0;
92 uint32_t ul_div;
93
94 /* Find prescaler and divisor values */
95 do {
96 ul_div = (ul_mck / ul_divisors[ul_pre]) / ul_frequency;
97 if (ul_div <= PWM_CLOCK_DIV_MAX) {
98 break;
99 }
100 ul_pre++;
101 } while (ul_pre < PWM_CLOCK_PRE_MAX);
102
103 /* Return result */
104 if (ul_pre < PWM_CLOCK_PRE_MAX) {
105 return ul_div | (ul_pre << 8);
106 } else {
108 }
109}
110
119uint32_t pwm_init(Pwm *p_pwm, pwm_clock_t *clock_config)
120{
121 uint32_t clock = 0;
122 uint32_t result;
123
124 /* Clock A */
125 if (clock_config->ul_clka != 0) {
126 result = pwm_clocks_generate(clock_config->ul_clka, clock_config->ul_mck);
127 if (result == PWM_INVALID_ARGUMENT) {
128 return result;
129 }
130
131 clock = result;
132 }
133
134 /* Clock B */
135 if (clock_config->ul_clkb != 0) {
136 result = pwm_clocks_generate(clock_config->ul_clkb, clock_config->ul_mck);
137
138 if (result == PWM_INVALID_ARGUMENT) {
139 return result;
140 }
141
142 clock |= (result << 16);
143 }
144#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
145 p_pwm->PWM_MR = clock;
146#else
147 p_pwm->PWM_CLK = clock;
148#endif
149 return 0;
150}
151
160uint32_t pwm_channel_init(Pwm *p_pwm, pwm_channel_t *p_channel)
161{
162 uint32_t tmp_reg = 0;
163 uint32_t ch_num = p_channel->channel;
164
165 /* Channel Mode/Clock Register */
166 tmp_reg = (p_channel->ul_prescaler & 0xF) |
167 (p_channel->polarity << 9) |
168#if (SAM3U || SAM3S || SAM3XA || SAM4S || SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
169 (p_channel->counter_event) |
170 (p_channel->b_deadtime_generator << 16) |
171 (p_channel->b_pwmh_output_inverted << 17) |
172 (p_channel->b_pwml_output_inverted << 18) |
173#endif
174 (p_channel->alignment);
175 p_pwm->PWM_CH_NUM[ch_num].PWM_CMR = tmp_reg;
176
177 /* Channel Duty Cycle Register */
178 p_pwm->PWM_CH_NUM[ch_num].PWM_CDTY = p_channel->ul_duty;
179
180 /* Channel Period Register */
181 p_pwm->PWM_CH_NUM[ch_num].PWM_CPRD = p_channel->ul_period;
182
183#if (SAM3U || SAM3S || SAM3XA || SAM4S || SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
184 /* Channel Dead Time Register */
185 if (p_channel->b_deadtime_generator) {
186 p_pwm->PWM_CH_NUM[ch_num].PWM_DT =
187 PWM_DT_DTL(p_channel->
188 us_deadtime_pwml) | PWM_DT_DTH(p_channel->
189 us_deadtime_pwmh);
190 }
191
192 /* Output Selection Register */
193 tmp_reg = p_pwm->PWM_OS & (~((PWM_OS_OSH0 | PWM_OS_OSL0) << ch_num));
194 tmp_reg |= ((p_channel->output_selection.b_override_pwmh) << ch_num) |
195 (((p_channel->output_selection.b_override_pwml) << ch_num)
196 << 16);
197 p_pwm->PWM_OS = tmp_reg;
198
199 /* Output Override Value Register */
200 tmp_reg = p_pwm->PWM_OOV & (~((PWM_OOV_OOVH0 | PWM_OOV_OOVL0) << ch_num));
201 tmp_reg |= ((p_channel->output_selection.override_level_pwmh) << ch_num) |
202 (((p_channel->output_selection.override_level_pwml) << ch_num)
203 << 16);
204 p_pwm->PWM_OOV = tmp_reg;
205
206 /* Sync Channels Mode Register */
207 uint32_t channel = (1 << ch_num);
208 if (p_channel->b_sync_ch) {
209 p_pwm->PWM_SCM |= channel;
210 } else {
211 p_pwm->PWM_SCM &= ~((uint32_t) channel);
212 }
213
214 /* Fault Protection Value Register */
215#if (SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
216 if (p_channel->ul_fault_output_pwmh == PWM_HIGHZ) {
217 p_pwm->PWM_FPV2 |= (0x01 << ch_num);
218 } else {
219 p_pwm->PWM_FPV2 &= ~(0x01 << ch_num);
220 if (p_channel->ul_fault_output_pwmh == PWM_HIGH) {
221 p_pwm->PWM_FPV1 |= (0x01 << ch_num);
222 } else {
223 p_pwm->PWM_FPV1 &= (~(0x01 << ch_num));
224 }
225 }
226 if (p_channel->ul_fault_output_pwml == PWM_HIGHZ) {
227 p_pwm->PWM_FPV2 |= ((0x01 << ch_num) << 16);
228 } else {
229 p_pwm->PWM_FPV2 &= ~((0x01 << ch_num) << 16);
230 if (p_channel->ul_fault_output_pwml == PWM_HIGH) {
231 p_pwm->PWM_FPV1 |= ((0x01 << ch_num) << 16);
232 } else {
233 p_pwm->PWM_FPV1 &= (~((0x01 << ch_num) << 16));
234 }
235 }
236#else
237 if (p_channel->ul_fault_output_pwmh == PWM_HIGH) {
238 p_pwm->PWM_FPV |= (0x01 << ch_num);
239 } else {
240 p_pwm->PWM_FPV &= (~(0x01 << ch_num));
241 }
242 if (p_channel->ul_fault_output_pwml == PWM_HIGH) {
243 p_pwm->PWM_FPV |= ((0x01 << ch_num) << 16);
244 } else {
245 p_pwm->PWM_FPV &= (~((0x01 << ch_num) << 16));
246 }
247#endif
248 /* Fault Protection Enable Register */
249 uint32_t fault_enable_reg = 0;
250#if (SAM3XA)
251 if (ch_num < 4) {
252 ch_num *= 8;
253 fault_enable_reg = p_pwm->PWM_FPE1;
254 fault_enable_reg &= ~(0xFF << ch_num);
255 fault_enable_reg |= ((p_channel->fault_id) << ch_num);
256 p_pwm->PWM_FPE1 = fault_enable_reg;
257 } else {
258 ch_num -= 4;
259 ch_num *= 8;
260 fault_enable_reg = p_pwm->PWM_FPE2;
261 fault_enable_reg &= ~(0xFF << ch_num);
262 fault_enable_reg |= ((p_channel->fault_id) << ch_num);
263 p_pwm->PWM_FPE2 = fault_enable_reg;
264 }
265#endif
266
267#if (SAM3U || SAM3S || SAM4S || SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
268 ch_num *= 8;
269 fault_enable_reg = p_pwm->PWM_FPE;
270 fault_enable_reg &= ~(0xFF << ch_num);
271 fault_enable_reg |= ((p_channel->fault_id) << ch_num);
272 p_pwm->PWM_FPE = fault_enable_reg;
273#endif
274#endif
275
276 ch_num = p_channel->channel;
277
278#if SAM4E
279 if (!ch_num) {
280 if (p_channel->spread_spectrum_mode ==
281 PWM_SPREAD_SPECTRUM_MODE_RANDOM) {
282 p_pwm->PWM_SSPR = PWM_SSPR_SPRD(p_channel->ul_spread) |
283 PWM_SSPR_SPRDM;
284 } else {
285 p_pwm->PWM_SSPR = PWM_SSPR_SPRD(p_channel->ul_spread);
286 }
287 }
288#elif (SAMV70 || SAMV71 || SAME70 || SAMS70)
289 if (!ch_num) {
290 if (p_channel->spread_spectrum_mode ==
291 PWM_SPREAD_SPECTRUM_MODE_RANDOM) {
292 p_pwm->PWM_SSPR = PWM_SSPR_SPRD(p_channel->ul_spread) |
293 PWM_SSPR_SPRDM;
294 } else {
295 p_pwm->PWM_SSPR = PWM_SSPR_SPRD(p_channel->ul_spread);
296 }
297 }
298 p_pwm->PWM_CH_NUM[ch_num].PWM_CMR &= (~PWM_CMR_PPM);
299 p_pwm->PWM_CH_NUM[ch_num].PWM_CMR |= (p_channel->ul_ppm_mode & PWM_CMR_PPM);
300#endif
301
302 return 0;
303}
304
314uint32_t pwm_channel_update_period(Pwm *p_pwm, pwm_channel_t *p_channel,
315 uint32_t ul_period)
316{
317 uint32_t ch_num = p_channel->channel;
318
320 if (p_channel->ul_duty > ul_period) {
322 } else {
323 /* Save new period value */
324 p_channel->ul_period = ul_period;
325
326#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
327 /* Set CPD bit to change period value */
328 p_pwm->PWM_CH_NUM[ch_num].PWM_CMR |= PWM_CMR_CPD;
329
330 p_pwm->PWM_CH_NUM[ch_num].PWM_CUPD = ul_period;
331#else
332 p_pwm->PWM_CH_NUM[ch_num].PWM_CPRDUPD = ul_period;
333#endif
334 }
335
336 return 0;
337}
338
348uint32_t pwm_channel_update_duty(Pwm *p_pwm, pwm_channel_t *p_channel,
349 uint32_t ul_duty)
350{
351 uint32_t ch_num = p_channel->channel;
352
354 if (p_channel->ul_period < ul_duty) {
356 } else {
357 /* Save new duty cycle value */
358 p_channel->ul_duty = ul_duty;
359
360#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
361 /* Clear CPD bit to change duty cycle value */
362 uint32_t mode = p_pwm->PWM_CH_NUM[ch_num].PWM_CMR;
363 mode &= ~PWM_CMR_CPD;
364 p_pwm->PWM_CH_NUM[ch_num].PWM_CMR = mode;
365
366 p_pwm->PWM_CH_NUM[ch_num].PWM_CUPD = ul_duty;
367#else
368 p_pwm->PWM_CH_NUM[ch_num].PWM_CDTYUPD = ul_duty;
369#endif
370 }
371
372 return 0;
373}
374
383uint32_t pwm_channel_get_counter(Pwm *p_pwm, pwm_channel_t *p_channel)
384{
385 return p_pwm->PWM_CH_NUM[p_channel->channel].PWM_CCNT;
386}
387
388
397void pwm_channel_enable(Pwm *p_pwm, uint32_t ul_channel)
398{
399 p_pwm->PWM_ENA = (1 << ul_channel);
400}
401
410void pwm_channel_disable(Pwm *p_pwm, uint32_t ul_channel)
411{
412 p_pwm->PWM_DIS = (1 << ul_channel);
413}
414
415
423{
424 return p_pwm->PWM_SR;
425}
426
435{
436#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
437 return p_pwm->PWM_ISR;
438#else
439 return p_pwm->PWM_ISR1;
440#endif
441}
442
451{
452#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
453 return p_pwm->PWM_IMR;
454#else
455 return p_pwm->PWM_IMR1;
456#endif
457}
458
467void pwm_channel_enable_interrupt(Pwm *p_pwm, uint32_t ul_event,
468 uint32_t ul_fault)
469{
470#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
471 p_pwm->PWM_IER = (1 << ul_event);
472 /* avoid Cppcheck Warning */
473 UNUSED(ul_fault);
474#else
475 p_pwm->PWM_IER1 = (1 << ul_event) | (1 << (ul_fault + 16));
476#endif
477}
478
479
488void pwm_channel_disable_interrupt(Pwm *p_pwm, uint32_t ul_event,
489 uint32_t ul_fault)
490{
491#if (SAM3N || SAM4N || SAM4C || SAM4CP || SAM4CM)
492 p_pwm->PWM_IDR = (1 << ul_event);
493 /* avoid Cppcheck Warning */
494 UNUSED(ul_fault);
495#else
496 p_pwm->PWM_IDR1 = (1 << ul_event) | (1 << (ul_fault + 16));
497#endif
498}
499
500
501#if (SAM3U || SAM3S || SAM3XA || SAM4S || SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
511 pwm_output_t *p_output, bool b_sync)
512{
513 uint32_t ch_num = p_channel->channel;
514
515 bool override_pwmh = p_output->b_override_pwmh;
516 bool override_pwml = p_output->b_override_pwml;
517 uint32_t pwmh = p_output->override_level_pwmh;
518 uint32_t pwml = p_output->override_level_pwml;
519
520 /* Save new output configuration */
521 p_channel->output_selection.b_override_pwmh = override_pwmh;
522 p_channel->output_selection.b_override_pwml = override_pwml;
525
526 /* Change override output level */
527 uint32_t override_value = p_pwm->PWM_OOV;
528 override_value &= ~((PWM_OOV_OOVH0 | PWM_OOV_OOVL0) << ch_num);
529 override_value |= (((pwml << 16) | pwmh) << ch_num);
530 p_pwm->PWM_OOV = override_value;
531
532 /* Apply new output selection */
533 if (b_sync) {
534 p_pwm->PWM_OSSUPD = ((override_pwml << ch_num) << 16) |
535 (override_pwmh << ch_num);
536 p_pwm->PWM_OSCUPD = ((!override_pwml << ch_num) << 16) |
537 (!override_pwmh << ch_num);
538 } else {
539 p_pwm->PWM_OSS = ((override_pwml << ch_num) << 16) |
540 (override_pwmh << ch_num);
541 p_pwm->PWM_OSC = ((!override_pwml << ch_num) << 16) |
542 (!override_pwmh << ch_num);
543 }
544}
545
555 uint16_t us_deadtime_pwmh, uint16_t us_deadtime_pwml)
556{
557 /* Save new dead time value */
558 p_channel->us_deadtime_pwmh = us_deadtime_pwmh;
559 p_channel->us_deadtime_pwml = us_deadtime_pwml;
560
561 /* Write channel dead time update register */
562 p_pwm->PWM_CH_NUM[p_channel->channel].PWM_DTUPD =
563 PWM_DTUPD_DTLUPD(us_deadtime_pwml) |
564 PWM_DTUPD_DTHUPD(us_deadtime_pwmh);
565}
566
567
568
577uint32_t pwm_fault_init(Pwm *p_pwm, pwm_fault_t *p_fault)
578{
579 uint32_t fault_id = p_fault->fault_id;
580 uint32_t fault_reg = p_pwm->PWM_FMR;
581
583 if (p_fault->polarity == PWM_HIGH) {
584 fault_reg |= fault_id;
585 } else {
586 fault_reg &= ~fault_id;
587 }
589 if (p_fault->b_clear) {
590 fault_reg |= (fault_id << 8);
591 } else {
592 fault_reg &= ~(fault_id << 8);
593 }
595 if (p_fault->b_filtered) {
596 fault_reg |= (fault_id << 16);
597 } else {
598 fault_reg &= ~(fault_id << 16);
599 }
600
601 p_pwm->PWM_FMR = fault_reg;
602
603 return 0;
604}
605
613uint32_t pwm_fault_get_status(Pwm *p_pwm)
614{
615 return ((p_pwm->PWM_FSR >> 8) & 0xFF);
616}
617
627{
628 uint32_t fault_status_reg = p_pwm->PWM_FSR;
629 fault_status_reg >>= id;
630
631 return ((fault_status_reg & 1) ? PWM_HIGH : PWM_LOW);
632}
633
641{
642 p_pwm->PWM_FCR = id;
643}
644
653uint32_t pwm_cmp_init(Pwm *p_pwm, pwm_cmp_t *p_cmp)
654{
655 uint32_t unit = p_cmp->unit;
656
657 p_pwm->PWM_CMP[unit].PWM_CMPV = PWM_CMPV_CV(p_cmp->ul_value) |
658 (p_cmp->b_is_decrementing << 24);
659
660 p_pwm->PWM_CMP[unit].PWM_CMPM = PWM_CMPM_CTR(p_cmp->ul_trigger) |
661 PWM_CMPM_CPR(p_cmp->ul_period) |
663
665 if (p_cmp->b_pulse_on_line_0) {
666 p_pwm->PWM_ELMR[0] |= (1 << unit);
667 } else {
668 p_pwm->PWM_ELMR[0] &= ~((uint32_t) (1 << unit));
669 }
671 if (p_cmp->b_pulse_on_line_1) {
672 p_pwm->PWM_ELMR[1] |= (1 << unit);
673 } else {
674 p_pwm->PWM_ELMR[1] &= ~((uint32_t) (1 << unit));
675 }
676
678 if (p_cmp->b_enable) {
679 p_pwm->PWM_CMP[unit].PWM_CMPM |= PWM_CMPM_CEN;
680 } else {
681 p_pwm->PWM_CMP[unit].PWM_CMPM &= ~PWM_CMPM_CEN;
682 }
683
684 return 0;
685}
686
687
696uint32_t pwm_cmp_change_setting(Pwm *p_pwm, pwm_cmp_t *p_cmp)
697{
698 uint32_t unit = p_cmp->unit;
699
700 p_pwm->PWM_CMP[unit].PWM_CMPVUPD = PWM_CMPV_CV(p_cmp->ul_value) |
701 (p_cmp->b_is_decrementing << 24);
702
703 p_pwm->PWM_CMP[unit].PWM_CMPMUPD = PWM_CMPM_CTR(p_cmp->ul_trigger) |
704 PWM_CMPM_CPR(p_cmp->ul_period) |
706
708 if (p_cmp->b_pulse_on_line_0) {
709 p_pwm->PWM_ELMR[0] |= (1 << unit);
710 } else {
711 p_pwm->PWM_ELMR[0] &= ~((uint32_t) (1 << unit));
712 }
714 if (p_cmp->b_pulse_on_line_1) {
715 p_pwm->PWM_ELMR[1] |= (1 << unit);
716 } else {
717 p_pwm->PWM_ELMR[1] &= ~((uint32_t) (1 << unit));
718 }
719
721 if (p_cmp->b_enable) {
722 p_pwm->PWM_CMP[unit].PWM_CMPMUPD |= PWM_CMPM_CEN;
723 } else {
724 p_pwm->PWM_CMP[unit].PWM_CMPMUPD &= ~PWM_CMPM_CEN;
725 }
726
727 return 0;
728}
729
730
739uint32_t pwm_cmp_get_period_counter(Pwm *p_pwm, uint32_t ul_cmp_unit)
740{
741 return (PWM_CMPM_CPRCNT(p_pwm->PWM_CMP[ul_cmp_unit].PWM_CMPM)
743}
744
753uint32_t pwm_cmp_get_update_counter(Pwm *p_pwm, uint32_t ul_cmp_unit)
754{
755 return (PWM_CMPM_CUPRCNT(p_pwm->PWM_CMP[ul_cmp_unit].PWM_CMPM)
757}
758
759
767void pwm_cmp_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources,
769{
770 if (type == PWM_CMP_MATCH) {
771 p_pwm->PWM_IER2 = ((1 << ul_sources) << 8);
772 } else if (type == PWM_CMP_UPDATE) {
773 p_pwm->PWM_IER2 = ((1 << ul_sources) << 16);
774 } else {
775 /* Do Nothing */
776 }
777}
778
779
787void pwm_cmp_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources,
789{
790 if (type == PWM_CMP_MATCH) {
791 p_pwm->PWM_IDR2 = ((1 << ul_sources) << 8);
792 } else if (type == PWM_CMP_UPDATE) {
793 p_pwm->PWM_IDR2 = ((1 << ul_sources) << 16);
794 } else {
795 /* Do Nothing */
796 }
797}
798
799#if !(SAMV70 || SAMV71 || SAME70 || SAMS70)
810 uint32_t ul_cmp_unit)
811{
812 uint32_t sync_mode = p_pwm->PWM_SCM;
813
814 sync_mode &= ~(PWM_SCM_PTRCS_Msk | PWM_SCM_PTRM);
815 sync_mode |= (PWM_SCM_PTRCS(ul_cmp_unit) | request_mode);
816
817 p_pwm->PWM_SCM = sync_mode;
818}
819
820
821
828void pwm_pdc_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
829{
830 p_pwm->PWM_IER2 = ul_sources;
831}
832
839void pwm_pdc_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
840{
841 p_pwm->PWM_IDR2 = ul_sources;
842}
843#endif
844
855 uint32_t ul_update_period)
856{
857 uint32_t sync_mode = p_pwm->PWM_SCM;
858
859 sync_mode &= ~PWM_SCM_UPDM_Msk;
860 sync_mode |= mode;
861
862 p_pwm->PWM_SCM = sync_mode;
863
864 p_pwm->PWM_SCUP = PWM_SCUP_UPR(ul_update_period);
865
866 return 0;
867}
868
877{
879}
880
887void pwm_sync_change_period(Pwm *p_pwm, uint32_t ul_update_period)
888{
889 p_pwm->PWM_SCUPUPD = PWM_SCUPUPD_UPRUPD(ul_update_period);
890}
891
900{
901 return PWM_SCUP_UPRCNT(p_pwm->PWM_SCUP);
902}
903
910void pwm_sync_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
911{
912 p_pwm->PWM_IER2 = ul_sources;
913}
914
921void pwm_sync_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
922{
923 p_pwm->PWM_IDR2 = ul_sources;
924}
925
933void pwm_enable_protect(Pwm *p_pwm, uint32_t ul_group, bool b_sw)
934{
935 uint32_t wp = 0;
936
937 if (b_sw) {
938 wp = PWM_WPCR_WPKEY_PASSWD | (ul_group << 2) |
940 } else {
941 wp = PWM_WPCR_WPKEY_PASSWD | (ul_group << 2) |
943 }
944
945 p_pwm->PWM_WPCR = wp;
946}
947
956void pwm_disable_protect(Pwm *p_pwm, uint32_t ul_group)
957{
959 | (ul_group << 2) | PWM_WPCR_WPCMD_DISABLE_SW_PROT;
960}
961
972{
973 uint32_t wpsr = p_pwm->PWM_WPSR;
974
975 p_protect->ul_hw_status = (wpsr >> 8) & 0x3F;
977 p_protect->ul_sw_status = (wpsr & 0x3F);
978
979 if ((PWM_WPSR_WPVS & wpsr) == PWM_WPSR_WPVS) {
980 p_protect->ul_offset =
981 (wpsr & PWM_WPSR_WPVSRC_Msk) >>
983 return true;
984 } else {
985 return false;
986 }
987}
988
997{
998 return p_pwm->PWM_ISR2;
999}
1000
1009{
1010 return p_pwm->PWM_IMR2;
1011}
1012#endif
1013
1014#if (SAM3S || SAM3XA || SAM4S || SAM4E || SAMV70 || SAMV71 || SAME70 || SAMS70)
1024 bool b_enable_gray, bool b_down)
1025{
1026 uint32_t motor = p_pwm->PWM_SMMR;
1027
1028 motor &= ~((PWM_SMMR_GCEN0 | PWM_SMMR_DOWN0) << pair);
1029 motor |= ((b_enable_gray | (b_down << 16)) << pair);
1030
1031 p_pwm->PWM_SMMR = motor;
1032}
1033#endif
1034
1035#if SAM4E
1043void pwm_channel_update_spread(Pwm *p_pwm, pwm_channel_t *p_channel,
1044 uint32_t ul_spread)
1045{
1046 /* Save new spread spectrum value */
1047 p_channel->ul_spread = ul_spread;
1048
1049 /* Write spread spectrum update register */
1050 p_pwm->PWM_SSPUP = PWM_SSPUP_SPRDUP(ul_spread);
1051}
1052
1061void pwm_channel_update_polarity_mode(Pwm *p_pwm, pwm_channel_t *p_channel,
1062 bool polarity_inversion_flag, pwm_level_t polarity_value)
1063{
1064 if (polarity_inversion_flag) {
1065 /* Set polarity inversion to the update register */
1066 p_pwm->PWM_CH_NUM_0X400[p_channel->channel].PWM_CMUPD =
1067 PWM_CMUPD_CPOLINVUP;
1068 } else {
1069 /* Save new polarity value */
1070 p_channel->polarity = polarity_value;
1071
1072 /* Write new polarity value to update register */
1073 if (polarity_value == PWM_HIGH) {
1074 p_pwm->PWM_CH_NUM_0X400[p_channel->channel].PWM_CMUPD =
1075 PWM_CMUPD_CPOLUP;
1076 } else {
1077 p_pwm->PWM_CH_NUM_0X400[p_channel->channel].PWM_CMUPD = 0;
1078 }
1079 }
1080}
1081#elif (SAMV70 || SAMV71 || SAME70 || SAMS70)
1089void pwm_channel_update_spread(Pwm *p_pwm, pwm_channel_t *p_channel,
1090 uint32_t ul_spread)
1091{
1092 /* Save new spread spectrum value */
1093 p_channel->ul_spread = ul_spread;
1094
1095 /* Write spread spectrum update register */
1096 p_pwm->PWM_SSPUP = PWM_SSPUP_SPRDUP(ul_spread);
1097}
1098
1107void pwm_channel_update_leading_edge(Pwm *p_pwm, pwm_channel_t *p_channel,
1108 uint32_t ul_leading_edge_delay,
1109 pwm_leading_edge_blanking_mode_t leading_edge_blanking_mode)
1110{
1111 /* Save new leading edge value */
1112 p_channel->ul_leading_edge_delay = ul_leading_edge_delay;
1113 p_channel->leading_edge_blanking_mode = leading_edge_blanking_mode;
1114
1115 /* Write channel leading edge update register */
1116 if (p_channel->channel == 1) {
1117 p_pwm->PWM_LEBR1 = PWM_LEBR1_LEBDELAY(ul_leading_edge_delay) | leading_edge_blanking_mode;
1118 } else if (p_channel->channel == 2) {
1119 p_pwm->PWM_LEBR2 = PWM_LEBR2_LEBDELAY(ul_leading_edge_delay) | leading_edge_blanking_mode;
1120 }
1121}
1122#endif
1123
1124#if (SAMV70 || SAMV71 || SAME70 || SAMS70)
1131void pwm_set_dma_duty(Pwm *p_pwm, uint32_t ul_dma_duty_value)
1132{
1133 uint32_t ul_mask = p_pwm->PWM_DMAR & (~PWM_DMAR_DMADUTY_Msk);
1134 p_pwm->PWM_DMAR = ul_mask | PWM_DMAR_DMADUTY(ul_dma_duty_value);
1135}
1136
1144void pwm_set_ext_trigger_mode(Pwm *p_pwm, pwm_channel_t *p_channel, uint32_t ul_mode)
1145{
1146 if (p_channel->channel == 1) {
1147 p_pwm->PWM_ETRG1 = ul_mode;
1148 } else if (p_channel->channel == 2) {
1149 p_pwm->PWM_ETRG2 = ul_mode;
1150 }
1151}
1152#endif
1153
1155
1157
1158#ifdef __cplusplus
1159}
1160#endif
1163
#define PWM_WPSR_WPVSRC_Pos
#define PWM_CMPM_CUPRCNT_Pos
#define PWM_SCUP_UPRCNT(value)
#define PWM_SCM_PTRCS(value)
#define PWM_SCM_PTRM
(PWM_SCM) PDC Transfer Request Mode
#define PWM_CMPM_CUPR(value)
#define PWM_DTUPD_DTLUPD(value)
#define PWM_SCUP_UPR(value)
#define PWM_DT_DTL(value)
#define PWM_OS_OSH0
(PWM_OS) Output Selection for PWMH output of the channel 0
#define PWM_DTUPD_DTHUPD(value)
#define PWM_CMPM_CPR(value)
#define PWM_DT_DTH(value)
#define PWM_SCUPUPD_UPRUPD(value)
#define PWM_SMMR_DOWN0
(PWM_SMMR) DOWN Count
#define PWM_CMPM_CPRCNT_Pos
#define PWM_WPSR_WPVS
(PWM_WPSR) Write Protect Violation Status
#define PWM_CMPV_CV(value)
#define PWM_OOV_OOVL0
(PWM_OOV) Output Override Value for PWML output of the channel 0
#define PWM_CMPM_CTR(value)
#define PWM_CMPM_CPRCNT(value)
#define PWM_WPSR_WPVSRC_Msk
(PWM_WPSR) Write Protect Violation Source
#define PWM_OS_OSL0
(PWM_OS) Output Selection for PWML output of the channel 0
#define PWM_SCUC_UPDULOCK
(PWM_SCUC) Synchronous Channels Update Unlock
#define PWM_CMPM_CEN
(PWM_CMPM) Comparison x Enable
#define PWM_CMPM_CUPRCNT(value)
#define PWM_SCM_UPDM_Msk
(PWM_SCM) Synchronous Channels Update Mode
#define PWM_OOV_OOVH0
(PWM_OOV) Output Override Value for PWMH output of the channel 0
#define PWM_SCM_PTRCS_Msk
(PWM_SCM) PDC Transfer Request Comparison Selection
#define PWM_SMMR_GCEN0
(PWM_SMMR) Gray Count ENable
void pwm_pdc_set_request_mode(Pwm *p_pwm, pwm_pdc_request_mode_t request_mode, uint32_t ul_cmp_unit)
Set PDC transfer request mode.
Definition pwm.c:809
void pwm_pdc_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
Disable the interrupt of PDC transfer.
Definition pwm.c:839
uint32_t pwm_channel_update_duty(Pwm *p_pwm, pwm_channel_t *p_channel, uint32_t ul_duty)
Change the duty cycle of the PWM channel.
Definition pwm.c:348
uint32_t pwm_get_interrupt_status(Pwm *p_pwm)
Get interrupt status of PDC transfer, synchronous channels and comparison.
Definition pwm.c:996
void pwm_pdc_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
Enable the interrupt of PDC transfer.
Definition pwm.c:828
uint32_t pwm_channel_get_interrupt_status(Pwm *p_pwm)
Get channel counter event and fault protection trigger interrupt status.
Definition pwm.c:434
uint32_t pwm_init(Pwm *p_pwm, pwm_clock_t *clock_config)
Initialize the PWM source clock (clock A and clock B).
Definition pwm.c:119
void pwm_stepper_motor_init(Pwm *p_pwm, pwm_stepper_motor_pair_t pair, bool b_enable_gray, bool b_down)
Initialize PWM stepper motor mode.
Definition pwm.c:1023
bool pwm_get_protect_status(Pwm *p_pwm, pwm_protect_t *p_protect)
Get PWM write protect status.
Definition pwm.c:971
void pwm_sync_unlock_update(Pwm *p_pwm)
Unlock the update of synchronous channels.
Definition pwm.c:876
#define PWM_CLOCK_DIV_MAX
Definition pwm.c:74
void pwm_disable_protect(Pwm *p_pwm, uint32_t ul_group)
Disable PWM write protect.
Definition pwm.c:956
uint32_t pwm_sync_get_period_counter(Pwm *p_pwm)
Get the value of the synchronization update period counter.
Definition pwm.c:899
#define PWM_WPCR_WPKEY_PASSWD
Definition pwm.c:59
void pwm_channel_enable_interrupt(Pwm *p_pwm, uint32_t ul_event, uint32_t ul_fault)
Enable the interrupt of a channel counter event and fault protection.
Definition pwm.c:467
void pwm_cmp_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources, pwm_cmp_interrupt_t type)
Enable the interrupt of comparison.
Definition pwm.c:767
uint32_t pwm_channel_get_status(Pwm *p_pwm)
Check which PWM channel is enabled.
Definition pwm.c:422
#define PWM_CLOCK_PRE_MAX
Definition pwm.c:75
void pwm_fault_clear_status(Pwm *p_pwm, pwm_fault_id_t id)
Clear a fault input.
Definition pwm.c:640
void pwm_channel_update_output(Pwm *p_pwm, pwm_channel_t *p_channel, pwm_output_t *p_output, bool b_sync)
Change output selection of the PWM channel.
Definition pwm.c:510
uint32_t pwm_channel_update_period(Pwm *p_pwm, pwm_channel_t *p_channel, uint32_t ul_period)
Change the period of the PWM channel.
Definition pwm.c:314
uint32_t pwm_cmp_change_setting(Pwm *p_pwm, pwm_cmp_t *p_cmp)
Change the setting of PWM comparison.
Definition pwm.c:696
void pwm_enable_protect(Pwm *p_pwm, uint32_t ul_group, bool b_sw)
Enable PWM write protect.
Definition pwm.c:933
void pwm_cmp_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources, pwm_cmp_interrupt_t type)
Disable the interrupt of comparison.
Definition pwm.c:787
void pwm_sync_disable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
Disable the interrupt of synchronous channels.
Definition pwm.c:921
uint32_t pwm_cmp_init(Pwm *p_pwm, pwm_cmp_t *p_cmp)
Initialize PWM comparison unit.
Definition pwm.c:653
void pwm_channel_disable_interrupt(Pwm *p_pwm, uint32_t ul_event, uint32_t ul_fault)
Disable the interrupt of a channel counter event and fault protection.
Definition pwm.c:488
uint32_t pwm_fault_get_status(Pwm *p_pwm)
Get fault status.
Definition pwm.c:613
uint32_t pwm_fault_init(Pwm *p_pwm, pwm_fault_t *p_fault)
Initialize the behavior of a fault input.
Definition pwm.c:577
pwm_level_t pwm_fault_get_input_level(Pwm *p_pwm, pwm_fault_id_t id)
Get the level of a fault input.
Definition pwm.c:626
#define PWM_WPCR_WPCMD_DISABLE_SW_PROT
Definition pwm.c:63
uint32_t pwm_channel_get_counter(Pwm *p_pwm, pwm_channel_t *p_channel)
Return channel counter value.
Definition pwm.c:383
uint32_t pwm_get_interrupt_mask(Pwm *p_pwm)
Get interrupt mask of PDC transfer, synchronous channels and comparison.
Definition pwm.c:1008
void pwm_sync_change_period(Pwm *p_pwm, uint32_t ul_update_period)
Change the wanted time between each update of the synchronous channels.
Definition pwm.c:887
void pwm_channel_disable(Pwm *p_pwm, uint32_t ul_channel)
Disable the PWM channel.
Definition pwm.c:410
uint32_t pwm_cmp_get_update_counter(Pwm *p_pwm, uint32_t ul_cmp_unit)
Report the value of the comparison update period counter.
Definition pwm.c:753
#define PWM_WPCR_WPCMD_ENABLE_HW_PROT
Definition pwm.c:71
uint32_t pwm_channel_get_interrupt_mask(Pwm *p_pwm)
Get channel counter event and fault protection trigger interrupt mask.
Definition pwm.c:450
#define PWM_WPCR_WPCMD_ENABLE_SW_PROT
Definition pwm.c:67
uint32_t pwm_cmp_get_period_counter(Pwm *p_pwm, uint32_t ul_cmp_unit)
Report the value of the comparison period counter.
Definition pwm.c:739
void pwm_channel_update_dead_time(Pwm *p_pwm, pwm_channel_t *p_channel, uint16_t us_deadtime_pwmh, uint16_t us_deadtime_pwml)
Change dead-time value for PWM outputs.
Definition pwm.c:554
uint32_t pwm_sync_init(Pwm *p_pwm, pwm_sync_update_mode_t mode, uint32_t ul_update_period)
Initialize synchronous channels update mode and period.
Definition pwm.c:854
void pwm_sync_enable_interrupt(Pwm *p_pwm, uint32_t ul_sources)
Enable the interrupt of synchronous channel.
Definition pwm.c:910
static uint32_t pwm_clocks_generate(uint32_t ul_frequency, uint32_t ul_mck)
Find a prescaler/divisor couple to generate the desired ul_frequency from ul_mck.
Definition pwm.c:87
uint32_t pwm_channel_init(Pwm *p_pwm, pwm_channel_t *p_channel)
Initialize one PWM channel.
Definition pwm.c:160
void pwm_channel_enable(Pwm *p_pwm, uint32_t ul_channel)
Enable the PWM channel.
Definition pwm.c:397
Pulse Width Modulation (PWM) driver for SAM.
pwm_level_t
Definitions for PWM level.
Definition pwm.h:73
@ PWM_LOW
Definition pwm.h:74
@ PWM_HIGH
Definition pwm.h:75
pwm_sync_update_mode_t
Definitions for PWM synchronous channels update mode.
Definition pwm.h:103
pwm_pdc_request_mode_t
Definitions for PWM PDC transfer request mode.
Definition pwm.h:190
pwm_cmp_interrupt_t
Definitions for PWM comparison interrupt.
Definition pwm.h:172
@ PWM_CMP_UPDATE
Definition pwm.h:174
@ PWM_CMP_MATCH
Definition pwm.h:173
#define PWM_INVALID_ARGUMENT
Definition pwm.h:50
pwm_fault_id_t
Definitions for PWM fault input ID.
Definition pwm.h:116
pwm_stepper_motor_pair_t
Definitions for PWM channels used by motor stepper.
Definition pwm.h:93
__O uint32_t PWM_DTUPD
(PwmCh_num Offset: 0x1C) PWM Channel Dead Time Update Register
__O uint32_t PWM_CPRDUPD
(PwmCh_num Offset: 0x10) PWM Channel Period Update Register
__I uint32_t PWM_CCNT
(PwmCh_num Offset: 0x14) PWM Channel Counter Register
__IO uint32_t PWM_CMR
(PwmCh_num Offset: 0x0) PWM Channel Mode Register
__O uint32_t PWM_CDTYUPD
(PwmCh_num Offset: 0x8) PWM Channel Duty Cycle Update Register
__IO uint32_t PWM_CPRD
(PwmCh_num Offset: 0xC) PWM Channel Period Register
__IO uint32_t PWM_CDTY
(PwmCh_num Offset: 0x4) PWM Channel Duty Cycle Register
__IO uint32_t PWM_DT
(PwmCh_num Offset: 0x18) PWM Channel Dead Time Register
__IO uint32_t PWM_CMPM
(PwmCmp Offset: 0x8) PWM Comparison 0 Mode Register
__IO uint32_t PWM_CMPV
(PwmCmp Offset: 0x0) PWM Comparison 0 Value Register
__O uint32_t PWM_CMPMUPD
(PwmCmp Offset: 0xC) PWM Comparison 0 Mode Update Register
__O uint32_t PWM_CMPVUPD
(PwmCmp Offset: 0x4) PWM Comparison 0 Value Update Register
__IO uint32_t PWM_FMR
(Pwm Offset: 0x5C) PWM Fault Mode Register
__I uint32_t PWM_IMR1
(Pwm Offset: 0x18) PWM Interrupt Mask Register 1
__I uint32_t PWM_IMR2
(Pwm Offset: 0x3C) PWM Interrupt Mask Register 2
__O uint32_t PWM_OSCUPD
(Pwm Offset: 0x58) PWM Output Selection Clear Update Register
__O uint32_t PWM_WPCR
(Pwm Offset: 0xE4) PWM Write Protection Control Register
__IO uint32_t PWM_SCM
(Pwm Offset: 0x20) PWM Sync Channels Mode Register
__I uint32_t PWM_FSR
(Pwm Offset: 0x60) PWM Fault Status Register
__IO uint32_t PWM_SCUC
(Pwm Offset: 0x28) PWM Sync Channels Update Control Register
__IO uint32_t PWM_ELMR[2]
(Pwm Offset: 0x7C) PWM Event Line 0 Mode Register
__O uint32_t PWM_IDR2
(Pwm Offset: 0x38) PWM Interrupt Disable Register 2
__I uint32_t PWM_SR
(Pwm Offset: 0x0C) PWM Status Register
__O uint32_t PWM_OSSUPD
(Pwm Offset: 0x54) PWM Output Selection Set Update Register
__O uint32_t PWM_SCUPUPD
(Pwm Offset: 0x30) PWM Sync Channels Update Period Update Register
__I uint32_t PWM_ISR2
(Pwm Offset: 0x40) PWM Interrupt Status Register 2
__IO uint32_t PWM_FPE
(Pwm Offset: 0x6C) PWM Fault Protection Enable Register
__O uint32_t PWM_IER1
(Pwm Offset: 0x10) PWM Interrupt Enable Register 1
__O uint32_t PWM_IER2
(Pwm Offset: 0x34) PWM Interrupt Enable Register 2
__O uint32_t PWM_DIS
(Pwm Offset: 0x08) PWM Disable Register
__O uint32_t PWM_OSS
(Pwm Offset: 0x4C) PWM Output Selection Set Register
__IO uint32_t PWM_OOV
(Pwm Offset: 0x44) PWM Output Override Value Register
__I uint32_t PWM_WPSR
(Pwm Offset: 0xE8) PWM Write Protection Status Register
PwmCh_num PWM_CH_NUM[PWMCH_NUM_NUMBER]
(Pwm Offset: 0x200) ch_num = 0 .
__O uint32_t PWM_FCR
(Pwm Offset: 0x64) PWM Fault Clear Register
__I uint32_t PWM_ISR1
(Pwm Offset: 0x1C) PWM Interrupt Status Register 1
__O uint32_t PWM_IDR1
(Pwm Offset: 0x14) PWM Interrupt Disable Register 1
PwmCmp PWM_CMP[PWMCMP_NUMBER]
(Pwm Offset: 0x130) 0 .
__IO uint32_t PWM_SMMR
(Pwm Offset: 0xB0) PWM Stepper Motor Mode Register
__IO uint32_t PWM_OS
(Pwm Offset: 0x48) PWM Output Selection Register
__IO uint32_t PWM_CLK
(Pwm Offset: 0x00) PWM Clock Register
__IO uint32_t PWM_SCUP
(Pwm Offset: 0x2C) PWM Sync Channels Update Period Register
__O uint32_t PWM_ENA
(Pwm Offset: 0x04) PWM Enable Register
__IO uint32_t PWM_FPV
(Pwm Offset: 0x68) PWM Fault Protection Value Register
__O uint32_t PWM_OSC
(Pwm Offset: 0x50) PWM Output Selection Clear Register
Input parameters when configuring a PWM channel mode.
Definition pwm.h:284
pwm_align_t alignment
Channel alignment.
Definition pwm.h:290
pwm_fault_id_t fault_id
Fault ID of the channel.
Definition pwm.h:316
bool b_pwml_output_inverted
Boolean of channel dead-time PWML output inverted.
Definition pwm.h:306
bool b_pwmh_output_inverted
Boolean of channel dead-time PWMH output inverted.
Definition pwm.h:304
bool b_deadtime_generator
Boolean of channel dead-time generator.
Definition pwm.h:302
pwm_level_t ul_fault_output_pwml
Channel PWML output level in fault protection.
Definition pwm.h:320
bool b_sync_ch
Boolean of Synchronous Channel.
Definition pwm.h:314
uint16_t us_deadtime_pwml
Dead-time Value for PWML Output.
Definition pwm.h:310
pwm_level_t polarity
Channel initial polarity.
Definition pwm.h:292
uint32_t ul_period
Period Cycle Value.
Definition pwm.h:296
uint32_t ul_prescaler
Channel prescaler.
Definition pwm.h:288
pwm_output_t output_selection
Channel output.
Definition pwm.h:312
uint32_t channel
Channel number.
Definition pwm.h:286
pwm_counter_event_t counter_event
Channel counter event.
Definition pwm.h:300
pwm_level_t ul_fault_output_pwmh
Channel PWMH output level in fault protection.
Definition pwm.h:318
uint16_t us_deadtime_pwmh
Dead-time Value for PWMH Output.
Definition pwm.h:308
uint32_t ul_duty
Duty Cycle Value.
Definition pwm.h:294
Input parameters when initializing PWM.
Definition pwm.h:82
uint32_t ul_clkb
Frequency of clock B in Hz (set 0 to turn it off).
Definition pwm.h:86
uint32_t ul_mck
Frequency of master clock in Hz.
Definition pwm.h:88
uint32_t ul_clka
Frequency of clock A in Hz (set 0 to turn it off).
Definition pwm.h:84
Configurations of PWM comparison.
Definition pwm.h:239
bool b_enable
Boolean of comparison enable.
Definition pwm.h:243
uint32_t ul_value
Comparison value.
Definition pwm.h:245
uint32_t ul_period
Comparison period value.
Definition pwm.h:251
uint32_t ul_trigger
Comparison trigger value.
Definition pwm.h:249
bool b_is_decrementing
Comparison mode.
Definition pwm.h:247
uint32_t ul_update_period
Comparison update period value.
Definition pwm.h:253
uint32_t unit
Comparison unit number.
Definition pwm.h:241
bool b_pulse_on_line_0
Boolean of generating a match pulse on PWM event line 0.
Definition pwm.h:255
bool b_pulse_on_line_1
Boolean of generating a match pulse on PWM event line 1.
Definition pwm.h:257
Configuration of PWM fault input behaviors.
Definition pwm.h:261
bool b_filtered
Boolean of fault filtering.
Definition pwm.h:269
pwm_fault_id_t fault_id
Fault ID.
Definition pwm.h:263
pwm_level_t polarity
Polarity of fault input.
Definition pwm.h:265
bool b_clear
Boolean of clearing fault flag.
Definition pwm.h:267
Configurations of a PWM channel output.
Definition pwm.h:227
bool b_override_pwml
Boolean of using override output as PWML.
Definition pwm.h:231
pwm_level_t override_level_pwml
Level of override output for PWML.
Definition pwm.h:235
pwm_level_t override_level_pwmh
Level of override output for PWMH.
Definition pwm.h:233
bool b_override_pwmh
Boolean of using override output as PWMH.
Definition pwm.h:229
Structure of PWM write-protect information.
Definition pwm.h:273
uint32_t ul_sw_status
Bitmask of PWM register group for write protect software status.
Definition pwm.h:277
uint32_t ul_offset
Offset address of PWM register in which a write access has been attempted.
Definition pwm.h:279
uint32_t ul_hw_status
Bitmask of PWM register group for write protect hardware status.
Definition pwm.h:275