请教高手:F4的OV9655和DCMI通过DMA双缓存到内部SRAM的配置问题

2019-07-20 23:14发布

用F4、OV9655和DCMI通过DMA双缓存到内部SRAM,然后再把两个缓存的图像片段搬到外部SRAM组成一帧图像,最后在另一外部SRAM数组中转化成RGB565格式在通过LCD_WriteRAM()显示到LCD上的配置问题:      1.我想用以上方法获取YUV422格式的图片,是否OV9655要设定成YUV422输出,并且输出格式是YUYV顺序;然后DCMI也设定成YUV422输出,而且DMA时是输出32位的字?这里能否设成16位的半字?
      2.然后进内部SRAM数组buf[]时,用半字传送,是否也是buf[]={Y0U0Y1V1Y2U2.......}这个顺序?

      3.从外部SRAM把YUV422格式转化成RGB565格式图片时,RGB在半字中的顺序是什么?送LCD显示时是否可以用函数LCD__WriteRAM()按顺序p0p1p2p3......半字半字的送?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
10条回答
luyongyun
2019-07-21 03:08
我用F4照相机例程修改了,用OV9655,RGB565输出,图像最开始是直接DMA到LCD,显示正常,如果这时按按键KEY1,则DMA变双缓冲先分别存于内部SRAM3的BUF0和BUF1,然后再搬运到外部SRAM中组合,最后用LCD__WriteRAM()按各种顺序给LCD显示,但这时是花屏。然后按键KEY2转回直接DMA到LCD,这时屏幕被4等分,每份的图像是相同的。KEY1和可用来回切换都如上。请问有没有高手知道为什么会这样,以下为图像和程序。请指教.u8 ov_frame=0;                                                  //帧率
//uint32_t Dma_bufsize= PICTURE_dma_bufsize;
extern u16 PICTURE_buf0;
extern u16 PICTURE_buf1;
extern u16 *PICTURE_data_buf;
extern void PICTURE_data_process(void);        //PICTURE数据处理函数
extern NVIC_InitTypeDef NVIC_InitStructure;

void OV9655_Init(ImageFormat_TypeDef ImageFormat)
{
  DCMI_InitTypeDef DCMI_InitStructure;
       
  /*** Configures the DCMI to interface with the OV9655 camera module ***/
  /* Enable DCMI clock */
  RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);

  /* DCMI configuration */
  DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous;   //连续捕获:DCMI_CaptureMode_Continuous;单帧:DCMI_CaptureMode_SnapShot
  DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware;
  DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Falling;
  DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High;
  DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_High;
  DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame;   //All_Frame;DCMI_CaptureRate_1of4_Frame
  DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
  DCMI_Init(&DCMI_InitStructure);

//  DCMI_ITConfig(DCMI_IT_FRAME,ENABLE);//开启帧中断
  DCMI_Cmd(ENABLE);        //DCMI使能

  NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;                //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器、

}

//DCMI DMA配置
//memaddr:存储器地址    将要存储摄像头数据的内存地址(也可以是外设地址)
//DMA_BufferSize:存储器长度    0~65535
//DMA_MemoryDataSize:存储器位宽    @defgroup DMA_memory_data_size MA_MemoryDataSize_Byte/DMA_MemoryDataSize_HalfWord/DMA_MemoryDataSize_Word
//DMA_MemoryInc:存储器增长方式  @defgroup DMA_memory_incremented_mode  /** @defgroup DMA_memory_incremented_mode : DMA_MemoryInc_Enable/DMA_MemoryInc_Disable

void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u32 DMA_Memory1BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc)
{
        DMA_InitTypeDef  DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
        DMA_DeInit(DMA2_Stream1);//等待DMA2_Stream1
        while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待DMA2_Stream1可配置
       
  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = DMA_Channel_1;  //通道1 DCMI通道
  DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;//外设地址为CMI->DR
  DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;//DMA 存储器0地址
  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;//存储器增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize;//存储器数据长度
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; //FIFO模式        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//使用全FIFO
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输
  DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化DMA Stream
               
        if(DMA_Memory1BaseAddr)
  {
                DMA_DoubleBufferModeCmd(DMA2_Stream1,ENABLE);//双缓冲模式
            DMA_MemoryTargetConfig(DMA2_Stream1,DMA_Memory1BaseAddr,DMA_Memory_1);//配置目标地址1
                DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE);//开启传输完成中断
               
                NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn;
                NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
                NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;                //子优先级0
                NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
                NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器、
        }
               
       
}


//DCMI,启动传输
void DCMI_Start(void)
{  
    LCD_SetCursor(0,0);  
        LCD_WriteRAM_Prepare();                //开始写入GRAM
        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
}

