Battery Sample - runtime error "voltage: setup: -134"

Hello, 

I'm building the sample Measure battery voltage on a custom board, and I have an error voltage: setup: -134  at runtime.

SEGGER J-Link V7.94i - Real time terminal output
SEGGER J-Link (unknown) V1.0, SN=1050264300
Process: JLink.exe
[00:00:00.390,777] <err> voltage: setup: -134
*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:04.254,882] <inf> BATTERY: Setup AIN2 got 0
[00:00:04.254,882] <inf> BATTERY: Battery setup: 0 1
[00:00:04.262,878] <inf> BATTERY: raw 1348 ~ 296 mV => 3256 mV


The overlay file is configure as explained in the sample:
/{
        vbatt {
                compatible = "voltage-divider";
                io-channels = <&adc 2>;
                output-ohms = <100000>; // 100k
                full-ohms = <(100000 + 1000000)>; // 100k + 1M
                power-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
        };
};

&adc {
        status = "okay";
};

And the code in the sample has not been changed.

I use the SDK v2.9.0


From what I can trace, the compatible = "voltage-divider"; will configure the .config with DT_HAS_VOLTAGE_DIVIDER_ENABLED, therefore enabling the "voltage_divider" folder located in <zephyr/drivers/sensors/voltage_divider>.

The error comes from the file voltage.c, more specifically the initialisation function called by the macro DT_INST_FOREACH_STATUS_OKAY(VOLTAGE_INIT)

static int voltage_init(const struct device *dev)
{
	const struct voltage_config *config = dev->config;
	struct voltage_data *data = dev->data;
	int ret;

	if (!adc_is_ready_dt(&config->voltage.port)) {
		LOG_ERR("ADC is not ready");
		return -ENODEV;
	}

	if (config->gpio_power.port != NULL) {
		if (!gpio_is_ready_dt(&config->gpio_power)) {
			LOG_ERR("Power GPIO is not ready");
			return -ENODEV;
		}
	}

	ret = adc_channel_setup_dt(&config->voltage.port);
	if (ret != 0) {
		LOG_ERR("setup: %d", ret);
		return ret;
	}

	ret = adc_sequence_init_dt(&config->voltage.port, &data->sequence);
	if (ret != 0) {
		LOG_ERR("sequence init: %d", ret);
		return ret;
	}

	data->sequence.buffer = &data->raw;
	data->sequence.buffer_size = sizeof(data->raw);

	return pm_device_driver_init(dev, pm_action);
}

#define VOLTAGE_INIT(inst)                                                                         \
	static struct voltage_data voltage_##inst##_data;                                          \
                                                                                                   \
	static const struct voltage_config voltage_##inst##_config = {                             \
		.voltage = VOLTAGE_DIVIDER_DT_SPEC_GET(DT_DRV_INST(inst)),                         \
		.gpio_power = GPIO_DT_SPEC_INST_GET_OR(inst, power_gpios, {0}),                    \
	};                                                                                         \
                                                                                                   \
	PM_DEVICE_DT_INST_DEFINE(inst, pm_action);                                                 \
                                                                                                   \
	SENSOR_DEVICE_DT_INST_DEFINE(inst, &voltage_init, PM_DEVICE_DT_INST_GET(inst),             \
			      &voltage_##inst##_data, &voltage_##inst##_config, POST_KERNEL,       \
			      CONFIG_SENSOR_INIT_PRIORITY, &voltage_api);

DT_INST_FOREACH_STATUS_OKAY(VOLTAGE_INIT)

The function adc_channel_setup_dt(&config->voltage.port) will fail as it is called POST_KERNEL and the parameters of the ADC are not configured yet.

The driver for adc is <zephyr/drivers/adc/adc_nrfx_saadc> and the function:

/* Implementation of the ADC driver API function: adc_channel_setup. */
static int adc_nrfx_channel_setup(const struct device *dev,
				  const struct adc_channel_cfg *channel_cfg)
{
...
}


implement the adc_channel_setup.

I'm not sure where the error is coming from next, but I guess from
int ret = adc_convert_acq_time(channel_cfg->acquisition_time, &config.acq_time);

as the acquisition time of the ADC has never been defined, and is done at run time in the sample (therefore at APPLICATION level and not POST_KERNEL).

Could you tell me why the ADC is not configured in the overlay file for something similar as:

&adc {
        #address-cells = <1>;
        #size-cells = <0>;
        status = "okay";
        channel@0 {
                reg = <0>;
                zephyr,gain = "ADC_GAIN_1_6";
                zephyr,reference = "ADC_REF_INTERNAL";
                zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
                zephyr,input-positive = <NRF_SAADC_AIN2>;
                zephyr,resolution = <12>;
        };
};

