4、图像采集与显示:摄像头初始化、图像格式转换、在LCD上实时显示画面
视觉AI应用的第一步,永远是“看得见”。K210作为一款面向机器视觉的RISC-V SoC,其核心优势在于内置KPU(Knowledge Processing Unit)神经网络加速器,但所有AI推理都依赖于高质量的图像输入。本章将聚焦于K210视觉开发中最基础的闭环链路:摄像头采集原始图像数据,经过格式转换后,最终在LCD屏幕上实时显示。这一过程不仅是后续人脸识别、物体分类等高级应用的前提,更是理解嵌入式视觉系统数据流的关键。我们将从硬件连接、寄存器配置、DMA传输到显示驱动,完整拆解这一条“光→电→数据→像素”的工程链路。
上图展示了K210视觉采集与显示的整体数据流架构。左侧为图像采集端,摄像头通过DVP(Digital Video Port)并行接口输出原始图像数据,同时通过SCCB(类似I2C)总线进行寄存器配置。中间是K210内部处理核心,DVP FIFO负责硬件级数据缓存,随后进行像素格式转换,最终通过DMA(Direct Memory Access)或SPI接口将图像数据传输至右侧的LCD显示模块。整个链路中,任何一环的时序不匹配或配置错误,都会导致显示花屏、黑屏或帧率骤降。
4.1 摄像头初始化:从上电到输出有效像素
摄像头初始化的本质是“让传感器按照我们期望的分辨率、帧率和输出格式开始工作”。K210开发板常用的摄像头为OV2640(200万像素)或GC0328(30万像素),两者均通过DVP接口与K210连接。初始化流程并非简单的“调用一个库函数”,而是涉及电源稳定、时钟同步、寄存器写入和时序验证四个阶段。
核心原理:DVP接口与SCCB控制
DVP接口是一种并行同步接口,包含8位或10位数据线(D0-D7)、像素时钟(PCLK)、行同步(HSYNC)、帧同步(VSYNC)以及主时钟(XVCLK)。K210作为主机,需要提供XVCLK时钟给摄像头,摄像头在PCLK的上升沿逐像素输出数据。SCCB协议与I2C高度相似,用于读写摄像头内部的寄存器,例如设置输出分辨率、增益、白平衡等。初始化时,必须先通过SCCB写入软复位命令,等待摄像头内部PLL锁定,再配置输出格式为RGB565(16位/像素),分辨率设为QVGA(320×240),帧率目标为30fps。
| 参数项 | 典型值 | 说明 |
|---|---|---|
| XVCLK | 24 MHz | K210输出给摄像头的主时钟 |
| PCLK | 12-48 MHz | 像素时钟,由摄像头内部PLL分频产生 |
| 输出格式 | RGB565 | 高字节在前,低字节在后 |
| 分辨率 | 320×240 (QVGA) | 兼顾清晰度与KPU处理速度 |
| VSYNC 极性 | 低电平有效 | 帧同步信号,标志一帧开始 |
操作流程:标准初始化步骤
- 硬件复位:将摄像头复位引脚拉低至少1ms,然后释放,确保传感器内部状态清零。
- 时钟使能:配置K210的DVP系统时钟,使XVCLK输出稳定在24MHz。使用
dvp_init()函数时,内部会自动完成时钟分频。 - SCCB探测:向摄像头地址(OV2640为0x60)发送读命令,确认I2C通信正常。若返回0xFF,则检查接线或地址。
- 寄存器配置:写入摄像头厂商提供的初始化寄存器数组。该数组通常包含数百个寄存器设置,建议直接使用官方驱动中的
ov2640_init()函数,避免手动逐条配置。 - 输出使能:设置DVP为接收模式,开启DMA传输通道,等待VSYNC中断。
// 伪代码示例:摄像头初始化核心逻辑
dvp_init(24 * 1000 * 1000); // 初始化DVP,时钟24MHz
dvp_set_output_enable(0, 1); // 使能DVP输出到FIFO
dvp_set_image_format(DVP_CFG_RGB565); // 设置RGB565格式
dvp_set_image_size(320, 240); // 设置分辨率
ov2640_init(); // 写入OV2640寄存器数组
dvp_clear_interrupt(); // 清除中断标志
dvp_enable_burst(); // 使能突发传输模式
实战场景:解决上电后无图像输出
某学员反馈,摄像头初始化后,读取FIFO数据全为0x00。排查过程如下:首先用示波器测量XVCLK引脚,发现无时钟波形,说明K210的DVP时钟未使能。进一步检查代码,发现dvp_init()被放在了fpioa_set_function之前,导致引脚复用未配置。修正顺序后,时钟正常,但图像仍为全黑。继续测量VSYNC信号,发现始终为高电平,说明摄像头未输出帧同步。最终定位为SCCB通信失败——摄像头SDA引脚被误接到其他外设。重新检查硬件连接后,图像正常输出。
4.2 图像格式转换:RGB565与RGB888的取舍
摄像头原生输出RGB565格式,即每个像素用16位表示,其中R占5位、G占6位、B占5位。而LCD显示屏(如ST7789)通常支持RGB565或RGB888格式。K210的LCD驱动为了简化设计,常直接使用RGB565,但某些AI预处理或显示特效需要RGB888(24位/像素)。格式转换看似简单,但在嵌入式环境中,需要考虑内存带宽和转换效率。
核心原理:像素位操作与内存布局
RGB565转RGB888的核心是位扩展:将5位通道扩展为8位,通常采用“高位补低位”的方式。例如5位红色值r5,转换公式为r8 = (r5 << 3) | (r5 >> 2)。这种近似转换能保持亮度感知。在K210上,由于CPU主频仅400MHz,逐像素转换会消耗大量时间。更高效的做法是使用DMA的字节重排功能,或者直接让LCD工作在RGB565模式,避免转换。
操作流程:手动转换与查表法
// RGB565 转 RGB888 查表法(预计算)
uint8_t r_table[32], g_table[64], b_table[32];
void init_tables() {
for (int i = 0; i < 32; i++) {
r_table[i] = (i << 3) | (i >> 2);
b_table[i] = (i << 3) | (i >> 2);
}
for (int i = 0; i < 64; i++) {
g_table[i] = (i << 2) | (i >> 4);
}
}
// 转换一个像素
void rgb565_to_rgb888(uint16_t pixel, uint8_t *r, uint8_t *g, uint8_t *b) {
*r = r_table[(pixel >> 11) & 0x1F];
*g = g_table[(pixel >> 5) & 0x3F];
*b = b_table[pixel & 0x1F];
}
查表法将位运算转换为内存访问,在K210上速度提升约2倍。但需要注意,查表法会占用约256字节的RAM,对于K210的6MB内存来说微不足道。
常见误区:字节序错误导致颜色错乱
RGB565在内存中的存储方式分为大端和小端两种。K210的DVP默认输出为大端模式(高字节在前),而LCD的SPI传输通常期望小端模式(低字节在前)。如果直接传输,会出现红色和蓝色互换的现象。解决方法是配置DVP的字节交换寄存器,或者在LCD驱动中设置lcd_set_invert。判断字节序是否正确,可以显示一张纯红色图片,若屏幕显示蓝色,则说明字节序反了。
4.3 LCD实时显示:从显存到屏幕的刷新机制
LCD显示的核心是“持续将显存中的像素数据传输到屏幕的GRAM(Graphics RAM)中”。K210通过SPI接口与LCD通信,SPI时钟频率可达40MHz,但传输一帧320×240×2字节(RGB565)的数据量约为150KB,理论最小传输时间为150KB×8bit / 40MHz ≈ 30ms,即约33fps。实际应用中,由于SPI协议开销和LCD初始化命令,帧率通常维持在20-25fps。
核心原理:SPI DMA与双缓冲
为了不占用CPU,K210的LCD驱动使用SPI DMA模式。CPU只需设置DMA源地址(显存地址)、目的地址(SPI数据寄存器)和传输长度,然后启动DMA,CPU即可处理其他任务。双缓冲机制是提高显示流畅度的关键:在DMA传输当前帧时,CPU同时处理下一帧图像数据。K210的LCD驱动库(如lcd_draw_picture)内部已实现双缓冲,但用户需注意,不要直接修改正在被DMA读取的显存区域。
操作流程:LCD初始化与刷新
- 引脚配置:使用
fpioa_set_function将SPI引脚(SCLK、MOSI、DC、CS、RST、BL)映射到K210的硬件SPI接口。 - LCD控制器初始化:发送ST7789的初始化命令序列,包括设置显示方向、颜色格式、背光亮度等。
- 清屏:将显存全部填充为0xFFFF(白色),避免上电时出现花屏。
- 循环刷新:在while(1)循环中,调用
lcd_draw_picture(0, 0, 320, 240, image_buffer),其中image_buffer是摄像头采集并转换后的RGB565数据。
// 主循环:采集并显示
while (1) {
dvp_get_frame(&frame); // 获取摄像头帧数据
lcd_draw_picture(0, 0, 320, 240, frame); // 显示到LCD
// 可在此处添加AI处理代码
}
案例拆解:实现30fps实时显示
某项目要求摄像头画面在LCD上流畅显示,且CPU占用率低于30%以便运行KPU人脸检测。初始实现中,帧率仅15fps,CPU占用率高达60%。分析发现,瓶颈在于lcd_draw_picture内部使用了阻塞式SPI传输。优化方案:
- 启用SPI DMA:将SPI传输模式改为DMA,CPU在传输期间进入休眠或处理其他任务。
- 降低分辨率:将摄像头输出从VGA(640×480)降至QVGA(320×240),数据量减少75%。
- 调整SPI时钟:将SPI时钟从20MHz提升至40MHz,需确认LCD模块的时序规格是否支持。
优化后,帧率稳定在28fps,CPU占用率降至25%,成功为KPU预留了足够的算力。此案例说明,显示性能优化应优先考虑DMA和分辨率,而非单纯提高主频。
4.4 常见误区与调试复盘
在图像采集与显示的教学实践中,学员常犯的错误具有高度共性。总结如下,帮助读者快速定位问题。
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| LCD白屏 | LCD初始化失败或背光未开启 | 检查BL引脚电平,重新发送初始化序列 |
| 画面全黑 | 摄像头未输出数据或DVP配置错误 | 测量PCLK是否有波形,检查VSYNC中断是否触发 |
| 颜色偏蓝/偏红 | RGB565字节序错误 | 交换高字节和低字节,或配置DVP字节交换 |
| 画面有噪点 | 电源纹波过大或摄像头排线过长 | 在摄像头电源引脚加100nF去耦电容,缩短排线 |
| 帧率极低(<5fps) | SPI未使用DMA,或摄像头输出分辨率过高 | 启用DMA,降低分辨率至QVGA |
调试方法论:从现象到根因
建议采用“信号追踪法”进行调试:先用示波器检查XVCLK和PCLK,确认时钟链路正常;再用逻辑分析仪抓取SCCB波形,验证寄存器写入是否正确;最后检查DVP数据线上的数据,确认像素数据有效。这种分层排查法能快速缩小问题范围,避免盲目修改代码。