Pinscape fork (KL25Z)

Dependents:   Pinscape_Controller_V2_arnoz Pinscape_Controller_V2

Fork of FastPWM by Erik -

Committer:
Sissors
Date:
Sun Jan 01 14:37:55 2017 +0000
Revision:
33:e880dcb178f4
Parent:
29:3c8a0d977bc3
Fixed issue where STM32 PWM on MCUs with high clock frequency could be a factor of two too fast

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 13:cdefd9d75b64 1 //This should (hopefully) work on all STM targets which use TIM timers for PWM
Sissors 13:cdefd9d75b64 2
Sissors 13:cdefd9d75b64 3 #ifdef TARGET_STM
Sissors 13:cdefd9d75b64 4
Sissors 13:cdefd9d75b64 5 #include "FastPWM.h"
Sissors 13:cdefd9d75b64 6
jocis 17:8378bc456f0d 7 typedef __IO uint32_t* CHANNEL_P_T;
jocis 17:8378bc456f0d 8
Sissors 33:e880dcb178f4 9 typedef struct {
Sissors 33:e880dcb178f4 10 CHANNEL_P_T channel;
Sissors 33:e880dcb178f4 11 uint32_t clk_prescaler;
Sissors 33:e880dcb178f4 12 } fastpwm_struct;
Sissors 33:e880dcb178f4 13
Sissors 33:e880dcb178f4 14 #define PWM_CHANNEL ((((fastpwm_struct*)fast_obj)->channel))
Sissors 33:e880dcb178f4 15 #define PWM_CLK_PRESCALER ((((fastpwm_struct*)fast_obj)->clk_prescaler))
Sissors 33:e880dcb178f4 16 #define PWM_TIMER ((TIM_TypeDef*)_pwm.pwm)
Sissors 13:cdefd9d75b64 17
Sissors 29:3c8a0d977bc3 18 #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1)
Sissors 29:3c8a0d977bc3 19 extern __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin);
Sissors 29:3c8a0d977bc3 20 #endif
Sissors 13:cdefd9d75b64 21
Sissors 13:cdefd9d75b64 22 void FastPWM::initFastPWM( void ) {
Sissors 33:e880dcb178f4 23 fast_obj = new fastpwm_struct;
Sissors 29:3c8a0d977bc3 24 #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1)
Sissors 33:e880dcb178f4 25 PWM_CHANNEL = getChannel(PWM_TIMER, _pwm.pin);
Sissors 29:3c8a0d977bc3 26 #else
Sissors 33:e880dcb178f4 27 PWM_CHANNEL = (&PWM_TIMER->CCR1 + _pwm.channel - 1);
Sissors 29:3c8a0d977bc3 28 #endif
jocis 17:8378bc456f0d 29
Sissors 33:e880dcb178f4 30 // Depending on the timer and the internal bus it is connected to, each STM timer
Sissors 33:e880dcb178f4 31 // can have a fixed prescaler from the clock, especially the faster devices.
Sissors 33:e880dcb178f4 32 // In order not to have to hardcode this in, we use knowledge that mbed lib sets
Sissors 33:e880dcb178f4 33 // default period to 20ms to reverse engineer the prescaler from this.
Sissors 33:e880dcb178f4 34 uint32_t current_hz = SystemCoreClock / (PWM_TIMER->PSC + 1) / (PWM_TIMER->ARR+1);
Sissors 33:e880dcb178f4 35 PWM_CLK_PRESCALER = (current_hz + 1) / 50; //50Hz is magic number it should be, +1 is to handle possible rounding errors in mbed setup
Sissors 33:e880dcb178f4 36
Sissors 33:e880dcb178f4 37 //Sanity check in case a target does something different
Sissors 33:e880dcb178f4 38 if ( (PWM_CLK_PRESCALER == 0 ) || (PWM_CLK_PRESCALER > 16)) {
Sissors 33:e880dcb178f4 39 PWM_CLK_PRESCALER = 1;
Sissors 33:e880dcb178f4 40 }
Sissors 33:e880dcb178f4 41
Sissors 22:db9c0cf445e2 42 //Enable PWM period syncing for glitch free result
Sissors 22:db9c0cf445e2 43 PWM_TIMER->CR1 |= TIM_CR1_ARPE;
Sissors 22:db9c0cf445e2 44
Sissors 13:cdefd9d75b64 45 bits = 16;
Sissors 13:cdefd9d75b64 46 }
Sissors 13:cdefd9d75b64 47
Sissors 13:cdefd9d75b64 48 void FastPWM::pulsewidth_ticks( uint32_t ticks ) {
Sissors 33:e880dcb178f4 49 *PWM_CHANNEL = ticks;
Sissors 13:cdefd9d75b64 50 }
Sissors 13:cdefd9d75b64 51
Sissors 13:cdefd9d75b64 52 void FastPWM::period_ticks( uint32_t ticks ) {
Sissors 13:cdefd9d75b64 53 PWM_TIMER->ARR = ticks - 1;
Sissors 13:cdefd9d75b64 54 }
Sissors 13:cdefd9d75b64 55
Sissors 13:cdefd9d75b64 56 uint32_t FastPWM::getPeriod( void ) {
Sissors 13:cdefd9d75b64 57 return PWM_TIMER->ARR + 1;
Sissors 13:cdefd9d75b64 58 }
Sissors 13:cdefd9d75b64 59
Sissors 13:cdefd9d75b64 60 uint32_t FastPWM::setPrescaler(uint32_t reqScale) {
Sissors 33:e880dcb178f4 61 if (reqScale == 0) {
Sissors 13:cdefd9d75b64 62 //Return prescaler
Sissors 33:e880dcb178f4 63 return (PWM_TIMER->PSC + 1) * PWM_CLK_PRESCALER;
Sissors 33:e880dcb178f4 64 }
Sissors 33:e880dcb178f4 65 if (reqScale > (uint32_t)(PWM_CLK_PRESCALER<<16)) {
Sissors 33:e880dcb178f4 66 reqScale = PWM_CLK_PRESCALER<<16;
Sissors 33:e880dcb178f4 67 }
Sissors 13:cdefd9d75b64 68 //Else set prescaler, we have to substract one from reqScale since a 0 in PCVAL is prescaler of 1
Sissors 33:e880dcb178f4 69 //Take into account PWM_CLK_PRESCALER, we need to make sure reqScale is always rounded up
Sissors 33:e880dcb178f4 70 PWM_TIMER->PSC = (reqScale + PWM_CLK_PRESCALER - 1)/PWM_CLK_PRESCALER - 1;
Sissors 13:cdefd9d75b64 71
Sissors 33:e880dcb178f4 72 return setPrescaler(0);
Sissors 13:cdefd9d75b64 73 }
Sissors 13:cdefd9d75b64 74
Sissors 13:cdefd9d75b64 75 #endif