cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4DIS-CAM: DCIM to FLASH Memory using DMA Issue

joao2
Associate II
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
4 REPLIES 4
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..
joao2
Associate II
Posted on January 08, 2016 at 21:36

Hi 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

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..
joao2
Associate II
Posted on January 11, 2016 at 19:02

Hello clive1,

Thanks for the enlightenment.

Best regards,

Joao Mauricio