Issue with RS485 Communication and Impact of a Faulty IC on the Entire Bus - Page 1
Forum section: electronics / projects

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 07:19:35 am
content: Hello everyone,I’ve designed a board where the SHT30 sensor is connected to an STM32G0 microcontroller, and I can successfully read the temperature and humidity data. These data are sent to the HMI via the Modbus protocol and RS485 bus. The problem occurs when multiple devices are connected to the RS485 line.After a few hours, if there is a disruption in one of the ADM485 ICs, it affects the entire line. After measuring the voltage, I noticed that the RE and DE pins, which are connected to the microcontroller for enabling data transmission or reception, get stuck at 3.3V. This issue disrupts the entire line and causes the other devices to stop working as well. I find that by cutting off the power and reconnecting the devices, everything works fine again, but after a few hours, the problem reoccurs.here is part of my design for RS48

author: Salitronic
author_rank: Contributor
timestamp: September 28, 2024, 08:23:25 am
content: This doesn't seems to be a case of faulty RS485 IC, rather something in your firmware is causing the RE/DE pin to stay high. RE/DE on the RS485 transceiver are inputs, they cannot be stuck high themself.RS485 transceivers have a number of fail-safe features that result in high-impedance connection to the bus so as not to disrupt communication. However if the RE/DE are constantly high then you are holding the bus constantly driven and this prevents any other device from using the bus.You should look into the firmware to understand what is causing the RE/DE to stay high.Side note: You have an on-board 120ohm termination resistor, if you have more than 2 devices on the bus you cannot have the resistor mounted on all devices. There should only be 2 120ohm termination resistors, one at either extreme end of the bus. If you have many devices on the bus it might be that all of these parallel resistors are leading to an overload and from there causing your firmware to get stuck somehow.

author: Siwastaja
author_rank: Super Contributor
timestamp: September 28, 2024, 08:31:10 am
content: Yeah, your code is broken.

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 09:22:38 am
content: Thank you for your detailed response!I forgot to mention that I haven't mounted the 120-ohm resistor on the board; I only have the PSM712 installed for protection. Regarding the RE/DE pins, I've written firmware that should restart the microcontroller if no data is received on the RX pin for a certain period, but it doesn't seem to be working as expected.What do you think about using a watchdog timer reset in this case? Could it help with the issue, or is there something else I might be missing?Code:void TIM1_BRK_UP_TRG_COM_IRQHandler(void) {/* USER CODE BEGIN TIM1_BRK_UP_TRG_COM_IRQn 0 */myTime++;if (myTime > 10000) {if (rxReceive == 0) {myTime = 0;NVIC_SystemReset();}}/* USER CODE END TIM1_BRK_UP_TRG_COM_IRQn 0 */HAL_TIM_IRQHandler(&htim1);/* USER CODE BEGIN TIM1_BRK_UP_TRG_COM_IRQn 1 *//* USER CODE END TIM1_BRK_UP_TRG_COM_IRQn 1 */}

author: tooki
author_rank: Super Contributor
timestamp: September 28, 2024, 10:27:22 am
content: Well, I mean... if you just set up the watchdog timer and never clear it, then you'll just reset periodically no matter what.Can you run your MCU with the debugger going the entire time, so that when the error occurs, you can go in and inspect what's going on?

author: Siwastaja
author_rank: Super Contributor
timestamp: September 28, 2024, 10:45:14 am
content: Quote from: digitalectron on September 28, 2024, 09:22:38 amWait, you have designed a modbus slave; why would you restart the microcontoller if no data is received? This is a pretty normal condition, not every master polls all the time.In RS485 slave it is crucial to correctly read the incoming packet, check for matching slave_id and valid CRC and then,with correct timing, enable the transmitter, output the reply and then immediately (again see timing from modbus specification) disable the transmitter. Just try to follow sensible programming practices and your code should not just become stuck in that sending part.And just to be sure, you have assigned different slave_id's to different slaves yes?

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 11:44:53 am
content: Quote from: tooki on September 28, 2024, 10:27:22 amThank you for your suggestion! " tooki"It's quite difficult for me to debug the MCU continuously in this case. I have 4 devices on one bus, and I leave them powered on for an entire day and night. The issue usually happens while I’m away. For example, when I leave the office and come back the next day, I often find that the problem has occurred after 10 or more hours.Do you have any suggestions for troubleshooting in such a scenario where real-time debugging is challenging?

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 11:52:18 am
content: Quote from: Siwastaja on September 28, 2024, 10:45:14 amThank you for the feedback!Just to clarify, the HMI broadcasts to the entire RS485 bus using the Modbus protocol. I've implemented a timer in the code that will restart the MCU after 10 seconds if no data is received. Under normal conditions, the MCU receives data from the HMI approximately every second to respond with temperature and humidity readings, and everything works fine until an issue arises—at which point the system gets stuck, and I'm not sure what causes it.Do you have any thoughts on what might be going wrong in this scenario?

