cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 UART DMA problem

robertnoble9
Associate III
Posted on January 04, 2017 at 00:01

 Hi,

I am working  on an application on an STM32F303RET6 on a nucleo board. I am struggling to get DMA working on USART1 Rx.  I can successfully enable the USART port and it works correctly with the receive interrupt but once I enable the DMA it no longer works. I did have this code working on a STM32F103 nucleo board before but can't for the life of me get it to wrk on the F3 board. I don't have access t my code currently so will edit and add the it later.

Is there anything different about the F3 chip compared to then F1 that might catch me out?

Thanks in advance.

Edit: code below. Hopefully its sufficiently readable.

#define USART_SBUS USART1

#define USART_SBUS_GPIO GPIOC

#define USART_SBUS_CLK RCC_APB2Periph_USART1

#define USART_SBUS_GPIO_CLK RCC_AHBPeriph_GPIOC

#define USART_SBUS_RX_PIN GPIO_Pin_5

#define USART_SBUS_RX_PIN_SOURCE GPIO_PinSource5

#define USART_SBUS_RX_DMA_CHANNEL DMA1_Channel5

#define DMA_SBUS_IRQN DMA1_Channel5_IRQn

#define DMA_SBUS_IRQHandler DMA1_Channel5_IRQHandler

uint8_t rxBuffer[4] = {0,0,0,0};

uint8_t usart_init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

/* enable usart clock */

RCC_APB2PeriphClockCmd(USART_SBUS_CLK, ENABLE);

RCC_AHBPeriphClockCmd(USART_SBUS_GPIO_CLK, ENABLE);

GPIO_InitStructure.GPIO_Pin = USART_SBUS_RX_PIN;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(USART_SBUS_GPIO, &GPIO_InitStructure);

GPIO_PinAFConfig(USART_SBUS_GPIO, USART_SBUS_RX_PIN_SOURCE, GPIO_AF_7);

// /* Enable the USART Interrupt */

// NVIC_InitStructure.NVIC_IRQChannel = USART_SBUS_IRQN;

// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;

// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;

// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

// NVIC_Init(&NVIC_InitStructure);

/* Enable the DMA Interrupt */

NVIC_InitStructure.NVIC_IRQChannel = DMA_SBUS_IRQN;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

USART_InitTypeDef USART_InitStructure;

USART_StructInit(&USART_InitStructure);

USART_InitStructure.USART_BaudRate = 100000;

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

USART_InitStructure.USART_StopBits = USART_StopBits_2;

USART_InitStructure.USART_Parity = USART_Parity_Even;

USART_InitStructure.USART_Mode = USART_Mode_Rx;

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_Init(USART_SBUS, &USART_InitStructure);

USART_InvPinCmd(USART_SBUS, USART_InvPin_Rx, ENABLE);

USART_ITConfig(USART_SBUS, USART_IT_RXNE, ENABLE);

USART_Cmd(USART_SBUS, ENABLE);

USART_DMACmd(USART_SBUS, USART_DMAReq_Rx, ENABLE);

// 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_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->RDR; // USART1 RX Data Register.

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rxBuffer; // Copy data to RxBuffer.

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Peripheral as source, memory as destination.

DMA_InitStructure.DMA_BufferSize = 4; // Defined above.

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // No increment on RDR address.

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment memory address.

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // Byte-wise copy.

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // Byte-wise copy.

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Ring buffer - don't interrupt when at end of memory region.

DMA_InitStructure.DMA_Priority = DMA_Priority_High; // High priority.

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // Peripheral to memory, not M2M.

// Initialize USART1 RX DMA Channel.

DMA_Init(DMA1_Channel5, &DMA_InitStructure);

// Enable Transfer Complete, Half Transfer and Transfer Error interrupts.

DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);

// Enable USART1 RX DMA Channel.

DMA_Cmd(DMA1_Channel5, ENABLE);

return 0x01;

}
15 REPLIES 15
Posted on January 05, 2017 at 17:04

Not sure how it 'stops working', the code I provided seems to work in validating it here, the Inverted 7E2 format strikes me as odd, but it doesn't appear to break things. You might want to mask the data you read into the buffer with 0x7F to clear the parity bit that gets added.

Make sure you don't get any overflow, framing or parity errors which would stop the receiver.

Make sure you want 7-bit data, if you want 8E2 you need to set the USART to 9-bit to account for the parity bit you are using.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 05, 2017 at 17:21

What I actually did was kind of messy because I had to modify HAL's stm32f1xx_hal_uart.c but it worked.. quickly.

 /* Set the UART DMA Half transfer complete callback */
 huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
 /* Set the DMA error callback */
 huart->hdmarx->XferErrorCallback = UART_DMAError;

 /* This seems to solve the problem */
 /*******************TESTING**********************/
 /* Enable the UART Parity Error Interrupt */
 __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
 /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
 __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
 /*******************TESTING**********************/

 /* Enable the DMA channel */
 tmp = (uint32_t*)&pData;
 HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

You can see my inserted code which is clearly between TESTING comments. That's part of HAL_UART_Receive_DMA. Also, you have turn on your UART interrupt, if you initialized your peripheals with STM32CubeMX, inside UART configuration there is a checkbox to enable interruptions. In case you manually initialized your UART:

 HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(USART3_IRQn);�?�?

That goes in your UART initialization just before initializing the DMA associated with that UART. Also in stm32f1xx_it.c

extern UART_HandleTypeDef huart3;
�?

and

void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
}�?�?�?�?

I call HAL_UART_IRQHandler mainly because it handles any error occured in the Transmission or Reception.

Don't forget to modify stm32f1xx_it.h accordingly.

I hope it helps.

robertnoble9
Associate III
Posted on January 05, 2017 at 19:51

Hi all,

This is now fixed.  Clive was on the ball, as always, it was my word length in the end.  I had it set to 8b (7E2) when it should have been 9b (8E2).

This:

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

should have been this:

USART_InitStructure.USART_WordLength = USART_WordLength_9b;

I believe the extra bit was causing an ORE interrupt, which when using the USART interrupt only, got cleared and it just had a bit missing.  When the DMA was enabled the ORE interrupt was not cleared, thus stopping the USART port.  I think!!

Thanks to everyone for their input, there is always more info to be had here, even if it's not always the answer you need now, it's still good info.

Posted on January 05, 2017 at 19:48

Well Clive, there is reason you are on here all the time, chiming in... and its because you are the man/woman !! (you never know).  You were correct, it was the word length being 8b not 9b.  Changed it to 8E2 and BOOM fixed.  I cannot thank you enough.

Posted on January 05, 2017 at 19:56

For the record I'm an English Guy

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 25, 2017 at 03:18

Thank you for this.  I would never have caught this if not for this post.  I need 8 data bits with even parity and I was specifying 8b never suspecting that the parity bit counted as a data bit.  I was getting framing errors and parity errors all over the place.  Once I changed to 9b, my UART DMA worked perfectly.  Another clue came from STM32CubeMX where the parameter settings for USARTs shows '(including Parity)', but I only noticed this after seeing your post.

Another factor that threw me off was that using 8b worked fine when I wasn't using DMA.  I could see framing and parity errors in the ISR and wondered where they were coming from, but I was getting good data from the UART.  Now I realize that DMA handles these errors differently than my interrupt-based code, which accounts for the difference in behavior.