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.

software forced SOC F28027

I am unable to get the ADC engine to respond to the line:

 AdcRegs.ADCSOCFRC1.all = 0x007F; // 7 ADC conversions, SOC0 -> SOC6

While running from my large program in flash. However, the same intialization (shown here)

// *****************************************************************************
void ConfigureADCSampling(){                // Configure ADC
 EALLOW;
 SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
 (*Device_cal)();
 EDIS;
 EALLOW;
 AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;    //ADCINT1 trips after AdcResults latch
 AdcRegs.ADCCTL1.bit.ADCREFSEL   = 0;    // use internal bandgap reference
 AdcRegs.ADCCTL1.bit.ADCREFPWD   = 1;    // power up reference
 AdcRegs.ADCCTL1.bit.ADCBGPWD    = 1;    // power up band gap
 AdcRegs.ADCCTL1.bit.ADCPWDN     = 1;    // power up ADC
 AdcRegs.ADCCTL1.bit.ADCENABLE   = 1;    // enable ADC
 AdcRegs.ADCSOC0CTL.all          = 0x000E; // ADCINA0, pin10, Synthesizer_5p2
 AdcRegs.ADCSOC1CTL.all          = 0x004E; // ADCINA1,  pin8, UltraCap_Float
 AdcRegs.ADCSOC2CTL.all          = 0x00CE; // ADCINA3,  pin7, Panel_Temp
 AdcRegs.ADCSOC3CTL.all          = 0x01CE; // ADCINA7,  pin6, Outside_Temp
 
 AdcRegs.ADCSOC4CTL.all         = 0x02CE; // ADCINB3, Battery_Bus
 AdcRegs.ADCSOC5CTL.all         = 0x02CE; // ADCINB3, Battery_Bus
 AdcRegs.ADCSOC6CTL.all         = 0x03CE; // ADCINB7, Ambient_Light

 EDIS;
}
// ****************************************************************************

When running from RAM in the following code snippet

// Enable CPU_Timer 1 in PIE
   PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable PIE block
   IER |= M_INT13;       // Enable CPU Interrupt 13, CPU_Timer 1
   EINT;                // Enable Global interrupt INTM
   ERTM;                // Enable Global realtime interrupt DBGM

   LoopCount = 0;
   ConversionCount = 0;

// Wait for Timer interrupt to increment count
 for(;;) {
   LoopCount++;
      if(CpuTimer1.InterruptCount != InterruptCount_old){
         EALLOW;
            AdcRegs.SOCPRICTL.all  = 0x0400;   // reset round robin pointer to 32
         EDIS;
         AdcRegs.ADCSOCFRC1.all = 0x007F;   // 7 ADC conversions, SOC0 -> SOC6

         InterruptCount_old = CpuTimer1.InterruptCount;
     }
 }
} // close main
// *******************************************************************

The ADC responds to the software forced SOC and result are visible in the results registers. The timer1 interrupt

routine simply increments a counter that's tested in the for(;;) loop to detemine if a ADC "refresh" is needed.

The logic is esentually the same in the larger program, but try as I might, I am unable to kick off a conversion sequence.

Thinking this might have something to do with the location of RAM versus ROM, I created a "ramfunc" ADC kickoff function

// *******************************************************************
void ADC_StartConv(){     // declared ramfunc
  EALLOW;
 AdcRegs.SOCPRICTL.all = 0x0400; // reset round robin pointer to 32
  EDIS;
 AdcRegs.ADCSOCFRC1.all = 0x007F; // 7 ADC conversions, SOC0 -> SOC
}
// ******************************************************************

that is called from the ROM code. No joy, still refuses to start.

I am stumped. Can anyone suggest a solution to this? PLEASE, PLEASE, PLEASE!

