Jump to content

artvvb

Technical Forum Moderator
  • Posts

    1,041
  • Joined

  • Last visited

Everything posted by artvvb

  1. 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. Thanks, Arthur
  2. 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
  3. 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: 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. In Vivado, open the Tools -> Custom Commands -> Customize Commands dialog. Click the plus button at the top of the list field to create a new command. 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. 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. After: GPIOs have been created for each of these ports. They can be connected to the PS as normal via connection automation. 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
  4. Hi Martin, 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
  5. 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. 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. \ 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
  6. Hi Scary66, welcome to the forums. Unfortunately, Digilent doesn't provide a Petalinux example or other embedded Linux designs for the Genesys 2. Thanks, Arthur
  7. Hi @Sergio Lopez, I2S data is signed, twos complement. I suspect that when the signal is ~0, it's toggling back and forth between numbers slightly above (~0x0000) and below zero (~0xFFFF), resulting in the wild swings you're seeing. This might also be obscuring the peak you're trying to detect - especially if the peak is a peak in signal amplitude with zero offset, which would still be switching back and forth between positive and negative. Thanks, Arthur
  8. Hi Davide, To confirm whether it's an issue with the board or physical ethernet setup, does running the LwIP Echo Server example suggested by the guide work for you? I don't have much experience with the freertos OS and haven't tested that particular example as of yet. Thanks, Arthur
  9. To be clear, yes, this concept is sound. I'm only concerned about doing it for both channels simultaneously and passing data up to software through a single DMA controller. Simulation for this kind of project would be best served by pulling apart the different pieces. Keeping it likely way too vague, you might write a wrapper and a testbench for everything in the stream between the ZmodScopeController and DMA, and verify that it responds to control signals correctly - for example, you'd set an "enable" bit in a testbench that simulates the pipeline instead of trying to include the software and PS in simulation through cosimulation. Doing simulations of small components regularly and on a small scale before integrating them together would be helpful to verify that assumptions we're making are correct. It's at a really low level compared to the entirety of the project, but this guide might help for starting to poke around the simulator UI, in case you haven't touched it yet: https://digilent.com/reference/programmable-logic/guides/simulation.
  10. Reading a captured stream as 64-bit pieces of data is relatively straightforward. The data would be interleaved - every other word is a raw sample and the rest are accumulated samples. I haven't tested this code, and it would depend on whether your real samples and accumulated samples are in the high or low word of the 64-bit piece, but it would look somewhat like the following: // start at line 562 of https://github.com/Digilent/Eclypse-Z7-SW/blob/b42fb15a8ab4c52a38db2c15918cd7263e84f65e/src/s2mm_cyclic_transfer_test/src/main.c for (u32 i = 0; i < BufferLength; i++) { u32 index = (i + BufferHeadIndex) % BufferLength; if (index % 2 == 0) { // then it's probably raw samples float ch1_mV = 1000.0f * RawDataToVolts(RxBuffer[index], 0, ZMOD_SCOPE_RESOLUTION, Relays.Ch1Gain); float ch2_mV = 1000.0f * RawDataToVolts(RxBuffer[index], 1, ZMOD_SCOPE_RESOLUTION, Relays.Ch2Gain); const u16 ch1_raw = ChannelData(0, RxBuffer[index], ZMOD_SCOPE_RESOLUTION); const u16 ch2_raw = ChannelData(1, RxBuffer[index], ZMOD_SCOPE_RESOLUTION); } else { // it's accumulated samples // do stuff with the samples } // ... } That said, I'm not certain how the logic that finds the start of the buffer would handle it, and an off-by-one error could crop up. There's a note in the S2mmFindStartOfBuffer function to this effect: https://github.com/Digilent/Eclypse-Z7-SW/blob/b42fb15a8ab4c52a38db2c15918cd7263e84f65e/src/s2mm_cyclic_transfer_test/src/s2mm_transfer.c#L238. Edit: Note that the DMA is currently transferring 64-bit chunks of data (in the demo project, it's sending two 32-bit samples at once), it's put sequentially into memory, and it's up to the software how to interpret this memory on the software side - it would also be possible to cast the buffer to a pointer of a 64-bit struct type, like the following, and iterate over it using that (though there's additional complexity from the "start of the buffer" potentially showing up anywhere in the memory region allocated for the it). The same possibilities of off-by-one, which word is the "top" of the 64-bit piece of data, and S2mmFindStartOfBuffer maybe needing changes show up here too. typedef struct { u16 acc_data_0; u16 acc_data_1; u16 raw_data_0; u16 raw_data_1; } rawAndAcc_Data; rawAndAcc_Data *buffer = (rawAndAcc_Data*)RxBuffer; // looping not shown here due to the aforementioned complexity around where the start of the buffer is located xil_printf("%04x", buffer[0].acc_data_0); The concern here was motivated by the potential loss of samples. The DMA master interface that connects to one of the PS HP ports is in fact 64 bits wide. In other demo projects, this was only 32 bits wide. The DDR demo increased the DMA master width of to 64 bits it to improve throughput - if the DMA is clocked at the same rate as incoming data (100 MHz for 100 MS/s or something) and the input interface to the DMA (AXI stream) and output interface are the same width, then protocol overhead needed for the AXI master interface makes it so that there will always be some clock cycles where data can't be pushed into the DMA. By protocol overhead, I mean that the DMA needs to take time to do things like specify the address it wants to write to. The way that this issue shows up is that if the DMA master interface is busy, its internal FIFOs are filling up - when they fill entirely, the ready signal on the DMA's AXI stream interface drops, and the rest of the input pipeline backs up. When the DMA becomes ready again, the stream starts up again, but there will have been samples that were lost during the stall. It may be possible to increase the clock frequency fed to the DMA sufficiently to cover the extra cycles needed for the protocol overhead, but that also makes it harder to meet timing. "Upconverting" from 32 to 64 bits inside of the DMA made this much easier to do, since it doubled the potential throughput at the output, giving plenty of margin to account for overhead. This is why I suggested limiting yourself to one channel of input, so that you could use 16 bit raw samples and 16 bit accumulated data from the same channel, staying within the original 32-bit width. Alternatively, it might be possible to copy the DMA hierarchy (effectively making a second instance of S2mmDmaTransfer_0) to handle a second 32-bit stream, but I would need to set up a project to see if/how it would work. It would also require software changes in main to manage a second DMA controller.
  11. artvvb

    XADC configuration

    No, the XADC primitive needs to be included in the project somehow for it to be connected in the bitstream, whether it's included through the IP or a direct primitive instantiation.
  12. Hi Davide, We don't have much experience with 2023.2 yet and there are significant changes between it and previous versions. It's possible that there's a new bug. I'll see if we can test a boot.bin file generated in 2023.2, but I would also recommend that you install another version to work with, I've personally found 2023.1 to be reasonably stable, but it will also depend on what support materials you want to be able to use - while it's possible to use material created for an older version of the tools, there could always be differences that break things. For 2023.2 specifically, these guides may be helpful, as the Cora and Arty Z7 are fairly similar: Vivado - https://www.hackster.io/whitney-knitter/getting-started-with-the-arty-z7-in-vivado-2023-2-26051a Vitis - https://www.hackster.io/whitney-knitter/getting-started-with-the-arty-z7-in-vitis-unified-ide-2023-2-1a8ee5 Thanks, Arthur
  13. artvvb

    XADC configuration

    Please refer to the demo linked in my previous comment for an example project that uses the XADC.
  14. Hey @salamus On further review, Viktor is correct, an intermediate state that lets the state machine wait until the uart transmitter has acknowledged receipt of the byte (maybe by just waiting a cycle, since busy being low means you know it's ready to accept a byte) would help. The issue is likely that the state machine sees busy as being low, so asserts ready_2, and moves to the next state - this is all good, except that on the next clock cycle when it checks busy again, assuming busy is registered inside the uart transmitter, that busy signal hasn't had a chance to update yet and the state machine thinks it's okay to send another byte. There's a comparable issue that requires that skid buffers be used in modules implementing AXI stream interfaces to be fully protocol compliant, since both sides of the handshake must be registered. There are some good articles around the web on this. This is an example: http://fpgacpu.ca/fpga/Pipeline_Skid_Buffer.html. It's not completely 1-to-1 with your issue, since there's a line in the AXI stream spec that states "a transmitter [your state machine] is not permitted to wait until TREADY [not busy] is asserted before asserting TVALID [ready_2]" (page 18, section 2.2: https://developer.arm.com/documentation/ihi0051/latest/), but is still a very similar registered handshake. Edit: Richm is also correct, as a FIFO correctly implementing a handshake protocol would also take care of the issue. A skid buffer is just a very small FIFO. Further edited: A third solution would be to eliminate the handshake entirely by holding ready continuously high as long as you aren't in reset and rewriting the state machine to either 1. select the byte to send combinationally depending on the state it's in or 2. set the data_store register to whatever byte you want to send in the next state (as in 8'b00110101 in idle, 8'b10101010 in byte1, etc). Thanks, Arthur
  15. See attached, built using 2023.1. Another colleague, @JColvin confirmed that it works on his hardware. When booted, it should toggle one of the RGB LEDs once per second. cora_sd_boot_image.zip vitis_export_archive.ide.zip cora_sd.xpr.zip
  16. Hey Davide, Sorry for the delay. One of my colleagues, @JRys, potentially reproduced the issue and has been doing some investigating. He found that when using an SD card originally used with a Raspberry Pi, a small additional boot partition was left on the card, making it so that an equivalent Zynq board wouldn't boot - it was trying to boot from the incompatible boot partition instead of the expected one where the boot image from Vitis was loaded. Could something like this be the case with your setup? Thanks, Arthur
  17. Hi @mvernengo Apologies for the delay. The Zedboard ships with an SD card with the out-of-box image included, and also potentially an image in flash - we're currently investigating the flash side. There is an "Out-of-box demo" ZIP file including out-of-box source files and an image for the Zedboard on its resource center: https://digilent.com/reference/programmable-logic/zedboard/start. Note that this image is quite old, and was created using Xilinx XPS 14.1 and SDK 14.1, according to the included readme, and as such, may be quite difficult to rebuild from scratch. Recreating an SD card for boot from the included prebuilt files looks to be relatively straightforward, and is documented in the readme. As an aside, in my experience, ChatGPT results for this kind of technical topic, especially when related to specific products, tend to either be highly unreliable or not specific enough to be helpful, at least for new users. In this particular case, the output isn't the worst. SD card boot is also an option, and you should make sure to set the programming mode select jumpers to the appropriate position for the intended boot source. AMD/Xilinx's Vivado or Vitis (previously SDK) tools would typically be used to handle flashing an image. SD card prep, given the boot image, can be performed using the normal stuff intended for formatting drives and moving files around. Thanks, Arthur
  18. Hi @fluxinduction I'm not aware of any testing of the Kuiper Linux platform that Digilent has done, so we will not be able to provide much support on this topic. You may need to reach out to ADI for support. Thanks, Arthur
  19. Hi @Arpita, We've received several questions about this functionality recently and are investigating. Please expect a response in this thread when we find a solution: Thanks, Arthur
  20. Hi ManiS, I apologize for the delay. We're still investigating this topic. Please expect a response in this thread when we find a solution: Thanks, Arthur
  21. Hi @sayantanb93 I apologize for the delay. We have received several questions related to this topic recently and are investigating. Please expect a response in this thread when we find a solution: Thanks, Arthur
  22. artvvb

    Basys 3 broken?

    Hi @css Could you provide some photos of your board while the 01n issue is happening? If it's damaged, the described behavior sounds odd. I'd expect that the seven-segment display would show the same constant value on one or more of the four digits, with the others being all off or all on, due to common anode signals remaining constant. If it's different on each digit, that means that the anode signals are changing. It would also be helpful to know if you've programmed your board's flash memory, since an out-of-box image similar to the GPIO demo comes preinstalled and boots from flash when the board is powered on. What position do you have the programming mode select jumper set to? Thanks, Arthur
  23. I'd expect restarting the IP packager fresh to create a new instance of the IP, adding in the files you pulled from the original instance, would work, even if it would be a hassle. There's some more discussion of this issue here: https://support.xilinx.com/s/question/0D52E00006miunQSAQ/ip-packager-not-updating-ports-from-vhdl-code?language=en_US. Thanks, Arthur
  24. Hi @salamus Could you share port, signal, and parameter declarations in addition to the state machine process? The data_store signal resetting to a one-bit value has some cause for concern, not necessarily for it being the cause of problems, but more in case there are other more relevant width mismatches - like if state is only one bit wide the state machine would presumably toggle back and forth between idle and byte1, depending on what the actual values of the state parameters are. Also, if you haven't, simulate your design. Thanks, Arthur
  25. artvvb

    XADC configuration

    Yes, you should technically be able to use XADC without any IP in a project. While the Cmod A7 15T demo (https://digilent.com/reference/programmable-logic/cmod-a7/demos/xadc) instantiates an XADC IP, the primitive that this IP wraps can be directly instantiated in your design. See the screenshot of the language templates built into Vivado, below. Note that primitives like this are not necessarily easy to configure and still require the appropriate review of corresponding datasheets. Thanks, Arthur
×
×
  • Create New...