FASTPWM
Diff: Device/FastPWM_STM_TIM.cpp
- Revision:
- 32:e880dcb178f4
- Parent:
- 28:3c8a0d977bc3
--- a/Device/FastPWM_STM_TIM.cpp Tue Sep 06 20:17:21 2016 +0000 +++ b/Device/FastPWM_STM_TIM.cpp Sun Jan 01 14:37:55 2017 +0000 @@ -6,22 +6,39 @@ typedef __IO uint32_t* CHANNEL_P_T; -#define PWM_CHANNEL (**(CHANNEL_P_T*)fast_obj) -#define PWM_TIMER ((TIM_TypeDef*)_pwm.pwm) +typedef struct { + CHANNEL_P_T channel; + uint32_t clk_prescaler; +} fastpwm_struct; + +#define PWM_CHANNEL ((((fastpwm_struct*)fast_obj)->channel)) +#define PWM_CLK_PRESCALER ((((fastpwm_struct*)fast_obj)->clk_prescaler)) +#define PWM_TIMER ((TIM_TypeDef*)_pwm.pwm) #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1) extern __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin); #endif void FastPWM::initFastPWM( void ) { - fast_obj = new (CHANNEL_P_T); - + fast_obj = new fastpwm_struct; #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1) - *(CHANNEL_P_T*)fast_obj = getChannel(PWM_TIMER, _pwm.pin); + PWM_CHANNEL = getChannel(PWM_TIMER, _pwm.pin); #else - *(CHANNEL_P_T*)fast_obj = &PWM_TIMER->CCR1 + _pwm.channel - 1; + PWM_CHANNEL = (&PWM_TIMER->CCR1 + _pwm.channel - 1); #endif + // Depending on the timer and the internal bus it is connected to, each STM timer + // can have a fixed prescaler from the clock, especially the faster devices. + // In order not to have to hardcode this in, we use knowledge that mbed lib sets + // default period to 20ms to reverse engineer the prescaler from this. + uint32_t current_hz = SystemCoreClock / (PWM_TIMER->PSC + 1) / (PWM_TIMER->ARR+1); + PWM_CLK_PRESCALER = (current_hz + 1) / 50; //50Hz is magic number it should be, +1 is to handle possible rounding errors in mbed setup + + //Sanity check in case a target does something different + if ( (PWM_CLK_PRESCALER == 0 ) || (PWM_CLK_PRESCALER > 16)) { + PWM_CLK_PRESCALER = 1; + } + //Enable PWM period syncing for glitch free result PWM_TIMER->CR1 |= TIM_CR1_ARPE; @@ -29,7 +46,7 @@ } void FastPWM::pulsewidth_ticks( uint32_t ticks ) { - PWM_CHANNEL = ticks; + *PWM_CHANNEL = ticks; } void FastPWM::period_ticks( uint32_t ticks ) { @@ -41,15 +58,18 @@ } uint32_t FastPWM::setPrescaler(uint32_t reqScale) { - if (reqScale == 0) + if (reqScale == 0) { //Return prescaler - return PWM_TIMER->PSC + 1; - if (reqScale > (uint32_t)(1<<16)) - reqScale = 1<<16; + return (PWM_TIMER->PSC + 1) * PWM_CLK_PRESCALER; + } + if (reqScale > (uint32_t)(PWM_CLK_PRESCALER<<16)) { + reqScale = PWM_CLK_PRESCALER<<16; + } //Else set prescaler, we have to substract one from reqScale since a 0 in PCVAL is prescaler of 1 - PWM_TIMER->PSC = reqScale - 1; + //Take into account PWM_CLK_PRESCALER, we need to make sure reqScale is always rounded up + PWM_TIMER->PSC = (reqScale + PWM_CLK_PRESCALER - 1)/PWM_CLK_PRESCALER - 1; - return reqScale; + return setPrescaler(0); } #endif \ No newline at end of file