DE

 

  • David,

    To help isolate the problem, do any of the ADC status registers reflect any activity after the ADCSOCFRC is set?  For example, ADCCTL1[ADCBSY], ADCSOCFLG, or ADCSOCOVF?

    Are you able to confirm that the TIMER interrupts are being triggered properly?

    Would you be able to add writes to unused ADCSOCxCTL registers just before and after the ADCSOCFRC write?  If the program is having trouble writing to ADCSOCFRC, I would expect that it will not be able to write to ADCSOCxCTL either because they are in the same memory space.

    -Tommy

  • Tommy, the ADC never "wakes up", the SOCPRICTL register still holds 0x20 in the RPOINTER field--the reset value. I see no change in any other ADC registers.

    In the case of the RAM code, the timer1 interrupt increments a count which is tested in the for(;;) loop. For the ROM code, an interrupt (XINT2) detecting changes on the encoder wheels (and pushbutton) returns a number that is tested in a <switch> statement in the main thread. For both programs the interrupts are behaving as expected. In both cases, the ADCSOCxCTL registers are initialized as expected, but I hadn't tried writing them after the problem appeared in the ROM program--but I will give it a try.

    DE

  • Am I correct in understanding that CPU writes to the ADC registers are not successful when the ADC clock is enabled and EALLOW is set when needed?

    Is it possible to halt your program execution from flash during the timer for() loop and manually poke at the ADC registers through the debugger?

  • TLee, In my init routine, the lines:

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

    are use to allow clocking of the ADC module and set the calibration. I then proceed to set the SOCxCTL registers for 7 start-of-conversion readings. HOWEVER, subsequent writes to un-used SOCxCTL registers are ignored--both in my code and from within the debugger. From prompting in your email, I took a look at SysCtrlRegs.PCLKCR0 and saw a value of 0x0515--bit 3, the ADC clock enable bit was NOT set. Poking 0x051D into this register allow me to manipulate register values within the ADC.

    So the question now becomes, how did that bit get cleared?

    bit-10 is set (SCI_A clock enable), but I'm not using this section. bit-8 is set (SPI-A clock enable), but I'm not using this section. bit-4 is set (I2C clock enable), but I'm not using this section. bit-0 is set (HRPWM clock enable), but I'm not using this section. Upon examination, these bits are set by the call to the TI routine InitSysCtrl() in my main_init.c code. I see the ADCENCLK bit set repeatedly within InitSysCtrl() and later set in my ConfigureADCSampling() and set once more in my comparator_init() routine. It should be set.

    I'm wondering now if the problem is the read-modify-write sequence needed to manipulate individual bits within a register.

    I've been spinning my wheels on this problem for some time. I think it's time to make a rule not to use .bit. notation with any code written for the C2000 controllers . . .

    Your thoughts?

  • Joe, thanks for the input, but I think the problem stems from a "spontaneous" clearing of the ADC's clock enable bit. See my previous post to TLee.

  • David,

    Can you try to set a hardware watchpoint for writes to PCLKCR0?  Hopefully this will help isolate the write that clears the ADCENCLK bit.

    I have heard people speak of concerns and complications when using read-modify-write bit operations, but I personally have not had any problems with them in my code.

    -Tommy

  • Tommy, your suggestion to try a watchpoint did the trick. Afte some fumbling on the watchpoint syntax, I was able to set the watchpoint and found that the TI routine void flash_main(void) would set the ADCENCLK bit in SysCtrlReg.PCLKCR0 to allow (*Device_cal)() to execute and THEN CLEAR THE BIT. Unfortunately, as I developed the code and tacked on additional functionality, this was the last access to the ADCENCLK bit.

    flash_main() is found in Flash2802x_API_main.c.

    DE

  • David,

    I'm glad that you were able to resolve the issue.  Sounds like it was not intuitive for the function to modify the ADC clock.  I'll try to look into the history of this.

    -Tommy

  • Tommy, I'm still having trouble with the read-modify-write setting of I/O bits on the F28027. The easiest workaround is to simple write the bits twice. With that, the changes to the I/O pins hold their desired value--the values "stick". Without the change, the pins with change briefly and revert to the previous value. For example the routine below behaves only with double writes. After several variations, I decided to double up the writes everywhere.

    My .h file has the variables defined as:

    #define     NHD_RS        GpioDataRegs.AIODAT.bit.AIO10

    #define     NHD_RWn     GpioDataRegs.AIODAT.bit.AIO12

    #define     NHD_E           GpioDataRegs.AIODAT.bit.AIO14

    // =========================================================

    void NHD_W_and_E(int type){
       // instrument code using XMT_Key, 04sep12
       GpioDataRegs.GPADAT.bit.GPIO28 = 1; // output high, XMT_Key
       DELAY_US(40); // delay 40us
       // flaky I/O, do it twice
       NHD_RS = type; data NHD_RS = type; // RS--register select, 0 => command, 1=> data
       NHD_RWn = 0;    NHD_RWn = 0;  // we're writing
       Bus_Drive();      // output previously set 8-bits
       NHD_E = 1; NHD_E = 1;  // enable high, active high
       DELAY_US(2); // delay 2us
       NHD_E = 0; NHD_E = 0;  // enable low, idle low
       NHD_RS = 0; NHD_RS = 0;  // idle low,
       GpioDataRegs.GPADAT.bit.GPIO28 = 0; // output low, XMT_Key
    }
    // =========================================================

    DE

     

  • David,

    Have you tried using the AIOSET, AIOCLEAR, and AIOTOGGLE registers?  Writes to these registers tend to be more robust when updating individual GPIO bits.  I think GPIO Data registers are a special case because the bits are used for both control and status.

    -Tommy