How to set up simple Modbus communication?

waterfox
Posts: 20
Joined: Sun Mar 22, 2020 10:19 pm

How to set up simple Modbus communication?

Postby waterfox » Fri Apr 10, 2020 8:24 pm

Hello together,

I'm working at an Modbus project in the ESP IDF 4.1.

Where do I find the documentation how to Write Single Registers and Read Holding Registers?
I have already tested it with example Master code, but it didn't work. I were not able to find how to write Single Registers.

For example I want to do the following:
- Device 1
- Write Single Register
- Address 0
- Value 3000

How do I set it up correctly?

waterfox
Posts: 20
Joined: Sun Mar 22, 2020 10:19 pm

Re: How to set up simple Modbus communication?

Postby waterfox » Mon Apr 13, 2020 4:46 pm

After testing different code over the weekend, I'm still not able to communicate with my device.
Either reading registers nor writing ones.

- How do I set the stop bit to 2? I didn't find any option for this like in uart.

For write input registers I've tried the following:

Code: Select all

mbc_master_set_parameter(uint16_t cid, char *name, uint8_t *value, uint8_t *type)
Here is my problem how to set the cid right to write to register. Here are only variables for reading registers.

Code: Select all

const mb_param_request_t setparam = {1,6,0,1}; //slave adr, command, start reg, number of registers
float value = 5000;
err = mbc_master_send_request(&setparam, &value);
Here I also have the problem that I don't now wich is the right command for writing registers. (Referring to the modbus protocol and the datasheet form my device i tried 3 (Read Holding Register) and 6 (Write Single Register))


I've also connected my logic analyzer and see that my devices answers. But I'm not able to decode the binary code wich is send over Modbus.


Maybe with this information someone is now able to help me with my Problem?

EDIT: Small update:
I found out that i have set my Logic analyzer wrong. After changing the variable value from "float" to "int" im able to set the register.

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: How to set up simple Modbus communication?

Postby ESP_alisitsyn » Tue May 12, 2020 9:08 am

Hi @waterfox,
- How do I set the stop bit to 2? I didn't find any option for this like in uart.
The modbus master supports UART_STOP_BITS_1 option set in the serial port components\freemodbus\port\portserial_m.c:xMBMasterPortSerialInit(). However it should not cause any communication issues.
Here I also have the problem that I don't now wich is the right command for writing registers. (Referring to the modbus protocol and the datasheet form my device i tried 3 (Read Holding Register) and 6 (Write Single Register))
The master operation function located in the example can explain how to read and write modbus registers:
examples\protocols\modbus\serial\mb_master\main\master.c:master_operation_func()

The function below is used to read registers into value parameter:

Code: Select all

         
                    // Read modbus parameter described by object dictionary CID into value parameter
                    err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
                                                                            (uint8_t*)value, &type);
This one is used to write registers:

Code: Select all

	// Write value into characteristic defined as cid mapped to corresponded modbus parameter
		err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
                                                              			(uint8_t*)value, &type);
Before start of communication you need to create the data dictionary (see the device_parameters in the example) for your device which maps the CID to actual modbus registers.
The parameter structures which contain instances for parameters can be assigned in the object dictionary for each CID using HOLD_OFFSET(holding_data2) macro as example (one macro per register area type). See the examples\protocols\modbus\serial\mb_example_common\modbus_params.c::holding_reg_params for example parameters.

The modbus stack uses modbus command 16 (Write Multiple Holding Registers) to write registers as more universal. The 6 (Write Single Register) command support can also be added into stack if required.

Let me know if you need more help with Modbus implementation in ESP-IDF.

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Re: How to set up simple Modbus communication?

Postby maldus » Wed Jun 17, 2020 1:29 pm

Hello ESP_alisitsyn,
The modbus stack uses modbus command 16 (Write Multiple Holding Registers) to write registers as more universal. The 6 (Write Single Register) command support can also be added into stack if required.
What do you mean it can be added to the stack if required? Is there a way for me to customize the underlying stack, or was that an offer to extend the existing library?

waterfox
Posts: 20
Joined: Sun Mar 22, 2020 10:19 pm

Re: How to set up simple Modbus communication?

Postby waterfox » Wed Jun 17, 2020 1:59 pm

What I'm using for reading and writing registers now is this function.

