Page 1 of 2

ESP32 MODBUS descriptor CID field issue

Posted: Tue Jan 18, 2022 10:17 am
by Ashvajit.P
I am implementing modbus master (RTU) and trying to read from Modbus Slave emulator tool. When I am initializing modbus table with sequential CID values, it is working fine. but in my end application modbus map index from 3 to 13 is reserved in slave device.
do I need to declare reserved parameters which are not used in my modbus map, just for the sake of indexing or is there some thing that I am missing ?


CID Index :

Code: Select all

enum
{
	SIZE_CFG_MBREG_CID = 0,
	COMMAND_WORD_MBREG_CID,
	SPEED_REF_MBREG_CID,
	REF_RAMP_RISE_TIME_CID = 0x0C,
	REF_RAMP_FALL_TIME_CID,
	OVERLOAD_SETT_CID,
	POWERBOARD_CTRL_CID,
	STATUS_WORD_CID,
	SPEED_FDB_CID	=	0x013,
	CURRENT_FDB_CID,
};
	

Code: Select all

 typedef struct
{
	uint16_t mb_device1_DriveID;
	uint16_t mb_device1_CMD_Word;
	uint16_t mb_device1_SpeedRef;
	uint16_t mb_device1_Ref_Rise_time;
	uint16_t mb_device1_Ref_Fall_Time;
	uint16_t mb_device1_Overload_setting;
	uint16_t mb_device1_Powerboard_Ctrl;
	uint16_t mb_device1_Status_word;
	uint16_t mb_device1_Speed_FDB;
	uint16_t mb_device1_Current_FDB;
	uint16_t mb_device1_DC_Bus_FDB;
	}holding_reg_params_t;
MODBUS Descriptor Table

Code: Select all

