FastPWM clone
Device/FastPWM_STM_TIM.cpp@35:d6c2b73d71f5, 2019-10-30 (annotated)
- Committer:
- blaze
- Date:
- Wed Oct 30 03:00:00 2019 +0000
- Revision:
- 35:d6c2b73d71f5
- Parent:
- 32:e880dcb178f4
Replace new/delete with malloc/free for void *. Deleting void pointer is undefined behavior in C++.
Who changed what in which revision?
User | Revision | Line number | New 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 | 32:e880dcb178f4 | 9 | typedef struct { |
Sissors | 32:e880dcb178f4 | 10 | CHANNEL_P_T channel; |
Sissors | 32:e880dcb178f4 | 11 | uint32_t clk_prescaler; |
Sissors | 32:e880dcb178f4 | 12 | } fastpwm_struct; |
Sissors | 32:e880dcb178f4 | 13 | |
Sissors | 32:e880dcb178f4 | 14 | #define PWM_CHANNEL ((((fastpwm_struct*)fast_obj)->channel)) |
Sissors | 32:e880dcb178f4 | 15 | #define PWM_CLK_PRESCALER ((((fastpwm_struct*)fast_obj)->clk_prescaler)) |
Sissors | 32:e880dcb178f4 | 16 | #define PWM_TIMER ((TIM_TypeDef*)_pwm.pwm) |
Sissors | 13:cdefd9d75b64 | 17 | |
Sissors | 28:3c8a0d977bc3 | 18 | #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1) |
Sissors | 28:3c8a0d977bc3 | 19 | extern __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin); |
Sissors | 28:3c8a0d977bc3 | 20 | #endif |
Sissors | 13:cdefd9d75b64 | 21 | |
Sissors | 13:cdefd9d75b64 | 22 | void FastPWM::initFastPWM( void ) { |
blaze | 35:d6c2b73d71f5 | 23 | fast_obj = malloc(sizeof(fastpwm_struct)); |
Sissors | 28:3c8a0d977bc3 | 24 | #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1) |
Sissors | 32:e880dcb178f4 | 25 | PWM_CHANNEL = getChannel(PWM_TIMER, _pwm.pin); |
Sissors | 28:3c8a0d977bc3 | 26 | #else |
Sissors | 32:e880dcb178f4 | 27 | PWM_CHANNEL = (&PWM_TIMER->CCR1 + _pwm.channel - 1); |
Sissors | 28:3c8a0d977bc3 | 28 | #endif |
jocis | 17:8378bc456f0d | 29 | |
Sissors | 32:e880dcb178f4 | 30 | // Depending on the timer and the internal bus it is connected to, each STM timer |
Sissors | 32:e880dcb178f4 | 31 | // can have a fixed prescaler from the clock, especially the faster devices. |
Sissors | 32:e880dcb178f4 | 32 | // In order not to have to hardcode this in, we use knowledge that mbed lib sets |
Sissors | 32:e880dcb178f4 | 33 | // default period to 20ms to reverse engineer the prescaler from this. |
Sissors | 32:e880dcb178f4 | 34 | uint32_t current_hz = SystemCoreClock / (PWM_TIMER->PSC + 1) / (PWM_TIMER->ARR+1); |
Sissors | 32: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 | 32:e880dcb178f4 | 36 | |
Sissors | 32:e880dcb178f4 | 37 | //Sanity check in case a target does something different |
Sissors | 32:e880dcb178f4 | 38 | if ( (PWM_CLK_PRESCALER == 0 ) || (PWM_CLK_PRESCALER > 16)) { |
Sissors | 32:e880dcb178f4 | 39 | PWM_CLK_PRESCALER = 1; |
Sissors | 32:e880dcb178f4 | 40 | } |
Sissors | 32: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 | 32: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 | 32:e880dcb178f4 | 61 | if (reqScale == 0) { |
Sissors | 13:cdefd9d75b64 | 62 | //Return prescaler |
Sissors | 32:e880dcb178f4 | 63 | return (PWM_TIMER->PSC + 1) * PWM_CLK_PRESCALER; |
Sissors | 32:e880dcb178f4 | 64 | } |
Sissors | 32:e880dcb178f4 | 65 | if (reqScale > (uint32_t)(PWM_CLK_PRESCALER<<16)) { |
Sissors | 32:e880dcb178f4 | 66 | reqScale = PWM_CLK_PRESCALER<<16; |
Sissors | 32: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 | 32:e880dcb178f4 | 69 | //Take into account PWM_CLK_PRESCALER, we need to make sure reqScale is always rounded up |
Sissors | 32:e880dcb178f4 | 70 | PWM_TIMER->PSC = (reqScale + PWM_CLK_PRESCALER - 1)/PWM_CLK_PRESCALER - 1; |
Sissors | 13:cdefd9d75b64 | 71 | |
Sissors | 32:e880dcb178f4 | 72 | return setPrescaler(0); |
Sissors | 13:cdefd9d75b64 | 73 | } |
Sissors | 13:cdefd9d75b64 | 74 | |
Sissors | 13:cdefd9d75b64 | 75 | #endif |