2015-04-22 10:16 AM
In the good old SPL we just had UART_Init, UART_SendData (to send 1 byte) and UART_RecieveData (to receive 1 byte). All interrupt handlers and DMA operation was our own problem.
And many of us already wrote them and tested them. Okay.Now though we have HAL_UART_Send, which allows us to send a whole buffer of some size (via already written interrupt or DMA). That's great. My question is - why there is also HAL_UART_Receive which allows us to RECEIVE a buffer of some size? It will call a callback function when buffer is full.. but what if one byte got lost? What if I just don't know how many bytes I'm about to receive? I'm working with many binary protocols where size of every message is not fixed and transmitted inside of the message.What should I do, make a buffer size of 1? That's kinda weird.Or should I poll RxXferCount in the uartHandle? That would be a bit tricky, since this counter is actually decremented in the irqHandler (and is it affected by DMA at all?).Am I the only one who thinks this API is a bit strange? It would be nice to have a non-blocking function like ''UART_IsNewByteAvailable'', for example. #uart #hal #usart2015-04-22 12:02 PM
Am I the only one who thinks this API is a bit strange?
No, it requires a paradigm shift, honestly I think it complicates more than it solves.2015-04-22 01:24 PM
I and others have said that ST's HAL for UARTs is missing the conventional UART ISR with a ring buffer and an API to check if there are bytes in waiting, read some/all bytes from the ring buffer, etc. For cases where the incoming 8 bit bytes' themselves dictate how many more to expect. And a ring buffer for output too, so that it can be non-blocking if the user app checks for output ring buffer full before sending.
Compared to convention, as in all systems I've worked with, this is a glaring omission. A few users have written their own replacement ISR but it a HAL update tends to clobber such. And I've not even seen a hook to take over the interrupt/ISR from HAL at run time. One can't do single-byte reads from the UART, non-blocking. Also, at some baud rates, a single byte read will fail to get the next read started before that byte's start bit occurs.2015-04-23 02:02 AM
I once read an article about use DMA to receive uart data, and check DMA counter to find out how many data received.
2015-04-23 02:48 AM
about ''And I've not even seen a hook to take over the interrupt/ISR from HAL at run time.''
I use ''#if 0/#endif'' to ignore default ISR, and deploy my own in another source file. If the ISR is regenerated, just revert it in git(or any other source constrol system)2015-04-23 03:22 AM
I have an idea how uart reception can be done using the new HAL api without tampering the generated files.
Start by creating a receive buffer in two halfs. The receive interrupt will toggle between the first and the second half.#define UART_RX_FIFO_SIZE 32
unsigned char Uart1RxFifo[UART_RX_FIFO_SIZE+UART_RX_FIFO_SIZE]; uint16_t Uart1CurrFifo = 0; Write the uart interrupt callback routines:/*** Uart call backs ***/
/** * HAL_UART_RxCpltCallback. Uart receive complete call back * \param huart Handle/pointer to uart */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart) { /* Toggle between first and second half of rx fifo */ if (Uart1CurrFifo == 0) { HAL_UART_Receive_IT(huart,&Uart1RxFifo[UART_RX_FIFO_SIZE],UART_RX_FIFO_SIZE); Uart1CurrFifo = 1; } else { HAL_UART_Receive_IT(huart,&Uart1RxFifo[0],UART_RX_FIFO_SIZE); Uart1CurrFifo = 0; } } /** * HAL_UART_ErrorCallback. Uart error call back * \param huart Handle/pointer to uart */ void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart) { /* Check errorcode */ if (huart->ErrorCode != HAL_UART_ERROR_NONE) { /* Clear errorcode */ huart->ErrorCode = HAL_UART_ERROR_NONE; } } In the main loop call a uart receive function that reads the content of the RX fifo:void UartReceive(void) {
static uint8_t * pRxBuffPtr; static int UartInit=0; unsigned char Ch; if (!UartInit) { HAL_UART_Receive_IT(&huart1,&Uart1RxFifo[0],UART_RX_FIFO_SIZE); pRxBuffPtr = &Uart1RxFifo[0]; UartInit = 1; } /* Check if new data has arrived */ while (pRxBuffPtr != huart1.pRxBuffPtr) { Ch = *pRxBuffPtr; /*** Handle received data here ***/ pRxBuffPtr++; if (pRxBuffPtr == Uart1RxFifo + sizeof(Uart1RxFifo)) { pRxBuffPtr = &Uart1RxFifo[0]; } } } main(void) { ... ... while (1) { .... .... UartReceive(); .... .... } } Rgds, Niels2015-04-23 03:42 AM
we want to be able to receive a SINGLE byte in non-blocking mode. Your approach doesn't actually resolve this and seems a bit irrelevant.
2015-04-23 04:03 AM
Sorry for suggesting a solution. The intterupt routine takes care of picking up data from the uart. You can adjust the UartReceive routine to receive a single character at a time.
2015-04-23 05:03 AM
andersen.niels.001, yes, I know. I actually wrote it in the first post. It's just seems a bit weird to make a buffer of length 1 and than wait for a callback after each byte.
If I make two buffers instead of one, it won't be any better.2015-04-24 10:30 AM
At some baud rates, it may not be possible, on a busy MCU with preemption of ISRs, to assure that one can post a new 1-character read in the one bit-time between chars.
A ring buffer driver is essential and commonplace in all systems but missing in the HAL.