MIMXRT1050 凭借高性能 Cortex-M7 内核与灵活的 FlexIO 外设,可实现对 OV7670 并口摄像头数据的采集与 TFT LCD 实时显示。本文基于 MIMXRT1050-EVKB 开发板,详解 FlexIO 采集 OV7670 数据、SPI 驱动 ILI9321 TFT LCD 的完整实现方案,包含硬件接线改造、核心软件适配(针对 RT1050 FlexIO 特性的代码修改)、LCD 单独测试方法,提供可直接复用的配置与源码思路,适配 240×320 分辨率的实时图像显示需求。
资料获取:RT1050 FlexIO采集OV7670摄像头数据TFTLCD显示
1. 核心方案与软硬件环境
1.1 方案整体逻辑
采用 “FlexIO 采集 + DMA 搬运 + SPI 显示” 架构,核心流程:
- OV7670 摄像头输出 8 位并行图像数据、像素时钟(PCLK)、行同步(HS)、帧同步(VS)信号;
- RT1050 的 FlexIO 外设模拟并行接口,捕获摄像头数据,通过 DMA 直接搬运至内存缓冲区,避免 CPU 占用;
- 内存中的图像数据(RGB565 格式)通过 SPI 接口传输至 ILI9321 TFT LCD,实现实时显示。
1.2 关键差异说明
NXP 官方应用笔记 AN12686 基于 RT1010(8 个 FlexIO shifter)开发,而 RT1050 仅支持 4 个 FlexIO shifter,因此需针对性修改DMA 配置与FlexIO 数据捕获逻辑,才能适配 4 shifter 硬件限制,这是本方案的核心适配点。
3. 软硬件清单
(1)硬件组件
| 设备名称 | 型号 / 规格 | 核心作用 |
|---|---|---|
| 主控板 | MIMXRT1050-EVKB revA1 | 核心控制单元,提供 FlexIO、SPI、DMA 等外设 |
| 摄像头 | OV7670 并口模组 | 输出 8 位并行图像数据,支持 SCCB 接口配置 |
| TFT LCD | 2.4 寸 ILI9321(SPI 接口) | 240×320 分辨率,接收 SPI 传输的图像数据并显示 |
| 辅助工具 | 杜邦线、电烙铁 | 硬件接线与开发板引脚改造 |
(2)软件环境
- 开发 IDE:MCUXpresso IDE(或 IAR/Keil);
- 底层驱动:NXP MCUXpresso SDK(适配 RT1050);
- 辅助工具:LVGL 在线图像转换工具(将图片转为 RGB565 数组)。
2. 硬件配置:接线与开发板改造
硬件部分核心是FlexIO 引脚分配(避开板载冲突)、OV7670 与 RT1050 接线、TFT LCD 与 SPI 接口连接,需先完成开发板引脚改造,再按定义接线。
2.1 开发板改造(关键步骤)
为减少信号干扰,需移除 MIMXRT1050-EVKB 板上的 3 个电阻与 1 个二极管,具体为:R323、R316、R309、D6,直接物理拔除即可,无需额外焊接。
2.2 OV7670 与 RT1050 接线定义
OV7670 的 8 位数据引脚、控制引脚均连接至 RT1050 的 FlexIO2 外设引脚,SCCB 配置接口(I2C)连接至 I2C1,具体接线如下:
| OV7670 引脚 | 信号名称 | RT1050-EVKB 引脚 | 对应外设功能 |
|---|---|---|---|
| P1 | PWDN | GPIO_AD_B1_02(GPIO1_IO18) | 功耗控制(拉低正常工作) |
| P2 | RESET | GPIO_AD_B1_03(GPIO1_IO19) | 复位控制(拉高正常工作) |
| P3-P10 | D0-D7 | GPIO_B0_05~GPIO_B0_12(FlexIO2_D05~D12) | 8 位并行数据输入 |
| P11 | XCLK | GPIO_B0_13(FlexIO2_D13) | 摄像头时钟输入 |
| P12 | PCLK | GPIO_B0_14(FlexIO2_D14) | 像素时钟(FlexIO 捕获触发信号) |
| P13 | HS(HREF) | GPIO_B0_15(FlexIO2_D15) | 行同步信号 |
| P14 | VS | GPIO_AD_B0_03(GPIO1_IO03) | 帧同步信号 |
| P15 | SDA | GPIO_AD_B1_01(I2C1_SDA) | SCCB 数据接口 |
| P16 | SCL | GPIO_AD_B1_00(I2C1_SCLK) | SCCB 时钟接口 |
| P17 | GND | GND | 接地 |
| P18 | 3.3V | 3.3V | 电源供电 |
2.3 TFT LCD 与 RT1050 SPI 接线
ILI9321 LCD 采用 SPI 接口通信,仅使用显示功能(触摸功能未启用),接线如下:
| LCD 引脚 | 信号名称 | RT1050-EVKB 引脚 | 对应外设功能 |
|---|---|---|---|
| 1 | GND | GND(J24_7) | 接地 |
| 2 | VCC | 3.3V(J24_8) | 电源供电 |
| 3 | CLK | GPIO_AD_B1_15(SPI3_CLK) | SPI 时钟信号 |
| 4 | MOSI | GPIO_AD_B1_14(SPI3_MOSI) | SPI 数据输出(图像数据) |
| 5 | RES | GPIO_AD_B0_02(GPIO1_IO02) | LCD 复位(高电平有效) |
| 6 | DC | GPIO_AD_B1_10(GPIO1_IO26) | 数据 / 命令选择(高 = 数据,低 = 命令) |
| 7 | BLK | 3.3V | 背光控制(拉高常亮,拉低关闭) |
| 9 | CS1 | GPIO_AD_B1_12(GPIO1_IO28) | 显示部分片选(拉低有效) |
3. 软件配置:核心代码适配与实现
软件部分按 “LCD 单独测试→OV7670 配置→FlexIO+DMA 采集→SPI 显示” 的顺序开发,核心适配 RT1050 的 4 shifter FlexIO 特性。
3.1 LCD 单独测试(验证 SPI 驱动)
先通过固定图片验证 LCD 显示功能,避免后续集成时定位问题,步骤如下:
(1)图片转 RGB565 数组
- 准备一张 240×320 分辨率的图片,通过 LVGL 在线转换工具(https://lvgl.io/tools/imageconverter)转换;
- 转换格式选择 “CF_RGB565”,生成 C 语言数组(自动去除 Alpha 通道冗余字节),保存为
horsepic.h头文件。
(2)LCD 初始化与图片显示代码
#include "ILI9321.h"
#include "horsepic.h"
// RGB888转RGB565(若转换工具未处理,需手动转换)
void convert8to16(void) {
uint32_t i;
for (i = 0; i < OV7670_FRAME_BYTES/3; i++) {
horse16[i] = ((horse8[i*3] & 0xF8) << 8) | ((horse8[i*3+1] & 0xFC) << 3) | ((horse8[i*3+2] & 0xF8) >> 3);
}
}
// 显示图片
int main(void) {
// 初始化SPI与LCD
ILI9321_Init();
// 转换图片格式(若已为RGB565可省略)
convert8to16();
// 在LCD全屏显示图片(x1,y1,x2,y2, 图像数组)
ILI9321_FillPic(0, 0, OV7670_FRAME_WIDTH-1, OV7670_FRAME_HEIGHT-1, (uint16_t *)horse16);
while(1);
return 0;
}
- 若 LCD 正常显示图片,说明 SPI 驱动与接线无误。
3.2 OV7670 配置(SCCB 接口)
通过 I2C1 模拟 SCCB 接口,配置 OV7670 的图像格式、分辨率、帧率等参数,核心配置为:
- 图像格式:RGB565(16 位色,适配 LCD);
- 分辨率:240×320(与 LCD 一致);
- 像素时钟:由 RT1050 FlexIO 提供(XCLK 引脚)。
核心配置代码(基于 SDK I2C 驱动):
#define OV7670_ADDR 0x21 // OV7670 SCCB地址
// 向OV7670寄存器写值
void OV7670_WriteReg(uint8_t reg, uint8_t val) {
I2C_MasterStart(I2C1, OV7670_ADDR, kI2C_Write);
I2C_MasterWrite(I2C1, reg);
I2C_MasterWrite(I2C1, val);
I2C_MasterStop(I2C1);
}
// OV7670初始化(配置RGB565格式与240×320分辨率)
void OV7670_Init(void) {
OV7670_WriteReg(0x12, 0x04); // 复位摄像头
delay_ms(10);
OV7670_WriteReg(0x11, 0x00); // 帧率控制
OV7670_WriteReg(0x3A, 0x05); // 选择RGB565格式
// 其他分辨率配置寄存器(参考OV7670 datasheet)
OV7670_WriteReg(0x17, 0x22);
OV7670_WriteReg(0x18, 0x04);
}
3.3 FlexIO+DMA 采集配置(核心适配)
针对 RT1050 的 4 个 FlexIO shifter,修改 FlexIO 设备结构体与 DMA 传输参数,实现 8 位数据的正确捕获。
(1)FlexIO 设备结构体配置
// FlexIO摄像头设备配置(4 shifter适配)
static FLEXIO_CAMERA_Type s_FlexioCameraDevice = {
.flexioBase = BOARD_CAMERA_FLEXIO_INST, // FlexIO2实例
.shifterStartIdx = 0U, // 起始shifter索引
.shifterCount = 4U, // RT1050仅支持4个shifter
.datPinStartIdx = BOARD_CAMERA_FLEXIO_DATA_PIN_START_INDEX, // 数据引脚起始索引
.pclkPinIdx = BOARD_CAMERA_FLEXIO_PCLK_PIN_INDEX, // PCLK引脚索引
.hrefPinIdx = BOARD_CAMERA_FLEXIO_HREF_PIN_INDEX, // HS引脚索引
.timerIdx = 0U, // 定时器索引
};
(2)DMA 配置(关键修改)
通过 DMA 将 FlexIO 捕获的数据直接搬运至内存缓冲区,核心修改传输大小与地址偏移,适配 4 shifter 的数据拼接逻辑:
#define DMA_TRSF_SIZE 8U // 每次传输8字节(适配4 shifter)
#define DMA_MINOR_LOOP_SIZE 8U // 次要循环大小
#define OV7670_FRAME_BYTES (240*320*2) // 一帧图像字节数(RGB565)
uint8_t g_FlexioCameraFrameBuffer[OV7670_FRAME_BYTES]; // 图像缓冲区
static void configDMA(void) {
uint32_t soff, smod = 0u, size = 0u;
// 计算size = log2(DMA_TRSF_SIZE),用于DMA ATTR配置
while((1u << size) < DMA_TRSF_SIZE) size++;
// 配置源地址偏移(根据传输大小调整)
if(DMA_TRSF_SIZE == DMA_MINOR_LOOP_SIZE) {
soff = 0u;
} else {
soff = DMA_TRSF_SIZE;
}
// 计算smod = log2(DMA_MINOR_LOOP_SIZE)
while((1u << smod) < DMA_MINOR_LOOP_SIZE) smod++;
// 配置DMA TCD(传输控制描述符)
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].SADDR = FLEXIO_CAMERA_GetRxBufferAddress(&s_FlexioCameraDevice);
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].SOFF = soff; // 源地址偏移
// 配置数据大小与模式(源/目的数据宽度一致)
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].ATTR = DMA_ATTR_SMOD(smod) |
DMA_ATTR_SSIZE(size) |
DMA_ATTR_DMOD(0u) |
DMA_ATTR_DSIZE(size);
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].NBYTES_MLNO = 16; // 每次传输16字节
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].SLAST = 0u; // 源地址最后偏移
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].DADDR = (uint32_t)g_FlexioCameraFrameBuffer; // 目的地址(图像缓冲区)
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].DOFF = 8; // 目的地址偏移
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].CITER_ELINKNO = DMA_MAJOR_LOOP_SIZE; // 主要循环次数
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].DLAST_SGA = -OV7670_FRAME_BYTES; // 传输完成后目的地址复位
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].CSR = DMA_CSR_DREQ_MASK; // 启用DMA请求
DMA0->TCD[FLEXIO_CAMERA_DMA_CHN].BITER_ELINKNO = DMA_MAJOR_LOOP_SIZE;
// 配置DMAMUX,关联FlexIO DMA请求源
DMAMUX->CHCFG[FLEXIO_CAMERA_DMA_CHN] = (DMAMUX->CHCFG[FLEXIO_CAMERA_DMA_CHN] & (~DMAMUX_CHCFG_SOURCE_MASK)) |
DMAMUX_CHCFG_SOURCE(FLEXIO_CAMERA_DMA_MUX_SRC);
DMAMUX->CHCFG[FLEXIO_CAMERA_DMA_CHN] |= DMAMUX_CHCFG_ENBL_MASK; // 启用DMAMUX通道
}
3.4 整体集成与显示
完成各模块配置后,集成采集与显示逻辑,实现 “采集一帧→显示一帧” 的实时流程:
int main(void) {
// 初始化硬件
BOARD_InitPins();
BOARD_InitClocks();
I2C1_Init();
SPI3_Init();
DMA_Init();
// 初始化外设
OV7670_Init();
ILI9321_Init();
FLEXIO_CAMERA_Init(&s_FlexioCameraDevice);
configDMA();
// 启用FlexIO采集与DMA传输
FLEXIO_CAMERA_Enable(&s_FlexioCameraDevice, true);
DMA_EnableChannel(DMA0, FLEXIO_CAMERA_DMA_CHN);
while(1) {
// 等待一帧数据采集完成(通过VS信号或DMA完成中断判断)
if(FLEXIO_CAMERA_IsFrameDone(&s_FlexioCameraDevice)) {
// 显示一帧图像(缓冲区数据→LCD)
ILI9321_FillPic(0, 0, 239, 319, (uint16_t *)g_FlexioCameraFrameBuffer);
// 清除帧完成标志
FLEXIO_CAMERA_ClearFrameDone(&s_FlexioCameraDevice);
}
}
return 0;
}
4. 常见问题排查与避坑指南
4.1 LCD 无显示,SPI 通信异常
- 原因 1:DC 引脚(数据 / 命令选择)接线错误,导致 LCD 无法区分命令与数据;
- 原因 2:CS1 片选引脚未拉低,LCD 未被选中;
- 解决:重新核对 SPI 接线(CLK/MOSI/DC/CS1),确保初始化时拉低 CS1,发送命令时拉低 DC,发送数据时拉高 DC。
4.2 采集到的数据乱码,图像花屏
- 原因 1:FlexIO shifter 数量配置错误(按 RT1010 的 8 shifter 配置,未改为 4);
- 原因 2:DMA 传输大小(NBYTES_MLNO)与 shifter 数量不匹配;
- 原因 3:OV7670 图像格式配置错误(非 RGB565);
- 解决:确认
shifterCount=4U,DMA 传输参数与 4 shifter 适配,重新检查 OV7670 的 0x3A 寄存器(配置为 0x05,RGB565)。
4.3 开发板发热,信号干扰严重
- 原因:未移除板载 R323、R316、R309 电阻与 D6 二极管,导致信号冲突;
- 解决:按要求完成开发板硬件改造,重新焊接或拔除冲突元件。
4.4 DMA 传输完成但缓冲区无数据
- 原因 1:DMAMUX 通道未关联正确的 FlexIO DMA 请求源;
- 原因 2:FlexIO 的 PCLK 触发边沿配置错误(未与 OV7670 的 PCLK 同步);
- 解决:核对
DMAMUX_CHCFG_SOURCE参数为 FlexIO2 的 DMA 请求源,调整 FlexIO 捕获的 PCLK 触发边沿(上升沿 / 下降沿)。
RT1050 通过 FlexIO+DMA 实现 OV7670 数据采集与 TFT LCD 显示的核心,是适配 4 shifter 的硬件限制,关键修改点为 FlexIO 设备结构体与 DMA 传输参数。整个方案的实现流程可概括为:
- 硬件改造→接线→LCD 单独测试(验证 SPI 驱动);
- OV7670 配置(SCCB 接口)→FlexIO+DMA 采集配置;
- 集成采集与显示逻辑,实现实时图像传输。
本方案避开了 RT1050 与 RT1010 的 FlexIO 硬件差异,提供了完整的接线定义、核心代码适配与问题排查方法,可直接移植到 MIMXRT1050-EVKB 开发板使用。测试结果表明,该方案能稳定捕获 OV7670 的 240×320 分辨率图像,并通过 SPI 接口在 ILI9321 LCD 上实时显示,无明显延迟与花屏现象。
如需进一步优化,可调整 OV7670 的帧率参数、DMA 缓存策略或 SPI 传输速率,以平衡显示流畅度与系统资源占用。
303