Skip to content

drivers: STM32 async flash erase and write#93173

Open
jpowen898 wants to merge 1 commit intozephyrproject-rtos:mainfrom
jpowen898:main
Open

drivers: STM32 async flash erase and write#93173
jpowen898 wants to merge 1 commit intozephyrproject-rtos:mainfrom
jpowen898:main

Conversation

@jpowen898
Copy link

  • Implemented async flash erase and writes using the STM32 hal HAL_FLASHEx_Erase_IT() and HAL_FLASH_Program_IT() functions with their associated interrupt handler.
  • I only implemented this for the h7, l4, and f4 stm32 families because that is the hardware I had available to test on.
  • Async flash transactions can be enabled using the FLASH_STM32_ASYNC config option.
  • Async transactions are implemented using a semaphore which blocks while waiting for the flash IRQ to indicate the end of a flash transaction. This allows other threads to take action while flash erase and write actions are taking place.
@github-actions
Copy link

Hello @jpowen898, and thank you very much for your first pull request to the Zephyr project!
Our Continuous Integration pipeline will execute a series of checks on your Pull Request commit messages and code, and you are expected to address any failures by updating the PR. Please take a look at our commit message guidelines to find out how to format your commit messages, and at our contribution workflow to understand how to update your Pull Request. If you haven't already, please make sure to review the project's Contributor Expectations and update (by amending and force-pushing the commits) your pull request if necessary.
If you are stuck or need help please join us on Discord and ask your question there. Additionally, you can escalate the review when applicable. 😊

@jpowen898 jpowen898 force-pushed the main branch 2 times, most recently from c34e153 to ae67109 Compare July 16, 2025 14:49
@jpowen898
Copy link
Author

@nordicjm Thanks for the feedback. I made all the requested changes, let me know if there is anything else.

@zephyrbot zephyrbot requested a review from etienne-lms July 17, 2025 16:05
@jpowen898 jpowen898 force-pushed the main branch 2 times, most recently from 9129568 to b5d3812 Compare July 17, 2025 16:13
@jpowen898 jpowen898 requested a review from nordicjm July 17, 2025 16:16
Copy link
Contributor

@etienne-lms etienne-lms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor issues, otherwise LGTM.

JarmouniA
JarmouniA previously approved these changes Sep 16, 2025
Comment on lines +111 to +112
select USE_STM32_HAL_FLASH
select USE_STM32_HAL_FLASH_EX
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the feature really that difficult to implement w/o the HAL?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not exactly sure what you mean. But to explain this a little better, when you attempt to do a write/erase to internal flash on the stm32's the current implementation is full blocking meaning it has some while(1) loops which block all threads (not just the current thread) until the flash operation is complete. To erase a single flash sector (128KB) on the stm32h7 platform typically takes ~1.1 seconds, so all threads end up getting starved for that period of time which is too long for my application.

My fix for this is to use the stm hal to start the flash write/erase, then block with a semaphore (so not all threads get starved) and then the semaphore get's free-ed when a the STM flash hw interrupt gets called. So maybe calling this an ASYNC flash opperation is misleading. The flash_write() and flash_erase() functions still block for the same amount of time and complete the same tasks before returning as they did previously, only now they allow the schedule to run other tasks.

Comment on lines +114 to +115
Use asynchronous flash operations to unblock other threads while
flash is busy.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that once this option is enabled, only asynchronous operations are enabled. This is a big change from the old behavior (e.g., not isr-ok) so it should be documented.

Copy link
Author

@jpowen898 jpowen898 Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yes when you enable this all operations are done in "asynchronous" mode, I am happy to document that if you would like, just point me to the correct spot to do that. But to be clear the flash_erase() and flash_write() functions complete the same high level tasks as they did before and return in the same amount of time so it should be pretty transperent to the user of the function if it is in async mode or not. Also those functions were never ISR safe because flash_erase() takes ~1.1s to return (longer if you erase multiple sectors at a time) and flash_write() takes ~3.5ms to return (depending on how much you are writting at a time).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy to document that if you would like, just point me to the correct spot to do that.

