扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

RT1050 CSI 采集 OV7670 数据并通过 eLCDIF 实时显示完整方案

1小时前
47
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

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 参与数据搬运,核心逻辑:

  1. OV7670 通过 8 位并行接口输出 RGB565 格式图像数据,同步输出像素时钟(PCLK)、行同步(HS)、帧同步(VS)信号;
  2. RT1050 的 CSI 接口按 gated clock 模式接收数据,直接存储至帧缓冲区;
  3. 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.cov7670.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 数据搬运、图像算法处理等模块,进一步提升系统性能。

相关推荐