00001
00040 #include <drv/pwm.h>
00041 #include "pwm_at91.h"
00042 #include <hw/hw_cpufreq.h>
00043 #include "cfg/cfg_pwm.h"
00044
00045
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 #include <cpu/irq.h>
00055
00056 #define PWM_HW_MAX_PRESCALER_STEP 10
00057 #define PWM_HW_MAX_PERIOD 0xFFFF
00058
00059 #if CFG_PWM_ENABLE_OLD_API
00060 #include "hw/pwm_map.h"
00061
00067 static PwmChannel pwm_map[PWM_CNT] =
00068 {
00069 {
00070 .duty_zero = false,
00071 .pol = false,
00072 .pwm_pin = BV(PWM0),
00073 .mode_reg = &PWM_CMR0,
00074 .duty_reg = &PWM_CDTY0,
00075 .period_reg = &PWM_CPRD0,
00076 .update_reg = &PWM_CUPD0,
00077 },
00078 {
00079 .duty_zero = false,
00080 .pol = false,
00081 .pwm_pin = BV(PWM1),
00082 .mode_reg = &PWM_CMR1,
00083 .duty_reg = &PWM_CDTY1,
00084 .period_reg = &PWM_CPRD1,
00085 .update_reg = &PWM_CUPD1,
00086 },
00087 {
00088 .duty_zero = false,
00089 .pol = false,
00090 .pwm_pin = BV(PWM2),
00091 .mode_reg = &PWM_CMR2,
00092 .duty_reg = &PWM_CDTY2,
00093 .period_reg = &PWM_CPRD2,
00094 .update_reg = &PWM_CUPD2,
00095 },
00096 {
00097 .duty_zero = false,
00098 .pol = false,
00099 .pwm_pin = BV(PWM3),
00100 .mode_reg = &PWM_CMR3,
00101 .duty_reg = &PWM_CDTY3,
00102 .period_reg = &PWM_CPRD3,
00103 .update_reg = &PWM_CUPD3,
00104 }
00105 };
00106
00107
00113 pwm_period_t pwm_hw_getPeriod(PwmDev dev)
00114 {
00115 return *pwm_map[dev].period_reg;
00116 }
00117
00123 void pwm_hw_setFrequency(PwmDev dev, uint32_t freq)
00124 {
00125 uint32_t period = 0;
00126
00127 for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++)
00128 {
00129 period = CPU_FREQ / (BV(i) * freq);
00130 LOG_INFO("period[%ld], prescale[%d]\n", period, i);
00131 if ((period < PWM_HW_MAX_PERIOD) && (period != 0))
00132 {
00133
00134 *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK;
00135 *pwm_map[dev].mode_reg |= i;
00136
00137 *pwm_map[dev].period_reg = period;
00138 break;
00139 }
00140 }
00141
00142 LOG_INFO("PWM ch[%d] period[%ld]\n", dev, period);
00143 }
00144
00150 void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty)
00151 {
00152 ASSERT(duty <= (uint16_t)*pwm_map[dev].period_reg);
00153
00154
00155
00156
00157
00158
00159 if (pwm_map[dev].pol)
00160 {
00161 duty = (uint16_t)*pwm_map[dev].period_reg - duty;
00162 LOG_INFO("Inverted duty[%d], pol[%d]\n", duty, pwm_map[dev].pol);
00163 }
00164
00165
00166
00167
00168
00169 if (!duty)
00170 {
00171 PWM_PIO_CODR = pwm_map[dev].pwm_pin;
00172 PWM_PIO_PER = pwm_map[dev].pwm_pin;
00173 pwm_map[dev].duty_zero = true;
00174 }
00175 else
00176 {
00177 PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00178 PWM_PIO_ABSR = pwm_map[dev].pwm_pin;
00179
00180 *pwm_map[dev].update_reg = duty;
00181 pwm_map[dev].duty_zero = false;
00182 }
00183
00184 PWM_ENA = BV(dev);
00185 LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", dev, duty, *pwm_map[dev].period_reg);
00186 }
00187
00188
00192 void pwm_hw_enable(PwmDev dev)
00193 {
00194 if (!pwm_map[dev].duty_zero)
00195 {
00196 PWM_PIO_PDR = pwm_map[dev].pwm_pin;
00197 PWM_PIO_ABSR = pwm_map[dev].pwm_pin;
00198 }
00199 }
00200
00204 void pwm_hw_disable(PwmDev dev)
00205 {
00206 PWM_PIO_PER = pwm_map[dev].pwm_pin;
00207 }
00208
00212 void pwm_hw_setPolarity(PwmDev dev, bool pol)
00213 {
00214 pwm_map[dev].pol = pol;
00215 LOG_INFO("Set pol[%d]\n", pwm_map[dev].pol);
00216 }
00217
00221 void pwm_hw_init(void)
00222 {
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00234 PWM_PIO_OER = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00235 PWM_PIO_PDR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00236 PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3);
00237 PMC_PCER |= BV(PWMC_ID);
00238
00239
00240 PWM_DIS = 0xFFFFFFFF;
00241
00242 PWM_MR = 0;
00243
00244
00245
00246
00247
00248
00249
00250 for (int ch = 0; ch < PWM_CNT; ch++)
00251 {
00252 *pwm_map[ch].mode_reg = 0;
00253 *pwm_map[ch].mode_reg = BV(PWM_CPOL);
00254 }
00255
00256 }
00257
00258 #else
00259
00260 typedef struct PwmChannelRegs
00261 {
00262 reg32_t CMR;
00263 reg32_t CDTY;
00264 reg32_t CPRD;
00265 reg32_t CCNT;
00266 reg32_t CUPD;
00267 } PwmChannelRegs;
00268
00269
00270
00271
00272
00273 void pwm_hw_setFrequency(Pwm *ctx, pwm_freq_t freq)
00274 {
00275 uint32_t period = 0;
00276
00277 for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++)
00278 {
00279 period = CPU_FREQ / (BV(i) * freq);
00280 LOG_INFO("period[%ld], prescale[%d]\n", period, i);
00281 if ((period < PWM_HW_MAX_PERIOD) && (period != 0))
00282 {
00283
00284 ctx->hw->base->CMR &= ~PWM_CPRE_MCK_MASK;
00285 ctx->hw->base->CMR |= i;
00286
00287 ATOMIC(
00288 ctx->hw->base->CPRD = period;
00289 ctx->hw->base->CDTY = period;
00290 );
00291 break;
00292 }
00293 }
00294
00295 LOG_INFO("PWM ch[%d] period[%ld]\n", ctx->ch, period);
00296 }
00297
00298 pwm_hwreg_t pwm_hw_getPeriod(Pwm *ctx)
00299 {
00300 return ctx->hw->base->CPRD;
00301 }
00302
00303
00304
00305
00306
00307
00308 void pwm_hw_setDuty(Pwm *ctx, pwm_hwreg_t hw_duty)
00309 {
00310 ASSERT(hw_duty <= ctx->hw->base->CPRD);
00311
00312
00313
00314
00315
00316 if (hw_duty < 2)
00317 {
00318 hw_duty = 2;
00319 PWM_PIO_PER = ctx->hw->pwm_pin;
00320 }
00321 else
00322 PWM_PIO_PDR = ctx->hw->pwm_pin;
00323
00324 ctx->hw->base->CUPD = hw_duty;
00325 LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", ctx->ch, hw_duty, ctx->hw->base->CPRD);
00326 }
00327
00328 static PwmHardware pwm_channels[] =
00329 {
00330 {
00331 .pwm_pin = BV(PWM0),
00332 .base = (volatile PwmChannelRegs *)&PWM_CMR0,
00333 },
00334 {
00335 .pwm_pin = BV(PWM1),
00336 .base = (volatile PwmChannelRegs *)&PWM_CMR1,
00337 },
00338 {
00339 .pwm_pin = BV(PWM2),
00340 .base = (volatile PwmChannelRegs *)&PWM_CMR2,
00341 },
00342 {
00343 .pwm_pin = BV(PWM3),
00344 .base = (volatile PwmChannelRegs *)&PWM_CMR3,
00345 },
00346 };
00347
00348
00349
00350
00351 void pwm_hw_init(Pwm *ctx, unsigned ch)
00352 {
00353
00354 ctx->hw = &pwm_channels[ch];
00355
00356
00357
00358
00359
00360
00361
00362
00363 PWM_PIO_CODR = ctx->hw->pwm_pin;
00364 PWM_PIO_OER = ctx->hw->pwm_pin;
00365 PWM_PIO_PER = ctx->hw->pwm_pin;
00366 PWM_PIO_ABSR = ctx->hw->pwm_pin;
00367
00368 PMC_PCER |= BV(PWMC_ID);
00369
00370
00371 PWM_MR = 0;
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 ctx->hw->base->CDTY = 2;
00383 ctx->hw->base->CMR = BV(PWM_CPOL);
00384 PWM_ENA = BV(ch);
00385 }
00386
00387 #endif