I checked as well the board definiton for the Nordic Thingy52 and there is not definition for the ADC, therefore I guess the error is happening as well.


Please, let me know how to get rid of that error, and correct the sample if necessay. 

Thank you. 


Parents
  • Hi Hileu, thanks for your answer.

    The adc sample works perfectly fine as the adc channel is properly configured in the devicetree:

    	channel@0 {
    		reg = <0>;
    		zephyr,gain = "ADC_GAIN_1_6";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
    		zephyr,input-positive = <NRF_SAADC_AIN1>; /* P0.03 */
    		zephyr,resolution = <12>;
    	};


    My issue is linked to the fact that the vbatt doesn't configure properly the ADC.

  • Hi cbraissant,

    I can see how you find it unusual that a sample

    Then please try to enable the ADC node. The thingy52/nrf52832 target actually does have the adc node. See https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2-1/boards/nordic/thingy52/thingy52_nrf52832.dts#L112-L114.

    I think DT_INST_FOREACH_STATUS_OKAY causing trouble might be because your custom board file doesn't have an ADC node yet, rather than acquisition be ran before it is configured.

    As for where to report, this is a sample in the Zephyr part of the SDK, but one that is specific to Nordic board, so I would say either DevZone or the Zephyr RTOS GitHub repository are both good places to discuss it. We can continue here.

  • Hi Hieu, 

    I think you misunderstood the issue... The ADC node is activated in all cases mentionned above.

    &adc {
    	status = "okay";
    };
    


    The issue comes from the channel not being declared in the devicetree.

    My first post explain that fairly clearly and the ADC is mentioned in my devicetree. The issue is more linked to the lack of configuration for the zephyr,acquisition-time

    Please, read again the original post for the details.

  • Hi cbraissant,

    My apology. I missed that ADC enable part.

    But the reason I don't think the channel configuration is necessary is because I ran a simple test with the nrf52840dk/nrf52840 target. I copy the vbatt node from thingy52_nrf52832.dts into an overlay file, and the sample runs just fine without any ADC channel configuration, as you can see in the adc node part of the compiled zephyr.dts here:

    		adc: adc@40007000 {
    			compatible = "nordic,nrf-saadc";
    			reg = < 0x40007000 0x1000 >;
    			interrupts = < 0x7 0x1 >;
    			status = "okay";
    			#io-channel-cells = < 0x1 >;
    			phandle = < 0x1c >;
    		};

    I checked my project and it turns out that the voltage divider driver wasn't a part of the build. Instead, the ADC channel is setup in the sample's battery.c with a zero initialized configuration.

    Could you please check your project to see if voltage.c was actually used? If so, could you please share your project and custom board file? If the full files are confidential, a minimalized version to reproduce the issue would be enough.

  • Did you actually check the logs?
    The sample runs as well here, but there is still a error at runtime.

    And like you said, the ADC channel is configured in the battery.c, but at application level:

    SYS_INIT(battery_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);


    Therefore the channel is not configured for when the voltage divider is initialized post kernel, and return an error.

    	SENSOR_DEVICE_DT_INST_DEFINE(inst, &voltage_init, PM_DEVICE_DT_INST_GET(inst),             \
    			      &voltage_##inst##_data, &voltage_##inst##_config, POST_KERNEL,       \
    			      CONFIG_SENSOR_INIT_PRIORITY, &voltage_api);

    I check another project, the ZMK (Zephyr Mechanical Keyboard), and they implement their own version of the voltage-divider, which has chanel and sequence initialisation in the driver. A lot neater, but less customization possible. (ZMK voltage-divider)

     

  • Further below is my original reply which focus on how I went into how things worked and confirmed they work correctly.
    However, I have a new idea on what is wrong now.

    The runtime error is printed before the boot banner. Do you have a bootloader? Does the bootloader also get the voltage-divider node? 
    It is probably the bootloader having the voltage-divider node defined, but no proper driver setup.


    Original reply:

    I checked the log carefully. Yes. Here is a copy where I first short AIN4 to GND, then move to VDD.

    *** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
    *** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
    [00:00:00.252,258] <inf> BATTERY: Setup AIN4 got 0
    [00:00:00.252,258] <inf> BATTERY: Battery setup: 0 1
    [00:00:00.256,866] <inf> BATTERY: raw 4 ~ 0 mV => 0 mV
    
    [0:00:00.256]: 0 mV; 0 pptt
    [00:00:02.257,690] <inf> BATTERY: raw 10 ~ 2 mV => 18 mV
    
    [0:00:02.257]: 18 mV; 0 pptt
    [00:00:04.258,544] <inf> BATTERY: raw 19 ~ 4 mV => 37 mV
    
    [0:00:04.258]: 37 mV; 0 pptt
    [00:00:06.259,399] <inf> BATTERY: raw 17 ~ 3 mV => 28 mV
    
    [0:00:06.259]: 28 mV; 0 pptt
    [00:00:08.260,253] <inf> BATTERY: raw 17 ~ 3 mV => 28 mV
    
    [0:00:08.260]: 28 mV; 0 pptt
    [00:00:10.261,138] <inf> BATTERY: raw 6167 ~ 1355 mV => 12646 mV
    
    [0:00:10.261]: 12646 mV; 10000 pptt
    [00:00:12.261,993] <inf> BATTERY: raw 13636 ~ 2996 mV => 27962 mV
    
    [0:00:12.262]: 27962 mV; 10000 pptt
    [00:00:14.262,847] <inf> BATTERY: raw 13627 ~ 2994 mV => 27944 mV
    
    [0:00:14.262]: 27944 mV; 10000 pptt
    [00:00:16.263,702] <inf> BATTERY: raw 13632 ~ 2995 mV => 27953 mV
    
    [0:00:16.263]: 27953 mV; 10000 pptt
    [00:00:18.264,587] <inf> BATTERY: raw 13631 ~ 2995 mV => 27953 mV

    I checked the application flow by debugger and logging, and can see clearly that:

    The channel is configured here in battery.c: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/samples/boards/nordic/battery/src/battery.c#L137

    Which goes here adc_nrfx_saadc.c: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/drivers/adc/adc_nrfx_saadc.c#L171-L314

    Before each sampling, the input is configured here: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/drivers/adc/adc_nrfx_saadc.c#L493-L540

    No runtime error. 

