From 9a2997e25cd73aa2126f51cd1b826b340cce433b Mon Sep 17 00:00:00 2001 From: gaoxu Date: Mon, 7 Jul 2025 14:28:31 +0800 Subject: [PATCH] feat(lcd_cam): add lc_dma_int value atomic protect for lcd and cam --- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 10 +++++++--- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 10 +++++++--- components/hal/esp32p4/include/hal/cam_ll.h | 8 +++++++- components/hal/esp32p4/include/hal/lcd_ll.h | 8 +++++++- components/hal/esp32s3/include/hal/cam_ll.h | 6 ++++++ components/hal/esp32s3/include/hal/lcd_ll.h | 8 +++++++- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index 0f96148c3c..ee392c602c 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -197,7 +197,9 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc (uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev), LCD_LL_EVENT_TRANS_DONE, i80_lcd_default_isr_handler, bus, &bus->intr); ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed"); - lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts + PERIPH_RCC_ATOMIC() { + lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts + } lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt // install DMA service bus->max_transfer_bytes = bus_config->max_transfer_bytes; @@ -213,8 +215,10 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc lcd_ll_set_swizzle_mode(bus->hal.dev, LCD_LL_SWIZZLE_AB2BA); // number of data cycles is controlled by DMA buffer size lcd_ll_enable_output_always_on(bus->hal.dev, true); - // enable trans done interrupt - lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, true); + PERIPH_RCC_ATOMIC() { + // enable trans done interrupt + lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, true); + } // trigger a quick "trans done" event, and wait for the interrupt line goes active // this could ensure we go into ISR handler next time we call `esp_intr_enable` lcd_periph_trigger_quick_trans_done_event(bus); diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 72df1e8266..cf639f89fb 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -332,7 +332,9 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf (uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev), LCD_LL_EVENT_VSYNC_END, rgb_lcd_default_isr_handler, rgb_panel, &rgb_panel->intr); ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed"); - lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END, false); // disable all interrupts + PERIPH_RCC_ATOMIC() { + lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END, false); // disable all interrupts + } lcd_ll_clear_interrupt_status(rgb_panel->hal.dev, UINT32_MAX); // clear pending interrupt // install DMA service @@ -569,8 +571,10 @@ static esp_err_t rgb_panel_init(esp_lcd_panel_t *panel) // in stream mode, after finish one frame, the LCD controller will ask for data automatically from the DMA // DMA should prepare the next frame data within porch region lcd_ll_enable_auto_next_frame(rgb_panel->hal.dev, rgb_panel->flags.stream_mode); - // trigger interrupt on the end of frame - lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END, true); + PERIPH_RCC_ATOMIC() { + // trigger interrupt on the end of frame + lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END, true); + } // enable intr esp_intr_enable(rgb_panel->intr); // start transmission diff --git a/components/hal/esp32p4/include/hal/cam_ll.h b/components/hal/esp32p4/include/hal/cam_ll.h index a48dba2dc8..6c7467023e 100644 --- a/components/hal/esp32p4/include/hal/cam_ll.h +++ b/components/hal/esp32p4/include/hal/cam_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -593,6 +593,12 @@ static inline void cam_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bo dev->lc_dma_int_ena.val &= ~(mask & 0x0c); } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_enable_interrupt(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + cam_ll_enable_interrupt(__VA_ARGS__); \ + } while(0) /** * @brief Get interrupt status value diff --git a/components/hal/esp32p4/include/hal/lcd_ll.h b/components/hal/esp32p4/include/hal/lcd_ll.h index 7c67bbadef..416e93b520 100644 --- a/components/hal/esp32p4/include/hal/lcd_ll.h +++ b/components/hal/esp32p4/include/hal/lcd_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -726,6 +726,12 @@ static inline void lcd_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bo dev->lc_dma_int_ena.val &= ~(mask & 0x03); } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define lcd_ll_enable_interrupt(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + lcd_ll_enable_interrupt(__VA_ARGS__); \ + } while(0) /** * @brief Get interrupt status value diff --git a/components/hal/esp32s3/include/hal/cam_ll.h b/components/hal/esp32s3/include/hal/cam_ll.h index 2556b004bc..28b151fa92 100644 --- a/components/hal/esp32s3/include/hal/cam_ll.h +++ b/components/hal/esp32s3/include/hal/cam_ll.h @@ -574,6 +574,12 @@ static inline void cam_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bo dev->lc_dma_int_ena.val &= ~(mask & 0x0c); } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_enable_interrupt(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + cam_ll_enable_interrupt(__VA_ARGS__); \ + } while(0) /** * @brief Get interrupt status value diff --git a/components/hal/esp32s3/include/hal/lcd_ll.h b/components/hal/esp32s3/include/hal/lcd_ll.h index 8ef0a32626..644cbb7825 100644 --- a/components/hal/esp32s3/include/hal/lcd_ll.h +++ b/components/hal/esp32s3/include/hal/lcd_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -709,6 +709,12 @@ static inline void lcd_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bo dev->lc_dma_int_ena.val &= ~(mask & 0x03); } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define lcd_ll_enable_interrupt(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + lcd_ll_enable_interrupt(__VA_ARGS__); \ + } while(0) /** * @brief Get interrupt status value