microbit: DynamicPwm fixes and additions
This commit introduces an initial draft fix for a bug where it would take two "setPeriods" for the PWM class to update to the expected value. This commit also adds three new methods to a DynamicPwm instance: * write() - which is a lightweight wrapper around PwmOut write, so that the value can be trapped. The trapping of the value is necessary for the bug fix. * getPeriod() - which returns the value of a static variable, containing the current period shared across the pwm bus. * getValue() - which returns a scaled value in the range 0-1024 representing the current duty cycle.
This commit is contained in:
parent
500f851991
commit
32c40cdc29
2 changed files with 186 additions and 21 deletions
104
inc/DynamicPwm.h
104
inc/DynamicPwm.h
|
@ -4,6 +4,7 @@
|
|||
#define MICROBIT_DYNAMIC_PWM_H
|
||||
|
||||
#define NO_PWMS 3
|
||||
#define MICROBIT_DEFAULT_PWM_PERIOD 20000
|
||||
|
||||
enum PwmPersistence
|
||||
{
|
||||
|
@ -14,27 +15,30 @@ enum PwmPersistence
|
|||
/**
|
||||
* Class definition for DynamicPwm.
|
||||
*
|
||||
* This class addresses a few issues found in the underlying libraries.
|
||||
* This class addresses a few issues found in the underlying libraries.
|
||||
* This provides the ability for a neat, clean swap between PWM channels.
|
||||
*/
|
||||
class DynamicPwm : public PwmOut
|
||||
{
|
||||
private:
|
||||
private:
|
||||
static DynamicPwm* pwms[NO_PWMS];
|
||||
static uint8_t lastUsed;
|
||||
static uint16_t sharedPeriod;
|
||||
uint8_t flags;
|
||||
|
||||
|
||||
float lastValue;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An internal constructor used when allocating a new DynamicPwm representation
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
*/
|
||||
DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Redirects the pwm channel to point at a different pin.
|
||||
* @param pin the new pin to direct PWM at.
|
||||
|
@ -46,12 +50,12 @@ class DynamicPwm : public PwmOut
|
|||
* @endcode
|
||||
*/
|
||||
void redirect(PinName pin);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a pointer to the first available free pwm channel - or the first one that can be reallocated.
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
* @param period the frequency of the pwm channel in us.
|
||||
*
|
||||
|
@ -61,7 +65,7 @@ class DynamicPwm : public PwmOut
|
|||
* @endcode
|
||||
*/
|
||||
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
|
||||
|
||||
|
||||
/**
|
||||
* Frees this DynamicPwm instance if the pointer is valid.
|
||||
*
|
||||
|
@ -72,31 +76,95 @@ class DynamicPwm : public PwmOut
|
|||
* @endcode
|
||||
*/
|
||||
void release();
|
||||
|
||||
|
||||
/**
|
||||
* A lightweight wrapper around the super class' write in order to capture the value
|
||||
*
|
||||
* @param value the duty cycle percentage in floating point format.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate();
|
||||
* pwm->write(0.5);
|
||||
* @endcode
|
||||
*/
|
||||
int write(float value);
|
||||
|
||||
/**
|
||||
* Retreives the pin name associated with this DynamicPwm instance.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPinName(); // equal to n
|
||||
* pwm->getPinName();
|
||||
* @endcode
|
||||
*/
|
||||
PinName getPinName();
|
||||
|
||||
|
||||
/**
|
||||
* Retreives the last value that has been written to this pwm channel.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getValue();
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module in microseconds.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getPeriodUs();
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module in milliseconds.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getPeriod();
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriodUs(1000); // period now is 1ms
|
||||
* @endcode
|
||||
*
|
||||
* @note The display uses the pwm module, if you change this value the display may flicker.
|
||||
*/
|
||||
void setPeriodUs(int period);
|
||||
|
||||
int setPeriodUs(int period);
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in milliseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriod(1); // period now is 1ms
|
||||
* @endcode
|
||||
*/
|
||||
int setPeriod(int period);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,8 @@ DynamicPwm* DynamicPwm::pwms[NO_PWMS] = { NULL };
|
|||
|
||||
uint8_t DynamicPwm::lastUsed = NO_PWMS+1; //set it to out of range i.e. 4 so we know it hasn't been used yet.
|
||||
|
||||
uint16_t DynamicPwm::sharedPeriod = 0; //set the shared period to an unknown state
|
||||
|
||||
/**
|
||||
* Reassigns an already operational PWM channel to the given pin
|
||||
* #HACK #BODGE # YUCK #MBED_SHOULD_DO_THIS
|
||||
|
@ -146,6 +148,30 @@ void DynamicPwm::release()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A lightweight wrapper around the super class' write in order to capture the value
|
||||
*
|
||||
* @param value the duty cycle percentage in floating point format.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate();
|
||||
* pwm->write(0.5);
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::write(float value){
|
||||
|
||||
if(value < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
PwmOut::write(value);
|
||||
lastValue = value;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the pin name associated with this DynamicPwm instance.
|
||||
*
|
||||
|
@ -160,18 +186,89 @@ PinName DynamicPwm::getPinName()
|
|||
return _pwm.pin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the last value that has been written to this DynamicPwm instance.
|
||||
* The value is in the range 0-1024
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getValue();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getValue()
|
||||
{
|
||||
return (float)lastValue * float(MICROBIT_PIN_MAX_OUTPUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getPeriodUs()
|
||||
{
|
||||
return sharedPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getPeriod()
|
||||
{
|
||||
return getPeriodUs() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriodUs(1000); // period now is 1ms
|
||||
* @endcode
|
||||
*
|
||||
* @note The display uses the pwm module, if you change this value the display may flicker.
|
||||
*/
|
||||
void DynamicPwm::setPeriodUs(int period)
|
||||
int DynamicPwm::setPeriodUs(int period)
|
||||
{
|
||||
if(period < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
//#HACK this forces mbed to update the pulse width calculation.
|
||||
period_us(period);
|
||||
write(lastValue);
|
||||
sharedPeriod = period;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriod(1); // period now is 1ms
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::setPeriod(int period)
|
||||
{
|
||||
return setPeriodUs(period * 1000);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue