Skip to content

Commit 6b144f1

Browse files
author
Marek Matej
committed
drivers: flash: esp32: Add async operations
Since flash access is restricted to use in cases when flash could be invalidated during the operation. Therefore accessing a flash memory from the code running from the PSRAM could lead to exception. This work implements asynchoronous operations to allow flash access only from the valid runtime. Signed-off-by: Marek Matej <[email protected]>
1 parent ad0f411 commit 6b144f1

File tree

2 files changed

+128
-13
lines changed

2 files changed

+128
-13
lines changed

drivers/flash/Kconfig.esp32

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ config MPU_ALLOW_FLASH_WRITE
1515
bool "Add MPU access to write to flash"
1616
help
1717
Enable this to allow MPU RWX access to flash memory
18+
19+
config ESP_FLASH_ASYNC
20+
bool "Use asynchronous work thread to execute the flash access operations"
21+
depends on MULTITHREADING
22+
help
23+
Enabling this makes the flash access operations deferred to the work thread.
24+
Meaning every flash read or write would be postponed and executed when available.

drivers/flash/flash_esp32.c

Lines changed: 121 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
2+
* Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -39,6 +39,16 @@ struct flash_esp32_dev_config {
3939
};
4040

4141
struct flash_esp32_dev_data {
42+
#ifdef CONFIG_ESP_FLASH_ASYNC
43+
struct k_work work;
44+
struct k_mutex lock;
45+
const struct device *dev;
46+
int type;
47+
off_t addr;
48+
size_t len;
49+
void *buf;
50+
int ret;
51+
#endif
4252
#ifdef CONFIG_MULTITHREADING
4353
struct k_sem sem;
4454
#endif
@@ -137,17 +147,20 @@ static int flash_esp32_read(const struct device *dev, off_t address, void *buffe
137147
}
138148
}
139149
#else
140-
flash_esp32_sem_take(dev);
141150

151+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
152+
flash_esp32_sem_take(dev);
153+
#endif
142154
if (esp_flash_encryption_enabled()) {
143155
ret = esp_flash_read_encrypted(NULL, address, buffer, length);
144156
} else {
145157
ret = esp_flash_read(NULL, buffer, address, length);
146158
}
147159

