inported from local
Revision 0:60857722c2ff, committed 2020-03-16
- Comitter:
- NYX
- Date:
- Mon Mar 16 06:36:03 2020 +0000
- Commit message:
- initial commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_KLXX_K20D50M.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,55 @@ +#if defined(TARGET_KLXX) || defined(TARGET_K20D50M) + +#include "FastPWM.h" + +void FastPWM::initFastPWM( void ) { + bits = 16; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + *(_pwm.CnV) = ticks; +} + +void FastPWM::period_ticks( uint32_t ticks ) { + *(_pwm.MOD) = ticks - 1; +} + +uint32_t FastPWM::getPeriod( void ) { + return *(_pwm.MOD) + 1; +} + +uint32_t FastPWM::setPrescaler(uint32_t reqScale) { + + //Yes this is ugly, yes I should feel bad about it + volatile uint32_t *TPM_SC = _pwm.MOD - 2; + + const char prescalers[] = {1, 2, 4, 8, 16, 32, 64, 128}; + + //If prescaler is 0, return current one + if (reqScale == 0) + return (prescalers[(*TPM_SC) & 0x07]); + + uint32_t retval = 0; + char bin; + + for (bin = 0; bin<8; bin++) { + retval = prescalers[bin]; + if (retval >= reqScale) + break; + } + if (bin == 8) + bin = 7; + + //Clear lower 5 bits, write new value: + char clockbits = *TPM_SC & (3<<3); + + //For some reason clearing them takes some effort + while ((*TPM_SC & 0x1F) != 0) + *TPM_SC &= ~0x1F; + + + *TPM_SC = bin + clockbits; + + return retval; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_KSDK.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,82 @@ +#if defined(TARGET_KPSDK_MCUS) + +#include "FastPWM.h" +#include "fsl_clock_manager.h" + + +#define PWM_CNV (*(((fastpwm_struct*)fast_obj)->CnV)) +#define PWM_MOD (*(((fastpwm_struct*)fast_obj)->MOD)) +#define PWM_SC (*(((fastpwm_struct*)fast_obj)->SC)) + +typedef struct { + __IO uint32_t *CnV; + __IO uint32_t *MOD; + __IO uint32_t *SC; +} fastpwm_struct; + +static uint32_t pwm_prescaler; + +void FastPWM::initFastPWM( void ) { + fast_obj = new fastpwm_struct; + bits = 16; + + uint32_t pwm_base_clock; + CLOCK_SYS_GetFreq(kBusClock, &pwm_base_clock); + pwm_prescaler = SystemCoreClock / pwm_base_clock; + + uint32_t ftms[] = FTM_BASE_ADDRS; + unsigned int ch_n = (_pwm.pwm_name & 0xFF); + FTM_Type *ftm = (FTM_Type *)ftms[_pwm.pwm_name >> TPM_SHIFT]; + + ((fastpwm_struct*)fast_obj)->CnV = &ftm->CONTROLS[ch_n].CnV; + ((fastpwm_struct*)fast_obj)->MOD = &ftm->MOD; + ((fastpwm_struct*)fast_obj)->SC = &ftm->SC; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + PWM_CNV = ticks; +} + +void FastPWM::period_ticks( uint32_t ticks ) { + PWM_MOD = ticks - 1; +} + +uint32_t FastPWM::getPeriod( void ) { + return PWM_MOD + 1; +} + +uint32_t FastPWM::setPrescaler(uint32_t reqScale) { + + uint32_t prescalers[] = {1, 2, 4, 8, 16, 32, 64, 128}; + + for (int i = 0; i<8; i++) + prescalers[i] = prescalers[i] * pwm_prescaler; + + //If prescaler is 0, return current one + if (reqScale == 0) + return (prescalers[(PWM_SC) & 0x07]); + + uint32_t retval = 0; + char bin; + + for (bin = 0; bin<8; bin++) { + retval = prescalers[bin]; + if (retval >= reqScale) + break; + } + if (bin == 8) + bin = 7; + + //Clear lower 5 bits, write new value: + char clockbits = PWM_SC & (3<<3); + + //For some reason clearing them takes some effort + while ((PWM_SC & 0x1F) != 0) + PWM_SC &= ~0x1F; + + + PWM_SC = bin + clockbits; + + return retval; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_LPC11XX.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,103 @@ +#if defined(TARGET_LPC11UXX) || defined(TARGET_LPC11XX_11CXX) + +#include "FastPWM.h" + +#define PWM_MR (*(((fastpwm_struct*)fast_obj)->MR)) +#define PWM_TIMER (((fastpwm_struct*)fast_obj)->timer) + +typedef struct { + uint8_t timer; + uint8_t mr; +} timer_mr; + +#ifdef TARGET_LPC11UXX +typedef struct { + __IO uint32_t *MR; + LPC_CTxxBx_Type *timer; +} fastpwm_struct; + +static timer_mr pwm_timer_map[11] = { + {0, 0}, {0, 1}, {0, 2}, + {1, 0}, {1, 1}, + {2, 0}, {2, 1}, {2, 2}, + {3, 0}, {3, 1}, {3, 2}, +}; + +static LPC_CTxxBx_Type *Timers[4] = { + LPC_CT16B0, LPC_CT16B1, + LPC_CT32B0, LPC_CT32B1 +}; +#else //LPC11XX +typedef struct { + __IO uint32_t *MR; + LPC_TMR_TypeDef *timer; +} fastpwm_struct; + +static timer_mr pwm_timer_map[5] = { + {0, 0}, /* CT16B0, MR0 */ + {0, 1}, /* CT16B0, MR1 */ + + {1, 0}, /* CT16B1, MR0 */ + {1, 1}, /* CT16B1, MR1 */ + + {2, 2}, /* CT32B0, MR2 */ +}; + +static LPC_TMR_TypeDef *Timers[3] = { + LPC_TMR16B0, LPC_TMR16B1, + LPC_TMR32B0 +}; +#endif + + +void FastPWM::initFastPWM( void ) { + fast_obj = new fastpwm_struct; + timer_mr tid = pwm_timer_map[_pwm.pwm]; + PWM_TIMER = Timers[tid.timer]; + (((fastpwm_struct*)fast_obj)->MR) = &PWM_TIMER->MR[tid.mr]; + + if (tid.timer < 2) + //16-bit timer + bits = 16; + else + //32-bit timer + bits = 32; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + if (ticks) + PWM_MR = PWM_TIMER->MR3 - ticks; //They inverted PWM on the 11u24 + else + PWM_MR = 0xFFFFFFFF; //If MR3 = ticks 1 clock cycle wide errors appear, this prevents that (unless MR3 = max). +} + +void FastPWM::period_ticks( uint32_t ticks ) { + PWM_TIMER->TCR = 0x02; + PWM_TIMER->MR3 = ticks; + PWM_TIMER->TCR = 0x01; +} + +uint32_t FastPWM::getPeriod( void ) { + return PWM_TIMER->MR3; +} + +uint32_t FastPWM::setPrescaler(uint32_t reqScale) { + //If 32-bit, disable auto-scaling, return 1 + if (bits == 32) { + dynamicPrescaler = false; + return 1; + } + + //Else 16-bit timer: + if (reqScale == 0) + //Return prescaler + return PWM_TIMER->PR + 1; + if (reqScale > (uint32_t)(1<<16)) + reqScale = 1<<16; + //Else set prescaler, we have to substract one from reqScale since a 0 in PCVAL is prescaler of 1 + PWM_TIMER->PR = reqScale - 1; + + return reqScale; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_LPC1768.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,34 @@ +#ifdef TARGET_LPC1768 + +#include "FastPWM.h" + +void FastPWM::initFastPWM( void ) { + //Set clock source + LPC_SC->PCLKSEL0|=1<<12; + bits = 32; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + *(_pwm.MR) = ticks; + LPC_PWM1->LER |= 1 << _pwm.pwm; +} + +void FastPWM::period_ticks( uint32_t ticks ) { + LPC_PWM1->MR0 = ticks; + LPC_PWM1->LER |= 1 << 0; +} + +uint32_t FastPWM::getPeriod( void ) { + return LPC_PWM1->MR0; +} + +//Maybe implemented later, but needing to change the prescaler for a 32-bit +//timer used in PWM mode is kinda unlikely. +//If you really need to do it, rejoice, you can make it run so slow a period is over 40,000 year +uint32_t FastPWM::setPrescaler(uint32_t reqScale) { + //Disable dynamic prescaling + dynamicPrescaler = false; + + return 1; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_STM_TIM.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,48 @@ +//This should (hopefully) work on all STM targets which use TIM timers for PWM + +#ifdef TARGET_STM + +#include "FastPWM.h" + +typedef __IO uint32_t* CHANNEL_P_T; + +#define PWM_CHANNEL (**(CHANNEL_P_T*)fast_obj) +#define PWM_TIMER ((TIM_TypeDef*)_pwm.pwm) + +extern CHANNEL_P_T getChannel(TIM_TypeDef* pwm, PinName pin); + +void FastPWM::initFastPWM( void ) { + fast_obj = new (CHANNEL_P_T); + *(CHANNEL_P_T*)fast_obj = getChannel(PWM_TIMER, _pwm.pin); + + //Enable PWM period syncing for glitch free result + PWM_TIMER->CR1 |= TIM_CR1_ARPE; + + bits = 16; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + PWM_CHANNEL = ticks; +} + +void FastPWM::period_ticks( uint32_t ticks ) { + PWM_TIMER->ARR = ticks - 1; +} + +uint32_t FastPWM::getPeriod( void ) { + return PWM_TIMER->ARR + 1; +} + +uint32_t FastPWM::setPrescaler(uint32_t reqScale) { + if (reqScale == 0) + //Return prescaler + return PWM_TIMER->PSC + 1; + if (reqScale > (uint32_t)(1<<16)) + reqScale = 1<<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; + + return reqScale; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_STM_TIM_PinOut.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,151 @@ +#include "mbed.h" + +#ifdef TARGET_NUCLEO_F303RE +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 + case PC_0: case PB_8: case PB_9: case PA_6: case PA_8: case PB_4: case PB_5: case PA_2: case PC_6: case PA_12: case PB_14: case PB_15: + // Channels 1N + case PA_1: case PA_5: case PB_6: case PB_3: case PA_13: case PB_7: case PC_13: + return &pwm->CCR1; + + // Channels 2 + case PC_1: case PA_7: case PC_7: case PA_9: case PA_3: case PA_14: + // Channels 2N + case PB_0: + return &pwm->CCR2; + + // Channels 3 + case PA_10: case PC_2: case PC_8: + // Channels 3N + case PB_1: + return &pwm->CCR3; + + // Channels 4 + case PC_3: case PC_9: case PA_11: + // Channels 4N + + return &pwm->CCR4; + } + return NULL; +} +#endif + +#ifdef TARGET_NUCLEO_F030R8 +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 + case PA_4: case PA_6: case PB_1: case PB_4: case PB_8: case PB_9: case PB_14: case PC_6: case PB_6: case PB_7: + return &pwm->CCR1; + + // Channels 2 + case PA_7: case PB_5: case PC_7: + return &pwm->CCR2; + + // Channels 3 + case PB_0: case PC_8: + return &pwm->CCR3; + + // Channels 4 + case PC_9: + return &pwm->CCR4; + } + return NULL; +} +#endif + +#if defined TARGET_NUCLEO_F401RE || defined TARGET_NUCLEO_F411RE || defined TARGET_NUCLEO_F446RE +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 : PWMx/1 + case PA_0: case PA_5: case PA_6: case PA_8: case PA_15: case PB_4: case PB_6: case PC_6: case PA_7: case PB_13: + return &pwm->CCR1; + + // Channels 2 : PWMx/2 + case PA_1: case PA_9: case PB_3: case PB_5: case PB_7: case PC_7: case PB_0: case PB_14: + return &pwm->CCR2; + + // Channels 3 : PWMx/3 + case PA_2: case PA_10: case PB_8: case PB_10: case PC_8: case PB_1: case PB_15: + return &pwm->CCR3; + + // Channels 4 : PWMx/4 + case PA_3: case PA_11: case PB_9: case PC_9: + return &pwm->CCR4; + } + return NULL; +} +#endif + +#if defined TARGET_NUCLEO_F103RB +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 : PWMx/1 + case PA_6: case PA_8: case PA_15: case PB_4: case PC_6: case PB_13: + return &pwm->CCR1; + + // Channels 2 : PWMx/2 + case PA_1: case PA_7: case PA_9: case PB_3: case PB_5: case PC_7: case PB_14: + return &pwm->CCR2; + + // Channels 3 : PWMx/3 + case PA_2: case PA_10: case PB_0: case PB_10: case PC_8: case PB_15: + return &pwm->CCR3; + + // Channels 4 : PWMx/4 + case PA_3: case PA_11: case PB_1: case PB_11: case PC_9: + return &pwm->CCR4; + } + return NULL; +} +#endif + +#ifdef TARGET_NUCLEO_F334R8 +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 + case PA_2: case PA_6: case PA_7: case PA_8: case PA_12: case PB_4: case PB_5: case PB_8: case PB_9: case PB_14: case PC_0: case PC_6: + case PA_1: case PA_13: case PB_6: case PB_13: case PC_13: + return &pwm->CCR1; + + // Channels 2 + case PA_3: case PA_4: case PA_9: case PB_15: case PC_1: case PC_7: + return &pwm->CCR2; + + // Channels 3 + case PA_10: case PB_0: case PC_2: case PC_8: + case PF_0: + return &pwm->CCR3; + + // Channels 4 + case PA_11: case PB_1: case PB_7: case PC_3: case PC_9: + return &pwm->CCR4; + } + return NULL; +} +#endif + +#if defined TARGET_NUCLEO_F072RB +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 : PWMx/1 + case PA_2: case PA_6: case PA_4: case PA_7: case PA_8: case PB_1: case PB_4: case PB_8: case PB_9: case PB_14: case PC_6: + // Channels 1N : PWMx/1N + case PA_1: case PB_6: case PB_7: case PB_13: + return &pwm->CCR1; + + // Channels 2 : PWMx/2 + case PA_3: case PA_9: case PB_5: case PC_7: case PB_15: + return &pwm->CCR2; + + // Channels 3 : PWMx/3 + case PA_10: case PB_0: case PC_8: + return &pwm->CCR3; + + // Channels 4 : PWMx/4 + case PA_11: case PC_9: + return &pwm->CCR4; + } + return NULL; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastPWM.h Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,150 @@ +/* + .---. _....._ + / p `\ .-""`: :`"-. + |__ - | ,' . ' ', + ._> \ /: : ; :, + '-. '\`. . : ' \ + `. | .'._.' '._.' '._.'. | + `;-\. : : ' '/,__, + .-'`'._ ' . : _.'.__.' + ((((-'/ `";--..:..--;"` \ + .' / \ \ + jgs ((((-' ((((-' + +Yeah ASCII art turtle more fun than copyright stuff +*/ + + +#include "mbed.h" + +#ifndef FASTPWM_H +#define FASTPWM_H + +/** Library that allows faster and/or higher resolution PWM output + * + * Library can directly replace standard mbed PWM library. + * + * Contrary to the default mbed library, this library takes doubles instead of floats. The compiler will autocast if needed, + * but do take into account it is done for a reason, your accuracy will otherwise be limitted by the floating point precision. + */ +class FastPWM : public PwmOut { +public: + /** + * Create a FastPWM object connected to the specified pin + * + * @param pin - PWM pin to connect to + * @param prescaler - Clock prescaler, -1 is dynamic (default), 0 is bit random, everything else normal + */ + FastPWM(PinName pin, int prescaler = -1); + ~FastPWM(); + + /** + * Set the PWM period, specified in seconds (double), keeping the pulsewidth the same. + */ + void period(double seconds); + + /** + * Set the PWM period, specified in milli-seconds (int), keeping the pulsewidth the same. + */ + void period_ms(int ms); + + /** + * Set the PWM period, specified in micro-seconds (int), keeping the pulsewidth the same. + */ + void period_us(int us); + + /** + * Set the PWM period, specified in micro-seconds (double), keeping the pulsewidth the same. + */ + void period_us(double us); + + /** + * Set the PWM period, specified in clock ticks, keeping _pulse width_ the same. + * + * This function can be used if low overhead is required. Do take into account the result is + * board (clock frequency) dependent, and this does not keep an equal duty cycle! + */ + void period_ticks(uint32_t ticks); + + /** + * Set the PWM pulsewidth, specified in seconds (double), keeping the period the same. + */ + void pulsewidth(double seconds); + + /** + * Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same. + */ + void pulsewidth_ms(int ms); + + /** + * Set the PWM pulsewidth, specified in micro-seconds (int), keeping the period the same. + */ + void pulsewidth_us(int us); + + /** + * Set the PWM pulsewidth, specified in micro-seconds (double), keeping the period the same. + */ + void pulsewidth_us(double us); + + /** + * Set the PWM period, specified in clock ticks, keeping the period the same. + * + * This function can be used if low overhead is required. Do take into account the result is + * board (clock frequency) dependent! + */ + void pulsewidth_ticks(uint32_t ticks); + + /** + * Set the ouput duty-cycle, specified as a percentage (double) + * + * @param duty - A double value representing the output duty-cycle, specified as a percentage. The value should lie between 0.0 (representing on 0%) and 1.0 (representing on 100%). + */ + void write(double duty); + + /** + * Return the ouput duty-cycle, specified as a percentage (double) + * + * @param return - A double value representing the output duty-cycle, specified as a percentage. + */ + double read( void ); + + /** + * An operator shorthand for write() + */ + FastPWM& operator= (double value); + + /** + * An operator shorthand for read() + */ + operator double(); + + /** + * Set the PWM prescaler + * + * The period of all PWM pins on the same PWM unit have to be reset after using this! + * + * @param value - The required prescaler. Special values: 0 = lock current prescaler, -1 = use dynamic prescaler + * @param return - The prescaler which was set (can differ from requested prescaler if not possible) + */ + int prescaler(int value); + +private: + void initFastPWM(void); + + uint32_t setPrescaler( uint32_t reqScale ); + int calcPrescaler(uint64_t clocks); + uint32_t getPeriod( void ); + + void updateTicks( uint32_t prescaler ); + uint32_t bits; + + double _duty; + + double dticks, dticks_us; + int iticks_ms, iticks_us; + + bool dynamicPrescaler; + + void *fast_obj; +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastPWM_common.cpp Mon Mar 16 06:36:03 2020 +0000 @@ -0,0 +1,108 @@ +#include "FastPWM.h" + +FastPWM::FastPWM(PinName pin, int prescaler) : PwmOut(pin) { + fast_obj = NULL; + initFastPWM(); + this->prescaler(prescaler); + + //Set duty cycle on 0%, period on 20ms + period(0.02); + write(0); + + +} + +FastPWM::~FastPWM( void ) { + if (fast_obj != NULL) + delete(fast_obj); +} + +void FastPWM::period(double seconds) { + if (dynamicPrescaler) + calcPrescaler((uint64_t)(seconds * (double) SystemCoreClock)); + + period_ticks(seconds * dticks + 0.5); +} + +void FastPWM::period_ms(int ms) { + if (dynamicPrescaler) + calcPrescaler(ms * (SystemCoreClock / 1000)); + + period_ticks(ms * iticks_ms); +} + +void FastPWM::period_us(int us) { + if (dynamicPrescaler) + calcPrescaler(us * (SystemCoreClock / 1000000)); + + period_ticks(us * iticks_us); +} + +void FastPWM::period_us(double us) { + if (dynamicPrescaler) + calcPrescaler((uint64_t)(us * (double)(SystemCoreClock / 1000000))); + + period_ticks(us * dticks_us + 0.5); +} + +void FastPWM::pulsewidth(double seconds) { + pulsewidth_ticks(seconds * dticks + 0.5); +} + +void FastPWM::pulsewidth_ms(int ms) { + pulsewidth_ticks(ms * iticks_ms); +} + +void FastPWM::pulsewidth_us(int us) { + pulsewidth_ticks(us * iticks_us); +} + +void FastPWM::pulsewidth_us(double us) { + pulsewidth_ticks(us * dticks_us + 0.5); +} + +void FastPWM::write(double duty) { + _duty=duty; + pulsewidth_ticks(duty*getPeriod()); +} + +double FastPWM::read( void ) { + return _duty; + } + +FastPWM & FastPWM::operator= (double value) { + write(value); + return(*this); + } + +FastPWM::operator double() { + return _duty; +} + +int FastPWM::prescaler(int value) { + int retval; + if (value == -1) { + dynamicPrescaler = true; + value = 0; + } + else + dynamicPrescaler = false; + + retval = setPrescaler(value); + updateTicks(retval); + return retval; +} + +void FastPWM::updateTicks( uint32_t prescaler ) { + dticks = SystemCoreClock / (double)prescaler; + dticks_us = dticks / 1000000.0f; + iticks_us = (int)(dticks_us + 0.5); + iticks_ms = (int)(dticks_us * 1000.0 + 0.5); +} + +int FastPWM::calcPrescaler(uint64_t clocks) { + uint32_t scale = (clocks >> bits) + 1; + uint32_t retval = setPrescaler(scale); + updateTicks(retval); + return retval; +}