2015-12-30 03:07 AM
Hello,
I am programming a shell based on HAL UART and I experienced difficulties with the HAL UART API provided with CUBEMX. I was using the non-blocking UART Reveice IO function (IT mode).I have modified the CUBEMX source code (stm32f4xxx_hal_uart.h and.c) to provided theses functionalities :- New IO functions from Arduino world : Available(), GetChar()- UART Receive IT handles a circular buffer to store each received byte.- Receiving a byte does not disable UART Rx IT.You will find the source code in the next posts of this thread.Let me know if you know a better solution. Any feedback is appreciated.Patrick. #uart-hal-it-byte2015-01-12 07:08 AM
Hi Patrick,
If you want to handle a circular buffer to store each received byte via the UART circular mode, we recommend to use the UART DMA Process so that can benefit for the Pause, Resume and Stop functionalities:2015-01-13 11:48 AM
Thank you very much. I will have a look at DMA.
I hope that the Transmit DMA does not cause the same probleme (ORE due to delay waiting TC) as Transmit IT.Bye.Patrick.2015-01-13 01:40 PM
How do I know the offset of the last byte transfered from UART to MEMORY using DMA in circular mode ? Do you have to use the following macro :
/**
* @brief Returns the number of remaining data units in the current DMAy Streamx transfer. * @param __HANDLE__: DMA handle * * @retval The number of remaining data units in the current DMA Stream transfer. */#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->NDTR)2015-01-14 02:27 PM
The UART+DMA combination in circular mode for RX (and normal for TX) seems to work very well. Thank you, Eisenberg.
Bye,Patrick.2015-01-15 04:43 PM
Hi there,
I'm seeing something where the last 4 characters of a transfer are regularly wrong, but seem to be duplicates of valid characters previously received.Would it be possible that NDTR is being decremented before the transfer of the last 32 bits (4 bytes) is done between the peripheral and the memory?If I rely on the half and full interrupts, the data is correct, but if I use partial buffer DMA with timeouts the last 32 bits are sometimes wrong.Does HAL_UART_DMAPause force that last transfer?Thanks,Andrei2015-01-16 12:02 PM
Got it. Yes, the final transfer from the UART to memory was not happening due to buffering.
DMA_SxFCR.DMDIS = 0By turning off FIFO mode and using DMA Direct the incoming characters are placed in the memory buffer immediately. There is a loss in efficiency, but now I can read characters without the overruns of polled mode, or the final 3 character corruption of interrupt mode.
2015-01-17 06:38 AM
Good ! DMA solved all my problems about UART overrun, too, and now I can send and receive data at 921.600bauds in non bloking mode reliably.
Patrick.2015-01-26 09:03 AM
Hi Patrick,
Would you mind to share your DMA non blocking mode code ?Thanks,BR.Vince.2015-01-28 01:19 PM
Here is the code produced by CUBEMX for the UART
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 460800;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);
}
Here is the code produced by CUBEMX for the DMA associated to the UART en RX :
/* Peripheral DMA init*/
hdma_usart3_rx.Instance = DMA1_Stream1;
hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart3_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_usart3_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_usart3_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_usart3_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&hdma_usart3_rx);
__HAL_LINKDMA(huart,hdmarx,hdma_usart3_rx);
In reception, I have got a few variables :
#define size_of_rx_circular_buffer 128
uint8_t rx_circular_buffer[size_of_rx_circular_buffer];
uint8_t const * rx_tail_ptr;
Then, I start DMA RX at the begining of my application :
HAL_UART_Receive_DMA(huart, rx_circular_buffer, size_of_rx_circular_buffer);
rx_tail_ptr = rx_circular_buffer;
Every time I want to know how many characters I have received :
uint8_t const * head = rx_circular_buffer + size_of_rx_circular_buffer - __HAL_DMA_GET_COUNTER(huart->hdmarx);
uint8_t const * tail = rx_tail_ptr;
if( head>=tail )
return head-tail;
else
return head-tail+size_of_rx_circular_buffer;
Every time I read a char in the circular buffer, I inc the tail ptr.
if(head!=tail)
{
char c = *rx_tail_ptr++;
if(rx_tail_ptr>=rx_circular_buffer + size_of_rx_circular_buffer)
rx_tail_ptr-=size_of_rx_circular_buffer;
return c;
}
Hope that will help you ! :)
Bye,
Patrick.