libmodbus icon indicating copy to clipboard operation
libmodbus copied to clipboard

Cannot set rs485 mode : ubuntu on phoenix industrial pc with hardware rs485

Open yarula opened this issue 7 years ago • 13 comments

I have an industrial Phoenix PC by hand with rs485 hardware support. Enable this mod in bios for ttyS1. This PC wired to kwh meter by appropriate cable.

Before I was successfull in reading data from the meter using rs485 to rs232 converter wihtout setting rs485 mode on by libmodbus call.

Now I want to drop converter and use native rs485 .


...

modbus_t *ctx;
ctx = modbus_new_rtu(_device_path.c_str(), _bod, _parity[0], _data_bit, _stop_bit);
if (ctx == NULL) {
        modbus_free(ctx);
          throw runtime_error("Unable to create the libmodbus context");
}

modbus_set_slave(ctx, 1);
if (modbus_connect(ctx) == -1) {
        string msg("Connection failed: "); msg += modbus_strerror(errno);
        modbus_free(ctx);
        throw runtime_error(msg);
}

if (modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) < 0 ) {
          int mode = modbus_rtu_get_serial_mode(ctx);
          modbus_free(ctx);
          string msg("Cannot set rs485 mode "); msg += modbus_strerror(errno);
          throw runtime_error(msg);
}
...

so I see

Cannot set rs485 mode Inappropriate ioctl for device

Need your advice :(

yarula avatar Jan 15 '18 13:01 yarula

if to call

modbus_rtu_get_serial_mode it returns MODBUS_RTU_RS232

Does it mean I should do something with driver ?

yarula avatar Jan 15 '18 13:01 yarula

the serial mode setting is for drivers that support switching from userspace.

If you have a bios setting that just turns it on automatically, there's nothing you need to do in your application, it's transparent. Just don't try and set the mode.

karlp avatar Jan 15 '18 13:01 karlp

Thanks for quick reply! It clears much.

After removing setting the mode code I get "connection timeout"

I'l try to dig it...

yarula avatar Jan 15 '18 13:01 yarula

I recently modified the driver for the Raspberry PI 3 to drive the RTS line for RS-485 support. If the driver for the UART on your PC doesn't support that, it's likely not too difficult to add. Fundamentally, the function is the same. When you transmit you drive the RTS line to the appropriate state, and when the transmitter buffer is empty, you flip it back. There's a handful of drivers that already support this, and you could use them for reference.

--jc

Save a life; adopt a shelter animal.

On Mon, Jan 15, 2018 at 8:54 AM, Alexander [email protected] wrote:

Thanks for quick reply! It clears much.

After removing setting the mode code I get "connection timeout" or "too many data" errors

I'l thy to dig it...

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/stephane/libmodbus/issues/418#issuecomment-357689100, or mute the thread https://github.com/notifications/unsubscribe-auth/AAgUqqhZcDWqNggriUI-6vMr7vdT38cfks5tK1iXgaJpZM4ReZSv .

jcwren avatar Jan 15 '18 15:01 jcwren

Where I could get this driver to test?

yarula avatar Jan 15 '18 15:01 yarula

now I'm struggling with ERROR Connection timed out: select

yarula avatar Jan 15 '18 15:01 yarula

If you have a bios setting that just turns it on automatically, there's nothing you need to do in your >application, it's transparent. Just don't try and set the mode.

But I checked this one: I called get_rtu_serial_mode and received MODBUS_RTU_RS232 despite the fact that in bios rs485 is enabled

yarula avatar Jan 15 '18 17:01 yarula

As it was already pointed out, this seems to be expected behaviour: from the point of view of your operating system, the port is still a simple UART. It does not see whether there is a RS232 or RS485 physical line driver chip enabled by the BIOS before the signal is routed to the plug. So your kernel still assumes this is RS232 and this is correct so. BTW: there should be some documentation whether you need RTS for driver enable, or whether this is also transparent.

If you run into timeout, then double-check that there is really some physical output at the port, e.g. using a second PC and your existing RS232->RS485 converter. Use HTerm or similar as terminal program to see whats going on...

mhei avatar Jan 16 '18 19:01 mhei

I have 2-wire rs485. First I double-checked the wire... The pin schema was suspected : 5-pin: gnd ( ok ) 2-pin: A (?) 3-pin: B (ok) I suppose correct schema is :

5-pin: gnd ( ok ) 7-pin: A (ok) 3-pin: B (ok)

I wired it, then connect PC and slave device, then sun the interceptty sinffer an my code.

Still the same: connection time out, and interceptty show outgoing ( from PC ) bytes (read_register_request) and no incoming .

http://opengear.com/images/sd4001-pinout.png

Another problem is that I found several different "2wire 485 to db9" wiring schemas.. the example above the only one of them )

Also I performed the loopback test

