当前位置: 首页 > news >正文

ESP32-S3模组上跑通esp32-camera(16)

接前一篇文章:ESP32-S3模组上跑通esp32-camera(15)

 

本文内容参考:

esp32-camera入门(基于ESP-IDF)_esp32 camera-CSDN博客

OV5640手册解读-CSDN博客

ESP32_CAM CameraWebServer例程源码解析笔记(一)_void startcameraserver();-CSDN博客

esp32-cam驱动程序阅读 - 哔哩哔哩

特此致谢!

 

一、OV5640初始化

2. 相机初始化及图像传感器配置

上一回解析完了ll_cam_set_pin函数。本回回到cam_init函数中,继续解析后续代码。为了便于理解和回顾,再次贴出cam_init函数代码,在components\esp32-camera\driver\cam_hal.c中,如下:

​esp_err_t cam_init(const camera_config_t *config)
{CAM_CHECK(NULL != config, "config pointer is invalid", ESP_ERR_INVALID_ARG);esp_err_t ret = ESP_OK;cam_obj = (cam_obj_t *)heap_caps_calloc(1, sizeof(cam_obj_t), MALLOC_CAP_DMA);CAM_CHECK(NULL != cam_obj, "lcd_cam object malloc error", ESP_ERR_NO_MEM);cam_obj->swap_data = 0;cam_obj->vsync_pin = config->pin_vsync;cam_obj->vsync_invert = true;ll_cam_set_pin(cam_obj, config);ret = ll_cam_config(cam_obj, config);CAM_CHECK_GOTO(ret == ESP_OK, "ll_cam initialize failed", err);#if CAMERA_DBG_PIN_ENABLEPIN_FUNC_SELECT(GPIO_PIN_MUX_REG[DBG_PIN_NUM], PIN_FUNC_GPIO);gpio_set_direction(DBG_PIN_NUM, GPIO_MODE_OUTPUT);gpio_set_pull_mode(DBG_PIN_NUM, GPIO_FLOATING);
#endifESP_LOGI(TAG, "cam init ok");return ESP_OK;err:free(cam_obj);cam_obj = NULL;return ESP_FAIL;
}

接下来是以下代码片段:

    ret = ll_cam_config(cam_obj, config);CAM_CHECK_GOTO(ret == ESP_OK, "ll_cam initialize failed", err);

ll_cam_config函数也在components\esp32-camera\target\esp32s3\ll_cam.c中,代码如下:

esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
{esp_err_t ret = ESP_OK;if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN) == 0) {REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST);REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST);}LCD_CAM.cam_ctrl.val = 0;LCD_CAM.cam_ctrl.cam_clkm_div_b = 0;LCD_CAM.cam_ctrl.cam_clkm_div_a = 0;LCD_CAM.cam_ctrl.cam_clkm_div_num = 160000000 / config->xclk_freq_hz;LCD_CAM.cam_ctrl.cam_clk_sel = 3;//Select Camera module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: no clock.LCD_CAM.cam_ctrl.cam_stop_en = 0;LCD_CAM.cam_ctrl.cam_vsync_filter_thres = 4; // Filter by LCD_CAM clockLCD_CAM.cam_ctrl.cam_update = 0;LCD_CAM.cam_ctrl.cam_byte_order = cam->swap_data;LCD_CAM.cam_ctrl.cam_bit_order = 0;LCD_CAM.cam_ctrl.cam_line_int_en = 0;LCD_CAM.cam_ctrl.cam_vs_eof_en = 0; //1: CAM_VSYNC to generate in_suc_eof. 0: in_suc_eof is controlled by reg_cam_rec_data_cyclelenLCD_CAM.cam_ctrl1.val = 0;LCD_CAM.cam_ctrl1.cam_rec_data_bytelen = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - 1; // Cannot be assigned to 0, and it is easy to overflowLCD_CAM.cam_ctrl1.cam_line_int_num = 0; // The number of hsyncs that generate hs interruptsLCD_CAM.cam_ctrl1.cam_clk_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_filter_en = 1;LCD_CAM.cam_ctrl1.cam_2byte_en = 0;LCD_CAM.cam_ctrl1.cam_de_inv = 0;LCD_CAM.cam_ctrl1.cam_hsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vh_de_mode_en = 0;LCD_CAM.cam_rgb_yuv.val = 0;#if CONFIG_CAMERA_CONVERTER_ENABLEDif (config->conv_mode) {ret = ll_cam_converter_config(cam, config);if(ret != ESP_OK) {return ret;}}
#endifLCD_CAM.cam_ctrl.cam_update = 1;LCD_CAM.cam_ctrl1.cam_start = 1;ret = ll_cam_dma_init(cam);return ret;
}

