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.

  • Hi  ,

    You can check this example ad7124-4 device tree where the channels used are single-ended: https://github.com/analogdevicesinc/linux/blob/rpi-5.4.y/arch/arm/boot/dts/overlays/rpi-ad7124-overlay.dts

    /dts-v1/;
    /plugin/;
    
    / {
    	compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
    
    	fragment@0 {
    		target-path = "/";
    		__overlay__ {
    			vref: fixedregulator@0 {
    				compatible = "regulator-fixed";
    				regulator-name = "fixed-supply";
    				regulator-min-microvolt = <2500000>;
    				regulator-max-microvolt = <2500000>;
    				regulator-boot-on;
    			};
    		};
    	};
    
    	fragment@1 {
    		target-path = "/";
    		__overlay__ {
    			clocks {
    				ad7124_mclk: clock@0 {
    					#clock-cells = <0>;
    					compatible = "fixed-clock";
    					clock-frequency = <614400>;
    				};
    			};
    		};
    	};
    
    	fragment@2 {
    		target = <&spi0>;
    		__overlay__ {
    			#address-cells = <1>;
    			#size-cells = <0>;
    			status = "okay";
    
    			ad7124@0 {
    				compatible = "adi,ad7124-4";
    				reg = <0>;
    				spi-max-frequency = <5000000>;
    				interrupts = <25 2>;
    				interrupt-parent = <&gpio>;
    				refin1-supply = <&vref>;
    				clocks = <&ad7124_mclk>;
    				clock-names = "mclk";
    
    				#address-cells = <1>;
    				#size-cells = <0>;
    
    				channel@0 {
    					reg = <0>;
    					diff-channels = <0 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@1 {
    					reg = <1>;
    					diff-channels = <1 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@2 {
    					reg = <2>;
    					diff-channels = <2 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@3 {
    					reg = <3>;
    					diff-channels = <3 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@4 {
    					reg = <4>;
    					diff-channels = <4 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@5 {
    					reg = <5>;
    					diff-channels = <5 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@6 {
    					reg = <6>;
    					diff-channels = <6 19>;
    					adi,reference-select = <0>;
    				};
    
    				channel@7 {
    					reg = <7>;
    					diff-channels = <7 19>;
    					adi,reference-select = <0>;
    				};
    			};
    		};
    	};
    
    	fragment@3 {
    		target = <&spidev0>;
    		__overlay__ {
    			status = "disabled";
    		};
    	};
    
    	fragment@4 {
    		target = <&spidev1>;
    		__overlay__ {
    			status = "disabled";
    		};
    	};
    };

    Note that to be able to create the single-ended channels, each ADC channel was paired with channel 19, which is a ground. And also note that this device tree example is compatible with the AD7124-4 which only has 4 channels. You can just adjust the number of channels for your AD7124-8.

    You can try to edit your existing device tree and let us know if this works for you.

    Regards,
    Andy

  • Hi dreamer21,

    Since the driver initialized there seems to be no problem in regards to the SPI bus.
    Because the issue arises when reading samples one-by-one (reading from in_voltage11-voltage0_raw
    triggers a single conversion) and the error is Input/output the problem should be with the setup of
    interrupts.

    To check if the interrupt is registered and they are getting triggered you can look at /proc/interrupts.

    Example from raspberry pi 3:

    root@analog:~# cat /proc/interrupts
               CPU0       CPU1       CPU2       CPU3
    [...]
    199:       1115          0          0          0  pinctrl-bcm2835  19 Edge      ad7124-8


    Could you please check if you are getting any interrupts triggered when reading from that file?

  • Hi Dumitru,

    Thanks for your response.

    I am not getting any interrupts while reading any of the files.

    Where is the interrupt line connected? Is it in DOUT/RDY?

    How to configure the interrupt in Device Tree?

    Current DT entries for interrupt:

    interrupts = <25 2>;
    interrupt-parent = <&gpio5>;

  •    The interrupt line you can say is "multiplexed" with the DOUT SPI pin, hence the "DOUT/RDY" naming.
    Usually the MISO or DOUT SPI pin from the processor does not not support to also register interrupts 
    so it will be necessary to connect DOUT/RDY to another pin as well.

        To configure the interrupt in the device tree you need to specify the desired GPIO pin in the first position
    of the "interrupts" property, the second number just specifies the type of interrupt (here, 2 selects falling edge).

       Since the interrupt was configured and appears registered in /proc/interrupts, the hardware connections must
    be at fault. You will need to also connect the DOUT/RDY pin from the ADC to GPIO 25.
    (or select a different GPIO pin "interrupts = <x 2>" and connect DOUT/RDY to GPIO x as well)

  • Ok,

    Let me spend some time on this and get back to you.

    Thanks for your input this is helpful.

  • Thanks Andieo,

    This is reference I have taken and at first set 19 then set 0 as my AIN0 is grounded. The device tree I shared in this thread is the with this file reference only.

  •   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 :)

  • 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.