2011-12-14 11:35 AM
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.2012-01-24 09:45 AM
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?2012-01-24 01:16 PM
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.2012-01-24 02:10 PM
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)2012-01-25 08:08 AM
Excellent catch, thanks clive1!
2012-01-25 08:27 AM
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.2012-01-26 12:36 AM
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.