CubeMX生成代码无法使用DCMI DMA

2019-07-20 05:07发布

      目前有个DEMO需要从FPGA高速接入数据,我选用DCMI+DMA双缓冲的方式来接收数据。参考的正点原子的Camera实验。做了一个简单的demo,是拿正点原子的跑马灯程序作为基础工程文件,然后添加DCMI的代码。
[mw_shl_code=c,true]#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
/************************************************
ALIENTEK 阿波罗STM32H7开发板 实验1
跑马灯实验-HAL库版本
技术支持:www.openedv.com
淘宝店铺:http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司  
作者:正点原子 @ALIENTEK
************************************************/

DCMI_HandleTypeDef  DCMI_Handler;           //DCMI句柄
DMA_HandleTypeDef   DMADMCI_Handler;        //DMA句柄

#define jpeg_buf_size   30*1024*1024        //定义JPEG数据缓存jpeg_buf的大小(1*4M字节)
#define jpeg_line_size        180                        //定义DMA接收数据时,一行数据的最大值

u32 dcmi_line_buf[2][jpeg_line_size];        //RGB屏时,摄像头采用一行一行读取,定义行缓存  
u32 jpeg_data_buf[jpeg_buf_size] __attribute__((at(0XC0000000+1280*800*2)));//JPEG数据缓存buf,定义在LCD帧缓存之后

static u32 line_buf_num = 0;
static u32 frame_num = 0;

void (*dcmi_rx_callback)(void);

void DCMI_Init(void)
{
        DCMI_Handler.Instance = DCMI;
        DCMI_Handler.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
        DCMI_Handler.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
        DCMI_Handler.Init.VSPolarity = DCMI_VSPOLARITY_LOW;
        DCMI_Handler.Init.HSPolarity = DCMI_HSPOLARITY_LOW;
        DCMI_Handler.Init.CaptureRate = DCMI_CR_ALL_FRAME;
        DCMI_Handler.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
       
        HAL_DCMI_Init(&DCMI_Handler);
       
        DCMI->IER=0x0;
        __HAL_DCMI_ENABLE_IT(&DCMI_Handler, DCMI_IT_FRAME);
        __HAL_DCMI_ENABLE(&DCMI_Handler);
}

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时钟
    __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
   
    //初始化PA6
    GPIO_Initure.Pin=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);         //初始化
   
    //PH8
    GPIO_Initure.Pin=GPIO_PIN_8;
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);         //初始化   
   
    HAL_NVIC_SetPriority(DCMI_IRQn,2,2);        //抢占优先级1,子优先级2
    HAL_NVIC_EnableIRQ(DCMI_IRQn);              //使能DCMI中断
}

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);
                        __HAL_DMA_ENABLE_IT(&DMADMCI_Handler,DMA_IT_TC);    //开启传输完成中断
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,2,3);        //DMA中断优先级
        HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
    }
    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);
    }   
}

void rgblcd_dcmi_rx_callback(void)
{  
        u32 wData, powData;
        u8 newData, oldData = 0;
        uint32_t i,j = 0;
        if(DMA2_Stream1->CR&(1<<19))//DMA使用buf1,读取buf0
        {
                //pbuf=dcmi_line_buf[0];
        }else                                                 //DMA使用buf0,读取buf1
        {
                //pbuf=dcmi_line_buf[1];
        }

        for (i=0; i<180; i++) {
                wData = dcmi_line_buf[0];
                for (j=0; j<4; j++) {
                        powData = 8*j;
                        newData = (wData >> powData) & 0xff;
                        if (newData != 0 && ((newData - oldData) != 1)) {
                                break;
                        }
                        oldData=newData;
                }
        }
       
        line_buf_num++;
}

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();
    }
}

int main(void)
{
        Cache_Enable();                 //打开L1-Cache
        HAL_Init();                                        //初始化HAL库
        Stm32_Clock_Init(160,5,2,4);    //设置时钟,400Mhz
        delay_init(400);                                //延时初始化
        uart_init(115200);                                //串口初始化
        LED_Init();                                                //初始化LED
       
        DCMI_Init();                        //DCMI配置
        dcmi_rx_callback=rgblcd_dcmi_rx_callback;//RGB屏接收数据回调函数
  //DCMI_DMA_Init((u32)dcmi_line_buf[0],(u32)dcmi_line_buf[1],180,DMA_MDATAALIGN_WORD,DMA_MINC_ENABLE);   
        DCMI_DMA_Init((u32)dcmi_line_buf[0],0,180,DMA_MDATAALIGN_WORD,DMA_MINC_ENABLE);  
        __HAL_DMA_ENABLE(&DMADMCI_Handler); //使能DMA
  DCMI->CR|=DCMI_CR_CAPTURE;          //DCMI捕获使能
       
        while(1)
        {

        }
}

[/mw_shl_code]

是可以接收到数据的,然后尝试使用CubeMX生成工程,只在CubeMX中设置了RCC时钟,其余全部默认。
生成之后也在main.c中添加和上面同样的代码,并且在stm32h7xx_hal_conf.h中放开了DCMI,DMA相关的宏。但是连DMA1_Stream1_IRQHandler()都进不去。

尝试直接使用CubeMX添加上DCMI DMA相关配置:



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。