cancel
Showing results for 
Search instead for 
Did you mean: 

DCMI or DMA problem. Detecting end of capture

Linas L
Senior II

Hello,

I am facing strange problem. I have a camera that transfers data, 90kPixels.

Since it is 10 bit camera, and data is packed into 32b word, I can tranfare image in singe DMA config ((300x300)/2 in DMA)

So I have Circular DMA buffer, continuous DCMI capture mode, and HSYNC, FRAME, DMA_TC IRQ's Enabled. I get perfect test paters and test data, so all is fine here with communication !

After image is captured, I start to do some image recognition.

Problem Is I get different behaviors (response in processed data on static image) if i use TC interrupt, frame interrupt, or VSYNC interrupt. All of them should be in time, where data has been transferred, but it's not. I can get IRQ's when DMA says data is not transferred yet, or i get corruption in half of frame, like overexposed frame. So my calculations would start to jump all over the place.

Any idea what could be wrong here? why is is a difference for calculated data, if DMA has highest priority and I am doing math from array start? even if it's not transferred, and few pixels left, in the time i process data all will be correct SRAM spot ( I am using internal SRAM)

Capture is done in this way. I have timer that triggers camera, and i have global variable that tracks status, if status is zero, I trigger camera, and DCMI/DMA starts it's job, no register edit needed. And when I get TC, VSYNC, FRAME interrupt, I change status to "capture_Done" value.

In main, i have while(1) cycle that tracks capture_Done value, and if value is triggered, it does the job, and at the end of job resets it to zero. So if my task is not doe after timer tries to trigger camera, i will skip the frame and get FPS/2 operation. No extra attention is needed.

At the moment i am running at 60-80% duty cycle.

2 REPLIES 2
Georgy Moshkin
Senior II

Few years ago I had DCMI project with circular buffer. There was several problems and I end up with initializing DCMI in circular mode following way, probably because generated code did not provide callback for half complete interrupt or something like that.

	hdcmi.Instance->CR &= ~(DCMI_CR_CM);
	hdcmi.Instance->CR |= (uint32_t) (DCMI_MODE_SNAPSHOT);
	hdcmi.DMA_Handle->XferHalfCpltCallback = &dcmiHalfCplt;
	hdcmi.DMA_Handle->XferCpltCallback = &dcmiCplt;
	hdcmi.DMA_Handle->XferErrorCallback = NULL;
	hdcmi.DMA_Handle->XferAbortCallback = NULL;
	HAL_DMA_Start_IT(hdcmi.DMA_Handle, (uint32_t) &hdcmi.Instance->DR,
			(uint32_t) jpegBuffer, JPEG_BUFFER_SIZE / 2);
	hdcmi.Instance->CR |= DCMI_CR_CAPTURE;

Array is called jpegBuffer, but I mainly tested it with uncompressed data. Frames was copied from jpegBuffer to a larger buffer using MEM2MEM inside dcmiHalfCplt and dcmiCplt functions. If you have constant data size using Cplt/halfCplt must provide deterministic behavior.

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!
Linas L
Senior II

Hi,

I do everything in LL, maybe I am missing something to.

What is strange, even optimization level has impact of data I get. I would understand if I use HSYNC to recalculate DMA address if i don't fit in 65535 DMA limit (when I had very big sensor I was using HSYNC DCMI IRQ to recalculate DMA since sensor was multiple times of DMA counter, in this case If i can't do this in time, I would get corruption. In that instance ping-pong DMA did the trick.)

But here I am using circular buffer with highest priority, I should not get any corruption in data with optimization level, or what I use to detect end of frame.

I am running 27MHz pclk, while the limit is HCLK/2 and it is 40.5MHz + It does use 32b packing, so my efective data transfer rate is 27/2 = 13,5MHz.

This is STM32L496RGT6 processor.

void Configure_DMA(void)
{  
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
  LL_DMA_DeInit(DMA2,LL_DMA_CHANNEL_6);
  LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_CHANNEL_6, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  LL_DMA_SetChannelPriorityLevel(DMA2, LL_DMA_CHANNEL_6, LL_DMA_PRIORITY_VERYHIGH);
  LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_6, LL_DMA_MODE_CIRCULAR);
  LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_CHANNEL_6, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_CHANNEL_6, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA2, LL_DMA_CHANNEL_6, LL_DMA_PDATAALIGN_WORD);
  LL_DMA_SetMemorySize(DMA2, LL_DMA_CHANNEL_6, LL_DMA_MDATAALIGN_WORD);
  
  LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_6, ((300)*(300))/2);
 
  LL_DMA_ConfigAddresses(DMA2, LL_DMA_CHANNEL_6, (uint32_t)&DCMI->DR, (uint32_t)&(PIXEL_DATA), LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  
  LL_DMA_SetPeriphRequest(DMA2, LL_DMA_CHANNEL_6, LL_DMA_REQUEST_0);
  
  LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_6);
  LL_DMA_EnableIT_TE(DMA2, LL_DMA_CHANNEL_6);
  
  NVIC_SetPriority(DMA2_Channel6_IRQn, 0);
  NVIC_EnableIRQ(DMA2_Channel6_IRQn);
}
 
and DCMI is just:
 
void DCMI_ENABLE_DMA(void)
{
  DCMI->CR = 0;
  NVIC_SetPriority(DCMI_IRQn, 1);
  NVIC_EnableIRQ(DCMI_IRQn);
  Configure_DMA();
  
  DCMI->IER =VSYNC_IE|FRAME_IE|LINE_IE;
  DCMI->CR  =DCMI_CR_ENABLE|EDM_10BIT;
  DCMI->CR |=DCMI_CR_CAPTURE;
  LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_6);
}