Improve STM32F4 Flash Behavior (#17946)
This commit is contained in:
parent
9d545f1231
commit
25aade1cf1
4 changed files with 87 additions and 13 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in a new issue