| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> [022] [STM32] 使用DCMI(DVP)驱动OV2640 -> 正文阅读 |
|
[嵌入式][022] [STM32] 使用DCMI(DVP)驱动OV2640 |
STM32
Contents
OV2640摄像头简介
OV2640引脚
及功能框图
SCCB时序
OV2640的寄存器
像素输出时序
STM32的DCMI外设
外部接口及时序
DCMI时钟
DCMI功能概述
数据格式说明
DCMI中断
STM32的DCMI编程
控制相关结构体
软件设计(使
用CH32验证)
|
管脚名称 | 管脚类型 | 管脚描述 |
---|---|---|
SIO_C | 输入 | SCCB总线的时钟线,可类比I2C的SCL |
SIO_D | I/O | SCCB总线的数据线,可类比I2C的SDA |
RESETB | 输入 | 系统复位管脚,低电平有效 |
PWDN | 输入 | 掉电/省电模式,高电平有效 |
HREF | 输出 | 行同步信号 |
VSYNC | 输出 | 帧同步信号 |
PCLK | 输出 | 像素同步时钟输出信号 |
XCLK | 输入 | 外部时钟输入端口,可接外部晶振 |
Y0…Y9 | 输出 | 像素数据输出端口 |
表中高亮引脚即为VGA
时序输出引脚。
控制寄存器
控制寄存器配置摄像头的相关参数,如对比度、曝光参数等,通过SCCB
(与I2C
类似)外设的SIO_C和SIO_D引脚写入。
通信、控制信号及时钟
其中PCLK
、HREF
及VSYNC
分别是像素同步时钟、行同步信号以及帧同步信号。RESETB
引脚为低电平时,用于复位整个传感器芯片,PWDN
用于控制芯片进入低功耗模式。
XCLK
是用于驱动整个传感器芯片的时钟信号,由外部时钟源(外接晶振或由外部控制器提供)输入到OV2640;而PCLK是OV2640输出数据时的同步信号,由OV2640输出。
感光矩阵用于将光信号转化为电信号,在2,010,624像素中, 有1,991,040 (1632x1220)是活跃的。 经过AMP(Analog Amplifier)模拟放大、(Gain Control)增益控制、10位A/D转换、通道平衡(Channel Balance)、黑电平1补偿(Black Level Compensation)处理,将信号存储成由像素点表示的数字图像。
DSP
处理单元,它会根据控制寄存器的配置做一些基本的图像处理运算,如色彩饱和度调整、边缘增强等。这部分还包含了图像格式转换单元及压缩单元,转换出的数据最终通过Y0-Y9引脚输出,一般使用8根据数据线传输,此时仅使用Y2-Y9引脚,OV2640的数据信号与外部器件的连接方式:外部控制器对OV2640
寄存器的配置参数通过SCCB总线传输配置,而SCCB总线时序与I2C基本一致,所以在STM32中可直接使用片上I2C外设与它通讯。(OV2640 device slave addresses are 0x60
for write and 0x61
for read.)
SCCB的起始信号、停止信号及数据有效性与I2C完全一样。
SCCB协议中定义的读写操作与I2C同样一致。
SCCB定义了两种写操作:
三步写操作
phase1:发送从设备的ID地址+W标志(相当于I2C的设备地址:7位设备地址+读写方向标志)
phase2:发送从设备目标寄存器的8位地址
phase3:发送要写入寄存器的8位数据
图中的“X”数据位可写入1或0,对通讯无影响。
二步写操作
两步写相对于三步写操作,没有phase3,一般用来配合后面的读寄存器数据操作,它与读操作一起使用,实现I2C的复合过程。
两步读操作,用于读取从设备目的寄存器中的数据。
phase1:发送从设备的设备ID+R标志(设备地址+读方向标志)和自由位
phase2:读取寄存器中的8位数据和写NA 位(非应答信号)
由于两步读操作「没有确定目的寄存器的地址」,所以在读操作前,必须有一个两步写操作,以提供读操作中的寄存器地址。
查询ov2640datasheet.pdf
进行了解,通过寄存器配置可控制输出图像的分辨率大小、图像格式、图像处理及图像方向等。
注意OV2640有两组寄存器,这两组寄存器有部分地址重合,通过设置地址为0xFF
的RA_DLMT
寄存器可以切换寄存器组:
官方还提供了OV2640_Camera_app.pdf
文档,它针对不同的配置需求,提供了配置范例:
帧率配置(0xFF = 0)
PLCK分频值(0xFF = 0)
4
的整数倍)(0xFF = 0)单个像素大小取决于图像格式,如RGB565格式单个像素大小为2字节。
OV2640输出的每帧图像的数据默认从左到右,从上到下输出每个采集像素(可通过寄存器修改方向),如下图所示。与控制液晶屏输出图像数据类似。
OV2640输出图像时则使用UXGA1600×1200@15fps
, SVGA@30fps
, 或CIF@60fps
时序,通过COM7寄存器切换模式。
自定义窗口像素范围:
2 x 4 to 1632 x 1220
800 x 600
408 x 304
视频格式尺寸详见「VGA、QVGA、CIF、SXGA等视频格式尺寸解释」
它们的像素输出格式如下图所示:
下面以UXGA
为例进行分析:
数据在PCLK上升沿阶段维持稳定,并在1个像素同步时钟PCLK的驱动下发送[9:0]位数据信号。
当行同步信号HREF
为高电平时,像素数据依次传输,每传完一行数据时,HREF
输出一个电平跳变信号间隔;当帧同步信号VSYNC
为低电平时,各行的像素数据依次开始传输,每传完一帧图像时,VSYNC
会输出一个电平跳变信号。
UXGA
模式下的Frame/Pixel Rates:
STM32F4系列的控制器具有DCMI(Digital camera Interface)数字摄像头接口,它支持使用类似VGA时序获取图像数据流,支持原始的按行、帧格式来组织的图像数据,如YUV、RGB,也支持接收JPEG格式压缩的数据流。接收数据时,主要使用HSYNC及VSYNC信号来同步。
DCMI向外部引出的信号线,方向均为输入:
引脚名称 | 说明 |
---|---|
DCMI_D[0:13] | 数据线 |
DCMI_PIXCLK | 像素同步时钟 |
DCMI_HSYNC | 行同步信号(水平同步信号) |
DCMI_VSYNC | 帧(场)同步信号(垂直同步信号) |
其中DCMI_D数据线的数量可选8、10、12或14位(通过DCMI_CR
的EDM[1:0]控制]),其中10/12/14需扩展到16位进行存储。
以10位数据为例,此时DCMI接口将捕获输入至D[0…9]的10位数据,将其存至16位字的低10位,其余最高有效位清零(位11~15)。因此,此情况下每两个像素时钟周期会生成1个32位的字。
一般采用某端口的编号连续的引脚读取数据。如传输8位数据时,采用PB8~PB15引脚读取,直接读取GPIOB端口IDR寄存器的高8位即可。
DCMI通讯时序示例:
图中DCMI_PIXCLK
的捕获沿为下降沿,DCMI_HSYNC
和DCMI_VSYNC
的有效电平为1。(捕获沿、有效电平均可通过寄存器配置,HSYNC和VSYNC的有效电平指的是采集完一行/帧图像后的状态电平)
STM32内部使用HCLK(168M)为DCMI外设提供时钟源,从DCMI引出DCMI_IT信号至中断控制器,并可通过DMA_REQ信号发送DMA请求。
DCMI从外部接收数据时,在HCLK的上升沿时对PIXCLK
同步的信号进行采样,PIXCLK的最大周期必须大于2.5 个 HCLK 周期,即最高频率为HCLK的1/4(42M)。
使用HSYNC和VSYNC作为同步信号的方式(OV2640即采用此同步方式),VSYNC用于指示一帧图像的起始, HSYNC被用作数据有效信号。其时序图如下图所示:
HSYNC与VSYNC的有效极性通过DCMI_CR的
HSPOL
位和VSPOL
位配置。
根据摄像头模块/模式的不同,可能在水平/垂直同步期间内发送数据,但此时由于系统会忽略HSYNC
/VSYNC
信号有效电平期间内接收的所有数据,HSYNC
/VSYNC
信号相当于消隐信号。
选择硬件同步模式并启用捕获(DCMI_CR
中的CAPTURE
位置1)时,数据传输将与VSYNC
信号的无效电平(从有效电平切换到无效电平,即开始下一帧时)同步,每一帧结束时都将激活VSIF
(垂直同步中断标志)。
注意:对于压缩数据(如JPEG格式),DCMI仅支持硬件同步模式。
该同步模式一般在特定场合下使用。
使用数据流中嵌入的特定的32 位码来表示同步信息,并且需用0x00
和0xFF
来表示编码,所以要确保 0x00 和 0xFF 值仅用于同步(不用于数据中)。共有 4 种同步码类型,均采用 0xFF0000XY 格式(XY值可编程)。
摄像头2种模式下的同步码如下表所示:
模式2的内嵌码 | 模式1的内嵌码 |
---|---|
帧开始**(FS)** | 有效行开始(SAV) |
帧结束**(FE)** | 有效行结束(EAV) |
行开始**(LS)** | 帧间消隐期内的行开始(SAV),其中消隐期内的即为无效数据 |
行结束**(LS)** | 帧间消隐期内的行结束(EAV),其中消隐期内的即为无效数据 |
若FS=0xff
意味着所有除此之外的同步码均视为有效的帧结束同步码。在此模式下,一旦使能DCMI,将在首次出现帧结束 (FE) 同步码并且后接帧开始(FS) 同步码之后开始捕获帧。
此外,还针对FS/E和LS/E同步码实现了非屏蔽位功能(通过DCMI_ESUR
寄存器配置),这样可仅用同步码中未被屏蔽的位进行比较。因此,可以选择一个位用于同步码的比较,来检测FS/E和LS/E,同时可用多个同步码表示FS/E和LS/E,它们仅在未被屏蔽的位相同即可。
「示例」
FS = 0x2e,FSU(FS的非屏蔽码) = 0x30。则只需比较位4和位5即可。
注意:只有8
位并行数据接口宽度支持内嵌码同步码。
为了对AHB上数据传输加以管理,在DCMI接口上实现了 4 个字(32bit x4)深度的 FIFO,用以缓冲接收到的数据。
DMCI向AHB总线读取数据时读指针自动递增,向FIFO写入数据时写指针自动递增。
注意:此FIFO没有溢出保护,如果数据传输率超过了AHB接口能够承受的速率,FIFO中的数据就会被覆盖。当如同步信号出错或FIFO溢出时,FIFO将复位,DCMI接口将等待新的数据帧开始。
DCMI接口挂载在AHB总线上,在AHB总线中有一个DCMI接口的数据寄存器,当我们读取该寄存器时,它会从FIFO中获取数据,并且FIFO中的数据指针会自动进行偏移。
当DCMI_CR
寄存器中的CAPTURE
位置1时,激活DMA接口。摄像头接口每次在其寄存器中收到一个完整的32
位数据块时,都将触发一个DMA请求。
快照模式(单帧)
DCMI_CR 寄存器中的 CM =1。当DCMI_CR的CAPTURE位置 1 后,DCMI等待帧起始信号,然后对数据采样。采样完一帧数据后自动清除CAPTURE
位,禁止再次采样。
注意:若数据溢出,则此帧丢失且依然会清除CAPTURE
位。
连续采集模式
DCMI_CR 寄存器中的 CM = 0。当DCMI_CR的CAPTURE位置 1 后,DCMI等待帧起始信号,然后对数据采样,采样过程一直持续至CAPTURE位被清零。CAPTURE 位清零后,采集过程将持续到当前帧结束。
在连续采集模式下,通过DCMI_CR中的FCRC
位可设置捕获率来控制采集的数据量,如下图所示:
DCMI_CR寄存器的CROP
位置1后,即开启采集功能。可从采集的图像从选择一个矩形窗口来裁剪图像。(注意若窗口大小超出图片大小,则进捕获图片大小)。
通过DCMI_CSTRT的VST
和HOFFCNT
位可设置窗口起点(Y,X),DCMI_CSIZE的VLINE
和CAPCNT
位可设置水平和垂直尺寸,如下图所示:
注意:CAPCNT
值只能是4的倍数(两个最低有效位强制为0),才能通过DMA正确传输数据。
如果在捕获DCMI_CWSIZE
寄存器中指定行数完成之前,VSYNC信号已有效,那么捕获将停止,并且在中断使能时生成IT_FRAME中断。
DMCI支持单色、RGB 和 YCbCr数据格式(最大输入大小为2048×2048像素),以及JPEG压缩格式(大小无限制)。
对于单色、RGB 和 YCbCr,帧缓冲区以光栅模式存储(即从顶部像素行到底部像素行,从像素行的左侧到右侧)。使用32
位字。仅支持小端对齐格式。
DCMI_CR的JPEG位置1时,用于JPEG2(Joint photographic experts group)图像数据传输。
JPEG图像不按行和帧存储,因此VSYNC
信号用于启动捕获过程,而HSYNC
则用作数据使能信号。行中包含的字节数可能不是4的倍数,因此处理此类情况时应十分谨慎,因为需要每次从捕获的数据形成一个完整的32位字时,才生成一个DMA请求。检测到帧结束并且尚未凑成32位字时,将使用“0”进行填充,并触发一个DMA请求。
注意:裁剪功能和内嵌码同步不适用JPEG格式。
每个像素 8 位,单色逐行视频格式的数据存储方式如下表所示:
仅支持16BPP(每个像素16位):RGB565
(每32位表示2个像素);不支持24BPP(托盘化格式)和灰度格式。
像素分量包括 R(红色)、G(绿色)和 B(蓝色),一帧数据中各个分量交替间隔存储(低/高16位字节中R、G、B从MSB->LSB
依次存储)。以 RGB 逐行视频格式存储数据格式如下表所示:
注意:若OV2640红色R与蓝色B错位,可通过0xda
地址的bit0
配置数据LSB先行还是MSB先行,同时0xc2
地址的寄存器bit4
会影响该的配置。
经实际测试,如下配置在UXGA
模式下RGB颜色可正常显示:
0xFF, 0x00, // 切换到DSP地址
0xc2, 0x0c, //^ bit4配置为1时 swap RGB中的R与B
0xda, 0x09, // BIT[3:2] = 10 - RGB565 BIT[0] = 1 LSB先行
YCbCr 4:2:2。像素分量包括Y(亮度)、Cb(蓝色色度)和Cr(红色色度)。每个分量都采用8位进行编码。亮度和色度(交替)存储在一起,如下表所示。
全局中断 (IT_DCMI) 是所有单个中断的逻辑或运算所得结果。
typedef struct
{
uint16_t DCMI_CaptureMode; /*!< 捕获模式,可选连续模式或快照模式 */
uint16_t DCMI_SynchroMode; /*!< 同步模式,可选硬件同步模式或内嵌码模式 */
uint16_t DCMI_PCKPolarity; /*!<像素时钟PIXCLK的有效边沿 */
uint16_t DCMI_VSPolarity; /*!< VSYNC的有效电平 */
uint16_t DCMI_HSPolarity; /*!< HSYNC的有效电平 */
uint16_t DCMI_CaptureRate; /*!< 捕获频率,可选all或1/2或1/4 */
uint16_t DCMI_ExtendedDataMode; /*!< 数据线宽度 可选8/10/12/14*/
} DCMI_InitTypeDef;
由于项目使用
ch32v307
芯片,因此基于此芯片完成本次实验,STM32配置流程类似。
使用DVP外设(即STM32的DCMI外设)采集摄像头数据,将DVP的FIFO数据缓存到内部RAM中,再使用DMA的M2M模式搬运到FSMC外设控制的内存中,最后让图像在屏幕上显示。
int8_t OV2640_Init(uint16_t img_w, uint16_t img_h)
{
uint16_t ov_pid, ov_mid;
OV2640_IDTypeDef OV2640_Camera_ID;
img_width = img_w;
img_height = img_h;
OV2640_GPIO_Init();
OV2640_Reset();
OV2640_ReadID(&OV2640_Camera_ID);
ov_mid = OV2640_Camera_ID.MIDH << 8 | OV2640_Camera_ID.MIDL;
ov_pid = OV2640_Camera_ID.PIDH << 8 | OV2640_Camera_ID.PIDL;
DBG_RAW("MID: %x", ov_mid);
DBG_RAW("PID: %x", ov_pid);
if (ov_mid != OV2640_MID) return -1;
else if (ov_pid != OV2640_PID) return -2;
OV2640_DMA_Init((uint32_t)dvp_buf0, FSMC_LCD_DATA_ADDR, lcd.width);
OV2640_DVP_Init((uint32_t*)dvp_buf0, (uint32_t*)dvp_buf1, RGB565_COL_NUM, RGB565_ROW_NUM);
return 0;
}
理论配置:OV2640捕获沿PCLK上升沿采样,HSYNC低电平有效,VSYNC高电平有效;
实际配置:OV2640捕获沿PCLK上升沿采样,HSYNC高电平有效,VSYNC高电平有效。(可见理论与实际存在差异zz)
注:有效电平指的是采集完一行/帧图像后的状态电平
ch32v307
的DMA与DVP外设关键信息如下:
「DMA外设(与STM32基本无异)」
DMA传输一次性最大数据量为65535
,同时M2M
不支持循环模式,且一但使能即开始后传输数据,因此数据传输完后需要手动加载DMA_CNTRx
剩余传输数据数目寄存器的初始值,同时若DMA_PADDRx
外设基址寄存器和DMA_MADDRx
内存基址寄存器配置了地址增量模式,需要重新设置基址。
DMA通道关闭后,DMA_PADDRx
/DMA_MADDRx
/DMA_CNTRx
/DMA_CFGRx
寄存器仅当相应的DMA通道关闭下才可写入。
「DAP外设(即STM32的DCMI外设)」
RGB
和YUV
数据流,硬件在每次帧信号从无效电平变为有效电平时会复位选择BUF0开始,存满一行数据将会切换的BUF1,实现交替存储。R16_DVP_COL_NUM
表示一行数据的有效PCLK周期数,R16_DVP_ROW_NUM
表示一帧图像数据内包含的行数;JPEG
压缩数据,硬件会根据设置的DMA接收长度设置BUF0和BUF1的切换阈值。此模式下,R16_DVP_COL_NUM
用于配置DMA长度,R16_DVP_ROW_NUM
寄存器不起作用。CH32的DAP外设与STM32的DCMI外设差异较大,其使用双BUF的FIFO缓存数据。在RGB模式下每个BUF交替采集每行数据;同时CH32的DMA不支持直接将DVP外设的FIFO数据通过DMA传输到内存(P2M),因此只能使用RAM先缓存FIFO数据,再通过DMA的M2M模式传输。
volatile uint16_t dvp_buf0[OV2640_RGB565_WIDTH];
volatile uint16_t dvp_buf1[OV2640_RGB565_WIDTH]
volatile uint32_t frame_cnt = 0, addr_cnt = 0, href_cnt = 0;
void DVP_IRQHandler(void)
{
if (DVP->IFR & RB_DVP_IF_ROW_DONE) // 行中断
{
/* Write 0 clear 0 */
DVP->IFR &= ~RB_DVP_IF_ROW_DONE; //clear Interrupt
if ((addr_cnt & 0x01) == 0) //buf1 done
{
addr_cnt++;
DMA_Transmit_Set((uint32_t)dvp_buf0, lcd.width); //Send DVP data to LCD
}
else //buf0 done
{
addr_cnt++;
DMA_Transmit_Set((uint32_t)dvp_buf1, lcd.width);
}
href_cnt++;
}
if (DVP->IFR & RB_DVP_IF_FRM_DONE)
{
DVP->IFR &= ~RB_DVP_IF_FRM_DONE; //clear Interrupt
addr_cnt = 0;
href_cnt = 0;
}
if (DVP->IFR & RB_DVP_IF_STR_FRM) // 帧起始中断
{
DVP->IFR &= ~RB_DVP_IF_STR_FRM;
// 每帧图像采集完需要重新设置屏幕开窗大小, 否则会有图像分割现象
LCD_OpenWindow((lcd.width - img_width) / 2, (lcd.height - img_height) / 2, img_width, img_height);
frame_cnt++;
}
if (DVP->IFR & RB_DVP_IF_STP_FRM) // 帧结束中断
{
DVP->IFR &= ~RB_DVP_IF_STP_FRM;
}
if (DVP->IFR & RB_DVP_IF_FIFO_OV)
{
DVP->IFR &= ~RB_DVP_IF_FIFO_OV;
LOG_RAW("Dvp FIFO overflow!\n");
}
}
在每行数据采集完后会触发行中断,在行中断里使用DMA_Transmit_Set
函数切换相应的buf地址为DMA源寄存器地址,并重新设置传输的数据量:
void DMA_Transmit_Set(uint32_t source_addr, uint16_t size)
{
DMA_Cmd(DMA2_Channel5, DISABLE);
DMA2_Channel5->CNTR = size;
DMA2_Channel5->PADDR = source_addr;
DMA_Cmd(DMA2_Channel5, ENABLE);
}
为了防止有时DMA 出现传输错误或传输速度跟不上导致数据错位、偏移等问题,需要在帧中断里使用LCD_OpenWindow
函数重新设置LCD显示窗口,可使它重新开始一帧的数据传输。
frame_cnt
记录采集的图像帧数,可以用于计算FPS:
uint16_t fps_cnt = 0;
void TIM1_UP_IRQHandler(void) // 5ms周期
{
if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
if (++fps_cnt >= 1000){
DBG_RAW("FPS:%.1f/s", (float)frame_cnt / 5.0);
fps_cnt = 0;
frame_cnt = 0;
}
}
}
END
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 22:37:48- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |