Skip to content

Commit 459b241

Browse files
committed
Merge branch 'feat/lcd_cam_dvp_driver_s3' into 'master'
DVP support and example for ESP32S3 Closes IDF-10475 See merge request espressif/esp-idf!39323
2 parents ffebb32 + b7d65d9 commit 459b241

32 files changed

+1322
-40
lines changed

components/esp_driver_cam/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
menu "ESP-Driver:Camera Controller Configurations"
22

3-
depends on SOC_MIPI_CSI_SUPPORTED || SOC_LCDCAM_CAM_SUPPORTED
3+
depends on SOC_MIPI_CSI_SUPPORTED || SOC_ISP_DVP_SUPPORTED || SOC_LCDCAM_CAM_SUPPORTED
44

55
config CAM_CTLR_MIPI_CSI_ISR_CACHE_SAFE
66
bool "CSI ISR Cache-Safe"
@@ -16,6 +16,7 @@ menu "ESP-Driver:Camera Controller Configurations"
1616

1717
config CAM_CTLR_ISP_DVP_ISR_CACHE_SAFE # IDF-10093
1818
bool "ISP_DVP ISR Cache-Safe"
19+
depends on SOC_ISP_DVP_SUPPORTED
1920
default n
2021
select DW_GDMA_ISR_IRAM_SAFE
2122
select DW_GDMA_CTRL_FUNC_IN_IRAM

components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,24 @@
2626
#include "../../dvp_share_ctrl.h"
2727

2828
#ifdef CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE
29-
#define CAM_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
29+
#define DVP_CAM_CTLR_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
3030
#else
31-
#define CAM_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_DEFAULT)
31+
#define DVP_CAM_CTLR_ALLOC_CAPS (MALLOC_CAP_DEFAULT)
3232
#endif
3333

34-
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
34+
#if CONFIG_SPIRAM
35+
#define DVP_CAM_BK_BUFFER_ALLOC_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
36+
#else
37+
#define DVP_CAM_BK_BUFFER_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
38+
#endif
39+
40+
#if SOC_PERIPH_CLK_CTRL_SHARED
41+
#define DVP_CAM_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
42+
#else
43+
#define DVP_CAM_CLK_ATOMIC()
44+
#endif
45+
46+
#define ALIGN_UP_BY(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
3547

