STM32F4DIS-CAM: DCIM to FLASH Memory using DMA Issue
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-01-08 9:36 AM
Posted on January 08, 2016 at 18:36
Hi there,
I'm trying to use the STM32F4 Discovery kit (STM32F4Discovery + BB + CAM [OV9655]; without LCD) to take a 16-bits QVGA (320x240) shot and simply store it in a byte array. Assuming that all DMA and DCMI structures are properly set (which I believe that are; more on that later), a 153600 (320*240*2[=16bits]) byte array is needed, which clearly exceeds the 128K RAM size. With this in mind, and in order to validate my assumptions, I've run a couple of tests using smaller buffer sizes and byte arrays and successfully got partial ''good'' pictures: 320x120 when using a 76800 array and 320x140 with a 89600. As such, what I am now trying (and failing) to do is to use the FLASH memory to allocate the desired 153600 bytes and store the image data into it - although I am now able to r/w from/to the whole array using simple initialization/attribution (e.g.: frame_buffer[0] = 0x10), I can't get the DMA to write to it. Please find the relevant code below.
#define DCMI_DR_ADDRESS 0x50050028
#define FRAME_BUFFER_SIZE 153600
__attribute__((__section__(
''.user_data''
))) uint8_t frame_buffer[FRAME_BUFFER_SIZE] = {0};
// uint8_t frame_buffer[FRAME_BUFFER_SIZE/2] = {0}; // WORKS AS EXPECTED, ALTHOUGH JUST 1/2 IMAGE STORED
uint8_t DCMI_OV9655Config(
void
)
{
I2C1_Config();
I2C_GenerateSTART(I2C1, ENABLE);
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_GenerateSTOP(I2C1, ENABLE);
if
(DCMI_SingleRandomWrite(OV9655_DEVICE_WRITE_ADDRESS,0x12, 0x80))
{
return
(0xFF);
}
DCMI_OV9655_QVGASizeSetup();
DCMI_SingleRandomWrite(OV9655_DEVICE_WRITE_ADDRESS, OV9655_COM7, 0x63);
DCMI_SingleRandomWrite(OV9655_DEVICE_WRITE_ADDRESS, OV9655_COM15, 0x10);
DCMI_SingleRandomWrite(OV9655_DEVICE_WRITE_ADDRESS, OV9655_COM10, 0x08);
DCMI_Config();
return
(0x00);
}
void
I2C1_Config(
void
)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);
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_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_Cmd(I2C1, ENABLE);
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;
I2C_Init(I2C1, &I2C_InitStruct);
}
void
DCMI_Config(
void
)
{
DCMI_InitTypeDef DCMI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE |
RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource4, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI);
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);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1
| GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
DCMI_InitStructure.DCMI_CaptureMode = 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_All_Frame;
DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_DeInit(DMA2_Stream1);
DMA_InitStructure.DMA_Channel = DMA_Channel_1;
DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&frame_buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = FRAME_BUFFER_SIZE/4;
// 320*240/WordSize
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_HalfWord;
DMA_InitStructure.DMA_Mode = 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;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
}
int
main()
{
DCMI_Control_IO_Init();
if
(DCMI_OV9655Config() == 0x0)
{
DMA_Cmd(DMA2_Stream1, ENABLE);
DCMI_Cmd(ENABLE);
DCMI_CaptureCmd(ENABLE);
DCMI_CaptureCmd(DISABLE);
for
(i = 0; i < FRAME_BUFFER_SIZE; i++)
{
// frame_buffer[i] = i; // WORKS EVEN WHEN USING FLASH MEMORY. ALL 153600 BYTES BECOME SET AND READABLE
printf
(
''0x%02x\r\n''
, frame_buffer[i]);
}
DCMI_CaptureCmd(ENABLE);
return
0;
}
LD script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 896K
DATA (rwx) : ORIGIN = 0x080E0000, LENGTH = 128K
// ADDED
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
CCM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
// ADDED SECTION
.user_data :
{
. = ALIGN(4);
*(.user_data)
. = ALIGN(4);
} >DATA
...
What am I missing here?
Thank you.
Best regards,
Joao Mauricio
#good-luck-with-that #flash #dma #stm32f4 #quem-não-sabe-é-como-quem-não-vê #tortoise-vs-hare #dcmi
Labels:
- Labels:
-
DCMI
-
DMA
-
Flash
-
STM32F4 Series
This discussion is locked. Please start a new topic to ask your question.
4 REPLIES 4
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-01-08 11:08 AM
Posted on January 08, 2016 at 20:08
I can't get the DMA to write to it.
Yeah, kind of think that's going to be a bit bandwidth limiting, and not going to work. Does the DMA fault, or do you get an overrun error?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Up vote any posts that you find helpful, it shows what's working..
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-01-08 12:36 PM
Posted on January 08, 2016 at 21:36Hi clive1,First, thanks for the quick reply.Yeah, kind of think that's going to be a bit bandwidth limiting, and not going to work. Would you please elaborate? If the same ''mechanism'' reportedly works when using the LCD module (with DMA writing to the LCD buffer), why can that be the problem? Note that this is an honest question, since I'm not an experienced embedded systems' software developer.Does the DMA fault, or do you get an overrun error?I'll get back to you as soon as I'm able to test it again. Finally, if I may, do you have any ideas or alternatives on how I can achieve my goal (acquire and manipulate the full image data)?Thank you.Best regards,Joao Mauricio
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-01-08 1:26 PM
Posted on January 08, 2016 at 22:26
You need something with enough RAM to hold the image, or the ability to write it somewhere else quicker than it's coming in. Or use a device with a FIFO on it.
The FLASH read is relatively slow, figure 5-6x slower than the internal SRAM. Writing, if the controller even permits this type of interaction, is about 2700x slower, and I doubt if your pixel clock is below 60 KHz.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Up vote any posts that you find helpful, it shows what's working..
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-01-11 10:02 AM
Posted on January 11, 2016 at 19:02
Hello clive1,
Thanks for the enlightenment.Best regards,Joao Mauricio