Post Go back to editing

ad7124_simple_capture.py does not find ad7124 device

Category: Software
Product Number: none
Software Version: IIO Daemon version 0.24.cc96e446

I'm using Kuiper Linux running on a Raspberry Pi 3B.  'uname -a' says: 

Linux analog 5.10.63-v7+ #1 SMP Wed Aug 3 14:47:24 UTC 2022 armv7l GNU/Linux

I have attached the EVAL-AD7124-8-PMDZ board to the Pi GPIO as described in https://wiki.analog.com/university/labs/software/precision_adc_toolbox

I know the board is connected properly and it works, because the ADI IIO Oscilloscope program works as expected, and shows reasonable values. Apparently it uses a sampling rate of about 10 samples per second. Also I can use iio_reddev for example

sudo iio_readdev -u local: -b 256 -s 10 -T 0 ad7124-8 voltage0-voltage1 > readings.dat 

and get reasonable binary data written to the "readings.dat" file. For reference, here is what iio_attr says:

analog@analog:~/ad7124 $ iio_attr -c -u local:
IIO context has 5 devices:
hwmon0, cpu_thermal: found 1 channels
hwmon1, rpi_volt: found 1 channels
iio:device0, ad7124-8: found 8 channels
iio_sysfs_trigger: found 0 channels
trigger0, ad7124-8-dev0: found 0 channels

However when I try to run a python program like ad7124_simple_capture.py from https://github.com/mthoren-adi/precision_adc_toolbox/blob/master/ad7124_simple_capture.py I have a problem as shown below:

analog@analog:~/ad7124 $ python ad7124_simple_capture.py ip:localhost
Traceback (most recent call last):
File "/home/analog/ad7124/ad7124_simple_capture.py", line 51, in <module>
my_ad7124 = adi.ad7124(uri=my_ip)
File "/usr/local/lib/python3.9/dist-packages/adi/ad7124.py", line 74, in __init__
for ch in self._ctrl._channels:
AttributeError: 'Device' object has no attribute '_channels'

I get the same result with no argument, instead of "ip:localhost". It looks like the Pyadi-iio cannot find the locally attached AD7124 chip, even though iio_readdev has no problem working. I also tried the loopback IP address, and got a different error:

analog@analog:~/ad7124 $ python ad7124_simple_capture.py 127.0.0.1
Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/adi/context_manager.py", line 65, in __init__
self._ctx = iio.Context(self.uri)
File "/usr/local/lib/python3.9/dist-packages/iio.py", line 1358, in __init__
self._context = _new_uri(_context.encode("ascii"))
File "/usr/local/lib/python3.9/dist-packages/iio.py", line 56, in _check_null
raise OSError(err, _strerror(err))
OSError: [Errno 38] Function not implemented

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/analog/ad7124/ad7124_simple_capture.py", line 51, in <module>
my_ad7124 = adi.ad7124(uri=my_ip)
File "/usr/local/lib/python3.9/dist-packages/adi/ad7124.py", line 54, in __init__
context_manager.__init__(self, uri, self._device_name)
File "/usr/local/lib/python3.9/dist-packages/adi/context_manager.py", line 67, in __init__
raise Exception("No device found")
Exception: No device found

I see that the iiod daemon is running. What am I doing wrong?

