cancel
Showing results for 
Search instead for 
Did you mean: 

DMA Double Buffer IRQ

markgilson9
Associate II
Posted on December 14, 2011 at 20:35

I currently have code which runs on the STM32F4-Discovery board and DMA's data from the ADC to a buffer.  I am using double buffering, so I can operate on one buffer while the other is being filled.  In short, my code works; both buffers are correctly filled with data.  The problem I'm having is that I'm interrupted at the end of filling both, when I really want to be interrupted when the first has been filled and the other one just starts getting filled by the DMA.  Some of my code is below:

DMA_InitStructure.DMA_Channel = DMA_Channel_2;  

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;

  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCBuf[0];

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  DMA_InitStructure.DMA_BufferSize = 800;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  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_Disable;         

  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

  DMA_Init(DMA2_Stream0, &DMA_InitStructure);

  DMA_DoubleBufferModeConfig(DMA2_Stream0, (uint32_t)&ADCBuf[1], DMA_Memory_0);

  DMA_DoubleBufferModeCmd(DMA2_Stream0, ENABLE);

  

  DMA_ITConfig(DMA2_Stream0, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, ENABLE);

  DMA_Cmd(DMA2_Stream0, ENABLE);

I then enable the interrupt:

void NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure and enable DMA interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

And then finally I have the IRQHandler reset the interrupt flags:

void DMA2_Stream0_IRQHandler()

{

DMA_ClearFlag(DMA2_Stream0, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE);

}

Any ideas as to how to be able to interrupt immediately following the filling of the first buffer?  I'm wondering if I have to use 2 separate streams?  Thanks in advance.
15 REPLIES 15
Posted on January 24, 2012 at 18:45

If you have an interrupt storm, it is likely that something remains pending. It is also critical to do something in interrupt routine so that it doesn't double entry (pipelining/writebuffer race condition against NVIC)

Output the value (DMA2->LISR  &  DMA_Stream0_IT_MASK) in your debug/telemetry output. Is it flagging anything, like a fault or half-transfer?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
markgilson9
Associate II
Posted on January 24, 2012 at 22:16

It looks like within the IRQ_Handler I see the LISR register value as either 0x00000030, or 0x00000020, which tells me that I'm interrupting due to Half-Transfer and Transfer Complete (correct?).  

What's wierd is that I'm only enabling TC and TE:

DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE, ENABLE);

Why would Half-Transfer trigger interrupts?  I also notice that even though I clear the interrupts twice within the IRQHandler, only the half transfer bit clears:

DMA_ClearFlag(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE);

DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE);

I must be missing something.

Posted on January 24, 2012 at 23:10

I must be missing something.

Yes, that

DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE);

should be

DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0 | DMA_IT_TEIF0);

and you don't need the ClearFlag code

#define DMA_IT_TC                         ((uint32_t)0x00000010)

#define DMA_IT_TE                         ((uint32_t)0x00000004)

#define DMA_IT_TEIF0                      ((uint32_t)0x10002008)

#define DMA_IT_HTIF0                      ((uint32_t)0x10004010)

#define DMA_IT_TCIF0                      ((uint32_t)0x10008020)

/**

  * @brief  Clears the DMAy Streamx's interrupt pending bits.

  * @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x can be 0

  *          to 7 to select the DMA Stream.

  * @param  DMA_IT: specifies the DMA interrupt pending bit to clear.

  *          This parameter can be any combination of the following values:

  *            @arg DMA_IT_TCIFx:  Streamx transfer complete interrupt

  *            @arg DMA_IT_HTIFx:  Streamx half transfer complete interrupt

  *            @arg DMA_IT_TEIFx:  Streamx transfer error interrupt

  *            @arg DMA_IT_DMEIFx: Streamx direct mode error interrupt

  *            @arg DMA_IT_FEIFx:  Streamx FIFO error interrupt

  *         Where x can be 0 to 7 to select the DMA Stream.

  * @retval None

  */

void DMA_ClearITPendingBit(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_IT)

/**

  * @brief  Enables or disables the specified DMAy Streamx interrupts.

  * @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x can be 0

  *          to 7 to select the DMA Stream.

  * @param DMA_IT: specifies the DMA interrupt sources to be enabled or disabled.

  *          This parameter can be any combination of the following values:

  *            @arg DMA_IT_TC:  Transfer complete interrupt mask

  *            @arg DMA_IT_HT:  Half transfer complete interrupt mask

  *            @arg DMA_IT_TE:  Transfer error interrupt mask

  *            @arg DMA_IT_FE:  FIFO error interrupt mask

  * @param  NewState: new state of the specified DMA interrupts.

  *          This parameter can be: ENABLE or DISABLE.

  * @retval None

  */

void DMA_ITConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_IT, FunctionalState NewState)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
markgilson9
Associate II
Posted on January 25, 2012 at 17:08

Excellent catch, thanks clive1!

Posted on January 25, 2012 at 17:27

Excellent catch, thanks clive1!

Bit of bastard isn't it? Who thought that was a good idea?

There aren't that many examples to be found either, I just thought to look because you said it wasn't clearing, and the bit values didn't jive.

I think you'll find HT signals, but isn't gated to the NVIC based on you not enabling it.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
raffael
Associate II
Posted on January 26, 2012 at 09:36

Thanks for your posts.

As you mentioned there aren't many examples...

Thanks to this posts I could implement dual simultaneous ADC to double buffer very fast.