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 , 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 = ÷r_config;
const struct io_channel_config *iocp = &cfg->io_channel;
const struct gpio_dt_spec *gcp = &cfg->power_gpios;
struct divider_data *ddp = ÷r_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 = ÷r_config.power_gpios;
if (gcp->port) {
gpio_pin_set_dt(gcp, true);
}
while (true) {
struct divider_data *ddp = ÷r_data;
const struct divider_config *dcp = ÷r_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;
}