Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve STM32F4 Flash Behavior #17946

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions Marlin/src/HAL/STM32/Servo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
18 changes: 15 additions & 3 deletions Marlin/src/HAL/STM32/Servo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
31 changes: 27 additions & 4 deletions Marlin/src/HAL/STM32/eeprom_flash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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);
thinkyhead marked this conversation as resolved.
Show resolved Hide resolved
#endif

#if ENABLED(FLASH_EEPROM_LEVELING)

Expand All @@ -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());
Expand Down Expand Up @@ -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
}
Expand Down
9 changes: 9 additions & 0 deletions Marlin/src/HAL/STM32/inc/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -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