How to program Modbus Master
How to program Modbus Master
Hello everybody,
I am trying to figure how to program an ESP32 as a Master Modbus device.
The code I found in the esp sdk (mbcontroller.h) seems to be only for the Slave.
Can you help me with a code example of the Master Modbus ?
I can program in Arduino IDE or with the C Espressif toolchain as well.
I appreciate your help.
Best regards,
Eduardo
Buenos Aires, Argentina
I am trying to figure how to program an ESP32 as a Master Modbus device.
The code I found in the esp sdk (mbcontroller.h) seems to be only for the Slave.
Can you help me with a code example of the Master Modbus ?
I can program in Arduino IDE or with the C Espressif toolchain as well.
I appreciate your help.
Best regards,
Eduardo
Buenos Aires, Argentina
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to program Modbus Master
Hello Eduardo,
There are plans to support Modbus Master RTU and TCP in ESP-IDF v4.0, but it was postponed. However there is a "Work In Progress" version of Modbus Master and Slave with examples. I can share it with you. Would you like to get the WIP implementation or it is ok for you to wait for official release?
--
Alexey
There are plans to support Modbus Master RTU and TCP in ESP-IDF v4.0, but it was postponed. However there is a "Work In Progress" version of Modbus Master and Slave with examples. I can share it with you. Would you like to get the WIP implementation or it is ok for you to wait for official release?
--
Alexey
-
- Posts: 48
- Joined: Mon Apr 30, 2018 5:32 pm
Re: How to program Modbus Master
Hello Alexy,
Could you please share the WIP implemenation for the Modbus mater RTU with me also ?
Thank you in advance,
Adham
Could you please share the WIP implemenation for the Modbus mater RTU with me also ?
Thank you in advance,
Adham
ESP_alisitsyn wrote: ↑Mon Feb 04, 2019 8:48 amHello Eduardo,
There are plans to support Modbus Master RTU and TCP in ESP-IDF v4.0, but it was postponed. However there is a "Work In Progress" version of Modbus Master and Slave with examples. I can share it with you. Would you like to get the WIP implementation or it is ok for you to wait for official release?
--
Alexey
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to program Modbus Master
Hello Adham,
Sure, I can share the implementation with you. Please find this topic and WIP implementation there:
https://www.esp32.com/viewtopic.php?f=1 ... ter+modbus
The official support will be released later but API should be unchanged. It includes IDF component with common interface for Modbus Master and Slave. Please use it with official Espressif license.
--
Alexey
Sure, I can share the implementation with you. Please find this topic and WIP implementation there:
https://www.esp32.com/viewtopic.php?f=1 ... ter+modbus
The official support will be released later but API should be unchanged. It includes IDF component with common interface for Modbus Master and Slave. Please use it with official Espressif license.
--
Alexey
-
- Posts: 48
- Joined: Mon Apr 30, 2018 5:32 pm
Re: How to program Modbus Master
Thank you Alexy
ESP_alisitsyn wrote: ↑Mon Mar 18, 2019 10:04 amHello Adham,
Sure, I can share the implementation with you. Please find this topic and WIP implementation there:
https://www.esp32.com/viewtopic.php?f=1 ... ter+modbus
The official support will be released later but API should be unchanged. It includes IDF component with common interface for Modbus Master and Slave. Please use it with official Espressif license.
--
Alexey
-
- Posts: 3
- Joined: Fri Sep 13, 2019 5:19 pm
Re: How to program Modbus Master
Hello Alexey,
I appreciate your sharing of the WIP modbus master code here, and was wondering if you could answer a question regarding the code here? It seems whenever my CID table contains more than 32 elements, I start getting assertion failures in the freertos queue implementation when trying to read certain registers. Some still work fine, and it always fails on the same registers, but shrinking down the CID table back to a size of 32 or less, results in all registers reading correctly.
Thanks,
Spencer
I appreciate your sharing of the WIP modbus master code here, and was wondering if you could answer a question regarding the code here? It seems whenever my CID table contains more than 32 elements, I start getting assertion failures in the freertos queue implementation when trying to read certain registers. Some still work fine, and it always fails on the same registers, but shrinking down the CID table back to a size of 32 or less, results in all registers reading correctly.
Thanks,
Spencer
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to program Modbus Master
Hello Spencer,
Thank you for this question. I think I know what is the reason for this issue. However could you make some change in your code to help me check this bug?
Please in the your device_params.c file in the device_parameters[] table change the offset to parameter instance to 0 (HOLD_OFFSET(par_name) change to 0 for all the parameters). This will allow to create instance for each parameter on the fly. Below is the example:
```
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
{ CID_DATA_CHAN_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
0, PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HUMIDITY_1, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
0, PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{....... all other parameters in your table with 0 offset to instance.... but more than 32 elements}
};
```
Then compile master example, flash it into board and check communication again. Let me know the result.
Thank you.
--
Alex
Thank you for this question. I think I know what is the reason for this issue. However could you make some change in your code to help me check this bug?
Please in the your device_params.c file in the device_parameters[] table change the offset to parameter instance to 0 (HOLD_OFFSET(par_name) change to 0 for all the parameters). This will allow to create instance for each parameter on the fly. Below is the example:
```
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
{ CID_DATA_CHAN_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
0, PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HUMIDITY_1, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
0, PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{....... all other parameters in your table with 0 offset to instance.... but more than 32 elements}
};
```
Then compile master example, flash it into board and check communication again. Let me know the result.
Thank you.
--
Alex
-
- Posts: 3
- Joined: Fri Sep 13, 2019 5:19 pm
Re: How to program Modbus Master
Hey Alex,
Thank you for the response. That does fix the modbus code. It seems the one of the instance pointers is being calculated incorrectly, and the line ```memset((void*)value_ptr, 0, cid_info->instance_size);``` in ```sense_modbus_read_value``` partially overwrites a pointer tied to one of my characteristics.
Best,
Spencer
Thank you for the response. That does fix the modbus code. It seems the one of the instance pointers is being calculated incorrectly, and the line ```memset((void*)value_ptr, 0, cid_info->instance_size);``` in ```sense_modbus_read_value``` partially overwrites a pointer tied to one of my characteristics.
Best,
Spencer
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to program Modbus Master
Hi Spencer,
Thank you. Unfortunately this is a bug in the code that came after rebase and squesh of some commits during development. The root reason is in sense_modbus.c file in function ```sense_modbus_get_param_data(const mb_parameter_descriptor_t* param_descriptor)```. It calculates instance address based on offset of parameter incorrectly because of bug during squesh. In order to fix it temporary, please change its code to:
```
// The function to get pointer to parameter storage (instance) according to parameter description table
static void* sense_modbus_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
{
assert(param_descriptor != NULL);
void* instance_ptr = NULL;
if (param_descriptor->param_offset != 0) {
switch(param_descriptor->mb_param_type)
{
case MB_PARAM_HOLDING:
instance_ptr = (void*)((uint32_t)&holding_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_INPUT:
instance_ptr = (void*)((uint32_t)&input_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_COIL:
instance_ptr = (void*)((uint32_t)&coil_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_DISCRETE:
instance_ptr = (void*)((uint32_t)&discrete_reg_params + param_descriptor->param_offset - 1);
break;
default:
instance_ptr = NULL;
break;
}
} else {
instance_ptr = malloc((size_t)(param_descriptor->param_size));
}
return instance_ptr;
}
```
This bug is fixed but not merged yet and will be fixed as soon as possible and backported to previous releases.
Thank you!
--
Alex
Thank you. Unfortunately this is a bug in the code that came after rebase and squesh of some commits during development. The root reason is in sense_modbus.c file in function ```sense_modbus_get_param_data(const mb_parameter_descriptor_t* param_descriptor)```. It calculates instance address based on offset of parameter incorrectly because of bug during squesh. In order to fix it temporary, please change its code to:
```
// The function to get pointer to parameter storage (instance) according to parameter description table
static void* sense_modbus_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
{
assert(param_descriptor != NULL);
void* instance_ptr = NULL;
if (param_descriptor->param_offset != 0) {
switch(param_descriptor->mb_param_type)
{
case MB_PARAM_HOLDING:
instance_ptr = (void*)((uint32_t)&holding_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_INPUT:
instance_ptr = (void*)((uint32_t)&input_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_COIL:
instance_ptr = (void*)((uint32_t)&coil_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_DISCRETE:
instance_ptr = (void*)((uint32_t)&discrete_reg_params + param_descriptor->param_offset - 1);
break;
default:
instance_ptr = NULL;
break;
}
} else {
instance_ptr = malloc((size_t)(param_descriptor->param_size));
}
return instance_ptr;
}
```
This bug is fixed but not merged yet and will be fixed as soon as possible and backported to previous releases.
Thank you!
--
Alex
-
- Posts: 3
- Joined: Fri Sep 13, 2019 5:19 pm
Re: How to program Modbus Master
Hey Alex,
Thanks for the response! That works as well, ended up changing everything to follow the format of:
```
instance_ptr = ((void*)&holding_reg_params + param_descriptor->param_offset - 1);
```
which also works fine.
Thanks for the assistance!
Best,
Spencer
Thanks for the response! That works as well, ended up changing everything to follow the format of:
```
instance_ptr = ((void*)&holding_reg_params + param_descriptor->param_offset - 1);
```
which also works fine.
Thanks for the assistance!
Best,
Spencer
Who is online
Users browsing this forum: No registered users and 96 guests