cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 USART1 RX DMA

connect
Associate II
Posted on April 24, 2014 at 15:59

Hi all,

Hoping to get a second pair of eyes on this code. I'm trying to capture large amounts of data from USART1 using DMA on an F30x series MCU. So far no luck - feels like I'm looking past an obvious error here 'cause this shouldn't be as complicated as it seems. Any feedback appreciated.

#include ''stm32f30x.h''
// ----------------------------------------------------------------------------
// USART1 DMA Buffer
#define RXBUFFERSIZE 0xFFF
uint8_t RxBuffer[RXBUFFERSIZE];
// ----------------------------------------------------------------------------
#define Loiter() uint8_t loitervar = 0; loitervar++;
void DMA1_Channel5IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC5))
{
// Transfer complete.
DMA_ClearITPendingBit(DMA1_IT_TC5);
GPIO_SetBits(GPIOE, GPIO_Pin_9);
}
else if (DMA_GetITStatus(DMA1_IT_HT5))
{
// Half transfer.
DMA_ClearITPendingBit(DMA1_IT_HT5);
}
else if (DMA_GetITStatus(DMA1_IT_TE5))
{
// Transfer error.
DMA_ClearITPendingBit(DMA1_IT_TE5);
}
// This line must be after clearing of interrupts to avoid immediate re-entry when interrupt is not TC.
Loiter();
}
void GPIO_Configuration()
{
// Enable GPIO Clocks.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOE, ENABLE);
// Configure PA9 & PA10 AF PP.
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // Alternate function.
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // Push pull.
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // GPIOA TX & RX for USART1.
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; // Not required.
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// Connect PA9 & PA10 to USART1.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7); // Tx Line
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7); // Rx Line
// Configure PE9 & PE12 Status LED's.
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void USART_Configuration()
{
// Enable USART1 Clock.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// Initialize USART1: 9600,8N1.
USART_InitTypeDef USART_InitStruct;
USART_StructInit(&USART_InitStruct);
USART_Init(USART1, &USART_InitStruct);
// Enable USART1.
USART_Cmd(USART1, ENABLE);
// Enable RX DMA Transfers from USART1.
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
}
void DMA_Configuration()
{
// Enable DMA1 Controller.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// Clear USART1 RX DMA Channel config.
DMA_DeInit(DMA1_Channel5);
// Initialize USART1 RX DMA Channel:
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->RDR; // USART1 RX Data Register.
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; // Copy data to RxBuffer.
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; // Peripheral as source, memory as destination.
DMA_InitStruct.DMA_BufferSize = RXBUFFERSIZE; // Defined above.
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // No increment on RDR address.
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment memory address.
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // Byte-wise copy.
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // Byte-wise copy.
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // Ring buffer - don't interrupt when at end of memory region.
DMA_InitStruct.DMA_Priority = DMA_Priority_High; // High priority.
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; // Peripheral to memory, not M2M.
// Initialize USART1 RX DMA Channel.
DMA_Init(DMA1_Channel5, &DMA_InitStruct);
// Enable Transfer Complete, Half Transfer and Transfer Error interrupts.
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE, ENABLE);
// Enable USART1 RX DMA Channel.
DMA_Cmd(DMA1_Channel5, ENABLE);
}
void NVIC_Configuration()
{
// We only want to use preemption.
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// Configure USART1 RX DMA Channel Interrupts.
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
}
int main(void)
{
GPIO_Configuration();
USART_Configuration();
DMA_Configuration();
NVIC_Configuration();
while (1);
}

#dma #usart #stm32f3
5 REPLIES 5
Posted on April 24, 2014 at 17:16

Does the USART1 work without using DMA?
 Does the use of C++ syntax suggest it's mangling the name of the IRQ Handler?
 Code doesn't appear unreasonable, would probably not do the if/then/else thing in the IRQ Handler. 

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

Thanks for the reply.

In answer to your questions: 1. The code works flawlessly when using RXNE flag polling as well as RXNE interrupt. 2. Despite my (habitual) C++ syntax, the name of the irq handler is not getting mangled in this case. Thanks for noting the if/then/else in the interrupt handler. The conditionals have been substituted as follows:

void DMA1_Channel5IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC5))
{
// Transfer complete.
DMA_ClearITPendingBit(DMA1_IT_TC5);
GPIO_SetBits(GPIOE, GPIO_Pin_9);
}
if (DMA_GetITStatus(DMA1_IT_HT5))
{
// Half transfer.
DMA_ClearITPendingBit(DMA1_IT_HT5);
}
if (DMA_GetITStatus(DMA1_IT_TE5))
{
// Transfer error.
DMA_ClearITPendingBit(DMA1_IT_TE5);
}
// This line must be after clearing of interrupts to avoid immediate re-entry when interrupt is not TC.
Loiter();
}

connect
Associate II
Posted on April 26, 2014 at 02:33

After some further debugging I can confirm that the DMA transfer does indeed happen, but the IRQ handler never gets called.

I double and triple checked that the handler name isn't getting mangled (inspected output symbols).

I've found an earlier posts which mentions a similar issue:

[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/DMA%20interrupt&amp%3bFolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&amp%3bcurrentviews=2922]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex%5Fmx%5Fstm32%2FDMA%20interrupt&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=2922

Can anybody help by confirming that DMA interrupts on the F30x devices actually do work for non M2M transfers?

Thanks heaps in advance.
Posted on April 26, 2014 at 03:17

void DMA1_Channel5_IRQHandler(void)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
connect
Associate II
Posted on April 26, 2014 at 07:12

Sorted. Thank you Clive.