stepper: Introduce and use gpio_out_toggle_noirq()

The gpio_out_toggle() function in the sam3x8e and stm32f1 code was
only valid if it was called with irqs disabled.

Commits 018c5daa and 9c52ad43 enabled the lcd code which called
gpio_out_toggle() with irqs enabled.  This could cause corruption of
the gpio state.

Introduce a gpio_out_toggle_noirq() function that will only be invoked
with irqs disabled, and fix gpio_out_toggle() on sam3x8e and stm32f1
so that it safe to call even if irqs are enabled.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-05-15 17:04:30 -04:00
parent 907cfb9105
commit 70068985a7
13 changed files with 46 additions and 10 deletions

View File

@ -63,11 +63,17 @@ fail:
} }
void void
gpio_out_toggle(struct gpio_out g) gpio_out_toggle_noirq(struct gpio_out g)
{ {
g.regs->in = g.bit; g.regs->in = g.bit;
} }
void
gpio_out_toggle(struct gpio_out g)
{
gpio_out_toggle_noirq(g);
}
void void
gpio_out_write(struct gpio_out g, uint8_t val) gpio_out_write(struct gpio_out g, uint8_t val)
{ {

View File

@ -9,6 +9,7 @@ struct gpio_out {
uint8_t bit : 8; uint8_t bit : 8;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);

View File

@ -7,6 +7,7 @@ struct gpio_out {
uint8_t pin; uint8_t pin;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);

View File

@ -115,7 +115,7 @@ static uint_fast8_t
soft_pwm_toggle_event(struct timer *timer) soft_pwm_toggle_event(struct timer *timer)
{ {
struct soft_pwm_s *s = container_of(timer, struct soft_pwm_s, timer); struct soft_pwm_s *s = container_of(timer, struct soft_pwm_s, timer);
gpio_out_toggle(s->pin); gpio_out_toggle_noirq(s->pin);
s->flags ^= SPF_ON; s->flags ^= SPF_ON;
uint32_t waketime = s->timer.waketime; uint32_t waketime = s->timer.waketime;
if (s->flags & SPF_ON) if (s->flags & SPF_ON)

View File

@ -7,6 +7,7 @@ struct gpio_out {
uint32_t pin; uint32_t pin;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);

View File

@ -104,11 +104,17 @@ fail:
} }
void void
gpio_out_toggle(struct gpio_out g) gpio_out_toggle_noirq(struct gpio_out g)
{ {
gpio_out_write(g, !(*g.reg & g.bit)); gpio_out_write(g, !(*g.reg & g.bit));
} }
void
gpio_out_toggle(struct gpio_out g)
{
gpio_out_toggle_noirq(g);
}
void void
gpio_out_write(struct gpio_out g, uint8_t val) gpio_out_write(struct gpio_out g, uint8_t val)
{ {

View File

@ -9,6 +9,7 @@ struct gpio_out {
uint32_t bit; uint32_t bit;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);

View File

@ -69,12 +69,20 @@ fail:
} }
void void
gpio_out_toggle(struct gpio_out g) gpio_out_toggle_noirq(struct gpio_out g)
{ {
Pio *regs = g.regs; Pio *regs = g.regs;
regs->PIO_ODSR ^= g.bit; regs->PIO_ODSR ^= g.bit;
} }
void
gpio_out_toggle(struct gpio_out g)
{
irqstatus_t flag = irq_save();
gpio_out_toggle_noirq(g);
irq_restore(flag);
}
void void
gpio_out_write(struct gpio_out g, uint8_t val) gpio_out_write(struct gpio_out g, uint8_t val)
{ {

View File

@ -10,6 +10,7 @@ struct gpio_out {
uint32_t bit; uint32_t bit;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);

View File

@ -9,6 +9,8 @@
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val) { struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val) {
return (struct gpio_out){.pin=pin}; return (struct gpio_out){.pin=pin};
} }
void gpio_out_toggle_noirq(struct gpio_out g) {
}
void gpio_out_toggle(struct gpio_out g) { void gpio_out_toggle(struct gpio_out g) {
} }
void gpio_out_write(struct gpio_out g, uint8_t val) { void gpio_out_write(struct gpio_out g, uint8_t val) {

View File

@ -88,7 +88,7 @@ stepper_load_next(struct stepper *s, uint32_t min_next_time)
} }
if (m->flags & MF_DIR) { if (m->flags & MF_DIR) {
s->position = -s->position + m->count; s->position = -s->position + m->count;
gpio_out_toggle(s->dir_pin); gpio_out_toggle_noirq(s->dir_pin);
} else { } else {
s->position += m->count; s->position += m->count;
} }
@ -108,24 +108,24 @@ stepper_event(struct timer *t)
if (CONFIG_NO_UNSTEP_DELAY) { if (CONFIG_NO_UNSTEP_DELAY) {
// On slower mcus it is possible to simply step and unstep in // On slower mcus it is possible to simply step and unstep in
// the same timer event. // the same timer event.
gpio_out_toggle(s->step_pin); gpio_out_toggle_noirq(s->step_pin);
uint16_t count = s->count - 1; uint16_t count = s->count - 1;
if (likely(count)) { if (likely(count)) {
s->count = count; s->count = count;
s->time.waketime += s->interval; s->time.waketime += s->interval;
gpio_out_toggle(s->step_pin); gpio_out_toggle_noirq(s->step_pin);
if (s->flags & SF_HAVE_ADD) if (s->flags & SF_HAVE_ADD)
s->interval += s->add; s->interval += s->add;
return SF_RESCHEDULE; return SF_RESCHEDULE;
} }
uint_fast8_t ret = stepper_load_next(s, 0); uint_fast8_t ret = stepper_load_next(s, 0);
gpio_out_toggle(s->step_pin); gpio_out_toggle_noirq(s->step_pin);
return ret; return ret;
} }
// On faster mcus, it is necessary to schedule the unstep event // On faster mcus, it is necessary to schedule the unstep event
uint32_t min_next_time = timer_read_time() + UNSTEP_TIME; uint32_t min_next_time = timer_read_time() + UNSTEP_TIME;
gpio_out_toggle(s->step_pin); gpio_out_toggle_noirq(s->step_pin);
s->count--; s->count--;
if (likely(s->count & 1)) if (likely(s->count & 1))
// Schedule unstep event // Schedule unstep event

View File

@ -72,11 +72,19 @@ fail:
} }
void void
gpio_out_toggle(struct gpio_out g) gpio_out_toggle_noirq(struct gpio_out g)
{ {
LL_GPIO_TogglePin(g.regs, g.bit); LL_GPIO_TogglePin(g.regs, g.bit);
} }
void
gpio_out_toggle(struct gpio_out g)
{
irqstatus_t flag = irq_save();
gpio_out_toggle_noirq(g);
irq_restore(flag);
}
void void
gpio_out_write(struct gpio_out g, uint8_t val) gpio_out_write(struct gpio_out g, uint8_t val)
{ {

View File

@ -11,6 +11,7 @@ struct gpio_out {
uint32_t bit; uint32_t bit;
}; };
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g); void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val); void gpio_out_write(struct gpio_out g, uint8_t val);