MODBUS RTU Communication Issue: No Response from AC Servo Drive (NUCLEO-F446RE)
Hello everyone,
I’m working on a project where I’m using a NUCLEO-F446RE board to control an AC servo drive via MODBUS RTU. I’m using a TTL to RS485 converter to handle the communication. The problem I’m facing is that I get no response from my servo drive when sending MODBUS RTU frames from the NUCLEO board.
I’ve already tried the same setup using an Arduino Mega, and everything works perfectly – I can communicate with the servo drive and control it without any issues. So, I believe the issue might be with my program or the way MODBUS RTU is being handled on the NUCLEO board.
Here’s the setup I'm using:
- Controller: NUCLEO-F446RE
- Converter: TTL to RS485 converter
- MODBUS Communication: USART1 (PA10 Rx, PA9 Tx, PA8 DE, PA7 RE)
- Servo Drive Baud Rate: 38400, no parity, 2 stop bits
I’ve attached my program below, and I’d appreciate it if anyone could help me identify where the issue might be.
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "stm32f4xx_hal.h"
#include "core_cm4.h" //ITM functions
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
// Define the GPIO port and pins for DE/RE control
#define DE_RE_GPIO_PORT GPIOA // Change to your actual port
#define DE_PIN GPIO_PIN_8 // Change to the actual pin used for DE
#define RE_PIN GPIO_PIN_7 // Change to the actual pin used for RE
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
uint8_t modbus_frames[][8] = {
{0x01, 0x06, 0x60, 0x02, 0x00, 0x40, 0x37, 0xFA},
{0x01, 0x06, 0x62, 0x00, 0x00, 0x01, 0x57, 0xB2},
{0x01, 0x06, 0x62, 0x01, 0x00, 0x03, 0x87, 0xB3},
{0x01, 0x06, 0x62, 0x02, 0x0D, 0x40, 0x32, 0xD2},
{0x01, 0x06, 0x62, 0x03, 0x02, 0x58, 0x66, 0xE8},
{0x01, 0x06, 0x62, 0x04, 0x00, 0x32, 0x56, 0x66},
{0x01, 0x06, 0x62, 0x05, 0x00, 0x32, 0x07, 0xA6},
{0x01, 0x06, 0x60, 0x02, 0x00, 0x10, 0x37, 0xC6}
};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
void MODBUS_Transmit(uint8_t *data, uint16_t size);
void Set_DE_RE_High(void);
void Set_DE_RE_Low(void);
int __io_putchar(int ch); //for SWV
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// Loop through and transmit each MODBUS frame
for (int i = 0; i < sizeof(modbus_frames) / sizeof(modbus_frames[0]); i++)
{
// Transmit MODBUS frame
MODBUS_Transmit(modbus_frames[i], 8);
// Delay for receiving response
HAL_Delay(2000);
// Here, you can write your code to read and print the response from the drive
// After transmitting, wait to receive and print received data
uint8_t rx_buffer[40]; // Buffer to hold incoming data
if (HAL_UART_Receive(&huart1, rx_buffer, sizeof(rx_buffer), 2000) == HAL_OK) // 2 second timeout
{
printf("Received: ");
for (int j = 0; j < sizeof(rx_buffer); j++)
{
printf("%02X ", rx_buffer[j]);
}
printf("\r\n");
}
else
{
printf("No response received.\r\n");
}
HAL_Delay(4000); // Delay before sending next frame
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
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 = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
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();
}
}
/**
* @brief USART1 Initialization Function (MODBUS)
* @PAram None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 38400;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_2;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @PAram None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 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 : USART_TX_Pin USART_RX_Pin */
GPIO_InitStruct.Pin = USART_TX_Pin|USART_RX_Pin;
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 4 */
// MODBUS Transmit function
void MODBUS_Transmit(uint8_t *data, uint16_t size)
{
Set_DE_RE_High(); // Enable transmission (DE=High, RE=High)
// Transmit data over UART
HAL_UART_Transmit(&huart1, data, size, HAL_MAX_DELAY);
Set_DE_RE_Low(); // Enable reception (DE=Low, RE=Low)
printf("Transmitted: ");
for (int i = 0; i < size; i++)
{
printf("%02X ", data[i]);
}
printf("\r\n");
}
// Set DE and RE high to enable transmission
void Set_DE_RE_High(void)
{
HAL_GPIO_WritePin(DE_RE_GPIO_PORT, DE_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(DE_RE_GPIO_PORT, RE_PIN, GPIO_PIN_SET);
}
// Set DE and RE low to enable reception
void Set_DE_RE_Low(void)
{
HAL_GPIO_WritePin(DE_RE_GPIO_PORT, DE_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(DE_RE_GPIO_PORT, RE_PIN, GPIO_PIN_RESET);
}
// Redirect printf to SWV (ITM)
int __io_putchar(int ch)
{
ITM_SendChar(ch); // Use ITM to send data via SWV
return ch;
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @PAram file: pointer to the source file name
* @PAram line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
}
#endif /* USE_FULL_ASSERT */
And i've attached a image of the output i'm receiiving.
Thank you!
