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.

F28335 ADC Max Conversion Rate Issue

Greetings,

 

                I am trying to get the maximum conversion rate of 12.5 MSPS from the ADC on an F28335 using the C2000 Microcontroller Development Kit which is running at 150 MHz.  The DMA is being used to transfer 2048 samples to memory.  The correct amount of data is being transferred, but instead of taking 163us (2048 samples * 80ns/sample), it is taking 326 us to finish.

 

The setup has been written per spru812a page 26 Table 1-7. It has been assumed that ‘HSPCP’ in the table should really be ‘HISPCP’.  In the routines below, AdcHwInit is called when the code is starting, and AdcSetupCapture is called just before the burst is to begin.  I have tried sending the SOCs from the PWM and also by having the code force them.  The result is the same either way.

 

                Any help would be much appreciated.

 

void AdcHwInit()

{

                InitAdc();

 

                // The following setup is to achieve the maximum conversion rate of 12.5 MSPS.

                // It is taken from spru812a (ADC document) page 26 (Table 1-7).

 

                EALLOW;

                SysCtrlRegs.HISPCP.all = 3;

                EDIS;

 

                AdcRegs.ADCTRL1.bit.ACQ_PS = 0;

                AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;

                AdcRegs.ADCTRL1.bit.CONT_RUN = 1;

 

                AdcRegs.ADCTRL2.bit.EPWM_SOCB_SEQ = 1;

                AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;

 

                AdcRegs.ADCTRL3.all = 0xE0;

 

                AdcRegs.ADCMAXCONV.all = 15;

}

 

void AdcSetupCapture()

{

                AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;

 

                AdcRegs.ADCCHSELSEQ1.all = ADCCHSELSEQ_SETUP_NORMAL;

                AdcRegs.ADCCHSELSEQ2.all = ADCCHSELSEQ_SETUP_NORMAL;

                AdcRegs.ADCCHSELSEQ3.all = ADCCHSELSEQ_SETUP_NORMAL;

                AdcRegs.ADCCHSELSEQ4.all = ADCCHSELSEQ_SETUP_NORMAL;

}

 

// Registers just before the burst starts

ADC_ADCTRL1                   0x0050

ADC_ADCTRL2                   0x8800

ADC_ADCMAXCONV                      0x000F

ADC_ADCCHSELSEQ1-4 0x0000

ADC_ADCASEQSR                            0x0000

ADC_CTRL3                         0x0E00

ADC_ADCST                       0x0000 0000 0000

ADC_ADCRESULT0-15    0x0000

ADC_ADCREFSEL                              0x1F28

