Skip to content

Commit 01e730c

Browse files
committed
Merge pull request #1512 from neilt6/master
[LPC11U68, LPC1549] Fixed PwmOut SCT Bugs
2 parents d465cb5 + 132f1e7 commit 01e730c

File tree

2 files changed

+62
-42
lines changed

2 files changed

+62
-42
lines changed

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11U6X/pwmout_api.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
8383
// halt and clear the counter
8484
pwm->CTRL |= (1 << 2) | (1 << 3);
8585

86-
// System Clock -> us_ticker (1)MHz
87-
pwm->CTRL &= ~(0x7F << 5);
88-
pwm->CTRL |= (((SystemCoreClock/1000000 - 1) & 0x7F) << 5);
89-
9086
switch(pwm_mapped) {
9187
case SCT0_0:
9288
case SCT1_0:
@@ -117,14 +113,6 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
117113
// Event 1 : MATCH and MATCHSEL=1
118114
pwm->EV1_CTRL = (1 << 12) | (1 << 0);
119115
pwm->EV1_STATE = 0xFFFFFFFF;
120-
121-
// Match reload register
122-
pwm->MATCHREL0 = 20000; // 20ms
123-
pwm->MATCHREL1 = (pwm->MATCHREL0 / 4); // 50% duty
124-
125-
// unhalt the counter:
126-
// - clearing bit 2 of the CTRL register
127-
pwm->CTRL &= ~(1 << 2);
128116

129117
// default to 20ms: standard for servos, and fine for e.g. brightness control
130118
pwmout_period_ms(obj, 20);
@@ -140,18 +128,25 @@ void pwmout_free(pwmout_t* obj) {
140128
}
141129

142130
void pwmout_write(pwmout_t* obj, float value) {
131+
LPC_SCT0_Type* pwm = obj->pwm;
143132
if (value < 0.0f) {
144133
value = 0.0;
145134
} else if (value > 1.0f) {
146135
value = 1.0;
147136
}
148-
uint32_t t_on = (uint32_t)((float)(obj->pwm->MATCHREL0) * value);
149-
obj->pwm->MATCHREL1 = t_on;
137+
uint32_t t_on = (uint32_t)((float)(pwm->MATCHREL0 + 1) * value);
138+
if (t_on > 0) {
139+
pwm->MATCHREL1 = t_on - 1;
140+
pwm->CTRL &= ~(1 << 2);
141+
} else {
142+
pwm->CTRL |= (1 << 2) | (1 << 3);
143+
pwm->OUTPUT = 0x00000000;
144+
}
150145
}
151146

152147
float pwmout_read(pwmout_t* obj) {
153-
uint32_t t_off = obj->pwm->MATCHREL0;
154-
uint32_t t_on = obj->pwm->MATCHREL1;
148+
uint32_t t_off = obj->pwm->MATCHREL0 + 1;
149+
uint32_t t_on = obj->pwm->MATCHREL1 + 1;
155150
float v = (float)t_on/(float)t_off;
156151
return (v > 1.0f) ? (1.0f) : (v);
157152
}
@@ -166,11 +161,20 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
166161

167162
// Set the PWM period, keeping the duty cycle the same.
168163
void pwmout_period_us(pwmout_t* obj, int us) {
169-
uint32_t t_off = obj->pwm->MATCHREL0;
170-
uint32_t t_on = obj->pwm->MATCHREL1;
164+
LPC_SCT0_Type* pwm = obj->pwm;
165+
uint32_t t_off = pwm->MATCHREL0 + 1;
166+
uint32_t t_on = pwm->MATCHREL1 + 1;
171167
float v = (float)t_on/(float)t_off;
172-
obj->pwm->MATCHREL0 = (uint32_t)us;
173-
obj->pwm->MATCHREL1 = (uint32_t)((float)us * (float)v);
168+
uint32_t period_ticks = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000);
169+
uint32_t pulsewidth_ticks = period_ticks * v;
170+
pwm->MATCHREL0 = period_ticks - 1;
171+
if (pulsewidth_ticks > 0) {
172+
pwm->MATCHREL1 = pulsewidth_ticks - 1;
173+
pwm->CTRL &= ~(1 << 2);
174+
} else {
175+
pwm->CTRL |= (1 << 2) | (1 << 3);
176+
pwm->OUTPUT = 0x00000000;
177+
}
174178
}
175179

176180
void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
@@ -182,7 +186,14 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
182186
}
183187

