ESP32-S3接OV5640出现“Failed to get the frame on time”以及“NO-SOI”、“NO-EOI”问题的定位过程与最终解决(3)

接前一篇文章:ESP32-S3接OV5640出现“Failed to get the frame on time”以及“NO-SOI”、“NO-EOI”问题的定位过程与最终解决(2)

 

上一回讲到跟进代码找到问题根源这条路并走不通,至少以目前对于OV5640和ESP32-S3的认知水平无法从源码中分析出根因。当前看来所有路都基本堵死了,到了“山重水复疑无路”的境地。那目前应该怎么办?这就是研发中的一个“窍门”了,直着走不行就绕着走。不是至少还有一个OV5640摄像头是好的嘛,就先用那个往下走,看一下正常拍照时候的流程,在这一过程中,也许就会对于流程有所熟悉,就有回过头来解决当前问题的可能性。

笔者用唯一能够初始化成功的那款OV5640摄像头,写了一个简单的拍照测试程序,代码片段如下:

void app_main(void)
{
    ……

    ESP_LOGI(TAG, "camera init");
    camera_init();
    vTaskDelay(20 / portTICK_PERIOD_MS);

    ESP_LOGI(TAG, "start to take picture");
    camera_fb_t *frame_buf = esp_camera_fb_get();
    if (!frame_buf)
    {
        ESP_LOGE(TAG, "camera capture failed");
        return;
    }
    ESP_LOGE(TAG, "camera capture succeeded");


    esp_camera_fb_return(frame_buf);
}

实测发现,虽然用这唯一的一款好的摄像头不会出现“Failed to get the frame on time”,但是通过肉眼就能观测到,调用esp_camera_fb_get()获取一帧图像时速度特别慢,3-4秒才能完成。这比前一版产品差了很多,前一版产品很快就会返回了。

这又是为什么呢?这就要跟进一下代码、一探究竟了。

esp_camera_fb_get函数在components/esp32-camera/driver/esp_camera.c中,代码如下:

camera_fb_t *esp_camera_fb_get(void)
{
    if (s_state == NULL) {
        return NULL;
    }

    camera_fb_t *fb = cam_take(FB_GET_TIMEOUT);
    //set the frame properties
    if (fb) {
        fb->width = resolution[s_state->sensor.status.framesize].width;
        fb->height = resolution[s_state->sensor.status.framesize].height;
        fb->format = s_state->sensor.pixformat;
    }

    return fb;
}

esp_camera_get()的核心函数是cam_take函数,这个cam_take函数可是“老朋友”了,上一回分析问题时就遇到过。这里为了便于理解和回顾,再贴一下其代码,在components/esp32-camera/driver/cam_hal.c中,如下:

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 (dma_buffer) {
        if(cam_obj->jpeg_mode){
            // find the end marker for JPEG. Data after that can be discarded
            int offset_e = cam_verify_jpeg_eoi(dma_buffer->buf, dma_buffer->len);
            if (offset_e >= 0) {
                // adjust buffer length
                dma_buffer->len = offset_e + sizeof(JPEG_EOI_MARKER);
                return dma_buffer;
            } else {
                ESP_LOGW(TAG, "NO-EOI");
                cam_give(dma_buffer);
                TickType_t ticks_spent = xTaskGetTickCount() - start;
                if (ticks_spent >= timeout) {
                    return NULL; /* We are out of time */
                }
                return cam_take(timeout - ticks_spent);//recurse!!!!
            }
        } else if(cam_obj->psram_mode && cam_obj->in_bytes_per_pixel != cam_obj->fb_bytes_per_pixel){
            //currently this is used only for YUV to GRAYSCALE
            dma_buffer->len = ll_cam_memcpy(cam_obj, dma_buffer->buf, dma_buffer->buf, dma_buffer->len);
        }
        return dma_buffer;
    } else {
        ESP_LOGW(TAG, "Failed to get the frame on time!");
    }
    return NULL;
}

上一回没有对于cam_take函数做过多解析,本回向前推进一点,看一下正常情况中的流程。这其中有一个超时参数timeout,它对用的实参为FB_GET_TIMEOUT。FB_GET_TIMEOUT宏在components/esp32-camera/driver/esp_camera.c中定义,如下:

#define FB_GET_TIMEOUT (4000 / portTICK_PERIOD_MS)

也就是说,超时时间为4000毫秒即4秒。那么成功的情况下,确实是在4秒以内得到了图像。只是理论上应该很快的,因为即使是2560x1440分辨率的情况下,帧率也有15帧,不可能2~3秒才获取到。

9ded3a998aa444a78e486959e0c2ed0b.png

这都是乐鑫库中的现成代码了,理论上不会出现这种问题。因此不能怀疑、至少目前不能怀疑是软件代码的问题。

到这里,我们在“山重水复”的情况下,往前走了一点,好像感觉更走到“山穷水尽”的地步了。但笔者反倒有了一丝看到了“柳岸花明”的感觉。笔者在这里把这个过程写得很细,希望读者也能跟随笔者一起体验这个过程,不光是过程,还有当时的心境。

接下来该如何从“山重水复疑无路”到“柳暗花明又一村”?请看下回。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝天居士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值