Post Go back to editing

iio and pyadi-iio buffer flow control how to tell how full a tx buffer is or rx buffer has data in it

I'm currently working in python on a pluto sdr using the AD9361 chipset. Most of the examples I have seen are using cyclic buffers. Such as the examples here:

https://analogdevicesinc.github.io/pyadi-iio/buffers/index.html#buffer-examples

I have not seen any concrete examples of using a streaming interface that correctly handles flow control or buffer overflow / buffer starvation. In the simplest cyclic case you create an array or list and pass that to the TX function then you are done. There is a call like this:

sdr.tx(iq)

In a streaming example you would want to add to the transmitted samples as they go out in a controlled fashion where you do not under run the TX buffers and you also do not let them grow to the point of overflowing. Typically if the .tx() was called it could return a watermark indicating how many buffers of the set buffer size was left in the dma queue to be transmitted or how many freebuffers are left, or total number of samples outstanding left to be transmitted. Or there would be other methods that would return similar information. These numbers let you know if you need to speed up or slow down the generation of samples that are output to the DAC for streaming data transfer.

The same is true for the input RX.

so x = sdr.rx() would set the array or list to x then the user can process that data but there does not seem to be a way to see if the buffers that the sdr object has control of is about to over flow or under flow. Does the sdr.rx() method block until it has enough data to fill the buffer of the block size? If you perform the read using the ".rx() method does it return everything that it has in increments of the block size?

Are there calls that can tell the user app what the data watermark levels are for both TX and RX methods for iio_buffer?

Here are the links where I am looking at:

https://wiki.analog.com/resources/tools-software/linux-software/pyadi-iio

https://analogdevicesinc.github.io/pyadi-iio/buffers/index.html

http://analogdevicesinc.github.io/libiio/v0.20/libiio/index.html

https://wiki.analog.com/resources/tools-software/linux-software/libiio_internals

https://ez.analog.com/linux-software-drivers/f/q-a/107129/libiio-kernel-buffers

https://ez.analog.com/linux-software-drivers/f/q-a/534095/libiio-refill-push-buffers

https://ez.analog.com/linux-software-drivers/f/q-a/120336/pyadi-iio-receiver-issues-on-adrv9361-z7035

  • Assuming you are pulling data or pushing data fast enough, the rx and tx methods will block when the internal queues fill (on TX) or have no data (on RX).  Underflow and overflow events are exposed through registers and not directly in the buffers. This feature comes from the HDL which is not applicable for all hardware that libiio supports. This is why it's not currently integrated together. These registers are accessible through libiio but are not tied into the datastreams.

    To my knowledge libiio does not expose the internal queue of the DMA. You would have to dig more into DMA driver itself.

    Please see here: High-speed mmap interface

    The in-kernel IIO driver are using the Linux DMA engine drivers.

    -Travis

  • Thanks Travis,

    Good information to know.The sample rates are fairly slow. This is a narrow band application so I believe the app should be able to keep up with the sample rate easily. The sample rate is less than 1Msps.

    How would  the user app read the underflow and overflow registers? Is there a python method that allows access? Where are they located in the register memory map and are they exposed to the python interface? A quick snip of could would be good to look at.

    Leonard.

  • btw the part is the AD9361 / 4 . Currently using it on the Pluto for demo purposes.

  • Something like this should work:

    sdr = adi.Pluto()
    
    r = 0x80000088
    # Clear status bits
    sdr._rxadc.reg_write(r,0x6)
    
    # Check for overflow
    def print_on_overflow(dev,is_rx,r):
    	status = dev.reg_read(r)
    	if is_rx:
    	    if status & 0b0100:
    		    print("Overflow")
    		    dev.reg_write(r,status)
    	elif status & 0b0001:
    		print("Underflow")
    		dev.reg_write(r,status)
    	
    
    while True:
    	data = sdr.rx()
    	print_on_overflow(sdr._rxadc,True,r)
    	sdr.tx(data)
    	print_on_overflow(sdr._txdac,False,r)

    -Travis

  • OK thanks

    the code you have above was only was giving me underflows and not overflows.

    when I reduced the while loop to this:

    while True:
    # data = sdr.rx()
    print_on_overflow(sdr._rxadc, True, r)
    sdr.tx(iq)

    forcing to always over flow and still had only underflows.

    I changed the function to this:

    def print_on_overflow(dev, is_rx, r):
    status = dev.reg_read(r)
    if is_rx:
    if status & 0b0100:
    print("Overflow")
    dev.reg_write(r, status)
    else:
    if status & 0b0001:
    print("Underflow")
    dev.reg_write(r, status)

    and I believe this works for both under and over flows.

    Thanks Travis.

    L

  • Ah thanks. I guess that's what happens when I write from memory. I've updated my original code.

    -Travis

  • Thank you very much for the code snippets.

    Where can I find information about this particular register? I'd like to read more about the meaning of each individual bit.