]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/pwmc.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / pwmc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2011, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup pwm_module Working with PWM\r
31  *  \ingroup peripherals_module\r
32  * The PWM driver provides the interface to configure and use the PWM\r
33  * peripheral.\r
34  *\r
35  * The PWM macrocell controls square output waveforms of 4 channels.\r
36  * Characteristics of output waveforms such as period, duty-cycle,\r
37  * dead-time can be configured.\n\r
38  * Some of PWM channels can be linked together as synchronous channel and\r
39  * duty-cycle of synchronous channels can be updated by PDC automaticly.\r
40  *\r
41  * Before enabling the channels, they must have been configured first.\r
42  * The main settings include:\r
43  * <ul>\r
44  * <li>Configuration of the clock generator.</li>\r
45  * <li>Selection of the clock for each channel.</li>\r
46  * <li>Configuration of output waveform characteristics, such as period, duty-cycle etc.</li>\r
47  * <li>Configuration for synchronous channels if needed.</li>\r
48  *    - Selection of the synchronous channels.\r
49  *    - Selection of the moment when the WRDY flag and the corresponding PDC\r
50  *      transfer request are set (PTRM and PTRCS in the PWM_SCM register).\r
51  *    - Configuration of the update mode (UPDM in the PWM_SCM register).\r
52  *    - Configuration of the update period (UPR in the PWM_SCUP register).\r
53  * </ul>\r
54  *\r
55  * After the channels is enabled, the user must use respective update registers\r
56  * to change the wave characteristics to prevent unexpected output waveform.\r
57  * i.e. PWM_CDTYUPDx register should be used if user want to change duty-cycle\r
58  * when the channel is enabled.\r
59  *\r
60  * For more accurate information, please look at the PWM section of the\r
61  * Datasheet.\r
62  *\r
63  * Related files :\n\r
64  * \ref pwmc.c\n\r
65  * \ref pwmc.h.\n\r
66  */\r
67 /*@{*/\r
68 /*@}*/\r
69 \r
70 /**\r
71  * \file\r
72  *\r
73  * Implementation of the Pulse Width Modulation Controller (PWM) peripheral.\r
74  *\r
75  */\r
76 \r
77 /*----------------------------------------------------------------------------\r
78  *        Headers\r
79  *----------------------------------------------------------------------------*/\r
80 \r
81 #include "chip.h"\r
82 \r
83 #include <stdint.h>\r
84 #include <assert.h>\r
85 \r
86 /*----------------------------------------------------------------------------\r
87  *         Local functions\r
88  *----------------------------------------------------------------------------*/\r
89 \r
90 /**\r
91  * \brief Finds a prescaler/divisor couple to generate the desired frequency\r
92  * from MCK.\r
93  *\r
94  * Returns the value to enter in PWM_CLK or 0 if the configuration cannot be\r
95  * met.\r
96  *\r
97  * \param frequency  Desired frequency in Hz.\r
98  * \param mck  Master clock frequency in Hz.\r
99  */\r
100 static uint16_t FindClockConfiguration(\r
101         uint32_t frequency,\r
102         uint32_t mck)\r
103 {\r
104     uint32_t divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};\r
105     uint8_t divisor = 0;\r
106     uint32_t prescaler;\r
107 \r
108     assert(frequency < mck);\r
109 \r
110     /* Find prescaler and divisor values */\r
111     prescaler = (mck / divisors[divisor]) / frequency;\r
112     while ((prescaler > 255) && (divisor < 11)) {\r
113 \r
114         divisor++;\r
115         prescaler = (mck / divisors[divisor]) / frequency;\r
116     }\r
117 \r
118     /* Return result */\r
119     if ( divisor < 11 )\r
120     {\r
121         TRACE_DEBUG( "Found divisor=%u and prescaler=%u for freq=%uHz\n\r", divisors[divisor], prescaler, frequency ) ;\r
122 \r
123         return prescaler | (divisor << 8) ;\r
124     }\r
125     else\r
126     {\r
127         return 0 ;\r
128     }\r
129 }\r
130 \r
131 /*----------------------------------------------------------------------------\r
132  *        Exported functions\r
133  *----------------------------------------------------------------------------*/\r
134 \r
135 /**\r
136  * \brief Configures PWM a channel with the given parameters, basic configure function.\r
137  *\r
138  * The PWM controller must have been clocked in the PMC prior to calling this\r
139  * function.\r
140  * Beware: this function disables the channel. It waits until disable is effective.\r
141  *\r
142  * \param channel  Channel number.\r
143  * \param prescaler  Channel prescaler.\r
144  * \param alignment  Channel alignment.\r
145  * \param polarity  Channel polarity.\r
146  */\r
147 void PWMC_ConfigureChannel(\r
148         Pwm* pPwm,\r
149         uint8_t channel,\r
150         uint32_t prescaler,\r
151         uint32_t alignment,\r
152         uint32_t polarity)\r
153 {\r
154     pPwm->PWM_CH_NUM[0].PWM_CMR = 1;\r
155 \r
156     //    assert(prescaler < PWM_CMR0_CPRE_MCKB);\r
157     assert((alignment & (uint32_t)~PWM_CMR_CALG) == 0);\r
158     assert((polarity & (uint32_t)~PWM_CMR_CPOL) == 0);\r
159 \r
160     /* Disable channel (effective at the end of the current period) */\r
161     if ((pPwm->PWM_SR & (1 << channel)) != 0) {\r
162         pPwm->PWM_DIS = 1 << channel;\r
163         while ((pPwm->PWM_SR & (1 << channel)) != 0);\r
164     }\r
165 \r
166     /* Configure channel */\r
167     pPwm->PWM_CH_NUM[channel].PWM_CMR = prescaler | alignment | polarity;\r
168 }\r
169 \r
170 /**\r
171  * \brief Configures PWM a channel with the given parameters, extend configure function.\r
172  *\r
173  * The PWM controller must have been clocked in the PMC prior to calling this\r
174  * function.\r
175  * Beware: this function disables the channel. It waits until disable is effective.\r
176  *\r
177  * \param channel            Channel number.\r
178  * \param prescaler          Channel prescaler.\r
179  * \param alignment          Channel alignment.\r
180  * \param polarity           Channel polarity.\r
181  * \param countEventSelect   Channel counter event selection.\r
182  * \param DTEnable           Channel dead time generator enable.\r
183  * \param DTHInverte         Channel Dead-Time PWMHx output Inverted.\r
184  * \param DTLInverte         Channel Dead-Time PWMHx output Inverted.\r
185  */\r
186 void PWMC_ConfigureChannelExt(\r
187         Pwm* pPwm,\r
188         uint8_t channel,\r
189         uint32_t prescaler,\r
190         uint32_t alignment,\r
191         uint32_t polarity,\r
192         uint32_t countEventSelect,\r
193         uint32_t DTEnable,\r
194         uint32_t DTHInverte,\r
195         uint32_t DTLInverte)\r
196 {\r
197     //    assert(prescaler < PWM_CMR0_CPRE_MCKB);\r
198     assert((alignment & (uint32_t)~PWM_CMR_CALG) == 0);\r
199     assert((polarity & (uint32_t)~PWM_CMR_CPOL) == 0);\r
200     assert((countEventSelect & (uint32_t)~PWM_CMR_CES) == 0);\r
201     assert((DTEnable & (uint32_t)~PWM_CMR_DTE) == 0);\r
202     assert((DTHInverte & (uint32_t)~PWM_CMR_DTHI) == 0);\r
203     assert((DTLInverte & (uint32_t)~PWM_CMR_DTLI) == 0);\r
204 \r
205     /* Disable channel (effective at the end of the current period) */\r
206     if ((pPwm->PWM_SR & (1 << channel)) != 0) {\r
207         pPwm->PWM_DIS = 1 << channel;\r
208         while ((pPwm->PWM_SR & (1 << channel)) != 0);\r
209     }\r
210 \r
211     /* Configure channel */\r
212     pPwm->PWM_CH_NUM[channel].PWM_CMR = prescaler | alignment | polarity |\r
213         countEventSelect | DTEnable | DTHInverte | DTLInverte;\r
214 }\r
215 \r
216 /**\r
217  * \brief Configures PWM clocks A & B to run at the given frequencies.\r
218  *\r
219  * This function finds the best MCK divisor and prescaler values automatically.\r
220  *\r
221  * \param clka  Desired clock A frequency (0 if not used).\r
222  * \param clkb  Desired clock B frequency (0 if not used).\r
223  * \param mck  Master clock frequency.\r
224  */\r
225 void PWMC_ConfigureClocks(Pwm* pPwm, uint32_t clka, uint32_t clkb, uint32_t mck)\r
226 {\r
227     uint32_t mode = 0;\r
228     uint32_t result;\r
229 \r
230     /* Clock A */\r
231     if (clka != 0) {\r
232 \r
233         result = FindClockConfiguration(clka, mck);\r
234         assert( result != 0 ) ;\r
235         mode |= result;\r
236     }\r
237 \r
238     /* Clock B */\r
239     if (clkb != 0) {\r
240 \r
241         result = FindClockConfiguration(clkb, mck);\r
242         assert( result != 0 ) ;\r
243         mode |= (result << 16);\r
244     }\r
245 \r
246     /* Configure clocks */\r
247     TRACE_DEBUG( "Setting PWM_CLK = 0x%08X\n\r", mode ) ;\r
248     pPwm->PWM_CLK = mode;\r
249 }\r
250 \r
251 /**\r
252  * \brief Sets the period value used by a PWM channel.\r
253  *\r
254  * This function writes directly to the CPRD register if the channel is disabled;\r
255  * otherwise, it uses the update register CPRDUPD.\r
256  *\r
257  * \param channel Channel number.\r
258  * \param period  Period value.\r
259  */\r
260 void PWMC_SetPeriod( Pwm* pPwm, uint8_t channel, uint16_t period)\r
261 {\r
262     /* If channel is disabled, write to CPRD */\r
263     if ((pPwm->PWM_SR & (1 << channel)) == 0) {\r
264 \r
265         pPwm->PWM_CH_NUM[channel].PWM_CPRD = period;\r
266     }\r
267     /* Otherwise use update register */\r
268     else {\r
269 \r
270         pPwm->PWM_CH_NUM[channel].PWM_CPRDUPD = period;\r
271     }\r
272 }\r
273 \r
274 /**\r
275  * \brief Sets the duty cycle used by a PWM channel.\r
276  * This function writes directly to the CDTY register if the channel is disabled;\r
277  * otherwise it uses the update register CDTYUPD.\r
278  * Note that the duty cycle must always be inferior or equal to the channel\r
279  * period.\r
280  *\r
281  * \param channel  Channel number.\r
282  * \param duty     Duty cycle value.\r
283  */\r
284 void PWMC_SetDutyCycle( Pwm* pPwm, uint8_t channel, uint16_t duty)\r
285 {\r
286     assert(duty <= pPwm->PWM_CH_NUM[channel].PWM_CPRD);\r
287 \r
288     /* If channel is disabled, write to CDTY */\r
289     if ((pPwm->PWM_SR & (1 << channel)) == 0) {\r
290 \r
291         pPwm->PWM_CH_NUM[channel].PWM_CDTY = duty;\r
292     }\r
293     /* Otherwise use update register */\r
294     else {\r
295 \r
296         pPwm->PWM_CH_NUM[channel].PWM_CDTYUPD = duty;\r
297     }\r
298 }\r
299 \r
300 /**\r
301  * \brief Sets the dead time used by a PWM channel.\r
302  * This function writes directly to the DT register if the channel is disabled;\r
303  * otherwise it uses the update register DTUPD.\r
304  * Note that the dead time must always be inferior or equal to the channel\r
305  * period.\r
306  *\r
307  * \param channel  Channel number.\r
308  * \param timeH    Dead time value for PWMHx output.\r
309  * \param timeL    Dead time value for PWMLx output.\r
310  */\r
311 void PWMC_SetDeadTime( Pwm* pPwm, uint8_t channel, uint16_t timeH, uint16_t timeL)\r
312 {\r
313     assert(timeH <= pPwm->PWM_CH_NUM[channel].PWM_CPRD);\r
314     assert(timeL <= pPwm->PWM_CH_NUM[channel].PWM_CPRD);\r
315 \r
316     /* If channel is disabled, write to DT */\r
317     if ((pPwm->PWM_SR & (1 << channel)) == 0) {\r
318 \r
319         pPwm->PWM_CH_NUM[channel].PWM_DT = timeH | (timeL << 16);\r
320     }\r
321     /* Otherwise use update register */\r
322     else {\r
323         pPwm->PWM_CH_NUM[channel].PWM_DTUPD = timeH | (timeL << 16);\r
324     }\r
325 }\r
326 \r
327 /**\r
328  * \brief Configures Syncronous channel with the given parameters.\r
329  * Beware: At this time, the channels should be disabled.\r
330  *\r
331  * \param channels                 Bitwise OR of Syncronous channels.\r
332  * \param updateMode               Syncronous channel update mode.\r
333  * \param requestMode              PDC transfer request mode.\r
334  * \param requestComparisonSelect  PDC transfer request comparison selection.\r
335  */\r
336 void PWMC_ConfigureSyncChannel( Pwm* pPwm,\r
337         uint32_t channels,\r
338         uint32_t updateMode,\r
339         uint32_t requestMode,\r
340         uint32_t requestComparisonSelect)\r
341 {\r
342     pPwm->PWM_SCM = channels | updateMode | requestMode | requestComparisonSelect;\r
343 }\r
344 \r
345 /**\r
346  * \brief Sets the update period of the synchronous channels.\r
347  * This function writes directly to the SCUP register if the channel #0 is disabled;\r
348  * otherwise it uses the update register SCUPUPD.\r
349  *\r
350  * \param period   update period.\r
351  */\r
352 void PWMC_SetSyncChannelUpdatePeriod( Pwm* pPwm, uint8_t period)\r
353 {\r
354     /* If channel is disabled, write to SCUP */\r
355     if ((pPwm->PWM_SR & (1 << 0)) == 0) {\r
356 \r
357         pPwm->PWM_SCUP = period;\r
358     }\r
359     /* Otherwise use update register */\r
360     else {\r
361 \r
362         pPwm->PWM_SCUPUPD = period;\r
363     }\r
364 }\r
365 \r
366 /**\r
367  * \brief Sets synchronous channels update unlock.\r
368  *\r
369  * Note: If the UPDM field is set to 0, writing the UPDULOCK bit to 1\r
370  * triggers the update of the period value, the duty-cycle and\r
371  * the dead-time values of synchronous channels at the beginning\r
372  * of the next PWM period. If the field UPDM is set to 1 or 2,\r
373  * writing the UPDULOCK bit to 1 triggers only the update of\r
374  * the period value and of the dead-time values of synchronous channels.\r
375  * This bit is automatically reset when the update is done.\r
376  */\r
377 void PWMC_SetSyncChannelUpdateUnlock( Pwm* pPwm )\r
378 {\r
379     pPwm->PWM_SCUC = PWM_SCUC_UPDULOCK;\r
380 }\r
381 \r
382 /**\r
383  * \brief Enables the given PWM channel.\r
384  *\r
385  * This does NOT enable the corresponding pin;this must be done in the user code.\r
386  *\r
387  * \param channel  Channel number.\r
388  */\r
389 void PWMC_EnableChannel( Pwm* pPwm, uint8_t channel)\r
390 {\r
391     pPwm->PWM_ENA = 1 << channel;\r
392 }\r
393 \r
394 /**\r
395  * \brief Disables the given PWM channel.\r
396  *\r
397  * Beware, channel will be effectively disabled at the end of the current period.\r
398  * Application can check channel is disabled using the following wait loop:\r
399  * while ((PWM->PWM_SR & (1 << channel)) != 0);\r
400  *\r
401  * \param channel  Channel number.\r
402  */\r
403 void PWMC_DisableChannel( Pwm* pPwm, uint8_t channel)\r
404 {\r
405     pPwm->PWM_DIS = 1 << channel;\r
406 }\r
407 \r
408 /**\r
409  * \brief Enables the period interrupt for the given PWM channel.\r
410  *\r
411  * \param channel  Channel number.\r
412  */\r
413 void PWMC_EnableChannelIt( Pwm* pPwm, uint8_t channel)\r
414 {\r
415     pPwm->PWM_IER1 = 1 << channel;\r
416 }\r
417 \r
418 /**\r
419  * \brief Return PWM Interrupt Status2 Register\r
420  *\r
421  */\r
422 uint32_t PWMC_GetStatus2( Pwm* pPwm)\r
423 {\r
424     return pPwm->PWM_ISR2;\r
425 }\r
426 \r
427 /**\r
428  * \brief Disables the period interrupt for the given PWM channel.\r
429  *\r
430  * \param channel  Channel number.\r
431  */\r
432 void PWMC_DisableChannelIt( Pwm* pPwm, uint8_t channel)\r
433 {\r
434     pPwm->PWM_IDR1 = 1 << channel;\r
435 }\r
436 \r
437 /**\r
438  * \brief Enables the selected interrupts sources on a PWMC peripheral.\r
439  *\r
440  * \param sources1  Bitwise OR of selected interrupt sources of PWM_IER1.\r
441  * \param sources2  Bitwise OR of selected interrupt sources of PWM_IER2.\r
442  */\r
443 void PWMC_EnableIt( Pwm* pPwm, uint32_t sources1, uint32_t sources2)\r
444 {\r
445     pPwm->PWM_IER1 = sources1;\r
446     pPwm->PWM_IER2 = sources2;\r
447 }\r
448 \r
449 /**\r
450  * \brief Disables the selected interrupts sources on a PWMC peripheral.\r
451  *\r
452  * \param sources1  Bitwise OR of selected interrupt sources of PWM_IDR1.\r
453  * \param sources2  Bitwise OR of selected interrupt sources of PWM_IDR2.\r
454  */\r
455 void PWMC_DisableIt( Pwm* pPwm, uint32_t sources1, uint32_t sources2)\r
456 {\r
457     pPwm->PWM_IDR1 = sources1;\r
458     pPwm->PWM_IDR2 = sources2;\r
459 }\r
460 \r
461 /**\r
462  * \brief Set PWM output override value.\r
463  *\r
464  * \param value  Bitwise OR of output override value.\r
465  */\r
466 void PWMC_SetOverrideValue( Pwm* pPwm, uint32_t value)\r
467 {\r
468     pPwm->PWM_OOV = value;\r
469 }\r
470 \r
471 /**\r
472  * \brief Enalbe override output.\r
473  *\r
474  * \param value  Bitwise OR of output selection.\r
475  * \param sync   0: enable the output asyncronously, 1: enable it syncronously\r
476  */\r
477 void PWMC_EnableOverrideOutput( Pwm* pPwm, uint32_t value, uint32_t sync)\r
478 {\r
479     if (sync) {\r
480 \r
481         pPwm->PWM_OSSUPD = value;\r
482     } else {\r
483 \r
484         pPwm->PWM_OSS = value;\r
485     }\r
486 }\r
487 \r
488 /**\r
489  * \brief Output Selection for override PWM output.\r
490  *\r
491  * \param value  Bitwise OR of output override value.\r
492  */\r
493 void PWMC_OutputOverrideSelection( Pwm* pPwm, uint32_t value )\r
494 {\r
495     pPwm->PWM_OS = value;\r
496 }\r
497 \r
498 \r
499 /**\r
500  * \brief Disalbe override output.\r
501  *\r
502  * \param value  Bitwise OR of output selection.\r
503  * \param sync   0: enable the output asyncronously, 1: enable it syncronously\r
504  */\r
505 void PWMC_DisableOverrideOutput( Pwm* pPwm, uint32_t value, uint32_t sync)\r
506 {\r
507     if (sync) {\r
508 \r
509         pPwm->PWM_OSCUPD = value;\r
510     } else {\r
511 \r
512         pPwm->PWM_OSC = value;\r
513     }\r
514 }\r
515 \r
516 /**\r
517  * \brief Set PWM fault mode.\r
518  *\r
519  * \param mode  Bitwise OR of fault mode.\r
520  */\r
521 void PWMC_SetFaultMode( Pwm* pPwm, uint32_t mode)\r
522 {\r
523     pPwm->PWM_FMR = mode;\r
524 }\r
525 \r
526 /**\r
527  * \brief PWM fault clear.\r
528  *\r
529  * \param fault  Bitwise OR of fault to clear.\r
530  */\r
531 void PWMC_FaultClear( Pwm* pPwm, uint32_t fault)\r
532 {\r
533     pPwm->PWM_FCR = fault;\r
534 }\r
535 \r
536 /**\r
537  * \brief Set PWM fault protection value.\r
538  *\r
539  * \param value  Bitwise OR of fault protection value.\r
540  */\r
541 void PWMC_SetFaultProtectionValue( Pwm* pPwm, uint32_t value)\r
542 {\r
543     pPwm->PWM_FPV1 = value;\r
544 }\r
545 \r
546 /**\r
547  * \brief Enable PWM fault protection.\r
548  *\r
549  * \param value  Bitwise OR of FPEx[y].\r
550  */\r
551 void PWMC_EnableFaultProtection( Pwm* pPwm, uint32_t value)\r
552 {\r
553     pPwm->PWM_FPE = value;\r
554 }\r
555 \r
556 /**\r
557  * \brief Configure comparison unit.\r
558  *\r
559  * \param x     comparison x index\r
560  * \param value comparison x value.\r
561  * \param mode  comparison x mode\r
562  */\r
563 void PWMC_ConfigureComparisonUnit( Pwm* pPwm, uint32_t x, uint32_t value, uint32_t mode)\r
564 {\r
565     assert(x < 8);\r
566 \r
567     /* If channel is disabled, write to CMPxM & CMPxV */\r
568     if ((pPwm->PWM_SR & (1 << 0)) == 0) {\r
569         pPwm->PWM_CMP[x].PWM_CMPM = mode;\r
570         pPwm->PWM_CMP[x].PWM_CMPV = value;\r
571     }\r
572     /* Otherwise use update register */\r
573     else {\r
574         pPwm->PWM_CMP[x].PWM_CMPMUPD = mode;\r
575         pPwm->PWM_CMP[x].PWM_CMPVUPD = value;\r
576     }\r
577 }\r
578 \r
579 /**\r
580  * \brief Configure event line mode.\r
581  *\r
582  * \param x    Line x\r
583  * \param mode Bitwise OR of line mode selection\r
584  */\r
585 void PWMC_ConfigureEventLineMode( Pwm* pPwm, uint32_t x, uint32_t mode)\r
586 {\r
587     assert(x < 2);\r
588 \r
589     if (x == 0) {\r
590         pPwm->PWM_ELMR[0] = mode;\r
591     } else if (x == 1) {\r
592         pPwm->PWM_ELMR[1] = mode;\r
593     }\r
594 }\r