160+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
148161
flash_esp32_sem_give(dev);
149162
#endif
150-
163+
#endif
151164
if (ret != 0) {
152165
LOG_ERR("Flash read error: %d", ret);
153166
return -EIO;
@@ -156,9 +169,7 @@ static int flash_esp32_read(const struct device *dev, off_t address, void *buffe
156169
return 0;
157170
}
158171

159-
static int flash_esp32_write(const struct device *dev,
160-
off_t address,
161-
const void *buffer,
172+
static int flash_esp32_write(const struct device *dev, off_t address, const void *buffer,
162173
size_t length)
163174
{
164175
int ret = 0;
@@ -173,17 +184,19 @@ static int flash_esp32_write(const struct device *dev,
173184

174185
ret = esp_rom_flash_write(address, (void *)buffer, length, encrypt);
175186
#else
187+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
176188
flash_esp32_sem_take(dev);
177-
189+
#endif
178190
if (esp_flash_encryption_enabled()) {
179191
ret = esp_flash_write_encrypted(NULL, address, buffer, length);
180192
} else {
181193
ret = esp_flash_write(NULL, buffer, address, length);
182194
}
183195

196+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
184197
flash_esp32_sem_give(dev);
185198
#endif
186-
199+
#endif
187200
if (ret != 0) {
188201
LOG_ERR("Flash write error: %d", ret);
189202
return -EIO;
@@ -199,9 +212,13 @@ static int flash_esp32_erase(const struct device *dev, off_t start, size_t len)
199212
#ifdef CONFIG_MCUBOOT
200213
ret = esp_rom_flash_erase_range(start, len);
201214
#else
215+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
202216
flash_esp32_sem_take(dev);
217+
#endif
203218
ret = esp_flash_erase_region(NULL, start, len);
219+
#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC)
204220
flash_esp32_sem_give(dev);
221+
#endif
205222
#endif
206223
if (ret != 0) {
207224
LOG_ERR("Flash erase error: %d", ret);
@@ -210,6 +227,83 @@ static int flash_esp32_erase(const struct device *dev, off_t start, size_t len)
210227
return 0;
211228
}
212229

230+
#ifdef CONFIG_ESP_FLASH_ASYNC
231+
static void flash_work_handler(struct k_work *work)
232+
{
233+
struct flash_esp32_dev_data *data = CONTAINER_OF(work, struct flash_esp32_dev_data, work);
234+
235+
if (data->type == 0) {
236+
data->ret = flash_esp32_read(data->dev, data->addr, data->buf, data->len);
237+
} else if (data->type == 1) {
238+
data->ret = flash_esp32_write(data->dev, data->addr, data->buf, data->len);
239+
} else if (data->type == 2) {
240+
data->ret = flash_esp32_erase(data->dev, data->addr, data->len);
241+
} else {
242+
data->ret = -1;
243+
}
244+
245+
k_sem_give(&data->sem);
246+
}
247+
248+
static int flash_esp32_read_async(const struct device *dev, off_t address,
249+
void *buffer, size_t length)
250+
{
251+
struct flash_esp32_dev_data *data = dev->data;
252+
253+
k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3));
254+
255+
data->dev = dev;
256+
data->addr = address;
257+
data->buf = buffer;
258+
data->len = length;
259+
data->type = 0;
260+
261+
k_work_submit(&data->work);
262+
k_sem_take(&data->sem, FLASH_SEM_TIMEOUT);
263+
k_mutex_unlock(&data->lock);
264+
265+
return data->ret;
266+
}
267+
268+
static int flash_esp32_write_async(const struct device *dev, off_t address,
269+
const void *buffer, size_t length)
270+
{
271+
struct flash_esp32_dev_data *data = dev->data;
272+
273+
k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3));
274+
275+
data->dev = dev;
276+
data->addr = address;
277+
data->buf = (void *) buffer;
278+
data->len = length;
279+
data->type = 1;
280+
281+
k_work_submit(&data->work);
282+
k_sem_take(&data->sem, FLASH_SEM_TIMEOUT);
283+
k_mutex_unlock(&data->lock);
284+
285+
return 0;
286+
}
287+
static int flash_esp32_erase_async(const struct device *dev, off_t start, size_t len)
288+
{
289+
struct flash_esp32_dev_data *data = dev->data;
290+
291+
k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3));
292+
293+
data->addr = start;
294+
data->len = len;
295+
data->buf = NULL;
296+
data->type = 2;
297+
298+
k_work_submit(&data->work);
299+
k_sem_take(&data->sem, FLASH_SEM_TIMEOUT);
300+
k_mutex_unlock(&data->lock);
301+
302+
return 0;
303+
}
304+
#endif
305+
306+
213307
#if CONFIG_FLASH_PAGE_LAYOUT
214308
static const struct flash_pages_layout flash_esp32_pages_layout = {
215309
.pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ,
@@ -223,7 +317,7 @@ void flash_esp32_page_layout(const struct device *dev,
223317
*layout = &flash_esp32_pages_layout;
224318
*layout_size = 1;
225319
}
226-
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
320+
#endif
227321

228322
static const struct flash_parameters *
229323
flash_esp32_get_parameters(const struct device *dev)
@@ -235,19 +329,33 @@ flash_esp32_get_parameters(const struct device *dev)
235329

236330
static int flash_esp32_init(const struct device *dev)
237331
{
238-
#ifdef CONFIG_MULTITHREADING
239-
struct flash_esp32_dev_data *const dev_data = dev->data;
332+
struct flash_esp32_dev_data *const data = dev->data;
240333

241-
k_sem_init(&dev_data->sem, 1, 1);
242-
#endif /* CONFIG_MULTITHREADING */
334+
#ifdef CONFIG_MULTITHREADING
335+
#ifdef CONFIG_ESP_FLASH_ASYNC
336+
k_sem_init(&data->sem, 0, 1);
337+
#else
338+
k_sem_init(&data->sem, 1, 1);
339+
#endif
340+
#endif
243341

342+
#ifdef CONFIG_ESP_FLASH_ASYNC
343+
k_mutex_init(&data->lock);
344+
k_work_init(&data->work, flash_work_handler);
345+
#endif
244346
return 0;
245347
}
246348

247349
static DEVICE_API(flash, flash_esp32_driver_api) = {
350+
#ifdef CONFIG_ESP_FLASH_ASYNC
351+
.read = flash_esp32_read_async,
352+
.write = flash_esp32_write_async,
353+
.erase = flash_esp32_erase_async,
354+
#else
248355
.read = flash_esp32_read,
249356
.write = flash_esp32_write,
250357
.erase = flash_esp32_erase,
358+
#endif
251359
.get_parameters = flash_esp32_get_parameters,
252360
#ifdef CONFIG_FLASH_PAGE_LAYOUT
253361
.page_layout = flash_esp32_page_layout,

0 commit comments

Comments
 (0)