yes
Revision 0:c60399891edd, committed 2022-05-08
- Comitter:
- braichi13
- Date:
- Sun May 08 14:39:57 2022 +0000
- Commit message:
- Yes
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_KLXX_K20D50M.cpp Sun May 08 14:39:57 2022 +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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_KSDK.cpp Sun May 08 14:39:57 2022 +0000 @@ -0,0 +1,88 @@ +#if defined(TARGET_KPSDK_MCUS) + +#include "FastPWM.h" +#include "fsl_ftm.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)) +#define PWM_SYNC (*(((fastpwm_struct*)fast_obj)->SYNC)) + +typedef struct { + __IO uint32_t *CnV; + __IO uint32_t *MOD; + __IO uint32_t *SC; + __IO uint32_t *SYNC; +} fastpwm_struct; + +static uint32_t pwm_prescaler; +static FTM_Type *const ftm_addrs[] = FTM_BASE_PTRS; + +void FastPWM::initFastPWM( void ) { + fast_obj = new fastpwm_struct; + bits = 16; + + pwm_prescaler = SystemCoreClock / CLOCK_GetFreq(kCLOCK_BusClk);; + + unsigned int ch_n = (_pwm.pwm_name & 0xF); + FTM_Type *ftm = ftm_addrs[_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; + ((fastpwm_struct*)fast_obj)->SYNC = &ftm->SYNC; + + //Do not clear counter when writing new value, set end of period as loading value + ftm->SYNCONF &= ~FTM_SYNCONF_SWRSTCNT_MASK; + ftm->SYNC |= FTM_SYNC_CNTMAX_MASK; +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + PWM_CNV = ticks; + PWM_SYNC |= FTM_SYNC_SWSYNC_MASK; +} + +void FastPWM::period_ticks( uint32_t ticks ) { + PWM_MOD = ticks - 1; + PWM_SYNC |= FTM_SYNC_SWSYNC_MASK; +} + +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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_LPC11XX.cpp Sun May 08 14:39:57 2022 +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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_LPC1768.cpp Sun May 08 14:39:57 2022 +0000 @@ -0,0 +1,34 @@ +#ifdef TARGET_LPC176X + +#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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_LPC_SCT.cpp Sun May 08 14:39:57 2022 +0000 @@ -0,0 +1,63 @@ +//For targets which use the SCT +#if defined(TARGET_LPC81X) || defined(TARGET_LPC82X) + +#ifdef TARGET_LPC82X +#define CTRL_U CTRL +#endif + +#include "FastPWM.h" + +void FastPWM::initFastPWM( void ) { + //Mbed uses the timer as a single unified 32-bit timer, who are we to argue with this, and it is easier + bits = 32; + + #ifdef TARGET_LPC82X + //The mbed lib uses the PWM peripheral slightly different, which is irritating. This sets it bck to the LPC81X + _pwm.pwm->EVENT[_pwm.pwm_ch + 1].CTRL = (1 << 12) | (_pwm.pwm_ch + 1); // Event_n on Match_n + _pwm.pwm->EVENT[_pwm.pwm_ch + 1].STATE = 0xFFFFFFFF; // All states + _pwm.pwm->OUT[_pwm.pwm_ch].SET = (1 << 0); // All PWM channels are SET on Event_0 + _pwm.pwm->OUT[_pwm.pwm_ch].CLR = (1 << (_pwm.pwm_ch + 1)); // PWM ch is CLRed on Event_(ch+1) + #endif + + //With 32-bit we fix prescaler to 1 + _pwm.pwm->CTRL_U |= (1 << 2) | (1 << 3); + _pwm.pwm->CTRL_U &= ~(0x7F << 5); + _pwm.pwm->CTRL_U &= ~(1 << 2); + +} + +void FastPWM::pulsewidth_ticks( uint32_t ticks ) { + #ifdef TARGET_LPC81X + _pwm.pwm->MATCHREL[_pwm.pwm_ch + 1].U = ticks; + #else + _pwm.pwm->MATCHREL[_pwm.pwm_ch + 1] = ticks; + #endif +} + +void FastPWM::period_ticks( uint32_t ticks ) { + #ifdef TARGET_LPC81X + _pwm.pwm->MATCHREL[0].U = ticks; + #else + _pwm.pwm->MATCHREL[0] = ticks; + #endif +} + +uint32_t FastPWM::getPeriod( void ) { + #ifdef TARGET_LPC81X + return _pwm.pwm->MATCHREL[0].U; + #else + return _pwm.pwm->MATCHREL[0]; + #endif +} + +//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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_STM_TIM.cpp Sun May 08 14:39:57 2022 +0000 @@ -0,0 +1,75 @@ +//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; + +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 fastpwm_struct; + #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1) + PWM_CHANNEL = getChannel(PWM_TIMER, _pwm.pin); + #else + 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; + + 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) * 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 + //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 setPrescaler(0); +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/FastPWM_STM_TIM_PinOut.cpp Sun May 08 14:39:57 2022 +0000 @@ -0,0 +1,102 @@ +#include "mbed.h" + +#if defined (TARGET_NUCLEO_F030R8) || (TARGET_DISCO_F051R8) +__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_F103RB) || (TARGET_DISCO_F100RB) +__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 + +#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 + + + +#if defined (TARGET_NUCLEO_L152RE) +__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) { + switch (pin) { + // Channels 1 : PWMx/1 + case PA_6: case PB_4: case PB_12: case PB_13: case PC_6: + return &pwm->CCR1; + + // Channels 2 : PWMx/2 + case PA_1: case PA_7: case PB_3: case PB_5: case PB_14: case PB_7: case PC_7: + return &pwm->CCR2; + + // Channels 3 : PWMx/3 + case PA_2: case PB_0: case PB_8: case PB_10: case PC_8: + return &pwm->CCR3; + + // Channels 4 : PWMx/4 + case PA_3: case PB_1:case PB_9: case PB_11: case PC_9: + return &pwm->CCR4; + default: + /* NOP */ + break; + } + return NULL; +} +#endif + + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastPWM.h Sun May 08 14:39:57 2022 +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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastPWM_common.cpp Sun May 08 14:39:57 2022 +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; +} \ No newline at end of file