Atomic configuration methods

The concept

HAL2 introduces several key updates to enhance flexibility and efficiency:

  • Unitary configuration APIs now allow configuring or retrieving a single item for a peripheral, such as setting the UART baud rate, without reapplying the full configuration.

  • The generic __HAL_LINKDMA macro has been replaced with dedicated DMA link APIs for clearer, more maintainable code.

  • New APIs for setting and getting user data within HAL handles, supporting flexible application-specific data management.

  • The callback registration mechanism has been optimized by replacing the global register API with individual callback APIs, removing the “UnRegister” callback and reducing overhead.

Together, these enhancements improve the usability and performance of the HAL2 library.

Unitary configuration APIs

In HAL 2, unitary configuration APIs enable configuring or retrieving a single item for a given peripheral, such as setting the UART baud rate. Depending on the peripheral, the unitary item can apply to the entire PPP instance, a specific PPP instance subblock, such as a TIM output compare subblock, or a PPP subinstance, like a TIM channel. These APIs are designed to dynamically modify or retrieve a unitary item, assuming that a global or subblock configuration has already been applied.

These functions allow the modification of a single configuration item without requiring the full configuration function to be called again. For certain HAL drivers, such as HAL I2C, these are new services. For other HAL drivers, like HAL TIM, these unitary APIs replace macros or functions previously used to dynamically modify a single item.

TIM example

TIM period in HAL1 and HAL2

HAL1

HAL2

TIM_HandleTypeDef htim;

/* Change the TIM Period */
__HAL_TIM_SET_AUTORELOAD(&htim, new_tim_period);

/* Change the TIM channel source */
HAL_TIMEx_TISelection(&htim,
                      TIM_TIM2_TI1_COMP2,
                      TIM_CHANNEL_1);
hal_tim_handle_t htim;

/* Change the TIM Period */
HAL_TIM_SetPeriod(&htim, new_tim_period);

/* Change the TIM channel source */
HAL_TIM_IC_SetChannelSource(&htim,
                            HAL_TIM_CHANNEL_1,
                            HAL_TIM_INPUT_TIM2_TI2_COMP2);

CRC example

CRC polynomial in HAL1 and HAL2

HAL1

HAL2

/* X^8 + X^7 + X^4 + X^3 + X + 1 */
#define APP_CRC_POLYNOMIAL_8B 0x9B

CRC_HandleTypeDef hcrc;

/* Change the CRC Polynomial */
__HAL_CRC_POLYNOMIAL_CONFIG(&hcrc, APP_CRC_POLYNOMIAL_8B);
/* X^8 + X^7 + X^4 + X^3 + X + 1 */
#define APP_CRC_POLYNOMIAL_8B 0x9B

hal_crc_handle_t hcrc;

/* Change the CRC Polynomial */
HAL_CRC_SetConfigPolynomial(&hcrc, APP_CRC_POLYNOMIAL_8B,
                                   HAL_CRC_POLY_SIZE_8B,
                                   0xFFFFFFFF);

Introduction of HAL user data set/get APIs

HAL2 introduces new APIs that allow associating application-specific user data with the HAL PPP handle. This feature lets applications store and retrieve a user data pointer of any type within the handle. The pointer is defined as a void pointer for maximum flexibility. The HAL driver initializes this pointer as NULL during HAL_PPP_Init but does not manipulate or validate it thereafter. Ownership of the pointer fully belongs to the user and it is managed with the HAL_PPP_SetUserData and HAL_PPP_GetUserData functions. A common use case is setting the pointer before a process starts and retrieving it in the completion callback. These APIs are enabled by defining USE_HAL_PPP_USER_DATA as “1” in the stm32tnxx_hal_conf file.

Example

struct hal_tim_handle_s;
typedef struct hal_tim_handle_s hal_tim_handle_t;

struct hal_tim_handle_s
{
  /* HAL TIM instance */
  hal_tim_t instance;
  ...
  #if defined (USE_HAL_TIM_USER_DATA) && (USE_HAL_TIM_USER_DATA == 1)
  /* User Data Pointer  */
  const void *p_user_data;
  #endif /* USE_HAL_TIM_USER_DATA */
};

