00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2011, Atmel Corporation 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the disclaimer below. 00013 * 00014 * Atmel's name may not be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00020 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00023 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00024 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00025 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00026 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 * ---------------------------------------------------------------------------- 00028 */ 00029 00030 /** \addtogroup pwm_module Working with PWM 00031 * \ingroup peripherals_module 00032 * The PWM driver provides the interface to configure and use the PWM 00033 * peripheral. 00034 * 00035 * The PWM macrocell controls square output waveforms of 4 channels. 00036 * Characteristics of output waveforms such as period, duty-cycle, 00037 * dead-time can be configured.\n 00038 * Some of PWM channels can be linked together as synchronous channel and 00039 * duty-cycle of synchronous channels can be updated by PDC automatically. 00040 * 00041 * Before enabling the channels, they must have been configured first. 00042 * The main settings include: 00043 * <ul> 00044 * <li>Configuration of the clock generator.</li> 00045 * <li>Selection of the clock for each channel.</li> 00046 * <li>Configuration of output waveform characteristics, such as period, 00047 * duty-cycle etc.</li> 00048 * <li>Configuration for synchronous channels if needed.</li> 00049 * - Selection of the synchronous channels. 00050 * - Selection of the moment when the WRDY flag and the corresponding PDC 00051 * transfer request are set (PTRM and PTRCS in the PWM_SCM register). 00052 * - Configuration of the update mode (UPDM in the PWM_SCM register). 00053 * - Configuration of the update period (UPR in the PWM_SCUP register). 00054 * </ul> 00055 * 00056 * After the channels is enabled, the user must use respective update registers 00057 * to change the wave characteristics to prevent unexpected output waveform. 00058 * i.e. PWM_CDTYUPDx register should be used if user want to change duty-cycle 00059 * when the channel is enabled. 00060 * 00061 * For more accurate information, please look at the PWM section of the 00062 * Datasheet. 00063 * 00064 * Related files :\n 00065 * \ref pwmc.c\n 00066 * \ref pwmc.h.\n 00067 */ 00068 /*@{*/ 00069 /*@}*/ 00070 00071 /** 00072 * \file 00073 * 00074 * Implementation of the Pulse Width Modulation Controller (PWM) peripheral. 00075 * 00076 */ 00077 00078 /*---------------------------------------------------------------------------- 00079 * Headers 00080 *----------------------------------------------------------------------------*/ 00081 00082 #include "chip.h" 00083 00084 #include <stdint.h> 00085 #include <assert.h> 00086 00087 /*---------------------------------------------------------------------------- 00088 * Local functions 00089 *----------------------------------------------------------------------------*/ 00090 00091 /** 00092 * \brief Finds a prescaler/divisor couple to generate the desired frequency 00093 * from MCK. 00094 * 00095 * Returns the value to enter in PWM_CLK or 0 if the configuration cannot be 00096 * met. 00097 * 00098 * \param frequency Desired frequency in Hz. 00099 * \param mck Master clock frequency in Hz. 00100 */ 00101 static uint16_t FindClockConfiguration( 00102 uint32_t frequency, 00103 uint32_t mck) 00104 { 00105 uint32_t divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}; 00106 uint8_t divisor = 0; 00107 uint32_t prescaler; 00108 00109 assert(frequency < mck); 00110 00111 /* Find prescaler and divisor values */ 00112 prescaler = (mck / divisors[divisor]) / frequency; 00113 while ((prescaler > 255) && (divisor < 11)) { 00114 divisor++; 00115 prescaler = (mck / divisors[divisor]) / frequency; 00116 } 00117 00118 /* Return result */ 00119 if ( divisor < 11 ) { 00120 TRACE_DEBUG( "Found divisor=%u and prescaler=%u for freq=%uHz\n\r", 00121 divisors[divisor], prescaler, frequency ) ; 00122 00123 return prescaler | (divisor << 8) ; 00124 } else { 00125 return 0 ; 00126 } 00127 } 00128 00129 /*---------------------------------------------------------------------------- 00130 * Exported functions 00131 *----------------------------------------------------------------------------*/ 00132 00133 /** 00134 * \brief Configures PWM a channel with the given parameters, basic configure 00135 * function. 00136 * 00137 * The PWM controller must have been clocked in the PMC prior to calling this 00138 * function. 00139 * Beware: this function disables the channel. It waits until disable is effective. 00140 * 00141 * \param channel Channel number. 00142 * \param prescaler Channel prescaler. 00143 * \param alignment Channel alignment. 00144 * \param polarity Channel polarity. 00145 */ 00146 void PWMC_ConfigureChannel( 00147 Pwm* pPwm, 00148 uint8_t channel, 00149 uint32_t prescaler, 00150 uint32_t alignment, 00151 uint32_t polarity) 00152 { 00153 pPwm->PWM_CH_NUM[0].PWM_CMR = 1; 00154 00155 // assert(prescaler < PWM_CMR0_CPRE_MCKB); 00156 assert((alignment & (uint32_t)~PWM_CMR_CALG) == 0); 00157 assert((polarity & (uint32_t)~PWM_CMR_CPOL) == 0); 00158 00159 /* Disable channel (effective at the end of the current period) */ 00160 if ((pPwm->PWM_SR & (1 << channel)) != 0) { 00161 pPwm->PWM_DIS = 1 << channel; 00162 while ((pPwm->PWM_SR & (1 << channel)) != 0); 00163 } 00164 00165 /* Configure channel */ 00166 pPwm->PWM_CH_NUM[channel].PWM_CMR = prescaler | alignment | polarity; 00167 } 00168 00169 /** 00170 * \brief Configures PWM a channel with the given parameters, extend configure 00171 * function. 00172 * The PWM controller must have been clocked in the PMC prior to calling this 00173 * function. 00174 * Beware: this function disables the channel. It waits until disable is effective. 00175 * 00176 * \param channel Channel number. 00177 * \param prescaler Channel prescaler. 00178 * \param alignment Channel alignment. 00179 * \param polarity Channel polarity. 00180 * \param countEventSelect Channel counter event selection. 00181 * \param DTEnable Channel dead time generator enable. 00182 * \param DTHInverte Channel Dead-Time PWMHx output Inverted. 00183 * \param DTLInverte Channel Dead-Time PWMHx output Inverted. 00184 */ 00185 void PWMC_ConfigureChannelExt( 00186 Pwm* pPwm, 00187 uint8_t channel, 00188 uint32_t prescaler, 00189 uint32_t alignment, 00190 uint32_t polarity, 00191 uint32_t countEventSelect, 00192 uint32_t DTEnable, 00193 uint32_t DTHInverte, 00194 uint32_t DTLInverte) 00195 { 00196 // assert(prescaler < PWM_CMR0_CPRE_MCKB); 00197 assert((alignment & (uint32_t)~PWM_CMR_CALG) == 0); 00198 assert((polarity & (uint32_t)~PWM_CMR_CPOL) == 0); 00199 assert((countEventSelect & (uint32_t)~PWM_CMR_CES) == 0); 00200 assert((DTEnable & (uint32_t)~PWM_CMR_DTE) == 0); 00201 assert((DTHInverte & (uint32_t)~PWM_CMR_DTHI) == 0); 00202 assert((DTLInverte & (uint32_t)~PWM_CMR_DTLI) == 0); 00203 00204 /* Disable channel (effective at the end of the current period) */ 00205 if ((pPwm->PWM_SR & (1 << channel)) != 0) { 00206 pPwm->PWM_DIS = 1 << channel; 00207 while ((pPwm->PWM_SR & (1 << channel)) != 0); 00208 } 00209 00210 /* Configure channel */ 00211 pPwm->PWM_CH_NUM[channel].PWM_CMR = prescaler | alignment | polarity | 00212 countEventSelect | DTEnable | DTHInverte | DTLInverte; 00213 } 00214 00215 /** 00216 * \brief Configures PWM clocks A & B to run at the given frequencies. 00217 * 00218 * This function finds the best MCK divisor and prescaler values automatically. 00219 * 00220 * \param clka Desired clock A frequency (0 if not used). 00221 * \param clkb Desired clock B frequency (0 if not used). 00222 * \param mck Master clock frequency. 00223 */ 00224 void PWMC_ConfigureClocks(Pwm* pPwm, uint32_t clka, uint32_t clkb, uint32_t mck) 00225 { 00226 uint32_t mode = 0; 00227 uint32_t result; 00228 00229 /* Clock A */ 00230 if (clka != 0) { 00231 result = FindClockConfiguration(clka, mck); 00232 assert( result != 0 ) ; 00233 mode |= result; 00234 } 00235 00236 /* Clock B */ 00237 if (clkb != 0) { 00238 result = FindClockConfiguration(clkb, mck); 00239 assert( result != 0 ) ; 00240 mode |= (result << 16); 00241 } 00242 00243 /* Configure clocks */ 00244 TRACE_DEBUG( "Setting PWM_CLK = 0x%08X\n\r", mode ) ; 00245 pPwm->PWM_CLK = mode; 00246 } 00247 00248 /** 00249 * \brief Sets the period value used by a PWM channel. 00250 * 00251 * This function writes directly to the CPRD register if the channel is disabled; 00252 * otherwise, it uses the update register CPRDUPD. 00253 * 00254 * \param channel Channel number. 00255 * \param period Period value. 00256 */ 00257 void PWMC_SetPeriod( Pwm* pPwm, uint8_t channel, uint16_t period) 00258 { 00259 /* If channel is disabled, write to CPRD */ 00260 if ((pPwm->PWM_SR & (1 << channel)) == 0) { 00261 00262 pPwm->PWM_CH_NUM[channel].PWM_CPRD = period; 00263 } else { 00264 /* Otherwise use update register */ 00265 pPwm->PWM_CH_NUM[channel].PWM_CPRDUPD = period; 00266 } 00267 } 00268 00269 /** 00270 * \brief Sets the duty cycle used by a PWM channel. 00271 * This function writes directly to the CDTY register if the channel is disabled; 00272 * otherwise it uses the update register CDTYUPD. 00273 * Note that the duty cycle must always be inferior or equal to the channel 00274 * period. 00275 * 00276 * \param channel Channel number. 00277 * \param duty Duty cycle value. 00278 */ 00279 void PWMC_SetDutyCycle( Pwm* pPwm, uint8_t channel, uint16_t duty) 00280 { 00281 assert(duty <= pPwm->PWM_CH_NUM[channel].PWM_CPRD); 00282 00283 /* If channel is disabled, write to CDTY */ 00284 if ((pPwm->PWM_SR & (1 << channel)) == 0) { 00285 pPwm->PWM_CH_NUM[channel].PWM_CDTY = duty; 00286 } else { 00287 /* Otherwise use update register */ 00288 pPwm->PWM_CH_NUM[channel].PWM_CDTYUPD = duty; 00289 } 00290 } 00291 00292 /** 00293 * \brief Sets the dead time used by a PWM channel. 00294 * This function writes directly to the DT register if the channel is disabled; 00295 * otherwise it uses the update register DTUPD. 00296 * Note that the dead time must always be inferior or equal to the channel 00297 * period. 00298 * 00299 * \param channel Channel number. 00300 * \param timeH Dead time value for PWMHx output. 00301 * \param timeL Dead time value for PWMLx output. 00302 */ 00303 void PWMC_SetDeadTime( Pwm* pPwm, uint8_t channel, uint16_t timeH, uint16_t timeL) 00304 { 00305 assert(timeH <= pPwm->PWM_CH_NUM[channel].PWM_CPRD); 00306 assert(timeL <= pPwm->PWM_CH_NUM[channel].PWM_CPRD); 00307 00308 /* If channel is disabled, write to DT */ 00309 if ((pPwm->PWM_SR & (1 << channel)) == 0) { 00310 pPwm->PWM_CH_NUM[channel].PWM_DT = timeH | (timeL << 16); 00311 } else { 00312 /* Otherwise use update register */ 00313 pPwm->PWM_CH_NUM[channel].PWM_DTUPD = timeH | (timeL << 16); 00314 } 00315 } 00316 00317 /** 00318 * \brief Configures Synchronous channel with the given parameters. 00319 * Beware: At this time, the channels should be disabled. 00320 * 00321 * \param channels Bitwise OR of Synchronous channels. 00322 * \param updateMode Synchronous channel update mode. 00323 * \param requestMode PDC transfer request mode. 00324 * \param requestComparisonSelect PDC transfer request comparison selection. 00325 */ 00326 void PWMC_ConfigureSyncChannel( Pwm* pPwm, 00327 uint32_t channels, 00328 uint32_t updateMode, 00329 uint32_t requestMode, 00330 uint32_t requestComparisonSelect) 00331 { 00332 pPwm->PWM_SCM = channels | updateMode | requestMode | requestComparisonSelect; 00333 } 00334 00335 /** 00336 * \brief Sets the update period of the synchronous channels. 00337 * This function writes directly to the SCUP register if the channel #0 is disabled; 00338 * otherwise it uses the update register SCUPUPD. 00339 * 00340 * \param period update period. 00341 */ 00342 void PWMC_SetSyncChannelUpdatePeriod( Pwm* pPwm, uint8_t period) 00343 { 00344 /* If channel is disabled, write to SCUP */ 00345 if ((pPwm->PWM_SR & (1 << 0)) == 0) { 00346 pPwm->PWM_SCUP = period; 00347 } else { 00348 /* Otherwise use update register */ 00349 pPwm->PWM_SCUPUPD = period; 00350 } 00351 } 00352 00353 /** 00354 * \brief Sets synchronous channels update unlock. 00355 * 00356 * Note: If the UPDM field is set to 0, writing the UPDULOCK bit to 1 00357 * triggers the update of the period value, the duty-cycle and 00358 * the dead-time values of synchronous channels at the beginning 00359 * of the next PWM period. If the field UPDM is set to 1 or 2, 00360 * writing the UPDULOCK bit to 1 triggers only the update of 00361 * the period value and of the dead-time values of synchronous channels. 00362 * This bit is automatically reset when the update is done. 00363 */ 00364 void PWMC_SetSyncChannelUpdateUnlock( Pwm* pPwm ) 00365 { 00366 pPwm->PWM_SCUC = PWM_SCUC_UPDULOCK; 00367 } 00368 00369 /** 00370 * \brief Enables the given PWM channel. 00371 * 00372 * This does NOT enable the corresponding pin;this must be done in the user code. 00373 * 00374 * \param channel Channel number. 00375 */ 00376 void PWMC_EnableChannel( Pwm* pPwm, uint8_t channel) 00377 { 00378 pPwm->PWM_ENA = 1 << channel; 00379 } 00380 00381 /** 00382 * \brief Disables the given PWM channel. 00383 * 00384 * Beware, channel will be effectively disabled at the end of the current period. 00385 * Application can check channel is disabled using the following wait loop: 00386 * while ((PWM->PWM_SR & (1 << channel)) != 0); 00387 * 00388 * \param channel Channel number. 00389 */ 00390 void PWMC_DisableChannel( Pwm* pPwm, uint8_t channel) 00391 { 00392 pPwm->PWM_DIS = 1 << channel; 00393 } 00394 00395 /** 00396 * \brief Enables the period interrupt for the given PWM channel. 00397 * 00398 * \param channel Channel number. 00399 */ 00400 void PWMC_EnableChannelIt( Pwm* pPwm, uint8_t channel) 00401 { 00402 pPwm->PWM_IER1 = 1 << channel; 00403 } 00404 00405 /** 00406 * \brief Return PWM Interrupt Status2 Register 00407 * 00408 */ 00409 uint32_t PWMC_GetStatus2( Pwm* pPwm) 00410 { 00411 return pPwm->PWM_ISR2; 00412 } 00413 00414 /** 00415 * \brief Disables the period interrupt for the given PWM channel. 00416 * 00417 * \param channel Channel number. 00418 */ 00419 void PWMC_DisableChannelIt( Pwm* pPwm, uint8_t channel) 00420 { 00421 pPwm->PWM_IDR1 = 1 << channel; 00422 } 00423 00424 /** 00425 * \brief Enables the selected interrupts sources on a PWMC peripheral. 00426 * 00427 * \param sources1 Bitwise OR of selected interrupt sources of PWM_IER1. 00428 * \param sources2 Bitwise OR of selected interrupt sources of PWM_IER2. 00429 */ 00430 void PWMC_EnableIt( Pwm* pPwm, uint32_t sources1, uint32_t sources2) 00431 { 00432 pPwm->PWM_IER1 = sources1; 00433 pPwm->PWM_IER2 = sources2; 00434 } 00435 00436 /** 00437 * \brief Disables the selected interrupts sources on a PWMC peripheral. 00438 * 00439 * \param sources1 Bitwise OR of selected interrupt sources of PWM_IDR1. 00440 * \param sources2 Bitwise OR of selected interrupt sources of PWM_IDR2. 00441 */ 00442 void PWMC_DisableIt( Pwm* pPwm, uint32_t sources1, uint32_t sources2) 00443 { 00444 pPwm->PWM_IDR1 = sources1; 00445 pPwm->PWM_IDR2 = sources2; 00446 } 00447 00448 /** 00449 * \brief Set PWM output override value. 00450 * 00451 * \param value Bitwise OR of output override value. 00452 */ 00453 void PWMC_SetOverrideValue( Pwm* pPwm, uint32_t value) 00454 { 00455 pPwm->PWM_OOV = value; 00456 } 00457 00458 /** 00459 * \brief Enable override output. 00460 * 00461 * \param value Bitwise OR of output selection. 00462 * \param sync 0: enable the output asynchronously, 1: enable it synchronously 00463 */ 00464 void PWMC_EnableOverrideOutput( Pwm* pPwm, uint32_t value, uint32_t sync) 00465 { 00466 if (sync) { 00467 pPwm->PWM_OSSUPD = value; 00468 } else { 00469 pPwm->PWM_OSS = value; 00470 } 00471 } 00472 00473 /** 00474 * \brief Output Selection for override PWM output. 00475 * 00476 * \param value Bitwise OR of output override value. 00477 */ 00478 void PWMC_OutputOverrideSelection( Pwm* pPwm, uint32_t value ) 00479 { 00480 pPwm->PWM_OS = value; 00481 } 00482 00483 00484 /** 00485 * \brief Disable override output. 00486 * 00487 * \param value Bitwise OR of output selection. 00488 * \param sync 0: enable the output asynchronously, 1: enable it synchronously 00489 */ 00490 void PWMC_DisableOverrideOutput( Pwm* pPwm, uint32_t value, uint32_t sync) 00491 { 00492 if (sync) { 00493 00494 pPwm->PWM_OSCUPD = value; 00495 } else { 00496 00497 pPwm->PWM_OSC = value; 00498 } 00499 } 00500 00501 /** 00502 * \brief Set PWM fault mode. 00503 * 00504 * \param mode Bitwise OR of fault mode. 00505 */ 00506 void PWMC_SetFaultMode( Pwm* pPwm, uint32_t mode) 00507 { 00508 pPwm->PWM_FMR = mode; 00509 } 00510 00511 /** 00512 * \brief PWM fault clear. 00513 * 00514 * \param fault Bitwise OR of fault to clear. 00515 */ 00516 void PWMC_FaultClear( Pwm* pPwm, uint32_t fault) 00517 { 00518 pPwm->PWM_FCR = fault; 00519 } 00520 00521 /** 00522 * \brief Set PWM fault protection value. 00523 * 00524 * \param value Bitwise OR of fault protection value. 00525 */ 00526 void PWMC_SetFaultProtectionValue( Pwm* pPwm, uint32_t value) 00527 { 00528 pPwm->PWM_FPV1 = value; 00529 } 00530 00531 /** 00532 * \brief Enable PWM fault protection. 00533 * 00534 * \param value Bitwise OR of FPEx[y]. 00535 */ 00536 void PWMC_EnableFaultProtection( Pwm* pPwm, uint32_t value) 00537 { 00538 pPwm->PWM_FPE = value; 00539 } 00540 00541 /** 00542 * \brief Configure comparison unit. 00543 * 00544 * \param x comparison x index 00545 * \param value comparison x value. 00546 * \param mode comparison x mode 00547 */ 00548 void PWMC_ConfigureComparisonUnit( Pwm* pPwm, uint32_t x, uint32_t value, uint32_t mode) 00549 { 00550 assert(x < 8); 00551 00552 /* If channel is disabled, write to CMPxM & CMPxV */ 00553 if ((pPwm->PWM_SR & (1 << 0)) == 0) { 00554 pPwm->PWM_CMP[x].PWM_CMPM = mode; 00555 pPwm->PWM_CMP[x].PWM_CMPV = value; 00556 } else { 00557 /* Otherwise use update register */ 00558 pPwm->PWM_CMP[x].PWM_CMPMUPD = mode; 00559 pPwm->PWM_CMP[x].PWM_CMPVUPD = value; 00560 } 00561 } 00562 00563 /** 00564 * \brief Configure event line mode. 00565 * 00566 * \param x Line x 00567 * \param mode Bitwise OR of line mode selection 00568 */ 00569 void PWMC_ConfigureEventLineMode( Pwm* pPwm, uint32_t x, uint32_t mode) 00570 { 00571 assert(x < 2); 00572 00573 if (x == 0) { 00574 pPwm->PWM_ELMR[0] = mode; 00575 } else if (x == 1) { 00576 pPwm->PWM_ELMR[1] = mode; 00577 } 00578 }