//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
    uint16_t * p;
        uint32_t i;
        p= PICTURE_data_buf;
        if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到一帧图像
        {
                DCMI_Stop();
                PICTURE_data_process();         //jpeg数据处理       
                DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除帧中断
//                LED1=!LED1;
        p=(uint16_t)((uint32_t)0x68000000);
        for(i=0;i<320*240;i++)
                {
                        LCD_WriteRAM(*p++);
                }
                ov_frame++;  
                DCMI_Start();
        }
}


void (*dcmi_rx_callback)(void);//DCMI DMA接收回调函数
//DMA2_Stream1中断服务函数(仅双缓冲模式会用到)
void DMA2_Stream1_IRQHandler(void)
{        
        if(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1)==SET)//DMA2_Steam1,传输完成标志
        {  
                 DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF1);//清除传输完成中断
         dcmi_rx_callback();        //执行摄像头接收回调函数,读取数据等操作在这里面处理  
        }                                                                                             
}  


#define BUFFER_SIZE        0x400              /*定义读写BUFFER大小*/
#define WRITE_READ_ADDR    0x0000             /*定义SRAM读写的地址*/
#define Bank1_SRAM3_ADDR  ((uint32_t)0x68000000)
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

ErrorStatus HSEStartUpStatus;

u16 TxBuffer[BUFFER_SIZE];
u16 RxBuffer[BUFFER_SIZE];
u32 WriteReadStatus = 0, Index = 0;
u8 count=0;


extern Camera_TypeDef Camera;
extern ImageFormat_TypeDef ImageFormat;
extern __IO uint8_t ValueMax;
extern const uint8_t *ImageForematArray[];

#define PICTURE_dma_bufsize        (uint32_t)0xF00                //定义JPEG DMA接收时数据缓存PICTURE_buf0/1的大小(*4字节),320X24X2/4=3840,每帧10次DMA中断
volatile u32 PICTURE_data_len=0;                         //buf中的PICTURE有效数据长度(*4字节)
volatile u8 PICTURE_data_ok=0;                                //PICTURE数据采集完成标志
                                                                                //0,数据没有采集完;
                                                                                //1,数据采集完了,但是还没处理;
                                                                                //2,数据已经处理完成了,可以开始下一帧接收
#define SRAM3_BASE  ((uint32_t)0x20020000) /*!< SRAM3(64 KB) base address in the alias region                              */                                                                               
u16 *PICTURE_buf0= (u16 *)((uint32_t)SRAM3_BASE);                                                              //PICTURE数据缓存buf0,内部SRAM1
u16 *PICTURE_buf1= (u16 *)(SRAM3_BASE+PICTURE_dma_bufsize*4);                      //PICTURE数据缓存buf1,内部SRAM1
u16 *PICTURE_data_buf= (uint16_t *) Bank1_SRAM3_ADDR ;      //(SRAM1_BASE+PICTURE_dma_bufsize*4*2);          //PICTURE数据缓存buf,外部SRAM

/* Private function prototypes -----------------------------------------------*/
void ADC_Config(void);


//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
void PICTURE_data_process(void)
{
        u16 i;
        u16 rlen;//剩余数据长度
        u16 *pbuf;
                if(PICTURE_data_ok==0)        //jpeg数据还未采集完?
                {
                        DMA_Cmd(DMA2_Stream1,DISABLE);                //停止当前传输
                        while(DMA_GetCmdStatus(DMA2_Stream1) != DISABLE);        //等待DMA2_Stream1可配置
                        rlen=PICTURE_dma_bufsize-DMA_GetCurrDataCounter(DMA2_Stream1);//得到剩余数据长度       
                        pbuf=(uint16_t*)(PICTURE_data_buf+PICTURE_data_len*4);//偏移到有效数据末尾,继续添加
                        if(DMA2_Stream1->CR&(1<<19))for(i=0;i<rlen*2;i++)pbuf[i]=PICTURE_buf1[i];//读取buf1里面的剩余数据
                        else for(i=0;i<rlen*2;i++)pbuf[i]=PICTURE_buf0[i];//读取buf0里面的剩余数据
                        PICTURE_data_len+=rlen;                        //加上剩余长度
                        PICTURE_data_ok=2;                                 //标记JPEG数据采集完按成,等待其他函数处理
                }
                if(PICTURE_data_ok==2)        //上一次的jpeg数据已经被处理了
                { DMA_SetCurrDataCounter(DMA2_Stream1,PICTURE_dma_bufsize);//传输长度为jpeg_buf_size*4字节
                        DMA_Cmd(DMA2_Stream1,ENABLE); //重新传输
                        PICTURE_data_ok=0;                                //标记数据未采集
                        PICTURE_data_len=0;                                //数据重新开始
                }
}


