diff --git a/driver/cam_hal.c b/driver/cam_hal.c index b65cdac8d0..89982b6065 100644 --- a/driver/cam_hal.c +++ b/driver/cam_hal.c @@ -242,9 +242,15 @@ static bool cam_start_frame(int * frame_pos) return false; } -void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken) +void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t *hp) { - if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) { + if (!cam->event_queue) { + // ESP_DRAM_LOGD(TAG, "drop event: queue deleted"); + return; + } + + BaseType_t woken = pdFALSE; + if (xQueueSendFromISR(cam->event_queue, &cam_event, &woken) != pdTRUE) { ll_cam_stop(cam); cam->state = CAM_STATE_IDLE; #if CAM_LOG_SPAM_EVERY_FRAME @@ -255,6 +261,10 @@ void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType cam_event==CAM_IN_SUC_EOF_EVENT ? "EV-EOF-OVF" : "EV-VSYNC-OVF"); #endif } + + if (hp && woken) { + *hp = pdTRUE; + } } //Copy fram from DMA dma_buffer to fram dma_buffer @@ -633,15 +643,17 @@ esp_err_t cam_deinit(void) return ESP_FAIL; } - cam_stop(); + cam_stop(); // disable VSYNC and DMA before deleting queues if (cam_obj->task_handle) { vTaskDelete(cam_obj->task_handle); } if (cam_obj->event_queue) { vQueueDelete(cam_obj->event_queue); + cam_obj->event_queue = NULL; } if (cam_obj->frame_buffer_queue) { vQueueDelete(cam_obj->frame_buffer_queue); + cam_obj->frame_buffer_queue = NULL; } ll_cam_deinit(cam_obj); diff --git a/target/esp32s3/ll_cam.c b/target/esp32s3/ll_cam.c index b54445521b..8a622a01bd 100644 --- a/target/esp32s3/ll_cam.c +++ b/target/esp32s3/ll_cam.c @@ -68,7 +68,7 @@ void ll_cam_dma_print_state(cam_obj_t *cam) 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_clr.val = 0xFFFFFFFFU; // register is W1C; mask covers all sources GDMA.channel[cam->dma_num].in.int_ena.val = 0; GDMA.channel[cam->dma_num].in.conf0.val = 0; @@ -94,7 +94,7 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) { //DBG_PIN_SET(1); cam_obj_t *cam = (cam_obj_t *)arg; - BaseType_t HPTaskAwoken = pdFALSE; + BaseType_t hp = pdFALSE; typeof(LCD_CAM.lc_dma_int_st) status = LCD_CAM.lc_dma_int_st; if (status.val == 0) { @@ -104,10 +104,10 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) LCD_CAM.lc_dma_int_clr.val = status.val; if (status.cam_vsync_int_st) { - ll_cam_send_event(cam, CAM_VSYNC_EVENT, &HPTaskAwoken); + ll_cam_send_event(cam, CAM_VSYNC_EVENT, &hp); } - if (HPTaskAwoken == pdTRUE) { + if (hp == pdTRUE) { portYIELD_FROM_ISR(); } //DBG_PIN_SET(0); @@ -116,7 +116,7 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg) { cam_obj_t *cam = (cam_obj_t *)arg; - BaseType_t HPTaskAwoken = pdFALSE; + BaseType_t hp = pdFALSE; typeof(GDMA.channel[cam->dma_num].in.int_st) status = GDMA.channel[cam->dma_num].in.int_st; if (status.val == 0) { @@ -126,20 +126,19 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg) GDMA.channel[cam->dma_num].in.int_clr.val = status.val; if (status.in_suc_eof) { - ll_cam_send_event(cam, CAM_IN_SUC_EOF_EVENT, &HPTaskAwoken); + ll_cam_send_event(cam, CAM_IN_SUC_EOF_EVENT, &hp); } - if (HPTaskAwoken == pdTRUE) { + if (hp == pdTRUE) { portYIELD_FROM_ISR(); } } bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam) { - if (cam->jpeg_mode || !cam->psram_mode) { - GDMA.channel[cam->dma_num].in.int_ena.in_suc_eof = 0; - GDMA.channel[cam->dma_num].in.int_clr.in_suc_eof = 1; - } + GDMA.channel[cam->dma_num].in.int_ena.val = 0; + GDMA.channel[cam->dma_num].in.int_clr.val = 0xFFFFFFFFU; // register is W1C; mask covers all sources + LCD_CAM.cam_ctrl1.cam_start = 0; GDMA.channel[cam->dma_num].in.link.stop = 1; return true; } @@ -148,10 +147,10 @@ bool ll_cam_start(cam_obj_t *cam, int frame_pos) { LCD_CAM.cam_ctrl1.cam_start = 0; - if (cam->jpeg_mode || !cam->psram_mode) { - GDMA.channel[cam->dma_num].in.int_clr.in_suc_eof = 1; - GDMA.channel[cam->dma_num].in.int_ena.in_suc_eof = 1; - } + GDMA.channel[cam->dma_num].in.int_ena.val = 0; + GDMA.channel[cam->dma_num].in.int_clr.val = 0xFFFFFFFFU; // register is W1C; mask covers all sources + GDMA.channel[cam->dma_num].in.int_clr.in_suc_eof = 1; // redundant but explicit + GDMA.channel[cam->dma_num].in.int_ena.in_suc_eof = 1; // only EOF interrupt is re-enabled LCD_CAM.cam_ctrl1.cam_reset = 1; LCD_CAM.cam_ctrl1.cam_reset = 0; diff --git a/target/private_include/ll_cam.h b/target/private_include/ll_cam.h index df6135f27e..2d6aa7f3ae 100644 --- a/target/private_include/ll_cam.h +++ b/target/private_include/ll_cam.h @@ -140,7 +140,7 @@ typedef struct { #endif uint32_t fb_size; - cam_state_t state; + volatile cam_state_t state; } cam_obj_t; @@ -162,4 +162,4 @@ 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); +void ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t *hp);