Attempting to use ADC to read the VDD_GPIO pin voltage.

We want to read the GPIO voltage level. Per the documentation this should be possible by using input 9 and the internal reference. What I am observing is that probing the pin with a multimeter reads 1.78 V. The ADC is giving me 1.68 - 1.72V. I've tweaked several of the configurations and this is the best I am getting. 

Is there any special considerations for reading the GPI voltage this way?

Implementation below:

// CODE TO READ THE VDD_GPIO
// With internal reference, single ended input (grounded negative input), and a gain of 1/6 the input range
// will be:
// Input range = (0.6 V)/(1/6) = 3.6 V

#include <device.h>
#include <drivers/gpio.h>
#include <drivers/adc.h>
#include <hal/nrf_saadc.h>

#define ADC_DEVICE_NODE DT_INST(0, nordic_nrf_saadc)
#define VRAIL_ADC_GAIN ADC_GAIN_1_4
#define ADC_REFERENCE ADC_REF_INTERNAL
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)
#define ADC_CHANNEL_INPUT NRF_SAADC_INPUT_VDD
#define ADC_CHAN_ID 0
#define ADC_RESOLUTION (14)
#define NUMBER_OF_EXTRA_SAMPLES (1)

static bool adc_calibrate_do = true;

struct device* adc_dev;
struct adc_channel_cfg adc_channel_config =
{
	.gain = VRAIL_ADC_GAIN,
	.reference = ADC_REFERENCE,
	.acquisition_time = ADC_ACQUISITION_TIME,
	.channel_id = ADC_CHAN_ID,
	.differential = false,
	.input_positive = ADC_CHANNEL_INPUT,
};

const struct adc_sequence_options sequence_opts =
{
		.interval_us = 10,
		.callback = NULL,
		.user_data = NULL,
		.extra_samplings = NUMBER_OF_EXTRA_SAMPLES,
};

bool util_set_up_rail_adc(void)
{
	bool ret = true;

	adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);

	if (!adc_dev) {
		LOG_ERR("device_get_binding ADC_0 failed\n");
		ret = false;
	}
	int err = adc_channel_setup(adc_dev, &adc_channel_config);
	if (err) {
		LOG_ERR("Error in adc setup: %d\n", err);
		ret = false;
	}

	return ret;
}

int util_get_rail_millivolts(int* adc_read_val)
{
	int ret = -ENOENT;
	int16_t raw_sample_buffer[NUMBER_OF_EXTRA_SAMPLES + 1];
	const struct adc_sequence sequence = {
		.options = &sequence_opts,
		.channels = BIT(ADC_CHAN_ID),
		.buffer = raw_sample_buffer,
		.buffer_size = sizeof(raw_sample_buffer),
		.resolution = ADC_RESOLUTION,
		.oversampling = 4,
		.calibrate = adc_calibrate_do,
	};

	if (!adc_dev) {
		return ret;
	}

	ret = adc_read(adc_dev, &sequence);

	// Set to false so subsequence calls to util_get_rail_millivolts do not
	// trigger calibration.
	adc_calibrate_do = false;

	// Do a rolling average of all samples.
	int avg_mv_reading = -1;
	for (int x = 0; x < (NUMBER_OF_EXTRA_SAMPLES + 1); x++)
	{
		int adc_mv = raw_sample_buffer[x];
		ret = adc_raw_to_millivolts(adc_ref_internal(adc_dev), adc_channel_config.gain, sequence.resolution, &adc_mv);
		if (ret >= 0)
		{
			LOG_DBG("RAIL RAW %d ~ %d mV", raw_sample_buffer[x], adc_mv);
			if (x == 0)
			{
				avg_mv_reading = adc_mv;
			}
			else
			{
				avg_mv_reading = (avg_mv_reading + adc_mv)/2;
			}

		}
	}

	if (ret >= 0)
	{
		*adc_read_val = avg_mv_reading;
		LOG_INF("RAIL AVG %d mV", avg_mv_reading);
	}

	return ret;
}
 

Parents
  • Hi Mitch

    Are you using an nRF9160DK, or is it custom hardware?

    Have you tried to measure the VDD_GPIO line with a scope to see if there could be some noise or dips while measuring that could explain the lower values? 

    For testing purposes would you be able to supply VDD_GPIO directly from a stable source just to see if this affects the readings? 

    Best regards
    Torbjørn

  • Here is a scope capture. It does not show a significant droop. This is on our PCB at the VDD_GPIO pin. Is there any specific configuration missing that is needed to measure VDD_GPIO accurately? 

  • Hi

    I can't really spot any issue in your configuration that would explain this issue. You could try with a higher oversampling parameter (like 16 or 32), but if you see consistently lower values I doubt that this will help. 

    Would it be possible to try and use one of the analog pins as an input and make an external connection to the VDD_GPIO line? 

    What if you connect the external pin to ground, what values do you see? (this is a simple way to measure the offset error)

    I would also recommend opening a separate private ticket and share your hardware design files for review, so we can ensure that the hardware design is good. 

    Best regards
    Torbjørn

Reply
  • Hi

    I can't really spot any issue in your configuration that would explain this issue. You could try with a higher oversampling parameter (like 16 or 32), but if you see consistently lower values I doubt that this will help. 

    Would it be possible to try and use one of the analog pins as an input and make an external connection to the VDD_GPIO line? 

    What if you connect the external pin to ground, what values do you see? (this is a simple way to measure the offset error)

    I would also recommend opening a separate private ticket and share your hardware design files for review, so we can ensure that the hardware design is good. 

    Best regards
    Torbjørn

Children
Related