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.

Help! I am at my wits end. My code inconsistently operates (somes it will enter an interrupt, sometimes it will not)

Other Parts Discussed in Thread: TMS320F28335

Hello all, I am having a problem with the ezDSP using the TI TMS320f28335. I need to eventually use this to switch up to 2000 Amps in a motor and needless to say it needs to be rock solid. I have set up a test program, where I initialize the chip, setting up the ADC and a timer using the ePWM peripheral. I assign it to my interrupt routine and inside of that I have a variable named test that I simply increment. I am watching that variable in a watch window (real time mode with continuous refresh) and sure enough, when I run the program I see it incrementing. I then stop the program and run it again and this time it never gets updated (it just hangs inside my while(1) loop and never enters the interrupt. Sometimes I change a #define variable (that I am currently not using for this particular test) and recompile and that seems to break it. Other times, it will work 10 times in a row, I will enter a space, then backspace, recompile and it will not work. This problem makes no sense to me. Here is some code, if anyone can see a problem I would greatly appreciate it. Thanks again.


#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "PIController.h"    // Header for PI controller
#include "PWM.h"   // Header for PWM update

// Configure which ePWM timer interrupts are enabled at the PIE level:
#define PWM1_INT_ENABLE  1

// Configure ADC
// ADC start parameters
#define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz

#define ADC_CKPS   0x1   // ADC module clock = HSPCLK/2*ADC_CKPS   = 25.0MHz/(1*2) = 12.5MHz
#define ADC_SHCLK  0xf   // Sample and Hold width in ADC module periods = 16 ADC clocks

#define RM 59 //Measurement Resistor = 59 ohms
#define IV_RATIO 2000.0//1000 to 1 convertsion from current to volts (LEM SENSOR LA55P) * 2
#define VOLT_OFFSET 0.0
#define VOLTSCALE 45.78754579e-6 

interrupt void pwmLoad_isr(void);
PICONTROLLER pi_current_controller = PICONTROLLER_DEFAULTS;
PWMOUT pwm = PWMOUT_DEFAULTS;

//Post Filtered Current Measurements
float current_pre = 0.0;
//Post Filtered Current Measurements
float current_post = 0.0;
//parameter for convex current filter (0<alpha<1)
float alpha = 0.985; 

// Define interrupt frequency (5KhZ control frequency)
const float ISR_frequency = 25000.0; 
float ISR_period = 1.0;   //Initialized in main to 1/ISR_frequency

//Define system clock speed
const float system_frequency = 150000000.0; //150MhZ
float current_ref = 0.0;

int test = 0;
int i;

void main(void){
    ISR_period = 1.0 / ISR_frequency;
   
    // Initialize System Control: PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
    InitSysCtrl();
  
    // Initialize GPIO for eQEP1
    // This function is found in DSP2833x_EQep.c
   //InitEQep1Gpio();
  
   // Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;
    // Initialize the PIE control registers to their default state.
    // This function is found in the DSP2833x_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 DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_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 registers
    PieVectTable.EPWM1_INT = &pwmLoad_isr;
    //PieVectTable.TINT0 = &pwmLoad_isr;
    EDIS;    // This is needed to disable write to EALLOW protected registers
   
    // Enable CPU INT3 which is connected to EPWM1-6 INT:
    IER |= M_INT3;

    // Enable EPWM INTn in the PIE: Group 3 interrupt 1-6
    PieCtrlRegs.PIEIER3.bit.INTx1 = PWM1_INT_ENABLE;

    InitAdc();  // Initalize the ADC

    // Specific ADC setup
    AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
    AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;        // 1  Cascaded mode
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x2;
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // pin2
    AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // pin3
    AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x4; // pin4
    AdcRegs.ADCTRL1.bit.CONT_RUN = 1;       // Setup continuous run
    AdcRegs.ADCTRL2.all = 0x2000;

    // Enable global Interrupts and higher priority real-time debug events:
    EINT;   // Enable Global interrupt INTM
    ERTM;   // Enable Global realtime interrupt DBGM
  
    EALLOW;
    //Configure pin to drive transistor
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // Use as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // Configure as Output
    EDIS;
   
    //INITIALIZE CONTROLLER
    pi_current_controller.Kp = .1;
    pi_current_controller.DeltaTime = ISR_period;
    pi_current_controller.Ki = .05;
    pi_current_controller.Kc = 0.001;
    pi_current_controller.Kd = .005;
    pi_current_controller.OutMax = 1;  //Limit between zero and one for PWM duty cycle control
    pi_current_controller.OutMin = 0;
    pi_current_controller.Ref = 0.0;
    pi_current_controller.Feedbk = 0.0;
   
    //INITIALIZE PWM
    pwm.PeriodClock = system_frequency / (10*ISR_frequency);//10*ISR_frequency; //make PWM 10X faster than control frequency;
    pwm.init(&pwm);
   
    for(;;){

    //sit and wait for interrupt}

    }
}
// Main FOC loop
interrupt void pwmLoad_isr(void)
{
   
       

    while (AdcRegs.ADCST.bit.INT_SEQ1== 0) {} // Wait for interrupt
    //current_pre = ((float)(AdcRegs.ADCRESULT0)*VOLTSCALE);
    current_pre = (((float)(AdcRegs.ADCRESULT0)*VOLTSCALE) - VOLT_OFFSET)*IV_RATIO/RM;
    current_post = alpha * current_post + (1.0-alpha)*current_pre;       
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
    test++;
   
    current_ref = 1.0; //Set desired current to 1.0 Amps
       pi_current_controller.Ref = -1.0*current_ref;
    pi_current_controller.Feedbk = -1.0*current_post;
    //pi_current_controller.calc(&pi_current_controller);
        pi_current_controller.Output=0.1;//manual duty cycle overide for testing

        pwm.Da = pi_current_controller.Output;
    pwm.Db = 0.0;
    pwm.Dc = 0.0;
 
    pwm.update(&pwm);
   
   
    // Clear INT flag for this timer
    EPwm1Regs.ETCLR.bit.INT = 1;

    // Acknowledge this interrupt to receive more interrupts from group 3
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}   


  • I think this has to do with the ADC both continous run(CONT_RUN) and ADC Interrupt flag, being in an undefined state when you perform a debug RESET.  Since the ADC is continously running, it could be setting the interrupt flag after you clear it but before the reset is issued.  When you get back into your code, the flag is still set, and you never get another interrupt again(PIE is edge detect). 

    I think all you should have to do is a dummy interrupt clear in your setup to remove any old flags.  The other item at play is CONT_RUN which will continue to fire ADC SOCs up until the reset occurs(I beleive debugger reset disables the ADC clock). 

    The easiest way to make sure everything is steady state is to issue an ADC_RESET via bit 14 in ADCTRL1 register.  On this device you'll want to make sure you do this prior to the ADC_cal() function call, since it will reset these values as well and the ADC results will be out of spec without the calibration value being loaded.

    Hopefully I haven't missed something in your code, but I think the main cluprit is the flag staying set.  On a system running infinitely this wouldn't be an issue, i.e. from a power on reset everything in the ADC is in the init state; only when the debugger comes into play will certain bits not get reset the same way.

    Best,

    Matthew

  • I have tried adding a reset to my InitAdc  function with no luck. I am posting my function below. Should I not be using CONT_RUN?  I just tried running it after the chip was freshly powered up and it didnt work right off the bat. Any other ideas would be greatly appreciated.

     

    // TI File $Revision: /main/5 $
    // Checkin $Date: October 23, 2007   13:34:09 $
    //###########################################################################
    //
    // FILE:    DSP2833x_Adc.c
    //
    // TITLE:    DSP2833x ADC Initialization & Support Functions.
    //
    //###########################################################################
    // $TI Release: DSP2833x/DSP2823x C/C++ Header Files V1.31 $
    // $Release Date: August 4, 2009 $
    //###########################################################################

    #include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
    #include "DSP2833x_Examples.h"   // DSP2833x Examples Include File

    #define ADC_usDELAY  5000L

    //---------------------------------------------------------------------------
    // InitAdc:
    //---------------------------------------------------------------------------
    // This function initializes ADC to a known state.
    //
    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.

            EALLOW;
            SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
            AdcRegs.ADCTRL1.bit.RESET = 1;    //Here is what I added //
            ADC_cal();
            EDIS;




        // To powerup the ADC the ADCENCLK bit should be set first to enable
        // clocks, followed by powering up the bandgap, reference circuitry, and ADC core.
        // Before the first conversion is performed a 5ms delay must be observed
        // after power up to give all analog circuits time to power up and settle

        // Please note that for the delay function below to operate correctly the
        // CPU_RATE define statement in the DSP2833x_Examples.h file must
        // contain the correct CPU clock period in nanoseconds.

        AdcRegs.ADCTRL3.all = 0x00E0;  // Power up bandgap/reference/ADC circuits
        DELAY_US(ADC_usDELAY);         // Delay before converting ADC channels
    }

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

  • Anyone else have any ideas? I have hacked the solution by using cpu timers instead of the interrupt generated by EPWM1, but this will not work for me as I am trying to implement  space vector modulation and I need the PWM interrupt to signal when to compute a new input. So far my experience with the eZdsp is that it is really unstable. Has anyone else had similar experiences? Thanks

  • Hi gideon,

    Not sure if it helps, but it might be possible that this could be in some way related to optimization. Optimizations are known to result in unstable codes. Maybe going into the disassembly window and checking out the performance of the interrupt and ADC-reset sections of your code might help. Its just a hunch though.

    Thanks and Regards,

    Sid