ADC Channle Not Configured... adc_nrfx_saadc: Channel 2 not configured

I am programming a RAK4631 Board, which is of course based on the nrf52840 SoC.  The BaseLine Device tree has no detail in the ADC Node so I have created an overlay.  The RAK4631 documentation indicates that AIN2 (P0.04) is directly connected to the battery for voltage measurement.  There are many Arduino examples out there but not many C code examples. Here is my overlay file contents: 

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

&adc {
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;

    channel@2 {
        reg = <2>;
        zephyr,gain = "ADC_GAIN_1_6";
        zephyr,reference = "ADC_REF_INTERNAL";
        zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
        zephyr,input-positive = <NRF_SAADC_AIN2>;  /* Corresponds to P0.04 */
        zephyr,resolution = <12>;
    };

    channel@7 {
        reg = <7>;
        zephyr,gain = "ADC_GAIN_1_6";
        zephyr,reference = "ADC_REF_INTERNAL";
        zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
        zephyr,input-positive = <NRF_SAADC_AIN7>;  /* Corresponds to P0.31 */
        zephyr,resolution = <12>;
    };
};
Here is my setup code: 
//
// ADC Defines
//
#define BATT_ADC_NODE DT_NODELABEL(adc)         // ADC peripheral node
#define ADC_RESOLUTION 12             // 12-bit ADC resolution
#define ADC_GAIN ADC_GAIN_1_6         // Gain setting for ADC
#define ADC_REFERENCE ADC_REF_INTERNAL // Internal reference voltage
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10) // Acquisition time
#define BATTERY_CHANNEL_ID 2          // ADC channel ID for the battery AIN2
#define ADC_MAX_VOLTAGE 3.6           // Maximum ADC input voltage (V)
#define ADC_FULL_SCALE (1 << ADC_RESOLUTION) // Full-scale value for 12-bit ADC
#define VOLTAGE_DIVIDER_RATIO 2.0f

const struct device *batt_adc_dev = DEVICE_DT_GET(BATT_ADC_NODE);
// Define ADC channel configuration
static const struct adc_channel_cfg battery_channel_cfg = {
    .gain = ADC_GAIN_1_6,
    .reference = ADC_REF_INTERNAL,
    .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10),
    .channel_id = BATTERY_CHANNEL_ID,  // Specify the channel ID for AIN2
    .differential = 0 // Single-ended input
};

// Define ADC sequence
static struct adc_sequence battery_adc_seq = {
    .channels = BIT(BATTERY_CHANNEL_ID),
    .buffer = NULL, // Buffer will be set dynamically
    .buffer_size = 0,
    .resolution = ADC_RESOLUTION,
};
I am calling this for setup:
   //
    // Check AIN Ready for Battery Voltage Read
    //
     if (!device_is_ready(batt_adc_dev))
    {
        LOG_ERR("AIN2 Device not ready");
        return;
    }
    else
    {
        LOG_ERR("AIN2 Device Ready!!");
    }

    ret = adc_channel_setup(batt_adc_dev, &battery_channel_cfg);
    if (ret != 0) {
        LOG_ERR("Failed to configure ADC channel: %d", ret);
    }else
    {
        LOG_INF("ADC channel configured for battery voltage measurement");
    }
These calls are all successful.
However, when I call this:
  int ret = adc_read(batt_adc_dev, &battery_adc_seq);
    if (ret < 0) {
        LOG_ERR("Failed to read ADC: %d", ret);
        return -1.0f;
    }
