Skip to main content
mikem1017
Associate II
October 31, 2022
Question

How can I pass pointer info from hal_uart_receive_it into the callback function?

  • October 31, 2022
  • 6 replies
  • 4077 views

I am trying to port over some code from PIC to STM32. In the pic code, the ISR took the pointer data from the received uart message (1 byte) and then sent that pointer data to a circular_buffer_put function (effectively putting it into the circular buffer).

The wall I'm running into is that the callback function is defined as only having one parameter - the huart handle - so I can't really do it the same way as before. All the examples I've seen online have the pointer data stored as a modular variable, which I'd really prefer not to do, and so the pointer data can be accessed in any function, including that of the callback.

Do any of you have a good idea on how to solve this problem?

Here's some example code of effectively what I'd like to do...

void HAL_UART_RxCpltCallback(uart_device_t *uart_struct, uint8_t *data)
{
 circular_buf_put(&RxBuffer, *data);
 HAL_UART_Receive_IT(uart_struct->huart, *data, 1);
}

This topic has been closed for replies.

6 replies

Tesla DeLorean
Guru
October 31, 2022

Use some compound structure where you park the normal handle structure at the front, and your stuff at the back, and then cast what gets passed into the HAL, and what it hands back to you later.

typedef struct _UART_SUPER_HandleTypeDef {

UART_HandleTypeDef UartHandle;

// Your stuff

uint8_t *data;

int foo;

} UART_SUPER_HandleTypeDef;

UART_SUPER_HandleTypeDef Uart1;

Use &Uart1->UartHandle

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
mikem1017
mikem1017Author
Associate II
October 31, 2022

Thank you so much for your detailed response!

Doesn’t the callback only take a handle though? If I do the method you mention, I’m still only sending it the handle right? How do I get the struct into the callback so that I can then pass the data to my circular buffer?

Tesla DeLorean
Guru
November 1, 2022

Cast it back to the super structure.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

UART_SUPER_HandleTypeDef *ptr = (UART_SUPER_HandleTypeDef *)UartHandle;

...

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
October 31, 2022

Very good suggestion Clive.

And as MCU have data in ram or flash, sub user blocks may have pointers to different memory.

Tesla DeLorean
Guru
October 31, 2022

It's honestly a pity that ST didn't think this through better and have a user data value or pointer within the original structure, or passed to the callbacks. The ability to link things seems like a very basic concept.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
mikem1017
mikem1017Author
Associate II
October 31, 2022

There actually is pointer value in the original structure I found... I'm just not sure whether I can use it. It's called *pRxBuffPtr. Any idea whether that's a pointer I can use?

typedef struct __UART_HandleTypeDef
{
 USART_TypeDef *Instance; /*!< UART registers base address */
 
 UART_InitTypeDef Init; /*!< UART communication parameters */
 
 const uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
 
 uint16_t TxXferSize; /*!< UART Tx Transfer size */
 
 __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
 
 uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
 
 uint16_t RxXferSize; /*!< UART Rx Transfer size */
 
 __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
 
 __IO HAL_UART_RxTypeTypeDef ReceptionType; /*!< Type of ongoing reception */
 
 DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
 
 DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
 
 HAL_LockTypeDef Lock; /*!< Locking object */
 
 __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
 and also related to Tx operations.
 This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
 __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
 This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
 __IO uint32_t ErrorCode; /*!< UART Error code */
 
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
 void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */
 void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */
 void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */
 void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
 void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
 void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
 void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
 void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
 void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
 void (* RxEventCallback)(struct __UART_HandleTypeDef *huart, uint16_t Pos); /*!< UART Reception Event Callback */
 
 void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
 void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
 
} UART_HandleTypeDef;

S.Ma
Principal
October 31, 2022

On my side sometime I use a "hook" which contains both a function pointer and a data context pointer to a user structure that can grow going up the sw layers. Type cast used to keep things tidy. Minimizing function passing parameters avoid filling up the core working registers that may not be used right away and could cause unseen performance losses.

Pavel A.
October 31, 2022

> Use some compound structure where you park the normal handle structure

There's absolutely no need for such structure in this case.

The UART "handle" structure contains all the context about the completed operation (the buffer address, number of bytes read, status...). The callback can just use that.

A better idea is NOT to use the HAL for UARTs at all.

mikem1017
mikem1017Author
Associate II
October 31, 2022

Thank you for the response. I am fairly new to all this (in fact I am a hardware engineer trying to learn some embedded). How would I 1) go about having the data pointer included in the uart handle structure? But more importantly 2) how do I not use Hal for this? Can you give me some example code on how I can write a uart receive interrupt with a call back including the passing of the data to a new function?

thank you!

Pavel A.
October 31, 2022

Hi @mikem1017​ 

1) you've already found the UART "handle" struct and the pointer. Yes, that pointer.

2) Sorry, I don't have a suitable example. But this is a frequent topic, there should be some examples around.

The complexity and size of the HAL code speaks for itself. It perhaps is good enough for demonstrating the hardware or a quick prototype, but one does not want this in a real product.

There is a well known collection of DMA based UART examples on github, but that is a higher level of complexity.

S.Ma
Principal
November 1, 2022

True, for variable incoming message size, such as console emulation, UART HAL is less appealing than LL. Crude method with per byte interrupt is a simple start point. The other way is dma with cyclic buffer checked at regular time interval. Decide if reactivity and optimized RAM is higher priority to choose.

mikem1017
mikem1017Author
Associate II
November 1, 2022

Thanks for taking the time to respond.

mikem1017
mikem1017Author
Associate II
November 1, 2022

0693W00000VOc5GQAT.pngOk, I've gotten this mostly working using the pointer inside of the uart handle struct. However, I'm noticing a slightly weird behaviour. When I echo back the received character, I'm getting an incremented letter. For example, if I send a, it echos back b.

Here's my init code:

	uart_struct->huart = huart;
 
	uint8_t *rxdata = (uint8_t*) (&uart_struct->huart->pRxBuffPtr);
 
	if (HAL_UART_Receive_IT(uart_struct->huart, rxdata, 1) != HAL_OK)
		return EID_INT_UART_RECEIVE_FAIL;
	else
		return EID_OKAY;

Here's my callback:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	uint8_t *rxdata = (uint8_t*) (&huart->pRxBuffPtr);
 
	// MAIN UART (MAX22502EATC+)
	if (huart->Instance == USART3) {
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
		// Reinitialize HAL_UART_Receive_IT
		HAL_UART_Transmit(huart, rxdata, 1, HAL_MAX_DELAY);
		HAL_UART_Receive_IT(huart, rxdata, 1);
	}

Any ideas what might be causing the character to increment?

mikem1017
mikem1017Author
Associate II
November 1, 2022

I've done some variable isolation and I can confirm now that the issue above is caused by using the pRxBuffPtr variable inside the struct. Is there a reason it's incrementing the data inside this ptr by 1?