author: Siwastaja
author_rank: Super Contributor
timestamp: September 28, 2024, 11:55:38 am
content: Quote from: digitalectron on September 28, 2024, 11:52:18 amWell here's your problem. Modbus broadcasts cannot be responded to. The master needs to individually poll the nodes (unicast).See Modbus specificationhttps://www.modbus.org/docs/Modbus_over_serial_line_V1_02.pdfpage 7

author: tooki
author_rank: Super Contributor
timestamp: September 28, 2024, 12:07:17 pm
content: Some avenues to investigate:- Does the problem occur when asingleMCU is on the bus with the HMI?-->Is this an issue that only occurs as a result of interactions between multiple slave devices, or is it the result of interaction between master and slave?- Does the problem occur if an MCU is not connected to the bus at all? (Monitor the TX_EN line and see if it goes high even with no communication at all.)-->Is this an issue that only occurs as a result of interactions between master and slave devices, or is it completely self-contained?- Can you perform accelerated testing by having the messages from the HMI come at a much higher rate?-->Is this an overflow, for example a counter that never gets reset and eventually increments to an illegal value, like a signed integer circling around to a negative number.Right now the HMI sends messages about every second. What if you generate those at, say 50 per second. Then you'd expose such an overflow in a few minutes instead of many hours.

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 12:31:38 pm
content: Quote from: Siwastaja on September 28, 2024, 11:55:38 amThank you for pointing that out! I read the PDF thoroughly and reviewed my Modbus code again to ensure proper communication between the HMI and the MCU.

author: Salitronic
author_rank: Contributor
timestamp: September 28, 2024, 12:35:48 pm
content: Can you share more of your code, the part handing the TX/RX?How are you handling the RE/DE: manual GPIO toggle or using the RS485 hardware flow control feature of the STM32?

author: digitalectron
author_rank: Contributor
timestamp: September 28, 2024, 12:36:50 pm
content: Quote from: tooki on September 28, 2024, 12:07:17 pmI want to let you know that I will check your suggestions and try them out. I’ll share my experiments here once I have some results.