const mb_parameter_descriptor_t device_parameters[] = {
    // { Cid, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
    // Parameter: Data channel 0 : Data channel 0 = Voltage
		{	SIZE_CFG_MBREG_CID, STR("Drive ID"), STR("GPM"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
	        HOLD_OFFSET(mb_device1_DriveID), PARAM_TYPE_U16, 2, OPTS(0, 0xFFFF, 1), PAR_PERMS_READ_TRIGGER	},
		{	COMMAND_WORD_MBREG_CID, STR("Command Word"), STR("hex"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
	        HOLD_OFFSET(mb_device1_CMD_Word), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	SPEED_REF_MBREG_CID, STR("Max Freq"), STR("Hz"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
	        HOLD_OFFSET(mb_device1_SpeedRef), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	REF_RAMP_RISE_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0C, 1,
	        HOLD_OFFSET(mb_device1_Ref_Rise_time), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	REF_RAMP_FALL_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 13, 1,
	        HOLD_OFFSET(mb_device1_Ref_Fall_Time), PARAM_TYPE_U16, 2, OPTS(0, 50000, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	OVERLOAD_SETT_CID, STR("Overload Sett"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 14, 1,
			HOLD_OFFSET(mb_device1_Overload_setting), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER },
		{	POWER_CTRL_CID, STR("Power Ctrl"), STR("hex"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 15, 1,
	        HOLD_OFFSET(mb_device1_Powerboard_Ctrl), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER  },
};


Re: ESP32 MODBUS descriptor CID field issue

Posted: Tue Jan 18, 2022 11:14 am
by ESP_alisitsyn
Hi @Ashvajit.P,

The current approach of ESP_Modbus requires defining the CIDs sequentially. The CID here is a unique identifier of characteristic in the master data dictionary that corresponds to registers in the slave. It is not connected to the start register number of the characteristic in the slave device. The mapping of the registers is defined by

Code: Select all

mb_parameter_descriptor_t::mb_param_type,mb_parameter_descriptor_t::mb_reg_start, mb_parameter_descriptor_t::mb_size
in data dictionary.

Code: Select all

enum
{
	SIZE_CFG_MBREG_CID = 0,
	COMMAND_WORD_MBREG_CID,
	SPEED_REF_MBREG_CID,
	REF_RAMP_RISE_TIME_CID, // corresponds to one register from address 0x0C and stored in mb_device1_Ref_Rise_time field of holding register structure.
	REF_RAMP_FALL_TIME_CID,
	OVERLOAD_SETT_CID,
	POWERBOARD_CTRL_CID,
	STATUS_WORD_CID,
	SPEED_FDB_CID,
	CURRENT_FDB_CID,
};
do I need to declare reserved parameters which are not used in my modbus map
You should not declare the reserved parameters if you do not use them. Just add the mapping of the addressable parameters and keep the CIDs in sequential order in the data dictionary.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Wed Jan 19, 2022 9:48 am
by Ashvajit.P
So, I filled the reserved spaces with the sequential values as shown in below snaps and its is working now.
But my concern is that, doesn't it occupy more memory than it should, if these parameters are added in descriptor table :?:

Code: Select all

enum
{
	SIZE_CFG_MBREG_CID = 0,
	COMMAND_WORD_MBREG_CID,
	SPEED_REF_MBREG_CID,
	RESERVED_CID_3,
	RESERVED_CID_4,
	RESERVED_CID_5,
	RESERVED_CID_6,
	RESERVED_CID_7,
	RESERVED_CID_8,
	RESERVED_CID_9,
	RESERVED_CID_10,
	RESERVED_CID_11,
	REF_RAMP_RISE_TIME_CID ,
	REF_RAMP_FALL_TIME_CID,};

Code: Select all

typedef struct
{	uint16_t mb_device1_DriveID;
	uint16_t mb_device1_CMD_Word;
	uint16_t mb_device1_SpeedRef;
	uint16_t mb_device1_RESERVED_CID_3;
	uint16_t mb_device1_RESERVED_CID_4;
	uint16_t mb_device1_RESERVED_CID_5;
	uint16_t mb_device1_RESERVED_CID_6;
	uint16_t mb_device1_RESERVED_CID_7;
	uint16_t mb_device1_RESERVED_CID_8;
	uint16_t mb_device1_RESERVED_CID_9;
	uint16_t mb_device1_RESERVED_CID_10;
	uint16_t mb_device1_RESERVED_CID_11;
	uint16_t mb_device1_Ref_Rise_time;
	uint16_t mb_device1_Ref_Fall_Time;} holding_reg_params_t;

Code: Select all

const mb_parameter_descriptor_t device_parameters[] = {
    // { Cid, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
    // Parameter: Data channel 0 : Data channel 0 = Voltage
		{	SIZE_CFG_MBREG_CID, STR("Drive ID"), STR("GPM"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
	        HOLD_OFFSET(mb_device1_DriveID), PARAM_TYPE_U16, 2, OPTS(0, 0xFFFF, 1), PAR_PERMS_READ_TRIGGER	},
		{	COMMAND_WORD_MBREG_CID, STR("Command Word"), STR("hex"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
	        HOLD_OFFSET(mb_device1_DriveID), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	SPEED_REF_MBREG_CID, STR("Max Freq"), STR("Hz"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
	        HOLD_OFFSET(mb_device1_DriveID), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	RESERVED_CID_3, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 3, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_3), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	RESERVED_CID_4, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_4), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	RESERVED_CID_5, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 5, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_5), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	RESERVED_CID_6, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 6, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_6), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	RESERVED_CID_7, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 7, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_7), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER}, 
		{	RESERVED_CID_8, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 8, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_8), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER}, 
		{	RESERVED_CID_9, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 9, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_9), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER}, 
		{	RESERVED_CID_10, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_10), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER}, 
		{	RESERVED_CID_11, STR("Reserved"), STR("NULL"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 11, 1,
			HOLD_OFFSET(mb_device1_RESERVED_CID_11), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	REF_RAMP_RISE_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 12, 1,
	        HOLD_OFFSET(mb_device1_Ref_Rise_time), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	REF_RAMP_FALL_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 13, 1,
	        HOLD_OFFSET(mb_device1_Ref_Fall_Time), PARAM_TYPE_U16, 2, OPTS(0, 50000, 1), PAR_PERMS_READ_WRITE_TRIGGER},
};

Re: ESP32 MODBUS descriptor CID field issue

Posted: Fri Jan 21, 2022 5:34 am
by ESP_alisitsyn
@Ashvajit.P,

In this case, it t occupies more memory than it should. As I described above it is not required to fill the reserved spaces to address the parameters correctly. However, it is your design decision to use CIDs that match start register number in your slave.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Mon Jan 24, 2022 5:55 am
by Ashvajit.P
If I am not filling the reserved spaces, controller is resetting and same error is displayed on the log.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Mon Jan 24, 2022 12:31 pm
by ESP_alisitsyn
@Ashvajit.P ,

I think there is some misunderstanding. If you configure the object dictionary like below you will be able to read/write any of the parameters from slave and don't need to define reserved data between `mb_device1_SpeedRef` and `mb_device1_Ref_Rise_time`. The master should work just fine and read the parameters to the appropriate place in the structure according to offset defined as `HOLD_OFFSET(mb_device1_CMD_Word)`(example).

Code: Select all

enum
{
	SIZE_CFG_MBREG_CID = 0,
	COMMAND_WORD_MBREG_CID,
	SPEED_REF_MBREG_CID,
	REF_RAMP_RISE_TIME_CID,
	REF_RAMP_FALL_TIME_CID,
	OVERLOAD_SETT_CID,
	POWERBOARD_CTRL_CID
};

typedef struct
{
	uint16_t mb_device1_DriveID;
	uint16_t mb_device1_CMD_Word;
	uint16_t mb_device1_SpeedRef;
	uint16_t mb_device1_Ref_Rise_time;
	uint16_t mb_device1_Ref_Fall_Time;
	uint16_t mb_device1_Overload_setting;
	uint16_t mb_device1_Powerboard_Ctrl;
}holding_reg_params_t;

const mb_parameter_descriptor_t device_parameters[] = {
    // { Cid, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
    // Parameter: Data channel 0 : Data channel 0 = Voltage
		{	SIZE_CFG_MBREG_CID, STR("Drive ID"), STR("GPM"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
	        HOLD_OFFSET(mb_device1_DriveID), PARAM_TYPE_U16, 2, OPTS(0, 0xFFFF, 1), PAR_PERMS_READ_TRIGGER},
		{	COMMAND_WORD_MBREG_CID, STR("Command Word"), STR("hex"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
	        HOLD_OFFSET(mb_device1_CMD_Word), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	SPEED_REF_MBREG_CID, STR("Max Freq"), STR("Hz"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
	        HOLD_OFFSET(mb_device1_SpeedRef), PARAM_TYPE_U16, 2, OPTS(0, 300, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	REF_RAMP_RISE_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0C, 1,
	        HOLD_OFFSET(mb_device1_Ref_Rise_time), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER	},
		{	REF_RAMP_FALL_TIME_CID, STR("Ramp rise time"), STR("sec"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 13, 1,
	        HOLD_OFFSET(mb_device1_Ref_Fall_Time), PARAM_TYPE_U16, 2, OPTS(0, 50000, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	OVERLOAD_SETT_CID, STR("Overload Sett"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 14, 1,
			HOLD_OFFSET(mb_device1_Overload_setting), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
		{	POWER_CTRL_CID, STR("Power Ctrl"), STR("hex"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 15, 1,
	        HOLD_OFFSET(mb_device1_Powerboard_Ctrl), PARAM_TYPE_U16, 2, OPTS(0, 100, 1), PAR_PERMS_READ_WRITE_TRIGGER},
};
Does this work for you?

Re: ESP32 MODBUS descriptor CID field issue

Posted: Tue Jan 25, 2022 9:30 am
by Ashvajit.P
Yes the CID issue has gone now but my esp32 keeps resetting after the 4th parameter read every time with "StoreProhibited" error.

This issue only occurs when last two values of HOLD_OFFSET is mb_device1_Overload_setting and mb_device1_Powerboard_Ctrl, when i keep it zero request and response is working fine. It is also working in the case , when i am assigning offset of first element of the structure.

I think I am not able to understand how this HOLD_OFFSET works.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Wed Jan 26, 2022 11:22 am
by ESP_alisitsyn
@Ashvajit.P ,

The HOLD_OFFSET(field) macro just calculates the byte offset of `field` from beginning of `holding_reg_params_t` structure.
https://github.com/espressif/esp-idf/bl ... ster.c#L43
This offset is used as an instance to save the parameter data. So your parameter data read from slave will be packed into `field` instance as defined in data dictionary (Data Type, Data Size). See https://github.com/espressif/esp-idf/bl ... ter.c#L445 .

According to log the first 5 parameters are correctly read into the holding registers structure. In order to find the reason for a crash you need to check carefully your slave read/write function.

I guess you updated the object dictionary (decreased number of parameters as per my suggestion but did not change the maximum CID to read in the function.
See https://github.com/espressif/esp-idf/bl ... ter.c#L487 .

Please make sure that the number of CIDs matches a number of parameters in the data dictionary.

Let me know the result.

Thanks.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Wed Jan 26, 2022 1:50 pm
by ESP_alisitsyn
ESP_alisitsyn wrote:
Wed Jan 26, 2022 11:22 am
@Ashvajit.P ,

The HOLD_OFFSET(field) macro just calculates the byte offset of `field` from beginning of `holding_reg_params_t` structure.
https://github.com/espressif/esp-idf/bl ... ster.c#L43
This offset is used to calculate the instance address to save the parameter data. So your parameter data read from slave will be packed into `field` instance as defined in data dictionary (Data Type, Data Size). See https://github.com/espressif/esp-idf/bl ... ter.c#L445 .

According to log the first 5 parameters are correctly read into the holding registers structure. In order to find the reason for a crash you need to check carefully your slave read/write function.

I guess you updated the object dictionary decreased the number of parameters as per my suggestion but did not change the maximum CID to read in the function.
See https://github.com/espressif/esp-idf/bl ... ter.c#L487 .

Please make sure that the number of CIDs matches a number of parameters in the data dictionary.

Let me know the result.

Thanks.

Re: ESP32 MODBUS descriptor CID field issue

Posted: Fri Feb 11, 2022 12:32 pm
by Ashvajit.P
I did what you suggested and it is working now. It turns out I was using older project which was using timestamp and all other parameters in the structure which I see is updated in the newer version.
Although when I copied my working code from one project, it is showing MODBUS resource failure. Can you please help me with this.
This was not the issue when I was running the code in another project.