IoDrvModbus 3.5.15.0 - ModbusRequest2

2020-03-04
2020-03-05
  • Tim.Manning - 2020-03-04

    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:

     SysComOpen - opens the port
    
     ModbusRequest2 - to first device
    
     ModbusRequest2 - to second device
    

    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.

     
  • dFx

    dFx - 2020-03-05

    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 ?

     
    • Tim.Manning - 2020-03-05

      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,
      ..

       
    • Tim.Manning - 2020-03-05
       

      Last edit: Tim.Manning 2020-03-05
  • dFx

    dFx - 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.

     
  • Tim.Manning - 2020-03-05

    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.

     
  • dFx

    dFx - 2020-03-05

    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.

     
  • Tim.Manning - 2020-03-05

    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.

     

Log in to post a comment.