master salve implemtatation esp idf 4.0

alllllllllllllllllll
Posts: 12
Joined: Fri Jul 24, 2020 3:48 pm

master salve implemtatation esp idf 4.0

Postby alllllllllllllllllll » Fri Jul 24, 2020 4:10 pm

Hi everyone, regarding the code for ESP32 v4.0 Master (https://github.com/espressif/esp-idf/tr ... /mb_master), I would like to know how to read a slave variable; by RealTerm I'm able to see the response of the slave device containing the red value but i don't know how to store it. Where is it stored?

Let me know.

Thank you for your valuable advice.

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

Re: master salve implemtatation esp idf 4.0

Postby ESP_alisitsyn » Mon Jul 27, 2020 6:46 am

Hi @alllllllllllllllllll,

It supposed that device stores its specific data as device parameters of type (float, uint16_t, uint8_t, ascii, etc.) and its data mapped to Modbus register spaces (Holding registers, Input Registers, Coils, Discr inputs).
The master and slave examples contain instances for each type of Modbus register space and its data addresses by data dictionary:
https://github.com/espressif/esp-idf/bl ... ster.c#L88
The actual instances (structures that incapsulate device data) are located here:
https://github.com/espressif/esp-idf/bl ... rams.c#L10
This package contains data instances which are common for master and slave examples.

The example of data dictionary: The characteristic "Data_channel_0" below corresponds to parameter stored in slave device with address=MB_DEVICE_ADDR1 as input registers (MB_PARAM_INPUT) from modbus address 0, length of parameter in registers = 2 registers,
this parameter will be stored in the instance input_reg_params.input_data0 of float type, instance length in bytes = 4, Options defined, access for parameter set as R/W)
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
}
So, The Characteristic can be linked to any Modbus register or complex parameter within any slave and be stored in appropriate place or structure of device memory. This allows to integrate this approach easily with MQTT, MESH and other networks or protocols.

User can store parameters differently by modifying *_OFFSET(par) macro to calculate offset to actual parameter and modify the master_get_param_data() function to calculate the address of actual storage for each characteristic according to offset.

The data dictionary can be simplified to work with modbus registers instead of parameters.
In this case the data dictionary can be modified as:
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 },
}

Please see the following topic for more information:
https://esp32.com/viewtopic.php?f=13&t= ... 150#p63158
Let me know if you have further questions.

alllllllllllllllllll
Posts: 12
Joined: Fri Jul 24, 2020 3:48 pm

Re: master salve implemtatation esp idf 4.0

Postby alllllllllllllllllll » Mon Jul 27, 2020 3:26 pm

Hi ESP_alisitsyn, as you suggested, I modified the data dictionary in order to communicate with a modbus register, as follows

