一、硬件资源

OV7725添加了一个型号为AL422B的FIFO,英文全称为:First in first out。用于缓冲数据,AL422B的本质是一种RAM存储器,容量大小为393216字节,支持同时写入和读取。
这就是FIFO的原理图了:

以下是它的引脚功能图:
| DI[0:7] |
数据输入引脚 |
|---|
| WCK |
数据输入同步时钟 |
| /WE |
写使能信号,低电平有效 |
| /WRST |
写指针复位信号,低电平有效 |
| DO[0:7] |
数据输出引脚 |
| RCK |
数据输出同步时钟 |
| /RE |
读使能信号,低电平有效 |
| /RRST |
读指针复位信号,低电平有效 |
| /OE |
数据输出使能,低电平有效 |
| TST |
测试引脚,实际使用时设置成低电平 |
1、写时序
在写时序中,当 WE 管脚为低电平时,FIFO 写入处于使能状态,随着读时钟 WCK 的运转, DI[0:7]表示的数据将会就会按地址递增的方式存入 FIFO;当 WE 管脚为高电平时,关闭输入,DI[0:7]的数据不会被写入 FIFO。 在控制写入数据时,一般会先控制写指针作一个复位操作:把 WRST 设置为低电平,写指针会复位到 FIFO 的 0 地址,然后 FIFO 接收到的数据会从该地址开始按自增的方式写入。

2、读时序
FIFO 的读时序类似,不过读使能由两个引脚共同控制,即 OE 和 RE 引脚均为低电平时,输出处于使能状态,随着读时钟 RCK 的运转,在数据输出管脚 DO[0:7]就会按地址递增的方式输出数据。类似地,在控制读出数据时,一般会先控制读指针作一个复位操作:把 RRST 设置为低电平,读指针会复位到 FIFO 的 0 地址,然后 FIFO 数据从该地址开始按自增的方式输出。

二、摄像头的驱动原理
OV7725中包含有FIFO,所以外部控制器驱动摄像头时,需要协调好FIFIO与OV7725之间的关系。
摄像头引出的接口包含了 OV7725 传感器及 FIFO 的混合引脚,外部的控制器使用这些引脚即可驱动摄像头。如下图:

