Description
On STM32G4, flash write and erase operations fail silently after
hardware timer peripherals (e.g. PWM for motor control) have been
initialized. The flash status register (FLASH->SR) retains sticky
error flags from motor_driver_init() → pwm_init(), and _wait_for_pending_operations()
does not clear them before proceeding.
Note: Other STM32 families are likely affected by the same issue but the current fix is scoped to STM32G4 only, as I don't have the hardware to test on other targets.
Steps to reproduce the issue
- Build and flash the following minimal test on an STM32G4-based
board (e.g. nucleo-g474re):
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "motor_driver.h"
#include "periph/flashpage.h"
#define TEST_PAGE (FLASHPAGE_NUMOF - 1)
#define TEST_PATTERN 0xBB
static const motor_driver_params_t motion_motors_params = {
.mode = MOTOR_DRIVER_1_DIR_BRAKE,
.pwm_dev = 0,
.pwm_mode = PWM_LEFT,
.pwm_frequency = 20000U,
.pwm_resolution = 500U,
.brake_inverted = true,
.enable_inverted = false,
.nb_motors = 2,
.motors = {
{ .pwm_channel = 0, .gpio_enable = GPIO_PIN(PORT_A, 10),
.gpio_dir0 = GPIO_PIN(PORT_C, 6),
.gpio_brake = GPIO_PIN(PORT_C, 8), .gpio_dir_reverse = 1 },
{ .pwm_channel = 1, .gpio_enable = GPIO_PIN(PORT_B, 1),
.gpio_dir0 = GPIO_PIN(PORT_B, 10),
.gpio_brake = GPIO_PIN(PORT_B, 2), .gpio_dir_reverse = 0 },
},
.motor_set_post_cb = NULL,
};
static motor_driver_t motor_driver;
static uint8_t buf[FLASHPAGE_SIZE]
__attribute__((aligned(FLASHPAGE_WRITE_BLOCK_ALIGNMENT)));
int main(void)
{
printf("FLASH->SR before init: 0x%08lX\n", (unsigned long)FLASH->SR);
motor_driver_init(&motor_driver, &motion_motors_params);
printf("FLASH->SR after PWM init: 0x%08lX\n", (unsigned long)FLASH->SR);
memset(buf, TEST_PATTERN, sizeof(buf));
int rc = flashpage_write_and_verify(TEST_PAGE, buf);
printf("write_and_verify: %s\n", (rc == FLASHPAGE_OK) ? "OK" : "FAIL");
printf("FLASH->SR after flash op: 0x%08lX\n", (unsigned long)FLASH->SR);
memset(buf, 0x00, sizeof(buf));
flashpage_read(TEST_PAGE, buf);
printf("first byte: 0x%02X (expected 0x%02X)\n", buf[0], TEST_PATTERN);
return 0;
}
- Without the fix:
FLASH->SR before init: 0x00000000
FLASH->SR after PWM init: 0x000000A0 <-- sticky error flags set
write_and_verify: FAIL
FLASH->SR after flash op: 0x000000A0 <-- flags still present
first byte: 0x00 (expected 0xBB) <-- stale data
- With the fix applied:
FLASH->SR before init: 0x00000000
FLASH->SR after PWM init: 0x000000A0 <-- flags set by PWM init
write_and_verify: OK
FLASH->SR after flash op: 0x00000000 <-- flags cleared
first byte: 0xBB (expected 0xBB) <-- OK
Expected results
Flash write/erase operations succeed and persist data correctly,
regardless of which peripherals were initialized beforehand.
Actual results
Flash operations fail and flashpage_write_and_verify correctly
reports the error. However, the failure is unrecoverable: FLASH->SR
contains stale error flags (e.g. PGAERR, PGSERR) set as a side
effect of timer peripheral initialization, and because these sticky
flags are never cleared, all subsequent flash operations
keep failing permanently
Versions
- Board: STM32G4-based (e.g. nucleo-g474re)
- RIOT: master
- Affected file:
cpu/stm32/periph/flash_common.c
Note: the example code was generated by an LLM (Claude). The English content of this issue was proofread/corrected by an LLM. The bug investigation and fix in the attached MR were done manually, inspired by the ST HAL implementation.
Description
On STM32G4, flash write and erase operations fail silently after
hardware timer peripherals (e.g. PWM for motor control) have been
initialized. The flash status register (
FLASH->SR) retains stickyerror flags from
motor_driver_init()→pwm_init(), and_wait_for_pending_operations()does not clear them before proceeding.
Steps to reproduce the issue
board (e.g. nucleo-g474re):
Expected results
Flash write/erase operations succeed and persist data correctly,
regardless of which peripherals were initialized beforehand.
Actual results
Flash operations fail and
flashpage_write_and_verifycorrectlyreports the error. However, the failure is unrecoverable: FLASH->SR
contains stale error flags (e.g. PGAERR, PGSERR) set as a side
effect of timer peripheral initialization, and because these sticky
flags are never cleared, all subsequent flash operations
keep failing permanently
Versions
cpu/stm32/periph/flash_common.c