Improve STM32F4 Flash Behavior (#17946)

This commit is contained in:
Jason Smith 2020-05-10 23:10:20 -07:00 committed by GitHub
parent 9d545f1231
commit 25aade1cf1
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 13 deletions

View file

@ -29,32 +29,62 @@
#include "Servo.h" #include "Servo.h"
static uint_fast8_t servoCount = 0; static uint_fast8_t servoCount = 0;
static libServo *servos[NUM_SERVOS] = {0};
constexpr millis_t servoDelay[] = SERVO_DELAY; constexpr millis_t servoDelay[] = SERVO_DELAY;
static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
libServo::libServo() libServo::libServo()
: delay(servoDelay[servoCount++]) : delay(servoDelay[servoCount]),
{} was_attached_before_pause(false),
value_before_pause(0)
{
servos[servoCount++] = this;
}
int8_t libServo::attach(const int pin) { int8_t libServo::attach(const int pin) {
if (servoCount >= MAX_SERVOS) return -1; if (servoCount >= MAX_SERVOS) return -1;
if (pin > 0) servo_pin = pin; if (pin > 0) servo_pin = pin;
return super::attach(servo_pin); return stm32_servo.attach(servo_pin);
} }
int8_t libServo::attach(const int pin, const int min, const int max) { int8_t libServo::attach(const int pin, const int min, const int max) {
if (servoCount >= MAX_SERVOS) return -1; if (servoCount >= MAX_SERVOS) return -1;
if (pin > 0) servo_pin = pin; if (pin > 0) servo_pin = pin;
return super::attach(servo_pin, min, max); return stm32_servo.attach(servo_pin, min, max);
} }
void libServo::move(const int value) { void libServo::move(const int value) {
if (attach(0) >= 0) { if (attach(0) >= 0) {
write(value); stm32_servo.write(value);
safe_delay(delay); safe_delay(delay);
TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach()); TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach());
} }
} }
#endif // HAS_SERVOS
void libServo::pause() {
was_attached_before_pause = stm32_servo.attached();
if (was_attached_before_pause) {
value_before_pause = stm32_servo.read();
stm32_servo.detach();
}
}
void libServo::resume() {
if (was_attached_before_pause) {
attach();
move(value_before_pause);
}
}
void libServo::pause_all_servos() {
for (auto& servo : servos)
if (servo) servo->pause();
}
void libServo::resume_all_servos() {
for (auto& servo : servos)
if (servo) servo->resume();
}
#endif // HAS_SERVOS
#endif // ARDUINO_ARCH_STM32 && !STM32GENERIC #endif // ARDUINO_ARCH_STM32 && !STM32GENERIC

View file

@ -27,15 +27,27 @@
#include "../../core/millis_t.h" #include "../../core/millis_t.h"
// Inherit and expand on the official library // Inherit and expand on the official library
class libServo : public Servo { class libServo {
public: public:
libServo(); libServo();
int8_t attach(const int pin); int8_t attach(const int pin = 0); // pin == 0 uses value from previous call
int8_t attach(const int pin, const int min, const int max); int8_t attach(const int pin, const int min, const int max);
void detach() { stm32_servo.detach(); }
int read() { return stm32_servo.read(); }
void move(const int value); void move(const int value);
void pause();
void resume();
static void pause_all_servos();
static void resume_all_servos();
private: private:
typedef Servo super; Servo stm32_servo;
int servo_pin = 0; int servo_pin = 0;
millis_t delay = 0; millis_t delay = 0;
bool was_attached_before_pause;
int value_before_pause;
}; };

View file

@ -28,10 +28,13 @@
#include "../shared/eeprom_api.h" #include "../shared/eeprom_api.h"
#if HAS_SERVOS
// Only STM32F4 can support wear leveling at this time #include "Servo.h"
#ifndef STM32F4xx #define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos()
#undef FLASH_EEPROM_LEVELING #define RESUME_SERVO_OUTPUT() libServo::resume_all_servos()
#else
#define PAUSE_SERVO_OUTPUT()
#define RESUME_SERVO_OUTPUT()
#endif #endif
/** /**
@ -139,6 +142,11 @@ bool PersistentStore::access_start() {
bool PersistentStore::access_finish() { bool PersistentStore::access_finish() {
if (eeprom_data_written) { if (eeprom_data_written) {
#ifdef STM32F4xx
// MCU may come up with flash error bits which prevent some flash operations.
// Clear flags prior to flash operations to prevent errors.
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#endif
#if ENABLED(FLASH_EEPROM_LEVELING) #if ENABLED(FLASH_EEPROM_LEVELING)
@ -159,7 +167,11 @@ bool PersistentStore::access_finish() {
current_slot = EEPROM_SLOTS - 1; current_slot = EEPROM_SLOTS - 1;
UNLOCK_FLASH(); UNLOCK_FLASH();
PAUSE_SERVO_OUTPUT();
DISABLE_ISRS();
status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError); status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
ENABLE_ISRS();
RESUME_SERVO_OUTPUT();
if (status != HAL_OK) { if (status != HAL_OK) {
DEBUG_ECHOLNPAIR("HAL_FLASHEx_Erase=", status); DEBUG_ECHOLNPAIR("HAL_FLASHEx_Erase=", status);
DEBUG_ECHOLNPAIR("GetError=", HAL_FLASH_GetError()); DEBUG_ECHOLNPAIR("GetError=", HAL_FLASH_GetError());
@ -204,7 +216,18 @@ bool PersistentStore::access_finish() {
return success; return success;
#else #else
// The following was written for the STM32F4 but may work with other MCUs as well.
// Most STM32F4 flash does not allow reading from flash during erase operations.
// This takes about a second on a STM32F407 with a 128kB sector used as EEPROM.
// Interrupts during this time can have unpredictable results, such as killing Servo
// output. Servo output still glitches with interrupts disabled, but recovers after the
// erase.
PAUSE_SERVO_OUTPUT();
DISABLE_ISRS();
eeprom_buffer_flush(); eeprom_buffer_flush();
ENABLE_ISRS();
RESUME_SERVO_OUTPUT();
eeprom_data_written = false; eeprom_data_written = false;
#endif #endif
} }

View file

@ -43,3 +43,12 @@
#endif #endif
#error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation."
#endif #endif
#if defined(STM32F4xx) && BOTH(PRINTCOUNTER, FLASH_EEPROM_EMULATION)
#warning "FLASH_EEPROM_EMULATION may cause long delays when writing and should not be used while printing."
#error "Disable PRINTCOUNTER or choose another EEPROM emulation."
#endif
#if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING)
#error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware."
#endif