Skip to content

Commit

Permalink
Merge pull request ARMmbed#13492 from talorion/fix-PwmOut-resets-afte…
Browse files Browse the repository at this point in the history
…r-suspend

Fix pwm out resets after suspend
  • Loading branch information
0xc0170 committed Sep 10, 2020
2 parents a17a481 + b1eedc0 commit 468372e
Show file tree
Hide file tree
Showing 40 changed files with 1,263 additions and 573 deletions.
10 changes: 10 additions & 0 deletions UNITTESTS/stubs/pwmout_api_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ void pwmout_period_us(pwmout_t *obj, int us)
{
}

int pwmout_read_period_us(pwmout_t *obj)
{
return 0;
}

void pwmout_pulsewidth(pwmout_t *obj, float seconds)
{
}
Expand All @@ -63,4 +68,9 @@ void pwmout_pulsewidth_us(pwmout_t *obj, int us)
{
}

int pwmout_read_pulsewidth_us(pwmout_t *obj)
{
return 0;
}

#endif // DEVICE_PWMOUT
13 changes: 13 additions & 0 deletions drivers/include/drivers/PwmOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ class PwmOut {
*/
void period_us(int us);

/** Read the PWM period
* @returns
* The PWM period, specified in microseconds (int)
*/
int read_period_us();

/** Set the PWM pulsewidth, specified in seconds (float), keeping the period the same.
* @param seconds Change the pulse width of a PWM signal specified in seconds (float)
*/
Expand All @@ -125,6 +131,12 @@ class PwmOut {
*/
void pulsewidth_us(int us);

/** Read the PWM pulsewidth
* @returns
* The PWM pulsewith, specified in microseconds (int)
*/
int read_pulsewitdth_us();

/** Suspend PWM operation
*
* Control the PWM state. This is primarily intended
Expand Down Expand Up @@ -191,6 +203,7 @@ class PwmOut {
bool _deep_sleep_locked;
bool _initialized;
float _duty_cycle;
int _period_us;
#endif
};

Expand Down
21 changes: 20 additions & 1 deletion drivers/source/PwmOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ PwmOut::PwmOut(PinName pin) :
_pin(pin),
_deep_sleep_locked(false),
_initialized(false),
_duty_cycle(0)
_duty_cycle(0),
_period_us(0)
{
PwmOut::init();
}
Expand Down Expand Up @@ -83,6 +84,14 @@ void PwmOut::period_us(int us)
core_util_critical_section_exit();
}

int PwmOut::read_period_us()
{
core_util_critical_section_enter();
auto val = pwmout_read_period_us(&_pwm);
core_util_critical_section_exit();
return val;
}

void PwmOut::pulsewidth(float seconds)
{
core_util_critical_section_enter();
Expand All @@ -104,11 +113,20 @@ void PwmOut::pulsewidth_us(int us)
core_util_critical_section_exit();
}

int PwmOut::read_pulsewitdth_us()
{
core_util_critical_section_enter();
auto val = pwmout_read_pulsewidth_us(&_pwm);
core_util_critical_section_exit();
return val;
}

void PwmOut::suspend()
{
core_util_critical_section_enter();
if (_initialized) {
_duty_cycle = PwmOut::read();
_period_us = PwmOut::read_period_us();
PwmOut::deinit();
}
core_util_critical_section_exit();
Expand All @@ -120,6 +138,7 @@ void PwmOut::resume()
if (!_initialized) {
PwmOut::init();
PwmOut::write(_duty_cycle);
PwmOut::period_us(_period_us);
}
core_util_critical_section_exit();
}
Expand Down
16 changes: 16 additions & 0 deletions hal/include/hal/pwmout_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ typedef struct pwmout_s pwmout_t;
* * ::pwmout_period sets the PWM period specified in seconds, keeping the duty cycle the same
* * ::pwmout_period_ms sets the PWM period specified in miliseconds, keeping the duty cycle the same
* * ::pwmout_period_us sets the PWM period specified in microseconds, keeping the duty cycle the same
* * ::pwmout_read_period_us reads the PWM period specified in microseconds
* * ::pwmout_pulsewidth sets the PWM pulsewidth specified in seconds, keeping the period the same
* * ::pwmout_pulsewidth_ms sets the PWM pulsewidth specified in miliseconds, keeping the period the same
* * ::pwmout_pulsewidth_us sets the PWM pulsewidth specified in microseconds, keeping the period the same
* * ::pwmout_read_pulsewidth_us read the PWM pulsewidth specified in microseconds
* * The accuracy of the PWM is +/- 10%
* * The PWM operations ::pwmout_write, ::pwmout_read, ::pwmout_read, ::pwmout_period_ms, ::pwmout_period_us
* ::pwmout_pulsewidth, ::pwmout_pulsewidth_ms, ::pwmout_pulsewidth_us take less than 20us to complete
Expand Down Expand Up @@ -125,6 +127,13 @@ void pwmout_period_ms(pwmout_t *obj, int ms);
*/
void pwmout_period_us(pwmout_t *obj, int us);

/** Read the PWM period specified in microseconds
*
* @param obj The pwmout object
* @return A int output period
*/
int pwmout_read_period_us(pwmout_t *obj);

/** Set the PWM pulsewidth specified in seconds, keeping the period the same.
*
* @param obj The pwmout object
Expand All @@ -146,6 +155,13 @@ void pwmout_pulsewidth_ms(pwmout_t *obj, int ms);
*/
void pwmout_pulsewidth_us(pwmout_t *obj, int us);

/** Read the PWM pulsewidth specified in microseconds
*
* @param obj The pwmout object
* @return A int output pulsewitdth
*/
int pwmout_read_pulsewidth_us(pwmout_t *obj);

/** Get the pins that support PWM
*
* Return a PinMap array of pins that support PWM.
Expand Down
10 changes: 10 additions & 0 deletions targets/TARGET_Cypress/TARGET_PSOC6/cy_pwmout_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ void pwmout_period_us(pwmout_t *obj, int us)
}
}

int pwmout_read_period_us(pwmout_t *obj)
{
return obj->period_us;
}

void pwmout_pulsewidth(pwmout_t *obj, float seconds)
{
pwmout_pulsewidth_us(obj, (int)(seconds * CY_US_PER_SECOND));
Expand All @@ -92,6 +97,11 @@ void pwmout_pulsewidth_us(pwmout_t *obj, int us)
}
}

int pwmout_read_pulsewidth_us(pwmout_t *obj)
{
return obj->width_us;
}

const PinMap *pwmout_pinmap(void)
{
return PinMap_PWM_OUT;
Expand Down
62 changes: 45 additions & 17 deletions targets/TARGET_Freescale/TARGET_K20XX/pwmout_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

static float pwm_clock = 0;

void pwmout_init(pwmout_t* obj, PinName pin) {
void pwmout_init(pwmout_t *obj, PinName pin)
{
// determine the channel
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
MBED_ASSERT(pwm != (PWMName)NC);
Expand All @@ -36,8 +37,9 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
while (clkval > 1) {
clkdiv++;
clkval /= 2.0;
if (clkdiv == 7)
if (clkdiv == 7) {
break;
}
}

pwm_clock = clkval;
Expand All @@ -53,7 +55,7 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
ftm->MODE = FTM_MODE_FTMEN_MASK;
ftm->SYNC = FTM_SYNC_CNTMIN_MASK;
ftm->SYNCONF = FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWWRBUF_MASK;

//Without SYNCEN set CnV does not seem to update
ftm->COMBINE = FTM_COMBINE_SYNCEN0_MASK | FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_SYNCEN2_MASK | FTM_COMBINE_SYNCEN3_MASK;

Expand All @@ -64,60 +66,86 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
// default to 20ms: standard for servos, and fine for e.g. brightness control
pwmout_period_ms(obj, 20);
pwmout_write(obj, 0.0);

// Wire pinout
pinmap_pinout(pin, PinMap_PWM);
}

void pwmout_free(pwmout_t* obj) {}
void pwmout_free(pwmout_t *obj) {}

void pwmout_write(pwmout_t* obj, float value) {
void pwmout_write(pwmout_t *obj, float value)
{
if (value < 0.0) {
value = 0.0;
} else if (value > 1.0) {
value = 1.0;
}
while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK);

while (*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
*obj->CnV = (uint32_t)((float)(*obj->MOD + 1) * value);
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
}

float pwmout_read(pwmout_t* obj) {
while(*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
float pwmout_read(pwmout_t *obj)
{
while (*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
float v = (float)(*obj->CnV) / (float)(*obj->MOD + 1);
return (v > 1.0) ? (1.0) : (v);
}

void pwmout_period(pwmout_t* obj, float seconds) {
void pwmout_period(pwmout_t *obj, float seconds)
{
pwmout_period_us(obj, seconds * 1000000.0f);
}

void pwmout_period_ms(pwmout_t* obj, int ms) {
void pwmout_period_ms(pwmout_t *obj, int ms)
{
pwmout_period_us(obj, ms * 1000);
}

// Set the PWM period, keeping the duty cycle the same.
void pwmout_period_us(pwmout_t* obj, int us) {
void pwmout_period_us(pwmout_t *obj, int us)
{
float dc = pwmout_read(obj);
*obj->MOD = (uint32_t)(pwm_clock * (float)us) - 1;
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
pwmout_write(obj, dc);
}

void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
int pwmout_read_period_us(pwmout_t *obj)
{
uint32_t pwm_period = 0;
if (pwm_clock > 0) {
pwm_period = ((*obj->MOD) + 1) / pwm_clock;
}
return pwm_period;
}

void pwmout_pulsewidth(pwmout_t *obj, float seconds)
{
pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
}

void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
{
pwmout_pulsewidth_us(obj, ms * 1000);
}

void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
{
*obj->CnV = (uint32_t)(pwm_clock * (float)us);
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
}

int pwmout_read_pulsewidth_us(pwmout_t *obj)
{
uint32_t pwm_pulsewidth = 0;
if (pwm_clock > 0) {
pwm_pulsewidth = (*obj->CnV) / pwm_clock;
}
return pwm_pulsewidth;
}

const PinMap *pwmout_pinmap()
{
return PinMap_PWM;
Expand Down
Loading

0 comments on commit 468372e

Please sign in to comment.