Hello, I’m facing a problem using the Colibri iMx7 serial bus. Everything is explained below. I hope it’s clear enough.
Modbus Issue
System configuration
### Kernel Version
4.9.220
git://git.toradex.com/linux-toradex.git
Colibri-iMX7_LXDE-Image_2.8b7.-20200610
### BSP Version
Kernel built out of the tree
Hardware
Colibir iMX7D 1GB V1.1B
Custom board
mcmon@pmm-300p-22-287 ~
$ sudo ./tdx-info.sh
Password:
Software summary
------------------------------------------------------------
Bootloader: U-Boot
Kernel version: 4.9.220 #1 SMP Thu Mar 21 14:40:00 CET 2024
Kernel command line: clk_ignore_unused root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait rauc.slot=A
Distro name: NAME=Mizar
Distro version: VERSION_ID=V4.1.1
Distro variant: -
Hostname: pmm-300p-22-287
------------------------------------------------------------
Hardware info
------------------------------------------------------------
HW model: MC-Monitoring PMM300 PLUS
Toradex version: 0039 V1.1B
Serial number: 14774805
Processor arch: armv7l
Libraries
-
gomodbus
-
libmodbus
Problem
We have 4 devices with Colibri connected to a modbus RTU network managed by 1 modbus master. The master read some random registers on each slave every 5 ms.
Suddenly after a certain amount of time, one the slave write some noise during 2 seconds then everything come back to normal.
Troubleshooting Attempts
First we analyzed deeply, to notice the library function calls. The noise packets was not correlated with the function calls. We assumed, the problem is not from our code written in go.
We rewrote a master and a slave in C with the libmodbus library. With one slave the problem didn’t happen. Once we connected additional slaves, it happened again.
Now we assume, we have to go deeper towards low-level functionning code.
Configuration
Configuration from the C code:
#ifdef __arm__
mb = modbus_new_rtu("/dev/ttymxc3", 19200, 'N', 8, 2);
#else
mb = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 2);
#endif
if (mb == NULL) {
fprintf(stderr, "modbus: modbus_new_rtu failed\n");
return -1;
}
Configuration from the device tree:
/* UART C */
&uart3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3>;
assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
fsl,dte-mode;
linux,rs485-enabled-at-boot-time;
rs485-rx-during-tx;
status = "okay";
};
Additional Context
Network topology
Master Node
#include <errno.h>
#include <modbus.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int return_code;
int i;
modbus_t *mb;
uint16_t tab_reg[32];
uint8_t tab_bits[32];
mb = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 2);
if (mb == NULL) {
fprintf(stderr, "modbus: modbus_new_rtu failed\n");
return -1;
}
return_code = modbus_set_slave(mb, 11);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_set_slave failed: %s\n",
modbus_strerror(errno));
return -1;
}
return_code = modbus_connect(mb);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_connect failed: %s\n",
modbus_strerror(errno));
return -1;
}
while (1) {
return_code = modbus_read_registers(mb, 0, 10, tab_reg);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_read_registers failed: %s\n",
modbus_strerror(errno));
continue;
}
for (i = 0; i < 10; i++) {
printf("%d\n", tab_reg[i]);
}
usleep(50000);
}
modbus_close(mb);
modbus_free(mb);
}
Slave Node
#include <errno.h>
#include <modbus.h>
#include <stdio.h>
#include <stdlib.h>
#define BITS_ADDRESS (0)
#define INPUT_BITS_ADDRESS (0)
#define REGISTERS_ADDRESS (0)
#define INPUT_REGISTERS_ADDRESS (0)
#define BITS_NUMBER (65536)
#define INPUT_BITS_NUMBER (65536)
#define REGISTERS_NUMBER (65536)
#define INPUT_REGISTERS_NUMBER (65536)
int running = 1;
void signal_handler(int sig_num) {
running = 0;
signal(sig_num, signal_handler);
}
int main(void) {
// Inspiration from:
// https://gist.github.com/JGrossholtz/d1d02a87d535d7772139
int return_code;
int i;
uint8_t *request;
modbus_t *mb;
modbus_mapping_t *mb_mapping;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
#ifdef __arm__
mb = modbus_new_rtu("/dev/ttymxc3", 19200, 'N', 8, 2);
#else
mb = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 2);
#endif
if (mb == NULL) {
fprintf(stderr, "modbus: modbus_new_rtu failed\n");
return -1;
}
return_code = modbus_set_debug(mb, FALSE);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_set_debug failed: %s\n",
modbus_strerror(errno));
return -1;
}
return_code = modbus_set_indication_timeout(mb, 1, 0);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_set_timeout failed: %s\n",
modbus_strerror(errno));
return -1;
}
request = malloc(MODBUS_RTU_MAX_ADU_LENGTH);
if(request == NULL) {
perror("modbus: request memory allocation failed");
return -1;
}
return_code = modbus_set_slave(mb, 11);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_set_slave failed: %s\n",
modbus_strerror(errno));
return -1;
}
return_code = modbus_connect(mb);
if (return_code == -1) {
fprintf(stderr, "modbus: modbus_connect failed: %s\n",
modbus_strerror(errno));
return -1;
}
mb_mapping = modbus_mapping_new(
BITS_ADDRESS + BITS_NUMBER, INPUT_BITS_ADDRESS + INPUT_BITS_NUMBER,
REGISTERS_ADDRESS + REGISTERS_NUMBER,
INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NUMBER);
if (mb_mapping == NULL) {
perror("cannot allocate mb_mapping");
return -1;
}
mb_mapping->tab_input_registers[0] = 4;
mb_mapping->tab_input_registers[1] = 42;
mb_mapping->tab_input_registers[2] = 421;
mb_mapping->tab_input_registers[3] = 342;
mb_mapping->tab_input_registers[4] = 412;
mb_mapping->tab_input_registers[5] = 429;
mb_mapping->tab_input_registers[6] = 842;
mb_mapping->tab_input_registers[7] = 8842;
while (running) {
return_code = modbus_receive(mb, request);
if (return_code == 0) {
printf("modbus: modbus_receive return_code=0 : %s\n",
modbus_strerror(errno));
continue;
} else if (return_code < 0) {
if (errno == ETIMEDOUT) {
fprintf(stderr, "modbus: debug: timeout, continue ...\n");
continue;
}
fprintf(stderr, "modbus: modbus_receive error: %s\n",
modbus_strerror(errno));
return -1;
}
// printf("Request received return_code=%d\n", return_code);
return_code = modbus_reply(mb, request, return_code, mb_mapping);
if (return_code < 0) {
fprintf(stderr, "modbus: modbus_reply error: %s\n",
modbus_strerror(errno));
return -1;
}
mb_mapping->tab_input_registers[0]++;
mb_mapping->tab_input_registers[1]--;
mb_mapping->tab_input_registers[2]++;
mb_mapping->tab_input_registers[3]--;
mb_mapping->tab_input_registers[4]++;
mb_mapping->tab_input_registers[5]--;
mb_mapping->tab_input_registers[6]++;
mb_mapping->tab_input_registers[7]--;
}
printf("closing server\n");
modbus_mapping_free(mb_mapping);
free(request);
modbus_close(mb);
modbus_free(mb);
}
Questions
Is this problem known at Toradex ?
Would a kernel upgrade solve this problem ?
Do you have any other suggestions ?