We are trying to communicate to multiple Modbus Slaves via a serial port (RS-485).
We are using the ModbusRequest2 Function Block, and when we communicate with one device, communications are successful.
If we attempt to communicate to more than one slave device, we are only able to successfully communicate to one device. We get a 'busy' error when communicating to the other devices.
First device referenced in code - communications are successful every scan
Second (and later) device reference in code - communications fail every scan
From your question, it sounds like the application needs to handle queuing the messages when using ModbusRequest2.
Our requirement is this:
Communicate to up to 8 devices (per communication port) every second.
When using the Modbus Driver in the device tree, all I needed to do was create 8 slave devices per port, and then create a Modbus channel for each of these devices that was cyclic. Communications to each device was successful - I assume the Modbus driver was queuing the requests and processing them in order.
Because we need more control over the communications than what we can get from the device tree, we've now created a program with 8 instances of a function block that includes the Modbus2 request. We are running this program in a task that runs at 500 msecs. The thinking was we would run with the execute set at the top of the second for each instance of the function block, and the execute would be cleared at the bottom of the second. We were assuming that all of the messages would be queued to the driver, and processed in order.
However, it sounds like we need to rethink our logic.
Run the task 16 times a second (minimum - probably need to run it faster in order to provide some 'deadtime' during the 1 second interval, in case exception based comms need to occur) -
You may need a cycle with execute=false (or two successive calls) because queries are send with raising edge of execute.
A simple case may be appropriate to handle the queue/active queries, and one more to correctly sequence your queries.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
cycle 1 - Execute instance 1 (execute.1 OFF to ON)
cycle 2 - look for instance 1 done (execute.1 should go from ON to OFF)
cycle 3 - If Instance 1 done, Execute instance 2 (execute.2 OFF to ON)
cycle 4 - look for instance 2 done (execute.2 should go from ON to OFF)
cycle 5 - If Instance 2 done, Execute instance 3 (execute.3 OFF to ON),
cycle 6 - look for instance 2 done (execute.3 should go from ON to OFF)
... etc.
So, by the time we get back to the first instance, its execute flag should already be OFF, and we will set it ON.
Our current logic is:
Cycle 1 - Execute Instance 1 through Instance 8 (execute.1 through execute.8 OFF to ON)
Cycle 2 - look for instance 1 through instance 8 done
Cycle 3 - Execute Instance 1 through Instance 8 (execute.1 through execute.8 OFF to ON)
Cycle 4 - look for instance 1 through instance 8 done
etc.
As I mentioned, our current logic only works for the first instance referenced in the code. The 2nd and later instances return a 'busy' error. So, the messages are being issued, they are just not being processed because the port is busy.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
To me it feels wrong using multiple instances. RTU aim one com port, so there is only one query at a time. Using only one instance is the guarantee you have only one running at a time.
Just update the pointers and sizes to point to the query you want to execute.
Cycle 1 : execute=true, instance call
Cycle 2 : if xDone, execute=false, instance call, update pointers, execute=true, instance call
Cycle n : same as cycle 2.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You are probably right. When doing this in the past, I always had the luxury of having a driver that handled queuing for me. The application could just issue requests and wait for the response.
I'll look into creating a message queue to handle all of the requests for all of the potential devices hanging off of a port. It shouldn't be too hard.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
We are trying to communicate to multiple Modbus Slaves via a serial port (RS-485).
We are using the ModbusRequest2 Function Block, and when we communicate with one device, communications are successful.
If we attempt to communicate to more than one slave device, we are only able to successfully communicate to one device. We get a 'busy' error when communicating to the other devices.
Our application looks like this:
When using the ModbusRequest2, is the application responsible for buffering multiple requests to the Com Port?
If we configure the Modbus Master in the device tree, the buffering seems to be handled by the Modbus driver.
Unfortunately, we have project requirements that prevent us from using i the Modbus Master in the device tree.
Do you suceed with multiples different queries to the same slave ?
Do you correctly wait for the xDone=TRUE plus a scan cycle with xExecute=FALSE ?
The current results are as follows:
First device referenced in code - communications are successful every scan
Second (and later) device reference in code - communications fail every scan
From your question, it sounds like the application needs to handle queuing the messages when using ModbusRequest2.
Our requirement is this:
Communicate to up to 8 devices (per communication port) every second.
When using the Modbus Driver in the device tree, all I needed to do was create 8 slave devices per port, and then create a Modbus channel for each of these devices that was cyclic. Communications to each device was successful - I assume the Modbus driver was queuing the requests and processing them in order.
Because we need more control over the communications than what we can get from the device tree, we've now created a program with 8 instances of a function block that includes the Modbus2 request. We are running this program in a task that runs at 500 msecs. The thinking was we would run with the execute set at the top of the second for each instance of the function block, and the execute would be cleared at the bottom of the second. We were assuming that all of the messages would be queued to the driver, and processed in order.
However, it sounds like we need to rethink our logic.
Run the task 16 times a second (minimum - probably need to run it faster in order to provide some 'deadtime' during the 1 second interval, in case exception based comms need to occur) -
cycle 1 - Execute instance 1
cycle 2 - look for instance 1 done
cycle 3 - If Instance 1 done, Execute instance 2
cycle 4 - look for instance 2 done
cycle 5 - If Instance 2 done, Execute instance 3,
..
Last edit: Tim.Manning 2020-03-05
You may need a cycle with execute=false (or two successive calls) because queries are send with raising edge of execute.
A simple case may be appropriate to handle the queue/active queries, and one more to correctly sequence your queries.
I think the proposed logic would handle this:
cycle 1 - Execute instance 1 (execute.1 OFF to ON)
cycle 2 - look for instance 1 done (execute.1 should go from ON to OFF)
cycle 3 - If Instance 1 done, Execute instance 2 (execute.2 OFF to ON)
cycle 4 - look for instance 2 done (execute.2 should go from ON to OFF)
cycle 5 - If Instance 2 done, Execute instance 3 (execute.3 OFF to ON),
cycle 6 - look for instance 2 done (execute.3 should go from ON to OFF)
... etc.
So, by the time we get back to the first instance, its execute flag should already be OFF, and we will set it ON.
Our current logic is:
Cycle 1 - Execute Instance 1 through Instance 8 (execute.1 through execute.8 OFF to ON)
Cycle 2 - look for instance 1 through instance 8 done
Cycle 3 - Execute Instance 1 through Instance 8 (execute.1 through execute.8 OFF to ON)
Cycle 4 - look for instance 1 through instance 8 done
etc.
As I mentioned, our current logic only works for the first instance referenced in the code. The 2nd and later instances return a 'busy' error. So, the messages are being issued, they are just not being processed because the port is busy.
To me it feels wrong using multiple instances. RTU aim one com port, so there is only one query at a time. Using only one instance is the guarantee you have only one running at a time.
Just update the pointers and sizes to point to the query you want to execute.
Cycle 1 : execute=true, instance call
Cycle 2 : if xDone, execute=false, instance call, update pointers, execute=true, instance call
Cycle n : same as cycle 2.
You are probably right. When doing this in the past, I always had the luxury of having a driver that handled queuing for me. The application could just issue requests and wait for the response.
I'll look into creating a message queue to handle all of the requests for all of the potential devices hanging off of a port. It shouldn't be too hard.