184188
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
185-
obj->pwm->MATCHREL1 = (uint32_t)us;
189+
LPC_SCT0_Type* pwm = obj->pwm;
190+
if (us > 0) {
191+
pwm->MATCHREL1 = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000) - 1;
192+
pwm->CTRL &= ~(1 << 2);
193+
} else {
194+
pwm->CTRL |= (1 << 2) | (1 << 3);
195+
pwm->OUTPUT = 0x00000000;
196+
}
186197
}
187198

188199
#endif

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX/pwmout_api.c

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,6 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
8989
// halt and clear the counter
9090
pwm->CTRL |= (1 << 2) | (1 << 3);
9191

92-
// System Clock -> us_ticker (1)MHz
93-
pwm->CTRL &= ~(0x7F << 5);
94-
pwm->CTRL |= (((SystemCoreClock/1000000 - 1) & 0x7F) << 5);
95-
96-
// Match reload register
97-
pwm->MATCHREL0 = 20000; // 20ms
98-
pwm->MATCHREL1 = (pwm->MATCHREL0 / 4); // 50% duty
99-
10092
pwm->OUT0_SET = (1 << 0); // event 0
10193
pwm->OUT0_CLR = (1 << 1); // event 1
10294

@@ -105,10 +97,6 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
10597
pwm->EV1_CTRL = (1 << 12) | (1 << 0);
10698
pwm->EV1_STATE = 0xFFFFFFFF;
10799

108-
// unhalt the counter:
109-
// - clearing bit 2 of the CTRL register
110-
pwm->CTRL &= ~(1 << 2);
111-
112100
// default to 20ms: standard for servos, and fine for e.g. brightness control
113101
pwmout_period_ms(obj, 20);
114102
pwmout_write (obj, 0);
@@ -127,13 +115,19 @@ void pwmout_write(pwmout_t* obj, float value) {
127115
} else if (value > 1.0f) {
128116
value = 1.0;
129117
}
130-
uint32_t t_on = (uint32_t)((float)(pwm->MATCHREL0) * value);
131-
pwm->MATCHREL1 = t_on;
118+
uint32_t t_on = (uint32_t)((float)(pwm->MATCHREL0 + 1) * value);
119+
if (t_on > 0) {
120+
pwm->MATCHREL1 = t_on - 1;
121+
pwm->CTRL &= ~(1 << 2);
122+
} else {
123+
pwm->CTRL |= (1 << 2) | (1 << 3);
124+
pwm->OUTPUT = 0x00000000;
125+
}
132126
}
133127

134128
float pwmout_read(pwmout_t* obj) {
135-
uint32_t t_off = obj->pwm->MATCHREL0;
136-
uint32_t t_on = obj->pwm->MATCHREL1;
129+
uint32_t t_off = obj->pwm->MATCHREL0 + 1;
130+
uint32_t t_on = obj->pwm->MATCHREL1 + 1;
137131
float v = (float)t_on/(float)t_off;
138132
return (v > 1.0f) ? (1.0f) : (v);
139133
}
@@ -149,11 +143,19 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
149143
// Set the PWM period, keeping the duty cycle the same.
150144
void pwmout_period_us(pwmout_t* obj, int us) {
151145
LPC_SCT0_Type* pwm = obj->pwm;
152-
uint32_t t_off = pwm->MATCHREL0;
153-
uint32_t t_on = pwm->MATCHREL1;
146+
uint32_t t_off = pwm->MATCHREL0 + 1;
147+
uint32_t t_on = pwm->MATCHREL1 + 1;
154148
float v = (float)t_on/(float)t_off;
155-
pwm->MATCHREL0 = (uint32_t)us;
156-
pwm->MATCHREL1 = (uint32_t)((float)us * (float)v);
149+
uint32_t period_ticks = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000);
150+
uint32_t pulsewidth_ticks = period_ticks * v;
151+
pwm->MATCHREL0 = period_ticks - 1;
152+
if (pulsewidth_ticks > 0) {
153+
pwm->MATCHREL1 = pulsewidth_ticks - 1;
154+
pwm->CTRL &= ~(1 << 2);
155+
} else {
156+
pwm->CTRL |= (1 << 2) | (1 << 3);
157+
pwm->OUTPUT = 0x00000000;
158+
}
157159
}
158160

159161
void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
@@ -165,6 +167,13 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
165167
}
166168

167169
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
168-
obj->pwm->MATCHREL1 = (uint32_t)us;
170+
LPC_SCT0_Type* pwm = obj->pwm;
171+
if (us > 0) {
172+
pwm->MATCHREL1 = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000) - 1;
173+
pwm->CTRL &= ~(1 << 2);
174+
} else {
175+
pwm->CTRL |= (1 << 2) | (1 << 3);
176+
pwm->OUTPUT = 0x00000000;
177+
}
169178
}
170179

0 commit comments

Comments
 (0)