3

I'm french student and I have been playing with SimpleModbus for 1 week, and it worked fine... Until I tried to implement a slave with a large amount of registers (1000 needed). Registers beyond 255 using slave 1 cannot be accessed. Whatever I do I get a timeout error as soon as the registers reading go beyond 255 :

control.modbus.CommunicationException: While reading holding registers 255 on slave 1

The documentation says nothing about such a limitation. Reading SimpleModbusSlave.cpp didn't help ... maybe I need to change the starting address in the "modbus update" function but I am too beginner to understand...

unsigned int modbus_update() {
  if (*(ModbusPort).available())
  {
    unsigned char buffer = 0;
    unsigned char overflow = 0;

    while ((*ModbusPort).available())
    {
      // The maximum number of bytes is limited to the serial buffer size of 128 bytes
      // If more bytes is received than the BUFFER_SIZE the overflow flag will be set and the
      // serial buffer will be red untill all the data is cleared from the receive buffer.
      if (overflow)
        (*ModbusPort).read();
      else
      {
        if (buffer == BUFFER_SIZE)
          overflow = 1;
        frame[buffer] = (*ModbusPort).read();
        buffer++;
      }
      delayMicroseconds(T1_5); // inter character time out
    }

    // If an overflow occurred increment the errorCount
    // variable and return to the main sketch without
    // responding to the request i.e. force a timeout
    if (overflow)
      return errorCount++;

    // The minimum request packet is 8 bytes for function 3 & 16
    if (buffer > 7)
    {
      unsigned char id = frame[0];

      broadcastFlag = 0;

      if (id == 0)
        broadcastFlag = 1;

      if (id == slaveID || broadcastFlag) // if the recieved ID matches the slaveID or broadcasting id (0), continue
      {
        unsigned int crc = ((frame[buffer - 2] << 8) | frame[buffer - 1]); // combine the crc Low & High bytes
        if (calculateCRC(buffer - 2) == crc) // if the calculated crc matches the recieved crc continue
        {
          function = frame[1];
          unsigned int startingAddress = ((frame[2] << 8) | frame[3]); // combine the starting address bytes
          unsigned int no_of_registers = ((frame[4] << 8) | frame[5]); // combine the number of register bytes
          unsigned int maxData = startingAddress + no_of_registers;
          unsigned char index;
          unsigned char address;
          unsigned int crc16;

          // broadcasting is not supported for function 3
          if (!broadcastFlag && (function == 3))
          {
            if (startingAddress < holdingRegsSize) // check exception 2 ILLEGAL DATA ADDRESS
            {
              if (maxData <= holdingRegsSize) // check exception 3 ILLEGAL DATA VALUE
              {
                unsigned char noOfBytes = no_of_registers * 2;
                // ID, function, noOfBytes, (dataLo + dataHi)*number of registers,
                //  crcLo, crcHi
                unsigned char responseFrameSize = 5 + noOfBytes;
                frame[0] = slaveID;
                frame[1] = function;
                frame[2] = noOfBytes;
                address = 3; // PDU starts at the 4th byte
                unsigned int temp;

                for (index = startingAddress; index < maxData; index++)
                {
                  temp = regs[index];
                  frame[address] = temp >> 8; // split the register into 2 bytes
                  address++;
                  frame[address] = temp & 0xFF;
                  address++;
                }

                crc16 = calculateCRC(responseFrameSize - 2);
                frame[responseFrameSize - 2] = crc16 >> 8; // split crc into 2 bytes
                frame[responseFrameSize - 1] = crc16 & 0xFF;
                sendPacket(responseFrameSize);
              }
              else
                exceptionResponse(3); // exception 3 ILLEGAL DATA VALUE
            }
            else
              exceptionResponse(2); // exception 2 ILLEGAL DATA ADDRESS
          }
          else if (function == 16)
          {
            // Check if the recieved number of bytes matches the calculated bytes
            // minus the request bytes.
            // id + function + (2 * address bytes) + (2 * no of register bytes) +
            // byte count + (2 * CRC bytes) = 9 bytes
            if (frame[6] == (buffer - 9))
            {
              if (startingAddress < holdingRegsSize) // check exception 2 ILLEGAL DATA ADDRESS
              {
                if (maxData <= holdingRegsSize) // check exception 3 ILLEGAL DATA VALUE
                {
                  address = 7; // start at the 8th byte in the frame

                  for (index = startingAddress; index < maxData; index++)
                  {
                    regs[index] = ((frame[address] << 8) | frame[address + 1]);
                    address += 2;
                  }

                  // only the first 6 bytes are used for CRC calculation
                  crc16 = calculateCRC(6);
                  frame[6] = crc16 >> 8; // split crc into 2 bytes
                  frame[7] = crc16 & 0xFF;

                  // a function 16 response is an echo of the first 6 bytes from
                  // the request + 2 crc bytes
                  if (!broadcastFlag) // don't respond if it's a broadcast message
                    sendPacket(8);
                }
                else
                  exceptionResponse(3); // exception 3 ILLEGAL DATA VALUE
              }
              else
                exceptionResponse(2); // exception 2 ILLEGAL DATA ADDRESS
            }
            else
              errorCount++; // corrupted packet
          }
          else
            exceptionResponse(1); // exception 1 ILLEGAL FUNCTION
        }
        else // checksum failed
          errorCount++;
      } // incorrect id
    }
    else if (buffer > 0 && buffer < 8)
      errorCount++; // corrupted packet
  }
  return errorCount;
}

