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.

Continuous AD conversion with F28027



Hi,

I'm using a Piccolo ControlSTICK (with a 28027 DSP) and are aiming to sample a signal at highest possible sample rate (4.6Msps). However, I have quite a lot of trouble when configuring my ADC.

First off, I get the feeling that the highest sample rate, 4.6Msps, might be very optimistic. When I've tried to do continuous sampling, even at lower sampling rates, I get problems that seems to be that I cant manage to process the adc results before next interrupt occurs. Sampling at 4.6 Msps seems to be a very big challenge if I have trouble sampling at 850ksps. Is it even theoretically possible to sample that fast with a 28027 running at 60 MHz? And if not, what can be the highest achievable sample rate?

Back to my problem.

As you can see in the attached code I use all SOCs, and they are triggered by ADCINT1. ADCINT1 is triggered by EOC14. In the ContinousAdc-example EOC14 triggers ADCINT1, so I did that too. With INT1CONT set and the round-robin principle I suppose ADCIN1 should be sampled at a periodic rate?

This is a graph of my buffer (currently 256 bytes, theres a 4KHz sine on ADCIN1):

The reason for using all SOCs was basically that it might be possible to copy the ADC result in the interrupt without stalling the next ADC interrupt while doing so. Im not sure if this is the way to do it though. Any suggestions?

I use the internal clock at 60MHz.

A related question; In the errata, problems with "Initial conversion" is mentioned. If I sample continuously, will every 16th value be corrupt, or will be jst be the first value in my buffer?

Best regards

Henrik Karlsson

This is the code:
static uint16_t m_adcBuffer[ADC_BUFFER_SIZE];

static uint16_t *m_pAdcBuffer = m_adcBuffer;
static uint16_t *m_pAdcBufferEnd;
//@} End of Data


//////////////////////////////////////////////////////////////////////
/// @name Private Methods
//@{

interrupt void adc_isr(void)
{
    *m_pAdcBuffer++ = AdcResult.ADCRESULT0;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT1;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT2;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT3;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT4;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT5;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT6;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT7;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT8;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT9;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT10;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT11;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT12;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT13;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT14;
    *m_pAdcBuffer++ = AdcResult.ADCRESULT15;
   
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE

    if (m_pAdcBuffer == m_pAdcBufferEnd)
    {
        PieCtrlRegs.PIEIER1.bit.INTx1 = 0;
        AdcRegs.INTSEL1N2.bit.INT1E = 0;
        EVENT_ISR_SET_BIT(kSampleDataAvailable);
    }
}

//@} End of Private Methods


//////////////////////////////////////////////////////////////////////
/// @name Public Methods
//@{
#define AQUISITION_PRESCALE 0x3F
void adc_init(void)
{
    int i;
    memset(m_adcBuffer, 0, ADC_BUFFER_SIZE * sizeof(uint16_t));
   
    m_pAdcBufferEnd = m_adcBuffer + ADC_BUFFER_SIZE;
   
    DINT;
    // Setup ADC
    EALLOW;
    AdcRegs.ADCCTL1.bit.ADCREFSEL    = 0;    // Use internal bandgap
    AdcRegs.ADCCTL1.bit.ADCBGPWD    = 1;     // Power up band gap
    AdcRegs.ADCCTL1.bit.ADCREFPWD    = 1;   // Power up reference
    AdcRegs.ADCCTL1.bit.ADCPWDN     = 1;      // Power up rest of ADC
    AdcRegs.ADCCTL1.bit.ADCENABLE    = 1;    // Enable ADC
    for(i=0; i<5000; i++){}                                           // wait 60000 cycles = 1ms (each iteration is 12 cycles)

    AdcRegs.ADCCTL1.bit.INTPULSEPOS    = 1;    // create int pulses 1 cycle prior to output latch
   
    // Configure ADCINT1 to be triggered on ADC0 EOC
    AdcRegs.INTSEL1N2.bit.INT1SEL = 14;        // Select which channel triggers Adc intrerupt
    AdcRegs.INTSEL1N2.bit.INT1CONT = 1;       // Set ADCINT1 to auto clr
    AdcRegs.INTSEL1N2.bit.INT1E = 1;               // Enable ADCINT1

    // set S/H window to 6 clk cycles (117ns)
    AdcRegs.ADCSOC0CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC1CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC2CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC3CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC4CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC5CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC6CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC7CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC8CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC9CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC10CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC11CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC12CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC13CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC14CTL.bit.ACQPS = AQUISITION_PRESCALE;
    AdcRegs.ADCSOC15CTL.bit.ACQPS = AQUISITION_PRESCALE;
    // Configure all SOCs to start at ADC Interrupt 1
    AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC1 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC2 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC3 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC4 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC5 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC6 = 1;
    AdcRegs.ADCINTSOCSEL1.bit.SOC7 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC8 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC9 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC10 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC11 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC12 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC13 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC14 = 1;
    AdcRegs.ADCINTSOCSEL2.bit.SOC15 = 1;
    // Configure all SOCs to convert channel 1
    AdcRegs.ADCSOC0CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC1CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC2CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC3CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC4CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC5CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC6CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC7CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC8CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC9CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC10CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC11CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC12CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC13CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC14CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC15CTL.bit.CHSEL = 1;
   
    PieVectTable.ADCINT1 = &adc_isr;
    EDIS;
   
    // Enable ADCINT1 in PIE
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;        // Enable INT 1.1 in the PIE
    IER |= M_INT1;                                            // Enable CPU Interrupt 1
    EINT;                                                             // Enable Global interrupt INTM
    ERTM;                                                           // Enable Global realtime interrupt DBGM
}

void adc_start()
{
    memset(m_adcBuffer, 0, ADC_BUFFER_SIZE * sizeof(uint16_t));
    m_pAdcBuffer = m_adcBuffer;
   
    EALLOW;
    AdcRegs.ADCSOCFRC1.bit.SOC14 = 1;
    AdcRegs.INTSEL1N2.bit.INT1E = 1;
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
    EDIS;
}

  • Time for an update.

    After some serious doubts about the processor and/or my own competence I figured out the problem. The ISR, adc_isr above, executed from The fact that the default wait state settings for the flash are 15 clks and that the flash pipeline is turned off by default didnt help that much for the speed either.

    Adding the following line made all the difference:

    #pragma CODE_SECTION(adc_isr, "ramfuncs");

    And then copy it to the RAM solved my issue.

    Best regards

    Henrik