Reply
  • Further below is my original reply which focus on how I went into how things worked and confirmed they work correctly.
    However, I have a new idea on what is wrong now.

    The runtime error is printed before the boot banner. Do you have a bootloader? Does the bootloader also get the voltage-divider node? 
    It is probably the bootloader having the voltage-divider node defined, but no proper driver setup.


    Original reply:

    I checked the log carefully. Yes. Here is a copy where I first short AIN4 to GND, then move to VDD.

    *** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
    *** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
    [00:00:00.252,258] <inf> BATTERY: Setup AIN4 got 0
    [00:00:00.252,258] <inf> BATTERY: Battery setup: 0 1
    [00:00:00.256,866] <inf> BATTERY: raw 4 ~ 0 mV => 0 mV
    
    [0:00:00.256]: 0 mV; 0 pptt
    [00:00:02.257,690] <inf> BATTERY: raw 10 ~ 2 mV => 18 mV
    
    [0:00:02.257]: 18 mV; 0 pptt
    [00:00:04.258,544] <inf> BATTERY: raw 19 ~ 4 mV => 37 mV
    
    [0:00:04.258]: 37 mV; 0 pptt
    [00:00:06.259,399] <inf> BATTERY: raw 17 ~ 3 mV => 28 mV
    
    [0:00:06.259]: 28 mV; 0 pptt
    [00:00:08.260,253] <inf> BATTERY: raw 17 ~ 3 mV => 28 mV
    
    [0:00:08.260]: 28 mV; 0 pptt
    [00:00:10.261,138] <inf> BATTERY: raw 6167 ~ 1355 mV => 12646 mV
    
    [0:00:10.261]: 12646 mV; 10000 pptt
    [00:00:12.261,993] <inf> BATTERY: raw 13636 ~ 2996 mV => 27962 mV
    
    [0:00:12.262]: 27962 mV; 10000 pptt
    [00:00:14.262,847] <inf> BATTERY: raw 13627 ~ 2994 mV => 27944 mV
    
    [0:00:14.262]: 27944 mV; 10000 pptt
    [00:00:16.263,702] <inf> BATTERY: raw 13632 ~ 2995 mV => 27953 mV
    
    [0:00:16.263]: 27953 mV; 10000 pptt
    [00:00:18.264,587] <inf> BATTERY: raw 13631 ~ 2995 mV => 27953 mV

    I checked the application flow by debugger and logging, and can see clearly that:

    The channel is configured here in battery.c: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/samples/boards/nordic/battery/src/battery.c#L137

    Which goes here adc_nrfx_saadc.c: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/drivers/adc/adc_nrfx_saadc.c#L171-L314

    Before each sampling, the input is configured here: https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/drivers/adc/adc_nrfx_saadc.c#L493-L540

    No runtime error. 

Children
No Data
Related