215 lines
8.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "sys.h"
#include "dcmi.h"
#include "lcd.h"
#include "ltdc.h"
#include "led.h"
#include "ov5640.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32H7开发板
//DCMI驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2017/8/15
//版本V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
DCMI_HandleTypeDef DCMI_Handler; //DCMI句柄
DMA_HandleTypeDef DMADMCI_Handler; //DMA句柄
u8 ov_frame=0; //帧率
extern void jpeg_data_process(void); //JPEG数据处理函数
//DCMI初始化
void DCMI_Init(void)
{
DCMI_Handler.Instance=DCMI;
DCMI_Handler.Init.SynchroMode=DCMI_SYNCHRO_HARDWARE; //硬件同步HSYNC,VSYNC
DCMI_Handler.Init.PCKPolarity=DCMI_PCKPOLARITY_RISING; //PCLK 上升沿有效
DCMI_Handler.Init.VSPolarity=DCMI_VSPOLARITY_LOW; //VSYNC 低电平有效
DCMI_Handler.Init.HSPolarity=DCMI_HSPOLARITY_LOW; //HSYNC 低电平有效
DCMI_Handler.Init.CaptureRate=DCMI_CR_ALL_FRAME; //全帧捕获
DCMI_Handler.Init.ExtendedDataMode=DCMI_EXTEND_DATA_8B; //8位数据格式
HAL_DCMI_Init(&DCMI_Handler); //初始化DCMI此函数会开启帧中断
//关闭行中断、VSYNC中断、同步错误中断和溢出中断
//__HAL_DCMI_DISABLE_IT(&DCMI_Handler,DCMI_IT_LINE|DCMI_IT_VSYNC|DCMI_IT_ERR|DCMI_IT_OVR);
//关闭所有中断函数HAL_DCMI_Init()会默认打开很多中断,开启这些中断
//以后我们就需要对这些中断做相应的处理,否则的话就会导致各种各样的问题,
//但是这些中断很多都不需要所以这里将其全部关闭掉也就是将IER寄存器清零。
//关闭完所有中断以后再根据自己的实际需求来使能相应的中断。
DCMI->IER=0x0;
__HAL_DCMI_ENABLE_IT(&DCMI_Handler,DCMI_IT_FRAME); //使能帧中断
__HAL_DCMI_ENABLE(&DCMI_Handler); //使能DCMI
}
//DCMI底层驱动引脚配置时钟使能中断配置
//此函数会被HAL_DCMI_Init()调用
//hdcmi:DCMI句柄
void HAL_DCMI_MspInit(DCMI_HandleTypeDef* hdcmi)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_DCMI_CLK_ENABLE(); //使能DCMI时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
//初始化PA4
GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_6;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽复用
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF13_DCMI; //复用为DCMI
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化
//PB7,8,9
GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
HAL_GPIO_Init(GPIOB,&GPIO_Initure); //初始化
//PC6,7,8,9,11
GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|\
GPIO_PIN_9|GPIO_PIN_11;
HAL_GPIO_Init(GPIOC,&GPIO_Initure); //初始化
//PD3
GPIO_Initure.Pin=GPIO_PIN_3;
HAL_GPIO_Init(GPIOD,&GPIO_Initure); //初始化
HAL_NVIC_SetPriority(DCMI_IRQn,2,2); //抢占优先级1子优先级2
HAL_NVIC_EnableIRQ(DCMI_IRQn); //使能DCMI中断
}
//DCMI DMA配置
//mem0addr:存储器地址0 将要存储摄像头数据的内存地址(也可以是外设地址)
//mem1addr:存储器地址1 当只使用mem0addr的时候,该值必须为0
//memblen:存储器位宽,可以为:DMA_MDATAALIGN_BYTE/DMA_MDATAALIGN_HALFWORD/DMA_MDATAALIGN_WORD
//meminc:存储器增长方式,可以为:DMA_MINC_ENABLE/DMA_MINC_DISABLE
void DCMI_DMA_Init(u32 mem0addr,u32 mem1addr,u16 memsize,u32 memblen,u32 meminc)
{
__HAL_RCC_DMA1_CLK_ENABLE(); //使能DMA1时钟
__HAL_LINKDMA(&DCMI_Handler,DMA_Handle,DMADMCI_Handler); //将DMA与DCMI联系起来
__HAL_DMA_DISABLE_IT(&DMADMCI_Handler,DMA_IT_TC); //先关闭DMA传输完成中断(否则在使用MCU屏的时候会出现花屏的情况)
DMADMCI_Handler.Instance=DMA1_Stream1; //DMA1数据流1
DMADMCI_Handler.Init.Request=DMA_REQUEST_DCMI; //DCMI的DMA请求
DMADMCI_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //外设到存储器
DMADMCI_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
DMADMCI_Handler.Init.MemInc=meminc; //存储器增量模式
DMADMCI_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD; //外设数据长度:32位
DMADMCI_Handler.Init.MemDataAlignment=memblen; //存储器数据长度:8/16/32位
DMADMCI_Handler.Init.Mode=DMA_CIRCULAR; //使用循环模式
DMADMCI_Handler.Init.Priority=DMA_PRIORITY_HIGH; //高优先级
DMADMCI_Handler.Init.FIFOMode=DMA_FIFOMODE_ENABLE; //使能FIFO
DMADMCI_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_HALFFULL; //使用1/2的FIFO
DMADMCI_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器突发传输
DMADMCI_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
HAL_DMA_DeInit(&DMADMCI_Handler); //先清除以前的设置
HAL_DMA_Init(&DMADMCI_Handler); //初始化DMA
//在开启DMA之前先使用__HAL_UNLOCK()解锁一次DMA,因为HAL_DMA_Statrt()HAL_DMAEx_MultiBufferStart()
//这两个函数一开始要先使用__HAL_LOCK()锁定DMA,而函数__HAL_LOCK()会判断当前的DMA状态是否为锁定状态如果是
//锁定状态的话就直接返回HAL_BUSY这样会导致函数HAL_DMA_Statrt()和HAL_DMAEx_MultiBufferStart()后续的DMA配置
//程序直接被跳过DMA也就不能正常工作为了避免这种现象所以在启动DMA之前先调用__HAL_UNLOC()先解锁一次DMA。
__HAL_UNLOCK(&DMADMCI_Handler);
if(mem1addr==0) //开启DMA不使用双缓冲
{
HAL_DMA_Start(&DMADMCI_Handler,(u32)&DCMI->DR,mem0addr,memsize);
}
else //使用双缓冲
{
HAL_DMAEx_MultiBufferStart(&DMADMCI_Handler,(u32)&DCMI->DR,mem0addr,mem1addr,memsize);//开启双缓冲
__HAL_DMA_ENABLE_IT(&DMADMCI_Handler,DMA_IT_TC); //开启传输完成中断
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,2,3); //DMA中断优先级
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
}
//DCMI,启动传输
void DCMI_Start(void)
{
LCD_SetCursor(0,0);
LCD_WriteRAM_Prepare(); //开始写入GRAM
__HAL_DMA_ENABLE(&DMADMCI_Handler); //使能DMA
DCMI->CR|=DCMI_CR_CAPTURE; //DCMI捕获使能
}
//DCMI,关闭传输
void DCMI_Stop(void)
{
DCMI->CR&=~(DCMI_CR_CAPTURE); //关闭捕获
while(DCMI->CR&0X01); //等待传输完成
__HAL_DMA_DISABLE(&DMADMCI_Handler);//关闭DMA
}
//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
HAL_DCMI_IRQHandler(&DCMI_Handler);
}
//捕获到一帧图像处理函数
//hdcmi:DCMI句柄
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
jpeg_data_process();//jpeg数据处理
LED1_Toggle;
ov_frame++;
//重新使能帧中断,因为HAL_DCMI_IRQHandler()函数会关闭帧中断
__HAL_DCMI_ENABLE_IT(&DCMI_Handler,DCMI_IT_FRAME);
}
void (*dcmi_rx_callback)(void);//DCMI DMA接收回调函数
//DMA1数据流1中断服务函数
void DMA1_Stream1_IRQHandler(void)
{
if(__HAL_DMA_GET_FLAG(&DMADMCI_Handler,DMA_FLAG_TCIF1_5)!=RESET)//DMA传输完成
{
__HAL_DMA_CLEAR_FLAG(&DMADMCI_Handler,DMA_FLAG_TCIF1_5);//清除DMA传输完成中断标志位
dcmi_rx_callback(); //执行摄像头接收回调函数,读取数据等操作在这里面处理
SCB_CleanInvalidateDCache(); //清除无效的D-Cache
}
}
////////////////////////////////////////////////////////////////////////////////
//以下两个函数,供usmart调用,用于调试代码
//DCMI设置显示窗口
//sx,sy;LCD的起始坐标
//width,height:LCD显示范围.
void DCMI_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{
DCMI_Stop();
LCD_Clear(WHITE);
LCD_Set_Window(sx,sy,width,height);
OV5640_OutSize_Set(0,0,width,height);
LCD_SetCursor(0,0);
LCD_WriteRAM_Prepare(); //开始写入GRAM
__HAL_DMA_ENABLE(&DMADMCI_Handler); //开启DMA1,Stream1
DCMI->CR|=DCMI_CR_CAPTURE; //DCMI捕获使能
}
//通过usmart调试,辅助测试用.
//pclk/hsync/vsync:三个信号的有限电平设置
void DCMI_CR_Set(u8 pclk,u8 hsync,u8 vsync)
{
HAL_DCMI_DeInit(&DCMI_Handler);//清除原来的设置
DCMI_Handler.Instance=DCMI;
DCMI_Handler.Init.SynchroMode=DCMI_SYNCHRO_HARDWARE;//硬件同步HSYNC,VSYNC
DCMI_Handler.Init.PCKPolarity=pclk<<5; //PCLK 上升沿有效
DCMI_Handler.Init.VSPolarity=vsync<<7; //VSYNC 低电平有效
DCMI_Handler.Init.HSPolarity=hsync<<6; //HSYNC 低电平有效
DCMI_Handler.Init.CaptureRate=DCMI_CR_ALL_FRAME; //全帧捕获
DCMI_Handler.Init.ExtendedDataMode=DCMI_EXTEND_DATA_8B;//8位数据格式
HAL_DCMI_Init(&DCMI_Handler); //初始化DCMI
DCMI_Handler.Instance->CR|=DCMI_MODE_CONTINUOUS; //持续模式
}