cancel
Showing results for 
Search instead for 
Did you mean: 

Hard Fault, after HAL_UART_Receive_DMA() is called.

Tadao Tomiyama
Associate III
Posted on September 28, 2017 at 08:43

Hello!

I am trying to use USART2 + DMA for Rx/Tx. Tx is working OK already.

For Rx, I would like to use DMA circular mode.

I use followings.

  STM32L476 nucleo

  STM32CubeMX, STM32CubeL4 1.9.0.

After do workaround PLLM problem adding RCC_OscInitStruct.PLL.PLLM = 1;

I called,

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

     huart == &huart2

     pData == &receive_str[0] == 0x2000194c

     Size == sizeof(receive_str) == 64

until 63rd character receive there is no problem. I typed 'a' 63 times.

The black backed area is buffer for  Receive_DMA.

0690X00000608PcQAI.png0690X00000608PhQAI.png

However, when I type 64th character 'b' Hard Fault raised as following.

'b' exists at  receive_str[63]  by DMA.

0690X00000608MUQAY.png0690X00000608PmQAI.png

PRECISEERR is 1 , BFAR = 0x20018000.

It looks unwanted memory access to 0x200018000, did not such access.

DMAC is still transfers Rx data correctly.

I typed 'c' 3times, then the buffer is overwriten circulariy as expected.

0690X00000608PrQAI.png

At the time, I lookd stack.

0690X00000608Q1QAI.png

Does anyone know my mistake, or how to workaround?

Thanks!

#uart-dma
2 REPLIES 2
Tadao Tomiyama
Associate III
Posted on October 06, 2017 at 08:38

Hi!

After I posted the above, I have investigated into this problem.

It might be caused by conflict between following two peripheral access.

    DMA1->CNDTR6 read by software.

    DMA1->CNDTR6 value reload by DMA circular transfer. 

If I kill DMA1->CNDTR6 read code as a test, the hard fault will not be raised.

The problem looks also be timing critical,  but I have never seen the hard fault without CNDTR6 read for now.

Does anyone know a workaround or way for further investigation?

I read CNDTR6 to make FIFO for UART2 Rx, it is useful.

However, if there is no way, I will do other things.

Thank you.

----

STM32L476 nucleo

STM32CubeMX4.22.1, STM32CubeL4 1.9.0.

FreeRTOS

USART2 + DMA for Rx/Tx (Rx is circular mode)

RNG

RTC

Tadao Tomiyama
Associate III
Posted on October 10, 2017 at 04:42

Hi!

One solution to eliminate software read DMA1->CNDTR6, is to use DMA interrupt callback every 1 byte receive.

If we set following DMA_LENGTH == 2, we can use HAL_UART_RxHalfCpltCallback() or HAL_UART_RxCpltCallback() for every 1 byte receive.

  usart_status = HAL_UART_Receive_DMA(&huart2,(uint8_t *)&uart_rx_dma_buffer[0],(uint16_t)

DMA_LENGTH

);

This solution is complicated, but it works.

Priority for DMA channel6 interrupt, and FreeRTOS tasks must  be set properly.

for(;;);  to trap erros might be too strict. 

/* USER CODE BEGIN Variables */

#define RECEIVE_LENGTH (64)

#define

DMA_LENGTH

(2)

#define ONE_LINE_LENGTH (32)

static uint8_t receive_str[RECEIVE_LENGTH] = '';

uint8_t one_line_str[ONE_LINE_LENGTH] = '';

static uint8_t uart_rx_dma_buffer[DMA_LENGTH] = '';

uint32_t read_index = 0U;

uint32_t dma_write_index = 0U;

/* USER CODE END Variables */

/* omit */

/* StartRxTask function */

void StartRxTask(void const * argument)

{

  /* USER CODE BEGIN StartRxTask */

  HAL_StatusTypeDef usart_status = HAL_OK;

  int read_char_inline = 0;

  int received_char = 0;

  int32_t flg_got_line = 0;

  UNUSED(one_line_str);

  UNUSED(flg_got_line);

  usart_status = HAL_UART_Receive_DMA(&huart2,(uint8_t *)&uart_rx_dma_buffer[0],(uint16_t)

DMA_LENGTH

);

  if(usart_status != HAL_OK){

  }

  /* Infinite loop */

  for(;;)

  {

    received_char = 0;

    flg_got_line = 0;

    while((received_char = fgetc_circular(&huart2)) != EOF){

      if(read_char_inline >= ONE_LINE_LENGTH){

        read_char_inline = 0;

      }

      switch(received_char){

      case '\r':

      case '\n':

        flg_got_line = 1;

        received_char = (int)'\0';

        one_line_str[read_char_inline] = (uint8_t)received_char;

        read_char_inline = 0;

        break;

      default:

        one_line_str[read_char_inline] = (uint8_t)received_char;

        read_char_inline++;

        break;

      }

    }

  }

  /* USER CODE END StartRxTask */

}

/* USER CODE BEGIN Application */

static int fgetc_circular(UART_HandleTypeDef *huart){

  int n_char = EOF;

  BaseType_t result_NotifyWait = pdFALSE;

  uint32_t index_in_rx_dma = 0U;

  result_NotifyWait = xTaskNotifyWait(0x00, (~0), &index_in_rx_dma, portMAX_DELAY);             /* use xTaskNotifyWait() API, to return RTOS scheduling */

  if(result_NotifyWait == pdTRUE){       /* received */

    if(read_index != dma_write_index){

      n_char = (int)(receive_str[read_index]);

      read_index++;

    }

  }

  else{

    for(;;);                                                                                   /* NOT REACHED, wait portMAX_DELAY */

  }

  return n_char;

}

/* ------------- DMA callback  ------------- */

static void uart_dma_store_1byte(uint8_t char_to_store){

  receive_str[dma_write_index] = char_to_store;

  dma_write_index++;

  if(dma_write_index >= RECEIVE_LENGTH){

    dma_write_index = 0U;

  }

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

  BaseType_t notify_result = pdPASS;

  if(huart == &huart2){

    uart_dma_store_1byte(uart_rx_dma_buffer[1]);

    notify_result = xTaskNotifyFromISR(RxTaskHandle, 1U, eSetValueWithoutOverwrite , NULL);

    if(notify_result != pdPASS){

      for(;;);                  /* notify error, lose rx data */

    }

  }

}

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)

{

  BaseType_t notify_result = pdPASS;

  if(huart == &huart2){

    uart_dma_store_1byte(uart_rx_dma_buffer[0]);

    notify_result = xTaskNotifyFromISR(RxTaskHandle, 0U, eSetValueWithoutOverwrite , NULL);

    if(notify_result != pdPASS){

      for(;;);                 /* notify error, lose rx data */

    }

  }

}

/* USER CODE END Application */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/