Skip to content

Commit ec406b1

Browse files
committed
[LPC1347] Fix PwmOut prescaler for 16-bit timer
* Fix PwmOut prescaler for 16-bit timer * Remove static variable pwm_clock_mhz * Fix spike pulse issue when 0% duty
1 parent 196584d commit ec406b1

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

hal/targets/hal/TARGET_NXP/TARGET_LPC13XX/pwmout_api.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ static LPC_CTxxBx_Type *Timers[4] = {
6666
LPC_CT32B0, LPC_CT32B1
6767
};
6868

69-
static unsigned int pwm_clock_mhz;
70-
7169
void pwmout_init(pwmout_t* obj, PinName pin) {
7270
// determine the channel
7371
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
@@ -91,7 +89,12 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
9189
/* Reset Functionality on MR3 controlling the PWM period */
9290
timer->MCR = 1 << 10;
9391

94-
pwm_clock_mhz = SystemCoreClock / 1000000;
92+
if (timer == LPC_CT16B0 || timer == LPC_CT16B1) {
93+
/* Set 16-bit timer prescaler to avoid timer expire for default 20ms
94+
This can be also modified by user application, but the prescaler value
95+
might be trade-off to timer accuracy */
96+
timer->PR = 30;
97+
}
9598

9699
// default to 20ms: standard for servos, and fine for e.g. brightness control
97100
pwmout_period_ms(obj, 20);
@@ -116,14 +119,24 @@ void pwmout_write(pwmout_t* obj, float value) {
116119
LPC_CTxxBx_Type *timer = Timers[tid.timer];
117120
uint32_t t_off = timer->MR3 - (uint32_t)((float)(timer->MR3) * value);
118121

122+
// to avoid spike pulse when duty is 0%
123+
if (value == 0) {
124+
t_off++;
125+
}
126+
127+
timer->TCR = TCR_RESET;
119128
timer->MR[tid.mr] = t_off;
129+
timer->TCR = TCR_CNT_EN;
120130
}
121131

122132
float pwmout_read(pwmout_t* obj) {
123133
timer_mr tid = pwm_timer_map[obj->pwm];
124134
LPC_CTxxBx_Type *timer = Timers[tid.timer];
125135

126136
float v = (float)(timer->MR3 - timer->MR[tid.mr]) / (float)(timer->MR3);
137+
if (timer->MR[tid.mr] > timer->MR3) {
138+
v = 0.0f;
139+
}
127140
return (v > 1.0f) ? (1.0f) : (v);
128141
}
129142

@@ -138,11 +151,11 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
138151
// Set the PWM period, keeping the duty cycle the same.
139152
void pwmout_period_us(pwmout_t* obj, int us) {
140153
int i = 0;
141-
uint32_t period_ticks = pwm_clock_mhz * us;
142154

143155
timer_mr tid = pwm_timer_map[obj->pwm];
144156
LPC_CTxxBx_Type *timer = Timers[tid.timer];
145157
uint32_t old_period_ticks = timer->MR3;
158+
uint32_t period_ticks = (SystemCoreClock / 1000000 * us) / (timer->PR + 1);
146159

147160
timer->TCR = TCR_RESET;
148161
timer->MR3 = period_ticks;
@@ -166,9 +179,9 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
166179
}
167180

168181
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
169-
uint32_t t_on = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000);
170182
timer_mr tid = pwm_timer_map[obj->pwm];
171183
LPC_CTxxBx_Type *timer = Timers[tid.timer];
184+
uint32_t t_on = (uint32_t)((((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000) / (timer->PR + 1));
172185

173186
timer->TCR = TCR_RESET;
174187
if (t_on > timer->MR3) {

0 commit comments

Comments
 (0)