From 25aade1cf13d6d8936859328addf21307b63d91e Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sun, 10 May 2020 23:10:20 -0700 Subject: [PATCH] Improve STM32F4 Flash Behavior (#17946) --- Marlin/src/HAL/STM32/Servo.cpp | 42 ++++++++++++++++++++++---- Marlin/src/HAL/STM32/Servo.h | 18 +++++++++-- Marlin/src/HAL/STM32/eeprom_flash.cpp | 31 ++++++++++++++++--- Marlin/src/HAL/STM32/inc/SanityCheck.h | 9 ++++++ 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/Marlin/src/HAL/STM32/Servo.cpp b/Marlin/src/HAL/STM32/Servo.cpp index d192da5d2..5fb8e3cd6 100644 --- a/Marlin/src/HAL/STM32/Servo.cpp +++ b/Marlin/src/HAL/STM32/Servo.cpp @@ -29,32 +29,62 @@ #include "Servo.h" static uint_fast8_t servoCount = 0; +static libServo *servos[NUM_SERVOS] = {0}; constexpr millis_t servoDelay[] = SERVO_DELAY; static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); 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) { if (servoCount >= MAX_SERVOS) return -1; 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) { if (servoCount >= MAX_SERVOS) return -1; 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) { if (attach(0) >= 0) { - write(value); + stm32_servo.write(value); safe_delay(delay); 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 diff --git a/Marlin/src/HAL/STM32/Servo.h b/Marlin/src/HAL/STM32/Servo.h index e8b3c4b10..50ae1a9b9 100644 --- a/Marlin/src/HAL/STM32/Servo.h +++ b/Marlin/src/HAL/STM32/Servo.h @@ -27,15 +27,27 @@ #include "../../core/millis_t.h" // Inherit and expand on the official library -class libServo : public Servo { +class libServo { public: 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); + void detach() { stm32_servo.detach(); } + int read() { return stm32_servo.read(); } void move(const int value); + + void pause(); + void resume(); + + static void pause_all_servos(); + static void resume_all_servos(); + private: - typedef Servo super; + Servo stm32_servo; int servo_pin = 0; millis_t delay = 0; + + bool was_attached_before_pause; + int value_before_pause; }; diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp index 49862957e..309c5eea9 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp @@ -28,10 +28,13 @@ #include "../shared/eeprom_api.h" - -// Only STM32F4 can support wear leveling at this time -#ifndef STM32F4xx - #undef FLASH_EEPROM_LEVELING +#if HAS_SERVOS + #include "Servo.h" + #define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos() + #define RESUME_SERVO_OUTPUT() libServo::resume_all_servos() +#else + #define PAUSE_SERVO_OUTPUT() + #define RESUME_SERVO_OUTPUT() #endif /** @@ -139,6 +142,11 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { 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) @@ -159,7 +167,11 @@ bool PersistentStore::access_finish() { current_slot = EEPROM_SLOTS - 1; UNLOCK_FLASH(); + PAUSE_SERVO_OUTPUT(); + DISABLE_ISRS(); status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError); + ENABLE_ISRS(); + RESUME_SERVO_OUTPUT(); if (status != HAL_OK) { DEBUG_ECHOLNPAIR("HAL_FLASHEx_Erase=", status); DEBUG_ECHOLNPAIR("GetError=", HAL_FLASH_GetError()); @@ -204,7 +216,18 @@ bool PersistentStore::access_finish() { return success; #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(); + ENABLE_ISRS(); + RESUME_SERVO_OUTPUT(); + eeprom_data_written = false; #endif } diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index 9cd8db81f..7734fc0e8 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -43,3 +43,12 @@ #endif #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." #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