Using SD card to store DCMI image in stm32f4

Publisher:京玩儿Latest update time:2018-08-21 Source: eefocusKeywords:stm32f4 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Because the innovative experiments and Freescale cars I did in my undergraduate studies were all cameras, and my graduate studies were also focused on video processing. Later, I wanted to make a small video monitor, but it was too troublesome, so I didn't use TI's DM6446, so I used the stm32f4 development board I had. Since there was no LCD display, I could only save the DCMI image directly in the internal RAM, then save it to the SD, and then read the SD card on the host computer to convert it into a picture. I used VC+OPENCV.


Now let me talk about the process. The camera I bought is OV9665. It is directly connected to the DCMI interface. The SD card cannot be connected to SDIO because my development board is a 100-pin package, and the SDIO and DCMI multiplexing pins conflict. Later, the SD card used the SPI interface.


1. Regarding the SD card read and write operations of the SPI interface, I have written about it in previous blogs, and also attached a written FATFS file system program. You can refer to it, so I will not write more here.


2. The important thing is the DCMI camera interface, mainly the DCMI configuration and DMA configuration, which will be explained in detail below.


void OV9655_HW_Init(void) 

{

  GPIO_InitTypeDef GPIO_InitStructure;

  I2C_InitTypeDef  I2C_InitStruct;

 

  /*** Configures the DCMI GPIOs to interface with the OV9655 camera module ***/

  /* Enable DCMI GPIOs clocks */

  /* Enable DCMI GPIOs clocks */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC |

                         RCC_AHB1Periph_GPIOE, ENABLE); 

 

  /* Enable DCMI clock */

  RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);

 

  /* Connect DCMI pins to AF13 ************************************************/

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI); //HSYNC

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI); //PIXCLK

 

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D5

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI); //VSYNC

 

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D0

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI); //DCMI_D1

 

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_DCMI); //DCMI_D2

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_DCMI); //DCMI_D3

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource4, GPIO_AF_DCMI); //DCMI_D4

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_DCMI); //DCMI_D6

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D7

  

  /* DCMI GPIO configuration **************************************************/

  /* HSYNC(PA4), PIXCLK(PA6) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOA, &GPIO_InitStructure);

 

  /* DCMI_D5(PB6), VSYNC(PB7) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOB, &GPIO_InitStructure);

 

  /* DCMI_D0(PC6), DCMI_D1(PC7) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOC, &GPIO_InitStructure);

 

  /* DCMI_D2(PE0), DCMI_D3(PE1), DCMI_D4(PE4), DCMI_D6(PE5), DCMI_D7(PE6),*/

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOE, &GPIO_InitStructure);

  

  /****** Configures the I2C1 used for OV9655 camera module configuration *****/

 /* I2C1 clock enable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

 

  /* GPIOB clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 

 

  /* Connect I2C1 pins to AF4 */

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

  

  /* Configure I2C1 GPIOs */  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

 

  /* Configure I2C1 */

  /* I2C DeInit */

  I2C_DeInit(I2C1);

    

  /* Enable the I2C peripheral */

  I2C_Cmd(I2C1, ENABLE);

 

  /* Set the I2C structure parameters */

  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;

  I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;

  I2C_InitStruct.I2C_OwnAddress1 = 0xFE;

  I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStruct.I2C_ClockSpeed = 30000;

  

  /* Initialize the I2C peripheral w/ selected parameters */

  I2C_Init(I2C1, &I2C_InitStruct);

}

The initialization procedures for DCMI and DMA are as follows

void OV9655_Init(ImageFormat_TypeDef ImageFormat)

{

  DCMI_InitTypeDef DCMI_InitStructure;

  DMA_InitTypeDef  DMA_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_SnapShot;//DCMI_CaptureMode_Continuous;

  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_1of4_Frame;//DCMI_CaptureRate_All_Frame;

  DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;

 

  //----- mask interrupt for DCMI -----

      DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE);

      DCMI_ITConfig(DCMI_IT_LINE, ENABLE);

      DCMI_ITConfig(DCMI_IT_FRAME, ENABLE);

      DCMI_ITConfig(DCMI_IT_OVF, ENABLE);

      DCMI_ITConfig(DCMI_IT_ERR, ENABLE);

  

  /* Configures the DMA2 to transfer Data from DCMI */

  /* Enable DMA2 clock */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

  

  /* DMA2 Stream1 Configuration */

  DMA_DeInit(DMA2_Stream1);

 

  DMA_InitStructure.DMA_Channel = DMA_Channel_1;  

  DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;

  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)theMap;//FSMC_LCD_ADDRESS;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  DMA_InitStructure.DMA_BufferSize = 9600;

  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_Byte;//DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//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_Single;

  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    //------------------------Interrupt

        DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);  

        DMA_ITConfig(DMA2_Stream1, DMA_IT_HT, ENABLE);   

        DMA_ITConfig(DMA2_Stream1, DMA_IT_TE, ENABLE);  

        DMA_ITConfig(DMA2_Stream1, DMA_IT_FE, ENABLE);   

 

                

  switch(ImageFormat)

  {

    case BMP_QQVGA:

    {

      /* DCMI configuration */

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure);

      break;

    }

    case BMP_QVGA:

    {

      /* DCMI configuration */ 

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure); 

      break;

    }

    default:

    {

      /* DCMI configuration */ 

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure);

      break;

    }

  }    

}

