pwm_at91.c

Go to the documentation of this file.
00001 
00041 #include "pwm_at91.h"
00042 
00043 #include <hw/hw_cpu.h>
00044 
00045 #include <cfg/macros.h>
00046 #include <cfg/debug.h>
00047 #include <io/arm.h>
00048 
00049 #include "appconfig.h"
00050 
00056 static PwmChannel pwm_map[PWM_CNT] =
00057 {
00058     {//PWM Channel 0
00059         .duty_zero = false,
00060         .pwm_pin = BV(PWM0),
00061         .mode_reg = &PWM_CMR0,
00062         .duty_reg = &PWM_CDTY0,
00063         .period_reg = &PWM_CPRD0,
00064         .update_reg = &PWM_CUPD0,
00065     },
00066     {//PWM Channel 1
00067         .duty_zero = false,
00068         .pwm_pin = BV(PWM1),
00069         .mode_reg = &PWM_CMR1,
00070         .duty_reg = &PWM_CDTY1,
00071         .period_reg = &PWM_CPRD1,
00072         .update_reg = &PWM_CUPD1,
00073     },
00074     {//PWM Channel 2
00075         .duty_zero = false,
00076         .pwm_pin = BV(PWM2),
00077         .mode_reg = &PWM_CMR2,
00078         .duty_reg = &PWM_CDTY2,
00079         .period_reg = &PWM_CPRD2,
00080         .update_reg = &PWM_CUPD2,
00081     },
00082     {//PWM Channel 3
00083         .duty_zero = false,
00084         .pwm_pin = BV(PWM3),
00085         .mode_reg = &PWM_CMR3,
00086         .duty_reg = &PWM_CDTY3,
00087         .period_reg = &PWM_CPRD3,
00088         .update_reg = &PWM_CUPD3,
00089     }
00090 };
00091 
00092 
00098 pwm_period_t pwm_hw_getPeriod(PwmDev dev)
00099 {
00100     return *pwm_map[dev].period_reg;
00101 }
00102 
00108 void pwm_hw_setFrequency(PwmDev dev, uint32_t freq)
00109 {
00110     uint32_t period = 0;
00111 
00112     for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++)
00113     {
00114         period = CLOCK_FREQ / (BV(i) * freq);
00115 //      TRACEMSG("period[%d], prescale[%d]", period, i);
00116         if ((period < PWM_HW_MAX_PERIOD) && (period != 0))
00117         {
00118             //Clean previous channel prescaler, and set new
00119             *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK;
00120             *pwm_map[dev].mode_reg |= i;
00121             //Set pwm period
00122             *pwm_map[dev].period_reg = period;
00123             break;
00124         }
00125     }
00126 
00127     PWM_ENA = BV(dev);
00128 
00129 //  TRACEMSG("PWM ch[%d] period[%d]", dev, period);
00130 }
00131 
00137 void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty)
00138 {
00139     ASSERT(duty <= (uint16_t)*pwm_map[dev].period_reg);
00140 
00141 
00142     /*
00143      * WARNING: is forbidden to write 0 to duty cycle value,
00144      * and so for duty = 0 we must enable PIO and clear output!
00145      */
00146     if (!duty)
00147     {
00148         PWM_PIO_PER = pwm_map[dev].pwm_pin;
00149         pwm_map[dev].duty_zero = true;
00150     }
00151     else
00152     {
00153         ASSERT(PWM_CCNT0);
00154         PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00155         *pwm_map[dev].update_reg = duty;
00156         pwm_map[dev].duty_zero = false;
00157     }
00158 
00159 //  TRACEMSG("PWM ch[%d] duty[%d], period[%ld]", dev, duty, *pwm_map[dev].period_reg);
00160 }
00161 
00162 
00166 void pwm_hw_enable(PwmDev dev)
00167 {
00168     if (!pwm_map[dev].duty_zero)
00169         PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00170 }
00171 
00175 void pwm_hw_disable(PwmDev dev)
00176 {
00177     PWM_PIO_PER = pwm_map[dev].pwm_pin;
00178 }
00179 
00180 
00184 void pwm_hw_init(void)
00185 {
00186 
00187     /*
00188      * Init pwm:
00189      * WARNING: is forbidden to write 0 to duty cycle value,
00190      * and so for duty = 0 we must enable PIO and clear output!
00191      * - clear PIO outputs
00192      * - enable PIO outputs
00193      * - Disable PIO and enable PWM functions
00194      * - Power on PWM
00195      */
00196     PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00197     PWM_PIO_OER = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00198     PWM_PIO_PDR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00199     PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00200     PMC_PCER |= BV(PWMC_ID);
00201 
00202     /* Disable all channels. */
00203     PWM_DIS = 0xFFFFFFFF;
00204     /* Disable prescalers A and B */
00205     PWM_MR = 0;
00206 
00207     /*
00208      * Set pwm mode:
00209      * - set period alidned to left
00210      * - set output waveform to low level
00211      * - allow duty cycle modify at next period event
00212      */
00213     for (int ch = 0; ch < PWM_CNT; ch++)
00214         *pwm_map[ch].mode_reg = 0;
00215 }
00216