采用STM32H7的dcmi接口,像素时钟50MHZ,用DMA2 sream1搬运数据,相机模组采用8位,像素分辨率480x480问题:
采用单帧捕获,内存数组大小【480*480】,dma传输完成中断能够正常进入,但是数组里面没有数据,貌似DMA没搬运成功,
上源码:
DCMI和DMA配置
#include "sys.h"
#include "dcmi.h"
DCMI_HandleTypeDef DCMI_Handler; //DCMI句柄
DMA_HandleTypeDef DMA_DCMI_Handler; //DMA句柄
/***********************************************************************************************
***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;//DCMI_PCKPOLARITY_RISING;//DCMI_PCKPOLARITY_FALLING; //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_CR_ALL_FRAME; //全帧捕获 DCMI_CR_ALTERNATE_4_FRAME
DCMI_Handler.Init.ExtendedDataMode=DCMI_EXTEND_DATA_8B; //8位数据格式
HAL_DCMI_Init(&DCMI_Handler); //初始化DCMI,此函数会开启帧中断
}
/***********************************************************************************************
//DCMI底层驱动,引脚配置,时钟使能,中断配置
//此函数会被HAL_DCMI_Init()调用
//@hdcmiCMI句柄
************************************************************************************************/
/**DCMI GPIO Configuration
PA4 ------> DCMI_HSYNC
PA6 ------> DCMI_PIXCLK
PC6 ------> DCMI_D0
PC7 ------> DCMI_D1
PC8 ------> DCMI_D2
PC9 ------> DCMI_D3
PC11 ------> DCMI_D4
PD3 ------> DCMI_D5
PG9 ------> DCMI_VSYNC
PB8 ------> DCMI_D6
PB9 ------> DCMI_D7
*/
void HAL_DCMI_MspInit(DCMI_HandleTypeDef* hdcmi)
{
GPIO_InitTypeDef GPIO_InitStruct;
//使能DCMI时钟,挂载在AHB2 总线上
__HAL_RCC_DCMI_CLK_ENABLE();
//初始化DCMI引脚
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_11;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
//DCMI_VSYNC
GPIO_InitStruct.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
//
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//设置中断
HAL_NVIC_SetPriority(DCMI_IRQn,1,1); //抢占优先级1,子优先级1
HAL_NVIC_EnableIRQ(DCMI_IRQn); //使能DCMI中断
//开始传输
//调用DMA_Config 函数开始DMA 数据传输,每传输完一帧数据需要调用一次,它包含本次传输的目的首地址及传输的数据量;
}
/* 配置DMA 从DCMI 中获取数据*/
//@DMA_Memory0BaseAddr:本次DMA 传输的目的首地址
//@DMA_BufferSize:指示本次DMA传输的数据量,单位是一个字,即4 字节
void DCMI_DMA_Init(uint32_t DMA_Memory0BaseAddr,uint32_t DMA_BufferSize)
{
__HAL_RCC_DMA2_CLK_ENABLE(); //使能DMA2时钟
DMA_DCMI_Handler.Instance=DMA2_Stream1; //DMA2数据流1
DMA_DCMI_Handler.Init.Request=DMA_REQUEST_DCMI; //DCMI的DMA请求
DMA_DCMI_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //外设到存储器
DMA_DCMI_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
DMA_DCMI_Handler.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
DMA_DCMI_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD; //外设数据长度:32位
DMA_DCMI_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;//DMA_MDATAALIGN_BYTE; //存储器数据长度:8/16/32位
DMA_DCMI_Handler.Init.Mode=DMA_CIRCULAR;//DMA_CIRCULAR;//DMA_NORMAL; //非循环模式
DMA_DCMI_Handler.Init.Priority=MDMA_PRIORITY_HIGH;//MDMA_PRIORITY_HIGH;//MDMA_PRIORITY_VERY_HIGH; //高优先级
DMA_DCMI_Handler.Init.FIFOMode=DMA_FIFOMODE_ENABLE; //使能FIFO
DMA_DCMI_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_HALFFULL; //使用1/2的FIFO
DMA_DCMI_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器突发传输
DMA_DCMI_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
__HAL_LINKDMA(&DCMI_Handler, DMA_Handle, DMA_DCMI_Handler);
//DMA 中断配置
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
HAL_DMA_DeInit(&DMA_DCMI_Handler); //先清除以前的设置
HAL_DMA_Init(&DMA_DCMI_Handler);
//使能DCMI 采集数据
//DCMI_MODE_CONTINUOUS
//DCMI_MODE_SNAPSHOT
HAL_DCMI_Start_DMA(&DCMI_Handler, DCMI_MODE_SNAPSHOT,(uint32_t)DMA_Memory0BaseAddr,DMA_BufferSize);
}
主程序
#define img_width 480 //图像的宽度,单位字节
#define img_height 480 //图像的高度,单位字节
#define img_size (img_width*img_height)//图像的大小,单位字节
u8 Img_Frame_Buffer[img_size];//对应img_width*img_height个像素灰度值
u16 CMOS_Frame_TakeOver=0;
//DMA2 中断服务函数
void DMA2_Stream1_IRQHandler(void)
{
// if ((__HAL_DMA_GET_FLAG(DMA2_Stream0, DMA_IT_TCIF0) != RESET))
if(__HAL_DMA_GET_FLAG(&DMA_DCMI_Handler,DMA_FLAG_TCIF1_5)!=RESET)//DMA传输完成
{
__HAL_DMA_CLEAR_FLAG(&DMA_DCMI_Handler,DMA_FLAG_TCIF1_5);//清除DMA传输完成中断标志位
if(HAL_DMA_GetState(&DMA_DCMI_Handler)!=HAL_DMA_STATE_BUSY)//
{
CMOS_Frame_TakeOver=1;
}
}
//HAL_DMA_IRQHandler(&DMA_DCMI_Handler);
}
//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
HAL_DCMI_IRQHandler(&DCMI_Handler);//此函数会调用HAL_DCMI_FrameEventCallback回调函数
}
void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi)
{
//每次帧同步来临是重新设置一次DMA 传输数据
//DCMI_DMA_Init((u32)Img_Frame_Buffer,img_size/4);
// CMOS_Frame_TakeOver=1;
}
int main(void)
{
Usart4RevState=0;
CMOS_Frame_TakeOver=0;
Cache_Enable();//打开 L1-Cache
HAL_Init();//初始化 HAL 库,可修改中断优先级分组
SystemClock_Config();
delay_init(400);//延时
GPIO_Init();
uart4_init(115200);
SimSPI_Init();
NOIL300A_Init();
DCMI_Init();
DCMI_DMA_Init((u32)Img_Frame_Buffer,img_size/4);
while(1)
{
CMOS_Test();//用串口传出测试
}
}
void CMOS_Test()
{
u32 uPixNum=0;
if(CMOS_Frame_TakeOver==1)//接收完一帧图像
{
for(uPixNum=0;uPixNum<img_size;uPixNum++)
{
UART4_SendChar(Img_Frame_Buffer[uPixNum]);//传出测试查看数据
}
CMOS_Frame_TakeOver=0;
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Supply configuration update enable
*/
MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY)
{
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 2;
RCC_OscInitStruct.PLL.PLLN = 64;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
//Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
//Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART4|RCC_PERIPHCLK_UART5
|RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_QSPI
|RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_D1HCLK;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&amperiphClkInitStruct) != HAL_OK)
{
//Error_Handler();
}
} |