2013-10-01 12:58 AM
Hello, I am trying to read data from USART using DMA. Receive buffer (DMA_BufferSize) in my code is 4 bytes, but even when 1 byte of data received, MCU is interrupted with Transfer Complete flag (DMA_IT_TCIF1). Giving the code below, can you please check what is wrong with configuration?
STM32F4 Discovery (STM32F407VG)
/* Includes ------------------------------------------------------------------*/ #include ''main.h'' #include ''string.h'' #include <stdlib.h> #include ''stdio.h'' #include ''float.h'' /*User variables -------------------------------------------------------------*/ #define RXBUFFERSIZE 4 uint8_t RxBuffer[RXBUFFERSIZE]; /* Private functions ---------------------------------------------------------*/ //initialization of USART3 used with DMA void init_usart3_dma(void) { GPIO_InitTypeDef GPIO_InitStruct; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART_InitStruct; DMA_InitTypeDef DMA_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //USART3 Clock Enable RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //GPIOB Clock Enable RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1 Clock Enable GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3); //USART3 Tx Pin GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3); //USART3 Rx Pin NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // Enable the USART3 RX DMA Interrupt NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_InitStruct.USART_BaudRate = 19200; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART3, &USART_InitStruct); USART_Cmd(USART3, ENABLE); // Enable USART3 // ----- USART3 DMA Rx Stream Init ----- DMA_DeInit(DMA1_Stream1); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_BASE; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RxBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive From Per to Mem DMA_InitStructure.DMA_BufferSize = RXBUFFERSIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; 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(DMA1_Stream1, &DMA_InitStructure); USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); // Enable USART Rx DMA Request DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE); // Enable Transfer Complete Interrupt DMA_Cmd(DMA1_Stream1, ENABLE); // Enable DMA Rx Stream } int main(void) { init_usart3_dma(); while(1) { } } void DMA1_Stream1_IRQHandler(void) // USART3 RX DMA Transfer Complete Interrupt { if (DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1)) { // ---------- DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1); } }2013-10-01 01:12 AM
Generally doesn't look bad
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; // Might be more appropriate and correct address I might also add some work after clearing the TC flags so as to avoid the hazard with the pipeline, NVIC, and tail-chaining.2013-10-01 01:39 AM
thanks, this seems to solve the problem!
what do you mean by saying 'hazard with the pipeline, NVIC, and tail-chaining' ? can you explain a bit?2013-10-01 02:16 AM
I've done so before, you might want to Google it.
Basically the pipeline in the processor decides what interrupt to service next before the clearing of the interrupt propagates back from external peripherals on the APB/AHB buses, and back into the NVIC. The latency will depend on the speed disparity of those buses, futher impacted by the write buffer on the processor. The effect will be that the processor will re-enter an interrupt service routine almost immediately with what looks like a spurious interrupt which will not be signalled in the status register as that read will have fenced the pending write, which may also have already completed. It's a classic race condition, the pipeline gives the appearance of single cycle execution (throughput), but the latency is much higher. So you either need to dwell for a couple of cycles to accommodated the pipeline/write buffer, or fence the write with some other reads/writes to enforce in-order completion. If you do anything remotely useful in the Handler you won't see this.void DMA1_Stream1_IRQHandler(void) // USART3 RX DMA Transfer Complete Interrupt
{
if (DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1)) // Guarded against spurious re-entry
{
DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1); // Clear Early
// ----------
// Do something useful here, toggle a GPIO, anything
}
}
2013-10-02 04:55 AM
okay, that sounds useful.
so, when using DMA in Normal Mode, what should be done in interrupt to reset Buffer and DMA to get ready for next data packet? is Disable/Enable logical?2013-10-25 08:27 AM
I have another question related to DMA Rx and decide not to create a new thread :)
What is wrong with behaviour of Half Transfer interrupt? I created a Normal Buffer of 10 bytes for DMA and HT interrupt is reached at 10 bytes, not 5. What could be the problem?