1、摄像头的引出接口
(1)与 OV7725 传感器像素输出相关的 PCLK 和 D[0:7]并没有引出,因为这些引脚被连接到了 FIFO 的输入部分,OV7725 的像 素输出时序与 FIFO 的写入数据时序是一致的,所以在 OV7725 时钟 PCLK 的驱动下,它输出的数据会一个字节一个字节地被 FIFO 接收并存储起来。
(2)其中最为特殊的是 WEN 引脚,它与 OV7725 的 HREF 连接到一个与非门的输入,与非门的输出连接到 FIFO 的 WE 引脚,因此,当 WEN 与 HREF 均为高电平时,FIFO 的 WE为低电平,此时允许 OV7725 向 FIFO 写入数据。
(3)外部控制器通过控制 WEN 引脚,可防止 OV7725 覆盖了还未被控制器读出的旧 FIFO数据。另外,在 OV7725 输出时序中,只有当 HREF 为高电平时,PCLK 驱动下 D[0:7]线表示的才是有效像素数据,因此,利用 HREF 控制 FIFO 的 WE 可以确保只有有效数据才被写入到 FIFO 中。
2、配合摄像头的原理图,以及OV7725、FIFO的时序,可以总结出摄像头菜鸡数据的过程如下:
(1)利用 SIO_C、SIO_D 引脚通过 SCCB 协议向 OV7725 的寄存器写入初始化配置;
(2)初始化完成后,OV7725 传感器会使用 VGA 时序输出图像数据,它的 VSYNC 会首先输出帧有效信号(低电平跳变),当外部的控制器(如 STM32)检测到该信 号时,把 WEN 引脚设置为高电平,并且使用 WRST 引脚复位 FIFO 的写指针到 0 地址;
(3)随着 OV7725 继续按 VGA 时序输出图像数据,它在传输每行有效数据时, HREF引脚都会持续输出高电平,由于 WEN 和 HREF 同时为高电平输入至与非门,使 得其连接到 FIFO WE 引脚的输出为低电平,允许向 FIFO 写入数据,所以在这期
间,OV7725 通过它的 PCLK 和 D[0:7]信号线把图像数据存储到 FIFO 中,由于前
面复位了写指针,所以图像数据是从 FIFO 的 0 地址开始记录的;
(4)各行图像数据持续传输至 FIFO,受 HREF 控制的 WE 引脚确保了写入到 FIFO 中的都是有效的图像数据,OV7725 输出完一帧数据时,VSYNC 会再次输出帧有效
信号,表示一帧图像已输出完成;
(5)控制器检测到上述 VSYNC 信号后,可知 FIFO 中已存储好一帧图像数据,这时控制 WEN 引脚为低电平,使得 FIFO 禁止写入,防止 OV7725 持续输出的下一帧数据覆盖当前 FIFO 数据;
(6)控制器使用 RRST 复位读指针到 FIFO 的 0 地址,然后通过 FIFO 的 RCLK 和DO[0:7]引脚,从 0 地址开始把 FIFO 缓存的整帧图像数据读取出来。在这期间,OV7725 是持续输出它采集到的图像数据的,但由于禁止写入 FIFO,这些数据被丢弃了;
(7)控制器使用 WRST 复位写指针到 FIFO 的 0 地址,然后等待新的 VSYNC 有效信号到来,检测到后把 WEN 引脚设置为高电平,恢复 OV7725 向 FIFO 的写入权限,OV7725 输出的新一帧图像数据会被写入到 FIFO 的 0 地址中,重复上述过程。
二、测试功能
源码地址:https://gitee.com/ramcu/cpk_examples/tree/main/cpkexp_ekra8x1/ceu_cpkexp_ra8d1_ep
编译和下载流程可以参考我上一个帖子,这里就不再重复赘述了。
代码分析:
1. 函数整体结构
hal_entry 是嵌入式系统(通常基于 Renesas FSP 框架)的硬件抽象层(HAL)入口函数,相当于程序的主函数。代码分为三个部分:
- 初始化硬件模块
- 主循环(
while(1))处理图像数据并显示
- 安全模式相关(可选)
2. 初始化阶段
(1)基础硬件初始化
fsp_err_t err = FSP_SUCCESS;
bsp_sdram_init();
bsp_sdram_init():初始化外部 SDRAM,为图像数据(如摄像头采集的帧数据)提供存储空间。
(2)I2C 主机初始化
err = R_IIC_MASTER_Open(&g_i2c_master1_ctrl, &g_i2c_master1_cfg);
if(err != FSP_SUCCESS){
APP_PRINT( "** IIC MASTER Open API failed ** \r\n");
}
R_IIC_MASTER_Open:通过 FSP 库函数初始化 I2C 主机控制器(g_i2c_master1_ctrl),配置参数由 g_i2c_master1_cfg 定义。
- 作用:I2C 是摄像头(如 OV7725、OV5640)的常用通信接口,用于配置摄像头寄存器(如分辨率、输出格式等)。
(3)摄像头初始化(条件编译)
#if 1
err = ov7725_open();
if(err != FSP_SUCCESS){
APP_PRINT( "** ov7725_open API failed ** \r\n");
}
OV7725_Window_Set(VGA_WIDTH, VGA_HEIGHT, 1);
#else
ov5640_init();
ov5640_set_output_format(OV5640_OUTPUT_FORMAT_RGB565);
ov5640_auto_focus_init();
ov5640_set_output_size(VGA_WIDTH,VGA_HEIGHT);
ov5640_set_exposure_level(OV5640_EXPOSURE_LEVEL_8);
#endif
- 功能:根据宏定义选择初始化 OV7725 或 OV5640 摄像头,配置输出分辨率(VGA:640x480)、格式等参数。
- 注意:OV7725 和 OV5640 是常用的 CMOS 图像传感器,支持不同的分辨率和功能(如 OV5640 支持自动对焦)。
(4)CEU 初始化
err = ceu_init(g_image_vga_sram, VGA_WIDTH, VGA_HEIGHT);
if(err != FSP_SUCCESS ){
APP_PRINT( "** ceu_init API failed ** \r\n");
}
ceu_init:初始化 CEU(Camera Electronics Unit,摄像头电子单元),用于处理摄像头输出的原始图像数据(如格式转换、裁剪等)。
g_image_vga_sram:存储 VGA 分辨率图像数据的缓冲区(位于 SDRAM)。
(5)图形系统与显示接口初始化
graphics_init();
mipi_dsi_entry();
gp_frame_buffer = gp_single_buffer;
mipi_dsi_entry:MIPI DSI 是显示屏的高速接口,用于将图像数据传输到屏幕。
gp_frame_buffer:帧缓冲区指针,用于双缓冲显示(避免画面闪烁)。
3. 主循环(while (1))
主循环持续采集图像、处理并输出到显示屏,核心步骤如下:
(1)双缓冲切换
gp_frame_buffer = (gp_frame_buffer == gp_single_buffer) ? gp_double_buffer : gp_single_buffer
- 切换帧缓冲区(双缓冲机制):当前使用的缓冲区和待写入的缓冲区交替,避免显示时画面撕裂。
(2)CEU 图像处理
err = ceu_operation(g_image_vga_sram);
if(err != FSP_SUCCESS ){
APP_PRINT( "** ceu_operation API failed ** \r\n");
}
ceu_operation:CEU 执行实际的图像处理(如从摄像头获取数据、存储到 g_image_vga_sram 缓冲区)。
(3)图像绘制到帧缓冲区
#if(0)
yuv422_to_rgb565(...);
graphics_draw_frame(...);
#else
graphics_draw_frame(&g_image_vga_sram[0], (uint8_t*) gp_frame_buffer, ...);
#endif
- 功能:将摄像头采集的图像数据(可能是 YUV 格式)绘制到当前帧缓冲区。
- 条件编译:可选择是否进行 YUV 到 RGB 的格式转换(取决于摄像头输出格式和显示屏要求)。
(4)更新显示屏并等待垂直同步
R_GLCDC_BufferChange (&g_display_ctrl, (uint8_t*) gp_frame_buffer, DISPLAY_FRAME_LAYER_1)
g_vsync_flag = RESET_FLAG
while (g_vsync_flag)
R_GLCDC_BufferChange:通知 GLCDC(图形 LCD 控制器)切换到新的帧缓冲区,准备显示新画面。
- 等待 Vsync:确保在显示屏完成一帧刷新后再更新缓冲区,避免画面撕裂。
三、测试效果
