Library that allows for higher resolution and speed than standard mbed PWM library. Based on FastPWM without floating point calculation in most functions

Fork of FastPWM by Erik -

Library that allows faster and/or higher resolution PWM output.

This library is based original on FastPWM by Erik Olieman but without floating point (double) calculation in each call of pulsewidth_xx. This change was nessecary to get a performant motion controller.

Library can directly replace standard mbed PWM library. Only limitation is that the maximum PWM period is four times shorter The maximum achievable period is roughly 40 seconds, I dont think that should be a problem. Do take into account all PWM objects (based on defailt PWM lib) will run four times faster than default.

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.

Using this library for a RC servo the resolution of steps (min to max) is increased from 1000 to 96000.

This library can be also used as a analoge output (with external low-pass filter) with a frequency of e.g. 20kHz and a resolution 4800 steps (similar to a 12 bit DAC) instead of 50 steps (similar to a 5 bit DAC) on original PWM lib.

In your program you can define F_CLK if you use a different clock frequency than the default one.

Only works on LPC1768 for now. If you want support for the other one, send a PM and I will have a look, but I cannot even compile for it.

Files at this revision

API Documentation at this revision

Comitter:
jocis
Date:
Thu May 23 10:39:29 2013 +0000
Parent:
3:3094d3806cfc
Commit message:
based on FastPWM, changed double calculation to int calculation for most functions

Changed in this revision

