Serial issue on Beaglebone Black running linux
2
votes
0
answers
49
views
For a project we are using Modbus which runs over a RS485 interface. Around 95% of the messages are correctly send by the client, after which the server responds correctly. However, once every few hundred messages the server does not respond, resulting in a timeout.
After digging deeper into why the server does not respond, it seems that the server either gets a wrong modbus id, which it should not respond to, or the CRC byte is incorrect. The RS485 signal was also shown on an osciloscope which showed that the server interpreted that data correctly, thus the client was sending the wrong data.
To see whether the client was indeed sending the data that is expected, some test code was written:
The second error which occurs is the opposite of the first error, where the id byte is not transmitted and the message seems to start with sending the function. Transmitting a complete random CRC byte.
In both cases libmodubs seems to try to transmit the right buffers. This is checked by intercepting the write call libmodbus uses to write to the uart peripheral in linux. This shows the correct bytes which should have been sent, but the signal on the scope seems to show that the buffer sent is not correctly written to the uart device.
How can I resolve this problem, or how I can debug this problem any further?
System specs:
Client: Beaglebone black industrial running linux
Server: STM32F103
#include
#include
#include
#include
#include "macrologger.h"
modbus_t *context = nullptr;
// Define the function pointer type for the original write function
typedef ssize_t (*write_t)(int, const void *, size_t);
// The wrapper for the write function
ssize_t write(int fd, const void *buf, size_t count) {
// Log data being written
printf("Intercepted write call: ");
for (size_t i = 0; i < count; i++) {
printf("{%02X}", ((unsigned char *)buf)[i]);
}
printf("\n");
// Use dlsym to get the original write function
write_t real_write = (write_t) dlsym(RTLD_NEXT, "write");
// Check for errors in dlsym
if (!real_write) {
fprintf(stderr, "Error: %s\n", dlerror());
return -1; // Return an error code if dlsym fails
}
// Call the original write function
return real_write(fd, buf, count);
}
uint32_t modbus_errors = 0;
uint8_t id = 0;
void setModbusSlaveId() {
// Set Modbus slave ID
if (modbus_set_slave(context, id++) < 0) {
LOG_ERROR("modbus set slave error: %s", modbus_strerror(errno));
}
}
void sendTest() {
uint16_t state;
for (uint32_t index = 0; index < 100; index++) {
printf("Sending message with slave ID: %d\n", modbus_get_slave(context));
setModbusSlaveId();
int reply = modbus_read_registers(context, 0x12, 1, &state);
if (reply == -1) {
modbus_errors++;
while (1);
}
}
}
int main() {
LOG_INFO("Starting libmodbus_test");
context = modbus_new_rtu("/dev/rs485-2", 115200, 'N', 8, 1);
if (context == nullptr) {
LOG_ERROR("Unable to create the libmodbus context");
return 0;
}
// Set response timeout
modbus_set_response_timeout(context, 2, 0);
if (modbus_rtu_set_rts(context, MODBUS_RTU_RTS_UP) < 0) {
LOG_ERROR("Unable to set modbus rtu rts mode");
return 0;
}
if (modbus_rtu_set_rts_delay(context, 200) < 0) {
LOG_ERROR("Unable to set modbus rtu rts delay");
return 0;
}
LOG_INFO("modbus rts: %i, current rts delay: %i us",
modbus_rtu_get_rts(context), modbus_rtu_get_rts_delay(context));
if (modbus_set_debug(context, false) < 0) {
LOG_ERROR("modbus set debug error");
return 0; // Not fatal, continue
}
if (modbus_connect(context) < 0) {
LOG_ERROR("modbus connect error");
return 0;
}
while (1) {
sendTest();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
This codes initializes the libmodbus library and opens the modbus connection on RS485-2 at 115200 baud. It sends bursts of a 100 messages every 100ms. The slave id is incremented every message to show where the error occurs, after which the program halts (while (1)). The server is setup to ignore the slave id, thus it responds to every message it receives.
The expected modbus command is: {id}{03}{00}{12}{01}{CRCH}{CRCL}
From this test 2 errors where noted after the program halted.
Firstly it seems that sometimes the slave id of the previous message first sent, after which the correct message follows. This however clips off the CRC byte causing an incorrect CRC error.




Asked by user3679572
(21 rep)
Feb 4, 2025, 11:37 AM
Last activity: Feb 4, 2025, 07:23 PM
Last activity: Feb 4, 2025, 07:23 PM