ll_cam_config函数比较长,仍然是一段一段来看。先来看第1段:

    if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN) == 0) {REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST);REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST);}

SYSTEM_PERIP_CLK_EN1_REG宏定义在工程目录下搜索是搜不到的,需要在ESP-IDF的安装路径下搜索才能找到。是在soc\esp32s3\include\soc\system_reg.h中,定义如下:

/** SYSTEM_PERIP_CLK_EN1_REG register*  peripheral clock gating register*/
#define SYSTEM_PERIP_CLK_EN1_REG (DR_REG_SYSTEM_BASE + 0x14)

SYSTEM_LCD_CAM_CLK_EN宏也是在soc\esp32s3\include\soc\system_reg.h中,定义如下:

/* SYSTEM_LCD_CAM_CLK_EN : R/W ;bitpos:[8] ;default: 1'b0 ; */
/*description: .*/
#define SYSTEM_LCD_CAM_CLK_EN    (BIT(8))
#define SYSTEM_LCD_CAM_CLK_EN_M  (BIT(8))
#define SYSTEM_LCD_CAM_CLK_EN_V  0x1
#define SYSTEM_LCD_CAM_CLK_EN_S  8

SYSTEM_PERIP_RST_EN1_REG宏也是在soc\esp32s3\include\soc\system_reg.h中,定义如下:

#define SYSTEM_PERIP_RST_EN1_REG          (DR_REG_SYSTEM_BASE + 0x24)

SYSTEM_LCD_CAM_RST宏也是在soc\esp32s3\include\soc\system_reg.h中,定义如下:

/* SYSTEM_LCD_CAM_RST : R/W ;bitpos:[8] ;default: 1'b1 ; */
/*description: .*/
#define SYSTEM_LCD_CAM_RST    (BIT(8))
#define SYSTEM_LCD_CAM_RST_M  (BIT(8))
#define SYSTEM_LCD_CAM_RST_V  0x1
#define SYSTEM_LCD_CAM_RST_S  8

由于这部分内容不是本系列重点,因此这里就不深入分析了,从字面意思上就能知道这段代码的作用:使能ESP32-S3 camera接口的时钟,以及进行复位。

接下来是第2段代码片段:

    LCD_CAM.cam_ctrl.val = 0;LCD_CAM.cam_ctrl.cam_clkm_div_b = 0;LCD_CAM.cam_ctrl.cam_clkm_div_a = 0;LCD_CAM.cam_ctrl.cam_clkm_div_num = 160000000 / config->xclk_freq_hz;LCD_CAM.cam_ctrl.cam_clk_sel = 3;//Select Camera module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: no clock.LCD_CAM.cam_ctrl.cam_stop_en = 0;LCD_CAM.cam_ctrl.cam_vsync_filter_thres = 4; // Filter by LCD_CAM clockLCD_CAM.cam_ctrl.cam_update = 0;LCD_CAM.cam_ctrl.cam_byte_order = cam->swap_data;LCD_CAM.cam_ctrl.cam_bit_order = 0;LCD_CAM.cam_ctrl.cam_line_int_en = 0;LCD_CAM.cam_ctrl.cam_vs_eof_en = 0; //1: CAM_VSYNC to generate in_suc_eof. 0: in_suc_eof is controlled by reg_cam_rec_data_cyclelenLCD_CAM.cam_ctrl1.val = 0;LCD_CAM.cam_ctrl1.cam_rec_data_bytelen = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - 1; // Cannot be assigned to 0, and it is easy to overflowLCD_CAM.cam_ctrl1.cam_line_int_num = 0; // The number of hsyncs that generate hs interruptsLCD_CAM.cam_ctrl1.cam_clk_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_filter_en = 1;LCD_CAM.cam_ctrl1.cam_2byte_en = 0;LCD_CAM.cam_ctrl1.cam_de_inv = 0;LCD_CAM.cam_ctrl1.cam_hsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vh_de_mode_en = 0;LCD_CAM.cam_rgb_yuv.val = 0;#if CONFIG_CAMERA_CONVERTER_ENABLEDif (config->conv_mode) {ret = ll_cam_converter_config(cam, config);if(ret != ESP_OK) {return ret;}}
