BeRTOS
|
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 // 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 #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 {//PWM Channel 0 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 {//PWM Channel 1 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 {//PWM Channel 2 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 {//PWM Channel 3 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 //Clean previous channel prescaler, and set new 00134 *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK; 00135 *pwm_map[dev].mode_reg |= i; 00136 //Set pwm period 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 * If polarity flag is true we must invert 00157 * PWM polarity. 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 * WARNING: is forbidden to write 0 to duty cycle value, 00167 * and so for duty = 0 we must enable PIO and clear output! 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 * Init pwm: 00226 * WARNING: is forbidden to write 0 to duty cycle value, 00227 * and so for duty = 0 we must enable PIO and clear output! 00228 * - clear PIO outputs 00229 * - enable PIO outputs 00230 * - Disable PIO and enable PWM functions 00231 * - Power on PWM 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 /* Disable all channels. */ 00240 PWM_DIS = 0xFFFFFFFF; 00241 /* Disable prescalers A and B */ 00242 PWM_MR = 0; 00243 00244 /* 00245 * Set pwm mode: 00246 * - set period alidned to left 00247 * - set output waveform to start at high level 00248 * - allow duty cycle modify at next period event 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 * Set pwm waveform frequecy. 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 //Clear previous channel prescaler, and set new 00284 ctx->hw->base->CMR &= ~PWM_CPRE_MCK_MASK; 00285 ctx->hw->base->CMR |= i; 00286 //Set pwm period 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 * Set pwm duty cycle. 00305 * 00306 * duty value 0 - (2^16 - 1) 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 * WARNING: is forbidden to write 0 or 1 to duty cycle value, 00314 * and so for duty < 2 we must enable PIO and clear output! 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 {//PWM Channel 0 00331 .pwm_pin = BV(PWM0), 00332 .base = (volatile PwmChannelRegs *)&PWM_CMR0, 00333 }, 00334 {//PWM Channel 1 00335 .pwm_pin = BV(PWM1), 00336 .base = (volatile PwmChannelRegs *)&PWM_CMR1, 00337 }, 00338 {//PWM Channel 2 00339 .pwm_pin = BV(PWM2), 00340 .base = (volatile PwmChannelRegs *)&PWM_CMR2, 00341 }, 00342 {//PWM Channel 3 00343 .pwm_pin = BV(PWM3), 00344 .base = (volatile PwmChannelRegs *)&PWM_CMR3, 00345 }, 00346 }; 00347 00348 /* 00349 * Init pwm. 00350 */ 00351 void pwm_hw_init(Pwm *ctx, unsigned ch) 00352 { 00353 00354 ctx->hw = &pwm_channels[ch]; 00355 00356 /* 00357 * Init pwm: 00358 * - clear PIO outputs 00359 * - enable PIO outputs 00360 * - Enable PWM functions 00361 * - Power on PWM 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 /* Disable prescalers A and B */ 00371 PWM_MR = 0; 00372 00373 /* 00374 * Set pwm mode: 00375 * WARNING: is forbidden to write 0 or 1 to duty cycle value, 00376 * and so for start we set duty to 2. 00377 * Also: 00378 * - set period aligned to left 00379 * - set output waveform to start at high level 00380 * - allow duty cycle modify at next period event 00381 */ 00382 ctx->hw->base->CDTY = 2; 00383 ctx->hw->base->CMR = BV(PWM_CPOL); 00384 PWM_ENA = BV(ch); 00385 } 00386 00387 #endif