Skip to content

Commit

Permalink
PmwOut: Add methods to suspend and resume PWM
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hugueskamba committed Oct 17, 2019
1 parent 7eb8807 commit a9496ad
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 9 deletions.
27 changes: 27 additions & 0 deletions drivers/PwmOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,24 @@ class PwmOut {
*/
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()
*/
Expand Down Expand Up @@ -155,8 +173,17 @@ class PwmOut {
/** 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
};

Expand Down
64 changes: 55 additions & 9 deletions drivers/source/PwmOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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

0 comments on commit a9496ad

Please sign in to comment.