Make gpio write atomic

Unfortunately, there is no way to differentiate between an optimized gpio write (safe always on the atmega32u4) and an unoptimized write (read-modify-write, dangerous if any other pin on that Port is used in an ISR).
While very quickly polling the tmc registers, I noticed that the moving stepper would do some random extra steps. That can only be explained by the following sequence of actions:
- the spi code reads the PORT register
- ISR toggles the step line, changing the value in the PORT register
- the spi code writes the upated PORT back, resetting the step line to the old state

After making the writes atomic, the stepping issue disappeared and the driver checks also worked correctly
pull/212/head
Alex Voinea 2022-10-09 22:11:36 +02:00
parent b4e95f0c49
commit 5cf84ab98a
1 changed files with 7 additions and 4 deletions

View File

@ -1,6 +1,7 @@
/// @file gpio.h /// @file gpio.h
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <util/atomic.h>
#ifdef __AVR__ #ifdef __AVR__
#include <avr/io.h> #include <avr/io.h>
@ -53,10 +54,12 @@ struct GPIO_pin {
}; };
__attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) { __attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) {
if (level == Level::high) ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
portPin.port->PORTx |= (1 << portPin.pin); if (level == Level::high)
else portPin.port->PORTx |= (1 << portPin.pin);
portPin.port->PORTx &= ~(1 << portPin.pin); else
portPin.port->PORTx &= ~(1 << portPin.pin);
}
} }
__attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) { __attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) {