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 { int cnt=0; for(int y=0; y { unsigned char* ptr = (unsigned char*)(pImg8u3->imageData + y * pImg8u3->widthStep); for(int x=0; x { *(ptr + 3*x+0) = vec.at(cnt++); *(ptr + 3*x+1) = vec.at(cnt++); *(ptr + 3*x+2) = vec.at(cnt++); } } }
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
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- 4.3-inch screen design
- How does AD19 transfer a BMP format logo image to PCB?
- EEWORLD University Hall----Live playback: Gigabit digital isolators for video, converters, and communications
- EEWORLD University Hall - Animated demonstration of common circuits and components
- ZigBee serial communication experimental code
- The serial port is always garbled when burning
- What do the MSP430 MCU POR and PUC mean?
- 【Development Kit for nRF52840】+ Review 2: Pathfinder
- ZIGBEE power management POWER_SAVING related functions
- TE's latest trend report | "How does temperature monitoring affect the generator market"