I always get this log message:
00> [00:30:35.901,824] <err> adc_nrfx_saadc: Channel 2 not configured
00> [00:30:36.002,075] <err> ublox_gps: Failed to read ADC: -22
The project builds successfully without warnings or errors. Any help letting me know where I am going wrong would be appreciated.  I am using Zephyr v2.9.0 which I believe is the latest and the RAK4631 dev board.
Thank you.
Parents
  • This Ticket can be closed.  I found an example that used zypher_user to access the overlay nodes, which was the trick!

  • Hi,eq

    Could u share me how u solved this problem?

    Thanx

  • Hi Martin, a couple of things.  In my initial setup, I used the zephyr user to get the device context like this: 

    static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user));

    int16_t buf;
    struct adc_sequence sequence = {
    .buffer = &buf,
    /* buffer size in bytes, not number of samples */
    .buffer_size = sizeof(buf),
    // Optional
    //.calibrate = true,
    };

    My initialization was then this:

    //
    // Initialize ADC for Battery Voltage Measurement
    //
    /* STEP 3.3 - validate that the ADC peripheral (SAADC) is ready */
    if (!adc_is_ready_dt(&adc_channel)) {
    LOG_ERR("ADC controller device %s not ready", adc_channel.dev->name);
    return;
    }
    /* STEP 3.4 - Setup the ADC channel */
    int err = adc_channel_setup_dt(&adc_channel);
    if (err < 0) {
    LOG_ERR("Could not setup channel #%d (%d)", 0, err);
    return;
    }
    /* STEP 4.2 - Initialize the ADC sequence */
    err = adc_sequence_init_dt(&adc_channel, &sequence);
    if (err < 0) {
    LOG_ERR("Could not initalize sequnce");
    return;
    }

    And then measuring:

    LOG_INF("Reading Battery Voltage...");

    int val_mv;
    uint32_t count = 0;

    /* STEP 5 - Read a sample from the ADC */
    int err = adc_read(adc_channel.dev, &sequence);
    if (err < 0) {
    LOG_ERR("Could not read (%d)", err);
    return 0.0;
    }

    val_mv = (int)buf;
    LOG_INF("ADC reading[%u]: %s, channel %d: Raw: %d", count++, adc_channel.dev->name, adc_channel.channel_id, val_mv);

    /* STEP 6 - Convert raw value to mV*/
    err = adc_raw_to_millivolts_dt(&adc_channel, &val_mv);
    /* conversion to mV may not be supported, skip if not */
    if (err < 0) {
    LOG_WRN(" (value in mV not available)\n");
    } else {
    LOG_INF("Unscaled voltage = %d mV", val_mv);
    }
    /* Calculate the battery voltage */
    float battery_voltage = (val_mv / 1000.0) / VOLTAGE_DIVIDER_RATIO;

    Oh yeah, how can i forget.  The big confusion point was this in my overlay file: 

            zephyr,input-positive = <NRF_SAADC_AIN3>;  /* Corresponds to P0.04 */

    I had mistakenly been using AIN4!!!

    I hope this helps!

    EQ

  • Thans a lot eq,

    But I am confused of NRF_SAADC_AIN3,Does NRF_SADDC_AIN3 boned with AIN2(P0.04)?Or NRF_SADDC_AIN2 is matched with P0.04?

    Best regard

  • Yeah, well me too! lol!  The documentation purports the following mapping: 

    RAK4631 <-> nRF52840

    WB_IO1 <-> P0.17 (GPIO 17)
    WB_IO2 <-> P1.02 (GPIO 34)
    WB_IO3 <-> P0.21 (GPIO 21)
    WB_IO4 <-> P0.04 (GPIO 4)
    WB_IO5 <-> P0.09 (GPIO 9)
    WB_IO6 <-> P0.10 (GPIO 10)
    WB_SW1 <-> P0.01 (GPIO 1)
    WB_A0 <-> P0.04/AIN2 (AnalogIn A2)
    WB_A1 <-> P0.31/AIN7 (AnalogIn A7)

    However, I had to use this in my overlay to get it working:

    channel@3 {
    reg = <3>;
    zephyr,gain = "ADC_GAIN_1_6";
    zephyr,reference = "ADC_REF_INTERNAL";
    zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
    zephyr,input-positive = <NRF_SAADC_AIN3>; /* Corresponds to P0.04 */
    zephyr,resolution = <12>;

    I wish I could explain it, but I can't...I discovered this by trying each pin one by one, and it was AIN3 that actually had my battery voltage on it.

    Sorry I can't explain it, but if you are using a RAK4631, this should work.

    Cheers!

    EQ

  • Thanks a lit eq,I have solved this problem.

    Thanks!

    Martin

Reply Children
No Data
Related