#if defined (USE_HAL_TIM_USER_DATA) && (USE_HAL_TIM_USER_DATA == 1)
void HAL_TIM_SetUserData(hal_tim_handle_t *htim, const void *p_user_data);
const void *HAL_TIM_GetUserData(const hal_tim_handle_t *htim);
#endif /* USE_HAL_TIM_USER_DATA */

Individual callback registration APIs replace global register and unregister functions

HAL2 optimizes the callback registration mechanism by replacing the global register callback API with separate registration functions for each callback, improving efficiency and reducing code footprint. The unregister callback API has been removed; users can restore default weak HAL PPP callbacks by re-registering them. Callback pointers remain stored in the HAL handle, and the feature is enabled with the USE_HAL_PPP_REGISTER_CALLBACK compilation define statement. Additionally, dedicated callback prototype types are introduced to enhance clarity and consistency.

UART example

UART callback registration in HAL1 and HAL2

HAL1

HAL2

UART_HandleTypeDef uart_handle;

void TxTransferCpltCallback(UART_HandleTypeDef *huart);
void RxTransferCpltCallback(UART_HandleTypeDef *huart,
                                   uint16_t Size);

void TransferErrorCallback(UART_HandleTypeDef *huart);

 /* Register Tx Complete Callback */
HAL_UART_RegisterCallback(&uart_handle,
                          HAL_UART_TX_COMPLETE_CB_ID,
                          TxTransferCpltCallback);

/* Register Rx Complete Callback */
HAL_UART_RegisterCallback(&uart_handle,
                           HAL_UART_RX_COMPLETE_CB_ID,
                           RxTransferCpltCallback);

/* Register Error Callback */
HAL_UART_RegisterCallback(&uart_handle,
                          HAL_UART_ERROR_CB_ID,
                          TransferErrorCallback);

/* UnRegister Tx Complete Callback */
HAL_UART_UnRegisterCallback(&uart_handle,
                          HAL_UART_TX_COMPLETE_CB_ID);
hal_uart_handle_t uart_handle;

void TxTransferCpltCallback(hal_uart_handle_t *huart);
void RxTransferCpltCallback(hal_uart_handle_t *huart,
                                   uint16_t size_byte,
                                   hal_uart_rx_event_types_t rx_event);
void TransferErrorCallback(hal_uart_handle_t *huart);

/* Register Tx Complete Callback */
HAL_UART_RegisterTxCpltCallback(&uart_handle,
                                TxTransferCpltCallback);


/* Register Rx Complete Callback */
HAL_UART_RegisterRxCpltCallback(&uart_handle,
                                RxTransferCpltCallback);


/* Register Error Callback */
HAL_UART_RegisterErrorCallback(&uart_handle,
                               TransferErrorCallback);


/* UnRegister Tx Complete Callback */
HAL_UART_RegisterTxCpltCallback(&uart_handle,
                                HAL_UART_TxCpltCallback);

TIM example

TIM callback registration in HAL1 and HAL2

HAL1

HAL2

hal_tim_handle_t tim_handle;

void UpdateCallback(hal_tim_handle_t *htim);
void InputCaptureCallback(hal_tim_handle_t *htim);


/* Register Update Callback */
HAL_TIM_RegisterCallback(&tim_handle,
                         HAL_TIM_PERIOD_ELAPSED_CB_ID,
                         UpdateCallback);

/* Register Input Capture Callback */
HAL_TIM_RegisterCallback(&tim_handle,
                         HAL_TIM_IC_CAPTURE_CB_ID,
                         InputCaptureCallback);

/* UnRegister Update Callback */
HAL_TIM_UnRegisterCallback(&tim_handle,
                           HAL_TIM_PERIOD_ELAPSED_CB_ID);
hal_tim_handle_t tim_handle;

void UpdateCallback(hal_tim_handle_t *htim);
void InputCaptureCallback(hal_tim_handle_t *htim,
                          hal_tim_channel_t channel);

/* Register Update Callback */
HAL_TIM_RegisterUpdateCallback(&tim_handle,
                               UpdateCallback);


/* Register Input Capture Callback */
HAL_TIM_RegisterInputCaptureCallback(&tim_handle,
                                     InputCaptureCallback);


/* UnRegister Update Callback */
HAL_TIM_RegisterUpdateCallback(&tim_handle,
                               HAL_TIM_UpdateCallback);