DCMI简介
STM32F4的DCMI接口包括如下信号
1,数据据输入(D[0:13]),接摄像头的数据输出。
2,水平同步(行同步)输入(HSYNC),接摄像头的HSYNC/HREF信号,用于确定一行数据的接收情况。
3,垂直同步(场同步)输入(VSYNC),接摄像头的VSYNC信号,用于确定一帧数据的接收情况。
4,像素时钟输入(PIXCLK),接摄像头的PCLK信号,同步时钟,数据接收同步信号。
DCMI接口的数据与PIXCLK(即PCLK)保持同步,并根据像素时钟的极性在像素时钟上升沿/下降沿发生变化。HSYNC(HREF)信号指示行的开始/结束,VSYNC信号指示帧的开始/结束。
DCMI的使用
1、配置时钟,初始化IO口
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE, ENABLE); //使能GPIOA B C E 时钟
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE); //使能DCMI时钟
//PA4/6初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6; //PA4/6 复用功能输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6; // PB6/7 复用功能输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_11; //PC6/7/8/9/11 复用功能输出
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; //PE5/6 复用功能输出
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI); //PA4 DCMI_HSYNC
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI); //PA6 DCMI_PCLK
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI); //PB7 DCMI_VSYNC
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI); //PC6 DCMI_D0
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI); //PC7 DCMI_D1
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_DCMI); //PC8 DCMI_D2
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_DCMI); //PC9 DCMI_D3
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_DCMI); //PC11 DCMI_D4
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI); //PB6 DCMI_D5
GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_DCMI); //PE5 DCMI_D6
GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_DCMI); //PE6 DCMI_D7
2、根据时序配置DCMI接口
DCMI_DeInit();//清除原来的设置
DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; //连续模式
DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; //全帧捕获
DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b; //8位数据格式
DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; //HSYNC 低电平有效
DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; //PCLK 上升沿有效
DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware; //硬件同步HSYNC,VSYNC
DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_Low; //VSYNC 低电平有效
DCMI_Init(&DCMI_InitStructure);
DCMI_Cmd(ENABLE); //DCMI使能
//中断视情况配置
DCMI_ITConfig(DCMI_IT_FRAME, ENABLE); //开启帧中断
NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
代码 DCMI 初始化结构体
1 /**
2 * @brief DCMI 初始化结构体
3 */
4 typedef struct
5 {
6 uint16_t DCMI_CaptureMode; /*选择连续模式或拍照模式 */
7 uint16_t DCMI_SynchroMode; /*选择硬件同步模式还是内嵌码模式 */
8 uint16_t DCMI_PCKPolarity; /*设置像素时钟的有效边沿*/
9 uint16_t DCMI_VSPolarity; /*设置 VSYNC 的有效电平*/
10 uint16_t DCMI_HSPolarity; /*设置 HSYNC 的有效边沿*/
11 uint16_t DCMI_CaptureRate; /*设置图像的采集间隔 */
12 uint16_t DCMI_ExtendedDataMode; /*设置数据线的宽度 */
13 } DCMI_InitTypeDef;
这些结构体成员说明如下,其中括号内的文字是对应参数在 STM32 标准库中定义的宏:
(1) DCMI_CaptureMode
本成员设置 DCMI的捕获模式,可以选择为连续摄像(DCMI_CaptureMode_Continuous)
或单张拍照 DCMI_CaptureMode_SnapShot。
(2) DCMI_SynchroMode
本成员设置 DCMI数据的同步模式,可以选择为硬件同步方式
(DCMI_SynchroMode_Hardware)或内嵌码方式(DCMI_SynchroMode_Embedded)。
(3) DCMI_PCKPolarity
本成员用于配置 DCMI接口像素时钟的有效边沿,即在该时钟边沿时,DCMI会对数
据线上的信号进行采样,它可以被设置为上升沿有效(DCMI_PCKPolarity_Rising)或下
降沿有效(DCMI_PCKPolarity_Falling)。
(4) DCMI_VSPolarity
本成员用于设置 VSYNC 的有效电平,当 VSYNC 信号线表示为有效电平时,表示新
的一帧数据传输完成,它可以被设置为高电平有效(DCMI_VSPolarity_High)或低电平
有效(DCMI_VSPolarity_Low)。
(5) DCMI_HSPolarity
类似地,本成员用于设置 HSYNC 的有效电平,当 HSYNC 信号线表示为有效电平时,
表示新的一行数据传输完成,它可以被设置为高电平有效(DCMI_HSPolarity_High)或
低电平有效(DCMI_HSPolarity_Low)。
(6) DCMI_CaptureRate
本成员可以用于设置 DCMI捕获数据的频率,可以设置为全采集、半采集或 1/4 采集
(DCMI_CaptureRate_All_Frame/ 1of2_Frame/ 1of4_Frame),在间隔采集的情况下,
STM32的 DCMI外设会直接按间隔丢弃数据。
(7) DCMI_ExtendedDataMode
本成员用于设置 DCMI的数据线宽度,可配置为 8/10/12及 14位数据线宽
(DCMI_ExtendedDataMode_8b/10b/12b/14b)。
配置完这些结构体成员后,我们调用库函数 DCMI_Init 即可把这些参数写入到 DCMI
的控制寄存器中,实现 DCMI的初始化。
DCMI的DMA传输
DCMI接收到的数据,存储在DCMI_DR寄存器(32位)里面,我们采用8位数据宽度,所以每4个像素时钟,才会捕获完32位数据,第一个字节存放在LSB位置,第四个字节存放在MSB位置,如下图所示:
DCMI支持DMA传输,当DCMI_CR寄存器中的CAPTURE位置1时,激活DMA接口。摄像头接口每次在其寄存器(DCMI_DR)中收到一个完整的32位数据块时,都将发一个DMA请求,由DMA将DCMI_DR寄存器的值搬运到目的地址。
/**
* @brief 配置 DCMI/DMA 以捕获摄像头数据
* @param DMA_Memory0BaseAddr:本次传输的目的首地址
* @param DMA_BufferSize:本次传输的数据量(单位为字,即4字节)
*/
void OV2640_DMA_Config(uint32_t DMA_Memory0BaseAddr,uint16_t DMA_BufferSize)
{
DMA_InitTypeDef DMA_InitStructure;
/* 配置DMA从DCMI中获取数据*/
/* 使能DMA*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_Cmd(DMA2_Stream1,DISABLE);
while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}
DMA_InitStructure.DMA_Channel = DMA_Channel_1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&DCMI->DR;//外设地址为:DCMI->DR
DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;//DMA传输的目的地址(传入的参数)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize =DMA_BufferSize; //传输的数据大小(传入的参数)
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//数据地址,自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/*DMA初始化 */
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1,ENABLE);
while(DMA_GetCmdStatus(DMA2_Stream1) != ENABLE){}
}
传输设置
//DCMI,启动传输
void DCMI_Start(void)
{
DMA_Cmd(DMA2_Stream1, ENABLE);//开启DMA2,Stream1
DCMI_CaptureCmd(ENABLE);//DCMI捕获使能
}
//DCMI,关闭传输
void DCMI_Stop(void)
{
DCMI_CaptureCmd(DISABLE);//DCMI捕获使关闭
while(DCMI->CR&0X01); //等待传输结束
DMA_Cmd(DMA2_Stream1,DISABLE);//关闭DMA2,Stream1
}