Post Go back to editing

AD7176-2 Overlay for RPi - Error in Selecting Matching Device

Category: Software
Product Number: AD7176-2
Software Version: Python 3.9.2, Kuiper Linux 2021_R2, Pyadi-iio 0.0.13

Hi All,

Following up on my previous post, I've made a DT overlay for the AD7176-2 based on an overlay for the AD7124-8. But I'm still running into the same issue that the device is not able to be selected.

This is my DT Overlay

/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 = <5000000>;
				regulator-max-microvolt = <5000000>;
				regulator-boot-on;
			};
		};
	};

	fragment@1 {
		target-path = "/";
		__overlay__ {
			clocks {
				ad7176_mclk: clock@0 {
					#clock-cells = <0>;
					compatible = "fixed-clock";
					clock-frequency = <16000000>;
				};
			};
		};
	};

	fragment@2 {
		target = <&spi0>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			ad7176@0 {
				compatible = "adi,ad7176-2";
				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 1>;
				};

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

	fragment@3 {
		target = <&spidev0>;
		__overlay__ {
			status = "disabled";
		};
	};

	fragment@4 {
		target = <&spidev1>;
		__overlay__ {
			status = "disabled";
		};
	};
};

And this is the error message I get;

Traceback (most recent call last):
File "/home/analog/AD7176/AD7176_adi.py", line 4, in <module>
my_adi = adi.ad717x(uri="local:")
File "/usr/local/lib/python3.9/dist-packages/adi/ad717x.py", line 85, in __init__
raise Exception("Error in selecting matching device")
Exception: Error in selecting matching device

I have compiled using the command; $ dtc -O dtb -o rpi-ad7176-myOverlay.dtbo rpi-ad7176-myOverlay.dts in Kuiper Linux command line and moved the .dtbo file into the /boot/overlays folder. I've added the following line into the /boot/config.txt file; dtoverlay=rpi-ad7176-myOverlay.

Any insight into where I'm going wrong would be greatly appreciated.

