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 Reply
  • 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.

Children
  • 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.

Related