Jump to content
  • 0

Zmod DAC 1411 4096 Sample Limit?


timmy

Question

I've been attempting to make a program that produces a 16383 sample long linear chirp on an Eclypse Z7 (DAC1411). Stuff is going well, I'm using Vivado 2019.1 to match with the IP create_hier script, but I can't seem to produce a signal over 4096 samples long. Attached is my main code and a photo of a scope showing the first quarter of the chirp.

Any help, or further questions would be greatly appreciated. I'm very new to FPGA programming.

main.cc

Scope (3).jpg

Link to comment
Share on other sites

18 answers to this question

Recommended Posts

  • 0

Hi @timmy,

Welcome to the forums.

The implementation of DMA and use of buffering in Zynq PL in the create_hier script design limits the buffer size available. The AXI adapter IP for the DAC includes circular buffers which are used to hold the samples that are played out through the DAC controller. The buffers are limited to 2^14 (4096) samples to save on BRAM resources - see section 4.2 here: https://github.com/Digilent/vivado-library/blob/zmod/v1/2019.1-2/ip/Zmods/AXI_Zmod_DAC1411/doc/ZmodDAC1411AxiAdapter.pdf.

There are several alternative approaches to the problem:

1. Use the WaveForms support. AWG buffers there are up to 64 kS per channel with a single DAC and 32 kS if you want to use two DACs. https://digilent.com/reference/programmable-logic/eclypse-z7/waveforms. This is the easiest approach if you don't need the hardware to be particularly configurable. Look into custom waves, see the attached screenshot.

2. Work in Vivado to generate an input pattern in hardware. Depending on the complexity of the signal, it could be relatively straightforward to just generate it in PL and ignore the PS. Modifying the low-pass filter demo could be a starting point: https://digilent.com/reference/programmable-logic/eclypse-z7/demos/low-level-low-pass-filter Edit - this approach would be complex to implement given your Chirp function, at least for a beginner.

3. Different DMA approaches can be used to stream data out from DDR rather than buffering in PL. This is a complex topic and requires extensive changes in hardware and software. This under-construction demo attempts to implement it in 2021.1: https://digilent.com/reference/programmable-logic/eclypse-z7/demos/ddr-streaming. There are still bugs that need ironed out.

Thanks,

Arthur

image.png

Link to comment
Share on other sites

  • 0
18 hours ago, artvvb said:

The buffers are limited to 2^14 (4096) samples to save on BRAM resources - see section 4.2

Thanks for the warm welcome @artvvb!

I'm still a little confused. 2^14 = 16,384, we seem to missing a factor of 4 somewhere. The documents states:image.png.a75a7a5f3360608836509b8e75485d50.png

and section 4.2 says:

image.png.0637bf8d00a676b40b7ceb21bc9e20b0.png

which is 16,383? Is this shared between multiple peripherals and partitioned or something?

I will default to the WaveForms approach if I can't get this baremetal version working. The final system will incorporate a sort of sonar device, and I was hoping to do the convolution/matched filter/cross-correlation in PL, but that might be a big job...

Much thanks

Edited by timmy
Link to comment
Share on other sites

  • 0

Ah, you're correct, my mistake, the buffer should be 16,384 samples per channel - the actual implementation in hardware uses one 18k BRAM to create one 16,384x1 dual port RAM per bit, for all 28 bits of the two 14-bit channels, with a 14-bit counter for addressing to read data back out.

I've reproduced the issue of data after the first 4096-ish being zeroed and am investigating further whether there's a bug in zmodlib or in the AXI controller IP.

Thanks,

Arthur

Link to comment
Share on other sites

  • 0

Hi @timmy,

There's a bug in the DMA implementation in Vivado. The "Width of Buffer Length Register" parameter in the DMA configuration should be increased to 16 bits from 14 bits, to increase the amount of data that a single DMA transfer is capable of sending to the circle buffers - this value reflects a maximum number of bytes that can be transferred. Currently, when the length of the transfer is written to the DMA, the top two bits are masked off, and only a quarter of the maximum amount of data can be sent.

Once the hardware is regenerated and the new HDF file has been used to update the hardware platform, no software changes are required to get it working.

Updated sources should be available on Github soon, at least for the baremetal projects.

Thanks,

Arthur

image.png

Link to comment
Share on other sites

  • 0
On 7/7/2023 at 3:08 PM, artvvb said:

