Skip to content

Create workaround for DMA failing on ESP32-S3 when WiFi is started #625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 23, 2024
Merged
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
13 changes: 13 additions & 0 deletions driver/cam_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,16 @@ camera_fb_t *cam_take(TickType_t timeout)
camera_fb_t *dma_buffer = NULL;
TickType_t start = xTaskGetTickCount();
xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout);
#if CONFIG_IDF_TARGET_ESP32S3
// Currently (22.01.2024) there is a bug in ESP-IDF v5.2, that causes
// GDMA to fall into a strange state if it is running while WiFi STA is connecting.
// This code tries to reset GDMA if frame is not received, to try and help with
// this case. It is possible to have some side effects too, though none come to mind
if (!dma_buffer) {
ll_cam_dma_reset(cam_obj);
xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout);
}
#endif
if (dma_buffer) {
if(cam_obj->jpeg_mode){
// find the end marker for JPEG. Data after that can be discarded
Expand All @@ -498,6 +508,9 @@ camera_fb_t *cam_take(TickType_t timeout)
return dma_buffer;
} else {
ESP_LOGW(TAG, "Failed to get the frame on time!");
// #if CONFIG_IDF_TARGET_ESP32S3
// ll_cam_dma_print_state(cam_obj);
// #endif
}
return NULL;
}
Expand Down
70 changes: 49 additions & 21 deletions target/esp32s3/ll_cam.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,54 @@

static const char *TAG = "s3 ll_cam";

void ll_cam_dma_print_state(cam_obj_t *cam)
{
esp_rom_printf("dma_infifo_status[%u] :\n", cam->dma_num);
esp_rom_printf(" infifo_full_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l1);
esp_rom_printf(" infifo_empty_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l1);
esp_rom_printf(" infifo_full_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l2);
esp_rom_printf(" infifo_empty_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l2);
esp_rom_printf(" infifo_full_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l3);
esp_rom_printf(" infifo_empty_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l3);
esp_rom_printf(" infifo_cnt_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l1);
esp_rom_printf(" infifo_cnt_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l2);
esp_rom_printf(" infifo_cnt_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l3);
esp_rom_printf(" in_remain_under_1b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_1b_l3);
esp_rom_printf(" in_remain_under_2b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_2b_l3);
esp_rom_printf(" in_remain_under_3b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_3b_l3);
esp_rom_printf(" in_remain_under_4b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_4b_l3);
esp_rom_printf(" in_buf_hungry : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_buf_hungry);
esp_rom_printf("dma_state[%u] :\n", cam->dma_num);
esp_rom_printf(" dscr_addr : 0x%lx\n", GDMA.channel[cam->dma_num].in.state.dscr_addr);
esp_rom_printf(" in_dscr_state : %lu\n", GDMA.channel[cam->dma_num].in.state.in_dscr_state);
esp_rom_printf(" in_state : %lu\n", GDMA.channel[cam->dma_num].in.state.in_state);
}

void ll_cam_dma_reset(cam_obj_t *cam)
{

GDMA.channel[cam->dma_num].in.int_clr.val = ~0;
GDMA.channel[cam->dma_num].in.int_ena.val = 0;

GDMA.channel[cam->dma_num].in.conf0.val = 0;
GDMA.channel[cam->dma_num].in.conf0.in_rst = 1;
GDMA.channel[cam->dma_num].in.conf0.in_rst = 0;

//internal SRAM only
if (!cam->psram_mode) {
GDMA.channel[cam->dma_num].in.conf0.indscr_burst_en = 1;
GDMA.channel[cam->dma_num].in.conf0.in_data_burst_en = 1;
}

GDMA.channel[cam->dma_num].in.conf1.in_check_owner = 0;
// GDMA.channel[cam->dma_num].in.conf1.in_ext_mem_bk_size = 2;

GDMA.channel[cam->dma_num].in.peri_sel.sel = 5;
//GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15
//GDMA.channel[cam->dma_num].in.sram_size.in_size = 6;//This register is used to configure the size of L2 Tx FIFO for Rx channel. 0:16 bytes, 1:24 bytes, 2:32 bytes, 3: 40 bytes, 4: 48 bytes, 5:56 bytes, 6: 64 bytes, 7: 72 bytes, 8: 80 bytes.
//GDMA.channel[cam->dma_num].in.wight.rx_weight = 7;//The weight of Rx channel 0-15
}

static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
{
//DBG_PIN_SET(1);
Expand Down Expand Up @@ -164,27 +212,7 @@ static esp_err_t ll_cam_dma_init(cam_obj_t *cam)
REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST);
REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST);
}

GDMA.channel[cam->dma_num].in.int_clr.val = ~0;
GDMA.channel[cam->dma_num].in.int_ena.val = 0;

GDMA.channel[cam->dma_num].in.conf0.val = 0;
GDMA.channel[cam->dma_num].in.conf0.in_rst = 1;
GDMA.channel[cam->dma_num].in.conf0.in_rst = 0;

//internal SRAM only
if (!cam->psram_mode) {
GDMA.channel[cam->dma_num].in.conf0.indscr_burst_en = 1;
GDMA.channel[cam->dma_num].in.conf0.in_data_burst_en = 1;
}

GDMA.channel[cam->dma_num].in.conf1.in_check_owner = 0;
// GDMA.channel[cam->dma_num].in.conf1.in_ext_mem_bk_size = 2;

GDMA.channel[cam->dma_num].in.peri_sel.sel = 5;
//GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15
//GDMA.channel[cam->dma_num].in.sram_size.in_size = 6;//This register is used to configure the size of L2 Tx FIFO for Rx channel. 0:16 bytes, 1:24 bytes, 2:32 bytes, 3: 40 bytes, 4: 48 bytes, 5:56 bytes, 6: 64 bytes, 7: 72 bytes, 8: 80 bytes.
//GDMA.channel[cam->dma_num].in.wight.rx_weight = 7;//The weight of Rx channel 0-15
ll_cam_dma_reset(cam);
return ESP_OK;
}

Expand Down
4 changes: 4 additions & 0 deletions target/private_include/ll_cam.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
bool ll_cam_dma_sizes(cam_obj_t *cam);
size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid);
#if CONFIG_IDF_TARGET_ESP32S3
void ll_cam_dma_print_state(cam_obj_t *cam);
void ll_cam_dma_reset(cam_obj_t *cam);
#endif

// implemented in cam_hal
void ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken);