CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

ex_modbus_slave.c Modbus address question

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Omer



Joined: 26 Jul 2013
Posts: 6
Location: United States

View user's profile Send private message

ex_modbus_slave.c Modbus address question
PostPosted: Wed May 13, 2015 6:18 pm     Reply with quote

Hi, I'm using the Modbus example code ex_modbus_slave.c. My PCW ver is 5.045. In this code the Modbus Holding Registers address range is defined as max 255 which is equal to 40001 - 400255. I need to increase this range to at least 512 (40001-40512).

Here is the explaination of my question with a little bit more detail:
The Modbus Read code in the ex_modbus_slave.c file:
Code:

 case FUNC_READ_HOLDING_REGISTERS:
            case FUNC_READ_INPUT_REGISTERS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                  if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
                     modbus_read_holding_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]);
                  else
                     modbus_read_input_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);

                  event_count++;
               }
               break;

Here the Modbus Holding Register address limit is "modbus_rx.data[1] >= 8" and the definition for this is given in the file modbus_phy_layer.h as follows:
Code:

struct
{
   unsigned int8 address;
   unsigned int8 len;                       //number of bytes in the message received
   function func;                           //the function of the message received
   exception error;                         //error recieved, if any
   unsigned int8 data[MODBUS_SERIAL_RX_BUFFER_SIZE]; //data of the message received
} modbus_rx;

As can be seen from above the "data[MODBUS_SERIAL_RX_BUFFER_SIZE]" is defined as int8 which limits the max # of Modbus Holding Registers to 255. Is there anyway I can increase this to at least 512? Maybe define "data[MODBUS_SERIAL_RX_BUFFER_SIZE]" as int16? If so what else do I need to change?

Thanks,
Omer
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Thu May 14, 2015 1:58 am     Reply with quote

The buffer size does _not_ limit the maximum register address that can be used. You don't need to change this.
The buffer size only affects the maximum amount of data that can be transferred in a single message packet.

The holding register address is already a 16bit value. It's allowed to be 0 to 9999.

What initially limits the registers that can be used, is the size of the 'hold_regs' array (only 8 words in the example), then how much RAM your PIC actually has. Finally the test in the read/write function. Expand the array size, and then you can increase the limit in the function. The READ and WRITE function, take byte 3 of the data, and test if this is >8, and if byte 2 is anything other than zero. You need instead to build a 16bit address from byte 3, and byte 2, then test if this value is greater than the array size you are using (in words).
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

Re: ex_modbus_slave.c Modbus address question
PostPosted: Thu May 14, 2015 2:22 am     Reply with quote

Omer wrote:
In this code the Modbus Holding Registers address range is defined as max 255 which is equal to 40001 - 400255.


No, the example implements eight of each type of Modbus entity: eight coils, eight input registers, eight holding registers and so on.

Quote:
I need to increase this range to at least 512 (40001-40512).
Code:

 case FUNC_READ_HOLDING_REGISTERS:
            case FUNC_READ_INPUT_REGISTERS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)


This is where the address range is checked. In this example, the address has to lie in the range 40000-40007. The maximum number if registers that can be sent is 254. These two are separate: the address range can be smaller or larger than the maximum number of registers to send in in MODBUS message.

The buffer size is separate again. It must be big enough to contain the longest possible message. The more registers that are transferred at a time, the bigger the messages can be. But you must be careful as there are many message types, and the biggest possible message may not be related to registers. So, the data buffer size is FIXED at 256 data bytes. Messages don't always include 256 data bytes of course, but they can not contain more. This means that only 254 registers can be sent or received in a message as twoo registers worth is used for addressing.

Its easy enough to extend the range of addresses. Personally, I don't make all registers into actual elements in an array as the example does. That's fine for a few registers, such as the eight the example gives, but causes problems with large numbers of registers on machines with limited memory, such as PICs. Instead I have virtual registers mapped on the relevant parts of the code by a read_ and write_register routines.

Quote:

[/code]
Here the Modbus Holding Register address limit is "modbus_rx.data[1] >= 8" and the definition for this is given in the file modbus_phy_layer.h as follows:
Code:

struct
{
   unsigned int8 address;
   unsigned int8 len;                       //number of bytes in the message received
   function func;                           //the function of the message received
   exception error;                         //error recieved, if any
   unsigned int8 data[MODBUS_SERIAL_RX_BUFFER_SIZE]; //data of the message received
} modbus_rx;

As can be seen from above the "data[MODBUS_SERIAL_RX_BUFFER_SIZE]" is defined as int8 which limits the max # of Modbus Holding Registers to 255. Is there anyway I can increase this to at least 512? Maybe define "data[MODBUS_SERIAL_RX_BUFFER_SIZE]" as int16? If so what else do I need to change?


More confusion and conflation, I'm afraid :-( MODBUS addressing is not the same as MODBUS register/coil numbering. The MODBUS address is the address of the node on the bus. Node addresses are eight bits and therefore nodes can be numbered from 0 to 255.

Register numbers are part of the data sent in the MODBUS message. They are the first four bytes of the data. It is these bytes that the example is checking:
Code:

            case FUNC_READ_INPUT_REGISTERS:
               // Check the upper bytes of the starting register number and number of registers are both zero.
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  // Now check the start address is less than eight
                  // AND the start plus length is less than eight. In other words all
                  // the registers being asked for are in our range. Remember this
                  // if is true if anything is OUTSIDE the allowable range.
                  // The two eights are related, change both to the same number if ess than 256 registers, differently if more (as then there are more bytes to worry about).
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)

// At this point call modbus_exception_rsp() with sensible parameters if there's anything wrong, i.e. address out of range.
.

What's all this mean? Well, first DO NOT change the buffer size. That's fixed by MODBUS. Second, don't worry about MODBUS address being only eight bits, that's also fixed by MODBUS and had nothing to do with register numbering. Third, look at FUNC_READ_HOLDING_REGISTERS and its friends. These implement the decoding of the various type of MODBUS messages. Not every application needs them all. For example few applications use input registers these days. You need to look at the register numbering checking carefully. If you really need more than 256 registers, you will need to change the code to use modbus_rx.data[0] differently as this is the upper bytes of address. The number of registers of registers is always going to be less than 256, as that's more than the MODBUS message format can handle, so leave that alone.
Omer



Joined: 26 Jul 2013
Posts: 6
Location: United States

View user's profile Send private message

Thanks!
PostPosted: Thu May 14, 2015 9:15 pm     Reply with quote

Thank you very much for your replies. It helped a lot. Here is how I fixed the Holding Register address range limit checking problem:
In my program the Holding Register array is set to 512. So I check if the Holding Registers starting address is larger than 512 or if the data length + starting address is larger than 512.
Code:

int16 start_adr = (modbus_rx.data[0] * 256) + modbus_rx.data[1]; 
         
switch(modbus_rx.func)
  {
   case FUNC_READ_HOLDING_REGISTERS:
   if(start_adr> 512 || modbus_rx.data[2] || modbus_rx.data[3]+ start_adr > 512) 
      modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func, ILLEGAL_DATA_ADDRESS);

This worked beautifully!

Thanks again.
Omer
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Fri May 15, 2015 1:36 am     Reply with quote

Be careful! Look again at the start address check. This is what the example had:

Code:
...
modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)


This is what you've written:
Code:
if(start_adr> 512 || modbus_rx.data[2] || modbus_rx.data[3]+ start_adr > 512)


Think about what happens if the address is 511 and the number of registers is one. Then think about what happens if someone, incorrectly, tries starting at 512...

By the way, by now you should have realised that the 10000, 20000, 40000 thing just distinguishes between the types of endpoints and doesn't actually get sent over the bus at all, as each type of endpoint is dealt with by different commands, not by different address ranges. Though the spec allows only 9999 or 10000 of each type, in fact, as the numbering is sixteen bit, you can actually have 65536 of each type of endpoint. Some implementations actually do that.

To be honest I don't even think of the "40000" range thing at all, and I can't remember what range goes with what endpoint type.

So, your code should be:
Code:
if(start_adr >= 512 || modbus_rx.data[2] || modbus_rx.data[3]+ start_adr > 512)
Omer



Joined: 26 Jul 2013
Posts: 6
Location: United States

View user's profile Send private message

Changed code to >=
PostPosted: Fri May 15, 2015 12:08 pm     Reply with quote

Yes you are right I changed my code to >= Thank you for pointing out that.
In my applications I do have to pay attention to the "10000" and "40000" address definitions because most of the SCADA software out there only use this addressing method and the Modbus driver handles the low level stuff. When I get a support call from my customers they say "I tried to write to address 40300 and your unit replies with an illegal address error what's going on"Smile

Thank you for all the help.
Omer
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group