PmwOut: Add methods to suspend and resume PWM

It is now possible to temporarily suspend PWM and safely preserve the duty
cycle set. This functionality is needed to allow a device to enter deep
sleep as a PWM instance prevents deep sleep in order for the timer it
relies on to run so its output can be modified. The duty cycle configuration
can be restored upon resuming from deep sleep.
pull/11641/head
Hugues Kamba 2019-10-08 12:36:47 +01:00
parent 7eb8807a76
commit a9496ad9f7
2 changed files with 82 additions and 9 deletions

View File

@ -118,6 +118,24 @@ public:
*/
void pulsewidth_us(int us);
/** Suspend PWM operation
*
* Control the PWM state. This is primarily intended
* for temporary power-saving; This call can
* allow pwm to be temporarily disabled to permit power saving without
* losing device state. The subsequent function call must be PwmOut::resume
* for PWM to resume; any other calls prior to resuming are undefined behavior.
*/
void suspend();
/** Resume PWM operation
*
* Control the PWM state. This is primarily intended
* to resume PWM operations after a previous PwmOut::suspend call;
* This call restores the device state prior to suspension.
*/
void resume();
/** A operator shorthand for write()
* \sa PwmOut::write()
*/
@ -155,8 +173,17 @@ protected:
/** Unlock deep sleep in case it is locked */
void unlock_deep_sleep();
/** Initialize this instance */
void init();
/** Power down this instance */
void deinit();
pwmout_t _pwm;
PinName _pin;
bool _deep_sleep_locked;
bool _initialized;
float _duty_cycle;
#endif
};

View File

@ -22,28 +22,28 @@
#include "platform/mbed_critical.h"
#include "platform/mbed_power_mgmt.h"
#include "platform/mbed_assert.h"
namespace mbed {
PwmOut::PwmOut(PinName pin) : _deep_sleep_locked(false)
PwmOut::PwmOut(PinName pin) :
_pin(pin),
_deep_sleep_locked(false),
_initialized(false),
_duty_cycle(0)
{
core_util_critical_section_enter();
pwmout_init(&_pwm, pin);
core_util_critical_section_exit();
PwmOut::init();
}
PwmOut::~PwmOut()
{
core_util_critical_section_enter();
pwmout_free(&_pwm);
unlock_deep_sleep();
core_util_critical_section_exit();
MBED_ASSERT(!_initialized);
PwmOut::deinit();
}
void PwmOut::write(float value)
{
core_util_critical_section_enter();
lock_deep_sleep();
pwmout_write(&_pwm, value);
core_util_critical_section_exit();
}
@ -98,6 +98,26 @@ void PwmOut::pulsewidth_us(int us)
core_util_critical_section_exit();
}
void PwmOut::suspend()
{
core_util_critical_section_enter();
if (_initialized) {
_duty_cycle = PwmOut::read();
PwmOut::deinit();
}
core_util_critical_section_exit();
}
void PwmOut::resume()
{
core_util_critical_section_enter();
if (!_initialized) {
PwmOut::init();
PwmOut::write(_duty_cycle);
}
core_util_critical_section_exit();
}
void PwmOut::lock_deep_sleep()
{
if (_deep_sleep_locked == false) {
@ -114,6 +134,32 @@ void PwmOut::unlock_deep_sleep()
}
}
void PwmOut::init()
{
core_util_critical_section_enter();
if (!_initialized) {
pwmout_init(&_pwm, _pin);
lock_deep_sleep();
_initialized = true;
}
core_util_critical_section_exit();
}
void PwmOut::deinit()
{
core_util_critical_section_enter();
if (_initialized) {
pwmout_free(&_pwm);
unlock_deep_sleep();
_initialized = false;
}
core_util_critical_section_exit();
}
} // namespace mbed
#endif // #if DEVICE_PWMOUT