#endifLCD_CAM.cam_ctrl.cam_update = 1;LCD_CAM.cam_ctrl1.cam_start = 1;

这个LCD_CAM笔者在当前工程下没有搜索到,满以为在ESP-IDF安装目录下能够搜索到,结果也没有搜索到,只是搜到了一处外部引用代码,在components\soc\esp32s3\include\soc\lcd_cam_struct.h中,如下:

extern lcd_cam_dev_t LCD_CAM;

笔者推测,LCD_CAM可能引自于components\soc\esp32s3\ld\esp32s3.peripherals.ld文件:

bcf82a2b19bb454786763986c62a43f6.png

而0x60041000正好就是DR_REG_LCD_CAM_BASE,即LCD_CAM系列寄存器的基地址。

7651a22624334ce3bacf3c07b4d8c4e8.png

LCD_CAM的类型是lcd_cam_dev_t,其在components\soc\esp32s3\include\soc\lcd_cam_struct.h中定义(就在外部引用LCD_CAM那一行的上边),如下:

typedef struct lcd_cam_dev_t {volatile lcd_cam_lcd_clock_reg_t lcd_clock;volatile lcd_cam_cam_ctrl_reg_t cam_ctrl;volatile lcd_cam_cam_ctrl1_reg_t cam_ctrl1;volatile lcd_cam_cam_rgb_yuv_reg_t cam_rgb_yuv;volatile lcd_cam_lcd_rgb_yuv_reg_t lcd_rgb_yuv;volatile lcd_cam_lcd_user_reg_t lcd_user;volatile lcd_cam_lcd_misc_reg_t lcd_misc;volatile lcd_cam_lcd_ctrl_reg_t lcd_ctrl;volatile lcd_cam_lcd_ctrl1_reg_t lcd_ctrl1;volatile lcd_cam_lcd_ctrl2_reg_t lcd_ctrl2;volatile lcd_cam_lcd_cmd_val_reg_t lcd_cmd_val;uint32_t reserved_02c;volatile lcd_cam_lcd_dly_mode_reg_t lcd_dly_mode;uint32_t reserved_034;volatile lcd_cam_lcd_data_dout_mode_reg_t lcd_data_dout_mode;uint32_t reserved_03c[10];volatile lcd_cam_lc_dma_int_ena_reg_t lc_dma_int_ena;volatile lcd_cam_lc_dma_int_raw_reg_t lc_dma_int_raw;volatile lcd_cam_lc_dma_int_st_reg_t lc_dma_int_st;volatile lcd_cam_lc_dma_int_clr_reg_t lc_dma_int_clr;uint32_t reserved_074[34];volatile lcd_cam_lc_reg_date_reg_t lc_reg_date;
} lcd_cam_dev_t;

根据定义的形式以及上边那个基地址,可以推断出,这个lcd_cam_dev_t LCD_CAM实际上就是一个指向LCD_CAM寄存器基地址的值(注意,并不是指针),其各个成员实际就指向了LCD_CAM寄存器组中的各个寄存器(定义是按照顺序来的)。