3648
#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv) \
3749
{ \
@@ -209,7 +221,6 @@ static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_jpeg_size(const uint8_t *buffer,
209221
*/
210222
static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_t *ctlr, uint8_t *rx_buffer, uint32_t dma_recv_size)
211223
{
212-
esp_err_t ret;
213224
uint32_t recv_buffer_size;
214225

215226
if (ctlr->pic_format_jpeg) {
@@ -218,8 +229,10 @@ static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_
218229
recv_buffer_size = ctlr->fb_size_in_bytes;
219230
}
220231

221-
ret = esp_cache_msync(rx_buffer, recv_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
222-
assert(ret == ESP_OK);
232+
if (esp_ptr_external_ram(rx_buffer)) {
233+
esp_err_t ret = esp_cache_msync(rx_buffer, recv_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
234+
assert(ret == ESP_OK);
235+
}
223236

224237
if (ctlr->pic_format_jpeg) {
225238
recv_buffer_size = esp_cam_ctlr_dvp_get_jpeg_size(rx_buffer, dma_recv_size);
@@ -336,7 +349,7 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e
336349
}
337350

338351
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true));
339-
PERIPH_RCC_ATOMIC() {
352+
DVP_CAM_CLK_ATOMIC() {
340353
cam_ll_enable_clk(ctlr_id, true);
341354
cam_ll_select_clk_src(ctlr_id, clk_src);
342355
};
@@ -367,7 +380,7 @@ esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src,
367380
ESP_LOGD(TAG, "DVP clock source frequency %" PRIu32 "Hz", src_clk_hz);
368381

369382
if ((src_clk_hz % xclk_freq) == 0) {
370-
PERIPH_RCC_ATOMIC() {
383+
DVP_CAM_CLK_ATOMIC() {
371384
cam_ll_set_group_clock_coeff(ctlr_id, src_clk_hz / xclk_freq, 0, 0);
372385
};
373386

@@ -390,7 +403,7 @@ esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id)
390403
{
391404
ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM);
392405

393-
PERIPH_RCC_ATOMIC() {
406+
DVP_CAM_CLK_ATOMIC() {
394407
cam_ll_enable_clk(ctlr_id, false);
395408
};
396409

@@ -710,19 +723,19 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_
710723
ESP_RETURN_ON_FALSE(config->external_xtal || config->pin_dont_init || config->pin->xclk_io != GPIO_NUM_NC, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_io is not set");
711724
ESP_RETURN_ON_FALSE(config->external_xtal || config->xclk_freq, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_freq is not set");
712725

713-
ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment");
726+
ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_CAM_BK_BUFFER_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment");
714727
ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_cam_get_frame_size(config, &fb_size_in_bytes), TAG, "invalid argument: input frame pixel format is not supported");
715728
ESP_RETURN_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), TAG, "failed to claim io signals");
716729

717-
esp_cam_ctlr_dvp_cam_t *ctlr = heap_caps_calloc(1, sizeof(esp_cam_ctlr_dvp_cam_t), CAM_DVP_MEM_ALLOC_CAPS);
730+
esp_cam_ctlr_dvp_cam_t *ctlr = heap_caps_calloc(1, sizeof(esp_cam_ctlr_dvp_cam_t), DVP_CAM_CTLR_ALLOC_CAPS);
718731
ESP_GOTO_ON_FALSE(ctlr, ESP_ERR_NO_MEM, fail0, TAG, "no mem for CAM DVP controller context");
719732

720733
ESP_GOTO_ON_ERROR(s_dvp_claim_ctlr(config->ctlr_id, ctlr), fail1, TAG, "no available DVP controller");
721734

722735
ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size);
723736
fb_size_in_bytes = ALIGN_UP_BY(fb_size_in_bytes, alignment_size);
724737
if (!config->bk_buffer_dis) {
725-
ctlr->backup_buffer = heap_caps_aligned_alloc(alignment_size, fb_size_in_bytes, MALLOC_CAP_SPIRAM);
738+
ctlr->backup_buffer = heap_caps_aligned_alloc(alignment_size, fb_size_in_bytes, DVP_CAM_BK_BUFFER_ALLOC_CAPS);
726739
ESP_GOTO_ON_FALSE(ctlr->backup_buffer, ESP_ERR_NO_MEM, fail2, TAG, "no mem for DVP backup buffer");
727740
}
728741

components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -10,9 +10,24 @@
1010
#include "esp_cache.h"
1111
#include "esp_private/esp_cache_private.h"
1212
#include "esp_cam_ctlr_dvp_dma.h"
13+
#include "esp_memory_utils.h"
1314

1415
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
1516

17+
#if defined(SOC_GDMA_TRIG_PERIPH_CAM0_BUS) && (SOC_GDMA_TRIG_PERIPH_CAM0_BUS == SOC_GDMA_BUS_AHB)
18+
#define DVP_GDMA_NEW_CHANNEL gdma_new_ahb_channel
19+
#define DVP_GDMA_DESC_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
20+
#elif defined(SOC_GDMA_TRIG_PERIPH_CAM0_BUS) && (SOC_GDMA_TRIG_PERIPH_CAM0_BUS == SOC_GDMA_BUS_AXI)
21+
#define DVP_GDMA_NEW_CHANNEL gdma_new_axi_channel
22+
#if CONFIG_SPIRAM
23+
#define DVP_GDMA_DESC_ALLOC_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
24+
#else
25+
#define DVP_GDMA_DESC_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
26+
#endif
27+
#else
28+
#error "Unsupported GDMA bus type for DVP"
29+
#endif
30+
1631
static const char *TAG = "dvp_gdma";
1732

1833
/**
@@ -72,9 +87,9 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
7287
#endif
7388
};
7489

75-
ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment");
90+
ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_GDMA_DESC_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment");
7691

77-
ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed");
92+
ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed");
7893

7994
ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed");
8095

@@ -90,17 +105,21 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
90105
.access_ext_mem = true,
91106
};
92107
ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed");
108+
size_t int_mem_align = 0;
109+
size_t ext_mem_align = 0;
110+
gdma_get_alignment_constraints(dma->dma_chan, &int_mem_align, &ext_mem_align);
93111

94112
dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
95113
if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) {
96114
dma->desc_count++;
97115
}
98116
dma->size = size;
99-
100-
ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size);
117+
alignment_size = (alignment_size == 0) ? 1 : alignment_size;
101118
dma->desc_size = ALIGN_UP_BY(dma->desc_count * sizeof(esp_cam_ctlr_dvp_dma_desc_t), alignment_size);
102119

103-
dma->desc = heap_caps_aligned_alloc(alignment_size, dma->desc_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
120+
ESP_LOGD(TAG, "alignment_size: %d, dma->desc_count: %d, dma->desc_size: %d", alignment_size, dma->desc_count, dma->desc_size);
121+
dma->desc = heap_caps_aligned_alloc(alignment_size, dma->desc_size, DVP_GDMA_DESC_ALLOC_CAPS);
122+
104123
ESP_GOTO_ON_FALSE(dma->desc, ESP_ERR_NO_MEM, fail1, TAG, "no mem for DVP DMA descriptor");
105124

106125
return ESP_OK;
@@ -144,15 +163,15 @@ esp_err_t esp_cam_ctlr_dvp_dma_deinit(esp_cam_ctlr_dvp_dma_t *dma)
144163
*/
145164
esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint8_t *buffer, size_t size)
146165
{
147-
esp_err_t ret;
148-
149166
ESP_RETURN_ON_FALSE_ISR(dma, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
150167
ESP_RETURN_ON_FALSE_ISR(dma->size >= size, ESP_ERR_INVALID_ARG, TAG, "input buffer size is out of range");
151168

152169
esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size);
153170

154-
ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
155-
assert(ret == ESP_OK);
171+
if (esp_ptr_external_ram(dma->desc)) {
172+
esp_err_t ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
173+
assert(ret == ESP_OK);
174+
}
156175

157176
return gdma_start(dma->dma_chan, (intptr_t)dma->desc);
158177
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| Supported Targets | ESP32-P4 |
2-
| ----------------- | -------- |
1+
| Supported Targets | ESP32-P4 | ESP32-S3 |
2+
| ----------------- | -------- | -------- |

components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TEST_CASE("TEST DVP driver allocation", "[DVP]")
1717
.h_res = 800,
1818
.v_res = 640,
1919
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
20-
.dma_burst_size = 128,
20+
.dma_burst_size = 64,
2121
.byte_swap_en = false,
2222
.pin_dont_init = true,
2323
.external_xtal = true,
@@ -42,7 +42,7 @@ TEST_CASE("TEST DVP driver allocation with JPEG input", "[DVP]")
4242
.clk_src = CAM_CLK_SRC_DEFAULT,
4343
.h_res = 800,
4444
.v_res = 640,
45-
.dma_burst_size = 128,
45+
.dma_burst_size = 64,
4646
.byte_swap_en = false,
4747
.pin_dont_init = true,
4848
.pic_format_jpeg = true,
@@ -69,7 +69,7 @@ TEST_CASE("TEST DVP driver no backup buffer usage", "[DVP]")
6969
.h_res = 800,
7070
.v_res = 640,
7171
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
72-
.dma_burst_size = 128,
72+
.dma_burst_size = 64,
7373
.byte_swap_en = false,
7474
.bk_buffer_dis = true,
7575
.pin_dont_init = true,
@@ -96,7 +96,7 @@ TEST_CASE("TEST DVP driver intern/extern init", "[DVP]")
9696
.h_res = 800,
9797
.v_res = 640,
9898
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
99-
.dma_burst_size = 128,
99+
.dma_burst_size = 64,
100100
.byte_swap_en = false,
101101
.external_xtal = true,
102102
};
@@ -128,7 +128,7 @@ TEST_CASE("TEST DVP driver intern/extern generate xclk", "[DVP]")
128128
.h_res = 800,
129129
.v_res = 640,
130130
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
131-
.dma_burst_size = 128,
131+
.dma_burst_size = 64,
132132
.byte_swap_en = false,
133133
.external_xtal = true,
134134
};

components/esp_driver_cam/test_apps/dvp/pytest_dvp.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@
1414
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
1515
def test_dvp(dut: Dut) -> None:
1616
dut.run_all_single_board_cases()
17+
18+
19+
@pytest.mark.octal_psram
20+
@pytest.mark.parametrize(
21+
'config',
22+
['cache_safe', 'release', 'pm_enable'],
23+
indirect=True,
24+
)
25+
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
26+
def test_dvp_octal(dut: Dut) -> None:
27+
dut.run_all_single_board_cases()

components/esp_driver_cam/test_apps/dvp/sdkconfig.ci.cache_safe

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,4 @@ CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
44
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
55
CONFIG_HAL_ASSERTION_SILENT=y
66

7-
CONFIG_CAM_CTLR_MIPI_CSI_ISR_CACHE_SAFE=y
8-
CONFIG_CAM_CTLR_ISP_DVP_ISR_CACHE_SAFE=y
97
CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE=y

components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
33
#
44
CONFIG_ESP_TASK_WDT_EN=n
5-
CONFIG_FREERTOS_HZ=1000
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CONFIG_IDF_TARGET="esp32s3"
2+
3+
CONFIG_SPIRAM=y
4+
CONFIG_SPIRAM_MODE_OCT=y

components/esp_lcd/i80/esp_lcd_panel_io_i80.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
199199
(uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev),
200200
LCD_LL_EVENT_TRANS_DONE, i80_lcd_default_isr_handler, bus, &bus->intr);
201201
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
202-
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts
202+
PERIPH_RCC_ATOMIC() {
203+
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts
204+
}
203205
lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt
204206
// install DMA service
205207
bus->max_transfer_bytes = bus_config->max_transfer_bytes;
@@ -215,8 +217,10 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
215217
lcd_ll_set_swizzle_mode(bus->hal.dev, LCD_LL_SWIZZLE_AB2BA);
216218
// number of data cycles is controlled by DMA buffer size
217219
lcd_ll_enable_output_always_on(bus->hal.dev, true);
218-
// enable trans done interrupt
219-
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, true);
220+
PERIPH_RCC_ATOMIC() {
221+
// enable trans done interrupt
222+
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, true);
223+
}
220224
// trigger a quick "trans done" event, and wait for the interrupt line goes active
221225
// this could ensure we go into ISR handler next time we call `esp_intr_enable`
222226
lcd_periph_trigger_quick_trans_done_event(bus);

0 commit comments

Comments
 (0)