There's a bug in the DMA implementation in Vivado. The "Width of Buffer Length Register" parameter in the DMA configuration should be increased to 16 bits from 14 bits, to increase the amount of data that a single DMA transfer is capable of sending to the circle buffers - this value reflects a maximum number of bytes that can be transferred. Currently, when the length of the transfer is written to the DMA, the top two bits are masked off, and only a quarter of the maximum amount of data can be sent.

Do you specify the length of a transfer in bytes, or in words on AXI Steam interface? AXI DMA IP expects the former, and this is a very common mistake.

Link to comment
Share on other sites

  • 0

Apologies for the confusion, to be clear, when I said that there's a bug in the DMA implementation, I intended to say that the selections we had made for the DMA configuration were incorrect - for exactly the reason you stated, that it needs the transfer length in bytes - not that there's a problem with the Xilinx IP.

Link to comment
Share on other sites

  • 0
1 hour ago, artvvb said:

Apologies for the confusion, to be clear, when I said that there's a bug in the DMA implementation, I intended to say that the selections we had made for the DMA configuration were incorrect - for exactly the reason you stated, that it needs the transfer length in bytes - not that there's a problem with the Xilinx IP.

No worries, I didn't mean to imply anything - I merely mention that because I've made that exact mistake myself more times than I'm willing to admit 🤐

Edited by asmi
Link to comment
Share on other sites

  • 0
On 7/6/2023 at 5:17 PM, artvvb said:

3. Different DMA approaches can be used to stream data out from DDR rather than buffering in PL. This is a complex topic and requires extensive changes in hardware and software. This under-construction demo attempts to implement it in 2021.1: https://digilent.com/reference/programmable-logic/eclypse-z7/demos/ddr-streaming. There are still bugs that need ironed out.

 

 

This may need a new thread because I've been attempting to use the DDR/DMA streaming approach. I want to stream to the AWG and stream from the Scope at the same time. So far I just combined the main.c code from the s2mm_cyclic_transfer and the mm2s_single_transfer demos, as well as merged all the includes.
Unfortunately, I can't seem to include "test_stream_sink.h" AND "test_stream_source.h" without error. It claims AxiStreamSourceMonitor does not exist when called. I'm sure there's something fundamentally wrong with my approach and would love some help

 

.image.png.1f538b30e3ff7a0849f4b08d505b30fe.png

Edited by timmy
Link to comment
Share on other sites

  • 0

Odd, that type should be coming in through an "AxiStreamSourceMonitor.h" header in the BSP, if you're using the same platform, I'd expect it to be there. Are you seeing any errors in the platform build which might cause the library that's getting linked against not to complete a build? You can view the platform build console through the "display selected console" selector, see below.

image.png

What are your includes, and have you copied all sources into the same app's src directory? I'd expect something like this to work - which builds on my machine, with no other changes to the scope example main.c file, for what it's worth.

Quote

#include "xparameters.h"
#include "xil_printf.h"
#include "sleep.h"
#include "xuartps.h"

#include "xaxidma.h"
#include "trigger.h"
#include "test_stream_source.h"
#include "s2mm_transfer.h"
#include "zmod_scope_axi_configuration.h"
#include "manual_trigger.h"
#include "xstatus.h"
#include "userregisters.h"
#include "scope_calibration.h"

#include "xil_cache.h"
#include "test_stream_sink.h"
#include "mm2s_transfer.h"
#include "zmod_awg_axi_configuration.h"
#include "awg_calibration.h"

Thanks,

Arthur

Link to comment
Share on other sites

  • 0
Quote

10:14:38 **** Build of configuration Debug for project ChirpStream ****
make all
make --no-print-directory pre-build
a9-linaro-pre-build-step
' '
make --no-print-directory main-build
'Building file: ../src/main.c'
'Invoking: ARM v7 gcc compiler'
arm-none-eabi-gcc -Wall -O0 -g3 -IC:/Users/Tim/Desktop/Anemometer_2023/DDR_Streaming_Vivado_2021_1/Testing_CaptureAndChirpStream/design_1_wrapper/export/design_1_wrapper/sw/design_1_wrapper/standalone_ps7_cortexa9_0/bspinclude/include -I"C:\Users\Tim\Desktop\Anemometer_2023\DDR_Streaming_Vivado_2021_1\Testing_CaptureAndChirpStream\design_1_wrapper\hw\drivers" -I"C:\Users\Tim\Desktop\Anemometer_2023\DDR_Streaming_Vivado_2021_1\Testing_CaptureAndChirpStream\design_1_wrapper\export\design_1_wrapper\hw\drivers" -c -fmessage-length=0 -MT"src/main.o" -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.c"
../src/main.c:162:2: error: unknown type name 'AxiStreamSourceMonitor'
  162 |  AxiStreamSourceMonitor TrafficGen;
      |  ^~~~~~~~~~~~~~~~~~~~~~