const mb_parameter_descriptor_t device_parameters[] = {
{
CID_HUMIDITY_1, STR("SH"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING , 8, 1,
HOLD_OFFSET(pippo), PARAM_TYPE_U16, 2, OPTS(-127, 128, 1), PAR_PERMS_READ
},


However, I've some troubles with the timeout error "eErrStatus = MB_MRE_TIMEDOUT" set by the function eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) (defined in portevent_m.c). My argument is that this error prevent to the read variable in Holding register "value_ptr" (I suppose that contain the temperature detected from my the slave device), to be correctly stored in the variable "value"; in fact
"error" , equal to 0x00000103, is different from ESP_OK= 0x00000000 (the segment below is defined in sense_modbus.c)

if (error == ESP_OK) {
// Copy the value to param
memcpy((void*)value, (void*)value_ptr, cid_info->instance_size);
cid_info->timestamp = sense_modbus_get_time_stamp_us();
}

Thanks to the debugger, I found out that error is not a ESP_ERR_INVALID_STATE error but rather a MB_MRE_TIMEDOUT error. I tried to change
both CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND and MB_RESPONSE_TIMEOUT(mb_size) in order to avoid MB_MRE_TIMEDOUT but nothing changed.



Thank for your valuable suggestions.

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

Re: master salve implemtatation esp idf 4.0

Postby ESP_alisitsyn » Tue Jul 28, 2020 8:30 am

Hi @alllllllllllllllllll,

Did you try rebase to v4.2 and check modbus there? Did you check communication between master and slave? I am asking this because communication can cause the same issue and v4.2 includes a lot of fixes for driver and modbus.
This sounds like known issues because of some modbus and driver fixes were not backported to v.4.0 correctly. I backported fixes of latest master to v4.0 manually but they are not ready to merge yet. On my side the fixes work just fine and code is free of the issues you mentioned. I can create the project that will incude most of fixes from v4.2 ported to v4.0. This will override existing freemodbus and UART driver of ESP_IDF v4.0. Are you interested to check this?

alllllllllllllllllll
Posts: 12
Joined: Fri Jul 24, 2020 3:48 pm

Re: master salve implemtatation esp idf 4.0

Postby alllllllllllllllllll » Wed Jul 29, 2020 9:20 am

Hi ESP_alisitsyn, unfortunately v4.2 was not completely compatible with Visual Studio (and Visual GDB as debugger), so I opted for v4.0.

Considering the attached file, Modbus communication between Master and Slave seems to work properly.

In the example you posted here

Code: Select all

read_modbus_parameter(CID_DEV_REG0, &register_data)
reads the value stored in &register_data. &register data is the passed as parameter to

Code: Select all

mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,(uint8_t*)par_data, &type)
as par_data. This fact allows me to conclude that the parameter "*value" in the function

Code: Select all

sense_modbus_read_value(uint16_t cid, void *value) 
is the field which contain the address of the value which is read (or written).

In mbc_serial_master.c the line

Code: Select all

// Set the buffer for callback function processing of received data
    mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;

should copy the value obtained from the slave response (the read value), in "data_ptr" the buffer of master "param_buffer[0]", whose data is then copied into "value" by means of the function "mbc_serial_master_set_param_data". I'm not completely sure about this fact.

Can you explain me exactly where the data read in the slave response is copied and how the slave response is detected?
I suspect that this happen in

Code: Select all

eMBMasterWaitRequestFinish( );
where the last detected event is the slave response.

It would be great If you could fix the bug in the v4.0 and post here a corrected version of the code.
If the Timeout error is fixed, then"value" in the function

Code: Select all

sense_modbus_read_value(uint16_t cid, void *value) 
contains the desired read value in the register?

Thank you for your valuable help.
Attachments
modbus_communication.png
modbus_communication.png (182.93 KiB) Viewed 290 times

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

Re: master salve implemtatation esp idf 4.0

Postby ESP_alisitsyn » Thu Jul 30, 2020 5:22 am

Hi @alllllllllllllllllll,

1.

Code: Select all

esp_err_t sense_modbus_read_value(uint16_t cid, void *value);
The *value - is pointer to actual instance of parameter or CID where to save read value but it also cached in

Code: Select all

characteristic_descriptor_t* cid_info->instance_ptr
.
2. For example for holding registers the actual MB transaction starts here:

Code: Select all

eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
3. The FSM of Modbus is processed by

Code: Select all

eMBErrorCode eMBMasterPoll( void )
function. On each event it performs appropriate action and then goes next state.
The

Code: Select all

eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
function just waits of final event means processing completed (timeout, error or success).
4. Once response from slave received by serial task, the frame is checked by `usMBMasterPortSerialRxPoll()` function which generates the EV_MASTER_FRAME_RECEIVED event.
Then frame is checked by

Code: Select all

peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
function which translates received ASCII or RTU frame into input buffer and then FSM goes to EV_MASTER_EXECUTE state.
5. The

Code: Select all

eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
calls the appropriate handler for the function code which then calls R/W callback function located in correspond modbus controller port:

Code: Select all

eMBErrorCode eMBRegHoldingCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
This function performs the actual data copy from response. It has access to mbcontroller interface structure and uses saved mbm_opts->mbm_reg_buffer_ptr address as a source for data.
When we get the data it will be copied to actual instance here:

Code: Select all

static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, uint8_t* value_ptr, uint8_t *type)
This is short description on how it works. I plan to share architecture details related to processing later.

Please use the project posted here which includes the latest fixes from v4.2 ported to v4.0.

Note: Please enable CONFIG_FMB_TIMER_ISR_IN_IRAM to avoid serial handler delays if you use NVS flash functions.
CONFIG_FMB_TIMER_PORT_ENABLED should be disabled to avoid failures when you have other tasks started on the same CPU. This increases delays of MB processing but allows to avoid issues in your application.
CONFIG_FMB_SERIAL_TASK_PRIO - should be set to your (highest task priority + 1) executed on the same CPU.
The zip archive contains the complete project which overrides existing freemodbus component and uart driver for v4.0.
You could replace the sources in ESP_IDF folders with the *.c/h files from components folder of this project.

This project has been tested on my side and works reliable. However please let me know if you still have troubles with this.
I suppose it will help you to solve your issues with VisualGdb and Modbus.
Attachments
simple_modbus_fixesv40.zip
simple_modbus_includes latest mb fix for ESP_IDF v4.0
(186.53 KiB) Downloaded 11 times

alllllllllllllllllll
Posts: 12
Joined: Fri Jul 24, 2020 3:48 pm

Re: master salve implemtatation esp idf 4.0

Postby alllllllllllllllllll » Fri Jul 31, 2020 7:22 am

Hi ESP_alisitsyn, fortunatley I've been able to use v4.2 and hence I've solved the problem. Thank you for your time and for the explanation about the code in the previous post (I think it is useful in every case).

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

Re: master salve implemtatation esp idf 4.0

Postby ESP_alisitsyn » Fri Jul 31, 2020 8:22 am

Hi alllllllllllllllllll,

Good to hear it helps. In spite your code works with v4.2, can I ask you to test the project for v4.0 on your side if you have some time? It is better to test it on user side as well before merge to v4.0. Thanks.

Who is online

Users browsing this forum: ytan86 and 21 guests