In the Kconfig help text itself

Also those functions were never ISR safe because flash_erase() takes ~1.1s to return (longer if you erase multiple sectors at a time) and flash_write() takes ~3.5ms to return (depending on how much you are writting at a time).

isr-ok-ness is unrelated to how long a function may take to execute (otherwise the ENTROPY_BUSYWAIT flag would not exist)

Added optional use of the stm32 hal async flash write and erase
capabilities on the l4, f4, and h7 soc families. It is implemented
using semaphores to allow for other threads to take action during
the erase/write actions. This feature is disabled by default and
can be optionally enabled using the FLASH_STM32_ASYNC config option.

Signed-off-by: Parker Owen <jpowen898@gmail.com>
Copy link
Contributor

@etienne-lms etienne-lms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit message says

This feature is disabled by default and
can be optionally enabled using the FLASH_STM32_ASYNC config option

Actually the feature is default enabled for drivers that support async operations.
(edited) my mistake, see my comment below.

Worth to mention also that when enabled, read operations are synced on flash erase/write semaphore.

When so, read operations are se


* :dtcompatible:`jedec,mspi-nor` now allows MSPI configuration of read, write and
control commands separately via devicetree.
* :kconfig:option:`CONFIG_FLASH_STM32_ASYNC`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a place to address #93173 (comment). E.g.:

  * :kconfig:option:`CONFIG_FLASH_STM32_ASYNC`. It is default enabled (when multithreading is enable)
    for STM32 flash drivers that support asynchronous operations.
for (size_t i = 0; i < n; i += FLASH_NB_32BITWORD_IN_FLASHWORD) {
FLASH_STM32_PRIV(dev)->async_complete = false;
FLASH_STM32_PRIV(dev)->async_error = false;
uint32_t wordAddr = (uint32_t)&data[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an empty line above local variable definition + use a snake_case label.

		uint32_t word_addr = (uint32_t)&data[i];
@etienne-lms
Copy link
Contributor

Commit message says

This feature is disabled by default and
can be optionally enabled using the FLASH_STM32_ASYNC config option

Actually the feature is default enabled for drivers that support async operations.

My mistake, it is default disabled. Discard this comment. Sorry.

flash_dev = FLASH_STM32_PRIV(dev);
flash_stm32_async_sem_init(dev);
IRQ_CONNECT(FLASH_IRQn, 0, flash_stm32_irq_handler, NULL, 0);
irq_enable(FLASH_IRQn);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please get flash IRQ from device tree.

return = 0;
} else if (FLASH_STM32_PRIV(dev)->async_error) {
LOG_ERR("Flash erase failed at 0x%x", FLASH_STM32_PRIV(dev)->async_ret);
return = -EIO;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return = -EIO;
return -EIO;

Ditto above.

FLASH_STM32_PRIV(dev)->async_error = false;

HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_SIZE, offset + FLASH_STM32_BASE_ADDRESS, val);
k_sem_take(&FLASH_STM32_PRIV(dev)->async_sem, K_FOREVER);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You provided a function for flash_stm32_async_sem_init, which is matching flash_stm32_sem_init implementation.
It would be nice to make it complete and consistent and provide matching flash_stm32_async_sem_take and flash_stm32_async_sem_give.

LOG_DBG("Read offset: %ld, len: %zu", (long int) offset, len);

if (IS_ENABLED(CONFIG_FLASH_STM32_ASYNC)) {
flash_stm32_sem_take(dev);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you tell in the commit message why read operations need to take the semaphore when using the flash programming interrupt.

@nordicjm
Copy link
Contributor

Since this also changes flash API, have added @de-nordic as co-assignee

@JarmouniA JarmouniA closed this Dec 22, 2025
@JarmouniA JarmouniA reopened this Dec 22, 2025
@zephyrbot zephyrbot requested review from erwango and kartben December 22, 2025 15:09
@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Feb 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Flash platform: STM32 ST Micro STM32 Release Notes To be mentioned in the release notes Stale

8 participants