../src/main.c: In function 'MinMaxAcquisition':
../src/main.c:178:2: error: unknown type name 'AxiStreamSourceMonitor'; did you mean 'AxiStreamSinkMonitor'?
  178 |  AxiStreamSourceMonitor *TrafficGenPtr = &(InstPtr->TrafficGen);
      |  ^~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor
../src/main.c:215:2: warning: implicit declaration of function 'AxiStreamSourceMonitorSetSelect'; did you mean 'AxiStreamSinkMonitor_SetSelect'? [-Wimplicit-function-declaration]
  215 |  AxiStreamSourceMonitorSetSelect(TrafficGenPtr, SWITCH_SOURCE_SCOPE);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor_SetSelect
../src/main.c:215:49: error: 'SWITCH_SOURCE_SCOPE' undeclared (first use in this function)
  215 |  AxiStreamSourceMonitorSetSelect(TrafficGenPtr, SWITCH_SOURCE_SCOPE);
      |                                                 ^~~~~~~~~~~~~~~~~~~
../src/main.c:215:49: note: each undeclared identifier is reported only once for each function it appears in
../src/main.c: In function 'TestInputWithMonitor':
../src/main.c:315:2: error: unknown type name 'AxiStreamSourceMonitor'; did you mean 'AxiStreamSinkMonitor'?
  315 |  AxiStreamSourceMonitor *TrafficGenPtr = &(InstPtr->TrafficGen);
      |  ^~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor
../src/main.c:347:49: error: 'SWITCH_SOURCE_GENERATOR' undeclared (first use in this function)
  347 |  AxiStreamSourceMonitorSetSelect(TrafficGenPtr, SWITCH_SOURCE_GENERATOR);
      |                                                 ^~~~~~~~~~~~~~~~~~~~~~~
../src/main.c:360:2: warning: implicit declaration of function 'AxiStreamSourceMonitorSetEnable'; did you mean 'AxiStreamSinkMonitor_GetIdle'? [-Wimplicit-function-declaration]
  360 |  AxiStreamSourceMonitorSetEnable(TrafficGenPtr, 1);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor_GetIdle
../src/main.c: In function 'AcquireDataToConsole':
../src/main.c:423:2: error: unknown type name 'AxiStreamSourceMonitor'; did you mean 'AxiStreamSinkMonitor'?
  423 |  AxiStreamSourceMonitor *TrafficGenPtr = &(InstPtr->TrafficGen);
      |  ^~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor
../src/main.c:470:49: error: 'SWITCH_SOURCE_SCOPE' undeclared (first use in this function)
  470 |  AxiStreamSourceMonitorSetSelect(TrafficGenPtr, SWITCH_SOURCE_SCOPE);
      |                                                 ^~~~~~~~~~~~~~~~~~~
../src/main.c: In function 'LevelTriggerAcquisition':
../src/main.c:538:2: error: unknown type name 'AxiStreamSourceMonitor'; did you mean 'AxiStreamSinkMonitor'?
  538 |  AxiStreamSourceMonitor *TrafficGenPtr = &(InstPtr->TrafficGen);
      |  ^~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor
../src/main.c:591:49: error: 'SWITCH_SOURCE_SCOPE' undeclared (first use in this function)
  591 |  AxiStreamSourceMonitorSetSelect(TrafficGenPtr, SWITCH_SOURCE_SCOPE);
      |                                                 ^~~~~~~~~~~~~~~~~~~
../src/main.c: In function 'main':
../src/main.c:665:2: warning: implicit declaration of function 'AxiStreamSourceMonitor_Initialize'; did you mean 'AxiStreamSinkMonitor_Initialize'? [-Wimplicit-function-declaration]
  665 |  AxiStreamSourceMonitor_Initialize(&(Pipe.TrafficGen), SOURCE_MONITOR_BASEADDR);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |  AxiStreamSinkMonitor_Initialize
../src/main.c:673:23: warning: unused variable 'HighGainDcCoupling' [-Wunused-variable]
  673 |  ZmodScopeRelayConfig HighGainDcCoupling = {1, 1, 1, 1};
      |                       ^~~~~~~~~~~~~~~~~~
../src/main.c:671:23: warning: unused variable 'CouplingTestRelays' [-Wunused-variable]
  671 |  ZmodScopeRelayConfig CouplingTestRelays = {0, 0, 1, 0};
      |                       ^~~~~~~~~~~~~~~~~~
