From 095ebd03e3d34c0af2a8e826b586e3742d72ab5a Mon Sep 17 00:00:00 2001 From: Sissors Date: Sat, 7 Mar 2015 22:06:01 +0100 Subject: [PATCH] [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. --- .../TARGET_Freescale/TARGET_K20XX/objects.h | 2 +- .../TARGET_K20XX/pwmout_api.c | 22 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/objects.h b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/objects.h index edf5aaa6ce..6067a60cd5 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/objects.h +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/objects.h @@ -41,7 +41,7 @@ struct port_s { struct pwmout_s { __IO uint32_t *MOD; - __IO uint32_t *CNT; + __IO uint32_t *SYNC; __IO uint32_t *CnV; }; diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/pwmout_api.c index fa318980aa..a2a7ba669a 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/pwmout_api.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20XX/pwmout_api.c @@ -38,26 +38,31 @@ void pwmout_init(pwmout_t* obj, PinName pin) { } pwm_clock = clkval; - unsigned int port = (unsigned int)pin >> PORT_SHIFT; unsigned int ftm_n = (pwm >> TPM_SHIFT); unsigned int ch_n = (pwm & 0xFF); - SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port); SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n); FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n); ftm->CONF |= FTM_CONF_BDMMODE(3); 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->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->MOD = &ftm->MOD; - obj->CNT = &ftm->CNT; + obj->SYNC = &ftm->SYNC; // default to 20ms: standard for servos, and fine for e.g. brightness control pwmout_period_ms(obj, 20); - pwmout_write(obj, 0); - + pwmout_write(obj, 0.0); + // Wire pinout pinmap_pinout(pin, PinMap_PWM); } @@ -70,11 +75,14 @@ void pwmout_write(pwmout_t* obj, float value) { } else if (value > 1.0) { value = 1.0; } - + + while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK); *obj->CnV = (uint32_t)((float)(*obj->MOD + 1) * value); + *obj->SYNC |= FTM_SYNC_SWSYNC_MASK; } float pwmout_read(pwmout_t* obj) { + while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK); float v = (float)(*obj->CnV) / (float)(*obj->MOD + 1); 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) { float dc = pwmout_read(obj); *obj->MOD = (uint32_t)(pwm_clock * (float)us) - 1; + *obj->SYNC |= FTM_SYNC_SWSYNC_MASK; 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) { *obj->CnV = (uint32_t)(pwm_clock * (float)us); + *obj->SYNC |= FTM_SYNC_SWSYNC_MASK; }