Electronic – Understanding ADC – TMS32F28027

adc

I am new to microcontrollers. I modified the Adc_Soc Example, such that CPU Timer 0 triggers ADCINA7. CPU Timer 0 is configured with 60MHz and period is 2 seconds. Also I increment a variable(LoopCount) inside adc_isr.

My doubt is, if I am triggering the SOC8 with CPU Timer 0 for every 2 seconds, then the variable(LoopCount) should increment every two seconds. But here it increases rapidly in 1000s within a second. Why is it so? And please correct me if I am wrong.

Edit 1 : Instead of declaring and defining the Interrupt _isr in the main.c, I used the f2802x_defaultisr.c and now the ADC register value is updated every 2 seconds. But still I don't know where I went wrong with the previous code(interrupt_isr in main.c). Please help me.

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
// Prototype statements for functions found within this file.
interrupt void adc_isr(void);
//interrupt void cputimer0_isr(void);
void Adc_Config(void);

// Global variables used in this example:
volatile uint16_t Voltage;
uint16_t LoopCount;


main()
{

    // WARNING: Always ensure you call memcpy before running any functions from RAM
// InitSysCtrl includes a call to a RAM based function and without a call to
// memcpy first, the processor will go "into the weeds"
#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif

Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2803x_SysCtrl.c file.
InitSysCtrl();


// Step 2. Initialize GPIO:
// This example function is found in the f2802x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
   InitGpio();  // Skipped for this example

// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
   DINT;

// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the f2802x_PieCtrl.c file.
   InitPieCtrl();

// Disable CPU interrupts and clear all CPU interrupt flags:
   IER = 0x0000;
   IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in f2802x_DefaultIsr.c.
// This function is found in f2802x_PieVect.c.
   InitPieVectTable();

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;  // This is needed to write to EALLOW protected register
   PieVectTable.ADCINT1 = &adc_isr;
//   PieVectTable.TINT0 = &cputimer0_isr;
   EDIS;    // This is needed to disable write to EALLOW protected registers

// Step 4. Initialize all the Device Peripherals:
// This function is found in f2802x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
   ConfigCpuTimer(&CpuTimer0, 60, 2000000);
   CpuTimer0Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
   InitAdc();  // For this example, init the ADC

// Step 5. User specific code, enable interrupts:

// Enable ADCINT1 & CPUTIMER0 in PIE
   PieCtrlRegs.PIEIER1.bit.INTx1 = 1;   // Enable INT 1.1 in the PIE
   PieCtrlRegs.PIEIER1.bit.INTx7 = 1;   // PIE Group 1 Vector INT1.7 --> CPU Timer 0

   IER |= M_INT1;                       // Enable CPU         Interrupt 1
   EINT;                                // Enable Global     interrupt INTM
   ERTM;                                // Enable Global     realtime interrupt DBGM

   LoopCount = 0;

// Configure ADC

//Note: Channel ADCINA4  will be double sampled to workaround the ADC 1st sample issue for rev0 silicon errata  

EALLOW;
AdcRegs.SOCPRICTL.bit.SOCPRIORITY = 0;  // SOC Priority is handled in round robin mode
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;    //ADCINT1 trips after AdcResults latch
AdcRegs.INTSEL1N2.bit.INT1E     = 1;    //Enabled ADCINT1
AdcRegs.INTSEL1N2.bit.INT1CONT  = 0;    //Disable ADCINT1 Continuous mode
AdcRegs.INTSEL1N2.bit.INT1SEL   = 8;    //setup EOC8 to trigger ADCINT1 to fire
AdcRegs.ADCSOC8CTL.bit.CHSEL    = 7;    //set SOC8 channel select to ADCINA7
AdcRegs.ADCSOC8CTL.bit.TRIGSEL  = 1;    //set SOC8 start trigger on CPUTIMER0
AdcRegs.ADCSOC8CTL.bit.ACQPS    = 6;    //set SOC8 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0;
GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1;

EDIS;

// Wait for ADC interrupt
    while(1)
    {}

}
interrupt void  adc_isr(void)
{

  Voltage = AdcResult.ADCRESULT8;  //discard ADCRESULT0 as part of the workaround to the 1st sample errata for rev0
  GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;
  AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;     //Clear ADCINT1 flag reinitialize for next SOC
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE

  LoopCount++;
  if(LoopCount == 38000)
  {
      LoopCount = 0;
  }
  return;
}

Best Answer

1) Your code (as you presented it here right now) doesn't work. You initialized and enabled CpuTimer0 interrupt but you haven't mapped it to any ISR, hence it will fall to the default ISR that can be found in f2802_defaultisr.c source file and will stuck there forever (by default there is infinite for loop).

You enabled CpuTimer interrupt in this line:

CpuTimer0Regs.TCR.all = 0x4001;

As you are using CpuTimer, together with ADC, that means you should also read the manual that deals with Cpu timer and with appropriate registers. Here is the link (page 62, just a couple of pages).

2) You have that many ADC interrupts because you haven't configured the timer (the very main issue). This line of code actually does nothing:

ConfigCpuTimer(&CpuTimer0, 60, 2000000);

And you haven't initialized CpuTimer0! At the moment it's a simple pointer that points to a random location. Meaning you are also writing 2000000 to some random location. To initialize it you should run the following function before calling ConfigCpuTimer:

InitCpuTimers();        // initialize Cpu Timers

Afterwards, CpuTimer0 will actually point to the real peripheral register. To learn more, you might wanna look into Cpu_Timer example. Or you could also write your own initialization procedure. That's a piece of cake.

3) Do all your peripheral initialization steps before (!!!) you enable interrupts:

  EINT;  // Enable Global     interrupt INTM

Otherwise it can be a great source of bugs.

4) For specific questions, regarding C2000 MCU family, it's much better to ask them on TI forum directly. There are lots of TI experts that are ready to help you with any specific question.