Post Go back to editing

AD7124-8 Driver Issue: Input/Output Error When Reading Raw Data

Category: Software
Product Number: AD7124-8
Software Version: Kernel 5.15

Hello AD Community,

I'm currently working with the AD7124-8 ADC on a custom board and encountering an issue. The driver loads successfully and the device tree configuration seems to be correct. However, when I attempt to read from the raw data files (e.g., /sys/bus/iio/devices/iio:device0/in_voltage11-voltage0_raw), I consistently receive an Input/output error.

Device Tree for reference:

ad7124_mclk: oscillator {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <614400>;
//clock-frequency = <8192000>;
};

adc@0 {
compatible = "adi,ad7124-8";
reg = <0>;
spi-max-frequency = <5000000>;
interrupts = <25 2>;
interrupt-parent = <&gpio5>;
clocks = <&ad7124_mclk>;
clock-names = "mclk";
syncreset-gpios = <&pca9539 15 GPIO_ACTIVE_HIGH>;

spi-cpol;
spi-cpha;

#address-cells = <1>;
#size-cells = <0>;

channel@0 {
reg = <0>;
diff-channels = <0 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@1 {
reg = <1>;
diff-channels = <1 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@2 {
reg = <2>;
diff-channels = <2 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@3 {
reg = <3>;
diff-channels = <3 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@4 {
reg = <4>;
diff-channels = <4 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@5 {
reg = <5>;
diff-channels = <5 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@6 {
reg = <6>;
diff-channels = <6 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@7 {
reg = <7>;
diff-channels = <7 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@8 {
reg = <8>;
diff-channels = <8 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@9 {
reg = <9>;
diff-channels = <9 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@10 {
reg = <10>;
diff-channels = <10 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@11 {
reg = <11>;
diff-channels = <11 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@12 {
reg = <12>;
diff-channels = <12 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@13 {
reg = <13>;
diff-channels = <13 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@14 {
reg = <14>;
diff-channels = <14 0>;
bipolar = <0>;
adi,buffered-positive;
};

channel@15 {
reg = <15>;
diff-channels = <15 0>;
bipolar = <0>;
adi,buffered-positive;
};
};
};

Observations:

The driver initializes successfully

Despite successful initialization, attempting to read the raw data from the ADC input channels results in an Input/output error.

root@target:/sys/bus/iio/devices/iio:device0# cat in_voltage11-voltage0_raw
cat: in_voltage11-voltage0_raw: Input/output error

Request:

I’m seeking advice on what could be causing this issue. Is there something specific in the configuration or hardware setup that I might be missing? Any guidance or suggestions for additional debugging steps would be greatly appreciated.

Thank you in advance for your support.

Parents
  •   Thanks for your support. Find the below update followed by another query:

    We can read the counter from raw file after setting up correct interrupt line and internal clock selection as we dont have external clock connected.
    Updated device tree which is working now is :

    adc@0 {
    compatible = "adi,ad7124-8";
    reg = <0>;
    spi-max-frequency = <5000000>;
    interrupts = <4 2>;
    interrupt-parent = <&gpio5>;

    spi-cpol;
    spi-cpha;

    #address-cells = <1>;
    #size-cells = <0>;

    channel@0 {
    reg = <0>;
    diff-channels = <0 19>;
    };

    channel@1 {
    reg = <1>;
    diff-channels = <1 19>;
    };

    channel@2 {
    reg = <2>;
    diff-channels = <2 19>;
    };

    channel@3 {
    reg = <3>;
    diff-channels = <11 19>;
    };

    We have below readings where we get variation in counts when fixed stable voltage or current input is connected.
    refer:

    With above reading variation, we have question on calibration. How in linux calibration is done for the AD7124. Does driver auto calibrate?

    we have got 5 files corresponds to each input lines:
    in_voltage0-voltage19_filter_low_pass_3db_frequency
    in_voltage0-voltage19_offset
    in_voltage0-voltage19_raw
    in_voltage0-voltage19_sampling_frequency
    in_voltage0-voltage19_scale

    What is the significance of these files what would be the optimum value to put in these files for better accuracy?

    Let me know if you need more info.

  • Hi,
    Calibration is not implemented in the driver at the moment, you could manually test if calibration would help by interacting with the chip registers trough debugfs .
    (debugfs can be accessed from /sys/kernel/debug/iio/iio:deviceX/direct_reg_access or using the iio util iio_reg iio_reg [Analog Devices Wiki])

    raw, offset and scale are used to convert a raw sample to voltage: (raw+offset)*scale

    Writing to the scale file adjusts the PGA bits (Gain select bits) from a configuration register used for a certain channel (more channel registers than configuration registers, a channel register points to a configuration => the driver decides at runtime which channels can point to the same config register). From the datasheet I understand the PGA bits as support for smaller voltage ranges but a finer precision due to the smaller range.

    in_voltage0-voltage19_sampling_frequency and in_voltage0-voltage19_filter_low_pass_3db_frequency both adjusts the sampling frequency, but with a small caveat:
    - sampling_frequency only adjusts the output data rate (FS - Filter output data rate select bits)
    - filter_low_pass_3db_frequency adjusts both the data rate and the selected filter sinc3 or sinc4 depending on the selected frequency

    The best accuracy is obtained with the lowest sampling frequency selected.
    Considering that you have such a high drift in readings from a fixed input voltage... it could be that the issue is with the hardware(noisy DGND). You could try to define a channel with ain1 connected externally to the supply ground.

    If this does not fixes the issue you are having, you might need support from a colleague more HW oriented :)

Reply
  • Hi,
    Calibration is not implemented in the driver at the moment, you could manually test if calibration would help by interacting with the chip registers trough debugfs .
    (debugfs can be accessed from /sys/kernel/debug/iio/iio:deviceX/direct_reg_access or using the iio util iio_reg iio_reg [Analog Devices Wiki])

    raw, offset and scale are used to convert a raw sample to voltage: (raw+offset)*scale

    Writing to the scale file adjusts the PGA bits (Gain select bits) from a configuration register used for a certain channel (more channel registers than configuration registers, a channel register points to a configuration => the driver decides at runtime which channels can point to the same config register). From the datasheet I understand the PGA bits as support for smaller voltage ranges but a finer precision due to the smaller range.

    in_voltage0-voltage19_sampling_frequency and in_voltage0-voltage19_filter_low_pass_3db_frequency both adjusts the sampling frequency, but with a small caveat:
    - sampling_frequency only adjusts the output data rate (FS - Filter output data rate select bits)
    - filter_low_pass_3db_frequency adjusts both the data rate and the selected filter sinc3 or sinc4 depending on the selected frequency

    The best accuracy is obtained with the lowest sampling frequency selected.
    Considering that you have such a high drift in readings from a fixed input voltage... it could be that the issue is with the hardware(noisy DGND). You could try to define a channel with ain1 connected externally to the supply ground.

    If this does not fixes the issue you are having, you might need support from a colleague more HW oriented :)

Children
  • Hi  ,  ,

    This is a bit out of scope for the Linux driver forum, but wanted to give a couple of comments on "accuracy" and "variation":

    The AD7124 is a device that will never give a stable output code - which sounds bad, but it's not, all it says is that the digital output word is so wide that the quantization noise is lower than the analog thermal noise of the input amplifier and ADC input. Figures 10 to 15 in the datasheet show the expected distribution of codes for a couple of modes, and tables 8 to 37 list the noise level for all of the modes. A quick test you can do is to short the inputs for a given channel together, make sure that they are biased within the device's absolute voltage limits (I usually bias the shorted inputs to Vref/2 with a 10k/10k divider), then take a collection of readings - 128 is a good starting point, then take the standard deviation and compare to the datasheet RMS numbers.

    Accuracy can also be tricky to fully interpret, but it looks like the gain error spec before calibration includes the reference error. But upon further inspection, the before calibration accuracy is 0.0025% and 0.016% after, which doesn't make sense. This is a question for precision ADC Q&A .

    I didn't go through your spreadsheet in detail, but it looks like you need to include more digits in your measured AIN voltage - what make / model meter are you using?

    I'd recommend posting further hardware / performance questions in Precision ADC Q&A , the apps engineers for this part monitor that forum. Feel free to link to this thread so they see the whole history.

    -Mark

  •   and  

    Thanks for your previous inputs; the variation observed is within acceptable limits, so we are only focusing on calibration when required.

    I would like to bring up another observation and seek your guidance. While reading from the raw files of AIN0, AIN1, AIN11, and AIN2 (these are the only four lines we are using on our board), we’ve noticed that the initial few readings seem to return unexpected or incorrect values.

    The IIO sysfs is populated, and we can read values, but these early readings don’t appear to reflect what we expect. After a few attempts, the values stabilize and seem accurate.

    My board setup for measurement reference.
    AIN0 --> Ground

    AIN1 --> Active low(input voltage)

    AIN2 --> Active low

    AIN11 --> 1V

    screenshot is reading value for AIN2 and AIN11 and can see that first 2-3 values are wrong count.

    Could you provide any explanation or suggest a solution for this issue? We’re not sure what could be causing these unexpected initial readings.

  • Wen we read the AIN11 with 1 sec delay, we get below behavior where counter drops to invalid values:


    These wrong values are noise/glitch? Please guide to understand this intermittency and path forward to stabilize the reading an make it consistent. 

    What are we missing here? 

    Current Device Tree Configuration:

    &ecspi1 {
        #address-cells = <1>;
        #size-cells = <0>;
        fsl,spi-num-chipselects = <1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>;
        cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
        status = "okay";

        adc@0 {
            compatible = "adi,ad7124-8";
            reg = <0>;
            spi-max-frequency = <5000000>;
            interrupts = <4 2>;
            interrupt-parent = <&gpio5>;

            spi-cpol;
            spi-cpha;

            #address-cells = <1>;
            #size-cells = <0>;

            channel@0 {
                reg = <0>;
                diff-channels = <0 19>;
            };

            channel@1 {
                reg = <1>;
                diff-channels = <1 19>;
            };

            channel@2 {
                reg = <2>;
                diff-channels = <2 19>;
            };

            channel@3 {
                reg = <3>;
                diff-channels = <11 19>;
            };
        };
    };

    Since the CLK pin is not in use, we opted for the internal clock. The following patch was added to select the internal clock:

    From 73f3cb165cf467397bf8df13056709441e06218e Mon Sep 17 00:00:00 2001
    From: OpenEmbedded <oe.patch@oe>
    Date: Mon, 23 Sep 2024 17:31:01 +0000
    Subject: [PATCH] internal clock source selection

    ---
    drivers/iio/adc/ad7124.c | 33 +++++++++++++++++++++++++++++++--
    1 file changed, 31 insertions(+), 2 deletions(-)

    diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
    index fb6239140ef0..e3fcde147d5e 100644
    --- a/drivers/iio/adc/ad7124.c
    +++ b/drivers/iio/adc/ad7124.c
    @@ -758,6 +758,11 @@ static const struct iio_info ad7124_info = {
    .attrs = &ad7124_attrs_group,
    };

    +static void ad7124_clk_disable(void *clk)
    +{
    + clk_disable_unprepare(clk);
    +}
    +
    static int ad7124_soft_reset(struct ad7124_state *st)
    {
    unsigned int readval, timeout;
    @@ -897,7 +902,13 @@ static int ad7124_setup(struct ad7124_state *st)
    unsigned int fclk, power_mode;
    int i, ret;

    - fclk = clk_get_rate(st->mclk);
    + /* Check if external clock is available, otherwise use internal clock */
    + if (st->mclk) {
    + fclk = clk_get_rate(st->mclk);
    + } else {
    + fclk = 614400; // Internal clock frequency of 614.4 kHz
    + }
    +
    if (!fclk)
    return -EINVAL;

    @@ -998,7 +1009,25 @@ static int ad7124_probe(struct spi_device *spi)

    st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
    if (IS_ERR(st->mclk))
    - return PTR_ERR(st->mclk);
    + {
    + dev_info(&spi->dev, "No external clock found, using internal clock\n");
    + st->mclk = NULL; // Use internal clock
    + }
    + else
    + {
    + ret = clk_prepare_enable(st->mclk);
    + if (ret)
    + {
    + dev_err(&spi->dev, "Failed to enable clock: %d\n", ret);
    + return ret;
    + }
    + ret = devm_add_action_or_reset(&spi->dev, ad7124_clk_disable, st->mclk);
    + if (ret) {
    + dev_err(&spi->dev, "Failed to register clock disable action: %d\n", ret);
    + return ret;
    + }
    + }
    +

    ret = ad7124_soft_reset(st);
    if (ret < 0)
    --
    2.25.1

    Without this patch, all pins were returning 0 readings. The driver was updated from the latest changes in the Analog Devices Linux repository:https://github.com/analogdevicesinc/linux

  • Hi  ,

    Is this PR applied to your driver?

    https://github.com/analogdevicesinc/linux/pull/2571

    (Sorry I'm not an expert at building drivers / kernels, but I help with the debugging process.)

    I was originally thinking a zero value would be extremely unlikely (but not impossible), then realized the inputs are configured for single-ended. Could you try an experiment only enabling a single channel?

    For testing channel alignment within the buffers, a great test is to bias the enabled inputs to a "staircase" of voltages. I use this trick all the time, but I think here is the only place it's been published:

    https://www.analog.com/en/resources/technical-articles/easy-drive-delta-sigma-adcs-deliver-powerful-features-and-reduce-design-effort.html

    Search for "Try this Trick!"

    -Mark

  • Since the reading is done from the *_raw file, there is no way for a channel mixup to happen. That bug happens when buffered mode is used with multiple channels.

     could you check if you have this fix applied? https://github.com/analogdevicesinc/linux/pull/2563