1

I am trying to implement an modbus device with a lot of registers, right now I need around 350 registers. However, once I try to send over 255 registers, Modbus poll gets an Illegal Data Address error

EDIT: To be clear, my device is the slave, I am using Modbus Poll to read the information.

Processor atmega2560, programming in Microchip Studio. I am using the library Modbus-Master-Slave-for-Arduino (github.com/smarmengol/Modbus-Master-Slave-for-Arduino)

Another user had the same issue and solved it (supposedly) with this library. Modbus Registers beyond 255 cannot be accessed SimpleModbus

However, once I increase my poll size to 256 I get an Illegal Data Address in Modbus Poll.

usb.poll(au16dataTotal, 255); works fine, I expanded the buffer to 256 so I can poll up to 123 registers at a time on modbus poll usb.poll(au16dataTotal, 256); Does not work.

The array of data that it is pulling from is large enough uint16_t au16dataTotal[500];

Taking a look at the library I don't think this is possible, as the size appears to be 8 bits or am I doing something wrong? Or is it worth trying to edit the library?

from the library:

/**
 * @brief
 * *** Only for Modbus Slave ***
 * This method checks if there is any incoming query
 * Afterwards, it would shoot a validation routine plus a register query
 * Avoid any delay() function !!!!
 * After a successful frame between the Master and the Slave, the time-out timer is reset.
 *
 * @param *regs  register table for communication exchange
 * @param u8size  size of the register table
 * @return 0 if no query, 1..4 if communication error, >4 if correct query processed
 * @ingroup loop
 */
int8_t Modbus::poll( uint16_t *regs, uint8_t u8size )
{

    au16regs = regs;
    u8regsize = u8size;
    uint8_t u8current;


    // check if there is any incoming frame
    u8current = port->available();

    if (u8current == 0) return 0;

    // check T35 after frame end or still no frame end
    if (u8current != u8lastRec)
    {
        u8lastRec = u8current;
        u32time = millis();
        return 0;
    }
    if ((unsigned long)(millis() -u32time) < (unsigned long)T35) return 0;

    u8lastRec = 0;
    int8_t i8state = getRxBuffer();
    u8lastError = i8state;
    if (i8state < 7) return i8state;

    // check slave id
    if (au8Buffer[ ID ] != u8id) return 0;

    // validate message: CRC, FCT, address and size
    uint8_t u8exception = validateRequest();
    if (u8exception > 0)
    {
        if (u8exception != NO_REPLY)
        {
            buildException( u8exception );
            sendTxBuffer();
        }
        u8lastError = u8exception;
        return u8exception;
    }

    u32timeOut = millis();
    u8lastError = 0;

    // process message
    switch( au8Buffer[ FUNC ] )
    {
    case MB_FC_READ_COILS:
    case MB_FC_READ_DISCRETE_INPUT:
        return process_FC1( regs, u8size );
        break;
    case MB_FC_READ_INPUT_REGISTER:
    case MB_FC_READ_REGISTERS :
        return process_FC3( regs, u8size );
        break;
    case MB_FC_WRITE_COIL:
        return process_FC5( regs, u8size );
        break;
    case MB_FC_WRITE_REGISTER :
        return process_FC6( regs, u8size );
        break;
    case MB_FC_WRITE_MULTIPLE_COILS:
        return process_FC15( regs, u8size );
        break;
    case MB_FC_WRITE_MULTIPLE_REGISTERS :
        return process_FC16( regs, u8size );
        break;
    default:
        break;
    }
    return i8state;
}


EDIT: My code below, I simplified it for this example. I currently have this running on my device.

#include <Arduino.h>
#include <ModbusRtu.h>

uint16_t au16dataTotal[500];


Modbus usb(1, 3, 0);

modbus_t telegram;

void setup() {
  Serial3.begin(115200);
}

void loop() {
    
    for(int i = 0; i <= 499; i++){
        au16dataTotal[i] = i;
    }
    
    usb.poll(au16dataTotal, 255);
}


James N
  • 11
  • 2
  • 2
    from Wikipedia: "Because the maximum length of a Modbus PDU is 253 (inferred from the maximum Modbus ADU length of 256 on RS485), up to 125 registers can be requested at once when using the RTU format" – Juraj May 09 '23 at 15:18
  • Right, that has to do with the amount of registers that can be requested at one time. Right now I am outputting 255 registers, however, you can only read 125 at a time, well 123 registers due to the max buffer size I have to work with. My issue is when I exceed 255 registers worth of data, I am not trying to read more than 125 registers at a time on modbus poll. – James N May 09 '23 at 15:37

1 Answers1

0

uint8_t includes values from 0-255 and that's 256 in total, so you'll just have to call this function multiple times to read all of the required registers!

Nick S.
  • 168
  • 1
  • 12
  • Hi, thanks for your reply. I have edited my post to include code. Unfortunately, every time you call a .poll function, it starts at register 0, and will overwrite the previous data. In my example I have an array of 500 values, but I can only transmit 255. Calling it again will still only send out the first 255 values. – James N May 09 '23 at 18:43
  • @JamesN I see, then yeah, looking into it, it seems that's how the library is written. If you want to fork it and change it, go ahead or you could try a different library, like this one: https://github.com/arduino-libraries/ArduinoModbus/tree/master. I'm curious, how are you using Modbus Poll to read 255 values? For holding and reading registers, you can only see 125 at a time - do you simply check 0-125 and 126-250 and then 250-255? – Nick S. May 09 '23 at 21:12
  • 1
    Yeah, I might end up ditching the library I am using, its a shame because it has an RS232 option. Yes that is exactly how I am using Modbus Poll, really I am just using Modbus Poll to verify my output. Its a weird project I'm working on. I have to read a device that is outputting its data via Modbus RS232 (it has about 210 registers), this would normally go to an FTDI chip, which would go into software made to read the device. I need to middle man that information, add my additional registers, and output the data by Modbus RS232 (to the software), Modbus RS485, and Modbus over TCP/IP. – James N May 09 '23 at 21:30
  • @JamesN I see, what do you mean it has an RS232 option (as in, if it can do serial, it should be able to do either RS232/RS485, that depends on your hardware)? That sounds like a normal project to me! :p A lot of Arduino libraries are a bit limited in what they can do (in my experience), so it's easier if you have a dedicated device which can do Modbus - usually a PLC or a datalogger. If not, I recommend running a Linux SBC (RPi) with PyModbus - I've been using it for one of my projects. It has an active maintainer. ESP-IDF (ESP32 chips/devboards) has a good Modbus framework too. – Nick S. May 09 '23 at 21:37