MIMXRT1050 搭载专用 CSI(CMOS Sensor Interface)接口与 eLCDIF(Enhanced LCD Interface)显示模块,可高效实现 OV7670 摄像头数据的采集与 LCD 实时显示。本文基于 MIMXRT1050-EVKB 开发板,详解 CSI 接口配置、OV7670 驱动移植、eLCDIF 显示适配的全流程,采用 RGB565 图像格式,支持 320×240(QVGA)摄像头分辨率与 480×272 LCD 分辨率的适配,提供稳定的 30FPS 帧率显示方案,可直接用于嵌入式图像采集显示场景。
资料获取:RT1050 CSI OV7670摄像头eLCDIF显示
1. 核心原理与技术基础
1.1 整体工作流程
方案采用 “CSI 采集 + 缓冲区存储 + eLCDIF 显示” 的架构,无需 CPU 参与数据搬运,核心逻辑:
- OV7670 通过 8 位并行接口输出 RGB565 格式图像数据,同步输出像素时钟(PCLK)、行同步(HS)、帧同步(VS)信号;
- RT1050 的 CSI 接口按 gated clock 模式接收数据,直接存储至帧缓冲区;
- eLCDIF 模块从帧缓冲区读取数据,按 LCD 时序要求输出至显示屏,实现实时图像显示。
1.2 关键技术要点
(1)RGB565 图像格式
RGB565 是嵌入式显示的常用格式,每个像素占 2 字节(16 位),颜色编码规则:
- 高 5 位(Bit15~Bit11):红色(R)分量,取值范围 0~31;
- 中间 6 位(Bit10~Bit5):绿色(G)分量,取值范围 0~63;
- 低 5 位(Bit4~Bit0):蓝色(B)分量,取值范围 0~31;
- 典型纯色编码:红色 0xF800、绿色 0x07E0、蓝色 0x001F,共支持 65536 种颜色。
(2)CSI 与 OV7670 时序匹配
CSI 接口采用 gated clock 模式,通过 VSYNC(帧同步)、HSYNC(行同步)、PIXCLK(像素时钟)实现数据同步:
- VSYNC 高电平表示一帧图像开始,低电平为帧间隔;
- HSYNC 高电平表示一行数据开始,低电平为行间隔;
- PIXCLK 上升沿 / 下降沿触发 CSI 采集像素数据,需与 OV7670 的 PCLK 时序保持一致。
(3)eLCDIF 显示时序
eLCDIF 模块生成 LCD 所需的 VSYNC、HSYNC、DOTCLK(点时钟)信号:
- VSYNC 周期对应一帧图像的显示时间;
- HSYNC 周期对应一行像素的显示时间;
- DOTCLK 控制单个像素的显示节奏,高电平期间输出有效像素数据。
2. 软硬件环境配置
2.1 硬件清单与连接
(1)核心硬件组件
| 设备名称 | 型号 / 规格 | 核心参数 |
|---|---|---|
| 主控板 | MIMXRT1050-EVKB revA1 | 搭载 Cortex-M7 内核,集成 CSI、eLCDIF 外设 |
| 摄像头 | OV7670 CMOS 模块 | 8 位并行输出,SCCB 控制,支持 320×240 分辨率,30FPS 帧率 |
| LCD 显示屏 | RK043FN02H(NXP 官方配套) | 4.3 英寸,480×272 分辨率,eLCDIF 接口 |
| 辅助配件 | FPC 转 2.54mm 转接板、杜邦线 | 解决 EVKB 板载 FPC 接口与 OV7670 直插引脚的适配 |
(2)硬件连接关键说明
- OV7670 与 RT1050 CSI 接口连接:8 位数据引脚(D0~D7)接 CSI 数据口,PCLK 接 CSI_PIXCLK,HS 接 CSI_HSYNC,VS 接 CSI_VSYNC,XCLK 由 RT1050 提供时钟;
- SCCB 控制接口:OV7670 的 SDA 接 RT1050 的 I2C_SDA,SCL 接 I2C_SCLK,用于配置摄像头参数;
- 控制引脚:OV7670 的 PWDN 拉低(正常工作),RESET 拉高(正常工作),需通过 RT1050 的 GPIO 引脚控制,确保上电复位稳定;
- LCD 连接:直接使用 EVKB 板载 eLCDIF 接口(FPC 插槽),无需额外接线。
2.2 软件环境与资源准备
(1)基础软件工具
- 开发 IDE:MCUXpresso IDE;
- SDK 版本:NXP MCUXpresso SDK_2_14_0_EVKB-IMXRT1050;
- 参考示例:SDK 自带 CSI 采集示例(路径:
boards/evkbimxrt1050/driver_examples/csi/rgb565)。
(2)驱动移植来源
RT1050 SDK 未直接提供 OV7670 驱动,需从 FRDM-K82 SDK 中移植 OV7670 相关驱动文件,核心需适配:
- SCCB 接口通信函数(I2C 模拟);
- OV7670 寄存器配置(分辨率、图像格式、帧率);
- RT1050 CSI 接口的数据接收逻辑。
3. 核心软件实现步骤
3.1 OV7670 驱动移植与初始化
(1)驱动文件移植
从 FRDM-K82 SDK 中拷贝 OV7670 驱动相关文件(如ov7670.c、ov7670.h),修改适配 RT1050:
- 替换 I2C 通信接口为 RT1050 的 I2C 外设(用于 SCCB 控制);
- 添加 PWDN 和 RESET 引脚的 GPIO 控制代码,确保摄像头上电复位稳定。
(2)摄像头初始化配置
通过 SCCB 接口配置 OV7670 为 RGB565 格式、320×240 分辨率、30FPS 帧率,核心代码:
#include "ov7670.h"
#include "fsl_i2c.h"
#define OV7670_SCCB_ADDR 0x21 // OV7670 SCCB设备地址
#define APP_BPP 2 // 每像素字节数(RGB565)
// SCCB写寄存器函数
static status_t OV7670_WriteReg(uint8_t reg, uint8_t val) {
i2c_master_transfer_t transfer;
memset(&transfer, 0, sizeof(transfer));
transfer.slaveAddress = OV7670_SCCB_ADDR;
transfer.direction = kI2C_Write;
transfer.subaddress = reg;
transfer.subaddressSize = 1;
transfer.data = &val;
transfer.dataSize = 1;
transfer.flags = kI2C_TransferDefaultFlag;
return I2C_MasterTransferBlocking(I2C1, &transfer);
}
// OV7670初始化
status_t APP_InitCamera(void) {
// 控制PWDN和RESET引脚,复位摄像头
GPIO_PinWrite(GPIO1, 18, 1); // RESET拉高
GPIO_PinWrite(GPIO1, 19, 0); // PWDN拉低(正常工作)
delay_ms(100); // 等待复位完成
// 配置RGB565格式
OV7670_WriteReg(0x3A, 0x05);
// 配置320×240分辨率
OV7670_WriteReg(0x17, 0x22);
OV7670_WriteReg(0x18, 0x04);
// 配置帧率为30FPS
OV7670_WriteReg(0x11, 0x00);
// 其他配置(如白平衡、曝光)参考OV7670 datasheet
return kStatus_Success;
}
3.2 CSI 接口配置
基于 SDK 的 CSI 示例代码,配置 CSI 接口为 gated clock 模式,匹配 OV7670 的时序参数:
#include "fsl_csi.h"
#include "fsl_camera_receiver.h"
#define DEMO_CAMERA_CONTROL_FLAGS (kCAMERA_HardwareSync | kCAMERA_VsyncActiveHigh | kCAMERA_HsyncActiveHigh)
#define APP_FRAME_BUFFER_COUNT 2 // 双缓冲区,避免显示撕裂
#define DEMO_BUFFER_WIDTH 480 // 缓冲区宽度(适配LCD分辨率)
#define DEMO_BUFFER_HEIGHT 272 // 缓冲区高度(适配LCD分辨率)
static uint8_t s_frameBuffer[APP_FRAME_BUFFER_COUNT][DEMO_BUFFER_WIDTH * DEMO_BUFFER_HEIGHT * APP_BPP] __attribute__((aligned(32)));
static camera_receiver_handle_t cameraReceiver;
static camera_device_handle_t cameraDevice;
// CSI初始化
static void APP_InitCSI(void) {
const camera_config_t cameraConfig = {
.pixelFormat = kVIDEO_PixelFormatRGB565,
.bytesPerPixel = APP_BPP,
.resolution = FSL_VIDEO_RESOLUTION(320, 240), // 摄像头分辨率
.frameBufferLinePitch_Bytes = DEMO_BUFFER_WIDTH * APP_BPP, // 缓冲区行间距(适配LCD)
.interface = kCAMERA_InterfaceGatedClock, // CSI工作模式
.controlFlags = DEMO_CAMERA_CONTROL_FLAGS, // 同步信号极性
.framePerSec = 30, // 帧率
};
// 初始化CSI接收器
BOARD_InitCameraResource(); // 初始化CSI引脚与时钟
CAMERA_RECEIVER_Init(&cameraReceiver, &cameraConfig, NULL, NULL);
// 初始化摄像头设备
if (kStatus_Success != CAMERA_DEVICE_Init(&cameraDevice, &cameraConfig)) {
PRINTF("Camera device init failed!rn");
while (1);
}
// 启动摄像头
CAMERA_DEVICE_Start(&cameraDevice);
// 提交空缓冲区到接收队列
for (uint32_t i = 0; i < APP_FRAME_BUFFER_COUNT; i++) {
CAMERA_RECEIVER_SubmitEmptyBuffer(&cameraReceiver, (uint32_t)s_frameBuffer[i]);
}
}
3.3 eLCDIF 显示配置
直接使用 SDK 中 eLCDIF 的 LCD 初始化代码,适配 RK043FN02H 显示屏的时序参数:
#include "fsl_elcdif.h"
#include "fsl_lcdc.h"
// LCD时序参数(适配RK043FN02H)
static const elcdif_rgb_mode_config_t s_rgbModeConfig = {
.panelWidth = 480,
.panelHeight = 272,
.hsw = 41, // HSYNC脉冲宽度
.hfp = 2, // 水平前廊
.hbp = 2, // 水平后廊
.vsw = 10, // VSYNC脉冲宽度
.vfp = 2, // 垂直前廊
.vbp = 2, // 垂直后廊
.polarityFlags = kELCDIF_RgbDataValidHigh | kELCDIF_HsyncActiveHigh | kELCDIF_VsyncActiveHigh,
.pixelFormat = kELCDIF_PixelFormatRGB565,
.dataBus = kELCDIF_DataBus16Bit,
};
// eLCDIF初始化
static void APP_InitELCDIF(void) {
elcdif_config_t config = {0};
ELCDIF_GetDefaultConfig(&config);
config.pixelClock_Hz = 9000000; // 点时钟频率
ELCDIF_Init(ELCDIF, &config);
// 配置RGB显示模式
ELCDIF_ConfigRgbMode(ELCDIF, &s_rgbModeConfig);
// 启用eLCDIF
ELCDIF_Enable(ELCDIF, true);
}
3.4 数据显示与缓冲区管理
采用双缓冲区机制,实现采集与显示的并行处理,避免图像撕裂:
// 主函数核心逻辑
int main(void) {
// 初始化硬件(时钟、引脚、I2C、CSI、eLCDIF)
BOARD_InitBootClocks();
BOARD_InitBootPins();
BOARD_InitI2C1();
APP_InitELCDIF();
APP_InitCamera();
APP_InitCSI();
while (1) {
// 等待一帧数据采集完成
camera_receiver_buffer_t filledBuffer;
if (kStatus_Success == CAMERA_RECEIVER_GetFilledBuffer(&cameraReceiver, &filledBuffer, kCMSIS_RTOS_AbsoluteTimeout, 0)) {
// 将采集到的320×240图像显示到480×272 LCD(居中显示)
int xOffset = (480 - 320) / 2;
int yOffset = (272 - 240) / 2;
ELCDIF_WriteFrameBuffer(ELCDIF, 0, xOffset, yOffset, 320, 240, (uint32_t)filledBuffer.buffer);
// 将缓冲区重新提交到接收队列
CAMERA_RECEIVER_SubmitEmptyBuffer(&cameraReceiver, (uint32_t)filledBuffer.buffer);
}
}
}
4. 关键适配与优化要点
4.1 分辨率适配
摄像头分辨率(320×240)与 LCD 分辨率(480×272)不一致时,有两种适配方案:
- 居中显示(本文采用):计算偏移量(xOffset=80,yOffset=16),仅在 LCD 中心区域显示摄像头图像;
- 缩放显示:通过 RT1050 的 PXP(像素处理管道)模块将 320×240 图像缩放至 480×272,需配置 PXP 的缩放系数。
4.2 稳定性优化
- 增加摄像头复位控制:上电时先拉低 RESET 引脚 100ms,再拉高,确保不同厂家的 OV7670 模块均能稳定启动;
- 双缓冲区机制:采集数据写入一个缓冲区,显示从另一个缓冲区读取,避免同一缓冲区同时读写导致的图像撕裂;
- 时序参数校准:根据实际硬件调整 CSI 的 PIXCLK 和 eLCDIF 的 DOTCLK 频率,确保数据采集与显示无花屏、拖影。
4.3 常见问题排查
(1)摄像头采集失败
- 原因:PWDN/RESET 引脚配置错误、SCCB 通信失败、CSI 时序不匹配;
- 解决:检查 GPIO 引脚电平(PWDN 拉低、RESET 拉高),核对 I2C 引脚接线,调整 CSI 的同步信号极性。
(2)LCD 显示花屏
- 原因:RGB565 格式配置错误、eLCDIF 时序参数不匹配、缓冲区地址未对齐;
- 解决:验证 OV7670 的 RGB565 配置寄存器(0x3A=0x05),调整 eLCDIF 的 HSW/VSW/HFP/VFP 参数,确保缓冲区按 32 字节对齐(添加
__attribute__((aligned(32))))。
(3)帧率过低
- 原因:缓冲区数量不足、CPU 占用过高、时钟频率配置过低;
- 解决:增加缓冲区数量(如双缓冲→三缓冲),优化中断处理逻辑,提高 CSI 和 eLCDIF 的时钟频率(确保不超过硬件极限)。
RT1050 通过 CSI+eLCDIF 实现 OV7670 数据采集与显示的核心,是时序匹配与驱动适配。方案利用 CSI 接口的硬件采集能力和 eLCDIF 的专用显示功能,无需 CPU 参与数据搬运,确保 30FPS 的实时显示效果。
整个实现流程可概括为:移植 OV7670 驱动→配置 CSI 采集参数→初始化 eLCDIF 显示时序→双缓冲区管理→分辨率适配。本文提供的代码可直接基于 NXP SDK 修改使用,适配 MIMXRT1050-EVKB 开发板与官方 LCD,不同硬件平台仅需调整引脚定义和时序参数。
该方案适用于嵌入式视觉、工业控制、消费电子等场景,如需扩展功能,可添加 PXP 图像缩放、DMA 数据搬运、图像算法处理等模块,进一步提升系统性能。
47