ADC On Nrf5340DK, Modifying the Battery Voltage Measurement

Hi, I have been trying to do a simple analogRead using the nrf5340 using the adc, the closest working example I found was Battery Voltage Measurement working with SDK 2.4 and Zephyr 3.2.

The example is working perfectly fine, but I am trying to modify it so I can read the voltage of an outside battery, a Classic AnalogRead on a pin. 

I am sure it's a simple modification, but I couldn't figure it out Sweat smile, I would appreciate if you could help me figure out which configuration I need to modify to not read the power supply voltage but the one coming into the Pin from an outside source  Thank you very much.

.overlay: 

   / {
	zephyr,user {
	   io-channels = <&adc 1>;
	};
     };


main.c
/*
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/init.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>


#define ZEPHYR_USER DT_PATH(zephyr_user)
#define BATTERY_ADC_GAIN ADC_GAIN_1_6

struct io_channel_config {
	uint8_t channel;
};


struct divider_config {
	struct io_channel_config io_channel;
	struct gpio_dt_spec power_gpios;
	/* output_ohm is used as a flag value: if it is nonzero then
	 * the battery is measured through a voltage divider;
	 * otherwise it is assumed to be directly connected to Vdd.
	 */
	uint32_t output_ohm;
	uint32_t full_ohm;
};
static const struct divider_config divider_config = {.io_channel = {
		DT_IO_CHANNELS_INPUT(ZEPHYR_USER),
	},
};


struct divider_data {
	const struct device *adc;
	struct adc_channel_cfg adc_cfg;
	struct adc_sequence adc_seq;
	int16_t raw;
};


static struct divider_data divider_data = {
.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(ZEPHYR_USER)),
};


static bool battery_ok;


static int divider_setup(void)
{
	const struct divider_config *cfg = &divider_config;
	const struct io_channel_config *iocp = &cfg->io_channel;
	const struct gpio_dt_spec *gcp = &cfg->power_gpios;
	struct divider_data *ddp = &divider_data;
	struct adc_sequence *asp = &ddp->adc_seq;
	struct adc_channel_cfg *accp = &ddp->adc_cfg;
	int rc;

	if (!device_is_ready(ddp->adc)) {
		printk("ADC device is not ready %s", ddp->adc->name);
		return -ENOENT;
	}

	if (gcp->port) {
		if (!device_is_ready(gcp->port)) {
			printk("%s: device not ready", gcp->port->name);
			return -ENOENT;
		}
		rc = gpio_pin_configure_dt(gcp, GPIO_OUTPUT_INACTIVE);
		if (rc != 0) {
			printk("Failed to control feed %s.%u: %d",
				gcp->port->name, gcp->pin, rc);
			return rc;
		}
	}

	*asp = (struct adc_sequence){
		.channels = BIT(0),
		.buffer = &ddp->raw,
		.buffer_size = sizeof(ddp->raw),
		.oversampling = 4,
		.calibrate = true,
	};

#ifdef CONFIG_ADC_NRFX_SAADC
	*accp = (struct adc_channel_cfg){
		.gain = BATTERY_ADC_GAIN,
		.reference = ADC_REF_INTERNAL,
		.acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40),
	};

	if (cfg->output_ohm != 0) {
		accp->input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0
			+ iocp->channel;
			printk("OUTPUT != 0\n");
			//this should not be activated in my situation
	} else {
		accp->input_positive = SAADC_CH_PSELP_PSELP_VDD;
		printk("OUTPUT == 0, else\n");
	}
	asp->resolution = 14;
#else /* CONFIG_ADC_var */
#error Unsupported ADC
#endif /* CONFIG_ADC_var */

	rc = adc_channel_setup(ddp->adc, accp);
	printk("Setup AIN%u got %d \n", iocp->channel, rc);

	return rc;
}


static int battery_setup(void)
{
	int rc = divider_setup();

	battery_ok = (rc == 0);
	printk("Battery setup: %d %d \n", rc, battery_ok);
	return rc;
}

SYS_INIT(battery_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); //when system start this initialise

int main(void)
{
		const struct gpio_dt_spec *gcp = &divider_config.power_gpios;
		if (gcp->port) {
		gpio_pin_set_dt(gcp, true);
		}

	while (true) {
		struct divider_data *ddp = &divider_data;
		const struct divider_config *dcp = &divider_config;
		struct adc_sequence *sp = &ddp->adc_seq;

		int batt_mV = adc_read(ddp->adc, sp);
			//printk("%d adc read;\n",batt_mV);

		sp->calibrate = false;

		if (batt_mV == 0) {
			int32_t val = ddp->raw;
			adc_raw_to_millivolts(adc_ref_internal(ddp->adc),ddp->adc_cfg.gain,sp->resolution,&val);
				batt_mV = val;
		}
		printk("%d mV;\n",batt_mV);
		k_busy_wait( ((1000U) * (1000U)));
	}
	return 0;
}

Parents Reply Children
No Data
Related