make[1]: *** [src/subdir.mk:53: src/main.o] Error 1
make: *** [makefile:35: all] Error 2

10:14:40 Build Finished (took 1s.711ms)

Here's the build errors. It just looks like the "AxiStreamSourceMonitor.h" isn't being included correctly. It is in my defined includes and I did copy over all of the includes from the s2mm example. Maybe I did this wrong (currently looking into it), but I do notice that if I comment out the "test_stream_sink.h" (AxiStreamSinkMonitor.h), then I get the same type error but for AxiStreamSinkMonitor:

image.png.b36a95426625e86a2929e906338c256a.png

Quote

#include "xparameters.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "test_stream_sink.h" // Appears to have issues
#include "mm2s_transfer.h"
#include "xuartps.h"
#include "zmod_awg_axi_configuration.h"
#include "awg_calibration.h"


#include "xaxidma.h"
#include "xil_printf.h"
#include "sleep.h"
#include "trigger.h"
#include "test_stream_source.h"
#include "s2mm_transfer.h"
#include "zmod_scope_axi_configuration.h"
#include "manual_trigger.h"
#include "xstatus.h"
#include "userregisters.h"
#include "scope_calibration.h"

#include <stdio.h>
#include <math.h>

image.png.124a77b20d3511823c1dbe166f7e2b33.png

Edited by timmy
Link to comment
Share on other sites

  • 0

It seems like the first one to be included dominates and the other is unusable.
If I " #include "test_stream_sink.h" " first I can call AxiStreamSinkMonitor just fine, but not AxiStreamSourceMonitor

But if I " #include "test_stream_source.h" " first the opposite happens...

Link to comment
Share on other sites

  • 0

@timmy

Found it. Pretty big oversight on my part, apologies. The test_stream_sink and test_stream_source headers use the same protection macro, so only the first one is successfully included. I should have tried building with definitions from both headers actually in use last week. Change the first two lines in test_stream_sink.h as follows:

Quote

#ifndef TEST_STREAM_SINK_H_   /* prevent circular inclusions */
#define TEST_STREAM_SINK_H_

And test_stream_source.h:

Quote

#ifndef TEST_STREAM_SOURCE_H_   /* prevent circular inclusions */
#define TEST_STREAM_SOURCE_H_

Thanks,

Arthur

Link to comment
Share on other sites

  • 0
On 7/8/2023 at 2:08 AM, artvvb said:

Hi @timmy,

There's a bug in the DMA implementation in Vivado. The "Width of Buffer Length Register" parameter in the DMA configuration should be increased to 16 bits from 14 bits, to increase the amount of data that a single DMA transfer is capable of sending to the circle buffers - this value reflects a maximum number of bytes that can be transferred. Currently, when the length of the transfer is written to the DMA, the top two bits are masked off, and only a quarter of the maximum amount of data can be sent.

Once the hardware is regenerated and the new HDF file has been used to update the hardware platform, no software changes are required to get it working.

Updated sources should be available on Github soon, at least for the baremetal projects.

Thanks,

Arthur

image.png

Where can I find the vivado project of the DAC1411_Demo to change the DMA configuration? I'm having the same issue when trying to generate signal with more than 4096 samples by following this tutorial. I've tried to recreate the vivado project of this repo, but in the design file, there's only ZYNQ 7 Processing System IP.

Link to comment
Share on other sites

  • 0
On 3/21/2024 at 11:26 PM, artvvb said:

Recreating the Vivado project for this demo requires Vivado 2019.1 and the process is documented here: https://digilent.com/reference/programmable-logic/eclypse-z7/git. What version are you using?

Thank you, it's already worked now on baremetal. I think I have some mistakes when checkouting to the correct branch. But, is there a way to import the hardware change so that it can be used on linux project? 

I try to run my linux project, but it's still capped at 4096 samples

Edited by Zufaruu
Link to comment
Share on other sites

  • 0
On 3/25/2024 at 5:22 AM, Zufaruu said:

Thank you, it's already worked now on baremetal. I think I have some mistakes when checkouting to the correct branch. But, is there a way to import the hardware change so that it can be used on linux project? 

I try to run my linux project, but it's still capped at 4096 samples

The fact the the project runs in Baremetal is great. It means that you have the proper hardware platform on one hand, and the proper Zmodlib code (which is identical on baremetal and platform) on another hand. So focus on providing the same hardware platform, build the project for linux (be sure you are defining LINUX_APP in your project) and it should work.

Good luck.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...