ADC_ADCOFFTRIM                         0x711D

 

  • Hi Edward,

    I don't see any issues with the ADC code you have above. Are you sure the system is running at 150MHz? Are you sure the DMA is stopping after 2048 conversions?
  • Hi Devin,

    Thank you for the quick response. I am certain that the board is running at 150 MHz because I am using the PWM and getting the expected output using calculations based on a 150 MHz system clock.

    I have added the DMA setup below. To test whether or not the DMA is stopping at the right place, I changed the code to test for a wrap around. It waits for the first address in the DMA buffer to be filled, and then fills it with 0x1234. I repeated this at the 0x400, 0x600, and 0x700 indexes. After the DMA interrupt, I checked each location. None had changed from the value the new code wrote to those indexes.

    void DmaHwInit()
    {
    DMAInitialize();

    EALLOW;

    // DMA Channel Registers
    // We need to set these up for each DMA channel we will use.
    //
    DmaRegs.CH1.MODE.bit.CHINTE = 1;
    DmaRegs.CH1.MODE.bit.DATASIZE = 0;
    DmaRegs.CH1.MODE.bit.SYNCSEL = 0;
    DmaRegs.CH1.MODE.bit.SYNCE = 1;
    DmaRegs.CH1.MODE.bit.CONTINUOUS = 0;
    DmaRegs.CH1.MODE.bit.ONESHOT = 0;
    DmaRegs.CH1.MODE.bit.CHINTMODE = 1;
    DmaRegs.CH1.MODE.bit.PERINTE = 1;
    DmaRegs.CH1.MODE.bit.OVRINTE = 1;
    DmaRegs.CH1.MODE.bit.PERINTSEL = 1;

    // Remap the interrupts to our ISRs.
    PieVectTable.DINTCH1= &Dma_DINTCH1_ISR;
    EDIS;

    IER = M_INT7 ;
    EnableInterrupts();

    return;
    }


    #define BURST_SIZE 8 // words
    #define TRANSFER_SIZE_WORDS 2048
    #define TRANSFER_SIZE_BURSTS TRANSFER_SIZE_WORDS / BURST_SIZE
    void DmaSetupransfer()
    {
    // To see if the buffer is overwritten by the DMA.
    for (int i = 0 ; i < DMA_BUFF_SIZE ; i++)
    {
    dma_buffer[i] = 0xA5A5;
    }

    EALLOW;
    volatile Uint16 *DMADest = &dma_buffer[0];
    volatile Uint16 *DMASource = 0;
    DMASource = &AdcMirror.ADCRESULT0;
    DMACH1AddrConfig(DMADest, DMASource);
    DMACH1BurstConfig(BURST_SIZE-1, 1, 1);
    DMACH1TransferConfig(TRANSFER_SIZE_BURSTS-1, 1, BURST_SIZE);
    DMACH1WrapConfig(1, 0, 0, BURST_SIZE);
    DMACH1ModeConfig(DMA_SEQ1INT,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);
    StartDMACH1();
    EDIS;

    return;
    }
  • Hi Edward,

    Could it be that the ADC is in cascaded sequencer mode with max conversions = 0xF, which will generate 16 conversions at a time, but the DMA is only set to transfer 8 words at a time (burst size = 8)?
  • Hi Devin,

     

                    I changed the BURST_SIZE equate to 16, and the duration of the transfer became the expected 160us.  However, the data is no longer good.  I now see 16 words of reasonable values followed by 16 words of 0.  This pattern repeats for the entire buffer.  In the example below, you can see the 0x1234 the code is inserting into the first location of the buffer as noted in the previous post.

     

    0x0000C040 dma_buffer

    0x0000C040 1234 0005 0006 0007 0007 0008 0009 000A 000A 000B 000C 000C 000E 000D 000E

    0x0000C050 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

    0x0000C060 0016 0016 0016 0016 0017 0017 0018 0017 0018 0018 0019 001A 0019 0019 001A

    0x0000C070 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

    etc

  • Hi Edward,

    Look like in this case DMA setting and ADC settings are not in sync.

    How many valid sample ADC result register will have when DMA event gets generated? When you had BURST SIZE 8, was the data correct? 

    Regards,

    Vivek Singh 

  • Hi Vivek,

     

                    I don't understand the first question.  When the burst size was 8, except for an anomaly at the start of the capture, the data was reasonable.  The setup is as follows:

     

                    I am using the TMS320C2000 Experimenter Kit docking station, with the F28335 Delfino controlCARD.  On the docking station, I have connected pin ADC A0 to ground with a 1K resistor.  This is my ADC input.  When the burst size was 8, the data appeared as follows:

    0x0000C040  1234 0005 0006 0006 0007 0008 0007 0009 0012 0012 0013 0013 0014 0014 0014 0014

    0x0000C050  0016 0016 0016 0016 0016 0016 0018 0018 001B 001C 001A 001B 001B 001B 001B 001C

    0x0000C060  001C 001C 001C 001C 001C 001D 001C 001C 001E 001F 001E 001E 001E 001E 001F 001F

    0x0000C070  001F 001F 001F 001E 001F 001F 0020 001E 001F 0020 001F 0020 0020 0020 0021 0020

    0x0000C080  0020 0020 0020 0020 0021 001F 0020 001F 0020 0020 0020 0020 0021 0020 0020 0020

    0x0000C090  0021 0020 001F 0021 0020 0021 0020 0021 0020 0020 0021 0021 0020 0020 0020 0021

    0x0000C0A0  0020 0021 0020 0021 0021 0021 0022 0021 0020 0020 0021 0021 0020 0020 0021 0021

    0x0000C0B0  0021 0020 0020 0020 0020 0021 0020 0021 0021 0021 0020 0020 0021 0020 0020 0021

    0x0000C0C0  0022 0021 0021 0021 0021 0021 0021 0020 0021 0021 0021 0021 0021 0020 0020 0021

    etc

     

                    Keep in mind that the code is deliberately overwriting the value at 0xC040 by inserting the 1234 value as a test of whether or not a wrap-around has occurred.  As you can see, all the data locations are filled.  However, there is an “asymptotic” rise to the final value.  The final value seems fairly reasonable given the setup.

     

    However, when the burst size is changed to 16, I get 16 words of data followed by 16 words of 0s as follows:

    0x0000C040 dma_buffer

    0x0000C040 1234 0005 0006 0007 0007 0008 0009 000A 000A 000B 000C 000C 000E 000D 000E

    0x0000C050 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

    0x0000C060 0016 0016 0016 0016 0017 0017 0018 0017 0018 0018 0019 001A 0019 0019 001A

    0x0000C070 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

    etc

     

    Regards,

     

    Ed

  • Hi Edward,

    Can you double check your DMA configuration change, you made for burst size 16 because it appears to me that in this case it's doing burst of 32 instead of 16.

    Regards,

    Vivek Singh

  • Hi Vivek,

     

                    I’ve double checked the code, and I'm certain that it is setting up for a burst of 16.  But I have included the latest code in case I’ve missed something.  I’ve eliminated the interrupt setup and handling.  Also, I’m wondering if the SOCs can affect this.  I found that I could not achieve the entire transfer with a single SOC.  So after the PWM has sent the initial SOC, the code goes into a tight loop sending SOCs to the ADC until the transfer is complete.  Could this have an effect on the DMA?

     

    ////////////////////////////////////////////////

    // DMA Setup

    #define SEQ1INT                   1

    #define       PERINTSEL_INIT                    SEQ1INT

    #define BURST_SIZE                16            // words

    #define TRANSFER_SIZE_WORDS       2048

    #define TRANSFER_SIZE_BURSTS      TRANSFER_SIZE_WORDS / BURST_SIZE

     

    void DmaHwInit()

    {

           DMAInitialize();

     

           EALLOW;

     

           DmaRegs.CH1.MODE.bit.CHINTE = 1;         // Enable the interrupt

           DmaRegs.CH2.MODE.bit.CHINTE = 1;

           DmaRegs.CH1.MODE.bit.DATASIZE = 0;       // 16 bit transfers

           DmaRegs.CH2.MODE.bit.DATASIZE = 0;

           DmaRegs.CH1.MODE.bit.SYNCSEL = 0;

           DmaRegs.CH2.MODE.bit.SYNCSEL = 0;

           DmaRegs.CH1.MODE.bit.SYNCE = 1;          // Allow the sync enable.

           DmaRegs.CH2.MODE.bit.SYNCE = 1;

           DmaRegs.CH1.MODE.bit.CONTINUOUS = 0;            // Stop when the transfer is complete.

           DmaRegs.CH2.MODE.bit.CONTINUOUS = 0;

           DmaRegs.CH1.MODE.bit.ONESHOT = 0;        // Allow other peripherals to use this

           DmaRegs.CH2.MODE.bit.ONESHOT = 0;

           DmaRegs.CH1.MODE.bit.CHINTMODE = 1;             // Interrupt at end of transfer

           DmaRegs.CH2.MODE.bit.CHINTMODE = 1;

           DmaRegs.CH1.MODE.bit.PERINTE = 1;        // Peripheral Interrupt Trigger enabled

           DmaRegs.CH2.MODE.bit.PERINTE = 1;

           DmaRegs.CH1.MODE.bit.OVRINTE = 1;        // Overflow interrupt enabled

           DmaRegs.CH2.MODE.bit.OVRINTE = 1;

           DmaRegs.CH1.MODE.bit.PERINTSEL = PERINTSEL_INIT; // Peripheral Interrupt Trigger from ADC

           DmaRegs.CH2.MODE.bit.PERINTSEL = PERINTSEL_INIT;

     

           EDIS;   // Disable access to EALLOW protected registers

     

           return;

    }

     

    void DmaSetupTransfer()

    {

           xferDone = false;

     

           for (int i = 0 ; i < DMA_BUFF_SIZE ; i++) dma_buffer[i] = 0xA5A5;    //###???

           EALLOW;

           volatile Uint16 *DMADest   = dma_buffer;

           volatile Uint16 *DMASource = 0;

           DMASource = &AdcMirror.ADCRESULT0;   //Point DMA source to ADC result register base

           DMACH1AddrConfig(DMADest, DMASource);

           DMACH1BurstConfig(BURST_SIZE-1, 1, 1);

           DMACH1TransferConfig(TRANSFER_SIZE_BURSTS-1, 1, BURST_SIZE);

           DMACH1WrapConfig(1, 0, 0, BURST_SIZE);

           DMACH1ModeConfig(DMA_SEQ1INT,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);

           StartDMACH1();

     

           EDIS;

     

           return;

    }

     

    ////////////////////////////////////////////////

    // ADC Setup

    #define ADC_MODCLK   0x3

    #define ADC_ADCBGRFND      0x00C0

    #define ADC_ADCPWDN  0x0020

    #define ADCTRL3_INIT ADC_ADCBGRFND + ADC_ADCPWDN

    #define ADCMAXCONV_INIT    15

    #define ADCCHSELSEQ_SETUP_NORMAL  0x0000

     

    void AdcHwInit()

    {

           InitAdc();

     

           // The following setup is to achieve the maximum conversion rate of 12.5 MSPS.

           // It is taken from spru812a (ADC document) page 26 (Table 1-7).

     

           EALLOW;

           SysCtrlRegs.HISPCP.all = ADC_MODCLK;

           EDIS;

     

           AdcRegs.ADCTRL1.bit.ACQ_PS = 0;

           AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;

           AdcRegs.ADCTRL1.bit.CONT_RUN = 1;

           AdcRegs.ADCTRL2.bit.EPWM_SOCB_SEQ = 1;

           AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;

           AdcRegs.ADCTRL3.all = ADCTRL3_INIT;

           AdcRegs.ADCMAXCONV.all = ADCMAXCONV_INIT;

    }

     

     

    void AdcSetupCapture()

    {

           AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;

     

           AdcRegs.ADCCHSELSEQ1.all = ADCCHSELSEQ_SETUP_NORMAL;

           AdcRegs.ADCCHSELSEQ2.all = ADCCHSELSEQ_SETUP_NORMAL;

           AdcRegs.ADCCHSELSEQ3.all = ADCCHSELSEQ_SETUP_NORMAL;

           AdcRegs.ADCCHSELSEQ4.all = ADCCHSELSEQ_SETUP_NORMAL;

    }

     

    Thank you,

     

    Ed

  • Hi Edward,

    Sorry for late reply. I did not understand the following statement in your last update -

    ---"So after the PWM has sent the initial SOC, the code goes into a tight loop sending SOCs to the ADC until the transfer is complete."

    Can you provide more detail on this.

    Regards,

    Vivek Singh

  • Hi Vivek,

     

                    I have programmed the PWM to send an SoC to start the ADC conversions.  When that was all the code did, I observed that a single burst of conversions occurred and were deposited into memory.  To get all the conversions programmed, I found that I needed to program the processor to continuously send SoCs until all the conversions had been done.  Does this help?

     

    Ed

     

  • Hi Edward,

    After changing the BURST SIZE to 16, you did not change the WRAP CONFIG setting for source in following code.

    DMACH1WrapConfig(1, 0, 0, BURST_SIZE);

    It's still configured to wrap after 2 burst and that's why DMA is reading 0 for next 16 data. Please change this to wrap after 1 burst and that should fix this issue.

    Regards,

    Vivek Singh

  • Bingo!!!  That was it.  My data quality is back to what it was when I started this thread.

    Thank you for your help,

    Ed

  • Hi Edward, glad to know issue this fixes the issue.

    Regards,
    Vivek Singh