Slave: SimpleModbusSlave Any thoughts ?

Edit : I think someone had the same problem but I really did not understand what he changed :( here

Thanks in advance to those who can enlighten me!

Gabriel
  • 319
  • 3
  • 15
  • Are you sure you are not getting an exception response? You have a statement "if (buffer > 7)", I think the size of an exception response is only 5 bytes: slave address (1), function code (1), exception code (1), crc (2). – Marker Jul 06 '18 at 11:49
  • thanks for your reply! no problem on this side, I use an old version of this librarie: https://github.com/pepsilla/Arduino/tree/master/MODBUS/ASCII/libraries/SimpleModbusSlave – Gabriel Jul 06 '18 at 12:39
  • I also see a comment "The maximum number of bytes is limited to the serial buffer size of 128 bytes". The maximum modbus ADU size (RTU) is 256 bytes. You may never hit this limit if you are only reading a few registers at a time. How many registers are you trying to read at once? It would be helpful to see all your code. – Marker Jul 06 '18 at 12:41
  • So you are using the Modbus ASCII not RTU? – Marker Jul 06 '18 at 12:46
  • I use the modbus to communicate in java with my arduino. The arduino collects sensor data and stokes in a circular buffer. Then on the master (in java) I come periodically collected the data of the circular buffer. I read register at once. There are 10 sensors with a circular buffer of 64 * 16 bits of data. There is no problem on the first 3 sensors but on the 4th I have this error message because I try to read the index 256 ... – Gabriel Jul 06 '18 at 12:59
  • I think I need to change something here: the address is stored only on 8 bits so after 255 ... But I do not know at all I am a little lost ...   unsigned int startingAddress = ((frame [2] << 8) | frame [3]); // combine the starting address bytes    unsigned int no_of_registers = ((frame [4] << 8) | frame [5]); // combine the number of register bytes (I use RTU Master) – Gabriel Jul 06 '18 at 12:59
  • OK, I was confused. The code you are using has "ASCII" in the URL (/MODBUS/ASCII/libraries/SimpleModbusSlave) so I thought you were using the Modbus ASCII protocol, but the header comments indicate that it is RTU. – Marker Jul 06 '18 at 13:33
  • I looked at (scanned) the slave code. Not overly robust and a little hard to follow, but it does look like it should work. I also looked at the master code and I think I understand it, but I was hoping to see what the packet that it sends looks like. I suggest you test your slave with CAS Modbus Scanner (free) or Modbus Poll (free trial). Both are Modbus master tools that I know work. If your slave code works with those tools, then your problem is in the master code; if it does not work with them, the problem is in the slave code. – Marker Jul 06 '18 at 14:33
  • Thank you very much ! I will try :) – Gabriel Jul 06 '18 at 14:45
  • Thank you very much @Marker it works now! I changed my librarie for the slave: https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino – Gabriel Jul 09 '18 at 10:10

1 Answers1

0

Thank you very much @Marker it works now! I changed my librarie for the slave: github.com/smarmengol/Modbus-Master-Slave-for-Arduino –

Gabriel
  • 319
  • 3
  • 15