Jump to content

Mamatchai

Members
  • Posts

    6
  • Joined

  • Last visited

Posts posted by Mamatchai

  1. Hello,

    As title, I'm currently working on an AMP (Asymmetric Multiprocessing) mode project. In this project, one core (CPU0) processes the data received from ZmodADC1410 and stores it in DDR3, which is a shared resource between the two cores. The other core (CPU1) establishes a TCP connection and acts as both client and server to continuously transmit the data stored in DDR3 to the server. However, I noticed that the sampling rate of our ZmodADC1410 is 40 Mbps,so according to the calculation based on the network speed requirement, it would be 40M*28 (dual-channel) = 1120Mbps, while the fastest network speed is only 160 Mbps. In theory, this should cause either bottlenecking or packet loss, but my senior has implemented a UDP version of the project without encountering such issues. The transmission is continuous and normal. Therefore, I want to examine the internal data transmission status and observe the hardware's cache flow.I wonder if there is any tools or method that I can acheive this.

  2. On 3/30/2024 at 7:36 AM, artvvb said:

    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);
    }

     

  3. On 3/8/2024 at 7:52 AM, artvvb said:

    For interrupts, there might be a way to work around it by making sure that zmodlib and the constructors for its classes either don't reinitialize the xscugic driver, or to make sure the constructors get called before the ethernet code initializes the driver. A quick way to check it would be to comment out or remove code from the functions in Zmod/baremetal/intc.c (assuming you're using baremetal).

    XStatus fnInitInterruptController(XScuGic *psIntc)
    {
    	return XST_SUCCESS;
    }
    
    void fnEnableInterrupts(XScuGic *psIntc, const ivt_t *prgsIvt, unsigned int csIVectors)
    {
    	return;
    }

    This would prevent zmodlib from reinitializing the interrupt controller and from registering any interrupts - which also means no interrupts that zmodlib uses would work anymore and you'd have to rely on the Polling acquisition functions. I'm not 100% sure whether there are other interrupts in zmodlib that are still used when using Polling functions, but I don't think so.

    That said, either a substantial rewrite of the ethernet code (so that it uses zmodlib's intc API) or a rewrite of the zmodlib source so that it can be told to not reinitialize the interrupt controller would probably be the better long-term solution.

    Hope this helps,

    Arthur

    Hello Arthur,

    After I remove code from the functions in Zmod/baremetal/intc.c,the functionality of initializing ZmodADC has been consistently unusable.I've been trying to solve the issue of initializing the functionality of ZmodADC these past few days.This problem has been bothering me for quite some time.This is quite a strange question, I can't figure it out by myself, I feel like I still need some advice from you.Here's my main.c code.

    //--------------------------------------------------
    //          blog.csdn.net/FPGADesigner
    //          copyright by CUIT Qi Liu
    //      Zynq Lwip TCP Communication Test Program
    //--------------------------------------------------
    
    #include "timer_intr.h"
    #include "sys_intr.h"
    #include "user_tcp.h"
    #include "lwip/netif.h"
    #include "sleep.h"
    //#define TRANSFER_LEN 0xB
    
    #define TIMER_LOAD_VALUE    XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8 //0.25S
    
    static  XScuGic Intc; //GIC
    static  XScuTimer Timer;//timer
    //extern volatile unsigned tcp_client_connected;
    //extern int tcp_trans_cnt;
    void start_application(void);
    
    
    #include "./Zmod/zmod.h"
    #include "./ZmodADC1410/zmodadc1410.h"
    
    #define SEND_SIZE 1463
    
    //extern struct netif server_netif;
    static char val_formatted[15];
    #define TRANSFER_LEN 0x5B7
    // ZMOD ADC parameters
    #define ZMOD_ADC_BASE_ADDR  XPAR_AXI_ZMODADC1410_0_S00_AXI_BASEADDR
    #define DMA_ADC_BASE_ADDR  XPAR_AXI_DMA_ADC_BASEADDR
    #define IIC_BASE_ADDR  XPAR_PS7_I2C_1_BASEADDR
    #define FLASH_ADDR_ADC   0x30
    #define ZMOD_ADC_IRQ  XPAR_FABRIC_AXI_ZMODADC1410_0_LIRQOUT_INTR
    #define DMA_ADC_IRQ  XPAR_FABRIC_AXI_DMA_ADC_S2MM_INTROUT_INTR
    //static char sendBuffer_main[TCP_SEND_BUFSIZE];
    
    //--------------------------------------------------
    //                中斷與定時器初始化
    //--------------------------------------------------
    void System_Init()
    {
    	Timer_init(&Timer,TIMER_LOAD_VALUE,TIMER_DEVICE_ID);
    	Init_Intr_System(&Intc); // initial DMA interrupt system
    	Setup_Intr_Exception(&Intc);
    	Timer_Setup_Intr_System(&Intc,&Timer,TIMER_IRPT_INTR);
    	Timer_start(&Timer);
    	TcpTmrFlag = 0;
    }
    
    //--------------------------------------------------
    //                     主程序
    //--------------------------------------------------
    int main(void)
    {
    	xil_printf("Im here~~~\n");
    
    
    	uint8_t channel=0;
    	uint8_t gain=0;
    	size_t length=TRANSFER_LEN;
    
    	ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_ADC, ZMOD_ADC_IRQ, DMA_ADC_IRQ);
    
    	uint32_t *acqBuffer;
    	adcZmod.setGain(channel, gain);
    	acqBuffer = adcZmod.allocChannelsBuffer(length);
    	adcZmod.acquireImmediatePolling(acqBuffer, length);
    
    
    	static char time_formatted[15];
    	uint32_t valBuf;
    	int16_t valCh;
    	float val;
    	int coo;
    
    	xil_printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    	struct netif *netif, server_netif;   //用於lwIP網絡接口的通用數據結構
    	struct ip4_addr ipaddr, netmask, gw;  //unsigned int
    
    	//開發板的MAC地址
    	unsigned char mac_ethernet_address[] = {
    			0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
    	System_Init();
    
    	netif = &server_netif;  //0x50C004
    	xil_printf("netif = %s\tnetif = 0x%p\t&server_netif = 0x%p\n", netif, netif, &server_netif);
    	//將4byte結構的IP地址轉換爲unsigned int
    	IP4_ADDR(&ipaddr,  192, 168,   1, 10);  //IP地址(開發板)
    	IP4_ADDR(&netmask, 255, 255, 255,  0);  //網絡掩碼
    	IP4_ADDR(&gw,      192, 168,   1,  1);  //網關
    
    	lwip_init();    //初始化lwIP
    	//將網絡接口添加到netif_list中
    	if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR))
    	{
    		xil_printf("Error adding N/W interface\r\n");
    		return -1;
    	}
    	xil_printf("netif_final = %s\n", netif);  //NULL
    	netif_set_default(netif);  //設置默認網絡接口
    	netif_set_up(netif);       //啓動網絡接口
    	tcp_send_init();           //初始化TCP PCB
    
    	xil_printf("New acquisition ------------------------\r\n");
    	xil_printf("Ch1\tRaw\tTime\t\r\n");
    	//
    	while(1)
    	{
    		if(TcpTmrFlag)
    		{
    			tcp_tmr();
    			TcpTmrFlag = 0;
    		}
    		xemacif_input(netif);     //將MAC隊列中的packets傳輸到lwIP棧中
    
    		if (tcp_client_connected)
    		{  //連接成功則發送數據
    			xil_printf("TCP Connected");
    			/*
    			for (int i = 0; i < 30; i++)//
    			{
    				valBuf = acqBuffer[i];
    				valCh = adcZmod.signedChannelData(channel, valBuf);
    				val = adcZmod.getVoltFromSignedRaw(valCh, gain);
    				adcZmod.formatValue(val_formatted, 1000.0*val, "mV\r\n");
    
    				//xil_printf("%d\t%s\t\r\n",i,val_formatted);
    				strcat(sendBuffer,val_formatted);
    			}
    			*/
    
    			//send_data();
    			//xil_printf("tran_cnt:%d\r\n", tcp_trans_cnt);
    			xil_printf("Ready to send");
    			//strcpy(sendBuffer,"");
    			//adcZmod.freeChannelsBuffer(acqBuffer, length);
    		}
    		if (tcp_client_connected==-1)
    		{
    			xil_printf("errorrrrr  exit\r\n");
    			return 0;
    		}
    		//sleep(2);
    	}
    	return 0;
    }
    
    

    And if I removed the initiate part of ZmodADC 

    	uint8_t channel=0;
    	uint8_t gain=0;
    	size_t length=TRANSFER_LEN;
    
    	ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_ADC, ZMOD_ADC_IRQ, DMA_ADC_IRQ);
    
    	uint32_t *acqBuffer;
    	adcZmod.setGain(channel, gain);
    	acqBuffer = adcZmod.allocChannelsBuffer(length);
    	adcZmod.acquireImmediatePolling(acqBuffer, length);
    
    
    	static char time_formatted[15];
    	uint32_t valBuf;
    	int16_t valCh;
    	float val;
    	int coo;

    the code of can run successfully.

    In my opinion, the Eclypse Z7 may have a certain procedure to confirm the normal execution of interrupt processes. When there is any abnormality in the interrupt process, other actions will not be executed. Of course, this is my observation based on experiments, which may not be accurate.

    If you need any other information, please let me know. Thank you very much.

  4. On 3/6/2024 at 9:18 AM, artvvb said:

    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

    Hello, about the solution you provided, it raises several questions for me.
    1.Since it's the first time that I am using dereferencing, so I am not sure if I am doing it correctly. The code is all in the screenshot. The error code it gives is:
    Exception: At col 12: Cannot read symbol data. Value of register pc not available in the selected frame
    for this report issue, it prevents me from reading the data stored in the register I dereferenced. The code compiles without errors, so I suspect there might be something incorrect in my code causing this.

    image.png

    2.If my dereferencing method is correct, then I would like to inquire about the subsequent data packaging method. Our goal is to try if we can transmit the measurement signals received by our ADC through TCP. After receiving your guidance, we found that the problem indeed lies in the conflict of interrupt handlers. From : https://forum.digilent.com/topic/27431-is-it-possible-to-run-tcp-and-zmod_adc-on-eclypse-z7-at-the-same-time/#comment-83944). Thus, if we try to do something further, can you give us some advice or tell us what to do so that we can continue working on our project.

×
×
  • Create New...