Skip to content
Open
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
4 changes: 4 additions & 0 deletions doc/releases/release-notes-4.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ New APIs and options
* :kconfig:option:`CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_AL_88`
* :kconfig:option:`CONFIG_SDL_DISPLAY_COLOR_TINT`

* Flash

* :kconfig:option:`CONFIG_FLASH_STM32_ASYNC`

* Kernel

* :kconfig:option:`CONFIG_HW_SHADOW_STACK`
Expand Down
6 changes: 6 additions & 0 deletions drivers/flash/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ config FLASH_HAS_EX_OP
This option is selected by drivers that support flash extended
operations.

config FLASH_HAS_ASYNC_OPS
bool
help
This option is selected by drivers that support asynchronous
flash operations.

config FLASH_HAS_EXPLICIT_ERASE
bool
help
Expand Down
12 changes: 12 additions & 0 deletions drivers/flash/Kconfig.stm32
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ menuconfig SOC_FLASH_STM32
select MPU_ALLOW_FLASH_WRITE if ARM_MPU
select USE_STM32_HAL_FLASH if BT_STM32WBA
select USE_STM32_HAL_FLASH_EX if BT_STM32WBA
select FLASH_HAS_ASYNC_OPS if SOC_SERIES_STM32L4X || \
SOC_SERIES_STM32F4X || \
SOC_SERIES_STM32H7X
help
Enable flash driver for STM32 series

Expand Down Expand Up @@ -100,4 +103,13 @@ config USE_MICROCHIP_QSPI_FLASH_WITH_STM32
the Global Block Protection Unlock instruction (ULBPR - 98H),
and write with SPI_NOR_CMD_PP_1_1_4 on 4 lines

config FLASH_STM32_ASYNC
bool "Use asynchronous flash operations"
depends on MULTITHREADING && FLASH_HAS_ASYNC_OPS
select USE_STM32_HAL_FLASH
select USE_STM32_HAL_FLASH_EX
help
Use asynchronous flash operations to unblock other threads while
flash is busy.

endif # SOC_FLASH_STM32
45 changes: 45 additions & 0 deletions drivers/flash/flash_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,16 @@ static int flash_stm32_read(const struct device *dev, off_t offset,

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

if (IS_ENABLED(CONFIG_FLASH_STM32_ASYNC)) {
flash_stm32_sem_take(dev);
}

memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len);

if (IS_ENABLED(CONFIG_FLASH_STM32_ASYNC)) {
flash_stm32_sem_give(dev);
}

return 0;
}

Expand Down Expand Up @@ -416,6 +424,36 @@ static DEVICE_API(flash, flash_stm32_api) = {
#endif
};

#if defined(CONFIG_FLASH_STM32_ASYNC)
/* STM32 HAL functions do not permit pass a cookie to the interrupt callback functions and therefore
* only support a single flash and require a static pointer to the flash device.
*/
static struct flash_stm32_priv *flash_dev;

/* IRQ handler function for async flash mode */
void flash_stm32_irq_handler(void)
{
HAL_FLASH_IRQHandler();
if (flash_dev->async_complete || flash_dev->async_error) {
k_sem_give(&flash_dev->async_sem);
}
}

/* STM32 HAL function called by HAL_FLASH_IRQHandler() when a flash op completes successfully */
void HAL_FLASH_EndOfOperationCallback(uint32_t op_ret_val)
{
flash_dev->async_complete = true;
flash_dev->async_ret = op_ret_val;
}

/* STM32 HAL function called by HAL_FLASH_IRQHandler() when a flash op completes with an error */
void HAL_FLASH_OperationErrorCallback(uint32_t op_ret_val)
{
flash_dev->async_error = true;
flash_dev->async_ret = op_ret_val;
}
#endif /* CONFIG_FLASH_STM32_ASYNC */

static int stm32_flash_init(const struct device *dev)
{
int rc;
Expand Down Expand Up @@ -458,6 +496,13 @@ static int stm32_flash_init(const struct device *dev)

flash_stm32_sem_init(dev);

#if defined(CONFIG_FLASH_STM32_ASYNC)
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);
#endif /* CONFIG_FLASH_STM32_ASYNC */

LOG_DBG("Flash @0x%x initialized. BS: %zu",
FLASH_STM32_BASE_ADDRESS,
flash_stm32_parameters.write_block_size);
Expand Down
9 changes: 9 additions & 0 deletions drivers/flash/flash_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ struct flash_stm32_priv {
struct stm32_pclken pclken;
#endif
struct k_sem sem;
#if defined(CONFIG_FLASH_STM32_ASYNC)
struct k_sem async_sem;
bool async_complete;
bool async_error;
uint32_t async_ret;
#endif /* CONFIG_FLASH_STM32_ASYNC */
};

