pwm_at91.c

Go to the documentation of this file.
00001 
00040 #include "pwm_at91.h"
00041 #include "hw/pwm_map.h"
00042 #include <hw/hw_cpufreq.h>
00043 #include "cfg/cfg_pwm.h"
00044 
00045 // Define logging setting (for cfg/log.h module).
00046 #define LOG_LEVEL         PWM_LOG_LEVEL
00047 #define LOG_FORMAT        PWM_LOG_FORMAT
00048 #include <cfg/log.h>
00049 
00050 #include <cfg/macros.h>
00051 #include <cfg/debug.h>
00052 
00053 #include <io/arm.h>
00054 
00055 
00061 static PwmChannel pwm_map[PWM_CNT] =
00062 {
00063     {//PWM Channel 0
00064         .duty_zero = false,
00065         .pol = false,
00066         .pwm_pin = BV(PWM0),
00067         .mode_reg = &PWM_CMR0,
00068         .duty_reg = &PWM_CDTY0,
00069         .period_reg = &PWM_CPRD0,
00070         .update_reg = &PWM_CUPD0,
00071     },
00072     {//PWM Channel 1
00073         .duty_zero = false,
00074         .pol = false,
00075         .pwm_pin = BV(PWM1),
00076         .mode_reg = &PWM_CMR1,
00077         .duty_reg = &PWM_CDTY1,
00078         .period_reg = &PWM_CPRD1,
00079         .update_reg = &PWM_CUPD1,
00080     },
00081     {//PWM Channel 2
00082         .duty_zero = false,
00083         .pol = false,
00084         .pwm_pin = BV(PWM2),
00085         .mode_reg = &PWM_CMR2,
00086         .duty_reg = &PWM_CDTY2,
00087         .period_reg = &PWM_CPRD2,
00088         .update_reg = &PWM_CUPD2,
00089     },
00090     {//PWM Channel 3
00091         .duty_zero = false,
00092         .pol = false,
00093         .pwm_pin = BV(PWM3),
00094         .mode_reg = &PWM_CMR3,
00095         .duty_reg = &PWM_CDTY3,
00096         .period_reg = &PWM_CPRD3,
00097         .update_reg = &PWM_CUPD3,
00098     }
00099 };
00100 
00101 
00107 pwm_period_t pwm_hw_getPeriod(PwmDev dev)
00108 {
00109     return *pwm_map[dev].period_reg;
00110 }
00111 
00117 void pwm_hw_setFrequency(PwmDev dev, uint32_t freq)
00118 {
00119     uint32_t period = 0;
00120 
00121     for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++)
00122     {
00123         period = CPU_FREQ / (BV(i) * freq);
00124         LOG_INFO("period[%ld], prescale[%d]\n", period, i);
00125         if ((period < PWM_HW_MAX_PERIOD) && (period != 0))
00126         {
00127             //Clean previous channel prescaler, and set new
00128             *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK;
00129             *pwm_map[dev].mode_reg |= i;
00130             //Set pwm period
00131             *pwm_map[dev].period_reg = period;
00132             break;
00133         }
00134     }
00135 
00136     LOG_INFO("PWM ch[%d] period[%ld]\n", dev, period);
00137 }
00138 
00144 void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty)
00145 {
00146     ASSERT(duty <= (uint16_t)*pwm_map[dev].period_reg);
00147 
00148 
00149     /*
00150      * If polarity flag is true we must invert
00151      * PWM polarity.
00152      */
00153     if (pwm_map[dev].pol)
00154     {
00155         duty = (uint16_t)*pwm_map[dev].period_reg - duty;
00156         LOG_INFO("Inverted duty[%d], pol[%d]\n", duty, pwm_map[dev].pol);
00157     }
00158 
00159     /*
00160      * WARNING: is forbidden to write 0 to duty cycle value,
00161      * and so for duty = 0 we must enable PIO and clear output!
00162      */
00163     if (!duty)
00164     {
00165         PWM_PIO_CODR = pwm_map[dev].pwm_pin;
00166         PWM_PIO_PER  = pwm_map[dev].pwm_pin;
00167         pwm_map[dev].duty_zero = true;
00168     }
00169     else
00170     {
00171         PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00172         PWM_PIO_ABSR = pwm_map[dev].pwm_pin;
00173 
00174         *pwm_map[dev].update_reg = duty;
00175         pwm_map[dev].duty_zero = false;
00176     }
00177 
00178     PWM_ENA = BV(dev);
00179     LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", dev, duty, *pwm_map[dev].period_reg);
00180 }
00181 
00182 
00186 void pwm_hw_enable(PwmDev dev)
00187 {
00188     if (!pwm_map[dev].duty_zero)
00189     {
00190         PWM_PIO_PDR  = pwm_map[dev].pwm_pin;
00191         PWM_PIO_ABSR = pwm_map[dev].pwm_pin;
00192     }
00193 }
00194 
00198 void pwm_hw_disable(PwmDev dev)
00199 {
00200     PWM_PIO_PER = pwm_map[dev].pwm_pin;
00201 }
00202 
00206 void pwm_hw_setPolarity(PwmDev dev, bool pol)
00207 {
00208         pwm_map[dev].pol = pol;
00209         LOG_INFO("Set pol[%d]\n", pwm_map[dev].pol);
00210 }
00211 
00215 void pwm_hw_init(void)
00216 {
00217 
00218     /*
00219      * Init pwm:
00220      * WARNING: is forbidden to write 0 to duty cycle value,
00221      * and so for duty = 0 we must enable PIO and clear output!
00222      * - clear PIO outputs
00223      * - enable PIO outputs
00224      * - Disable PIO and enable PWM functions
00225      * - Power on PWM
00226      */
00227     PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00228     PWM_PIO_OER  = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00229     PWM_PIO_PDR  = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00230     PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00231     PMC_PCER |= BV(PWMC_ID);
00232 
00233     /* Disable all channels. */
00234     PWM_DIS = 0xFFFFFFFF;
00235     /* Disable prescalers A and B */
00236     PWM_MR = 0;
00237 
00238     /*
00239      * Set pwm mode:
00240      * - set period alidned to left
00241      * - set output waveform to start at high level
00242      * - allow duty cycle modify at next period event
00243      */
00244     for (int ch = 0; ch < PWM_CNT; ch++)
00245     {
00246         *pwm_map[ch].mode_reg = 0;
00247         *pwm_map[ch].mode_reg = BV(PWM_CPOL);
00248     }
00249 
00250 }
00251