2014-04-24 06:59 AM
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
2014-04-24 08:16 AM
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.
2014-04-24 04:17 PM
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();
}
2014-04-25 05:33 PM
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&%3bFolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&%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¤tviews=2922Can anybody help by confirming that DMA interrupts on the F30x devices actually do work for non M2M transfers?Thanks heaps in advance.2014-04-25 06:17 PM
void DMA1_Channel5_IRQHandler(void)
2014-04-25 10:12 PM
Sorted. Thank you Clive.