2017-09-27 11:43 PM
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 nucleoSTM32CubeMX, 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.
However, when I type 64th character 'b' Hard Fault raised as following.
'b' exists at receive_str[63] by DMA.
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.
At the time, I lookd stack.
Does anyone know my mistake, or how to workaround?
Thanks!
#uart-dma2017-10-05 11:38 PM
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
2017-10-09 07:42 PM
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****/