cancel
Showing results for 
Search instead for 
Did you mean: 

New HAL_UART API

amomum
Associate III
Posted on April 22, 2015 at 19:16

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 #usart
14 REPLIES 14
Posted on April 22, 2015 at 21:02

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
childresss
Associate II
Posted on April 22, 2015 at 22:24

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.

zh_jianjun
Associate II
Posted on April 23, 2015 at 11:02

I once read an article about use DMA to receive uart data, and check DMA counter to find out how many data received.

zh_jianjun
Associate II
Posted on April 23, 2015 at 11:48

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)

niels
Associate II
Posted on April 23, 2015 at 12:22

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,

Niels

amomum
Associate III
Posted on April 23, 2015 at 12:42

andersen.niels.001,

 

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.

niels
Associate II
Posted on April 23, 2015 at 13:03

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.

amomum
Associate III
Posted on April 23, 2015 at 14:03

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.

childresss
Associate II
Posted on April 24, 2015 at 19:30

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.