Among them, DCMI_InitStructure.DCMI_CaptureMode uses DCMI_CaptureMode_SnapShot instead of DCMI_CaptureMode_Continuous, because the program stores the image in SD, the speed is limited, and only one image can be captured and stored.

Therefore, as long as DCMI_CaptureCmd(ENABLE); is pressed, DCMI will start taking a photo, and after taking a photo, the enable will be automatically turned off. Next time you want to take a photo, just press DCMI_CaptureCmd(ENABLE); again.

Then regarding DMA, this configuration gave me a headache for some time, mainly because I was not familiar with DMA.


DMA_InitStructure.DMA_Mode uses the DMA_Mode_Circular mode. Since DCMI uses single-frame photography, there is no problem using the DMA_Mode_Circular mode here.


DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //The data word length of the peripheral. The DCMI register is 32 bits, so the word selected here is

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //The data word length of the memory. The array I use to store the image is of unsigned char type, so BYTE is used here.


DMA_InitStructure.DMA_BufferSize = 9600; //The key is this, because the image size set by the camera is 120*160, which is RGB565 format, and one pixel occupies two bytes, so it takes 38400 bytes to store an image. And this buffersize is relative to the word length of the DMA data source, here is the word type of the DCMI data register, 38400/4=9600;


There is also a method for the host computer software to read this file. I use VC+OPENCV. In 38400 bytes, every two bytes represent the RGB color of a pixel. The two bytes are low byte first and high byte second. The schematic method is as follows


for(int i=0; i

    {

        rgb565 = p[2*i+0] + 256*p[2*i+1];

        

        b = (rgb565>>0)  & 0x001f;

        g = (rgb565>>5)  & 0x003f;

        r = (rgb565>>11) & 0x001f;

        b = b<<3;

        g = g<<2;

        r = r<<3;

        vec.push_back(b);

        vec.push_back(g);

        vec.push_back(r);

    }    

The procedure for storing images in OPENCV is as follows:


void vecToImage(vector & vec, IplImage* pImg8u3)

{

    int cnt=0;


    for(int y=0; yheight; y++)

    {

        unsigned char* ptr = (unsigned char*)(pImg8u3->imageData + y * pImg8u3->widthStep);

        for(int x=0; xwidth; x++)

        {

            *(ptr + 3*x+0) =  vec.at(cnt++);

            *(ptr + 3*x+1) =  vec.at(cnt++);

            *(ptr + 3*x+2) =  vec.at(cnt++);

        }

    }

}


Keywords:stm32f4 Reference address:Using SD card to store DCMI image in stm32f4

Previous article:STM32CubeMX local upgrade firmware library method
Next article:STM32F103 test SD card serial port write test

Recommended ReadingLatest update time:2024-11-16 14:59

Playing Control with STM32F407 - Smith Predictive Compensation Control
The principle of Smith predictive compensation control is shown in Figure 1. The transfer function Ksgs(s) in Figure 1 is called a predictive compensator (this figure comes from the Internet, and the literature can be found in Jin Yihui's "Process Control"). In principle, Ksgs(s)=Kpgp(s)(1-exp(-τd*s)), so that the clo
[Microcontroller]
Playing Control with STM32F407 - Smith Predictive Compensation Control
STM32F429 timer
F429 has 14 timers in total 2 advanced TIM1, TIM8 10 general purpose TIM2~TIM5 TIM9~TIM14 2 basic TM6, TIM7 only TIM_Prescaler and TIM_Period 1. Configuration priority     NVIC_InitTypeDef NVIC_InitStructure;      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); The interrupt group is 0     NVIC_InitStructure
[Microcontroller]
CubeMX clock settings STM32F407VET
A tutorial on how to use CubeMX is available at:  http://blog.csdn.net/u013429988/article/details/54566969 The first time I used the F4 series chip, I planned to use an 8M passive crystal as an external crystal. Connect it between RCC_OSC_IN and RCC_OSC_OUT as shown in the figure below. Configure the pins. The two g
[Microcontroller]
CubeMX clock settings STM32F407VET
STM32F4 ADC internal temperature sensor
Used to measure the ambient temperature around the chip. The voltage output by this temperature sensor is proportional to the temperature. To obtain the temperature, the ADC is used to measure this voltage. Inside the chip, the temperature sensor is connected to CH16 of ADC1. When the sensor is not in use, it can be s
[Microcontroller]
STM32F4 Development Notes 10: USB FS enumeration method
    FS stands for Full Speed, which refers to a full-speed USB device. During circuit design, a 1.5K pull-up resistor is connected to the power supply at DP to inform the host that it is a full-speed USB device. However, there is still a problem in actual use. After the microcontroller is reset, the host can still rec
[Microcontroller]
STM32F407 ADC DMA multi-channel + temperature
Here is the temperature added in the previous chapter The above figure is the temperature calculation formula: where Vsense is the ADC value collected from the temperature channel. The stm32f407 temperature channel is channel 16 of ADC1. Avg_Slope is usually set to 0.0025 Compared with the previous one, the foll
[Microcontroller]
STM32F407 ADC DMA multi-channel + temperature
Personal summary of driving LCD screen with stm32f4 development board
After studying the F4 FSMC method to drive the touch screen for a few days, I have gained some understanding, which are listed below. The unorganized record is only for my own reference in the future. The development board used was a F407 from Weixue Electronics, but their customer service was reluctant to answer qu
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号