Neu: Die KI-Firewall überwacht die gesamte Plattform und erklärt jeden Vorfall in einfachen Worten. So funktioniert es

STM32 with a MAX3485 gets my own echo and loses the start of the Modbus reply

STM32 with a MAX3485 gets my own echo and loses the start of the Modbus reply

Gelöst 5 4

Fourteen years on the PLC side, first time doing Modbus RTU from a bare microcontroller, so the protocol is not the problem, the MCU side is.

Hardware: STM32F103 (Blue Pill), USART2, MAX3485, DE and /RE tied together on PA8. Reading a magnetic flow meter, 9600 8N1, slave 7, holding registers 0x0010 to 0x0013. Later an ESP32 next to it will send the values to Hermetry, but first I need clean reads.

On the scope my request looks correct and the meter answers, I can see its reply on A/B. What my code receives is wrong. Usually the first two or three bytes of the reply are missing. Sometimes I get my own request back in the buffer before the reply. Code, simplified:

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);    // DE on
HAL_UART_Transmit(&huart2, req, 8, 100);
HAL_Delay(5);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);  // DE off, RE on
HAL_UART_Receive(&huart2, rx, 9, 200);
♥ 0

Did you try swapping A and B?

Still waiting for the gateway to reconnect.
♥ 0

Maybe a baud rate mismatch between the two?

Measure twice, poll once.
♥ 0

Neither, the request decodes fine on the scope and the meter replies to it. It’s my side.

♥ 0

It’s the timing around DE, I had the exact same thing on a lab rig with an F103.

HAL_UART_Transmit returns when the last byte has gone into the data register, not when it has left the shift register. Then you wait 5 ms on top. At 9600 one byte is about 1 ms, and a fast meter starts answering within a few ms. While DE is high, /RE is high too, so the receiver is off and the first bytes of the reply are gone. And because HAL_UART_Receive is only called after that, anything that came in meanwhile is lost or sits half in the data register.

The echo comes from the other order: if the receive is already armed while you transmit and /RE is low for a moment, you read back your own request.

Drop DE the moment the transmit complete flag (TC) is set, and arm the receive right after:

__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, req, 8, 100);
while (!__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC)) {}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
__HAL_UART_FLUSH_DRREGISTER(&huart2);
HAL_UART_Receive(&huart2, rx, 9, 200);

Better still, use interrupt or DMA receive with the idle line interrupt, then a 3.5 character gap ends the frame and you don’t need to know the length in advance. The F103 has no hardware DE pin for RS-485, newer families do, which saves all of this.

Timestamps in UTC or it didn't happen.
Akzeptierte Lösung♥ 3

That was it. The HAL_Delay(5) was something I’d added while guessing, removing it and waiting on TC gives me all 9 bytes and the CRC checks out every time. No more echo either. Moving to idle line DMA next like Aoife suggested.

♥ 2
Ansicht von 6 Beiträgen – 1 bis 6 (von insgesamt 6)
  • Du musst angemeldet sein, um auf dieses Thema antworten zu können.

Mitdiskutieren

Melde dich an, um Fragen zu stellen und zu beantworten, hilfreiche Beiträge mit „Gefällt mir“ zu markieren und die Antwort zu kennzeichnen, die dein Problem gelöst hat. Jeder Beitrag bringt Punkte und Stufen.

Teilen