Improve STM32F4 Flash Behavior (#17946)
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user