ESP32之esp_camera分析(一)

初始化分析,首先定义一个camera_config_t类型的结构体变量,然后给结构中的成员赋值,再调用err = esp_camera_init(&camera_config);函数进行初始化,代码如下:

    esp_err_t err;

	camera_config_t camera_config = {
		.pin_pwdn = CAM_PWDN,
		.pin_reset = CAM_RET,
		.pin_xclk = CAM_XCLK,
		.pin_sscb_sda = CAM_SDA,
		.pin_sscb_scl = CAM_SCL,

		.pin_d7 = CAM_D7,
		.pin_d6 = CAM_D6,
		.pin_d5 = CAM_D5,
		.pin_d4 = CAM_D4,
		.pin_d3 = CAM_D3,
		.pin_d2 = CAM_D2,
		.pin_d1 = CAM_D1,
		.pin_d0 = CAM_D0,
		.pin_vsync = CAM_VSYNC,
		.pin_href = CAM_HSYNC,
		.pin_pclk = CAM_PCLK,

		//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
		.xclk_freq_hz = 24000000,
		.ledc_timer = LEDC_TIMER_0,
		.ledc_channel = LEDC_CHANNEL_0,
#ifdef CONFIG_CAMERA_JPEG_MODE
		.pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG
#else
		.pixel_format = PIXFORMAT_GRAYSCALE,
#endif
		.frame_size = FRAMESIZE_QVGA,	 //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
		.jpeg_quality = 12, //0-63 lower number means higher quality
		.fb_count = 2,		//if more than one, i2s runs in continuous mode. Use only with JPEG
		.grab_mode = CAMERA_GRAB_WHEN_EMPTY//CAMERA_GRAB_LATEST. Sets when buffers should be filled
	};
	//initialize the camera
	err = esp_camera_init(&camera_config);

esp_camera_init()函数过程分析,调用cam_init()初始化camera外设;接着调用camera_probe()检测sensor是否存在,如果存在,则对senor进行初始化,包括硬件复位,通过i2c接口对寄存器初始化;接着调用cam_config(),设置窗口模式,初始化cam_obj结构,创建cam_task任务并启动;最后调用cam_start()使能vsync_pin的中断接收服务,vsync为帧同步信号。

esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint16_t sensor_pid)
{
    CAM_CHECK(NULL != config, "config pointer is invalid", ESP_ERR_INVALID_ARG);
    esp_err_t ret = ESP_OK;

    ret = ll_cam_set_sample_mode(cam_obj, (pixformat_t)config->pixel_format, config->xclk_freq_hz, sensor_pid);

    cam_obj->jpeg_mode = config->pixel_format == PIXFORMAT_JPEG;
#if CONFIG_IDF_TARGET_ESP32
    cam_obj->psram_mode = false;
#else
    cam_obj->psram_mode = (config->xclk_freq_hz == 16000000);
#endif
    cam_obj->frame_cnt = config->fb_count;
    cam_obj->width = resolution[frame_size].width;
    cam_obj->height = resolution[frame_size].height;

    if(cam_obj->jpeg_mode){
        cam_obj->recv_size = cam_obj->width * cam_obj->height / 5;
        cam_obj->fb_size = cam_obj->recv_size;
    } else {
        cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel;
        cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
    }
    
    ret = cam_dma_config(config);
    CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);

    cam_obj->event_queue = xQueueCreate(cam_obj->dma_half_buffer_cnt - 1, sizeof(cam_event_t));
    CAM_CHECK_GOTO(cam_obj->event_queue != NULL, "event_queue create failed", err);

    size_t frame_buffer_queue_len = cam_obj->frame_cnt;
    if (config->grab_mode == CAMERA_GRAB_LATEST && cam_obj->frame_cnt > 1) {
        frame_buffer_queue_len = cam_obj->frame_cnt - 1;
    }
    cam_obj->frame_buffer_queue = xQueueCreate(frame_buffer_queue_len, sizeof(camera_fb_t*));
    CAM_CHECK_GOTO(cam_obj->frame_buffer_queue != NULL, "frame_buffer_queue create failed", err);

    ret = ll_cam_init_isr(cam_obj);
    CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);

    
#if CONFIG_CAMERA_CORE0
    xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
#elif CONFIG_CAMERA_CORE1
    xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
#else
    xTaskCreate(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
#endif

    ESP_LOGI(TAG, "cam config ok");
    return ESP_OK;

err:
    cam_deinit();
    return ESP_FAIL;
}

cam_config()中有一句代码设置是否使用PSRAM方式,如果是ESP32-S2处理器,xclk_freq_hz为16000000Hz,则使用PSRAM方式。

esp_camera_init()之后,sensor会不断的输出图像,cam_task任务会不断的被唤醒。

ESP32/8266技术交流QQ群:1018891543

你可能感兴趣的:(ESP32/ESP8266,ESP32,camera,mcu)