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 Problem



Hi folks,

I'm working on a flash application and I dealing with an ADC conversion problem. Every time I download a program into the target flash memory (using the CCS On chip flash programmer), and we make it runs, the ADC conversions seems to be ok. But If I stop the program, reset the target and makes it run again, the ADC conversions fail. The ADC_cal() function is invoked in the application. On the other hand, if I restart the program (Debug-->Restart), the ADC conversions are always good. I don´t really know why the ADC has this strange behavior.

Any ideas?
Thank you in advance.

Sergio

  • Are you resetting target hardware when JTAG is connected?

  • Bhaskar,

    Yes, the emulator is normally connected.

    Regards,

    Sergio.

  • Sergio,

    Can you check the values in the REFSEL register(even the reserved space in this register) and OFFTRIM registers after the ADC_cal() function runs in both the passing and failing conditions?  I suspect that we are not transferring the values over to the ADC properly in the bad case.  I beleive that the function is in protected region, but since this is a function call into the region, even if the CSM is locked this shouldn't be an issue.

    You may want to remove any GEL files you have open, since there is ADC_cal() autoload that is performed on almost every OnConnect, Reset, Reload type action.  This may be clouding the picture as to what is actually loading the ADC and at what time when the emulator/CCS is active.

    Best,

    Matthew

  • Matthew,

    I have already checked the REFSEL and the OFFTRIM registers and they have the same values in both conditions. (the passing and failing conditions). I removed the gel file from the project and nothing changed.

    On the other hand my application is  flash based. So, it can run stand alone with no Emulator/CCS interaction. I have verified the ACD conversions via a communication interfase and I could see that the conversions are not always the same when applying the same voltage input.

    Regards,

    Sergio

  • If these values are the same then there must be a setup issue at play.  The ADC requires some start up time after power up before using; 5ms must be observed between power up and ADC conversion.  I just trying to isolate anything may be done statically by the debugger that is helping you application code in the background.  If your source is identical to the example code provided in the header files(at least for the setup and power up); then there should be no difference.

    Perhaps also worth looking to make sure the register settings are consistent in both cases, including HSPCLK divider in the SYSCTRL regs, since this sets the clock that is fed to the ADC.

    Would it be possible to post passing and failing data, to get an idea of the delta between good/bad?

    Best,
    Matthew

  • Matthew,

    Here is my ADC config file.

    ....

    #define ADC_usDELAY  10000L

    ....

    void InitAdc(void)
    {
        extern void DSP28x_usDelay(Uint32 Count);


        // *IMPORTANT*
     // The ADC_cal function, which  copies the ADC calibration values from TI reserved
     // OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the
     // Boot ROM. If the boot ROM code is bypassed during the debug process, the
     // following function MUST be called for the ADC to function according
     // to specification. The clocks to the ADC MUST be enabled before calling this
     // function.
     // See the device data manual and/or the ADC Reference
     // Manual for more information.

     ///////////////////////////////////////////////////////
     AdcRegs.ADCTRL1.bit.RESET = 1;       // Reset the ADC //
     asm(" RPT #22 || NOP");              // Must for ADC reset to take effect //

     DELAY_US(ADC_usDELAY);

     EALLOW;
      SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
      ADC_cal();
        EDIS;
     

        AdcRegs.ADCTRL3.bit.ADCBGRFDN = 0x3;  // Power up bandgap/reference circuitry
     DELAY_US(ADC_usDELAY);         // Delay before powering up rest of ADC
     DELAY_US(ADC_usDELAY);         // Delay before powering up rest of ADC

        AdcRegs.ADCTRL3.bit.ADCPWDN = 1;      // Power up rest of ADC
     DELAY_US(ADC_usDELAY); 
     DELAY_US(ADC_usDELAY);         // Delay before powering up rest of ADC
         

     AdcRegs.ADCREFSEL.bit.REF_SEL=0; 
     DELAY_US(ADC_usDELAY);         // Delay before powering up rest of ADC 

     AdcRegs.ADCTRL3.bit.ADCCLKPS= 4;//0;   // ADCCLK=25Mhz


     //----------------------------------------------------------------------
     // ADC is configurred for either sequential or simultaneous mode of
     // conversion:
     //
     // SEQUENTIAL:   ADC channels are converted one at a time:
     //               A0->A1->A2->...B0->B1->B2->....
     //
     // SIMULTANEOUS: ADC channels are converted in pairs:
     //               A0->A1->A2->....
     //               B0  B1  B2
     //
     // The mapping of the ADC channel pins to ADC result registers for
     // sequnetial or simultaneous mode is given below:
     //
     // SEQUENTIAL:   ADC channels are converted one at a time:
     //               A0 -> ADCRESULT0
     //               A1 -> ADCRESULT1
     //               A2 -> ADCRESULT2
     //               A3 -> ADCRESULT3
     //               A4 -> ADCRESULT4
     //               A5 -> ADCRESULT5
     //               A6 -> ADCRESULT6
     //               A7 -> ADCRESULT7
     //               B0 -> ADCRESULT8
     //               B1 -> ADCRESULT9
     //               B2 -> ADCRESULT10
     //               B3 -> ADCRESULT11
     //               B4 -> ADCRESULT12
     //               B5 -> ADCRESULT13
     //               B6 -> ADCRESULT14
     //               B7 -> ADCRESULT15
     //
     // SIMULTANEOUS: ADC channels are converted in pairs:
     //               A0 -> ADCRESULT0
     //               A1 -> ADCRESULT2
     //               A2 -> ADCRESULT4
     //               A3 -> ADCRESULT6
     //               A4 -> ADCRESULT8
     //               A5 -> ADCRESULT10
     //               A6 -> ADCRESULT12
     //               A7 -> ADCRESULT14
     //               B0 -> ADCRESULT1
     //               B1 -> ADCRESULT3
     //               B2 -> ADCRESULT5
     //               B3 -> ADCRESULT7
     //               B4 -> ADCRESULT9
     //               B5 -> ADCRESULT11
     //               B6 -> ADCRESULT13
     //               B7 -> ADCRESULT15
     //

     #if ADC_SAMPLING_MODE == SIMULTANEOUS
     AdcRegs.ADCTRL3.bit.SMODE_SEL = 1;
        AdcRegs.ADCMAXCONV.all = 7;         
     #endif

     #if ADC_SAMPLING_MODE == SEQUENTIAL
     AdcRegs.ADCTRL3.bit.SMODE_SEL = 0;
        AdcRegs.ADCMAXCONV.all = 15;      
        #endif 


        AdcRegs.ADCCHSELSEQ1.all= 0x3210;
        AdcRegs.ADCCHSELSEQ2.all= 0x7654;
        AdcRegs.ADCCHSELSEQ3.all= 0xba98;
        AdcRegs.ADCCHSELSEQ4.all= 0xfedc;

     
     //////////////////////////////////////////////////////
        AdcRegs.ADCTRL1.bit.RESET = 0x0;            /* bit14(0): RESET, 0=no action, 1=reset ADC */
        AdcRegs.ADCTRL1.bit.SUSMOD = 0x00;      /* bit13-12(00): emulation suspend is ignored */
        AdcRegs.ADCTRL1.bit.ACQ_PS = 0xF;//0x0;//0x07;       /* bit11-8(0111): ACQ_PS (Acquisition), 0100 = 5 x ADCCLK */
        AdcRegs.ADCTRL1.bit.CPS = 0x0;                 /* bit7(0): CPS (Core clock), 0: ADCCLK=FCLK/1, 1: ADCCLK=FCLK/2 */
        AdcRegs.ADCTRL1.bit.CONT_RUN = 0x0;   /* bit6(0): CONT_RUN, 0=start/stop mode, 1=continuous run */
        AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0x0;    /* bit5(0): SEQ_OVRD, 0=disabled, 1=enabled */
        AdcRegs.ADCTRL1.bit.SEQ_CASC = 0x1;    /* bit4(1): SEQ_CASC, 0=dual sequencer, 1=cascaded sequencer */
     ///////////////////////////////////////////////////////

        AdcRegs.ADCTRL2.all = 0x0000;

        /* bit 15        0:      ePWM_SOCB_SEQ, 0=no action */
        /* bit 14        0:      RST_SEQ1, 0=no action */
        /* bit 13        0:      SOC_SEQ1, 0=clear any pending SOCs */
        /* bit 12        0:      reserved */
        /* bit 11        0:      INT_ENA_SEQ1, 1=enable interrupt */
        /* bit 10        0:      INT_MOD_SEQ1, 0=int on every SEQ1 conv */
        /* bit 9         0:      reserved */
        /* bit 8         0:      ePWM_SOCA_SEQ1, 1=SEQ1 start from ePWM_SOCA trigger */
        /* bit 7         0:      EXT_SOC_SEQ1, 1=SEQ1 start from ADCSOC pin */
        /* bit 6         0:      RST_SEQ2, 0=no action */
        /* bit 5         0:      SOC_SEQ2, no effect in cascaded mode */
        /* bit 4         0:      reserved */
        /* bit 3         0:      INT_ENA_SEQ2, 0=int disabled */
        /* bit 2         0:      INT_MOD_SEQ2, 0=int on every other SEQ2 conv */
        /* bit 1         0:      reserved */
        /* bit 0         0:      ePWM_SOCB_SEQ2, 0=no action */


        AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;  // Enable EVASOC to start SEQ1
        AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;  // Enable SEQ1 interrupt (every EOS) 

     //

    }

    //===========================================================================
    // End of file.
    //===========================================================================

    And this is the HSPCLK config...

    void InitPeripheralClocks(void)
    {
       EALLOW;

    // HISPCP/LOSPCP prescale register settings, normally it will be set to default values
       SysCtrlRegs.HISPCP.all = 0x0000;//0x0003;// /*(150 MHz)*/ //0x0001 (75MHz);
    ...

    The mean values of each channel in both cases.

    // Good conversions
    channel_offset.CH_1=2046;
    channel_offset.CH_2= 2041;
    channel_offset.CH_3= 2041;

    channel_offset.CH_4= 3;
    channel_offset.CH_5=3;
    channel_offset.CH_6= 2041;
    channel_offset.CH_7= 2041;
    channel_offset.CH_8 =2041;
    channel_offset.CH_9=6;
    channel_offset.CH_10=8;
    channel_offset.CH_11=8;
    channel_offset.CH_12 =2046;
    channel_offset.CH_13=2045;
    channel_offset.CH_14= 2047;
    channel_offset.CH_15=2048;
    channel_offset.CH_16=7;

    //Bad conversions

    channel_offset.CH_1=2043; 
    channel_offset.CH_2=2052;
    channel_offset.CH_3=2050;
    channel_offset.CH_4=4;
    channel_offset.CH_5=5;
    channel_offset.CH_6=2057;
    channel_offset.CH_7=2070;
    channel_offset.CH_8=2084;
    channel_offset.CH_9=52;
    channel_offset.CH_10=80;
    channel_offset.CH_11= 88;
    channel_offset.CH_12=2131;
    channel_offset.CH_13= 2129;
    channel_offset.CH_14= 2132;
    channel_offset.CH_15=2142;
    channel_offset.CH_16= 97;

    // Bad conversions (another start up)

    channel_offset.CH_1=2002;
    channel_offset.CH_2= 1990;
    channel_offset.CH_3= 1987;
    channel_offset.CH_4= 0;
    channel_offset.CH_5=0;
    channel_offset.CH_6=001;
    channel_offset.CH7=010;
    channel_offset.CH_8= 2010;
    channel_offset.CH_9= 0;
    channel_offset.CH_10= 0;
    channel_offset.CH_11=0;
    channel_offset.CH_12= 1996;
    channel_offset.CH_13= 1987;
    channel_offset.CH_14=1984;
    channel_offset.CH_15=1990;
    channel_offset.CH_16= 0;
    ...

    Best,

    Regards

  • Sergio,

    I've been focusing on any delta from each setup in the literal sense; but could there be something else in the overall system that would behave in a different way under each condition?  Some of the conversions are so far off, it almost seems like there is some system noise at play when the sample occurs for those channels, because on different channels the data is quite close to the "good" value.

    Any thoughts on the above? 

    Your setup looks OK BTW, ADC is running at 18.75MHz clock which is in the spec box. 

    Best,

    Matthew 

  • Matthew,

    I get your point. But, It is very strange that the conversions get better with a restart condition, so I´m not thinking of noise .

    On the other hand, if you take a look at the "bad conversions"  on the previous email channels CH1-Ch8 are relatively close to the good case (but CH9-CH16 are pretty far), but on the second start up, all the channels are so far off.

    Could it be a problem with the F28335´s ADC themself or their internal references?. I mean, some not reported issue. I am using the revision ID A ( which is the earliest TMS hardware revision).

    Best,

    Sergio.

  • Matthew,

    I changed the ADC clock in order it run at 25MHz. I changed:

    SysCtrlRegs.HISPCP.all = 0x0003, in InitPeripheralClocks(), and

     AdcRegs.ADCTRL3.bit.ADCCLKPS= 0; in InitAdc().

    I tested these changes over a project which doesn´t use PWM and the ADC seems to convert rigth, even the DC values.

    The project which I have problem uses PWM. (This project has differents dc values, at differents resets) Could it be some kind of PWM configuration problem?

    Best,

    Sergio.

  • Sergio,

    When you have a problem are the physical PWM pins connected to something, i.e. FET, etc?  I would then start to suspect some type of noise from the switching is getting coupled back into the analog signal prior to it entering the device.  Or are we in an undefined state at reset and there is something driving externally that shouldn't?

     

    Best,

    Matthew

  • Matthtew,

    Actually, there are nothing connected to the physical PWM pins. Then there is no switching at play. I am starting to think of a problem with the ADC sequencers ( remember I'm using cascaded mode) and the SOC trigger source, but I can figure out what the problem could be.

     I have configurated the SOC trigger in order it generate an interrupt a fixed number of counts after a CTR=0 and after CTR=TBPRD.  My config is:

       main(){

       ....

       /////////////////////////
       InitAdc(); // The previuos e mail init
       /////////////////////////
       ///////////////
       InitEPwm(); 
       ...

      // Configure ADC SOC trigger
       EPwm1Regs.ETSEL.bit.SOCAEN = 1;     // Enable SOC on A group
       EPwm1Regs.CMPB = EPwm1Regs.TBPRD - adc_SOC_delay;                 //EPwm1Regs.TBPRD= 21739,  adc_SOC_delay=12000
       EPwm1Regs.ETSEL.bit.SOCASEL = 7;   // Select SOC CTR=CMPB DEC
       EPwm1Regs.ETPS.bit.SOCAPRD = 1;    // Generate pulse on 1st event

       PieCtrlRegs.PIEACK.bit.ACK1= 1;      // Estoy listo para Atender Interrupcion desde el ADC
       IER |= M_INT1;    // Enable CPU INT1 which is connected to CPU-Timer 0
       IER |= M_INT9; // Enable CPU INT9 which is connected to SCI
       IER |= M_INT13; // Enable CPU INT13 which is connected to CPU-Timer 1

       // Enable global Interrupts and higher priority real-time debug events:
       EINT;   // Enable Global interrupt INTM
       ERTM;   // Enable Global realtime interrupt DBGM

       ....

      while(1);

    Later in the ADC interrupt routine...

    interrupt void adc_isr(void)
    {

      channel.CH_1= ((AdcRegs.ADCRESULT0)>>4)- channel_offset.CH_1;    // A0
      channel.CH_2= ((AdcRegs.ADCRESULT2)>>4)- channel_offset.CH_2;    // A1
      channel.CH_3= ((AdcRegs.ADCRESULT4)>>4)- channel_offset.CH_3;    // A2
      channel.CH_4= ((AdcRegs.ADCRESULT6)>>4);          // A3
      channel.CH_5= ((AdcRegs.ADCRESULT8)>>4);       // A4
      channel.CH_6= ((AdcRegs.ADCRESULT10)>>4)- channel_offset.CH_6;   // A5
      channel.CH_7= ((AdcRegs.ADCRESULT12)>>4)- channel_offset.CH_7;   // A6
      channel.CH_8= ((AdcRegs.ADCRESULT14)>>4)- channel_offset.CH_8;   // A7
      channel.CH_9= ((AdcRegs.ADCRESULT1)>>4);       // B0
      channel.CH_10= ((AdcRegs.ADCRESULT3)>>4);       // B1
      channel.CH_11= ((AdcRegs.ADCRESULT5)>>4);       // B2
      channel.CH_12= ((AdcRegs.ADCRESULT7)>>4)- channel_offset.CH_12;  // B3
      channel.CH_13= ((AdcRegs.ADCRESULT9)>>4)- channel_offset.CH_13;  // B4
      channel.CH_14= ((AdcRegs.ADCRESULT11)>>4)- channel_offset.CH_14; // B5
      channel.CH_15= ((AdcRegs.ADCRESULT13)>>4)- channel_offset.CH_15; // B6
      channel.CH_16= ((AdcRegs.ADCRESULT15)>>4);       // B7
     //
     
     if(EPwm1Regs.ETSEL.bit.SOCASEL==7)
     {//
            EPwm1Regs.CMPB = adc_SOC_delay;
            EPwm1Regs.ETSEL.bit.SOCASEL = 6;  // Select SOC CTR=CMPB INC
      
      }
     else
     {// CTR=0

          EPwm1Regs.CMPB = EPwm1Regs.TBPRD - adc_SOC_delay;
          EPwm1Regs.ETSEL.bit.SOCASEL = 7;  // Select SOC CTR=CMPB DEC
     }

    ....

       // Reinitialize for next ADC sequence
        AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;         // Reset SEQ1
        AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;       // Clear INT SEQ1 bit
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE
    }

    If you believe it useful I can send you the InitEPwm() function content.

    Best,

    Sergio

  • Matthew,

    Did you recieve my last post? I still haven't found what the problem is and I really need further assistance.

    Thank you in advance for your cooperation.

    Best.

    Sergio

  • Sergio,

    Can we try removing the ePWMs from the equation and see what happens?  Just use the SW start of conversion, you could call this from an ISR that is triggered off PWM event to maintain similar timings if needed.

    Can you also advise if you are using simultaneous mode or sequential?  I see a compiler option for this but didn't see the control var.

    Best,

    Matthew