inported from local

Files at this revision

API Documentation at this revision

Comitter:
NYX
Date:
Mon Mar 16 06:36:03 2020 +0000
Commit message:
initial commit

Changed in this revision

Device/FastPWM_KLXX_K20D50M.cpp Show annotated file Show diff for this revision Revisions of this file
Device/FastPWM_KSDK.cpp Show annotated file Show diff for this revision Revisions of this file
Device/FastPWM_LPC11XX.cpp Show annotated file Show diff for this revision Revisions of this file
Device/FastPWM_LPC1768.cpp Show annotated file Show diff for this revision Revisions of this file
Device/FastPWM_STM_TIM.cpp Show annotated file Show diff for this revision Revisions of this file
Device/FastPWM_STM_TIM_PinOut.cpp Show annotated file Show diff for this revision Revisions of this file
FastPWM.h Show annotated file Show diff for this revision Revisions of this file
FastPWM_common.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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;
+}