Jump to content

artvvb

Technical Forum Moderator
  • Posts

    1,063
  • Joined

  • Last visited

Posts posted by artvvb

  1. Hey @CEEJ38

    Apologies for the delay. There are various ways forward depending on the architecture you're going for and the systems/subsystems you want to learn about - if you want to do something only in Vivado with Verilog, that's possible. If you want to use software with the existing peripherals or custom peripherals, either is possible.

    The block design as presented ought to work - the Zynq PS runs software that controls both peripherals and would repeatedly poll the Pmod controller and update the PWM controller in a loop. The main thing to pay attention to would be translating from the PmodAD1's ADC codes to PWM duty cycles - the software would likely do some extra math to scale or offset these values however you want.

    If you want to learn to design your own peripheral, you would be looking into how to design an AXI peripheral (or other form of PS-PL communication). Funcdamentally, the goal would be to expose the pulseLength value to software. You could potentially do something like convert the pulseLength value into an input to your main_file module, instantiate the main_file module in your block design, and connect the pulseLength input to something controlled by software. As an easy first step, you could control the new pulseLength input with an AXI GPIO. I recently wrote about some related info on using AXI GPIOs for this kind of purpose here: 

     

    On 3/4/2024 at 5:17 PM, CEEJ38 said:

    Is the answer converting the C code to Verilog and running the code in Vivado instead of Vitis? Apologies if the question is basic. I am a student studying independently and could use the help. Thanks   

    Third option, you could implement everything in the programmable logic (FPGA fabric). I wouldn't recommend using the PmodAD1 IP core for this, as you would then need to write a custom AXI4-lite master (probably overly complex and a large topic), however, you could pull the SPI controller out of it (https://github.com/Digilent/vivado-library/blob/master/ip/Pmods/PmodAD1_v1_0/src/ad1_spi.v) and put together a relatively simple FPGA-only design in Vivado. You'd be designing a bridge component that can pull data out of the AD1 controller whenever it's ready and send it to a custom PWM component.

    Thanks,

    Arthur

  2. Simulating your code has a much faster turnaround time when tweaking IP settings and checking results than repeatedly building bitstreams and programming them into the FPGA. As previously mentioned, please check the radix you're using while viewing your data. Your results look like you're using signed magnitude instead of signed decimal.

  3. Hi @Mamatchai

    Edit: There's no specific zmodlib API function for reading back the trigger value after it's written, you'd need to store data in the application calling setTrigger or one of the acquire functions. The rest of this comment is about how to work around this.

    So these tips are mainly for baremetal. Linux user space virtual addresses probably complicate things, and could require modifications to zmodlib sources. A screenshot showing each is attached.

    You can view values stored in memory-mapped registers in the debugger - though this feature has had a bug in some versions of Vitis where only the lowest byte of each word can be viewed (this can be seen in the screenshot).

    You can also use a debugger expression to determine the value of the register at a particular point in the code, by dereferencing its address. Note that the debugger may not have access to macros coming in from headers like xparameters for this, so you may need to declare the pointer in the code.

    If you're trying to modify the code to read the register value and then use it for something, you can use the above method of dereferencing a pointer that has been set to the register address.

    Hope this helps,

    Arthur

    image.png

  4. Yes, use LVCMOS33. Per the manual, https://files.digilent.com/resources/programmable-logic/zedboard/ZedBoard_HW_UG_v2_2.pdf, the PL Pmod pins are connected to bank 13, which is run at 3.3V. The master XDC sets the bank voltage for bank 13 to LVCMOS33 at the bottom of the file - https://github.com/Digilent/digilent-xdc/blob/fa60017608b914b6765c8620e85a3b97a36179bf/Zedboard-Master.xdc#L374C75-L375C75.

    image.png

    You can also see that bank 13 is powered at 3.3 V in the schematics - https://digilent.com/reference/_media/reference/programmable-logic/zedboard/zed_sch_rev_f1-public.pdf.

    image.png

    image.png

  5. Hi @CEEJ38, welcome to the forums.

    There are two versions of the Zedboard board files, one from Avnet and one from Digilent. Please make sure you are using the Digilent version as the Avnet version does not include Pmod interfaces - installation instructions can be found here: https://digilent.com/reference/programmable-logic/guides/installing-vivado-and-vitis#install_digilent_s_board_files.

    Alternatively, you can manually constrain your Pmod ports instead of relying on the board files. The "Add GPIO Peripherals to a Block Design" section of this guide discusses how to do this, in the context of some button inputs: https://digilent.com/reference/programmable-logic/guides/getting-started-with-ipi#add_gpio_peripherals_to_a_block_design. I would recommend this approach over the board files for this kind of I/O interface, as the board files and IP presets can obscure some important details of what is going on that are better to learn sooner rather than later (I/O constraints, configuring IP as necessary for the peripherals you're talking to, etc).

    Thanks,

    Arthur

  6. Hey Julii,

    Are you using Eclypse and Zmods or some other Zynq + ADC setup? The rest of my comments below assume Eclypse along with the IP cores provided for it that handle the ADC interface.

    If you're looking for the ADC configuration portion of this, the low-level low-pass filter demo might be helpful: https://digilent.com/reference/programmable-logic/eclypse-z7/demos/low-level-low-pass-filter. The ZmodScopeController IP used in the demo is specifically targetted to the Eclypse and the Zmod products that support it, but its architecture might be relevant for implementing a similar controller for another ADC and board - depending on the vendor of your parts, you may find similar controllers and examples provided by them.

    For designing the HLS module, Digilent doesn't have much if any material for it on the web. I'd recommend starting out by finding a passthrough example that you can work from and modifying it to suit your needs. This might be suitable (and the rest of UG1399 is also relevant): https://docs.xilinx.com/r/2023.1-English/ug1399-vitis-hls/AXI4-Stream-Interfaces-without-Side-Channels.

    How data is packed in the source AXI stream interface is also extremely relevant. For example, for the ZmodScopeController, the data format is defined in the IP Top Level Port Description table of the user guide on page 21 (particularly cDataAxisTdata), and in the ADC Calibration section, pages 7-9: https://github.com/Digilent/vivado-library/blob/master/ip/Zmods/ZmodScopeController/docs/ZmodScopeController.pdf.

    Thanks,

    Arthur

  7. Could you share the rgb_gen source and IP configuration settings?

    Looking at the block design, please check your reset polarity. The "locked" outputs from the clocking wizard IPs are active high - when high, they indicate that the clocks are working. It looks like rgb2dvi and your rgb_gen module are working, but the data path through dvi2rgb may not be. Both dvi2rgb and rgb2dvi have active high resets by default, which are used in your design.

    What Digilent provides to test and debug the core is described in the "Debugging" section of the dvi2rgb IP core user guide, there are some internal logic analyzers that can be optionally instantiated and used to check signals while a board is programmed, but no simulation sources are provided (though you can still create testbenches yourself, as you are doing). Based on its datasheet, rgb2dvi doesn't have similar debugging logic.

  8. @Abdullah1

    The record configuration dialog includes this note for AD2: 

    image.png

    Unfortunately, this means that this recording is likely not possible with AD2, as USB 2.0 and buffer sizes limit the throughput over USB. The approx 3 MHz maximum rate is too close to your signal frequency, and you would only get one sample per period of the 2.5 MHz signal. Unchecking the "Noise" box may also help, as indicated by the note in the dialog, but I suspect that it won't help enough.

    Newer devices like the AD3 would be capable of this measurement due to improvements in the hardware - AD3 can do 32 kS at up to 125 MS/s or record for longer at up to ~10 MS/s, as opposed to the AD2's 16 kS at up to 100 MS/s or up to ~3 MS/s recordings.

    @attila may have additional suggestions.

    Thanks,

    Arthur

  9. Hi @T106A81

    Do you need the output sine wave to be 100 MHz or just the clock input? If the former, a 100 MHz input clock will not be able to produce it. Ultimately this IP iterates across an array of predefined values and you would need to provide a clock adequately faster than the output waveform. If a 400 MHz clock is used to generate a 100 MHz sine wave (as an example, I'm not positive the core can hit that speed on your board), the "sine wave" output would still only consist of four distinct samples and still appear as a triangle wave.

    For example, in simulation, a DDS core with a 16-bit output and phase angle increment set to "1" loops after approximately 65536 one-ns clock cycles. This is the amount of time it takes a 16-bit counter with 1 added each clock cycle to roll over.

    image.png

    All this to say, to see a sine wave on the output, try to feed the core a higher clock frequency, drastically reduce your phase angle increment, or both.

    If you haven't, to select the correct configuration parameters, please review the IP datasheet (https://docs.xilinx.com/v/u/en-US/pg141-dds-compiler) and think about how the hardware it represents is architected. As a caveat, I don't have much experience with the DDS compiler.

    Thanks,

    Arthur

  10. Hi @rarow

    Using AXI GPIO to control module ports works fine, for example: https://forum.digilent.com/topic/28261-qol-script-for-vivado-block-design-and-ps-pl-communication/, https://forum.digilent.com/topic/22978-axi-dma-help-on-cora-z7-10/#comment-85544. Could you provide a screenshot of how your GPIO IPs are connected to your nets, as well as some source code that controls the GPIOs? There are some gotchas, for example, if the AXI GPIO doesn't use "All Outputs" for the appropriate channels and the tristate pins are set to input, output signals are not driven - as workarounds for this specific issue, you could either use the All Outputs setting or you could drive your module ports with the _t pin within the GPIO interface, and use SetDataDirection calls instead of DiscreteWrite (assuming you're using the xgpio driver).

    Thanks,

    Arthur

     

  11. Hi @bryan78

    Try a custom waveform. The screenshots below show the equivalent for an amplitude sweep, but the principle would be the same for frequency.

    image.png

    image.png

     

    Frequency modulation could also do it. The equivalent using amplitude modulation is below. It would be easier if you don't need to worry about a consistent frequency at each stage of the sweep, as you could use a normal signal type like a triangle wave instead of a custom one.

    image.png

    Thanks,

    Arthur

  12. If your application allows you to reduce the sample rate below 3 MHz, you could use record mode, as seen below. I was able to successfully capture 60 ms of data at 2 MHz using AD2:

    image.png

    The "base" setting in the config dialog lets you specify how long to record for.

  13. So there's a lot to it. The "UltraFast Design Methodology" document might be a decent thing to go through, as it describes Xilinx's recommended workflow: https://docs.xilinx.com/r/2023.1-English/ug949-vivado-design-methodology/Introduction. That said, the PDF version is well over 300 pages and the document assumes quite a bit of knowledge, though it does link to some summaries in the intro. UG903 also has a lot of info related to timing: https://docs.xilinx.com/r/2023.1-English/ug903-vivado-using-constraints/Introduction. A lot of what I've personally learned has come from clicking around in the tools, googling everything I see (which mostly results in finding various forum threads and answer records), and skimming any pertinent documentation I can find.

  14. Hi @Manik Dautta

    I believe you need to update WaveForms and WaveForms SDK. Installers can be found via the WaveForms resource center - http://reference.digilentinc.com/software/waveforms/waveforms-3/start. The AD3 is supported by 3.20.1 and higher (3.21.3 is most recent). We've also updated the compatibility list for SDK on the reference site and appreciate the feedback - it had been missed during the launch of the AD3.

    Thanks,

    Arthur

  15. Hi @SGdigi, welcome to the forums.

    The localhost connected in the hardware list means that the hardware server is up and running but it can't find your device.

    There are a couple of possibilities.

    1. Please try using an alternate USB cable - some charging cables are not capable of transferring data. If you are using a cable that came with the board, it should be okay.

    2. Drivers may not be installed correctly: Assuming you are using Windows - if not, please let me know what OS you are using - please use the Device Manager to check whether cable drivers are installed. You should see two USB serial converters as in this comment:

    If the device doesn't show up correctly, you should attempt to install the drivers either by installing Adept from this page - https://digilent.com/reference/software/adept/start - or by rerunning the Vivado installer from the Tools -> Add Design Tools or Devices menu option, as there's a checkbox on one of the screens that installs drivers (documented in this guide - https://digilent.com/reference/programmable-logic/guides/installing-vivado-and-vitis).

    3. If neither of the above works, the programming circuitry on your board may be damaged, in which case you may need to pursue an RMA.

    Thanks,

    Arthur

     

  16. Hi @Abdullah1

    There are several options depending on which Analog Discovery device you're using.

    Assuming AD3, you could reduce the sample rate below ~10 MHz and should be able to record all 120 frames to the screen, using "Mode: Record". You would need to specify an appropriate samples count and sample rate in the Time settings to make sure all 120 events are recorded. Assuming 2 events per millisecond, 120 events takes 60 ms, and 600 kS at 10 MS/s should cover it.

    If information about the voltage signal between events is not important, you could use repeated triggers - if you are using the 3000-series Analog Discovery Pro, device buffering would let you capture every pulse. This guide was put together recently: https://digilent.com/reference/test-and-measurement/guides/waveforms-buffers. The gear dropdown next to the "Buffer" field near the Scope's Run button lets you configure the device to acquire multiple buffers of data sequentially, from repeated triggers. That said, each buffer may need to be individually exported.

    image.png

    Thanks,

    Arthur

  17. Hi @T106A81

    I have not personally used Xilinx's DDS or FFT IPs. If you haven't reviewed their documentation, you should. pay attention to sections that talk about the formats of AXI stream interfaces in and out. FFT seems to be described in PG109, DDS in PG141. PG141's "AXI4-Stream Considerations" section (page 30) and the corresponding section of PG109 are both relevant. On an initial read of these sections, you likely need to introduce additional logic to the hardware design that can frame packets for the DMA; that can assert the TLAST signal at the appropriate time.

    For the DMA software side of things, you may find the example and common stumbling blocks that I described in this thread helpful:

    How you configured each IP is also relevant - the software described in the link above makes various assumptions about the configuration of the DMA core.

    Thanks,

    Arthur

  18. A common issue that new users tend to run into, particularly with Zynq devices, is how to control custom modules in FPGA fabric from software. There are various techniques for this, including implementing custom AXI IP, using AXI GPIO controllers (what this post relies on), or using EMIO to control your modules via common communication interfaces (GPIOs, UART, SPI, etc). The goal of this post is to present a method for implementing this kind of communication that is relatively quick to set up and use, and that fits into a “standard” block-design-based workflow.

    Custom commands in Vivado can be used to run TCL scripts via a button press or hotkey. Attached is a script that when run, will take all selected ports on IP in your block design and create an AXI GPIO for each of them. These pieces together make it so that module ports can be wired up to a processor with only a couple of clicks.

    Note: This is intended as a way of building out a project quickly and potentially makes inefficient use of FPGA resources. It also doesn’t account for clock domains. I'd be curious for any suggestions for improvements that could be made.

    Setup:

    1. Download this script:create_register_file_from_selection.tcl. As is normal with downloading arbitrary code that will be run on your system from the internet, be careful and read through it before running it.
    2. In Vivado, open the Tools -> Custom Commands -> Customize Commands dialog.
    3. Click the plus button at the top of the list field to create a new command.
    4. Pick a name, shortcut, etc. Importantly, select “Source Tcl file” and fill the path to your downloaded copy of the script into the corresponding text field.

    image.png

    The script is now installed. To run it for the first time, create a block diagram with some ports that you want to control. Select these ports by clicking on each of them. Use your hotkey or new button, found in the toolbar at the top of the screen, to run the script. You should see a new hierarchy created with several AXI GPIOs included, one connecting to each of your ports.

    Before: The start and high_count ports of a custom counter module are selected.

    image.png

    After: GPIOs have been created for each of these ports. They can be connected to the PS as normal via connection automation.

    image.png

    It should also be noted that control-Z will undo the actions performed by the entire script (as startgroup/endgroup commands are used).

    These GPIOs can then be used as normal from software, either by directly accessing their DATA registers or by using the xgpio driver. The following snippet of code could be used to toggle the start bit seen in previous screenshots.

    #include "xgpio_l.h"
    #include "xparameters.h"
    
    // ...
    
    u32 *start_reg = (u32*) (XPAR_CONTROL_0_START_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
    *start_reg = 1;
    *start_reg = 0;

    I hope this helps someone out there be a little more productive in Vivado, and as mentioned previously, am interested in feedback/suggestions.

    -Arthur

  19. Hi Martin,

    12 minutes ago, mvernengo said:

    If I connect the UART cable, a strange character is being continuously transmitted. BTW, this is probably because of how the problem started: I had programmed a PS (ARM processor) application that sent some characters with "print" command and I guess this program is called by the system instead of the SD boot.  THIS IS ALSO A FAULTY PART !!!

    Strange characters showing up in the terminal could indicate a baud rate mismatch between your terminal and the board, I'd at least try to see if they become something intelligible with 115200 or 9600 baud, possibly some others. If there's a baud rate that works, printed statements could help us figure out what's going on.

    Your JTAG boot mode behavior sounds perfectly normal. I've asked some colleagues for ideas on what could be causing the failure to boot from SD - the DONE LED not lighting up means that the bitstream is not being loaded. Since the OLED is controlled from fabric, no bitstream means that the OLED wouldn't be controllable, so there isn't necessarily damage to the physical part.

    Thanks,

    Arthur

  20. Hi @Julii

    The following describes a minimal PL -> PS transfer example. Code was tested on an Eclypse in Vivado/Vitis 2023.1. An AXI stream counter module is used to generate stimulus for the DMA's AXIS_S2MM port and Verilog source code for it is attached. It has a couple of control signals - when start is asserted, it asserts tvalid and counts whenever tready is asserted until it reaches a software-specified limit, at which point it asserts tlast, sends a final beat, and pauses until start is sent again. AXI GPIOs are used to hit the counter's control ports from software.

    image.png

    Source code:

    axis_counter.v

    The DMA was configured as follows. Scatter Gather was turned off, the width of buffer length was maximized, and the read channel was disabled. Width of buffer length is an important parameter, as it defines the maximum number of bytes that can be sent in a single transfer (2**26 in this case). I didn't touch "allow unaligned transfers" but it would be helpful if you're working with u8 arrays, as it allows the software to be more flexible in where DDR buffers are located.

    image.png\

    The Zynq PS had the HP0 port enabled so that the DMA could use it to push data to DDR.

    For software, registers are directly accessed via pointers that are pointed at the corresponding addresses, to showcase how to avoid using the xaxidma and xgpio drivers. It follows the process outlined in the Programming Sequence -> Direct Register Mode section of the DMA product guide: https://docs.xilinx.com/r/en-US/pg021_axi_dma/Direct-Register-Mode-Simple-DMA. The software sets the Runstop bit in the DMA's S2MM control register, sets the destination address and buffer length, then configures the AXI stream counter and starts it. Once the S2MM status register's Idle bit returns to "1", it invalidates the cache and verifies that data has been successfully transferred.

    main.c

    This system accounts for several potential stumbling blocks:

    1. The DMA S2MM interface's tready bit cannot be relied on to prevent data from flowing into the DMA before software initiates a transfer. It comes up as soon as the DMA comes out of reset. This means it's important to manually start upstream IP after setting up the S2MM transfer.

    2. The module upstream of the DMA must assert tlast at the right time. If tlast is not asserted before the buffer that the DMA is pointing at would overflow, the DMA will lock up and needs to be manually reset to continue being used.

    3. If the PS cache is enabled, data you're trying to write or access from software may not be the same as that seen by hardware. Manually flushing and invalidating relevant ranges of addresses ensures that the two are in sync.

    4. Lastly, pay attention to where your buffers are placed in memory. If the memory segment they're placed in is not located in DDR, the DMA may not be able to access them. If the memory segment is too small, you may see issues like stack overflows.

    Hope this helps,

    Arthur

×
×
  • Create New...