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_cpu.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 = CLOCK_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      * WARNING: is forbidden to write 0 to duty cycle value,
00151      * and so for duty = 0 we must enable PIO and clear output!
00152      */
00153     if (!duty)
00154     {
00155         PWM_PIO_PER = pwm_map[dev].pwm_pin;
00156         pwm_map[dev].duty_zero = true;
00157     }
00158     else
00159     {
00160         ASSERT(PWM_CCNT0);
00161         /*
00162          * If polarity flag is true we must invert
00163          * PWM polarity.
00164          */
00165         if (pwm_map[dev].pol)
00166         {
00167                 duty = (uint16_t)*pwm_map[dev].period_reg - duty;
00168                 LOG_INFO("Inverted duty[%d], pol[%d]\n", duty, pwm_map[dev].pol);
00169         }
00170 
00171         PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00172         *pwm_map[dev].update_reg = duty;
00173         pwm_map[dev].duty_zero = false;
00174     }
00175 
00176     PWM_ENA = BV(dev);
00177 
00178     LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", dev, duty, *pwm_map[dev].period_reg);
00179 }
00180 
00181 
00185 void pwm_hw_enable(PwmDev dev)
00186 {
00187     if (!pwm_map[dev].duty_zero)
00188         PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00189 }
00190 
00194 void pwm_hw_disable(PwmDev dev)
00195 {
00196     PWM_PIO_PER = pwm_map[dev].pwm_pin;
00197 }
00198 
00202 void pwm_hw_setPolarity(PwmDev dev, bool pol)
00203 {
00204         pwm_map[dev].pol = pol;
00205         LOG_INFO("Set pol[%d]\n", pwm_map[dev].pol);
00206 }
00207 
00211 void pwm_hw_init(void)
00212 {
00213 
00214     /*
00215      * Init pwm:
00216      * WARNING: is forbidden to write 0 to duty cycle value,
00217      * and so for duty = 0 we must enable PIO and clear output!
00218      * - clear PIO outputs
00219      * - enable PIO outputs
00220      * - Disable PIO and enable PWM functions
00221      * - Power on PWM
00222      */
00223     PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00224     PWM_PIO_OER = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00225     PWM_PIO_PDR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00226     PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00227     PMC_PCER |= BV(PWMC_ID);
00228 
00229     /* Disable all channels. */
00230     PWM_DIS = 0xFFFFFFFF;
00231     /* Disable prescalers A and B */
00232     PWM_MR = 0;
00233 
00234     /*
00235      * Set pwm mode:
00236      * - set period alidned to left
00237      * - set output waveform to start at high level
00238      * - allow duty cycle modify at next period event
00239      */
00240     for (int ch = 0; ch < PWM_CNT; ch++)
00241     {
00242         *pwm_map[ch].mode_reg = 0;
00243         *pwm_map[ch].mode_reg = BV(PWM_CPOL);
00244     }
00245 
00246 }
00247