2.38 梁山派GD32F470驱动OV2640 200W像素摄像头实战:从SCCB配置到屏幕显示
2.38 梁山派GD32F470驱动OV2640 200W像素摄像头实战从SCCB配置到屏幕显示最近有不少朋友在玩梁山派GD32F470开发板想用它来驱动摄像头做图像识别或者视频监控。我正好用OV2640这个200万像素的摄像头模块做了个项目今天就把从硬件接线、SCCB配置到最终在RGB屏幕上显示图像的完整过程手把手分享给大家。这个教程适合已经对GD32或STM32有一定了解想上手图像采集的开发者。我会假设你手头有梁山派开发板、OV2640摄像头模块以及一个RGB屏幕比如通过屏幕扩展板连接。咱们的目标很明确让摄像头拍到的画面实时显示在屏幕上。1. 认识你的硬件OV2640摄像头模块在动手写代码之前咱们得先搞清楚要驱动的对象是什么。OV2640是一个挺经典的200万像素CMOS图像传感器很多嵌入式视觉项目里都能见到它。1.1 模块核心特性我用的这个模块是从网上采购的核心是1/4英寸的OV2640传感器。它有几个特点对咱们开发者特别友好高灵活性支持多种图像输出格式。你既可以直接要原始的RGB565数据每个像素用16位表示颜色也可以让它内部压缩成JPEG格式再输出这样能大大节省传输的数据量。还支持YUV、YCbCr等格式方便做图像处理。可调参数多像曝光时间、白平衡让白色看起来就是白色、饱和度、对比度这些都能通过软件配置。这意味着你可以在不同光照环境下获得更好的图像效果不用总去调硬件。接口简单控制接口是SCCB可以理解为I2C的“亲戚”数据传输用并口或DVP数字视频端口接线和驱动都相对成熟。1.2 关键参数与引脚拿到模块先看它的“身份证”。这是模块的关键参数接线和供电都靠它参数项规格说明工作电压3.3V非常重要千万别接5V会烧坏工作电流约150mA 供电要充足线别太细最大分辨率1600 x 1200 这就是200万像素输出格式RGB565, JPEG, YUV, YCbCr控制接口SCCB 用于配置摄像头参数模块尺寸27mm x 27mm 很小巧引脚间距2.54mm 标准排针模块通常只有4个引脚有些版本可能更多但核心功能就这几个VCC接3.3V电源。GND接地。SDASCCB的数据线。SCLSCCB的时钟线。 另外图像数据是通过一组并口数据线D0-D7或D0-D9和行场同步信号线输出的这些线需要连接到MCU的特定GPIO或DVP接口。注意一定要确认你的模块供电是3.3V我刚开始玩的时候顺手接了5V结果模块一阵青烟直接报废了。这是第一个要避开的坑。2. 搭建开发环境与获取资料工欲善其事必先利其器。在写代码前先把材料和环境准备好。2.1 资料获取原始资料里提供了两个关键链接模块采购与基础资料如果你还没有模块可以参考这个链接。更重要的是卖家通常会提供针对STM32F4的驱动源码这是咱们移植的基础。[OV2640 摄像头模块 200W 像素 STM32F4 驱动源码 支持 JPEG 输出](https://item.taobao.com/item.htm?spma21n57.1.0.0.4039523cyryLpoid574382680203ns1abbucket0#detail)立创·梁山派移植示例代码这是已经移植到梁山派GD32F470上的成功示例是咱们最重要的参考。你可以直接下载来对比学习。 链接:https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA提取码: LCKF我的建议是先下载梁山派的成功示例代码跑通它看到现象。然后再去仔细研究卖家提供的STM32F4源码理解其原理。这样你就能知道“目标是什么”以及“原始的砖头长什么样”移植起来心里更有底。2.2 硬件连接思路硬件连接主要分三部分电源梁山派开发板上的3.3V输出引脚接到模块的VCCGND接GND。控制线SCCB将模块的SCL和SDA连接到GD32F470的任意一组I2C接口引脚例如I2C0。记得接上拉电阻通常4.7KΩ如果开发板I2C线路已自带则不用。数据线DVP这是最复杂的一部分。OV2640的图像数据、行同步HREF、场同步VSYNC、像素时钟PCLK等信号线需要连接到MCU的DVP接口或特定的GPIO组。你必须查阅梁山派开发板的原理图找到这些信号线对应的引脚。通常DVP数据线D0-D7会连接到MCU的同一组GPIO例如GPIOA或GPIOB以方便DMA快速搬运。3. 核心移植过程详解移植的本质就是把为STM32F4写的驱动代码改成能在GD32F470上运行。两者都是ARM Cortex-M4内核外设也相似但寄存器名字和库函数可能有细微差别。咱们一步步来。3.1 第一步搞定SCCB通信SCCB是配置摄像头的钥匙。你需要通过它告诉摄像头输出什么格式的图像RGB565还是JPEG、分辨率多大、曝光怎么调等等。卖家提供的驱动里通常会有一个sccb.c和sccb.h文件里面实现了SCCB的读写函数。STM32用的是自家的I2C库HAL库或标准库而GD32用的是自家的驱动库。移植关键点初始化函数找到SCCB_Init()这类函数。里面会初始化GPIO模拟I2C方式或配置I2C外设。你需要将其替换为GD32的GPIO或I2C初始化代码。// 示例GD32的I2C初始化代码片段需根据实际引脚修改 void SCCB_Init(void) { // 1. 使能I2C和GPIO时钟 rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_I2C0); // 2. 配置GPIO为复用开漏模式I2C功能 gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7); // PB6:SCL, PB7:SDA // 3. 配置I2C参数 i2c_clock_config(I2C0, 100000, I2C_DTCY_2); // 标准模式100kHz i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00); i2c_enable(I2C0); i2c_ack_config(I2C0, I2C_ACK_ENABLE); }读写函数找到SCCB_WriteByte()和SCCB_ReadByte()函数。将里面STM32的HAL_I2C_Mem_Write、HAL_I2C_Mem_Read等函数替换为GD32对应的i2c_master_addressing、i2c_transfer7_byte等函数。这里需要仔细对照GD32的库函数手册。提示OV2640的SCCB设备地址通常是0x60写和0x61读。如果通信失败先用逻辑分析仪或示波器抓一下SCL和SDA的波形看看起始信号、地址、应答有没有问题。3.2 第二步配置OV2640寄存器驱动里会有一个ov2640.c文件里面有一大堆的初始化序列其实就是通过SCCB向摄像头内部的各个寄存器写入特定的值。// 示例设置图像输出格式为RGB565 static const struct sensor_reg ov2640_rgb565_regs[] { {0xff, 0x00}, // 选择寄存器组 {0xda, 0x08}, // 图像数据格式控制 {0xd7, 0x03}, // 更多格式控制 // ... 可能还有很多其他寄存器 {0xff, 0xff}, // 序列结束标记 };这部分通常不需要改动因为这是摄像头传感器本身的配置和主控MCU型号无关。你只需要确保上一步的SCCB通信函数是正常的然后调用OV2640_Init()或OV2640_RGB565_Mode()这样的函数这些配置序列就会被正确发送到摄像头。3.3 第三步处理图像数据流DVP接口这是移植中最核心、也最容易出问题的一步。OV2640通过DVP接口源源不断地输出图像数据MCU需要准确地把这些数据“接住”并存起来。关键概念VSYNC场同步一个帧开始的信号。VSYNC来一个脉冲表示新的一帧图像开始了。HREF行同步一行数据有效的信号。在HREF为高电平期间数据线上的数据才是有效的像素数据。PCLK像素时钟每个PCLK的上升沿或下降沿数据线上就出现一个像素的数据8位。移植关键点引脚与时钟配置将DVP的数据线D0-D7、VSYNC、HREF、PCLK引脚配置为正确的复用功能DVP或GPIO输入。必须参考GD32F470的数据手册和梁山派原理图确认这些引脚是否支持DVP功能以及对应的复用映射。使用DCMI数字摄像头接口GD32F470有DCMI外设它就是专门用来接收摄像头数据的能自动根据同步信号抓取数据大大减轻CPU负担。你需要初始化DCMI外设配置同步极性、数据宽度8位或10位、捕获模式等。// 示例GD32 DCMI初始化片段 void DCMI_Init(void) { // 使能DCMI和对应GPIO时钟 rcu_periph_clock_enable(RCU_DCMI); // ... 配置DVP数据引脚为复用功能 ... // 配置DCMI dcmi_init_para_struct dcmi_initpara; dcmi_struct_para_init(dcmi_initpara); dcmi_initpara.capture_mode DCMI_SNAP_MODE; // 快照模式 dcmi_initpara.synchro_mode DCMI_SYNCHRO_HARDWARE; // 硬件同步使用VSYNC/HREF dcmi_initpara.pckpolarity DCMI_PCKPOLARITY_RISING; // 像素时钟上升沿有效 dcmi_initpara.vspolarity DCMI_VSPOLARITY_LOW; // VSYNC低电平有效 dcmi_initpara.hspolarity DCMI_HSPOLARITY_LOW; // HREF低电平有效 dcmi_initpara.frame_rate DCMI_FRAME_RATE_ALL; // 捕获所有帧 dcmi_initpara.data_width DCMI_DATA_8BITS; // OV2640 DVP输出8位数据 dcmi_init(dcmi_initpara); }配置DMA图像数据量很大一帧RGB565的QVGA图像就有3202402150KB必须用DMA直接存储器访问把DCMI接收到的数据直接搬运到内存中的缓冲区否则CPU根本忙不过来。你需要配置一个DMA通道源地址是DCMI的数据寄存器目标地址是你定义的数组帧缓冲区。开启捕获配置好DCMI和DMA后使能DCMI它就会在VSYNC信号到来时自动开始一帧的捕获并通过DMA将数据填充到缓冲区。一帧完成后会产生一个中断你可以在中断里标记“新一帧数据准备好了”。3.4 第四步在屏幕上显示图像数据抓取到内存里之后最后一步就是把它“画”到屏幕上。这取决于你用的什么屏幕。如果是RGB/MCU屏通常通过FSMC灵活的静态存储器控制器或GPIO模拟8080时序来驱动。你需要将帧缓冲区里的RGB565数据通过FSMC或GPIO写入到屏幕的GRAM显存中。可以使用DMA2D如果有的话来加速数据搬运和格式转换。如果是LVDS/MIPI屏可能需要通过LTDC液晶显示控制器外设。你需要配置LTDC的层Layer将帧缓冲区的地址分配给某一层LTDC会自动将图层内容混合后输出给屏幕。一个简单的显示思路以FSMC屏为例在内存中开辟两个缓冲区frame_buffer1和frame_buffer2双缓冲防止撕裂。DCMIDMA将摄像头数据填充到frame_buffer1。填充完成后启动另一个DMA或memcpy将frame_buffer1的数据搬运到屏幕的GRAM地址。在搬运的同时DCMI可以开始捕获下一帧到frame_buffer2。如此循环。4. 调试心得与常见问题移植不可能一帆风顺这里分享几个我踩过的坑没图像全黑或全白首先检查SCCB通信用调试器单步跟踪看OV2640_Init函数里的SCCB读写是否都返回成功。可以用I2C工具扫描一下总线看能否找到0x60地址的设备。检查DVP引脚配置确认VSYNC、HREF、PCLK和数据线引脚是否全部正确配置为复用功能且极性上升沿/下降沿高有效/低有效与摄像头模块输出的一致。极性配反是常事。检查缓冲区地址和大小确保DMA的目标地址是你定义的数组且数组大小足够容纳一帧图像例如RGB565 QVGA是150KB。图像错位、撕裂、颜色不对检查数据对齐和格式确认DCMI配置的数据宽度8位/10位与摄像头输出是否匹配。RGB565格式下两个字节组成一个像素要确保在内存中的排列顺序RGB高位在前还是低位在前与屏幕期望的一致。检查同步信号用逻辑分析仪同时抓取VSYNC、HREF、PCLK和一条数据线如D0看看波形是否符合预期。一帧内应该有很多行HREF脉冲一行内有很多PCLK脉冲。双缓冲没处理好如果用了双缓冲确保在DMA传输完成中断里正确切换缓冲区指针并且在新一帧完全捕获完之前不要开始向屏幕传输。图像卡顿帧率低优化数据搬运使用DMA2D如果MCU支持来搬运和转换图像数据比CPU的memcpy快得多。降低分辨率如果屏幕分辨率不高可以配置OV2640输出更小的分辨率比如从UXGA降到QVGA数据量会锐减帧率自然上去。使用JPEG模式如果只是显示不需要对图像做处理可以配置OV2640直接输出JPEG格式。一帧QVGA的JPEG可能只有几KB通过串口发送给上位机或用解码芯片显示都非常快。不过这就需要MCU或外部芯片具备JPEG解码能力。最后强烈建议你下载并运行立创提供的那个移植成功示例代码。把它烧录到板子上看到摄像头画面正常显示后再去对照着源码一点点理解每一个配置、每一行代码的作用。有了成功的现象作为参照调试你自己的代码就会更有方向。祝你移植顺利
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2421749.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!