2026-03-13 6:27 AM - edited 2026-03-16 1:26 AM
#ifdef HWVR_AC_CG_NOV25
#include "lpuart.h"
#include "main.h"
UART_HandleTypeDef hlpuart1;
DMA_HandleTypeDef hdma_lpuart1_rx;
DMA_HandleTypeDef hdma_lpuart1_tx;
#define LPUART_RX_BUF_SIZE (uint8_t)1
static volatile uint8_t lpuart_rx_buffer[LPUART_RX_BUF_SIZE]; // Buffer for DMA reception
#define LPUART_TX_BUF_SIZE (uint8_t)64
static volatile uint8_t lpuart_tx_string[LPUART_TX_BUF_SIZE];
static uint8_t lpuart_tx_string_size = 0; // Size of the lpuart_tx_string buffer
#define LPUART_FLAG_RX_COMPLETE ((uint8_t)((uint8_t)1U<<(uint8_t)0U))
#define LPUART_FLAG_READY_TO_SEND ((uint8_t)((uint8_t)1U<<(uint8_t)1U))
#define LPUART_FLAG_TX_ONGOING ((uint8_t)((uint8_t)1U<<(uint8_t)2U))
static volatile uint8_t lpuart_flag = 0;
void_const_uint8_t_p_callback_t lpuart_fill_callback = NULL; // Callback for the loop function
void_void_callback_t lpuart_loop_callback = NULL; // Callback for the loop function
static volatile uint32_t last_timestamp = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == LPUART1)
{
// Handle reception complete
if(lpuart_fill_callback != NULL)
{
lpuart_fill_callback((uint8_t *)&(lpuart_rx_buffer[0])); // Call the fill callback with the received data
lpuart_flag |= LPUART_FLAG_RX_COMPLETE; // Set the flag to indicate UART RX complete
last_timestamp = HAL_GetTick(); // Update the timestamp of the last reception
}
}
}
void HAL_UARTEx_TxFifoEmptyCallback(UART_HandleTypeDef *huart)
{
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == LPUART1)
{
// Handle transmission complete
// You can perform additional actions here if needed
lpuart_flag &= ~LPUART_FLAG_TX_ONGOING; // Clear the flag to indicate UART TX complete
}
}
/**
* @brief LPUART1 Initialization Function
* None
* @retval None
*/
mid_error_t MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_TC);
if(HAL_UART_Receive_DMA(&hlpuart1,(uint8_t *)lpuart_rx_buffer, (uint8_t)LPUART_RX_BUF_SIZE) != HAL_OK)
{
return MID_ERROR_GENERAL;
}
// Start reception in DMA mode with a buffer of 256 bytes
/* USER CODE BEGIN LPUART1_Init 2 */
return MID_ERROR_OK;
/* USER CODE END LPUART1_Init 2 */
}
mid_error_t lpuart_dma_init()
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
__HAL_RCC_DMA1_CLK_ENABLE();
/* USER CODE BEGIN LPUART1_MspInit 0 */
/* USER CODE END LPUART1_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;
PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
return MID_ERROR_GENERAL ;
}
/* Peripheral clock enable */
__HAL_RCC_LPUART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**LPUART1 GPIO Configuration
PA2 ------> LPUART1_TX
PA3 ------> LPUART1_RX
*/
GPIO_InitStruct.Pin = serial_tx_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_LPUART1;
HAL_GPIO_Init(serial_tx_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = serial_rx_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_LPUART1;
HAL_GPIO_Init(serial_rx_GPIO_Port, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART1_RX Init */
hdma_lpuart1_rx.Instance = DMA1_Channel2;
hdma_lpuart1_rx.Init.Request = DMA_REQUEST_LPUART1_RX;
hdma_lpuart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_lpuart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_lpuart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_lpuart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_lpuart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_lpuart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_lpuart1_rx.Init.Priority = DMA_PRIORITY_LOW;
/* LPUART1_TX Init */
hdma_lpuart1_tx.Instance = DMA1_Channel3;
hdma_lpuart1_tx.Init.Request = DMA_REQUEST_LPUART1_TX;
hdma_lpuart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_lpuart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_lpuart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_lpuart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_lpuart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_lpuart1_tx.Init.Mode = DMA_NORMAL;
hdma_lpuart1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_lpuart1_rx) != HAL_OK)
{
return MID_ERROR_GENERAL ;
}
if (HAL_DMA_Init(&hdma_lpuart1_tx) != HAL_OK)
{
return MID_ERROR_GENERAL ;
}
__HAL_LINKDMA(&hlpuart1, hdmarx, hdma_lpuart1_rx);
__HAL_LINKDMA(&hlpuart1, hdmatx, hdma_lpuart1_tx);
/* USER CODE BEGIN LPUART1_MspInit 1 */
/* USER CODE END LPUART1_MspInit 1 */
return MID_ERROR_OK ;
}
mid_error_t lpuart_init(void_const_uint8_t_p_callback_t checking_reception_fill_callback_in, void_void_callback_t checking_reception_loop_callback_in)
{
lpuart_set_rx_callback(checking_reception_fill_callback_in);
lpuart_set_loop_callback(checking_reception_loop_callback_in);
if(lpuart_dma_init() != MID_ERROR_OK)
{
return MID_ERROR_GENERAL;
}
if(MX_LPUART1_UART_Init() != MID_ERROR_OK)
{
return MID_ERROR_GENERAL;
}
if(HAL_UART_Receive_DMA(&hlpuart1, (uint8_t *)lpuart_rx_buffer, LPUART_RX_BUF_SIZE) != HAL_OK)
{
return MID_ERROR_GENERAL;
}
return MID_ERROR_OK;
}
mid_error_t lpuart_loop()
{
if (lpuart_flag & LPUART_FLAG_RX_COMPLETE && (HAL_GetTick() - last_timestamp > 10))
{
lpuart_flag &= ~LPUART_FLAG_RX_COMPLETE; // Clear the UART RX complete flag
//uint8_t uart_tx_single_char[1] = {0xCC};
lpuart_loop_callback(); // Call the loop callback function if set
//HAL_UART_Transmit_DMA(&huart1, uart_tx_single_char, 1);
}
else if (lpuart_flag & LPUART_FLAG_READY_TO_SEND)
{
lpuart_flag &= ~LPUART_FLAG_READY_TO_SEND; // Clear the UART TX complete flag
if (lpuart_tx_string_size > 0)
{
// lpuart_tx_string[lpuart_tx_string_size] = '\0'; // Null-terminate the string
// if(HAL_UART_Transmit_DMA(&hlpuart1, (const uint8_t *) lpuart_tx_string, (uint8_t)lpuart_tx_string_size) != HAL_OK)
if(HAL_UART_Transmit_DMA(&hlpuart1, (const uint8_t *) lpuart_tx_string, (uint8_t)lpuart_tx_string_size) != HAL_OK)
{
lpuart_tx_string_size = 0; // Reset the size after sending
return MID_ERROR_GENERAL;
}
else
{
//lpuart_flag |= LPUART_FLAG_TX_ONGOING; // Set the flag to indicate UART TX ongoing
lpuart_tx_string_size = 0; // Reset the size after sending
}
}
else
{
// No data to send, handle as needed
}
}
return MID_ERROR_OK;
}
mid_error_t lpuart_send_data(const uint8_t* data_in, size_t size_in)
{
// This function is a placeholder for sending data over UART.
// Implement the actual data sending logic here.
// For example, you can use HAL_UART_Transmit() to send data.
memset((void *)lpuart_tx_string, 0, LPUART_TX_BUF_SIZE); // Clear the transmit buffer after sending
for (uint8_t i = 0; i < size_in; i++) {
if (i < LPUART_TX_BUF_SIZE)
{
lpuart_tx_string[i] = data_in[i]; // Copy data to the transmit buffer
}
else
{
break; // Prevent buffer overflow
}
}
//lpuart_tx_string[0] = 0x2;
lpuart_tx_string_size = size_in; // Set the size of the data to send
lpuart_flag |= LPUART_FLAG_READY_TO_SEND; // Set the flag to indicate UART RX complete
return MID_ERROR_OK;
}
void lpuart_set_rx_callback(void_const_uint8_t_p_callback_t callback_in)
{
if (callback_in == NULL)
{
// Handle the case where no callback is set, if needed
return;
}
lpuart_fill_callback = callback_in; // Set the fill callback function
}
void lpuart_set_tx_callback(void_void_callback_t callback_in)
{
// Not implemented yet
}
void lpuart_set_loop_callback(void_void_callback_t callback_in)
{
if (callback_in == NULL)
{
// Handle the case where no callback is set, if needed
return;
}
lpuart_loop_callback = callback_in; // Set the loop callback function
}
#endif // HWVR_AC_CG_NOV25
I used the dma with the usart1 and I didn't have any problem... but I wanted to change pinout and use the lpuart and now I am just able to use the HAL_UART_Transmit_DMA once.
PD: I think I solved this problem. But I have another question: the problem occurs because the pinout of the pcb changed so I decided to use the LPUART1 instead of the USART1. It is ok to use 2 different build configurations -or more- for 2 different hardware pinout?? Thank you all.
Solved! Go to Solution.
2026-03-16 1:20 AM
I think I solved. Correct me if I am wrong. The dma-driven lpuart requires the activatio or the enabling of 2 types of interruptions the dma interruption and the lpuart interruptions.
I didn't use these 2 functions.
// 1) Set priority (0 = highest, adjust for your system/RTOS)
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
// 2) Enable the interrupt in NVIC
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
I set them in the MX_LPUART1_UART_Init function.
/**
* @brief LPUART1 Initialization Function
* @PAram None
* @retval None
*/
mid_error_t MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
// 1) Set priority (0 = highest, adjust for your system/RTOS)
HAL_NVIC_SetPriority(LPUART1_IRQn, 3, 3);
// 2) Enable the interrupt in NVIC
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_TC);
if(HAL_UART_Receive_DMA(&hlpuart1,(uint8_t *)lpuart_rx_buffer, (uint8_t)LPUART_RX_BUF_SIZE) != HAL_OK)
{
return MID_ERROR_GENERAL;
}
// Start reception in DMA mode with a buffer of 256 bytes
/* USER CODE BEGIN LPUART1_Init 2 */
return MID_ERROR_OK;
/* USER CODE END LPUART1_Init 2 */
}
2026-03-13 10:53 AM
Check if both UART and DMA interrupts are enabled.
2026-03-13 11:26 AM - edited 2026-03-13 11:27 AM
The code provided doesn't call lpuart_loop at all. Hard to know what's going on.
Looks like AI has incorporated some weird flags instead of using the HAL handle state, some of them commented out. It's just a mess.
The CubeMX examples work, perhaps start from those.
2026-03-16 12:15 AM
I overload the tx callback but the tx callback is never called
2026-03-16 12:16 AM
lpuart_loop is called in a loop by another function outside this file.
2026-03-16 12:17 AM
I try to enable them but it is no use...
2026-03-16 12:27 AM
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == LPUART1)
{
// Handle transmission complete
// You can perform additional actions here if needed
lpuart_flag &= ~LPUART_FLAG_TX_ONGOING; // Clear the flag to indicate UART TX complete
}
}
This is a callback that I overloaded but it is never called despite the fact that I sent I guess one of the "request frames" ok.
2026-03-16 1:20 AM
I think I solved. Correct me if I am wrong. The dma-driven lpuart requires the activatio or the enabling of 2 types of interruptions the dma interruption and the lpuart interruptions.
I didn't use these 2 functions.
// 1) Set priority (0 = highest, adjust for your system/RTOS)
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
// 2) Enable the interrupt in NVIC
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
I set them in the MX_LPUART1_UART_Init function.
/**
* @brief LPUART1 Initialization Function
* @PAram None
* @retval None
*/
mid_error_t MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
// 1) Set priority (0 = highest, adjust for your system/RTOS)
HAL_NVIC_SetPriority(LPUART1_IRQn, 3, 3);
// 2) Enable the interrupt in NVIC
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_TC);
if(HAL_UART_Receive_DMA(&hlpuart1,(uint8_t *)lpuart_rx_buffer, (uint8_t)LPUART_RX_BUF_SIZE) != HAL_OK)
{
return MID_ERROR_GENERAL;
}
// Start reception in DMA mode with a buffer of 256 bytes
/* USER CODE BEGIN LPUART1_Init 2 */
return MID_ERROR_OK;
/* USER CODE END LPUART1_Init 2 */
}
2026-03-16 3:45 AM
Hello @carleslsregner
Did you solve your problem?
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
// 2) Enable the interrupt in NVIC
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
These lines should be automatically generated when you enable the NVIC settings in the .ioc file.
However, I have attached a project based on STM32G474 that performs continuous transmission with LPUART and DMA enabled.
Connect the LPUART_TX pin to the LPUART_RX pin and Open Txbuf and Rxbuf in Live Expression to view the demonstration.
You can use this project as a reference to resolve your issue.
BR
Gyessine
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2026-03-16 4:14 AM - edited 2026-03-16 4:16 AM
@carleslsregner wrote:PD: I think I solved this problem.
If it's solved, please mark the solution on the post which provided the answer (not this one!)
@carleslsregner wrote:I have another question:
Please start a new thread for a new question.
Please give a link here to the new thread, so that people can find it.
Your new thread, you could also give a link back to this one, if you think it helps...