//jpeg数据接收回调函数
void PICTURE_dcmi_rx_callback(void)
{
        u16 i;
        u16 *pbuf;
        pbuf=(uint16_t*)(PICTURE_data_buf+PICTURE_data_len*4);//偏移到有效数据末尾
        if(DMA2_Stream1->CR&(1<<19))//buf0已满,DMA正在处理buf1
        {
                for(i=0;i<ICTURE_dma_bufsize*2;i++)pbuf[i]=PICTURE_buf0[i];//读取buf0里面的数据
                PICTURE_data_len+=PICTURE_dma_bufsize;//偏移
        }else //buf1已满,DMA正在处理buf0
        {
                for(i=0;i<ICTURE_dma_bufsize*2;i++)pbuf[i]=PICTURE_buf1[i];//读取buf1里面的数据
                PICTURE_data_len+=PICTURE_dma_bufsize;//偏移
        }        
}


int main(void)
{
  u8 keynum;
  u32 i;
  u16 p=0;
  uint32_t WriteAddr=0;

  /* SysTick end of count event each 10ms */
  RCC_GetClocksFreq(&RCC_Clocks);
  SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);
  GPIO_KEY_Config();      //按键使用的GPIO初始化

/* Initialize the LCD */
  STM324xG_LCD_Init();
  LCD_Clear(Red);
  LCD_SetTextColor(White);
  LCD_LOG_SetHeader("STM32F407 Camera Demo");

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
  SRAM_Init();
  /* Initializes the DCMI interface (I2C and GPIO) used to configure the camera */
  OV9655_HW_Init();
  OV9655_ReadID(&OV9655_Camera_ID);
  if(OV9655_Camera_ID.PID  == 0x96)
  {
    Camera = OV9655_CAMERA;
    sprintf((char*)buffer, "OV9655 Camera ID 0x%x", OV9655_Camera_ID.PID);
  }
  LCD_SetTextColor(LCD_COLOR_YELLOW);
  LCD_DisplayStringLine(LINE(4), (uint8_t*)buffer);
  LCD_SetTextColor(LCD_COLOR_WHITE);
  Delay(200);

       
/* Configure the Camera module mounted on STM324xG-EVAL board */
  OV9655_QVGAConfig();
  OV9655_Init(BMP_QVGA);

//  /* Enable DMA2 stream 1 and DCMI interface then start image capture */
  DMA_Cmd(DMA2_Stream1, ENABLE);
  DCMI_Cmd(ENABLE);

//  /* Insert 100ms delay: wait 100ms */
  Delay(200);
  dcmi_rx_callback=PICTURE_dcmi_rx_callback;//回调函数
  DCMI_CaptureCmd(ENABLE);
  /* LCD Display window */
  LCD_SetDisplayWindow(239, 319, 240, 320);
  LCD_WriteReg(LCD_REG_3, 0x1038);
  LCD_WriteRAM_Prepare();
  ImageFormat = BMP_QVGA;
  DCMI_DMA_Init((u32)FSMC_LCD_ADDRESS,0,1,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Disable);//DCMI DMA配置   
  DCMI_Start();

  while(1)
  {
            /* 按键按下时为低电平,如果按键按下则改变指示灯状态 */
        keynum =ReadKeyDown();
        if(keynum != 0)
        {   
            switch(keynum)
            {                 
                case 1:   
                                          LCD_WriteReg(LCD_REG_3, 0x1030);
                                          DCMI_DMA_Init((u32)PICTURE_buf0,(u32)PICTURE_buf1,PICTURE_dma_bufsize,DMA_MemoryDataSize_Word,DMA_MemoryInc_Enable);//DCMI DMA配置(双缓冲模式)
                                          DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE);  //开启传输完成中断
                      DCMI_ITConfig(DCMI_IT_FRAME,ENABLE);  //开启帧中断
                                          DCMI_Start();                         //启动传输
                    break;                    
                case 2:   
                                      OV9655_Init(BMP_QVGA);
                                          LCD_WriteReg(LCD_REG_3, 0x1038);
                                          DCMI_ITConfig(DCMI_IT_FRAME,DISABLE);//开启帧中断
                                          DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,DISABLE);//开启传输完成中断
                                          DCMI_DMA_Init((u32)FSMC_LCD_ADDRESS,0,1,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Disable);//DCMI DMA配置   
                                          DCMI_Start();
                    break;                    
                case 3:   
//                    Led_Turn_on(2); /* 改变指示灯3状态 */

                    break;                    
                case 4:
//                    Led_Turn_on(3); /* 改变指示灯4状态 */
                    break;
                default:   
                    ;
            }           
            /* 等待按键释放 */
            while(keynum == ReadKeyDown());
            p=0x1234;
    /* Insert 100ms delay */
    Delay(10);
        ADCVal = 130;
    OV9655_BrightnessConfig(ADCVal);

        }
  }
}




一周热门 更多>