cancel
Showing results for 
Search instead for 
Did you mean: 

How to reset DMA buffer for UART

Raider E
Associate III
Posted on January 19, 2017 at 04:06

Hi Everyone,

Just a little issue, I would like to reset the receiving buffer of the DMA in circular mode every time it completes reception. If i know the exact size of received data problem solved the DMA buffer will reset when its full. However, I receive various size of data (strings), say every 100 ms from a connected device and it makes parsing much easier if the DMA buffer reset

uint8_t rxbytes[32]='';
 
HAL_UART_Receive_DMA(&huart1, (uint8_t *)rxbytes, 32); // use DMA
MSP file (DMA config for UART1):
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
 GPIO_InitTypeDef GPIO_InitStruct;
 if(huart->Instance==USART1)
 {
 /* USER CODE BEGIN USART1_MspInit 0 */
 /* USER CODE END USART1_MspInit 0 */
 /* Peripheral clock enable */
 __HAL_RCC_USART1_CLK_ENABLE();
 
 /**USART1 GPIO Configuration 
 PB14 ------> USART1_TX
 PB15 ------> USART1_RX 
 */
 GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF4_USART1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 /* Peripheral DMA init*/
 
 hdma_usart1_rx.Instance = DMA2_Stream2;
 hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
 hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
 hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
 hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
 hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
 hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
 hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
 hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
 if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
 {
 Error_Handler();
 }
 __HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);
 /* Peripheral interrupt init */
 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(USART1_IRQn);
 /* USER CODE BEGIN USART1_MspInit 1 */
// /* Peripheral interrupt init */
// HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(USART1_IRQn);
// /* USER CODE BEGIN USART1_MspInit 1 */
 /* USER CODE END USART1_MspInit 1 */
 }
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
 if(huart->Instance==USART1)
 {
 /* USER CODE BEGIN USART1_MspDeInit 0 */
 /* USER CODE END USART1_MspDeInit 0 */
 /* Peripheral clock disable */
 __HAL_RCC_USART1_CLK_DISABLE();
 
 /**USART1 GPIO Configuration 
 PB14 ------> USART1_TX
 PB15 ------> USART1_RX 
 */
 HAL_GPIO_DeInit(GPIOB, GPIO_PIN_14|GPIO_PIN_15);
 /* Peripheral DMA DeInit*/
 HAL_DMA_DeInit(huart->hdmarx);
 /* Peripheral interrupt DeInit*/
 HAL_NVIC_DisableIRQ(USART1_IRQn);
 }
 /* USER CODE BEGIN USART1_MspDeInit 1 */
 /* USER CODE END USART1_MspDeInit 1 */
}

peripherals and clock configurations:

void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct;
 RCC_ClkInitTypeDef RCC_ClkInitStruct;
 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
 /**Configure the main internal regulator output voltage
 */
 __HAL_RCC_PWR_CLK_ENABLE();
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 /**Initializes the CPU, AHB and APB busses clocks
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLM = 8;
 RCC_OscInitStruct.PLL.PLLN = 192;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
 RCC_OscInitStruct.PLL.PLLQ = 2;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 /**Activate the Over-Drive mode
 */
 if (HAL_PWREx_EnableOverDrive() != HAL_OK)
 {
 Error_Handler();
 }
 /**Initializes the CPU, AHB and APB busses clocks
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK)
 {
 Error_Handler();
 }
 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
 PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 /**Configure the Systick interrupt time
 */
 HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 /**Configure the Systick
 */
 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 /* SysTick_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}
void MX_USART1_UART_Init(void)
{
 huart1.Instance = USART1;
 huart1.Init.BaudRate = 38400;
 huart1.Init.WordLength = UART_WORDLENGTH_8B;
 huart1.Init.StopBits = UART_STOPBITS_1;
 huart1.Init.Parity = UART_PARITY_NONE;
 huart1.Init.Mode = UART_MODE_TX_RX;
 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
 huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;
 huart1.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
 if (HAL_UART_Init(&huart1) != HAL_OK)
 {
 Error_Handler();
 }
}
/**
 * Enable DMA controller clock
 */
