Page 1 of 1

ESP32 Modbus RTU broadcast is not supported if it is

Posted: Fri Apr 19, 2024 1:08 pm
by steevke
I'm porting an application to the ESP32 platform and the application uses ModBus RTU broadcasts (sending writing commands to slave address 0). I am not using the CID approach but use mbc_master_send_request() directly.

If the first command sent is a broadcast (slave addrss == 0) the ESP-IDF modbus implementation throws an error and crashes:
E (990) MB_PORT_COMMON: eMBMasterPoll(394): receive buffer initialization fail.

Steps to reproduce:
1) Create a simple modbus master project based on the template.
2) change the main function to

Code: Select all

void app_main(void)
{
  esp_err_t               err = 0;
  mb_param_request_t      req = {};
  uint16_t                data[10];

  data[0] = 0x03;

  ESP_ERROR_CHECK(master_init());
  vTaskDelay(5);

  while (1)
  {
    // FIRST send the BROADCAST and THEN try to send to slave 25
    // populate the modbus request
    req.slave_addr        =  0;               // broadcast
    req.reg_start         =  0;               // Start at 0
    req.reg_size          =  1;               // 1 to test ??
    req.command           = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
    err                   = mbc_master_send_request(&req, (void *)&data[0]);
    ESP_LOGI("TEST  0", "Modbus result code: (%d)", (int)err);
    vTaskDelay(5);
    // populate the modbus request
    req.slave_addr        = 25;               // slave address
    req.reg_start         =  0;               // Start at 0
    req.reg_size          =  1;               // 1 to test ??
    req.command           = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
    err                   = mbc_master_send_request(&req, (void *)&data[0]);
    ESP_LOGI("TEST 25", "Modbus result code: (%d)", (int)err);
    vTaskDelay(1000);
  }
}
Running this will lead to:

Code: Select all

I (378) app_start: Starting scheduler on CPU0
I (383) app_start: Starting scheduler on CPU1
I (383) main_task: Started on CPU0
I (393) main_task: Calling app_main()
I (393) uart: queue free spaces: 20
I (453) MASTER_TEST: Modbus master stack initialized...
E (703) MB_PORT_COMMON: eMBMasterPoll(394): receive buffer initialization fail.
(and then nothing anymore)
However, if you FIRST address a "normal" slave device and then send a broadcast it works as intended:

Code: Select all

  while (1)
  {
    // FIRST send to slave 25 and THEN do the BROADCAST
    // populate the modbus request
    req.slave_addr        = 25;               // slave address
    req.reg_start         =  0;               // Start at 0
    req.reg_size          =  1;               // 1 to test ??
    req.command           = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
    err                   = mbc_master_send_request(&req, (void *)&data[0]);
    ESP_LOGI("TEST 25", "Modbus result code: (%d)", (int)err);
    vTaskDelay(5);
    // populate the modbus request
    req.slave_addr        =  0;               // broadcast
    req.reg_start         =  0;               // Start at 0
    req.reg_size          =  1;               // 1 to test ??
    req.command           = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
    err                   = mbc_master_send_request(&req, (void *)&data[0]);
    ESP_LOGI("TEST  0", "Modbus result code: (%d)", (int)err);
    vTaskDelay(1000);
  }

Code: Select all

I (378) app_start: Starting scheduler on CPU0
I (383) app_start: Starting scheduler on CPU1
I (383) main_task: Started on CPU0
I (393) main_task: Calling app_main()
I (393) uart: queue free spaces: 20
I (453) MASTER_TEST: Modbus master stack initialized...
I (513) TEST 25: Modbus result code: (0)
I (763) TEST  0: Modbus result code: (0)
I (10773) TEST 25: Modbus result code: (0)
I (11023) TEST  0: Modbus result code: (0)
Any ideas (other than do a dummy read / write first?)

Thanks.

Steven