#if DT_PROP(DT_INST(0, soc_nv_flash), write_block_size)
Expand Down Expand Up @@ -310,6 +316,9 @@ static inline void _flash_stm32_sem_give(const struct device *dev)
#define flash_stm32_sem_init(dev) k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1)
#define flash_stm32_sem_take(dev) _flash_stm32_sem_take(dev)
#define flash_stm32_sem_give(dev) _flash_stm32_sem_give(dev)
#if defined(CONFIG_FLASH_STM32_ASYNC)
#define flash_stm32_async_sem_init(dev) k_sem_init(&FLASH_STM32_PRIV(dev)->async_sem, 0, 1)
#endif /* CONFIG_FLASH_STM32_ASYNC */
#else
#define flash_stm32_sem_init(dev)
#define flash_stm32_sem_take(dev)
Expand Down
66 changes: 66 additions & 0 deletions drivers/flash/flash_stm32f4x.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ typedef uint8_t flash_prg_t;
#error Write block size must be a power of 2, from 1 to 8
#endif

#if defined(CONFIG_FLASH_STM32_ASYNC)
#if FLASH_STM32_WRITE_BLOCK_SIZE == 8
#define FLASH_TYPEPROGRAM_SIZE FLASH_TYPEPROGRAM_DOUBLEWORD
#elif FLASH_STM32_WRITE_BLOCK_SIZE == 4
#define FLASH_TYPEPROGRAM_SIZE FLASH_TYPEPROGRAM_WORD
#elif FLASH_STM32_WRITE_BLOCK_SIZE == 2
#define FLASH_TYPEPROGRAM_SIZE FLASH_TYPEPROGRAM_HALFWORD
#elif FLASH_STM32_WRITE_BLOCK_SIZE == 1
#define FLASH_TYPEPROGRAM_SIZE FLASH_TYPEPROGRAM_BYTE
#else
#error Write block size must be a power of 2, from 1 to 8
#endif
#endif /* CONFIG_FLASH_STM32_ASYNC */

bool flash_stm32_valid_range(const struct device *dev, off_t offset,
uint32_t len,
bool write)
Expand Down Expand Up @@ -82,6 +96,27 @@ static inline void flush_cache(FLASH_TypeDef *regs)

static int write_value(const struct device *dev, off_t offset, flash_prg_t val)
{
#if defined(CONFIG_FLASH_STM32_ASYNC)
FLASH_STM32_PRIV(dev)->async_complete = false;
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);
if (FLASH_STM32_PRIV(dev)->async_complete) {
LOG_DBG("Flash write successful. Wrote 0x%x at 0x%lx", val,
offset + FLASH_STM32_BASE_ADDRESS);
return 0;
}

if (FLASH_STM32_PRIV(dev)->async_error) {
LOG_ERR("Flash write failed at 0x%x", FLASH_STM32_PRIV(dev)->async_ret);
return -EIO;
}

/* Should never be reached */
return -EFAULT;
#else /* CONFIG_FLASH_STM32_ASYNC */

FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
#if defined(FLASH_OPTCR_DB1M)
bool dcache_enabled = false;
Expand Down Expand Up @@ -132,10 +167,40 @@ static int write_value(const struct device *dev, off_t offset, flash_prg_t val)
#endif /* FLASH_OPTCR_DB1M */

return rc;
#endif /* CONFIG_FLASH_STM32_ASYNC */
}

static int erase_sector(const struct device *dev, uint32_t sector)
{
#if defined(CONFIG_FLASH_STM32_ASYNC)
FLASH_STM32_PRIV(dev)->async_complete = false;
FLASH_STM32_PRIV(dev)->async_error = false;

FLASH_EraseInitTypeDef erase_init = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Banks = 1, /* dual bank flash not supported */
.Sector = sector,
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_4,
};

HAL_FLASHEx_Erase_IT(&erase_init);
k_sem_take(&FLASH_STM32_PRIV(dev)->async_sem, K_FOREVER);
if (FLASH_STM32_PRIV(dev)->async_complete) {
LOG_DBG("Flash erase successful. Erased sector %d at 0x%x", sector,
FLASH_STM32_PRIV(dev)->async_ret);
return = 0;
}

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

/* Should never be reached */
return -EFAULT;
#else /* CONFIG_FLASH_STM32_ASYNC */

FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
uint32_t tmp;
int rc;
Expand Down Expand Up @@ -182,6 +247,7 @@ static int erase_sector(const struct device *dev, uint32_t sector)
regs->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB);

return rc;
#endif /* CONFIG_FLASH_STM32_ASYNC */
}

int flash_stm32_block_erase_loop(const struct device *dev,
Expand Down
Loading
Loading