那么,上边这一段代码片段的意思就是:

    LCD_CAM.cam_ctrl.val = 0;LCD_CAM.cam_ctrl.cam_clkm_div_b = 0;LCD_CAM.cam_ctrl.cam_clkm_div_a = 0;LCD_CAM.cam_ctrl.cam_clkm_div_num = 160000000 / config->xclk_freq_hz;LCD_CAM.cam_ctrl.cam_clk_sel = 3;//Select Camera module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: no clock.LCD_CAM.cam_ctrl.cam_stop_en = 0;LCD_CAM.cam_ctrl.cam_vsync_filter_thres = 4; // Filter by LCD_CAM clockLCD_CAM.cam_ctrl.cam_update = 0;LCD_CAM.cam_ctrl.cam_byte_order = cam->swap_data;LCD_CAM.cam_ctrl.cam_bit_order = 0;LCD_CAM.cam_ctrl.cam_line_int_en = 0;LCD_CAM.cam_ctrl.cam_vs_eof_en = 0; //1: CAM_VSYNC to generate in_suc_eof. 0: in_suc_eof is controlled by reg_cam_rec_data_cyclelenLCD_CAM.cam_ctrl1.val = 0;LCD_CAM.cam_ctrl1.cam_rec_data_bytelen = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - 1; // Cannot be assigned to 0, and it is easy to overflowLCD_CAM.cam_ctrl1.cam_line_int_num = 0; // The number of hsyncs that generate hs interruptsLCD_CAM.cam_ctrl1.cam_clk_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_filter_en = 1;LCD_CAM.cam_ctrl1.cam_2byte_en = 0;LCD_CAM.cam_ctrl1.cam_de_inv = 0;LCD_CAM.cam_ctrl1.cam_hsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vsync_inv = 0;LCD_CAM.cam_ctrl1.cam_vh_de_mode_en = 0;LCD_CAM.cam_rgb_yuv.val = 0;#if CONFIG_CAMERA_CONVERTER_ENABLEDif (config->conv_mode) {ret = ll_cam_converter_config(cam, config);if(ret != ESP_OK) {return ret;}}
#endifLCD_CAM.cam_ctrl.cam_update = 1;LCD_CAM.cam_ctrl1.cam_start = 1;

给寄存器组中的各个寄存器(的对应位)赋值。

ll_cam_config函数的后续代码,在下一回中继续解析。

 


http://www.mrgr.cn/news/74711.html

相关文章:

  • go语言使用总结(持续更新)
  • 【机器学习】数学知识:标准差,方差,协方差,平均数,中位数,众数
  • odoo17 owl 前端 顶部导航栏右侧添加自定义按钮
  • VScode下脚本被禁止运行的原因及解决方案
  • 计算机代码python代做matlab编程c语言编写接单matlabqt开发java
  • MDBook 使用指南
  • 基于51单片机的高压蒸汽灭菌自动控制器proteus仿真
  • 远程踏勘系统(源码+文档+部署+讲解)
  • 浅谈C#之多线程流式适配器
  • 返校宣讲活动总结记录
  • cesium特效扩散圆
  • springboot濒危野生植物信息管理系统-计算机毕业设计源码06463
  • 使用Python实现对接Hadoop集群(通过Hive)并提供API接口
  • 丹摩征文活动|Llama3.1:零障碍部署,尽享无忧使用!
  • 鸿蒙学习基本概念
  • 【go从零单排】Spawning Processes 、Exec‘ing Processes
  • 01、Spring MVC入门程序
  • 室内定位论文精华-无人机与机器人在地下与室内环境中的自主导航与定位新技术
  • 高阶智驾「血拼」,跨域融合开启淘汰,谁会冲出重围,谁将出局?
  • RocketMQ-02 集群架构部署
  • jenkins使用cli发行uni-app到h5
  • ChatGPT提问prompt范例模板
  • ArkTs面向对象编程
  • 网络基础协议理论(SSH协议)
  • 校友会系统的实现ssm+论文源码调试讲解
  • PHP Session