MODBUS and serial disable

We use custom board with NRF52840 and a MODBUS CO2 sensor. We are struggling with power consumption when the serial is enabled. The goal is to take measurements and then put the board to sleep, after a certain time, wake board up and take new measurements. Currently, the idle power consumption is about 1.2 mA. When I disabled the serial in the config file, we got the power consumption down to 300 µA. However, MODBUS requires the serial. Is it possible to disable the serial before putting the board to sleep and reinitialize it after waking up so that MODBUS continues to work?

Parents Reply Children
  • Yes .. I toke MODBUS RTU Client Sample as base for my code. I tried modbus_disable before sleep and reinit after wake, but it does still not communicate anymore (the error -116 should be timeout).

    I have right now only one DK board and I can't try the MODBUS RTU Server and Client sample with UART sleep -- I think there would be the same problem.

  • I'm just playing a bit around with the Modbus RTU client and server sample using two DKs. I don't have access to my PPK today but I see no issue when I add the following

    pm_device_action_run(uart,PM_DEVICE_ACTION_SUSPEND);
    
    k_msleep(sleep);
    
    pm_device_action_run(uart,PM_DEVICE_ACTION_RESUME);

    Log

    Client side
    [00:00:15.360,961] <inf> mbc_sample: Coils state 0x07
    [00:00:20.388,000] <inf> mbc_sample: Coils state 0x00
    server side
    [00:00:18.276,062] <inf> mbs_sample: Coil write, addr 2, 1
    [00:00:23.289,672] <inf> mbs_sample: Coil read, addr 0, 1
    [00:00:23.289,672] <inf> mbs_sample: Coil read, addr 1, 1
    [00:00:23.289,703] <inf> mbs_sample: Coil read, addr 2, 1
    [00:00:23.303,222] <inf> mbs_sample: Coil write, addr 0, 0
    [00:00:23.303,222] <inf> mbs_sample: Coil write, addr 1, 0
    [00:00:23.303,222] <inf> mbs_sample: Coil write, addr 2, 0
    [00:00:28.316,864] <inf> mbs_sample: Coil read, addr 0, 0
    [00:00:28.316,864] <inf> mbs_sample: Coil read, addr 1, 0
    [00:00:28.316,894] <inf> mbs_sample: Coil read, addr 2, 0
    [00:00:28.329,193] <inf> mbs_sample: Coil write, addr 0,

  • Hmm .. strange. OK .. I try again here,

  • Could you upload the logs, prj.conf and the modbus part of your application just in case there is something there 

    Regards

    Runar

  • Strange .. I did a test with DK and my sensor and it is working OK. It is something in my custom boards code then, that is not functioning. I will check what is the problem.

    I tried with that:

    #include <zephyr/kernel.h>
    #include <zephyr/sys/util.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/pm/pm.h>
    #include <zephyr/pm/device.h>
    #include <zephyr/pm/state.h>
    #include <zephyr/modbus/modbus.h>
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(mbc_sample, LOG_LEVEL_DBG);
    
    static int client_iface;
    
    const static struct modbus_iface_param client_param = {
    	.mode = MODBUS_MODE_RTU,
    	.rx_timeout = 10000,
    	.serial = {
    		.baud = 9600,
    		.parity = UART_CFG_PARITY_NONE,
    		.stop_bits_client = UART_CFG_STOP_BITS_1,
    		},
    };
    
    #define SENSOR_UID 104
    #define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
    
    static const struct device *const uart_modbus =  DEVICE_DT_GET(DT_NODELABEL(uart0));
    
    static int init_modbus_client(void)
    {
    	const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
    
    	client_iface = modbus_iface_get_by_name(iface_name);
    
    	return modbus_init_client(client_iface, client_param);
    }
    
    void measure_co2() {
    	uint16_t input_reg_data[4] = {0};
    	int err;
    
    	init_modbus_client();
    
    	while(true){
    		//Read CO2 value
    		err = modbus_read_input_regs(client_iface, SENSOR_UID, 0, input_reg_data, 4);
    		
    		if (err != 0) {
    			LOG_ERR("MODBUS error %d", err);
    			if(true){
    				LOG_INF("Trying once more...");
    			}else{
    			break;
    			}
    		} else {
    
    			uint16_t co2_value = input_reg_data[3];
    
    			if (input_reg_data[0] != 0)	{
    			}else{
    				LOG_INF("CO2 Level: %d", co2_value);
    
    			break;
    			}
    		}
    	k_sleep(K_MSEC(1000));
    	}
    }
    
    int main(void)
    {
    	int err = 0;
    	
    	for (int i=1;i<5;i++){
    		measure_co2();
    		
    		k_sleep(K_MSEC(1000));
    		
    		err = pm_device_action_run(uart_modbus, PM_DEVICE_ACTION_SUSPEND);
    		if(err) LOG_INF("PM Error: %d",err);
    		
    		k_sleep(K_MSEC(5000));
    		LOG_INF("Sleep 5 sec...");
    
    		err = pm_device_action_run(uart_modbus, PM_DEVICE_ACTION_RESUME);
    		if(err) LOG_INF("PM Error: %d",err);
    				
    		measure_co2();
    		
    		k_sleep(K_MSEC(1000));
    	}
    
    }

    And the log is:

    00> *** Booting nRF Connect SDK v3.5.99-ncs1 ***
    00> [00:00:00.538,177] <inf> modbus_serial: RTU timeout 4010 us
    00> [00:00:00.548,278] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:00.548,278] <err> mbc_sample: MODBUS error -116
    00> [00:00:00.548,278] <inf> mbc_sample: Trying once more...
    00> [00:00:01.558,471] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:01.558,502] <err> mbc_sample: MODBUS error -116
    00> [00:00:01.558,502] <inf> mbc_sample: Trying once more...
    00> [00:00:02.558,624] <inf> mbc_sample: CO2 Level: 674
    00> [00:00:08.558,746] <inf> mbc_sample: Sleep 5 sec...
    00> [00:00:08.558,776] <err> modbus: Interface already used
    00> [00:00:08.568,878] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:08.568,878] <err> mbc_sample: MODBUS error -116
    00> [00:00:08.568,878] <inf> mbc_sample: Trying once more...
    00> [00:00:09.568,969] <inf> mbc_sample: CO2 Level: 674
    00> [00:00:10.569,061] <err> modbus: Interface already used
    00> [00:00:10.579,193] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:10.579,193] <err> mbc_sample: MODBUS error -116
    00> [00:00:10.579,193] <inf> mbc_sample: Trying once more...
    00> [00:00:11.579,284] <inf> mbc_sample: CO2 Level: 674
    00> [00:00:17.579,437] <inf> mbc_sample: Sleep 5 sec...
    00> [00:00:17.579,467] <err> modbus: Interface already used
    00> [00:00:17.589,569] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:17.589,569] <err> mbc_sample: MODBUS error -116
    00> [00:00:17.589,569] <inf> mbc_sample: Trying once more...
    00> [00:00:18.589,660] <inf> mbc_sample: CO2 Level: 675
    00> [00:00:19.589,752] <err> modbus: Interface already used
    00> [00:00:19.599,884] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:19.599,884] <err> mbc_sample: MODBUS error -116
    00> [00:00:19.599,884] <inf> mbc_sample: Trying once more...
    00> [00:00:20.599,975] <inf> mbc_sample: CO2 Level: 675
    00> [00:00:26.600,128] <inf> mbc_sample: Sleep 5 sec...
    00> [00:00:26.600,158] <err> modbus: Interface already used
    00> [00:00:26.610,260] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:26.610,260] <err> mbc_sample: MODBUS error -116
    00> [00:00:26.610,260] <inf> mbc_sample: Trying once more...
    00> [00:00:27.610,351] <inf> mbc_sample: CO2 Level: 675
    00> [00:00:28.610,443] <err> modbus: Interface already used
    00> [00:00:28.620,574] <wrn> modbus: Client wait-for-RX timeout
    00> [00:00:28.620,574] <err> mbc_sample: MODBUS error -116
    00> [00:00:28.620,574] <inf> mbc_sample: Trying once more...
    00> [00:00:29.620,666] <inf> mbc_sample: CO2 Level: 675

    The sensor is not answering always in first try, and thats OK. 

    Anyway.. thanks for testing it and giving good advise.

Related