This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DMA setup for ADC

Hi,

I need to implement a ADC double buffering using DMA. I've setup the ADC with FIFO size of 32 8BIT samples and the ADC RAM of 64 sample. The DMA would be triggered every FIFO sample so will transfer the first half of the ADC RAM while the ADC write the second half and so on. The DMA destination buffer is 512Bytes.

My DMA control packet is set as follow:

    g_dmaCTRLPKT.SADD = (uint32)adcRAM1; /* source address */
    g_dmaCTRLPKT.DADD = (uint32)&Buffer; /* destination address */
    g_dmaCTRLPKT.CHCTRL = 0; /* channel control */
    g_dmaCTRLPKT.FRCNT = 16; /* frame count */
    g_dmaCTRLPKT.ELCNT = 32; /* element count */
    g_dmaCTRLPKT.ELDOFFSET = 0; /* element destination offset - is required? */
    g_dmaCTRLPKT.ELSOFFSET = 0; /* element source offset - is required? */
    g_dmaCTRLPKT.FRDOFFSET = 0; /* frame detination offset - is required? */
    g_dmaCTRLPKT.FRSOFFSET = 0; /* frame source offset - is required? */
    g_dmaCTRLPKT.PORTASGN = 4; /* port b */
    g_dmaCTRLPKT.RDSIZE = ACCESS_8_BIT; /* read size */
    g_dmaCTRLPKT.WRSIZE = ACCESS_8_BIT; /* write size */
    g_dmaCTRLPKT.TTYPE = FRAME_TRANSFER ; /* transfer type */
    g_dmaCTRLPKT.ADDMODERD = ADDR_FIXED; /* address mode read */
    g_dmaCTRLPKT.ADDMODEWR = ADDR_INC1; /* address mode write */
    g_dmaCTRLPKT.AUTOINIT = AUTOINIT_ON; /* autoinit (loop) */
    dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT);
    dmaSetChEnable(DMA_CH0, DMA_HW);

but I'm not sure it is right. In particular ADDMODERD = ADDR_FIXED will cause the DMA read from a fixed address insted of alternating the two half of the ADC RAM. AFAIK the frame and element couts are referred to the destination buffer. How can I setup this behaviour?

thank you,

Matteo

  • Matteo,

    I've referred this question to our DMA expert who will get back to you.

    Paul B

  • Matteo,

    Frame/Element counts are applicable to both Source & Destination. You control the Source/Dest rd/wr address using the ELxOFFSET/FRxOFFSETs (in bytes) and ADDMODEx registers.

    With your current setup, for every DMA request, dma will transfer 32 bytes(ELCNT) from the fixed source(ADCRAM1) to your Buffer. The destination addr will wrap after 16 (FRCNT), total 512 bytes. Is the request generated after FIFO full? or for each conversion?

    If you want to alternate between 2 source addr, you can set the FRCNT to 2, FRSOFFSET=32 and ADDMODERD=ADDR_OFFSET. With this setup you will loose the bigger destination buffering, it is better to use the ADC RAM itself.

    1. You may be able to access the FIFO elements at discrete address to overcome this limitation.

    2. Are you not interested in the whole 12bits of ADC result?

    Thanks,

    Joe

  • Hi Joe,

    thank you for the answer.

    Actually I'm not interested in the 12Bit because I'm running ADC with 8BIt data resolution.

    The DMA request from ADC would be generated every FIFO conversion/32 sample (I've not yet investigated how to enable this) and I have set the DNDA for ADC1 memory at 32 so the ADC1 RAM should contain 2 FIFO (BTW: is this setup automatic? If the RAM size doubles the FIFO size the ADC will double-buffer by its own?),

    According with your answer I've modified my DMA setup as follow:

        g_dmaCTRLPKT.SADD = (uint32)adcRAM1;
        g_dmaCTRLPKT.DADD = (uint32)&Buffer;
        g_dmaCTRLPKT.CHCTRL = 0;
        g_dmaCTRLPKT.FRCNT = 16;
        g_dmaCTRLPKT.ELCNT = 32;
        g_dmaCTRLPKT.ELDOFFSET = 0;
        g_dmaCTRLPKT.ELSOFFSET = 0;
        g_dmaCTRLPKT.FRDOFFSET = 0;
        g_dmaCTRLPKT.FRSOFFSET = 1;
        g_dmaCTRLPKT.PORTASGN = 4;
        g_dmaCTRLPKT.RDSIZE = ACCESS_8_BIT;
        g_dmaCTRLPKT.WRSIZE = ACCESS_8_BIT;
        g_dmaCTRLPKT.TTYPE = FRAME_TRANSFER;
        g_dmaCTRLPKT.ADDMODERD = ADDR_OFFSET;
        g_dmaCTRLPKT.ADDMODEWR = ADDR_INC1;
        g_dmaCTRLPKT.AUTOINIT = AUTOINIT_ON;
        dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT);
        dmaSetChEnable(DMA_CH0, DMA_HW);
        dmaReqAssign(DMA_CH0,7);

        dmaEnableInterrupt(DMA_CH0, HBC);
        dmaEnableInterrupt(DMA_CH0, BTC);

    Is this correct?

    thank you,

    Matteo