void MX_DMA_Init(void)
{
 /* DMA controller clock enable */
 __HAL_RCC_DMA2_CLK_ENABLE();
 /* DMA interrupt init */
 /* DMA2_Stream0_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 /* DMA2_Stream2_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);

}

�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

One more question is for some reason I had to set the baud rate on my UART to 38400 in order to get 19200!! I checked it on oscilloscope and indeed this is the case, any thing alarming in my settings. Thank you all in advance.

6 REPLIES 6
Raider E
Associate III
Posted on January 22, 2017 at 22:20

Anyone can help with this issue please?.

Raider E
Associate III
Posted on January 23, 2017 at 01:56

I just looked at the code for:

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

{

uint32_t *tmp;

/* Check that a Rx process is not already ongoing */

if(huart->RxState == HAL_UART_STATE_READY)

{

if((pData == NULL ) || (Size == 0U))

{

return HAL_ERROR;

}

/* Process Locked */

__HAL_LOCK(huart);

huart->pRxBuffPtr = pData;

huart->RxXferSize = Size;

huart->ErrorCode = HAL_UART_ERROR_NONE;

huart->RxState = HAL_UART_STATE_BUSY_RX;

/* Set the UART DMA transfer complete callback */

huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;

/* Set the UART DMA Half transfer complete callback */

huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;

/* Set the DMA error callback */

huart->hdmarx->XferErrorCallback = UART_DMAError;

/* Set the DMA abort callback */

huart->hdmarx->XferAbortCallback = NULL;

/* Enable the DMA channel */

tmp = (uint32_t*)&pData;

HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, *(uint32_t*)tmp, Size);

/* Process Unlocked */

__HAL_UNLOCK(huart);

/* Enable the UART Parity Error Interrupt */

SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);

/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */

SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

/* Enable the DMA transfer for the receiver request by setting the DMAR bit

in the UART CR3 register */

SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);

return HAL_OK;

}

else

{

return HAL_BUSY;

}

}

Basically i'd like to check if reception is complete which is

UART_DMAReceiveCplt

then reset streamindex but dont know how to do it using macros ?

Posted on January 23, 2017 at 02:02

Oh just found an easy solution to reset the the stream index

HAL_UART_DMAStop(&huart1);

HAL_UART_Receive_DMA(&huart1, (uint8_t *)&rxbytes, 100); // use DMA

However I still would like to check when reception is complete.

Chensie
Associate II
Posted on January 23, 2017 at 07:52

Hi,

You use HAL_UART_Receive_DMA(&huart1, (uint8_t *)rxbytes, 32)
may received maxium 32 bytes, but 

receive various size of data (strings), so you CAN use UART_IT_IDLE interrupt to solve it. __HAL_UART_ENABLE_IT(uartHandle, UART_IT_IDLE); // Enable IDLE interrupt in UART_IT_IDLE interrupt handle get the real received strings and stop Receive_DMA like as: if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == RESET) { HAL_UART_DMAStop() /* Get recieved counter */ rcv.size =sizeof(rcv.buf) - huart1.hdmarx->Instance->NDTR; }
Yasin Yelkovan
Associate III
Posted on July 26, 2017 at 14:04

Hi Chensie.lei,

I think your solution way is very usefull but I have problem with DMA and UART interrupts. When I enable UART ITs while DMA is running, if ı send message from computer to kit, program always crashes , however if ı dont send any message it running normaly. I mean I couldn't receive any message  with UART when DMA is enabled. Do you have any idea for this issue?

And I use STM32F407 Discovery kit.

Thanks

l90mehdi
Associate II
Posted on August 20, 2017 at 17:04

HI

hdma_usart6_rx.Instance->CR=0XA00051E;

hdma_usart6_rx.Instance->NDTR='desired amount';

hdma_usart6_rx.Instance->CR=0XA00051F;

desired amount : the DMA interrupt runs after desired amount.

if after each receive  you write these codes then the new data that receive from usart will be in first of DMA buffer.

for example if you want receive data from usart and maximum number od received data should be smaller than 1000

you should write 

hdma_usart6_rx.Instance->CR=0XA00051E;

hdma_usart6_rx.Instance->NDTR=

'1000

'

;

hdma_usart6_rx.Instance->CR=0XA00051F;

after each receive.

in this way you can reset the usart receiver counter after receive data from usart.