From c96d9d038076bbf4b1152afd89b45b3279c07d49 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 31 Aug 2026 13:40:37 +0800 Subject: [PATCH] fix(driver): allocate driver objects containing atomic variables from internal SRAM Objects with atomic members must not be allocated to PSRAM, otherwise the ordering guarantee of atomic accesses is weakened due to a hardware behavior on ESP32 chips. Explicitly request MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT for: - i2c master bus object (atomic status/trans_idx) - i3c master bus object (atomic fsm) - ISP processor and AE/AF/AWB/HIST controllers (atomic fsm) - JPEG decoder/encoder dma2d transaction descriptors (atomic started) - PPA transaction storage embedding dma2d_trans_t - dma2d m2m test transaction embedding dma2d_trans_t --- components/esp_driver_i2c/i2c_master.c | 3 ++- components/esp_driver_i3c/i3c_master.c | 3 ++- components/esp_driver_isp/src/isp_ae.c | 3 ++- components/esp_driver_isp/src/isp_af.c | 3 ++- components/esp_driver_isp/src/isp_awb.c | 3 ++- components/esp_driver_isp/src/isp_core.c | 3 ++- components/esp_driver_isp/src/isp_hist.c | 3 ++- components/esp_driver_jpeg/jpeg_decode.c | 3 ++- components/esp_driver_jpeg/jpeg_encode.c | 3 ++- components/esp_driver_ppa/src/ppa_core.c | 3 ++- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index de52da6cf54..8c6c56b7697 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -1058,7 +1058,8 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast ESP_RETURN_ON_FALSE(bus_config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep"); #endif // SOC_I2C_SUPPORT_SLEEP_RETENTION - i2c_master = heap_caps_calloc(1, sizeof(i2c_master_bus_t) + 20 * sizeof(i2c_transaction_t), I2C_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variables + i2c_master = heap_caps_calloc(1, sizeof(i2c_master_bus_t) + 20 * sizeof(i2c_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(i2c_master, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c master bus"); diff --git a/components/esp_driver_i3c/i3c_master.c b/components/esp_driver_i3c/i3c_master.c index 86d97dd7d01..75d84702df2 100644 --- a/components/esp_driver_i3c/i3c_master.c +++ b/components/esp_driver_i3c/i3c_master.c @@ -706,7 +706,8 @@ esp_err_t i3c_new_master_bus(const i3c_master_bus_config_t *bus_config, i3c_mast esp_err_t ret = ESP_OK; i3c_master_bus_t *i3c_master_handle = NULL; - i3c_master_handle = (i3c_master_bus_t*) heap_caps_calloc(1, sizeof(i3c_master_bus_t), I3C_MASTER_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variable + i3c_master_handle = (i3c_master_bus_t*) heap_caps_calloc(1, sizeof(i3c_master_bus_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(i3c_master_handle, ESP_ERR_NO_MEM, TAG, "no mem for i3c master bus handle"); s_i3c_master_platform.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; diff --git a/components/esp_driver_isp/src/isp_ae.c b/components/esp_driver_isp/src/isp_ae.c index 9033b80d544..8d686af8042 100644 --- a/components/esp_driver_isp/src/isp_ae.c +++ b/components/esp_driver_isp/src/isp_ae.c @@ -83,7 +83,8 @@ esp_err_t esp_isp_new_ae_controller(isp_proc_handle_t isp_proc, const esp_isp_ae (ae_config->window.btm_right.y >= ae_config->window.top_left.y) && (ae_config->window.btm_right.y < ISP_LL_AE_WINDOW_MAX_RANGE)), ESP_ERR_INVALID_ARG, TAG, "invalid window"); - isp_ae_ctlr_t ae_ctlr = heap_caps_calloc(1, sizeof(isp_ae_controller_t), ISP_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variable + isp_ae_ctlr_t ae_ctlr = heap_caps_calloc(1, sizeof(isp_ae_controller_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(ae_ctlr, ESP_ERR_NO_MEM, TAG, "no mem"); ae_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_ae_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(ae_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for ae event queue"); diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index 1df3dfd24bf..8accbff8a8b 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -101,7 +101,8 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af } ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0"); - isp_af_ctlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variable + isp_af_ctlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem"); af_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_af_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(af_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for af event queue"); diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index 6469134f914..52bc376040c 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -139,7 +139,8 @@ esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_a esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(isp_proc && awb_cfg && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - isp_awb_ctlr_t awb_ctlr = heap_caps_calloc(1, sizeof(isp_awb_controller_t), ISP_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variable + isp_awb_ctlr_t awb_ctlr = heap_caps_calloc(1, sizeof(isp_awb_controller_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(awb_ctlr, ESP_ERR_NO_MEM, TAG, "no mem for awb controller"); awb_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_awb_stat_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(awb_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for awb event queue"); diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index 641ae2f3294..35e9f2526b5 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -95,7 +95,8 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == proc_config->output_data_color_type, ESP_ERR_INVALID_ARG, TAG, "isp is bypassed, input and output data color type should be same"); } - isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variables + isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(proc, ESP_ERR_NO_MEM, TAG, "no mem"); INIT_CRIT_SECTION_LOCK_RUNTIME(&proc->spinlock); diff --git a/components/esp_driver_isp/src/isp_hist.c b/components/esp_driver_isp/src/isp_hist.c index a50e9012f22..3ea4e560606 100644 --- a/components/esp_driver_isp/src/isp_hist.c +++ b/components/esp_driver_isp/src/isp_hist.c @@ -104,7 +104,8 @@ esp_err_t esp_isp_new_hist_controller(isp_proc_handle_t isp_proc, const esp_isp_ esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(isp_proc && hist_cfg && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - isp_hist_ctlr_t hist_ctlr = heap_caps_calloc(1, sizeof(isp_hist_controller_t), ISP_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the driver object contains atomic variable + isp_hist_ctlr_t hist_ctlr = heap_caps_calloc(1, sizeof(isp_hist_controller_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(hist_ctlr, ESP_ERR_NO_MEM, TAG, "no mem for hist controller"); hist_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_hist_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(hist_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for hist event queue"); diff --git a/components/esp_driver_jpeg/jpeg_decode.c b/components/esp_driver_jpeg/jpeg_decode.c index 8cd7d62d067..d1861fc2929 100644 --- a/components/esp_driver_jpeg/jpeg_decode.c +++ b/components/esp_driver_jpeg/jpeg_decode.c @@ -119,7 +119,8 @@ esp_err_t jpeg_new_decoder_engine(const jpeg_decode_engine_cfg_t *dec_eng_cfg, j ESP_GOTO_ON_ERROR(dma2d_acquire_pool(&dma2d_client_config, &decoder_engine->dma2d_group_handle), err, TAG, "dma2d client acquire failed"); - decoder_engine->trans_desc = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, JPEG_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the dma2d transaction descriptor contains atomic variable + decoder_engine->trans_desc = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(decoder_engine->trans_desc, ESP_ERR_NO_MEM, err, TAG, "No memory for dma2d descriptor"); #if JPEG_USE_RETENTION_LINK if (dec_eng_cfg->flags.allow_pd != 0) { diff --git a/components/esp_driver_jpeg/jpeg_encode.c b/components/esp_driver_jpeg/jpeg_encode.c index a013ccea7d7..fc5a105689d 100644 --- a/components/esp_driver_jpeg/jpeg_encode.c +++ b/components/esp_driver_jpeg/jpeg_encode.c @@ -163,7 +163,8 @@ esp_err_t jpeg_new_encoder_engine(const jpeg_encode_engine_cfg_t *enc_eng_cfg, j }; ESP_ERROR_CHECK(dma2d_acquire_pool(&dma2d_group_config, &encoder_engine->dma2d_group_handle)); - encoder_engine->trans_desc = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, JPEG_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the dma2d transaction descriptor contains atomic variable + encoder_engine->trans_desc = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(encoder_engine->trans_desc, ESP_ERR_NO_MEM, err, TAG, "No memory for dma2d descriptor"); encoder_engine->header_info = (jpeg_enc_header_info_t*)heap_caps_calloc(1, sizeof(jpeg_enc_header_info_t), JPEG_MEM_ALLOC_CAPS); diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c index 43843f4bc53..79d40cab599 100644 --- a/components/esp_driver_ppa/src/ppa_core.c +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -422,7 +422,8 @@ static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t t assert(ppa_trans_desc_size != 0); size_t trans_elm_storage_size = sizeof(ppa_trans_t) + SIZEOF_DMA2D_TRANS_T + sizeof(dma2d_trans_config_t) + sizeof(ppa_dma2d_trans_on_picked_config_t) + ppa_trans_desc_size; for (int i = 0; i < trans_elm_num; i++) { - void *trans_elm_storage = heap_caps_calloc(1, trans_elm_storage_size, PPA_MEM_ALLOC_CAPS); + // always allocate memory from internal memory because the transaction storage embeds a dma2d_trans_t which contains atomic variable + void *trans_elm_storage = heap_caps_calloc(1, trans_elm_storage_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); SemaphoreHandle_t ppa_trans_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS); if (!trans_elm_storage || !ppa_trans_sem) {