FastPWM.cpp Show diff for this revision Revisions of this file
FastPWM.h Show diff for this revision Revisions of this file
HighPWM.cpp Show annotated file Show diff for this revision Revisions of this file
HighPWM.h Show annotated file Show diff for this revision Revisions of this file
diff -r 3094d3806cfc -r 923b54e7c2c1 FastPWM.cpp
--- a/FastPWM.cpp	Wed Jul 25 07:14:39 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#include "FastPWM.h"
-
-FastPWM::FastPWM(PinName pin) : PWMObject(pin){
-    //Set clock source
-    LPC_SC->PCLKSEL0|=1<<12;
-    
-    _duty=0;
-    _period=0.02;
-    if (pin==p26||pin==LED1) {
-        PWMUnit=1;
-        MR=&LPC_PWM1->MR1;
-        }
-    else if (pin==p25||pin==LED2){
-        PWMUnit=2;
-        MR=&LPC_PWM1->MR2;
-        }
-    else if (pin==p24||pin==LED3){
-        PWMUnit=3;
-        MR=&LPC_PWM1->MR3;
-        }
-    else if (pin==p23||pin==LED4){
-        PWMUnit=4;
-        MR=&LPC_PWM1->MR4;
-        }
-    else if (pin==p22){
-        PWMUnit=5;
-        MR=&LPC_PWM1->MR5;
-        }
-    else if (pin==p21){
-        PWMUnit=6;
-        MR=&LPC_PWM1->MR6;
-        }
-    else
-        error("No hardware PWM pin\n\r");
-    
-    period(_period);
-}
-
-void FastPWM::period(double seconds) {
-    LPC_PWM1->MR0 = (unsigned int) (seconds * (double)F_CLK);
-    LPC_PWM1->LER |= 1;
-    _period = seconds;
-    pulsewidth(_duty*_period);
-}
-
-void FastPWM::period_ms(int ms) {
-    period((double)ms/1000.0);
-}
-
-void FastPWM::period_us(int us) {
-    period((double)us/1000000.0);
-}
-
-void FastPWM::period_us(double us) {
-    period(us/1000000.0);
-}
-
-void FastPWM::pulsewidth(double seconds) {
-    *MR=(unsigned int) (seconds * (double)F_CLK);
-    LPC_PWM1->LER |= 1<<PWMUnit;
-    _duty=seconds/_period;
-}
-
-void FastPWM::pulsewidth_ms(int ms) {
-    pulsewidth((double)ms/1000.0);
-}
-
-void FastPWM::pulsewidth_us(int us) {
-    pulsewidth((double)us/1000000.0);
-}
-
-void FastPWM::pulsewidth_us(double us) {
-    pulsewidth(us/1000000.0);
-}
-
-void FastPWM::write(double duty) {
-    _duty=duty;
-    pulsewidth(duty*_period);
-}
-
-double FastPWM::read( void ) {
-    return _duty;
-    }
-    
-FastPWM & FastPWM::operator= (double value) {
-    write(value);
-    return(*this);
-    }
-    
-FastPWM::operator double() {
-    return _duty;
-}
-    
\ No newline at end of file
diff -r 3094d3806cfc -r 923b54e7c2c1 FastPWM.h
--- a/FastPWM.h	Wed Jul 25 07:14:39 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
-    .---.           _....._
-   /  p  `\     .-""`:     :`"-.
-   |__   - |  ,'     .     '    ',
-    ._>    \ /:      :     ;      :,
-     '-.    '\`.     .     :     '  \
-        `.   | .'._.' '._.' '._.'.  |
-          `;-\.   :     :     '   '/,__,
-          .-'`'._ '     .     : _.'.__.'
-         ((((-'/ `";--..:..--;"` \
-             .'   /           \   \
-       jgs  ((((-'           ((((-'
-       
-Yeah ASCII art turtle more fun than copyright stuff
-*/
-
-
-#include "mbed.h"
-
-
-#ifndef FASTPWM_H
-#define FASTPWM_H
-
-#ifndef F_CLK
-#define F_CLK   96000000
-#endif
-
-/** Library that allows faster and/or higher resolution PWM output
-  *
-  * Library can directly replace standard mbed PWM library. Only limitation is that the maximum PWM period is four times shorter
-  * The maximum achievable period is roughly 40 seconds, I dont think that should be a problem.
-  * Do take into account all PWM objects will run four times faster than default.
-  *
-  * 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.
-  *
-  * In your program you can define F_CLK if you use a different clock frequency than the default one. 
-  *
-  * Only works on LPC1768 for now. If you want support for the other one, send a PM and I will have a look, but I cannot even compile for it.
-  */
-class FastPWM {
-public:
-    /**
-    * Create a FastPWM object connected to the specified pin
-    *
-    * @param pin - PWM pin to connect to
-    */
-    FastPWM(PinName pin);
-    
-    /**
-    * Set the PWM period, specified in seconds (double), keeping the duty cycle the same.
-    */
-    void period(double seconds);
-    
-    /**
-    * Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same.
-    */
-    void period_ms(int ms);
-    
-    /**
-    * Set the PWM period, specified in micro-seconds (int), keeping the duty cycle the same.
-    */
-    void period_us(int us);
-    
-    /**
-    * Set the PWM period, specified in micro-seconds (double), keeping the duty cycle the same.
-    */
-    void period_us(double us);
-    
-    /**
-    * 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 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();
-    
-private:
-    PwmOut PWMObject;
-    double _duty;
-    double _period;
-    unsigned int PWMUnit;
-    
-    __IO uint32_t *MR;
-
-};
-#endif
\ No newline at end of file
diff -r 3094d3806cfc -r 923b54e7c2c1 HighPWM.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighPWM.cpp	Thu May 23 10:39:29 2013 +0000
@@ -0,0 +1,123 @@
+#include "HighPWM.h"
+
+HighPWM::HighPWM(PinName pin) : PWMObject(pin){
+    //Set clock source to CPU clock (without devider)
+    LPC_SC->PCLKSEL0 |= 1<<12;
+    
+    _pulsewidth = 0;
+    _period = 0;
+    
+    if (pin==p26||pin==LED1) {
+        PWMUnit=1;
+        MR=&LPC_PWM1->MR1;
+        }
+    else if (pin==p25||pin==LED2){
+        PWMUnit=2;
+        MR=&LPC_PWM1->MR2;
+        }
+    else if (pin==p24||pin==LED3){
+        PWMUnit=3;
+        MR=&LPC_PWM1->MR3;
+        }
+    else if (pin==p23||pin==LED4){
+        PWMUnit=4;
+        MR=&LPC_PWM1->MR4;
+        }
+    else if (pin==p22){
+        PWMUnit=5;
+        MR=&LPC_PWM1->MR5;
+        }
+    else if (pin==p21){
+        PWMUnit=6;
+        MR=&LPC_PWM1->MR6;
+        }
+    else
+        error("Invalid hardware PWM pin\n\r");
+    
+    frequency(10000);   // 10kHz
+}
+
+void HighPWM::frequency(double frq) 
+{
+    if ( frq>0.0 )
+        period(1.0/frq);
+}
+
+void HighPWM::period(double seconds) 
+{
+    period_ticks((unsigned int)(seconds*s_2_F_CLK+0.5));
+}
+
+void HighPWM::period_us(double us) 
+{
+    period_ticks((unsigned int)(us*us_2_F_CLK+0.5));
+}
+
+void HighPWM::period_ms(unsigned int ms) 
+{
+    period_ticks(ms*ms_2_F_CLK);
+}
+
+void HighPWM::period_us(unsigned int us) 
+{
+    period_ticks(us*us_2_F_CLK);
+}
+
+void HighPWM::period_ticks(unsigned int ticks) 
+{
+    double duty = (double)_pulsewidth/(double)_period;
+    
+    LPC_PWM1->MR0 = ticks;
+    LPC_PWM1->LER |= 1;
+    _period = ticks;
+    pulsewidth_ticks((int)(duty*(double)_period+0.5));
+}
+
+void HighPWM::pulsewidth(double seconds) 
+{
+    pulsewidth_ticks((unsigned int)(seconds*s_2_F_CLK+0.5));
+}
+
+void HighPWM::pulsewidth_us(double us) 
+{
+    pulsewidth_ticks((unsigned int)(us*us_2_F_CLK+0.5));
+}
+
+void HighPWM::pulsewidth_ms(unsigned int ms) 
+{
+    pulsewidth_ticks(ms*ms_2_F_CLK);
+}
+
+void HighPWM::pulsewidth_us(unsigned int us) 
+{
+    pulsewidth_ticks(us*us_2_F_CLK);
+}
+
+void HighPWM::pulsewidth_ticks(unsigned int ticks) 
+{
+    *MR = ticks;
+    LPC_PWM1->LER |= 1<<PWMUnit;
+    _pulsewidth = ticks;
+}
+
+void HighPWM::write(double duty) 
+{
+    pulsewidth_ticks((int)(duty*(double)_period+0.5));
+}
+
+double HighPWM::read( void ) 
+{
+    return (double)_pulsewidth/(double)_period;
+}
+    
+HighPWM & HighPWM::operator= (double value) 
+{
+    write(value);
+    return(*this);
+}
+    
+HighPWM::operator double() 
+{
+    return read();
+}
+    
\ No newline at end of file
diff -r 3094d3806cfc -r 923b54e7c2c1 HighPWM.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighPWM.h	Thu May 23 10:39:29 2013 +0000
@@ -0,0 +1,132 @@
+#ifndef HighPWM_H
+#define HighPWM_H
+
+#include "mbed.h"
+
+#ifndef F_CLK
+#define F_CLK   96000000
+#endif
+
+#define us_2_F_CLK (F_CLK/1000000)
+#define ms_2_F_CLK (F_CLK/1000)
+#define s_2_F_CLK (F_CLK)
+
+/** Library that allows faster and/or higher resolution PWM output
+  *
+  * This library is based original on FastPWM by Erik Olieman but without floating point (double) calculation in each call of pulsewidth_xx.
+  * This change was nessecary to get a performant motion controller.
+  *
+  * Library can directly replace standard mbed PWM library. Only limitation is that the maximum PWM period is four times shorter
+  * The maximum achievable period is roughly 40 seconds, I dont think that should be a problem.
+  * Do take into account all PWM objects (based on defailt PWM lib) will run four times faster than default.
+  *
+  * 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.
+  *
+  * Using this library for a RC servo the resolution of steps (min to max) is increased from 1000 to 96000.
+  *
+  * This library can be also used as a analoge output (with external low-pass filter) with a frequency of e.g. 20kHz and a resolution 4800 steps (similar to a 12 bit DAC) instead of 50 steps (similar to a 5 bit DAC) on original PWM lib.
+  *
+  * In your program you can define F_CLK if you use a different clock frequency than the default one. 
+  *
+  * Only works on LPC1768 for now. If you want support for the other one, send a PM and I will have a look, but I cannot even compile for it.
+  */
+class HighPWM {
+public:
+    /**
+    * Create a HighPWM object connected to the specified pin
+    *
+    * @param pin - PWM pin to connect to
+    */
+    HighPWM(PinName pin);
+    
+    /**
+    * Set the PWM frequency, specified in Hz (double), keeping the duty cycle the same.
+    */
+    void frequency(double frq);
+    
+    /**
+    * Set the PWM period, specified in seconds (double), keeping the duty cycle the same.
+    */
+    void period(double seconds);
+    
+    /**
+    * Set the PWM period, specified in micro-seconds (double), keeping the duty cycle the same.
+    */
+    void period_us(double us);
+    
+    /**
+    * Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same.
+    */
+    void period_ms(unsigned int ms);
+    
+    /**
+    * Set the PWM period, specified in micro-seconds (int), keeping the duty cycle the same.
+    */
+    void period_us(unsigned int us);
+    
+    /**
+    * Set the PWM period, specified in cpu ticks based on 96MHz (int), keeping the duty cycle the same.
+    */
+    void period_ticks(unsigned int ticks);
+    
+    /**
+    * Set the PWM pulsewidth, specified in seconds (double), keeping the period the same.
+    */
+    void pulsewidth(double seconds);
+    
+    /**
+    * Set the PWM pulsewidth, specified in micro seconds (double), keeping the period the same.
+    */
+    void pulsewidth_us(double us);
+    
+    /**
+    * Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same.
+    */
+    void pulsewidth_ms(unsigned int ms);
+    
+    /**
+    * Set the PWM pulsewidth, specified in micro-seconds (int), keeping the period the same.
+    */
+    void pulsewidth_us(unsigned int us);
+    
+    /**
+    * Set the PWM pulsewidth, specified in cpu ticks based on 96MHz (int), keeping the period the same.
+    */
+    void pulsewidth_ticks(unsigned int 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()
+    */
+    HighPWM& operator= (double value);
+    
+    /**
+    * An operator shorthand for read()
+    */
+    operator double();
+    
+private:
+    PwmOut PWMObject;
+    //double _duty;
+    int _period;
+    int _pulsewidth;
+    unsigned int PWMUnit;
+    
+    __IO uint32_t *MR;
+
+};
+#endif
\ No newline at end of file