author: digitalectron
author_rank: Contributor
timestamp: September 29, 2024, 05:24:01 am
content: Quote from: Salitronic on September 28, 2024, 12:35:48 pmCode:void vTask_Modbus(void *pvParameters) {for (;;) {/******************************************************* ModBUS******************************************************/if (rxReceive) {rxReceive = 0;HAL_UART_DMAStop(&huart1);HAL_UART_Receive_DMA(&huart1, (uint8_t*) RxData, ModbusSizeReceive); // Enable MODBUSif (RxData == SLAVE_ID) {switch (RxData) {case 0x3:readHoldingRegs();case 0x06:writeSingleReg();default:modbusException(ILLEGAL_FUNCTION);break;}}}vTaskDelay(500);}}...void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {rxReceive = 1;myTime = 0;HAL_UART_DMAStop(&huart1);HAL_UART_Receive_DMA(&huart1, (uint8_t*) RxData, ModbusSizeReceive); // Enable MODBUS}...uint8_t readHoldingRegs (void){uint16_t startAddr = ((RxData<<8)|RxData); // start Register AddressstartAddr = startAddr - 200;//start of register in HMI is 200uint16_t numRegs = ((RxData<<8)|RxData); // number to registers master has requestedif ((numRegs<1)||(numRegs>125)) // maximum no. of Registers as per the PDF{modbusException (ILLEGAL_DATA_VALUE); // send an exceptionreturn 0;}uint16_t endAddr = startAddr+numRegs-1; // end Registerif (endAddr>49) // end Register can not be more than 49 as we only have record of 50 Registers in total{modbusException(ILLEGAL_DATA_ADDRESS); // send an exceptionreturn 0;}TxData = SLAVE_ID; // slave IDTxData = RxData; // function codeTxData = numRegs*2; // Byte countint indx = 3;for (int i=0; i<numRegs; i++) // Load the actual data into TxData buffer{TxData[indx++] = (Holding_Registers_Database>>8)&0xFF; // extract the higher byteTxData[indx++] = (Holding_Registers_Database)&0xFF; // extract the lower byte//TxData[indx++] = (myTemp>>8)&0xFF; // extract the higher byte//TxData[indx++] = (myTemp)&0xFF; // extract the lower bytestartAddr++; // increment the register address}sendData(TxData, indx);return 1;}...void sendData (uint8_t *data, int size){uint16_t crc = crc16(data, size);data = crc&0xFF; // CRC LOWdata[size+1] = (crc>>8)&0xFF; // CRC HIGHHAL_GPIO_WritePin(TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_SET);// RE-DEHAL_UART_Transmit(&huart1, data, size+2, 1000);HAL_Delay(1);HAL_GPIO_WritePin(TX_EN_GPIO_Port,TX_EN_Pin , GPIO_PIN_RESET);// // RE-DE}I use GPIO for handling the RE/DE and usethese in both the Rx callback and the task to perform certain DMA work. It worked for me for hours or moreCode:HAL_UART_DMAStop(&huart1);HAL_UART_Receive_DMA(&huart1, (uint8_t*) RxData, ModbusSizeReceive); // Enable MODBUS

author: Doctorandus_P
author_rank: Super Contributor
timestamp: September 29, 2024, 07:55:32 am
content: I think you made an error. You used a wire instead of labels to connect pins 2 and 3 of the IC on your schematic.

author: Siwastaja
author_rank: Super Contributor
timestamp: September 29, 2024, 08:36:14 am
content: Quote from: Doctorandus_P on September 29, 2024, 07:55:32 amNothing wrong in that, this most usual RS485 transceiver pinout uses opposite polarity driver enable and receiver enable signals purposely so they can be tied together to create a simpler 1-bit "direction" signal. Doing that you lose {inactive, inactive} combination which might be lower power (or useful if you want to multiplex many transceivers to single MCU UART peripheral, an idea applicable to modbus masters but not slaves), and {active, active} combination which would allow you to "listen back" what you send detecting some error conditions like bus short circuit, but these features are often not necessary.

author: PGPG
author_rank: Frequent Contributor
timestamp: September 29, 2024, 11:22:41 am
content: Quote from: Doctorandus_P on September 29, 2024, 07:55:32 amQuote from: Siwastaja on September 29, 2024, 08:36:14 amDoctorandus_P didn't questioned the connection itself but lack of consistency in drawing the schematic.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: September 29, 2024, 02:11:35 pm
content: Quote from: PGPG on September 29, 2024, 11:22:41 amIndeed. A single 8 pin IC and it has 6 dislocated sections connected with labels.It's almost surprising he managed to connect a LED and a resistor without using labels.

author: Salitronic
author_rank: Contributor
timestamp: September 29, 2024, 07:19:53 pm
content: Quote from: digitalectron on September 29, 2024, 05:24:01 amThe switch cases for 0x3 and 0x06 lack break statements. This results in fall-through, meaning that after executing readHoldingRegs(), the code continues to execute writeSingleReg() and then modbusException(ILLEGAL_FUNCTION). This might be causing unintended behavior.It's not clear what size you are declaring TxData, check that you do not have a buffer overrun in readHoldingRegs() or sendData()It is possible that an exception is being raised in HAL_UART_Transmit, if you are using cubeMX the default Hard/Mem fault ISRs are an infinite loop. That would leave the RE/DE high.

author: Siwastaja
author_rank: Super Contributor
timestamp: September 30, 2024, 06:40:21 am
content: Yeah, for a project like this write some kind ofCode:void error(int errcode){_disable_irq();GPIOx->MODER = // set the critical control pin as outputGPIOx->BSRR = // write the critical control pin to safe state (in this case, listen mode, transmitter disabled)while(1){// blink errcode counts on a LED.}}Then make sure every interrupt handler (including hardfault, busfault, your default handler for unhandler ISRs, etc.) calls this function. Especially important for unmaskable highest-priority interrupts like hardfault. Then configure a watchdog which gives you highest possible priority interrupt (that would be next to hardfault) and call error() there, too. Now it should be impossible for any infinite loop to ever cause stuck driver.Then, use different error codes from different call sites so that when things get stuck, you can look at the blinking LED and immediately rule out many wrong leads.

author: digitalectron
author_rank: Contributor
timestamp: October 01, 2024, 06:07:04 am
content: Quote from: Doctorandus_P on September 29, 2024, 02:11:35 pmThis is part of my Schematic, LED label connected to rest of circuit

author: digitalectron
author_rank: Contributor
timestamp: October 01, 2024, 06:17:16 am
content: Quote from: Salitronic on September 29, 2024, 07:19:53 pmI had actually added the missing break statements for 0x03 and 0x06 earlier but forgot to mention it. However, I’ll double-check to make sure everything is functioning as expected and that no fall-through is occurring.I’ll also verify the size of TxData to ensure there’s no buffer overrun in readHoldingRegs() or sendData().

author: digitalectron
author_rank: Contributor
timestamp: October 01, 2024, 06:23:17 am
content: Quote from: Siwastaja on September 30, 2024, 06:40:21 amThank you for the suggestions!I’ll make sure that all interrupt handlers, including hardfault,and ..... , call the error-handling function as you mentioned.Using different error codes from various call sites to debug with the blinking LED is a great idea. That will definitely help in pinpointing the issue more effectively.I appreciate your insights—this will help me a lot!