analog@analog:~/ad7124 $ ps aux | grep iiod
root 670 0.0 0.2 66608 2684 ? Ssl 22:26 0:00 /usr/sbin/iiod

  • I found that line 74 of this file https://github.com/analogdevicesinc/pyadi-iio/blob/master/adi/ad7124.py has an apparent typo. There is an extra underscore on the .channels member, so

    for ch in self._ctrl._channels:  should actually be for ch in self._ctrl.channels:

    having made that change to the library, the example now works as expected for me, at least for single reads.

    Buffered data capture does return values but the values are nearly all identical, as if the driver is copying the same reading many times over, instead of waiting for a new conversion result for each read. Using other software I know this chip only rarely produces two or three identical readings in a row, and it should never happen 50 times in a row.

    The python program needs to be run with sudo if run on the same machine the AD7124 is attached to, but the same program works OK from a remote host on the LAN knowing only the IP address of the machine.

  • Progress: the error message was actually helpful: "'Device' object has no attribute '_channels'" is because indeed, the source apparently has a typo, writing "_channels" when it should be ".channels".  I have made a pull request with this one-character fix. 

    github.com/.../377

  • Progress update: when I run this code:

    import adi

    adc = adi.ad7124(uri="ip:localhost")
    adc.rx_buffer_size = 400 # get this many samples
    adc.sample_rate = 1000
    adc.rx_enabled_channels = [0] # first channel only
    adc._ctx.set_timeout(10000) # in what units?
    adc_data = adc.rx() # get one buffer of samples
    for i in adc_data:
        print(i)

    I do get 400 numbers returned in the "adc_data" array. It is a large decaying exponential (plausible, due to an external RC time constant in my circuit, if the converter has just switched on the Vref output pin when the sequence starts) but it moves in very large steps. Each step is exactly 65536 counts in size. So it looks like the low-order 16 bits of each result are being truncated, eg. the 24-bit converter appears as if it is an 8-bit converter being scaled up. Could there be an "endian" machine-architecture problem somewhere?  This is running on ADI Kuiper Linux on the Raspberry Pi.  I do not have these problems when getting separate raw values individually, for example with  reading = adc.channel[0].raw  I get very close to the expected DC value, with only about 15 counts of noise.

     400 data points from AD7124

  • Hi Jbeale,

    I'm going to try to replicate what you're seeing here. There have been a few changes to the driver and pyadi-iio since that exercise was written, not sure which have made their way into the Kuiper image.

    I've got the script running, just need to bias the inputs at a few mV to get a reasonable noise reading.

    In the meantime, can you confirm you're using the latest Kuiper release, 2021_r1, from HERE,  (which, contrary to the name, was released this August)?

    -Mark

  • Thank you very much for your reply! Yes, that is the link I used for the Kuiper image, and the device reports it is using a version from 3-Aug-2022:

    analog@analog:~ $ uname -a
    Linux analog 5.10.63-v7+ #1 SMP Wed Aug 3 14:47:24 UTC 2022 armv7l GNU/Linux

  • Hi Jbeale,

    So far it looks like you're correct, I see 2^16 steps in the data. I've contacted the developers of this driver.

    Are you able to work with raw (unbuffered) data for now? That should be okay for doing histograms, noise measurements, etc. where timing is not critical.

    -Mark

  • I found that the iio-readdev utility is able to read the device as expected, although at one fixed sampling rate. I wrote some crude code to convert the 4-byte unsigned binary words that utility sends out, into text numbers and feed that into a network port so I can use the data on another machine on my network; this works well enough for testing purposes. https://github.com/jbeale1/data-remote   

    However it would be great to have the Pyadi-iio library operating properly with this chip, that would be much more convenient; thank you. 

    -John

  • What is the sample rate you are using ? Can you modify the python script to use that particular sample rate and report the results ?

    For testing purposes, can you use a low sample rate in your initial script ?

    adc.sample_rate = 100 and maybe get less samples ?

    -Adrian

  • Yes, I did try a rate of 100 samples per second, and also lower rates. In every case, I found that the buffered data values returned from the adc.rx() call to the Pyadi-iio library were quantized in the same way, so it appears that the low-order 16 bits of the reading do not change. For a noise test with a simple resistive divider at a nominally fixed DC voltage, this makes the reading appear stuck because every output value is exactly the same, implying zero noise.

    Using the iio_readdev utility I see that is not true, for example at 100 sps I found 3.39 counts RMS of noise, with a 10k /  10 ohm / 10k resistive divider at the input. I have no concern about the hardware performance, my question is specific to the Python software.

  • I understand. Is it possible to provide the readings.dat file (generated with iio_readdev), I can take a look at it ? Also let me know what it should contain ( a constant DC voltage, an RC circuit, etc ..).

    I can then dry run that file through the pyadi-iio and see where the conversion problem might be.

    -Adrian