[HAL] K20DXX PWM fix

The old code for the K20 PWM had an issue where calling for example
pwm.period and pwm.write after each other resulted in the pwm.write
function setting the pulsewidth with the value of the old pwm period.
This makes sure it waits until the latest pwm period is written before
it will do so.
pull/958/head
Sissors 2015-03-07 22:06:01 +01:00
parent ac0504da13
commit 095ebd03e3
2 changed files with 17 additions and 7 deletions

View File

@ -41,7 +41,7 @@ struct port_s {
struct pwmout_s { struct pwmout_s {
__IO uint32_t *MOD; __IO uint32_t *MOD;
__IO uint32_t *CNT; __IO uint32_t *SYNC;
__IO uint32_t *CnV; __IO uint32_t *CnV;
}; };

View File

@ -38,26 +38,31 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
} }
pwm_clock = clkval; pwm_clock = clkval;
unsigned int port = (unsigned int)pin >> PORT_SHIFT;
unsigned int ftm_n = (pwm >> TPM_SHIFT); unsigned int ftm_n = (pwm >> TPM_SHIFT);
unsigned int ch_n = (pwm & 0xFF); unsigned int ch_n = (pwm & 0xFF);
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n); SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n);
FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n); FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n);
ftm->CONF |= FTM_CONF_BDMMODE(3); ftm->CONF |= FTM_CONF_BDMMODE(3);
ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz
ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */ ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */
ftm->MODE = FTM_MODE_FTMEN_MASK;
ftm->SYNC = FTM_SYNC_CNTMIN_MASK;
ftm->SYNCONF = FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWWRBUF_MASK;
//I don't actually want to use SYNCEN which enables synchronization for match register,
// but this is only way I get the thing to do anything with FTMEN = 1
ftm->COMBINE = FTM_COMBINE_SYNCEN0_MASK | FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_SYNCEN2_MASK | FTM_COMBINE_SYNCEN3_MASK;
obj->CnV = &ftm->CONTROLS[ch_n].CnV; obj->CnV = &ftm->CONTROLS[ch_n].CnV;
obj->MOD = &ftm->MOD; obj->MOD = &ftm->MOD;
obj->CNT = &ftm->CNT; obj->SYNC = &ftm->SYNC;
// default to 20ms: standard for servos, and fine for e.g. brightness control // default to 20ms: standard for servos, and fine for e.g. brightness control
pwmout_period_ms(obj, 20); pwmout_period_ms(obj, 20);
pwmout_write(obj, 0); pwmout_write(obj, 0.0);
// Wire pinout // Wire pinout
pinmap_pinout(pin, PinMap_PWM); pinmap_pinout(pin, PinMap_PWM);
} }
@ -70,11 +75,14 @@ void pwmout_write(pwmout_t* obj, float value) {
} else if (value > 1.0) { } else if (value > 1.0) {
value = 1.0; value = 1.0;
} }
while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
*obj->CnV = (uint32_t)((float)(*obj->MOD + 1) * value); *obj->CnV = (uint32_t)((float)(*obj->MOD + 1) * value);
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
} }
float pwmout_read(pwmout_t* obj) { float pwmout_read(pwmout_t* obj) {
while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
float v = (float)(*obj->CnV) / (float)(*obj->MOD + 1); float v = (float)(*obj->CnV) / (float)(*obj->MOD + 1);
return (v > 1.0) ? (1.0) : (v); return (v > 1.0) ? (1.0) : (v);
} }
@ -91,6 +99,7 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
void pwmout_period_us(pwmout_t* obj, int us) { void pwmout_period_us(pwmout_t* obj, int us) {
float dc = pwmout_read(obj); float dc = pwmout_read(obj);
*obj->MOD = (uint32_t)(pwm_clock * (float)us) - 1; *obj->MOD = (uint32_t)(pwm_clock * (float)us) - 1;
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
pwmout_write(obj, dc); pwmout_write(obj, dc);
} }
@ -104,4 +113,5 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
void pwmout_pulsewidth_us(pwmout_t* obj, int us) { void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
*obj->CnV = (uint32_t)(pwm_clock * (float)us); *obj->CnV = (uint32_t)(pwm_clock * (float)us);
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
} }