interceptty -s 'ispeed 19200 ospeed 19200' /dev/ttyS1 /dev/ttyDOOMY | interceptty-nicedump < 01 03 5b 15 00 02 c6 eb | [

01 03 5b 15 00 02 c6 eb |

We see the command immediately returned back.

yarula avatar Jan 17 '18 09:01 yarula

update: I ringed serial pc pins and found that 5,2,3-schema corrsponds to current pins voltage. So it's strange anough but it is ok. So the question is the same , why I'm not still able to receive data from the slave.

yarula avatar Jan 17 '18 11:01 yarula

Hello, I have the same problem. I'm using ITX-M51-D826 with built in RS485. I have enabled RS485 with a DIP-switch. I am connecting it with another PC using USB converter. On another PC I'm using modbus slave server, on ITX this code:

int main(void) {
	modbus_t *ctx;
	uint16_t tab_reg[64];
	int rc;
	int i;
	ctx = modbus_new_rtu("/dev/ttyS4", 38400, 'N', 8, 1);
	if (ctx == NULL) {
	    fprintf(stderr, "Unable to create the libmodbus context\n");
	    return -1;
	}
	modbus_set_slave(ctx, 99);
//	modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
//	modbus_set_response_timeout(ctx, 3, 200000);
//	modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
//	modbus_rtu_set_rts_delay(ctx, 1000);
	modbus_set_debug(ctx, TRUE);
    	modbus_set_error_recovery(ctx,
                              MODBUS_ERROR_RECOVERY_LINK |
                              MODBUS_ERROR_RECOVERY_PROTOCOL);

	if (modbus_connect(ctx) == -1) {
	    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
	    modbus_free(ctx);
	    return -1;
	}
	rc = modbus_read_registers(ctx, 1, 1, tab_reg);
	if (rc == -1) {
	    fprintf(stderr, "%s\n", modbus_strerror(errno));
	    return -1;
	}
	for (i=0; i < rc; i++) {
	    printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
	}
	modbus_close(ctx);
	modbus_free(ctx);
}

Output of the programm:

Opening /dev/ttyS4 at 38400 bauds (N, 8, 1) [63][03][00][01][00][01][DD][88] Waiting for a confirmation... ERROR Connection timed out: select Bytes flushed (0) Connection timed out

But in communication console on my PC i'm geting:

RX: 63 03 00 01 00 01 DD 88 TX: 63 03 02 00 01 80 4C

It means PC gets request and generate response, but ITX did't receive data from the slave. Is this a common problem?

AAG-ch avatar Jan 17 '18 12:01 AAG-ch

little update: I prepared windows IoT as dual boot on a problem device. Runned the same test program and received register data from the 1st try.

Returned back to linux ( I reinstalled it for pure experiment ) - no answer.

My conclusion is that: I have a problem with serial driver in linux. ubuntu 16.04, kernel 4.4.0-87

Nuvoton communications port is a device manufacturer.

So, I'm gonna dig driver question...

Any advice?

yarula avatar Jan 24 '18 18:01 yarula

Hello, I have the same problem. I'm using ITX-M51-D826 with built in RS485. I have enabled RS485 with a DIP-switch. I am connecting it with another PC using USB converter. On another PC I'm using modbus slave server, on ITX this code:

int main(void) {
	modbus_t *ctx;
	uint16_t tab_reg[64];
	int rc;
	int i;
	ctx = modbus_new_rtu("/dev/ttyS4", 38400, 'N', 8, 1);
	if (ctx == NULL) {
	    fprintf(stderr, "Unable to create the libmodbus context\n");
	    return -1;
	}
	modbus_set_slave(ctx, 99);
//	modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
//	modbus_set_response_timeout(ctx, 3, 200000);
//	modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
//	modbus_rtu_set_rts_delay(ctx, 1000);
	modbus_set_debug(ctx, TRUE);
    	modbus_set_error_recovery(ctx,
                              MODBUS_ERROR_RECOVERY_LINK |
                              MODBUS_ERROR_RECOVERY_PROTOCOL);

	if (modbus_connect(ctx) == -1) {
	    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
	    modbus_free(ctx);
	    return -1;
	}
	rc = modbus_read_registers(ctx, 1, 1, tab_reg);
	if (rc == -1) {
	    fprintf(stderr, "%s\n", modbus_strerror(errno));
	    return -1;
	}
	for (i=0; i < rc; i++) {
	    printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
	}
	modbus_close(ctx);
	modbus_free(ctx);
}

Output of the programm:

Opening /dev/ttyS4 at 38400 bauds (N, 8, 1) [63][03][00][01][00][01][DD][88] Waiting for a confirmation... ERROR Connection timed out: select Bytes flushed (0) Connection timed out

But in communication console on my PC i'm geting:

RX: 63 03 00 01 00 01 DD 88 TX: 63 03 02 00 01 80 4C

It means PC gets request and generate response, but ITX did't receive data from the slave. Is this a common problem?

i am trying to same and i am also suffering from the same problem.

VishvasMirani avatar Mar 22 '23 06:03 VishvasMirani