Jump to content

Tommy 777

Members
  • Posts

    4
  • Joined

  • Last visited

Posts posted by Tommy 777

  1. 10 hours ago, artvvb said:

    The ADC IIC base address should also be I2C_1, both Zmods share that MIO I2C:

    
    
    #define IIC_ADC_BASE_ADDR       XPAR_PS7_I2C_1_BASEADDR

     

    The heap size should also be increased in the linker script (lscript.ld). 0x4000 should be sufficient, though larger won't hurt (and if you want to use significantly bigger software buffers, it will need to be larger). I'd adjusted this while debugging yesterday prior to correcting the length, in order to see if there was a memory leak or something progressively eating more of the heap on each pass through the DAC demo.

    In case it's helpful, I've attached the modified dma.c that I've been using while debugging, which takes advantage of the mallinfo function to track when and how much of the memory in the heap is being allocated and freed.

    This produced the following log, which I've annotated with the objects getting allocated and freed. Note that fordblks shows the amount of free memory that can be accessed by the malloc function.

      Hide contents

    malloc info (fnInitDMA:DMAEnv): -- Allocate ADC DMAEnv
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 000009E8
     fordblks: 00000E28
     keepcost: 00000E28
    malloc info (fnInitDMA:xAxiDma): -- Allocate ADC xAxiDma
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 00000A00
     fordblks: 00000E10
     keepcost: 00000E10
    malloc info (fnAllocBuffer): -- Allocate ADC acqBuffer
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 000011F0
     fordblks: 00000620
     keepcost: 00000620
    -109.863 mV     3FDC    0 L     0 ns
    malloc info (fnFreeBuffer): -- Free ADC acqBuffer
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 00001200
     fordblks: 00000610
     keepcost: 00000610
    malloc info (fnInitDMA:DMAEnv): -- Allocate DAC DMAEnv
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 000011F0
     fordblks: 00000620
     keepcost: 00000620
    malloc info (fnInitDMA:xAxiDma): -- Allocate DAC xAxiDma
     arena:    00001810
     ordblks:  00000001
     smblks:   00000000
     hblks:    00000000
     hblkhd:   00000000
     usmblks:  00000000
     fsmblks:  00000000
     uordblks: 00001208
     fordblks: 00000608 -- hovering over sizeof(XAxiDMA) in debug shows it to be 0x750 bytes!
     keepcost: 00000608
    Can't allocate XAxiDma for 40410000

    This shows that when the DAC XAxiDma is being allocated, there isn't enough memory left for malloc.

     

    The length variable is still an issue (but has now been corrected in the Github sources).

    The 14 bit length limit you note is due to the size of the AXI DMA's transfer length register rather than the size of the allocated buffer in DDR. The overflow I'm describing happens solely in software. In the original code, with amplitude 5 and step 2, the following line allocates an 8-word memory space:

    
    
    length = (size_t)(amplitude/step) << 2;
    buf = dacZmod.allocChannelsBuffer(length);
    
    // (size_t)(5.0 / 2.0) << 2
    // = (size_t)(2.5) << 2
    // = 2 << 2
    // = 8

    while each of the for loops count five times.

    
    
    for(val = -amplitude; val < amplitude; val += step) // expands to -5, -3, -1, 1, 3
    for(val = amplitude; val > -amplitude; val -= step) // expands to 5, 3, 1, -1, -3

    This can be checked by printing the value of length and the value of i after the for loops.

     

    Yesterday, before correcting the length, the mallinfo technique showed the uordblks, fordblks, and keepcost values to be underflowing at some point prior to the failed DMAEnv allocation (which was a different failure point than the xAxiDma), meaning that more memory had been freed than had previously been allocated.

    Thanks,

    Arthur

    dma.c 11.5 kB · 0 downloads

     

     

    Hi: @artvvb

    Thanks for your answers.

    it works!!!!, that is really helpful. And I have understood your explanation  about length, I really learn much.

    Thanks for your patient and help, hope there is another chance to discuss with you in the future.

  2. 14 hours ago, artvvb said:

    Hi @Tommy 777

    This looks like it's due to a bug in the DAC example code.
    The following line in your version of the code introduces a rounding error when the amplitude divided by step (5 / 2 = 2.5) is converted to an integer, causing the loop later in the function to count past the end of the allocated buffer, overwriting something critical above it.

    
    length = ((size_t)(amplitude/step)) << 2;

    Changing the line to the following should address the problem.

    
    length = ((size_t)((amplitude * 2.0) / step)) * 2;

    I'm working to get it addressed in the github sources.

    Thanks,

    Arthur

     

    Hi @artvvb

    Thanks for your answer.

    I have tried to change the code as you posted, but unfortunately it cannot solve the problem. I am a beginner so I hope to discusses this problem more and share my ideas with you. 

    First of all, in your answer, you think the length may count past the end of the allocated buffer, but the demo limits the length when data get overflow like:

     if (length > ((1<<14) - 1))
        {
            // limit the length to maximum buffer size (1<<14 - 1)
            length = ((1<<14) - 1);
            // adjust step
            step = amplitude/(length>>2);
        }

    I think this code could make sure the length will not over the limitation of buffer (14 bit ), because of that, I don't need to calculate the length to make sure it is not over the maximum buffer size when the amplitude and step are modified. So I think it is not the key point of this problem.

     

     

    Next I want to share some of my findings about the problem.

    I think the problem may happen in the DMA but not the DAC buffer. (I think they are two different things, if I am wrong please tell me). Here are some evidence.

    First, assume the problem happens in the DAC buffer, when I just call the DAC function, there should be a same problem and the DAC could not generate the correct waveform. But in fact, the DAC could work perfectly when I just call it. 

    Secondly, assume the problem happens in the DAC buffer, the problem will have no relationship with the order in which DAC and ADC are called. In the other word, whatever I call ADC first or DAC first, the problem will always happen in DAC and ADC will work perfectly. But in fact, when I call the ADC first, the DAC could not work; while I call the DAC first, the ADC could not work.

    thirdly, according to the feedback of SDK 'Can't allocate DMAEnv for 40410000', I found the source code in dam.c document, which is in 'zmodlib>Zmod' folder. The code is as follow:

    /**
     * Initialize the DMA.
     *
     * @param dmaBaseAddr the base address of the DMA device
     * @param direction the direction of the DMA transfers
     * @param dma_interrupt_id the interrupt number of the DMA device
     *
     * @return a pointer to an instance of DMAEnv
     */
    uint32_t fnInitDMA(uintptr_t dmaBaseAddr, enum dma_direction direction,
    		int dma_interrupt_id) {
    	DMAEnv *dmaEnv = (DMAEnv *)malloc(sizeof(DMAEnv));
    	ivt_t ivt[] = {
    		{ dma_interrupt_id, (XInterruptHandler)fnDMAInterruptHandler, dmaEnv },
    	};
    
    	if (!dmaEnv) {
    		xil_printf("Can't allocate DMAEnv for %X\n", dmaBaseAddr);
    		return 0;
    	}
    
    	// Init interrupt controller
    	if (!fIntCInit) {
    		fnInitInterruptController(&sIntc);
    		fIntCInit = true;
    	}
    
    	dmaEnv->xAxiDma = (XAxiDma *)malloc(sizeof(XAxiDma));
    	if (!dmaEnv->xAxiDma) {
    		xil_printf("Can't allocate XAxiDma for %X\n", dmaBaseAddr);
    		return 0;
    	}
    
    	dmaEnv->base_addr = fnConfigDma(dmaEnv->xAxiDma, dmaBaseAddr);
    	if (dmaEnv->base_addr < 0) {
    		xil_printf("DMA configuration failure for %X\n", dmaBaseAddr);
    		fnDestroyDMA((uint32_t)dmaEnv);
    		return 0;
    	}
    
    	// Enable all interrupts in the interrupt vector table
    	fnEnableInterrupts(&sIntc, &ivt[0], sizeof(ivt)/sizeof(ivt[0]));
    
    	dmaEnv->direction = direction;
    	if (dmaEnv->direction == DMA_DIRECTION_RX) {
    		// enable AXIDMA S2MM IOC interrupt
    		writeDMARegFld(dmaEnv->base_addr, AXIDMA_REGFLD_S2MM_DMACR_IOC_IRQ, 1);
    	}
    	else{	// DMA_DIRECTION_TX
    		// enable AXIDMA MM2S IOC interrupt
    		writeDMARegFld(dmaEnv->base_addr, AXIDMA_REGFLD_MM2S_DMACR_IOC_IRQ, 1);
    
    	}
    
        return (uint32_t)dmaEnv;
    }
    

    According to this, I think the problem is DMA initialisation failed. Back to my code, the programme stops at:

    ZMODDAC1411 dacZmod(ZMOD_DAC_BASE_ADDR, DMA_DAC_BASE_ADDR, IIC_DAC_BASE_ADDR, FLASH_ADDR_DAC, DMA_DAC_IRQ);

    This code is the initialisation of DAC and the address of the second parameter 'DMA_DAC_BASE_ADDR' is '40410000'. (Here I choose the DAC as the example just because I call the ADC first in my code and the DAC initialisation failed. I have tried to call DAC first and in that situation, the ADC initialisation will failed and the SDK shows 'Can't allocate DMAEnv for 40400000' which is the DMA base address for ADC).

    More over, I found the DDR cannot allocate addresses for ADC initialisation and DAC initialisation at the same time. I have tried the one shot test of my code, like:

    void dacRampDemo(float offset, float amplitude, float step, uint8_t channel, uint8_t frequencyDivider, uint8_t gain, uint8_t checkpoint)
    {
        ZMODDAC1411 dacZmod(ZMOD_DAC_BASE_ADDR, DMA_DAC_BASE_ADDR, IIC_DAC_BASE_ADDR, FLASH_ADDR_DAC, DMA_DAC_IRQ);
        
    }
    
    
    void ADCBaremetalDemo(uint8_t channel,uint8_t gain)
    {
        
        ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_ADC_BASE_ADDR, FLASH_ADDR_ADC,
                        ZMOD_ADC_IRQ, DMA_ADC_IRQ)
    }
    
    int main() {
    
    
       ADCBaremetalDemo(0,0);
       dacRampDemo(0, 5, 2, 0, 8, 1,checkpoint);
    
        return 0;
    }

    I just post the struct here for reading convenience. In one shot test, there is not loop and the processing is start > call ADC > ADC initialisation > realise ADC function > return void(free the ADC initialisation at same time) > call DAC > DAC initialisation > realise DAC function > return void(free the DAC initialisation at the same time)> return 0. So I assume that because the ADC function and the DAC function will free the initialisation, in one shot test, the DAC and the ADC initialisation will not affect each other and they both work by order. In order to prove my guess, I use 'static' to fixed the ADC initialisation like:

    static ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_ADC_BASE_ADDR, FLASH_ADDR_ADC,
                        ZMOD_ADC_IRQ, DMA_ADC_IRQ)

    In this situation, the DMA of DAC cannot be initialised. It proves my guess that when ADC has been initialised, ADC DMA will occupy something and the DAC DMA cannot be allocated.

    In summary, I think the problem is the initialisation of DAC. More specifically, it is the initialisation of DMA failed when the DAC and the ADC are initialised at the same time.

     

     

    Next are some possible reasons I guess:

     As I stated before, the problem is the DMA initialisation failed when the DAC and the ADC are initialised together, so I focus my eyes on the function of DMA initialisation. There are two possibilities, one is the parameter has problem and another is the code gets problem. In the aspect of code, I don't find any obvious bug. I also tried the 'new'  function to replace the 'malloc' function but nothing improved. In the aspect of parameter, the only one I am not sure is the direction of DMA transform. In my opinion, the direction of DMA transform in ADC is from device to DMA and that is from DMA to device in DAC. If it is true, is there any possible when ADC has been initialised, the direction of DMA has been set and it is not suitable for DAC, that cause the DAC DMA initialisation failed?

    Looking forward to your further answer, thank you.

  3. Hi:

    When I try to initialize the ADC and DAC in a same void function, the SDK shows me that 'Can't allocate DMAEnv for 40410000'. '40410000' is the address of DMA_DAC_BASE_ADDR. Because of that, DAC cannot generate the correct waveform when ADC works perfect. By the way, it works perfectly when I just use DAC or ADC.

    Thanks for any suggestion.

    Spoiler


    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <xil_printf.h>
    #include "xparameters.h"


    #include "D:\Gitbash\ADC-test\Eclypse-Z7\hw\proj\hw.sdk\zmodlib\ZmodADC1410\zmodadc1410.h"
    #include "D:\Gitbash\DAC-test\Eclypse-Z7\hw\proj\hw.sdk\zmodlib\ZmodDAC1411\zmoddac1411.h"
    #include "D:\Gitbash\ADC-test\Eclypse-Z7\hw\proj\hw.sdk\zmodlib\Zmod\zmod.h"

    #define TRANSFER_LEN    0x1 /*100=2us*/
    #define ZMOD_ADC_BASE_ADDR     XPAR_ZMODADC_0_AXI_ZMODADC1410_1_S00_AXI_BASEADDR
    #define DMA_ADC_BASE_ADDR     XPAR_ZMODADC_0_AXI_DMA_0_BASEADDR
    #define IIC_ADC_BASE_ADDR       XPAR_PS7_I2C_0_BASEADDR
    #define FLASH_ADDR_ADC       0x30
    #define ZMOD_ADC_IRQ         XPAR_FABRIC_ZMODADC_0_AXI_ZMODADC1410_1_LIRQOUT_INTR
    #define DMA_ADC_IRQ         XPAR_FABRIC_ZMODADC_0_AXI_DMA_0_S2MM_INTROUT_INTR

    #define ZMOD_DAC_BASE_ADDR     XPAR_ZMODDAC_0_AXI_ZMODDAC1411_V1_0_0_BASEADDR
    #define DMA_DAC_BASE_ADDR     XPAR_ZMODDAC_0_AXI_DMA_1_BASEADDR
    #define FLASH_ADDR_DAC       0x31
    #define DMA_DAC_IRQ         XPAR_FABRIC_ZMODDAC_0_AXI_DMA_1_MM2S_INTROUT_INTR
    #define IIC_DAC_BASE_ADDR       XPAR_PS7_I2C_1_BASEADDR

    uint8_t checkpoint;

    void dacRampDemo(float offset, float amplitude, float step, uint8_t channel, uint8_t frequencyDivider, uint8_t gain, uint8_t checkpoint)
    {
        ZMODDAC1411 dacZmod(ZMOD_DAC_BASE_ADDR, DMA_DAC_BASE_ADDR, IIC_DAC_BASE_ADDR, FLASH_ADDR_DAC, DMA_DAC_IRQ);
        uint32_t *buf;
        float val;
        uint32_t valBuf;
        int16_t valRaw;
        size_t length;

        length = (size_t)(amplitude/step) << 2;
        int i;
        if (length > ((1<<14) - 1))
        {
            // limit the length to maximum buffer size (1<<14 - 1)
            length = ((1<<14) - 1);
            // adjust step
            step = amplitude/(length>>2);
        }

        buf = dacZmod.allocChannelsBuffer(length);

        dacZmod.setOutputSampleFrequencyDivider(frequencyDivider);
        dacZmod.setGain(channel, gain);


        if(checkpoint==0)
        {
            i = 0;
            // ramp up
            for(val = -amplitude; val < amplitude; val += step)
                {
                    valRaw = dacZmod.getSignedRawFromVolt(val + offset, gain);
                    valBuf = dacZmod.arrangeChannelData(channel, valRaw);
                    buf[i++] = valBuf;
                }
            // ramp down
            for(val = amplitude; val > -amplitude; val -= step)
                {
                    valRaw = dacZmod.getSignedRawFromVolt(val + offset, gain);
                    valBuf = dacZmod.arrangeChannelData(channel, valRaw);
                    buf[i++] = valBuf;
                }
            // send data to DAC and start the instrument
            dacZmod.setData(buf, length);// necessary
            dacZmod.start(); //necessary

            dacZmod.freeChannelsBuffer(buf, length);
            dacZmod.stop();
        }

        if(checkpoint==1)
            {
                i = 0;
                // ramp up
                for(val = -amplitude; val < amplitude; val += step)
                    {
                        valRaw = dacZmod.getSignedRawFromVolt(amplitude + offset, gain);
                        valBuf = dacZmod.arrangeChannelData(channel, valRaw);
                        buf[i++] = valBuf;
                    }
                // ramp down
                for(val = amplitude; val > -amplitude; val -= step)
                    {
                        valRaw = dacZmod.getSignedRawFromVolt(-amplitude + offset, gain);
                        valBuf = dacZmod.arrangeChannelData(channel, valRaw);
                        buf[i++] = valBuf;
                    }
                // send data to DAC and start the instrument
                dacZmod.setData(buf, length);// necessary
                dacZmod.start(); //necessary

                dacZmod.freeChannelsBuffer(buf, length);
                dacZmod.stop();
            }


    }

    void formatADCDataOverUART(ZMODADC1410 *padcZmod, uint32_t *acqBuffer, uint8_t channel, uint8_t gain, size_t length)
    {
        char val_formatted[15];
        char time_formatted[15];
        char check[15];
        uint32_t valBuf;
        int16_t valCh;
        float val;
        for (size_t i = 0; i < length; i++)
        {
            valBuf = acqBuffer[i];
            valCh = padcZmod->signedChannelData(channel, valBuf);
            val = padcZmod->getVoltFromSignedRaw(valCh, gain);
            padcZmod->formatValue(val_formatted, 1000.0*val, "mV");

            if(1000.0*val<2400)
            {
                padcZmod->formatValue(check, 0, "L");
                checkpoint=0;
            }
            else
            {
                padcZmod->formatValue(check, 1, "H");
                checkpoint=1;
            }

            if (i < 100)
            {
                padcZmod->formatValue(time_formatted, i*10, "ns");
            }
            else
            {
                padcZmod->formatValue(time_formatted, (float)(i)/100.0, "us");
            }


            xil_printf("%s\t%x\t%s\t%s\n", val_formatted, (uint32_t)(valCh&0x3FFF), check, time_formatted );

        }
    }


    void ADCBaremetalDemo(uint8_t channel,uint8_t gain)
    {
        // channel                     CH1
        // gain                        LOW - Corresponds to HIGH input Range
        // length                    0x1

        ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_ADC_BASE_ADDR, FLASH_ADDR_ADC,
                        ZMOD_ADC_IRQ, DMA_ADC_IRQ);

        uint32_t *acqBuffer;
        size_t acqbufferlength=TRANSFER_LEN;

        adcZmod.setGain(channel, gain);

        while(1)
            {
                acqBuffer = adcZmod.allocChannelsBuffer(acqbufferlength);
                adcZmod.acquireImmediatePolling(acqBuffer, acqbufferlength);

                formatADCDataOverUART(&adcZmod, acqBuffer, channel, gain, acqbufferlength);
                adcZmod.freeChannelsBuffer(acqBuffer, acqbufferlength);

                dacRampDemo(0, 5, 2, 0, 8, 1,checkpoint);
                sleep(1);

            }

    }


    /*
     * ADC Baremetal Demo
     */
    int main() {


        ADCBaremetalDemo(0,0);

        return 0;
    }
     

     

     

    Update 26th January

    My project is using the ADC collect the data and compare the data with the threshold, DAC will generate the different waveform according to the result of comparative.

     

    Update 27th January

    The problem has been solved!!!! Tanks to @artvvb

    I will share some experience here to help others.

    First, just like what @artvvb said you need change the size of heap and the default value is just 2000, if you hope to initialise the ADC and DAC at the same time.

    Secondly, don't forget to use static to avoid the duplicate initialisation in loop, or the heap will overflow again.

    By the way, in my code, I enable two I2C, so the I2C base address of ADC and ADC are different. If you use the default demo from the GitHub, please follow the answer from @artvvb.

×
×
  • Create New...