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;

}
1 ACCEPTED SOLUTION

Accepted Solutions
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.

View solution in original post

15 REPLIES 15
T J
Lead
Posted on January 04, 2017 at 03:24

Did you fix it ?

I had the same problem,

I had to use the Half Complete and Complete interrupt call backs.

I had to use a 2byte DMA buffer so I could get an interrupt on each byte without having to be so concerned about timing.

1MByte of text sent from Teraterm @ 460800, received and re-transmitted through a double buffered DMA Tx set, seems to work ok.

Posted on January 04, 2017 at 09:03

No, not yet.  Still working on it.

I can't get the DMA working with or without the interrupts enabled.

Posted on January 04, 2017 at 17:32

Your code isn't sufficiently complete to test/evaluate, this is a blind port of something I would expect to work

// STM32 USART1 (Rx PC.5 100000 baud inverted) STM32F3 Discovery - sourcer32@gmail.com
#include 'stm32f3_discovery.h'
//****************************************************************************
void RCC_Configuration(void)
{
 /* USART1 clock enable */
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
 /* GPIOC and DMA clock enable */
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_DMA1, ENABLE);
}
//****************************************************************************
void GPIO_Configuration(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 /* GPIO Configuration */
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOC, &GPIO_InitStructure);
 /* Connect USART pins to AF */
 GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_7); // USART1_R
X}
//****************************************************************************
void USART1_Configuration(void)
{
 USART_InitTypeDef USART_InitStructure;
 /* USARTx configuration ------------------------------------------------------*/
 /* USARTx configured as follow:
 - BaudRate = 100000 baud
 - Word Length = 8 Bits
 - Two Stop Bit
 - Even parity
 - Hardware flow control disabled (RTS and CTS signals)
 - Receive and transmit enabled
 */
 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_HardwareFlowControl = USART_HardwareFlowControl_None;
 USART_InitStructure.USART_Mode = USART_Mode_Rx;
 USART_Init(USART1, &USART_InitStructure);
 USART_InvPinCmd(USART1, USART_InvPin_Rx, ENABLE);
 USART_Cmd(USART1, ENABLE);
}
/**************************************************************************************/
volatile uint8_t Buffer[] = 'The quick brown fox jumps over the lazy dog';
void DMA_Configuration(void)
{
 DMA_InitTypeDef DMA_InitStructure;
 DMA_DeInit(DMA1_Channel5);
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Receive
 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Buffer;
 DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer);
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->RDR;
 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_Circular;
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
 DMA_Init(DMA1_Channel5, &DMA_InitStructure);
 /* Enable the USART Rx DMA request */
 USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
 /* Enable DMA Stream Transfer Complete interrupt */
 DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
 /* Enable the DMA RX Stream */
 DMA_Cmd(DMA1_Channel5, ENABLE);
}
/**************************************************************************************/
void DMA1_Channel5_IRQHandler(void)
{
 /* Test on DMA Stream Transfer Complete interrupt */
 if (DMA_GetITStatus(DMA1_IT_TC5))
 {
 /* Clear DMA Stream Transfer Complete interrupt pending bit */
 DMA_ClearITPendingBit(DMA1_IT_TC5);
 // ...
 }
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
 NVIC_InitTypeDef NVIC_InitStructure;
 /* Configure the Priority Group to 2 bits */
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
 /* Enable the USART1 RX DMA Interrupt, per RM0316 */
 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
}
//****************************************************************************
int main(void)
{
 RCC_Configuration();
 NVIC_Configuration();
 GPIO_Configuration();
 USART1_Configuration();
 DMA_Configuration();
 while(1); // Don't want to exit
}
//****************************************************************************
#ifdef USE_FULL_ASSERT
/**
 * @brief Reports the name of the source file and the source line number
 * where the assert_param error has occurred.
 * @param file: pointer to the source file name
 * @param line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t* file, uint32_t line)
{
 /* User can add his own implementation to report the file name and line number,
 ex: printf('Wrong parameters value: file %s on line %d

', file, line) */
 /* Infinite loop */
 while (1)
 {
 }
}
#endif
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

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 01:35

So tried a little more but still with no luck.

- I can successfully enable the USART port and receive data, so this configuration is ok.

- I can successfully configure the DMA channel in question (DMA1 channel5) to transfer data from memory to memory, just with two arrays.

Putting the two together (after changing the M2M parameter and addresses for the DMA config) it stops working.  When checking the register values against the reference manual all looks to be configured correctly.  I'm at my wits end with this and running out of ideas.

Posted on January 05, 2017 at 02:12

I had to use a nested DMA buffer arrangement to ensure high speed and reliable data.

in transmit, the string is moved to a DMA Queing buffer, the DMA was NORMAL mode.

in Receive, under half & full complete DMA interrupts. I had to DMA only 2 bytes in CIRCULAR mode,  to get two interrupts, to save each byte into the Rx buffer.

These both work very well at 460800 simultaneously.

Posted on January 05, 2017 at 08:57

It seems the USART port stops working once the DMAR bit within the CCR3 register is set.  I am doing this with

USART_DMACmd(USART1, USART_DMAReq_Rx).

Posted on January 05, 2017 at 09:58

I am using the standard peripheral library rather than HAL.

Posted on January 05, 2017 at 16:14

I had an issue with HAL but maybe you can get something useful.

I was using DMA to receive an unspecified lenght buffer so I had configured a UART to receive and a DMA to copy 256 bytes to an array. Then I checked periodically the array for any useful data of interest.

After a while I could notice DMA was not receiving data anymore and it seems like ORE flag was set in the Status Register (SR) of the UART that I was using.

My fix was activating the interrupt of that UART when any error happened and clearing the flag properly, altough not perfect, it works. I think that if I weren't checking the receive buffer (the array that DMA fills with the data arriving on my UART) there is a chance that the DMA transfer would never be complete because ORE flag was set before completing the transfer and the following data would never been copied by the DMA.

So I rather suggest that you check your UART's SR register in order to spot any (unhandled) error condition that might be stopping your DMA transfer. If you notice one, handling it on an interrupt handler will probably fix your problem.

Posted on January 05, 2017 at 16:22

Thats interesting.  I will give it a go.  Did you have associated the interrupts enabled or just code to handle them if the occurred by chance?