MMIO data format

Hi all,

I have a question about the use of the MMIO package for reading data out of a BRAM.

My setup with the ZCU111 is the following:

  • Transmitter side: 16samples à 16bits (either high (0x7FFF) or low level (0x8000)) stored in a constant → that means this pattern is repeated from the transmitter
  • DAC: Reference clock: 4GHz, Sampling rate: 4GSPS, Interpolation x4, 16 samples per AXI-stream cycle, low-speed single-ended balun DAC used
  • DAC → ADC: Directly connect the DAC to the ADC
  • ADC: Reference clock: 4GHZ, Sampling rate: 4GSPS, Decimation x2, 8 samples per AXI-stream cycle → 8*16=128bits wide bus, low-speed single-ended balun ADC used
  • Receiver side: The ADC data stream comes with 128bits at 250MHz. These data I store in a simple dual-port BRAM (Port A: 128bits wide, 256 words deep; Port B: 32bits wide, 1024 words deep). At Port B I got a BRAM controller to read the data out with PYNQ. The address of the BRAM is controlled by a

The PYNQ code to read out the data from the BRAM is:

from pynq import MMIO

base_address = 0xA0000000
mem_size = 4096
mmio = MMIO(base_address, mem_size)

Read out the data from BRAM:
received_data = [0]*1024

for i in range(0,1024)
received_data[i] = mmio.read(i*4)
#address increment of 4 because 32bit system

Well… I read out 32bits from the BRAM. That means 2 samples at the same time. The received data in PYNQ is represented as an integer.
In order to split this 32bits wide word into two 16bits (or 12bits, because the ADC has a resolution of 12bits), I convert the integer back into a binary representation and split the string (as shown in the screenshot).

Now my question: What is the MMIO data format?
If I look on my 32bit words, the data makes no sense to me.
I would assume that the 32bits have the following format:
12bits of sample2, 4 redundant bits, 12bits of sample1, 4 redundant bits (because the data from the ADC is MSB aligned).
In other representation:
b12,b11,b10,…,b2,b1,x,x,x,x,a12,a11,a10,…,a2,a1,x,x,x,x
Where x is either all-zero or all-ones.

However, in my data I cannot see such a pattern.
When I then split the binary string of 32bits into 2 samples with 12 bits, reconvert into integer format and adapt the number by the two’s complement, my signal is not as defined in my transmitter side constant…

Do I miss something in my interpretation of the data format delivered by the MMIO.read function?

Thanks for any help!

Kind regards
Patrick

Patrick,

Do you have the design I could look at to help diagnose this? I can build it from the tcl file, for example. Thank you.

Hello Chris,

Many thanks for the help!
I have attached the tcl file. Furthermore, I uploaded the complete Vivado Project in the Drive.

https://drive.google.com/drive/folders/1ery9XjKliUl5aDVyDmJ5JoB52hQtfiGJ?usp=sharing
realtime_dac_adc_loopback_bd.tcl (48.4 KB)

Kind regards,
Patrick

Meanwhile I connected the ADC to the DAC again to check on the oscilloscope that the data is also correctly present after the ADC (a DAC-ADC-DAC loop). I can see the signal perfectly on the oscilloscope… I.e. up to the ADC everything works.

Here is my jupyter notebook:
DAC_ADC_Loop.ipynb (324.1 KB)

  • Could it be an addressing issue when writing into the BRAM? But then I should still see a repeating pattern, even if its not the correct one. My BRAM Port A, where I write the ADC data into, is 256 deep and 128bits wide. I address it with a counter IP core, where I count up to 4096 in steps of 16 (step size: 4x4, because 32bit system → count up in steps of 4 and my output Port B will be 4 times deeper, such that I need to take this also in account). With 4096/16=256 , I write data into 256 BRAM slots and read out with a word width of 32 bits → 256*128/32 = 1024, which is also the memory size I specified.

  • Sometimes I’ve seen in the PYNQ MMIO tutorials, that the BRAM needs (somehow) to be initialized by writing a zero into the zeroth address. I’ve only seen this for writing into the BRAM (but didn’t found a documentation for that). Do I need to activate the BRAM like this also for reading?

Kind regards
Patrick

I got the solution!

my counter repeats continuously as soon as he reaches its maximum count.
That means my ADC overwrites the BRAM all the time.
However, on the other side of the BRAM, I read with another clock rate the data out in PYNQ. That means, during I read, the data changes again and that’s the reason why I have a weird signal.

I now added a GPIO port at the ZYNQ and use the GPIO function in PYNQ to enable the “en” signal at the Port A BRAM.

Kind regards
Patrick

Good news. I requested access to the drive with the original project. Has that been updated? I’d like to see your complete solution, as I’m trying to do something similar. Thank you.