2025-09-27 9:07 AM
Hello ST,
I have been working on trying to get the FreeMODBUS library working on the NUCLEO-F446RE development board.
The FreeMODBUS library can be found here,
https://github.com/cwalter-at/freemodbus
I am having trouble getting the USART port working correctly,
So far I am able send packets to the microcontroller and get interrupt calls to the USART2_IRQHandler();
However calling HAL_USART_Receive_IT(&uart_mb, (uint8_t *)byte, 1) only returns zeros in byte.
BOOL xMBPortSerialGetByte(CHAR *byte)
{
//*byte = MB_USART->RDR;
HAL_USART_Receive_IT(&uart_mb, (uint8_t *)byte, 1);
//HAL_UART_StateTypeDef state = HAL_UART_GetState(&uart_mb);
//*byte = MB_USART->DR;
return TRUE;
}
I am configuring the USART port in the following manner,
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity, UCHAR stopBit)
{
HAL_Delay(10);
// Enable UART peripheral clock
MB_USART_CLK_ENABLE();
HAL_Delay(10);
// Enable GPIO clocks
MB_TX_GPIO_CLK_ENABLE();
MB_RX_GPIO_CLK_ENABLE();
HAL_Delay(10);
__HAL_UART_ENABLE_IT(&uart_mb, UART_IT_RXNE);
__HAL_UART_ENABLE_IT(&uart_mb, UART_IT_TC);
// Configure NVIC for UART interrupt
HAL_NVIC_SetPriority(MB_USART_IRQn, MB_USART_IRQ_priority, MB_USART_IRQ_subpriority);
//HAL_NVIC_DisableIRQ(MB_USART_IRQn);
// Configure UART for Modbus communication
uart_mb.Instance = MB_USART;
uart_mb.Init.BaudRate = ulBaudRate;
uart_mb.Init.StopBits = UART_STOPBITS_1; // Always use 1 stop bit
uart_mb.Init.Mode = UART_MODE_TX_RX;
uart_mb.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uart_mb.Init.OverSampling = UART_OVERSAMPLING_16;
// Configure WordLength and Parity based on data bits and parity
if( ucDataBits == 8 )
{
if( eParity == MB_PAR_NONE )
{
uart_mb.Init.WordLength = UART_WORDLENGTH_8B;
uart_mb.Init.Parity = UART_PARITY_NONE;
}
else
{
uart_mb.Init.WordLength = UART_WORDLENGTH_9B; // 8 data bits + parity
uart_mb.Init.Parity = (eParity == MB_PAR_ODD) ? UART_PARITY_ODD : UART_PARITY_EVEN;
}
}
else if( ucDataBits == 7 )
{
if( eParity == MB_PAR_NONE )
{
uart_mb.Init.WordLength = UART_WORDLENGTH_8B;
uart_mb.Init.Parity = UART_PARITY_NONE;
}
else
{
uart_mb.Init.WordLength = UART_WORDLENGTH_8B; // 7 data bits + parity
uart_mb.Init.Parity = (eParity == MB_PAR_ODD) ? UART_PARITY_ODD : UART_PARITY_EVEN;
}
}
else
{
return FALSE; // Unsupported data bits configuration
}
if( HAL_UART_Init( &uart_mb ) != HAL_OK )
{
return FALSE; // UART initialization failed
}
//Critical Delay Flush Everything
//Let hardware settle.
HAL_Delay(10);
//Read and discard any garbage data
while(__HAL_UART_GET_FLAG(&uart_mb, UART_FLAG_RXNE))
{
uint8_t dummy = (uint8_t)uart_mb.Instance->DR;
(void)dummy;
}
//Clear ALL possible flags
__HAL_UART_CLEAR_PEFLAG(&uart_mb);
__HAL_UART_CLEAR_FEFLAG(&uart_mb);
__HAL_UART_CLEAR_NEFLAG(&uart_mb);
__HAL_UART_CLEAR_OREFLAG(&uart_mb);
HAL_Delay(10);
for (;;)
{
HAL_USART_Transmit_IT(&uart_mb, (uint8_t *)"hi", 2);
HAL_Delay(10);
}
// Disable RX and TX interrupts initially
//__HAL_UART_DISABLE_IT(&uart_mb, UART_IT_RXNE);
//__HAL_UART_DISABLE_IT(&uart_mb, UART_IT_TXE);
//HAL_NVIC_EnableIRQ(MB_USART_IRQn);
return TRUE;
}
I have found that uncommenting,
HAL_NVIC_DisableIRQ(MB_USART_IRQn);
//and
HAL_NVIC_EnableIRQ(MB_USART_IRQn);
Will prevent the HAL_Delay(10) function from working properly.
main() initializes HAL, configures the system clock, pin multiplexing, and timer 7.
int main(void)
{
//Vars
eMBErrorCode eStatus;
//0. Initialize HAL
HAL_Init();
//1. System Clock Config
SystemClock_Config();
//2. GPIO Config
MX_GPIO_Init();
HAL_Delay(10);
MX_TIM7_Init();
HAL_Delay(10);
//3. MODBUS
//a. Initialize
eStatus = eMBInit(MB_RTU, 0x0A, 0, 38400, MB_PAR_NONE, 1);
usRegInputBuf[0] = 0; /* Initialize counter */
usRegInputBuf[1] = 0;
usRegInputBuf[2] = 0;
usRegInputBuf[3] = 0;
//b. Enable the protocol stack.
eStatus = eMBEnable();
//c. Handle Errors
if( eStatus != MB_ENOERR )
{
Error_Handler();
}
/* Loop forever */
for(;;)
{
(void)eMBPoll();
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 84;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM7_Init(void)
{
/* USER CODE BEGIN TIM7_Init 0 */
/* USER CODE END TIM7_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM7_Init 1 */
/* USER CODE END TIM7_Init 1 */
htim7.Instance = TIM7;
htim7.Init.Prescaler = 0;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 65535;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM7_Init 2 */
/* USER CODE END TIM7_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PA2 PA3 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
I have tried adding,
for (;;)
{
HAL_USART_Transmit_IT(&uart_mb, (uint8_t *)"hi", 2);
HAL_Delay(10);
}
to BOOL xMBPortSerialInit(), but this has really strange behavior.
The SysTick interrupt will stop being called and execution will hang.
Does anyone have any suggestions on how to get the USART port working reliably?
The complete project is attached.
Thanks,
Allan