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

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

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

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

  • Thanks for your assistance. I have a simple resistive divider,  REFOUT--R1--R2--R3--Vss, where R1=R3=10k and R2=10 ohms. AIN0 and AIN1 are connected on either side of R2. This should give me a small DC voltage. I took 100 readings at 100 sps using Pyadi-iio, and every reading was exactly the same, which looks wrong. Then I took 100 readings using iio_readdev and found a standard deviation of 3.8 counts, with range 8291 to 8311 counts; this is about what I expect.  I will try to enclose the readings.dat file, assuming this forum accepts binary files.

    iio_readdev -u "ip:localhost" -b 256 -s 100 -T 0 ad7124-8 voltage0-voltage1 > readings.dat

    [EDIT: see next message for readings.dat in ZIP file]

    import adi  # use the Pyadi-iio library

    my_ad7124 = adi.ad7124(uri="ip:localhost")

    sc = my_ad7124.scale_available
    my_ad7124.channel[0].scale = sc[-1] # get highest range

    my_ad7124.sample_rate = 100 # this sampling rate
    my_ad7124.rx_enabled_channels = [0]
    my_ad7124.rx_buffer_size = 100 # this many samples
    my_ad7124._ctx.set_timeout(100000)

    data = my_ad7124.rx()
    print(data)

    [2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904 2427904
    2427904]

  • A second attempt to upload the readings.dat binary file, now in a .zip format:

    readings.zip

  • Are you able to remove/comment these lines and report back ?

    https://github.com/analogdevicesinc/pyadi-iio/blob/master/adi/rx_tx.py#L337-L343 and replace them with 

    x=data

    The patch is a little bigger than this, but wanted to doublecheck that it works for you as well ... 

  • I made that change to /usr/local/lib/python3.9/dist-packages/adi/rx_tx.py  and re-ran the Python example code I listed above. The print(data) output now looks like what previously were all the same number in a text format, have become a binary representation of slightly different numbers:

    bytearray(b'm \x00\x00p \x00\x00n \x00\x00k \x00\x00n \x00\x00n \x00\x00j \x00\x00a \x00\x00g \x00\x00l  [...and so forth]

  • Changing the last line of Python example code to print it in hex format, this looks promising. Looks like we now have 32-bit integers that look like real readings:

    print( ' '.join('{:02x}'.format(x) for x in data) )

    6d 20 00 00 71 20 00 00 6e 20 00 00 70 20 00 00 6b 20 00 00 6f 20 00 00 70 20 00 00 6f 20 00 00 6a 20 00 00 64 20 00 00 68 20 00 00 6c 20 00 00 6d 20 00 00 68 20 00 00 6a 20 00 00 70 20 00 00 71 20 00 00 6d 20 00 00 6b 20 00 00 69 20 00 00 67 20 00 00 6a 20 00 00 6e 20 00 00 6c 20 00 00 6b 20 00 00 72 20 00 00 70 20 00 00 6a 20 00 00 68 20 00 00 6a 20 00 00 6f 20 00 00 6c 20 00 00 6e 20 00 00 6b 20 00 00 6a 20 00 00 6e 20 00 00 69 20 00 00 6c 20 00 00 72 20 00 00 70 20 00 00 6d 20 00 00 6c 20 00 00 6e 20 00 00 73 20 00 00 71 20 00 00 6a 20 00 00 6c 20 00 00

    [...and so forth]

  • An additional tweak to the display code shows that yes, the data now looks good:

    fmt = "%dI" % (len(data) // 4)
    print( list(struct.unpack(fmt, data) ) )

    [8304, 8305, 8307, 8302, 8302, 8306, 8301, 8302, 8300, 8301, 8303, 8304, 8304, 8303, 8299, 8300, 8297, 8301, 8304, 8305, 8293, 8298, 8302, 8299, 8295, 8295, 8299, 8303, 8306, 8304, 8305, 8303, 8295, 8298, 8297, 8297, 8300, 8298, 8302, 8304, 8301, 8299, 8301, 8304, 8299, 8299, 8304, 8304, 8302, 8301, 8299, 8297, 8301, 8305, 8303, 8300, 8298, 8298, 8298, 8301, 8300, 8301, 8300, 8302, 8300, 8294, 8297, 8299, 8300, 8299, 8299, 8298, 8298, 8301, 8302, 8300, 8298, 8294, 8297, 8303, 8299, 8297, 8306, 8300, 8297, 8302, 8300, 8299, 8300, 8295, 8304, 8301, 8301, 8294, 8297, 8294, 8293, 8294, 8295, 8298]

  • Thanks, we will patch the library as soon as possible .. 

    -Adrian