cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Nucleo-64 G070RB Board USART1 Modbus RTU Master without RTOS and UART Interrupts

arunachalamram
Associate II

I am trying to configure STM32 Nucleo-64 G070RB Board as Modbus RTU Master to send commands to a slave and receive response. I have connected MAX485 - TTL to RS485 board. Powered with 5V, DE and RE connected to USART1 DE Pin. Board's A and B are connected to slave (VFD) at a distance of less than 2 meters.

I am able to send commands and slave works fine. The response from salve received is not echo of the command as expected. UART reports Parity error and Noise error :1h and 2h => 3h.

When the slave was connected to PC and same commands were sent using QModBus, slave works the same way (as expected) and response received is correct (echo of the command).

UART1 configuration:

 
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_9B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_EVEN;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_RS485Ex_Init(&huart1, UART_DE_POLARITY_HIGH, 0, 0) != HAL_OK)

This is the send receive function and code:

void send_modbus_write_register(UART_HandleTypeDef *huart, uint16_t reg_addr,
uint16_t reg_value, const char* cmd_name)
{
  uint8_t request[8], response[8];
  int uart_receive_error = HAL_ERROR;

  // Build Modbus frame

...


  // TX PHASE
  HAL_StatusTypeDef tx_status = HAL_UART_Transmit(huart, request, 8, 100);
  if (tx_status != HAL_OK) {
    printf("%s: UART Transmit Error[%d]\r\n", cmd_name, tx_status);
  }

  // RX PHASE
  // RX PHASE - HAL manages DE automatically. You still need a small delay
  // for the VFD *processing time* (Modbus turnaround delay).
  // Add VFD *processing time* delay only (no pin switching delay needed)
  HAL_Delay(50); // Increased delay to 100ms for safety

  uart_receive_error = HAL_UART_Receive(huart, response, 8, 200);

  // Debug print
  printf("%s Request: ", cmd_name);
  printHexArray(request, 8);
  printf("%s Response: ", cmd_name);
  printHexArray(response, 8);

  if (uart_receive_error != HAL_OK) {
    printf("%s: UART Receive Error[%d]\r\n", cmd_name, uart_receive_error);

...
  }

This is the debug message:

Setting 40.00 Hertz
SET SPEED Request: Hex values to / from VFD: 0x01 0x06 0x20 0x01 0x0F 0xA0 0xD6 0x42
SET SPEED Response: Hex values to / from VFD: 0x1C 0x00 0x00 0x20 0x0A 0x00 0x00 0x00
SET SPEED: UART Receive Error[3]
Sending START signal
START Request: Hex values to / from VFD: 0x01 0x06 0x20 0x00 0x00 0x01 0x43 0xCA
START Response: Hex values to / from VFD: 0xF1 0x4F 0x00 0x08 0x68 0x02 0x00 0x20
START: UART Receive Error[3]
Sending STOP signal
STOP Request: Hex values to / from VFD: 0x01 0x06 0x20 0x00 0x00 0x05 0x42 0x09
STOP Response: Hex values to / from VFD: 0xF1 0x4F 0x00 0x08 0x68 0x02 0x00 0x20
STOP: UART Receive Error[3]

------------------------------------

I do not want to use manual DE / RE controlling / RTOS and Interrupt handling of UART Tx / Rx to make it simple.

Data sent by STM32 are received by slave but STM32 does not receive data sent by slave.

Any pointers?


Edited to apply source code formatting - please see How to insert source code for future reference.

13 REPLIES 13
arunachalamram
Associate II

>>Perhaps your management of the DE/RE pin states is not correct.

arunachalamram_0-1764661685908.png

 

My understanding of USART1 Hardware Flow Control (RS485) is DE (PA12) is SET during transmission and RESET once transmission is completed by MCU. RE tied DE shall give half-duplex channel using MAX485 based TTL to RS485 board connected to USART1 pins, DE & RE to PA12, 5V and GND. Data transmitted is received by slave. Shall see DE and RE values mapped to transmission signals and keep you posted. Thank you.

I would check this in relation to the observed error interrupts.
Those should not happen, normally.


I would instrument the code, especially the UART error interrupt. E.g. by toggling a GPIO used as a trigger for the scope / logic analyser.
This would have to be a post-trigger kind, i.e. the scope / logic analyser should stop recording, so that you see the last few characters (Rx), and DE / RE transitions before the error.
I suppose you are aware there are possible signal/noise issues you cannot see with a logic analyser.

FirstCommandFrame.pngSecondCommandFrame.pngThirdCommandFrame.png

These are captured with Logic Analyzer:

Channel 0: Tx from MCU (bytes are good)

Channel 1: Rx from VFD (No signal at all and hence there is no image for this)

Channel 2: DE (PA12) from MCU (SET during MCU UART transmitting and then RESET)

Somehow VFD does not work now - perhaps I lost / rearranged some lines of code or delay. Need to look at backup code, merge and test.

These are only to show DE (PA12) toggled by hardware (SET during transmit) so that half-duplex mode shall be effective with MAX485. Shall keep you posted after getting code to previous state / condition  (i.e., VFD working).

There is 120 Ohm resistor on MAX485 - TTL to RS485 board and I connected 100 Ohm resistor at VFD end.

arunachalamram_0-1764857260702.jpeg

 

STM32_ModbusMaster.png

It works fine now. D0 is data sent by STM32 (Modbus RTU Master) and D1 is reply data from VFD and D2 is DE. Rewired and cleaned by merging with previous working code. Issue was probably with

1. Wiring of Rx signal from STM32 to MAX485 (TTL to RS485 board) and / or to VFD.

2. Delay

Updated code to send and Modbus RTU frame is:

tx_status = HAL_UART_Transmit(huart, request, 8, 100);
while (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC) == RESET);

rx_status = HAL_UART_Receive(huart, response, 8, 200);

Thank you all for the inputs. Issue can be closed.