Code: Select all


    esp_err_t err = ESP_OK;
    

    
     mb_param_request_t setparam = {1, 6, 0, 1};  //Device Adress, Func code (3 Read Holding Reg, 6 Write Input Reg), start Adr, reg length
    
int value = 3000;  //Value to set or Variable for Output
  


    err = mbc_master_send_request(&setparam, value);
    switch (err)
    {
    case ESP_OK:
        ESP_LOGI(TAG, "Set to Value = %d", Value);
        break;

    case ESP_ERR_INVALID_ARG:
        ESP_LOGE(TAG, "invalid Argument");  
        break;  
    
    default:
       break;
    }

Have a look at mb_param_request_t at the docs.

At the moment I havn't spend enough time on it to figure out how to work with CID'S.

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Re: How to set up simple Modbus communication?

Postby maldus » Wed Jun 17, 2020 3:46 pm

Many thanks for the clarification. I find the section of the documentation about Modbus quite cryptic, and in fact I don't think it describes the content of the structure `mb_param_request_t`. The source code is quite simple however, so I think I got it!

Since I'm here, are you aware of any way get the exact error response if the function requested could not be completed (e.g. if I try to write a register outside of its allowed range)?

waterfox
Posts: 20
Joined: Sun Mar 22, 2020 10:19 pm

Re: How to set up simple Modbus communication?

Postby waterfox » Wed Jun 17, 2020 3:53 pm

I think that depends on your device. My device will return a value which is out of range. But I'm not sure if this is modbus standard.

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: How to set up simple Modbus communication?

Postby ESP_alisitsyn » Thu Jul 23, 2020 4:22 pm

Hello waterfox,
What do you mean it can be added to the stack if required? Is there a way for me to customize the underlying stack, or was that an offer to extend the existing library?
You don't need to extend library. In order to read registers from your device you can use command "Read Holding Registers 0x03", and "Write Multiple Holding Registers 0x10". The modbus controller is the common interface above Modbus API for all ports which allows to read and write any parameters of your slave device. Additionally it allows to integrate this functionality with other components or networks adding abstraction object "characteristic" with its CID - characteristic iD. So you do not need to go deeper to lower layer of Modbus port and read description of its parameters (`mb_param_request_t`). I prepared the simplified example to read and write two holding registers of the device. The example has just one file and I removed as much as possible from there. Hope it will help you to understand API and read your device data.

Per your request to read rite holding register:
- Device 1
- Write Single Register
- Address 0
- Value 3000

The device address, reg type, start address of register, number of registers defined as: `MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,`
```
// Example Data (Object) Dictionary for Modbus parameters
const mb_parameter_descriptor_t device_parameters[] = {
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length,
// Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
{ CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS( 0,0,0 ), PAR_PERMS_READ_WRITE_TRIGGER },
...
```
To write register you can use a call:
```
register_data = 3000;
err = write_modbus_parameter(CID_DEV_REG0, &register_data);
err = read_modbus_parameter(CID_DEV_REG0, &register_data);
```
Attachments
simple_modbus_example.zip
Simple example to read and write holding registers of slave.
(12.13 KiB) Downloaded 766 times

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: How to set up simple Modbus communication?

Postby ESP_alisitsyn » Fri Jul 24, 2020 4:57 am

waterfox wrote:
Wed Jun 17, 2020 3:53 pm
I think that depends on your device. My device will return a value which is out of range. But I'm not sure if this is modbus standard.
There are two possible situations:
1. Read/write the register outside of supported address space: the Modbus stack returns exception response back with the most significant bit set to 1 in the command field of PDU (0x80 + send command). The register space supported by device is described in its protocol (memory map) provided with device.
2. Read/write register from the middle of complex parameter of the device: Modbus stack returns the correct answer with value which may be out of range (depends on memory map of concrete device). Usually the parameters are stored in the device memory using different types (like: float, uint16_t, uint8_t and etc.). These complex values are mapped to Modbus register space according to memory map of the device which is defined in the documentation for device. The parameter description table in the modbus_master example can describe complex parameters of device as well as register values from each register space (input registers, holding registers, coils, disrete inputs) to allow read and write parameters and registers using api calls. See simple example.

Who is online

Users browsing this forum: No registered users and 88 guests