Nouveau : le pare-feu IA surveille toute la plateforme et explique chaque incident en termes simples. Découvrez comment ça marche

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

Résolu 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.
Solution acceptée♥ 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
6 sujets de 1 à 6 (sur un total de 6)
  • Vous devez être connecté pour répondre à ce sujet.

Rejoignez la discussion

Connectez-vous pour poser et répondre à des questions, aimer les messages utiles et marquer la réponse qui a résolu votre problème. Chaque contribution rapporte des points et des niveaux.

Partager