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 CLEAR ADCINT1 FLAG

Hey, guys

I am now using F28069. I am trying to use DMA to transfer the data from ADC result register to RAM 5. From the menu, it is said that when 

Upon receipt of a peripheral interrupt event signal, the DMA will automatically send a
clear signal to the interrupt source so that subsequent interrupt events will occur. (P.806)

However, when I run the program in Debug mode, it shows that the ADCINT1 Flag, which I use to trigger the DMA, is not cleared even after one burst of data is transferred. Does anybody know about it or meet with same problem? Thank you in advance.

Xinjun

  • Does anyone has any idea? Thank you.

  • Hi Xinjun,

    You could try setting the INT1CONT bit in INTSEL1N2 register (if you haven't already).

  • Thank you for your reply. I have set the interrupt to continue already, otherwise it can only transfer one burst of data rather than number of transfers I set in the TRANSFER_SIZE register. I would like to ask the peak sampling frequency F28069 can reach. Right now, I am using 2 MHz. Is it going to cause the problem?Thank you.

  • Maximum sampling rate is 3.4 MSPS, and I believe you should be able to use the DMA at that rate too.  

    So the way I understand it, you want to trigger the ADC at 2MHz, each sample is transferred by DMA, and then after some amount of samples are aggregated, you want to process the data?  Are you still having problems with getting the DMA to transfer multiple samples, or is the issue that the ADCINT flag is not cleared after all the samples have aggregated (or something else)?

  • I saw that maximum ADC frequency in the data sheet as well, but it seems that it just based on the data conversion time, regardless of ADC window and data transfer, so I am curious about the real peak sampling frequency it can reach.

    What you describe is almost what I would like to realize. I would like to sample the data at frequency of 2MHz, so I set ADC triggered by PWM whose period is 2MHz. Then, I set ADCINT1 to be continuously triggered by EOC0 (ADCB5). Also, DMA is triggered by ADCINT1 whose burst size is 0 ( convert 1 sample per burst), and transfer size is 499 (convert 500 samples) in all. At the end of converting 500 samples of data, I will stop ADC, PWM and DMA. 

    The problem is that I set the overflow bit enable in ADC, and I checked that the adc always overflows. Moreover, I use the function generator to input sinusoidal single to ADCB5. and it turns out that the signal is discontinuous. 

    Here is the code I make:

    /************************************************************************************
    Filename: DmaAdc.c

    // Description: This program implement the internal ADC
    * and DMA to do high frequency DAQ

    ***********************************************************************************/

    #include "definitions.h"
    #include "F2806x_Dma.h"
    #define BUF_SIZE 1000 // Sample buffer size

    Uint16 frequency = 1600;
    Uint16 i;

    volatile Uint16 *adcflg_ptr = &(AdcRegs.ADCINTFLGCLR.all); // ADC interrupt flag clear register
    extern volatile Uint16 DMABuf1[1000]; //DMA buffer store ADC results
    extern volatile Uint16 DMABuf2[1000];
    volatile Uint16 *DMADest; //DMA source pointer
    volatile Uint16 *DMASource; //DMA destination pointer

    interrupt void local_DINTCH1_ISR(void); //DMA CH1 interrupt routine
    interrupt void dma_adc_isr(void); //ADC INT1 interrupt routine

    //Perform high frequency DAQ with DMA
    void HifreqDAQ(void) {
    EALLOW; // Allow access to EALLOW protected registers
    PieVectTable.DINTCH1= &local_DINTCH1_ISR; //Acknowledge interrupt routine
    EDIS;
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; //Enable DMACH1 interrupt
    IER |= M_INT7 ; //Enable INT7 (7.1 DMA Ch1)
    EINT; // Enable Global interrupt INTM
    ERTM; // Enable Global realtime interrupt

    for (i=0; i < BUF_SIZE; i++) {

    DMABuf1[i] = 0; // Initialize Buffer;
    }
    InitializeDma(); // Initialize DMAs


    // Configure DMA Channel
    //DMASource = &DMABuf2[0];
    DMASource = &AdcResult.ADCRESULT0; //DMA source
    DMADest = &DMABuf1[0]; //DMA destination;
    ConfigDMACH1Addr(DMADest,DMASource); //Configure DMA address;
    ConfigDMACH1Burst(0,0,1); //Configure DMA burst size
    ConfigDMACH1Transfer(499,0,1); //Configure DMA transfer size
    ConfigDMACH1Wrap(0xFFFF,0,0xFFFF,0); //Configure DMA wrap size ( set to never happen)
    ConfigureDMACH1Mode(); //Configure DMA mode

    EALLOW;
    DmaRegs.CH1.CONTROL.bit.RUN = 1; //Start DMA channel;
    EDIS;

    InitialULTADC(); //Initialize ADC;

    }
    // INT7.1
    interrupt void local_DINTCH1_ISR(void) // DMA Channel 1
    {
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;
    }

    //interrupt void adc01_isr(void);
    void InitializeDma(void){
    EALLOW;
    // Perform a hard reset on DMA
    DmaRegs.DMACTRL.bit.HARDRESET = 1;
    asm (" nop"); // one NOP required after HARDRESET
    // Allow DMA to run free on emulation suspend
    DmaRegs.DEBUGCTRL.bit.FREE = 1;
    EDIS;

    }

    void ConfigDMACH1Addr(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source)
    {
    EALLOW;
    // Set up SOURCE address:
    DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32)DMA_Source; // Point to beginning of source buffer
    DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32)DMA_Source;
    // Set up DESTINATION address:
    DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)DMA_Dest; // Point to beginning of destination buffer
    DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)DMA_Dest;
    EDIS;
    }
    void ConfigDMACH1Burst(Uint16 bsize, int16 srcbstep, int16 desbstep)
    {
    EALLOW;
    // Set up BURST registers:
    DmaRegs.CH1.BURST_SIZE.all = bsize; // Number of words(X-1) x-ferred in a burst
    DmaRegs.CH1.SRC_BURST_STEP = srcbstep; // Increment source addr between each word x-ferred
    DmaRegs.CH1.DST_BURST_STEP = desbstep; // Increment dest addr between each word x-ferred
    EDIS;
    }
    void ConfigDMACH1Transfer(Uint16 tsize, int16 srctstep, int16 deststep)
    {
    EALLOW;
    // Set up TRANSFER registers:
    DmaRegs.CH1.TRANSFER_SIZE = tsize; // Number of bursts per transfer, DMA interrupt will occur after completed transfer
    DmaRegs.CH1.SRC_TRANSFER_STEP = srctstep; // TRANSFER_STEP is ignored when WRAP occurs
    DmaRegs.CH1.DST_TRANSFER_STEP = deststep; // TRANSFER_STEP is ignored when WRAP occurs
    EDIS;
    }
    void ConfigDMACH1Wrap(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep)
    {
    EALLOW;
    // Set up WRAP registers:
    DmaRegs.CH1.SRC_WRAP_SIZE = srcwsize; // Wrap source address after N bursts
    DmaRegs.CH1.SRC_WRAP_STEP = srcwstep; // Step for source wrap
    DmaRegs.CH1.DST_WRAP_SIZE = deswsize; // Wrap destination address after N bursts
    DmaRegs.CH1.DST_WRAP_STEP = deswstep; // Step for destination wrap
    EDIS;
    }


    void ConfigureDMACH1Mode(void){
    EALLOW;
    // Set up MODE Register:
    DmaRegs.CH1.MODE.bit.PERINTSEL = DMA_SEQ1INT; // Passed DMA channel as peripheral interrupt source
    DmaRegs.CH1.MODE.bit.PERINTE = PERINT_ENABLE; // Peripheral interrupt enable
    DmaRegs.CH1.MODE.bit.ONESHOT = ONESHOT_DISABLE; // OneShot enable
    DmaRegs.CH1.MODE.bit.CONTINUOUS =CONT_DISABLE; // Continuous disable
    DmaRegs.CH1.MODE.bit.SYNCE = SYNC_DISABLE; // Peripheral disable
    DmaRegs.CH1.MODE.bit.SYNCSEL = 0; // Sync effects source or destination
    DmaRegs.CH1.MODE.bit.OVRINTE = OVRFLOW_DISABLE; // Enable the overflow interrupt
    DmaRegs.CH1.MODE.bit.DATASIZE = SIXTEEN_BIT; // 16-bit data size transfers
    DmaRegs.CH1.MODE.bit.CHINTMODE = CHINT_END; // Generate interrupt to CPU at end of transfer
    DmaRegs.CH1.MODE.bit.CHINTE = CHINT_ENABLE; // Channel Interrupt to CPU enable*/
    // Clear any spurious flags:
    DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // Clear any spurious interrupt flags
    DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1; // Clear any spurious sync flags
    DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; // Clear any spurious sync error flags
    EDIS;
    }
    void InitialULTADC()
    {
    //Uint16 AdcConvMean;
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
    (*Device_cal)();
    EDIS;


    // To power-up the ADC the ADCENCLK bit should be set first to enable clocks
    EALLOW;
    AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; // Power ADC BG (Band-gap buffer's circuitry inside core is powered up)
    AdcRegs.ADCCTL1.bit.ADCREFPWD = 1; // Power reference
    AdcRegs.ADCCTL1.bit.ADCPWDN = 1; // Power ADC
    AdcRegs.ADCCTL1.bit.ADCENABLE = 0; // Enable ADC
    AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; // Select internal BG
    AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // ADCINT1 trips after AdcResults latch // this is important. EOC should be triggerred after end of conversion.
    EDIS;
    delayTime(ADC_usDELAY);

    EALLOW;
    AdcRegs.ADCCTL2.bit.CLKDIV2EN = 1; //ADCCLK equals SYSCLK/2 40 MHz.
    AdcRegs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Enable non-overlap mode
    EDIS;
    delayTime(ADC_usDELAY);

    EALLOW;
    AdcRegs.ADCSAMPLEMODE.bit.SIMULEN0 = 0; // SOC0 in single sample mode (vs. simultaneous mode)
    AdcRegs.ADCSOC0CTL.bit.CHSEL = 13; //Set SOC0 to sample B5 (saved in AdcResult0)
    AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 13; //set SOC 0 start trigger on EPWM5A
    AdcRegs.ADCSOC0CTL.bit.ACQPS = 8; //set SOC0 S/H Window to 7 ADC Clock Cycles

    AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 0; // No ADCINT triggers SOC0. TRIGSEL field determines trigger.

    AdcRegs.SOCPRICTL.bit.SOCPRIORITY = 0; // All SOCs handled in round-robin mode

    //--- ADCINT1 configuration
    AdcRegs.INTSEL1N2.bit.INT1CONT = 1; // ADCINT1 pulses regardless of ADCINT1 flag state
    AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enable ADCINT1
    AdcRegs.INTSEL1N2.bit.INT1SEL = 0; // EOC0 triggers ADCINT1

    //--- Enable the ADC interrupt
    IER |= 0x0001; // Enable INT1 in IER to enable PIE group // Enable INT1 in IER to enable PIE group

    //--- Finish up
    AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // Enable the ADC

    EDIS;

    // Initialize EPWM for triggering ADC SOC

    EPwm5Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
    EPwm5Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
    EPwm5Regs.TBCTR = 0x0000; // Clear counter
    EPwm5Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
    EPwm5Regs.ETSEL.bit.SOCASEL = 4; // Enable SOC when counter matches CMPB on upcount
    EPwm5Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on every 1st event
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Enable TBCLK
    EDIS;
    // Set EPWM5 period
    EPwm5Regs.TBPRD = frequency-1; // Set period for ePWM5s
    EPwm5Regs.CMPA.half.CMPA = frequency/2; // Set compare A value //TO make duty 50%
    EPwm5Regs.CMPB = frequency/2; // Set compare B value //make duty 50%
    EPwm5Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up and start;
    }

    Thank you so much for your help. My project is a little bit urgent, and I have got stuck on this for 2 weeks already.

    Xinjun

  • Xinjun,

    With the setup that you described, the ADCINT overflow is not really a concern because your are transferring the ADC results via the DMA hardware.  With the DMA handling the data, you don't need the CPU to continuously acknowledge or service the ADC.  You would only need to service the DMA after your data set is complete.  The overflow condition is merely indicating that the ADCINT was not serviced between each sample.

    The overflow bit would be a concern if you were transferring the results via software/CPU.  In such a scenario, the overflow condition would indicate that the CPU missed an ADC result.  As you have probably discovered, this is not an ideal configuration when operating a single SOC at full speed because the CPU would spend much of its time trying to keep up with the ADCINT ISR requests flooding in.  It would only be appropriate if ADCINT is generated at a slower pace.

    -Tommy