µTasker Forum

µTasker Forum => NXPTM LPC2XXX and LPC17XX => Topic started by: kiryat8 on September 10, 2014, 07:06:44 AM

Title: Modbus User task callback
Post by: kiryat8 on September 10, 2014, 07:06:44 AM
When implementing a Modbus RTU slave...
I have all NULL pointers passed to the fnInitialiseMODBUS_port() function so I get an user callback.
static int fnMODBUSSlaveuserFunction(int iType, MODBUS_RX_FUNCTION *modbus_rx_function)
Using the code below I determine which Modbus command was received and handle accordingly.
  switch(iType){
    case USER_RECEIVING_MODBUS_UNDEFINED_FUNCTION:
       switch (modbus_rx_function->ucFunctionCode){
          case MODBUS_WRITE_SINGLE_REGISTER://         0x06
             ...
             fnMODBUS_transmit(modbus_rx_function,modbus_HostBuf,8);
             return 0;
           case MODBUS_WRITE_MULTIPLE_REGISTERS://      0x10
       } // switch Modbus message type
  } // switch

1) The problem I have is that I get two calls to the function.
  The first time when receiving the incoming message and the second time after my reply was sent.
  In the read request message I checked the MODBUS_RX_FUNCTION fields to detect the reply,
  BUT in the MODBUS_WRITE_SINGLE_REGISTER the reply is exactly the same as the incoming message.
  How can I differentiate between the reply and the incoming callbacks?

2) I receive the MODBUS_WRITE_MULTIPLE_REGISTERS message as 0x90 instead of 0x10.
I can not find out why?

Thanks
David Kaplan



Title: Re: Modbus User task callback
Post by: mark on September 10, 2014, 02:29:07 PM
Hi David

2) A response with 0x80 bit set means that the slave is returning an exception rather than a result (to the command). Check the second byte (the exception code) to see the reason for the exception response. These are the possible reasons:

// MODBUS exception codes
//
#define MODBUS_EXCEPTION_ILLEGAL_FUNCTION    0x01
#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADD    0x02
#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE  0x03
#define MODBUS_EXCEPTION_SLAVE_DEV_FAILURE   0x04
#define MODBUS_EXCEPTION_ACKNOWLEDGE         0x05
#define MODBUS_EXCEPTION_SLAVE_DEVICE_BUSY   0x06
#define MODBUS_EXCEPTION_MEMORY_PARITY_ERROR 0x07
#define MODBUS_EXCEPTION_GATEWAY_PATH_UNAV   0x0a
#define MODBUS_EXCEPTION_GATEWAY_DEV_NO_RESP 0x0b


Always check for exceptions with
modbus_rx_function->ucFunctionCode & 0x80
To determine the function code that returned an error use
modbus_rx_function->ucFunctionCode & ~(0x80)

Regards

Mark

Title: Re: Modbus User task callback
Post by: mark on September 10, 2014, 02:40:02 PM
David

1) The call back event USER_RECEIVING_MODBUS_UNDEFINED_FUNCTION is only called when a valid Modbus message has been received. There is no call back on transmission.

Is it possible that you have something echoing the transmitted message back on the bus or are you using RS485 where the transmitted message is being received as it is sent? There is usually a tx/rx control line stopping this taking place in the second case.

Regards

Mark
Title: Re: Modbus User task callback
Post by: kiryat8 on September 11, 2014, 08:21:08 AM
I did not think of the RS485 echo which in my original code I handled.
I just disabled the RS485  receiver while transmitting and it works well.
I found that the write multiple register returns under USER_RECEIVING_ALL_MODBUS_TYPE while the other
Modbus functions that I use return under USER_RECEIVING_MODBUS_UNDEFINED_FUNCTION
which is no problem at all.

Thanks
Title: Re: Modbus User task callback
Post by: mark on September 11, 2014, 05:15:12 PM
David

Thanks for the feedback.

Note that if you define NO_SLAVE_MODBUS_WRITE_MULTIPLE_COILS you will get USER_RECEIVING_MODBUS_UNDEFINED_FUNCTION for all functions.
Since the code is following this path it looks like ptrMODBUS_table[_USER_PORT] is not zero (which I thought it was but may have misunderstood - maybe just some register ranges are zeroed) and in that case the call back event will depend on whether the function is known or not and whether the adressed range is valid or not (in this case the register address range will not have been valid but the function was otherwise understood and so USER_RECEIVING_ALL_MODBUS_TYPE would have been used).

Regards

Mark