Skip to content

[LPC824] Fixed PwmOut SCT Bugs #1585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 4, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC82X/pwmout_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ void pwmout_init(pwmout_t* obj, PinName pin)
pwm->CTRL &= ~(0x7F << 5);
pwm->CTRL |= (((SystemCoreClock/1000000 - 1) & 0x7F) << 5);

// Set event number
pwm->OUT[sct_n].SET = (1 << ((sct_n * 2) + 0));
pwm->OUT[sct_n].CLR = (1 << ((sct_n * 2) + 1));

Expand All @@ -99,10 +100,6 @@ void pwmout_init(pwmout_t* obj, PinName pin)
pwm->EVENT[(sct_n * 2) + 1].CTRL = (1 << 12) | ((sct_n * 2) + 1);
pwm->EVENT[(sct_n * 2) + 1].STATE = 0xFFFFFFFF;

// unhalt the counter:
// - clearing bit 2 of the CTRL register
pwm->CTRL &= ~(1 << 2);

// default to 20ms: standard for servos, and fine for e.g. brightness control
pwmout_period_ms(obj, 20);
pwmout_write (obj, 0);
Expand All @@ -120,16 +117,32 @@ void pwmout_write(pwmout_t* obj, float value)
if (value < 0.0f) {
value = 0.0;
} else if (value > 1.0f) {
value = 1.0;
value = 1.0f;
}
uint32_t t_on = (uint32_t)((float)(obj->pwm->MATCHREL[obj->pwm_ch * 2] + 1) * value);
if (t_on > 0) { // duty is not 0%
if (value != 1.0f) { // duty is not 100%
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = t_on - 1;
// unhalt the counter
obj->pwm->CTRL &= ~(1 << 2);
} else { // duty is 100%
// halt and clear the counter
obj->pwm->CTRL |= (1 << 2) | (1 << 3);
// output level tied to high
obj->pwm->OUTPUT |= (1 << obj->pwm_ch);
}
} else { // duty is 0%
// halt and clear the counter
obj->pwm->CTRL |= (1 << 2) | (1 << 3);
// output level tied to low
obj->pwm->OUTPUT &= ~(1 << obj->pwm_ch);
}
uint32_t t_on = (uint32_t)((float)(obj->pwm->MATCHREL[obj->pwm_ch * 2]) * value);
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = t_on;
}

float pwmout_read(pwmout_t* obj)
{
uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0];
uint32_t t_on = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1];
uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0] + 1;
uint32_t t_on = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] + 1;
float v = (float)t_on/(float)t_off;
return (v > 1.0f) ? (1.0f) : (v);
}
Expand All @@ -147,11 +160,21 @@ void pwmout_period_ms(pwmout_t* obj, int ms)
// Set the PWM period, keeping the duty cycle the same.
void pwmout_period_us(pwmout_t* obj, int us)
{
uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0];
uint32_t t_on = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1];
// The period are off by one for MATCHREL, so +1 to get actual value
uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0] + 1;
uint32_t t_on = obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] + 1;
float v = (float)t_on/(float)t_off;
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0] = (uint32_t)us;
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = (uint32_t)((float)us * (float)v);
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 0] = (uint32_t)us - 1;
if (us > 0) { // PWM period is not 0
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = (uint32_t)((float)us * (float)v) - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be beneficial to add comments why us > 0 , what it handles, or lines like below obj->pwm->CTRL |= (1 << 2) | (1 << 3); ? I without the reference manual have no clue what is going on. From the commit message, off by one errors are probably for lines 158 and 159, and then if (value != 1.0f) is probably for 100 percent error (also from the commit message).

// unhalt the counter
obj->pwm->CTRL &= ~(1 << 2);
} else { // PWM period is 0
// halt and clear the counter
obj->pwm->CTRL |= (1 << 2) | (1 << 3);
// output level tied to low
obj->pwm->OUTPUT &= ~(1 << obj->pwm_ch);
}
}

void pwmout_pulsewidth(pwmout_t* obj, float seconds)
Expand All @@ -166,7 +189,15 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms)

void pwmout_pulsewidth_us(pwmout_t* obj, int us)
{
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = (uint32_t)us;
if (us > 0) { // PWM peried is not 0
obj->pwm->MATCHREL[(obj->pwm_ch * 2) + 1] = (uint32_t)us - 1;
obj->pwm->CTRL &= ~(1 << 2);
} else { //PWM period is 0
// halt and clear the counter
obj->pwm->CTRL |= (1 << 2) | (1 << 3);
// output level tied to low
obj->pwm->OUTPUT &= ~(1 << obj->pwm_ch);
}
}

#endif