Jump to content

artvvb

Technical Forum Moderator
  • Posts

    1,063
  • Joined

  • Last visited

Posts posted by artvvb

  1. Hi @Sergio Lopez

    8 hours ago, Sergio Lopez said:

    In the last topic i had a problem while reading the audio data from the memory which i have solved using pointers with the correct memory direction and the byte lenght of each data.

    How are you allocating buffers? If using something like malloc, you can increase the amount of memory available to the stack and heap in the linker script (lscript.ld). If you're using the predefined memory base address the demo uses, could you describe the errors you're running into?

    Thanks,

    Arthur

  2. Hi @Eran Zeavi

    Do other demo projects run successfully on your board? I would also confirm that the programming mode select jumper is set to JTAG and power cycling, as it could be related to a project actively running on the board while attempting to program it. Others have reported similar errors with other Zynq boards, and other threads may have useful troubleshooting tips, like here: 

    Thanks,

    Arthur

     

  3. There are various potential things to troubleshoot for this:

    1. Does the power good indicator LED come on when it is powered up?
    2. Please try another USB cable in case your cable is not capable of transferring data.
    3. Please confirm whether USB drivers are installed on your system - there is a checkbox in the Vivado installer that can easily be missed. If you are using a Windows system, in the Device Manager, your board should show up as several USB serial converters and a COM port (see here: https://forum.digilent.com/topic/21713-brand-new-basys-3-user-cant-get-vivado-to-see-it/#comment-62685). You could also install Adept Runtime to quickly reinstall the drivers: https://digilent.com/reference/software/adept/start.

    Thanks,

    Arthur

  4. For some additional reading, UG480 (the XADC user guide) talks about the dedicated interface between PS and XADC: https://docs.amd.com/r/en-US/ug480_7Series_XADC/Zynq-7000-SoC-Processing-System-PS-to-XADC-Dedicated-Interface. As does the Zynq technical reference manual: https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/Control-Interfaces.

    The two control interfaces described here are the two pieces of hardware underlying the two drivers. XSysMon is used to control XADC when XADC is instantiated in PL. XAdcPs must be used when an XADC isn't instantiated and has a slightly different hardware interface, reflected by the difference in drivers. There are likely various tradeoffs for which interface to use - choosing whether to "waste" FPGA resources or to disallow hardware in PL from using alarm signals comes to mind - but they're likely all pretty irrelevant for just getting the thing working. This is all to say, if you have an XADC instantiated in the design, you should be able to run the code I posted previously as-is.

  5. In case I haven't mentioned, I'm working in Vitis 2023.1.

    3 hours ago, engrpetero said:

    Where are XSysMon_GetStatus() (or XAdcPs_GetStatus()) and XSM_SR_EOS_MASK (or XADCPS_SR_EOS_MASK) defined, please?

    XAdcPs_GetStatus does not exist in that API.

    XSysMon_GetStatus is defined in xsysmon.h and the mask macros are defined in xsysmon_hw.h. In general, if you have the code loaded into the IDE and the macro or function exists in scope, you can control-click on it to find declaration locations.

    3 hours ago, engrpetero said:

    It also *seems* since the last in the setup function calls was to setup up for continuous sequencer cycling that there is no need to clear the status and then 'wait' for the status mask to be set (though I'll certainly do that if that's what it takes. :-)).

    I think this just prevents reading the same sample twice if the software is moving fast. Removing it works fine for me.

  6. I'll need to check out the XAdcPs API. If you have an XADC instantiated in your block design, you ought to be able to use the XSysMon drivers by directly copying over the posted code.

    Guessing, but I think that XAdcPs represents direct PS access to the XADC core, while XSysMon is only pulled in when an XADC is included in block design. I'm not sure what the differences between the APIs are, or if the PS gets a different level of access if the XADC isn't hung off of the AXI bus. Given the existence of the XAdcPs drivers, it seems that it should be possible to use XADC without instantiating the IP - which might make XSysMon completely redundant for Zynq parts - but I'll need to try it out.

  7. I suspect that the transfer function defined by XSysMon_RawToVoltage is not accurate for differential aux channels. The following comes from UG480 (https://docs.amd.com/r/en-US/ug480_7Series_XADC/ADC-Transfer-Functions), when it describes the bipolar mode transfer function.

    Quote

     The LSB size in volts is equal to 1V/2^12 or 1V/4096 = 244 µV.

    Whereas the power supply transfer function is "ADC Code / 4096 * 3V".

    I think this means that the XSysMon_RawToVoltage macro ("((((float)(AdcData))* (3.0f))/65536.0f)") lines up with the supply conversion, not the aux input conversion, which doesn't seem to be defined in the drivers.
    The following is working cleanly for me:

    #include "xsysmon.h"
    #include "xparameters.h"
    #include "sleep.h"
    #include "stdio.h"
    #include "xil_types.h"
    
    #define XADC_DEVICE_ID XPAR_XADC_WIZ_0_DEVICE_ID
    
    typedef struct ChannelInfo {
    	u8 Channel;
    	u32 Mask;
    	char *Name;
    	u8 IsDiff; // 0 or 1
    } ChannelInfo;
    
    #define NUMBER_OF_CHANNELS 4
    ChannelInfo Channels[NUMBER_OF_CHANNELS] = {
    		{XSM_SEQ_CH_AUX_SHIFT + 14, XSM_SEQ_CH_AUX14, "AUX14", 1},
    		{XSM_SEQ_CH_AUX_SHIFT + 7,  XSM_SEQ_CH_AUX07, "AUX07", 1},
    		{XSM_SEQ_CH_AUX_SHIFT + 15, XSM_SEQ_CH_AUX15, "AUX15", 1},
    		{XSM_SEQ_CH_AUX_SHIFT + 6,  XSM_SEQ_CH_AUX06, "AUX06", 1}
    };
    
    void Xadc_Init(XSysMon *InstancePtr, u32 DeviceId) {
    	XSysMon_Config *ConfigPtr;
    	u32 DiffChannels, EnabledChannels;
    	u8 Index;
    
    	ConfigPtr = XSysMon_LookupConfig(DeviceId);
    	XSysMon_CfgInitialize(InstancePtr, ConfigPtr, ConfigPtr->BaseAddress);
    
    	DiffChannels = 0;
    	EnabledChannels = 0;
    	for (Index = 0; Index < NUMBER_OF_CHANNELS; Index++) {
    		EnabledChannels |= Channels[Index].Mask;
    		if (Channels[Index].IsDiff) {
    			DiffChannels |= Channels[Index].Mask;
    		}
    	}
    
    	// Disable the Channel Sequencer before configuring the Sequence registers.
    	XSysMon_SetSequencerMode(InstancePtr, XSM_SEQ_MODE_SAFE);
    	// Disable all alarms
    	XSysMon_SetAlarmEnables(InstancePtr, 0x0);
    	// Set averaging for all channels to 16 samples
    	XSysMon_SetAvg(InstancePtr, XSM_AVG_16_SAMPLES);
    	// Set differential input mode for appropriate channels
    	XSysMon_SetSeqInputMode(InstancePtr, DiffChannels);
    	// Set 6ADCCLK acquisition time in all channels
    	XSysMon_SetSeqAcqTime(InstancePtr, EnabledChannels);
    	// Disable averaging in all channels
    	XSysMon_SetSeqAvgEnables(InstancePtr, EnabledChannels);
    	// Enable all channels
    	XSysMon_SetSeqChEnables(InstancePtr, EnabledChannels);
    	// Set the ADCCLK frequency equal to 1/32 of System clock
    	XSysMon_SetAdcClkDivisor(InstancePtr, 32);
    	// Enable Calibration
    	XSysMon_SetCalibEnables(InstancePtr, XSM_CFR1_CAL_PS_GAIN_OFFSET_MASK | XSM_CFR1_CAL_ADC_GAIN_OFFSET_MASK);
    	// Enable the Channel Sequencer in continuous sequencer cycling mode
    	XSysMon_SetSequencerMode(InstancePtr, XSM_SEQ_MODE_CONTINPASS);
    }
    
    void Xadc_ReadData (XSysMon *InstancePtr)
    {
    	u8 Index;
    	s16 RawData;
    	float VoltageData;
    
    	printf("Waiting for EOS...\r\n");
    
    	// Clear the Status
    	XSysMon_GetStatus(InstancePtr);
    	// Wait until the End of Sequence occurs
    	while ((XSysMon_GetStatus(InstancePtr) & XSM_SR_EOS_MASK) != XSM_SR_EOS_MASK);
    
    	printf("Capturing XADC Data...\r\n");
    
    	for (Index = 0; Index < NUMBER_OF_CHANNELS; Index++) {
    		RawData = XSysMon_GetAdcData(InstancePtr, Channels[Index].Channel);
    		VoltageData = ((float)(RawData) * (1.0f) / 65536.0f);
    		printf("Capturing Data for Channel %s: ", Channels[Index].Name);
    		printf("%04hx = ", RawData);
    		printf("%.3fV\r\n", VoltageData);
    	}
    }
    
    int main () {
    	XSysMon Xadc;
    
    	Xadc_Init(&Xadc, XADC_DEVICE_ID);
    	printf("Zybo Z7 XADC Initialized!\r\n");
    
    	while(1) {
    		Xadc_ReadData(&Xadc);
    		sleep(1);
    	}
    }

    Results, with VAUX14P at 25 mV, VAUX14N at 100 mV, and the rest grounded:

    image.png

  8. Some progress, I can see changing values printed when running the attached code (a heavily modified version of the Cora XADC source), but am still figuring out how to interpret raw data readings and what the register configuration settings applied in the init function might need to be.

    (Edited to remove code after posting a followup)

  9. Hi @AaronNowack

    Apologies for the delay. We reached out to the engineer who designed the front-end circuitry on both Zmods about your question. Their response is below:

    Quote

    The Zmod Scope (formerly Zmod ADC) does not have a proper filter with a standard approximation like Bessel, Butterworth, etc. Here filtering simply means a natural BW limit of around FS/2 that serves as anti aliasing filter. The main purpose of the amplifier and filter front end is to adapt the input signal ranges to the ADC full scale input voltage.

    The Zmod Digitizer has a proper RLC filter designed for a linear phase Bessel approximation and 75MHz bandwidth. The main idea behind this filter was to keep the group delay as flat as possible for high frequency sampling. However, the real filter response depends on board parasitics and on RLC tolerances. Also, the other analog components might distort the ideal delay response to some extent, but we expect no large delay peaks around the corner frequency as it happens for example with Chebyshev approximations.

    Hope this helps,

    Arthur

  10. Hi DGISTKSJ,

    No, the MIG cannot be used to interface with DDR on the Eclypse, as the DDR is connected to the Zynq PS. However, you ought to be able to access DDR memory through the Zynq PS's AXI slave ports, which can be enabled in the PS configuration, as below. It isn't trivial to implement a custom full AXI master interface to control these ports, so we would normally recommend using IP like Xilinx's AXI DMA.

    Thanks,

    Arthur

    image.png

  11. On 4/2/2024 at 10:40 AM, Oscar O. said:

    Have you ever simulated the Zynq server project? Not sure if there is something that would mimic an ethernet connection to the Z7's FPGA that could send data to it and receive it from the board??? Is there something like that around? I am a firm believer of simulating the design before going to the actual hardware.

    I have not. There are some AMD resources on simulating the Zynq PS, but I'm not sure if they cover external HW like Ethernet or if they're primarily for simulating software in conjunction with FPGA gateware.

    On 4/2/2024 at 11:21 AM, Oscar O. said:

    I downloaded the Audio zip files and followed the instructions for importing the project... however I got the error below. Mind you I am using Vivado 2023.1. Could that be the problem....I cant install every version of Vivado as I had a hard time getting 2023.1 installed due to space issues

    I'm sure "It works on my machine" isn't the most helpful, but I was able to download the 2022.1 Vitis archive for the Zybo Z7-20 variant of the DMA Audio demo, open it in 2023.1, and run it in hardware. Which download did you use?

  12. What raw data value does 0.790 V correspond to? If it's all zeros or some other notable bit pattern then something isn't being initialized.

    It's been quite a while since I worked on the Cora demo and I don't recall if the XADC device actually needs to be initialized in software, but that demo does it here: https://github.com/Digilent/Cora-Z7-SW/blob/d35d836848fed00dec917ff0784f6232862220f5/src/Cora-Z7-10-XADC_SW/src/main.c#L58. It also uses an "xsysmon" driver instead of xadcps, which might be a renamed version of the same drivers... Building out a project for Zybo to try it out.

  13. Hey CEEJ38,

    This sounds like an electrical concern. The Zedboard's Pmod ports use 3.3V logic and the bank voltage cannot be changed (section 2.9.2 of the user guide covers it in brief, and DS187 covers it in extreme detail). You might look into using a level shifter circuit.

    Thanks,

    Arthur

  14. Another potential way to fix the issues would be to make sure that your source code uses the same instance of the XScuGic handler as the zmodlib sources. In zmodlib, this is declared in zmodlib/Zmod/zmod.cpp and is externed into other files where it's relevant. Options are to either modify the zmodlib sources so you can pass in a handler to an instance that you declare in code outside of zmodlib, or use the API defined in intc.h when setting up handlers for the ethernet and timer sources. I'm not sure of the details of either option.

    @Xband I realized you weren't necessarily just asking about the base addresses. Register offsets that specify where a particular register is located relative to a base address are commonly defined in both peripheral drivers and in IP documentation. The section of the AXI DMA user guide I linked in the previous comment is an example of the latter. As an example of where you might find register offsets in drivers, xaxidma_hw.h (found in BSP sources or by clicking through various other AXI DMA driver files) includes them for the DMA core. That receive status register offset is defined by the two following lines:

    #define XAXIDMA_RX_OFFSET	0x00000030 /**< RX channel registers base
    					     * offset */
    #define XAXIDMA_SR_OFFSET	 0x00000004   /**< Status */

     

  15. Regarding the approach of commenting out the interrupt functionality, as an experiment, I cloned a fresh instance of the Zmod Scope baremetal demo (here: https://digilent.com/reference/programmable-logic/eclypse-z7/demos/zmod-scope), and ran it in 2019.1 with and without the contents of the interrupt initialization functions. It worked fine with the interrupt functions, but when the sources were commented out, there was no response. Debugging the demo, it seems that the DMA API doesn't expose the polled version of the fnIsDMATransferComplete function, and the system stalls while waiting for data to be transferred from PL.

    To fix this, I added the second line below to zmodlib/Zmod/dma.h:

    uint8_t fnIsDMATransferComplete(uintptr_t addr);
    uint8_t fnIsDMATransferCompletePoll(uintptr_t addr);

    Modified the following line in zmodlib/ZmodADC1410/zmodadc1410.cpp's ZMODADC1410::acquirePolling function:

        // Wait for DMA to Complete transfer
        while(!isDMATransferCompletePoll()) {}

    And added the following function to zmodlib/Zmod/zmod.cpp and the corresponding header:

    /**
     * Check if the DMA transfer previously started has completed.
     *
     * @return true if the DMA transfer completed, false if it is still running
     */
    bool ZMOD::isDMATransferCompletePoll() {
    	return fnIsDMATransferCompletePoll(dmaAddr);
    }

    The zmodlib/Zmod/zmod.h header:

    	bool isDMATransferComplete();
    	bool isDMATransferCompletePoll();

    I also needed to adjust the fnIsDMATransferCompletePoll function in zmodlib/Zmod/baremetal/dma.c as follows, since the status register for PL->PS transfer is at address 0x34 instead of 4 (https://docs.amd.com/r/en-US/pg021_axi_dma/S2MM_DMASR-S2MM-DMA-Status-Register-Offset-34h):

    uint8_t fnIsDMATransferCompletePoll(uintptr_t addr) {
    	DMAEnv *dmaEnv = (DMAEnv *)addr;
    	if (!dmaEnv)
    		return 0;
    	uint32_t offset = (dmaEnv->direction == DMA_DIRECTION_RX) ? 0x34 : 0x04;
    	uint8_t val = readDMAReg(dmaEnv->base_addr, offset);
    	return (val & 2);
    }

     

  16. Mamatchai, I'll need a bit of time to reproduce and double-check whether there are other important interrupts.

    4 hours ago, Xband said:

    Are these addresses constant for the Eclypse Z7 platform or do you need to look at this file each time when wanting to get data?

    I was wondering how these came about, does building an application in Vitis automatically assign the values or properly route existing hardware values?

    or other magic?

    Addresses for PL IP are different per project, they're assigned in the address editor in Vivado. You can either let Vivado automatically assign them (the default behavior) or manually set them. Either way, the address map is exported with the XSA file after generating a bitstream, along with various additional information about the hardware design (this is also how IP configuration information makes its way into the files used by *_LookupConfig functions). Including the xparameters file in your code and using the macros it defines is recommended in case the peripheral addresses are changed in Vivado.

    image.png

  17. 2 hours ago, Oscar O. said:

    One issue I keep thinking of is the fact that we have packets that are about 1400 bytes big coming in every 300 hz or so on a serial interface then we have to take them and send it out on the ethernet port. Same going the other say.

    I haven't benchmarked the TCP echo server example, but this sounds plausible to implement. Packets for the echo server unmodified might be 1 byte, or however large the software creating the packets makes them (a serial terminal you're typing into seems like it would likely send one byte at a time), but the raw ethernet packets max out only a little smaller than 1500 bytes. This blog post also extends the echo server example to send more than a byte at a time, using a python script on the PC side.

    2 hours ago, Oscar O. said:

    What I need to do is grab the packet of data from the ethernet connection and send it to the PL so I can serially send it out. Going the other way, receive the serial data in the PL and send it to the host computer via the ethernet interface.

    Once data is received in the PS & DDR, you could use AXI DMA or a similar mechanism to move it to PL. Note that AXI DMA is an IP that is added to a block design, and not the hard DMAs built into the Zynq PS (which I believe are much less performant, could be wrong). There are various demo projects around, you could check out the Zybo's DMA Audio demo, which uses DMA to move audio data between DDR (where PS can access it) and an I2S interface. I've also written about DMA a fair amount on the forum, this thread being one example:

    There was another user building a similar system in this thread:

     

  18. Yep, good catch. It's four differential inputs.

    From the feature list in the Zybo Z7 reference manual:

    image.png

    From the Zybo Z7 XADC Demo description:

    image.png

    Note that the channel names in the table above correspond to the actual XADC channel numbers you should be using in the XADC settings. Channels 6, 7, 14, and 15 correspond to the Zybo's Pmod inputs. This configuration should also be seen in the sequencer settings for the Zybo XADC demo.

    The Zybo schematics (screenshot from page 11) also show that the analog input circuitry is the same as the Cora's differential analog inputs:

    image.png 

    The Cora manual's description of diff. inputs: image.png

     

×
×
  • Create New...