I'd also like to make the inputs single ended (I believe you have to specify this in the .dts/.dtbo file) - if anyone has an example they can show me of how to do this that'd be awesome!

  • Hi All,

    I've made some changes to my .dts file - taking out fragment@0 & fragment@1. I'm using an ADR445 as my voltage reference an external crystal so I don't believe I need to declare these in my DTOverlay (please correct me if I'm wrong). The updated .dts file is;

    /dts-v1/;
    /plugin/;
    
    / {
    	compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
    
    	fragment@0 {
    		target = <&spi0>;
    		__overlay__ {
    			#address-cells = <1>;
    			#size-cells = <0>;
    			status = "okay";
    
    			ad7176@0 {
    				compatible = "adi,ad7176-2";
    				reg = <0>;
    				spi-max-frequency = <5000000>;
    				interrupts = <25 2>;
    				interrupt-parent = <&gpio>;
    
    				#address-cells = <1>;
    				#size-cells = <0>;
    
    				channel@0 {
    					reg = <0>;
    					diff-channels = <0 1>;
    				};
    
    				channel@1 {
    					reg = <1>;
    					diff-channels = <2 3>;
    				};
    			};
    		};
    	};
    
    	fragment@3 {
    		target = <&spidev0>;
    		__overlay__ {
    			status = "disabled";
    		};
    	};
    
    	fragment@4 {
    		target = <&spidev1>;
    		__overlay__ {
    			status = "disabled";
    		};
    	};
    };
    

    I've compiled and moved the .dtbo file as described in my original post. Unfortunately I'm still getting the same error. I did some digging in the kernel logs ($ dmesg) and found the following error;

    [    6.743529] ad7173 spi0.0: Unexpected device id: 4040, expected: c90

    It's very odd that it's thinking that an AD7173 should be there.

    I think I'm on the right track but if anyone can spot any errors please let me know!

  • Hi  ,

    The ID for the AD7173 is 0x30DX: https://github.com/analogdevicesinc/linux/blob/master/drivers/iio/adc/ad7173.c#L53C26-L53C26

    4040 is sort of a strange number, but it's not all zeros, nor all ones, so that indicates that there is at least activity on the SPI bus.

    Have you verified signal integrity with a high-speed oscilloscope? If the SPI traces are long and / or the ground integrity poor, there are a number of things that can happen to corrupt communication - double clocking if there is ringing on the clock signal, data shifted right or left by one bit position, etc. For example if the requested register (0x07) for the ID is corrupted, then data may be received, but from the wrong register. Or if the correct register is received by the AD7176, the problem may be with the data that is sent back to the Pi.

    Can you post a schematic and a photograph or board layout showing exactly how the Pi is connected to your board, and ultimately to the AD7176?

    -Mark

  • Hello SJayawardena,

    It is good that you were inspired by AD7124-8 overlay, but when creating a device tree, you should always check the documentation in Documentation/devicetree/bindings. You have this for your device.

    An other note on your device tree, you should not use fragments. Instead check out this devicetree for reference.

  • Hi Mark,

    Thanks for your reply!

    The Kernel Log error I was receiving before was due to the fact that I mistakenly plugged in the Sync/Error into GPIO pin 25 on the RPi. Disconnecting this makes the "[    6.743529] ad7173 spi0.0: Unexpected device id: 4040, expected: c90" error disappear from the kernel logs. It's odd that the RPi was trying to connect to an AD7173 since I did not enable any DTOverlays for that chip. 

     

    Following your advice, I probed the SPI lines using a RIGOL DS1054 scope sending a 0x81 data packet to the chip using SPIDev - see the code below. This was run on Raspbian (with no ADI overlays installed).

    '''PREAMBLE'''
    import spidev
    import numpy as np
    
    # Initilise constants
    bus = 0
    device = 0
    
    
    # Initialise SPI bus
    spi = spidev.SpiDev(bus, device)
    spi.max_speed_hz = 2000000 
    spi.mode = 0b11
    spi.lsbfirst = False
    
    
    # Write something to AD7176
    spi.writebytes2([0b10000001])

    And this is what is displayed on the scope (all lines are AC coupled - CLK and CS idle high). Ch1=CS (Yellow), Ch2=CLK (Blue), Ch3=MOSI (Purple). I've zoomed into the interesting bits - there is a bit chopped off to the LHS and RHS where the CS line is low and then high - I don't think anything interesting is happening there.

    It seems that there is a some oscillations on each line but the there is a strong edge and voltage difference. I am breaking out the lines to connect to the scope using a breadboard a jumper wires - I this is the most likely cause of these small oscillations.

    Below is a photo of my PCB (sorry for the quality - my phone is a potato). I created it based on the schematics given in the user guide for the AD7176-2's evaluation board. The SPI lines are on the bottom side of the board and I connect them to the RPi using Adafruit 6" jumpers.

    As always, any insight would be greatly appreciated!

    -Jay

  • Hi  ,

    Thanks for your reply!

    I've updated the .dts file based on your advice however, I'm still getting the "Exception Error in selecting matching device" error when running the python script detailed in my original post.

    /dts-v1/;
    /plugin/;
    
    
    /{
        ad7173 {
            compatible = "adi,ad7176-2";
            reg = <0>;
            interrupt-parent = <&gpio>;
            interrupts = <25 2>;
            spi-max-frequency = <32000000>;
            spi-cpol;
            spi-cpha;
            spi-cs-high;
    
            adi,channels {
                #address-cells = <2>;
                #size-cells = <0>;
                
                channel@0 {
                    reg = <21 2>;
                };
                
                channel@1 {
                    reg = <22 2>;
                };
                
                channel@2 {
                    reg = <23 2>;
                };
    
                channel@4 {
                    reg = <24 2>;
                };
            };
        };
    };

    I am getting a number of warning when I compile;

    rpi-ad7176-myOverlay2.dts:11.9-19: Warning (reg_format): /ad7176:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
    rpi-ad7176-myOverlay2.dts:9.12-39.7: Warning (unit_address_vs_reg): /ad7176: node has a reg or ranges property, but no unit name
    rpi-ad7176-myOverlay2.dtbo: Warning (pci_device_reg): Failed prerequisite 'reg_format'
    rpi-ad7176-myOverlay2.dtbo: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
    rpi-ad7176-myOverlay2.dtbo: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
    rpi-ad7176-myOverlay2.dtbo: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
    rpi-ad7176-myOverlay2.dtbo: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
    rpi-ad7176-myOverlay2.dts:9.12-39.7: Warning (avoid_default_addr_size): /ad7176: Relying on default #address-cells value
    rpi-ad7176-myOverlay2.dts:9.12-39.7: Warning (avoid_default_addr_size): /ad7176: Relying on default #size-cells value
    rpi-ad7176-myOverlay2.dtbo: Warning (avoid_unnecessary_addr_size): Failed prerequisite 'avoid_default_addr_size'
    rpi-ad7176-myOverlay2.dtbo: Warning (unique_unit_address): Failed prerequisite 'avoid_default_addr_size'

    From my understanding, these errors/warnings can generally be ignored because the compiler only understands syntax errors and not semantic errors.

    Any help would be greatly appreciated!

    I note that I'm not stating which processors are compatible (e.g. brcm2835...) nor am I disabling spiDev in this updated code - is this something that I still need to do? If so, how would I do this without the use of fragments/with this updated syntax?

    I'm a bit confused as to why we shouldn't use fragments. Has there been an update to the formatting of DTOverlays? Do you have any references which I could read?

  • So that scope shot is not too bad for such a setup - I wouldn't rule out signal integrity entirely, but you're on the right track it seems. You do have some visible crosstalk from SCK to MOSI (glitches on the falling SCK edges). Also if you're using the probe's ground clip wires, those will also contribute to visible ringing. Here's a technique that tends to give much better results:

    The only other things I can think of at this level, would be to try to get a few more ground wires on your board, it looks like you only have one. You could scrape some soldermask off of the top-side ground plane and lay a spare header flat against the exposed copper, then put a big blob of solder to hold it in place. Then use some of the Pi's additional ground pins.

    The Adafruit jumpers are okay, but the Schmartboard ones are better: https://www.digikey.com/en/products/detail/schmartboard,-inc./920-0192-50/9559347 I use these all the time for connecting Pmod boards to Raspberry Pis. They grip all four sides of the post, and quite securely.

    On the software / SPI side, the one other thing I can think of is to try reading out the device ID from register 0x07 with your Spidev code above. And I think I misunderstood above, the device ID for the AD7176-2 is 0xC9x. If that works, you can head back to debugging your device tree.

    -Mark

  • Hello ,

    Your hunch is correct. You should indeed include of the Broadcom Soc into the devicetree.

    Firstly, you should not have the devicetree node of the sensor directly connected to root node(/). Instead your devicetree should start like this:

    / {
    
        compatible =  = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"
    
    }

    Now you are using nodes instead of fragments, but the logic is quite similar. Instead of:

    	fragment@0 {
    		target = <&spi0>;
    		__overlay__ {
    			#address-cells = <1>;
    			#size-cells = <0>;
    			status = "okay";
    			...

    you should use:

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

    There are multiple devicetrees which you could check in the folder:

    linux/arch/arm/boot/dts/overlays at rpi-5.15.y · analogdevicesinc/linux · GitHub

    Using nodes instead of fragments is rather a suggestion than a must. Nowadays devicetree programmers do not use them.

    These are some useful links to read about the devicetree; I will list them in order of importance:

    1. Release v0.4 · devicetree-org/devicetree-specification · GitHub - the official documentation posted by the guys who are developing the devicetree. I strongly recommend you read this, sometime. It helps a lot understanding the basics of the devicetree.

    2. Title (bootlin.com) - a great summary done by Thomas Petazzoni. There are multiple versions of this PPT available online and you can find videos on Youtube going through this. There are minor additional explanations in the videos, which could help, but usually the PDF is enough.

    3. Linux and the Devicetree — The Linux Kernel documentation

  • Hi Mark,

    Thanks for your reply!

    Sorry, I should have included a proper picture of my setup in my previous reply. The picture below was how I had my setup. The scope probes aren't pictured but they hook onto the wires that are currently in the middle of the breadboard using the hook attachments and ground clips.

    I've simplified this a bit based on your feedback (see image below). The setup is still not ideal - I think I need more ground connections between my PCB and the RPi and I should move away from using the ground clips. What I've done is soldered some wires onto the bottom of the rectangular headers on my PCB to be able to attach scope probes onto them.

    Thanks for the tip on the Schmartboard connectors!

    As you suggested in the last part of your reply, I tried reading the AD7176's ID register. The code below is what I've been using. From my understanding we need to write an 0x47 (as per the data sheet, equivalent to 0b01000111) command to the communications register and then keep the cs line low by sending two more dummy bytes and read the device's output during those two dummy byte transfers. Please correct me if I'm wrong

    import spidev
    import numpy as np
    
    # Initilise constants
    bus = 0
    device = 0
    
    # Initialise SPI bus
    spi = spidev.SpiDev(bus, device)
    spi.max_speed_hz = 1000000 # for RPi should be <=32MHz
    spi.mode = 0b11
    spi.lsbfirst = False
    
    data = spi.xfer2([0x47, 0x00, 0x00])
    print(hex((data[1]<<8) + data[2]))

    The scope shows that the MOSI line is working well (the image below shows the first 8 bits of the transfer specified in the code above). CS=Yellow, CLK=Cyan, MOSI=Magenta (MISO is omitted from this figure to minimise clutter).

    The next 16 bits are where things go wrong. The figure below shows the CS(Yellow), CLK(Cyan), and MISO(Blue) lines when the remaining 16bits ([0x00, 0x00]) are transferred. The MOSI(Magenta) is omitted to avoid clutter but was observed to be low (zero volts), as expected.

    What's concerning is that the figure show the line shifting voltages on the rising edge of the clock (5th rising edge in byte 2). Is this what you were referring to when you mentioned bit shifting in your original reply? I'm also confused as to why the MISO line shifts voltages even after the clock line returns to its idle position (the RHS of the image) is this normal behaviour or is my chip being weird? The image below shows a bit more of this behaviour (again the MOSI line is not shown for clarity but the results were captured running the python script above). Also, weirdly, the MISO line is active during the MOSI 0x47 transfer to the AD7176 - should this be happening?

    Further complicating matters is when I run the script multiple times, the value printed to screen jumps around from anywhere between 0x881c to 0x0b (the last line of my code prints the output which should be 0x0C94 according to the datasheet). 

    As always, any insight would be appreciated!

    Thanks,

    Jay

  • Hi Jay,

    Sorry I realized that there's a dangling question here. Regarding "shifting voltages on the rising edge of the clock (5th rising edge in byte 2)." - yes this is exactly the sort of thing I was referring to. The MISO line should only ever transition at falling SCK edges. This means that the rising edge may be ringing above VCC, then back down below the AD7176 SCK input's threshold voltage, which is being interpreted as a falling edge. Also note that while your scope may not be showing that effect, it could be due to your probing technique, scope bandwidth, etc. The only thing that matters is what the AD7176 sees.

    If that's the case - clock edges being misinterpreted, then all bets are off on the data itself. I'd focus on further improvement to your setup - more grounds, shorter grounds, and even separating the ribbon cable conductors to reduce crosstalk may help.

    Another anecdote - as the driver for the ADIN1110 (SPI interface to Raspberry Pi) was being developed, the setup looked similar to yours. The author had to throttle back the SPI frequency to a few MHz (one or two.) When the CN0575 boards showed up, which use the ADIN1110, and includes a full 40-pin interface connector with all ground pins connected to a proper ground plane, we were able to bump the SCK frequency all the way to the datasheet maximum: https://github.com/analogdevicesinc/linux/blob/rpi-5.10.y/arch/arm/boot/dts/overlays/rpi-cn0575-overlay.dts#L28

    Of course it is the edge rate that is more important than the frequency, but as frequency increases, ringing edges will bleed into one another. We didn't do any signal integrity measurements on the hand wired setup, it was better to just go straight to the PC board.

    Could you re-do your board to include the Raspberry Pi connector? There are lots of low-cost, quick-turn PC board manufacturers you could use.

    -Mark

    P.S. the MISO line wiggling AFTER the SCK has stopped might just be the DRDY# indication - the period looks a bit shorter than 1 division at 5 us per division, and the max sample rate is 250 ksps, or a period of 4 us.

  • Hi Mark,

    Thanks for your reply!

    I managed to get my board working - I switched out the benchtop DC power supply with a small ToolkitRC P200 and 2Ah Xfinity Plus battery. I've included a picture of my setup below the banana plugs on the right get plugged into the P200 power supply (not pictured). Power to the pi is regulated down to 5V through the switching reg on the black PCB and fed into the RPi through a standard USB-A to USB-C cable. The rest is the same as before with the addition of another wire connecting the DOUT/RDY to GPIO pin 22 on the RPi to monitor for data ready pings.

    Regardless, I agree that my grounding needs to be improved. I'll implement your suggestions and let you know how it goes.

    I also agree that the MISO wiggles after the comms are from data ready asserts - my apologies, I completely forgot about it when I posted my last message.

    I appreciate all the help!

    -Jay