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.

[ Config and Start CPU-Timer of DSP TMS320F28335 ]

Other Parts Discussed in Thread: CONTROLSUITE, TMS320F28335

Hello,

In my motion control project, I would like to use the Cpu-Timer0 in order to generate an interrupt every 200us which launch an interrupt service routine "ISRKernel". This interrupt service routine is used to compute the current and the speed control of the AC motor.

So, I need to initialize, configurate, start the Cpu-Timer0 and associate to it the ISRKernel . I got some help from controlSuite example files.

Here is the way I initialize, configurate and start the Cpu-Timer0 is developed below :

In the file "cpu_timer.c"

struct CPUTIMER_VARS CpuTimer0;

//=====================================
// InitCpuTimers: Initialize specified Cpu Timer :
//-------------------------------------
// This function initializes all three CPU timers to a known state.
//=====================================
void InitCpuTimers(void)
{
// CPU Timer 0
// Initialize address pointers to respective timer registers:
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
}

//=====================================
// ConfigCpuTimer: Configure Cpu Timer :
//-------------------------------------
// This function initializes the selected timer to the period specified
// by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz"
// and the period in "uSeconds". The timer is held in the stopped state
// after configuration.
//=====================================
void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
{
Uint32 temp;

// Initialize timer period:
Timer->CPUFreqInMHz = Freq;
Timer->PeriodInUSec = Period;
temp = (long) (Freq * Period);
Timer->RegsAddr->PRD.all = temp;

// Set pre-scale counter to divide by 1 (SYSCLKOUT):
Timer->RegsAddr->TPR.all = 0;
Timer->RegsAddr->TPRH.all = 0;

// Initialize timer control register:
Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart Timer
Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer
Timer->RegsAddr->TCR.bit.SOFT = 1;
Timer->RegsAddr->TCR.bit.FREE = 1; // Timer Free Run
Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer Interrupt

// Reset interrupt counter:
Timer->InterruptCount = 0;
}

In the "main function"in the file "imvf28.c" :

// Configure CPU-Timer 0 to interrupt every second : 150MHz CPU Freq, 200 usecond Period
InitCpuTimers();                                               // Init CPU-Timer0
ConfigCpuTimer(&CpuTimer0, 150, 200); // Config the Cpu-Timer0
StartCpuTimer0();                                           // CpuTimer0Regs.TCR.bit.TSS = 0 : start the Cpu-Timer 0

EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM

In the function "InitKernel" in the file "kernel.c" :

EALLOW; // Enable write to EALLOW protected registers
PieVectTable.TINT0 = &ISRKernel; // used to associate "IsrKernel" to CPU-Timer0
EDIS; // Disable write to EALLOW protected registers

// Enable TINT0 in the PIE: Group 1 interrupt 7 :
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
IER |= M_INT1;

// Enable EPWM1 INT in the PIE: Group 3 interrupt 1             // The original program used EPWM1 timer for this ISR
//PieCtrlRegs.PIEIER3.bit.INTx1 = 1;                                          // The original program used EPWM1 timer for this ISR                         

//IER |= M_INT3; // Enable CPU INT3 for EPWM1 INT              // The original program used EPWM1 timer for this ISR


Since my project is still not working correctly, I would be grateful if you could provide me with some tips to make my interrupt service routine work properly with the Cpu-Timer0.

Thank you in advance for your help in this matter.

Malory


  • Hi!

    Check your code carefully referring to 

    //###########################################################################
    //
    // FILE:    Example_2833xCpuTimer.c
    //
    // TITLE:   DSP2833x Device Getting Started Program.
    //
    // ASSUMPTIONS:
    //
    //    This program requires the DSP2833x header files.
    //
    //    Other then boot mode configuration, no other hardware configuration
    //    is required.
    //
    //
    //    As supplied, this project is configured for "boot to SARAM"
    //    operation.  The 2833x Boot Mode table is shown below.
    //    For information on configuring the boot mode of an eZdsp,
    //    please refer to the documentation included with the eZdsp,
    //
    //       $Boot_Table:
    //
    //         GPIO87   GPIO86     GPIO85   GPIO84
    //          XA15     XA14       XA13     XA12
    //           PU       PU         PU       PU
    //        ==========================================
    //            1        1          1        1    Jump to Flash
    //            1        1          1        0    SCI-A boot
    //            1        1          0        1    SPI-A boot
    //            1        1          0        0    I2C-A boot
    //            1        0          1        1    eCAN-A boot
    //            1        0          1        0    McBSP-A boot
    //            1        0          0        1    Jump to XINTF x16
    //            1        0          0        0    Jump to XINTF x32
    //            0        1          1        1    Jump to OTP
    //            0        1          1        0    Parallel GPIO I/O boot
    //            0        1          0        1    Parallel XINTF boot
    //            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
    //            0        0          1        1    Branch to check boot mode
    //            0        0          1        0    Boot to flash, bypass ADC cal
    //            0        0          0        1    Boot to SARAM, bypass ADC cal
    //            0        0          0        0    Boot to SCI-A, bypass ADC cal
    //                                              Boot_Table_End$
    //
    // DESCRIPTION:
    //
    //    This example configures CPU Timer0, 1, and 2 and increments
    //    a counter each time the timers assert an interrupt.
    //
    //       Watch Variables:
    //          CpuTimer0.InterruptCount
    //          CpuTimer1.InterruptCount
    //          CpuTimer2.InterruptCount
    //
    //###########################################################################
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Prototype statements for functions found within this file.
    interrupt void cpu_timer0_isr(void);
    interrupt void cpu_timer1_isr(void);
    interrupt void cpu_timer2_isr(void);
    
    void main(void)
    {
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();
    
    // Step 2. Initalize GPIO:
    // This example function is found in the DSP2833x_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 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.TINT0 = &cpu_timer0_isr;
       PieVectTable.XINT13 = &cpu_timer1_isr;
       PieVectTable.TINT2 = &cpu_timer2_isr;
       EDIS;    // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize the Device Peripheral. This function can be
    //         found in DSP2833x_CpuTimers.c
       InitCpuTimers();   // For this example, only initialize the Cpu Timers
    
    #if (CPU_FRQ_150MHZ)
    // Configure CPU-Timer 0, 1, and 2 to interrupt every second:
    // 150MHz CPU Freq, 1 second Period (in uSeconds)
    
       ConfigCpuTimer(&CpuTimer0, 150, 1000000);
       ConfigCpuTimer(&CpuTimer1, 150, 1000000);
       ConfigCpuTimer(&CpuTimer2, 150, 1000000);
    #endif
    
    #if (CPU_FRQ_100MHZ)
    // Configure CPU-Timer 0, 1, and 2 to interrupt every second:
    // 100MHz CPU Freq, 1 second Period (in uSeconds)
    
       ConfigCpuTimer(&CpuTimer0, 100, 1000000);
       ConfigCpuTimer(&CpuTimer1, 100, 1000000);
       ConfigCpuTimer(&CpuTimer2, 100, 1000000);
    #endif
    // To ensure precise timing, use write-only instructions to write to the entire register. Therefore, if any
    // of the configuration bits are changed in ConfigCpuTimer and InitCpuTimers (in DSP2833x_CpuTimers.h), the
    // below settings must also be updated.
    
       CpuTimer0Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
       CpuTimer1Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
       CpuTimer2Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
    
    // Step 5. User specific code, enable interrupts:
    
    
    // Enable CPU int1 which is connected to CPU-Timer 0, CPU int13
    // which is connected to CPU-Timer 1, and CPU int 14, which is connected
    // to CPU-Timer 2:
       IER |= M_INT1;
       IER |= M_INT13;
       IER |= M_INT14;
    
    // Enable TINT0 in the PIE: Group 1 interrupt 7
       PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    
    // Enable global Interrupts and higher priority real-time debug events:
       EINT;   // Enable Global interrupt INTM
       ERTM;   // Enable Global realtime interrupt DBGM
    
    // Step 6. IDLE loop. Just sit and loop forever (optional):
       for(;;);
    
    }
    
    
    interrupt void cpu_timer0_isr(void)
    {
       CpuTimer0.InterruptCount++;
    
       // Acknowledge this interrupt to receive more interrupts from group 1
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }
    
    interrupt void cpu_timer1_isr(void)
    {
       CpuTimer1.InterruptCount++;
       // The CPU acknowledges the interrupt.
       EDIS;
    }
    
    interrupt void cpu_timer2_isr(void)
    {  EALLOW;
       CpuTimer2.InterruptCount++;
       // The CPU acknowledges the interrupt.
       EDIS;
    }
    
    //===========================================================================
    // No more.
    //===========================================================================
    
    . Why do you call StartCpuTimer0()? (You need to initialize the timer, then it is necessary to specify it the address of your ISR and enable interrupts).

    Regards,

    Igor

  • Hello Igor,

    Thank for your answer. I use StartCpuTimer0() to start the CPU-Timer0. Here are the line which are defined in a header file :

    // Start Timer:
    #define StartCpuTimer0()   CpuTimer0Regs.TCR.bit.TSS = 0

    I initialied the timer with the following functions (which are defined in a "cpu_timer.c" file) in the main function of my project :

    // Configure CPU-Timer 0 to interrupt every second : 150MHz CPU Freq, 200 usecond Period
    InitCpuTimers();                                               // Init CPU-Timer0
    ConfigCpuTimer(&CpuTimer0, 150, 200); // Config the Cpu-Timer0

    I specified the timer of CPU-Timer0 to the adress of my ISRKernel with the following line which is defined in a function "Init_ISRKernel" :

    PieVectTable.TINT0 = &ISRKernel;  // used to associate "IsrKernel" to CPU-Timer0

    I think I have made the right settings... I guess

    So I don't understand where I have done a mistake or an oversight...

    Regards,

    Malory


  • Hello!

    Could you please send me your Init_ISRKernel & ISRKernel code? Too little information to be able to give some advice.

    Regards,

    Igor

  • Hello Igor,

    Thanks for your answer. Here are the  functions which are defined in my file "ISRKernel.c" :

    /*********************************************************************************************************
    Routine Name: InitKernel
    ------------------------
    Purpose: Initialization routine, called from the main function
    Calling Convention: extern void InitKernel(KERNEL *temp);
    Description: Enable T1UFINT and unmask INT2. Sets the corresponding registers of the DSP
    **********************************************************************************************************/
    void InitKernel(KERNEL *temp)
    {
    temp->FastMaxCounter = 2;                                                                               //_ctrl_crt_sampling/(2*_sym_pwm_per); // = 2
    if( temp->FastMaxCounter <= 2 ) temp->FastMaxCounter = 2;                 // Securite au cas ou FastMaxCounter != 2
    temp->SlowMaxCounter = 5;                                                                             // CTRL_PS_SAMPLING fixe et _sym_pwm_per varie donc !=2
    if( temp->SlowMaxCounter <= 2 ) temp->SlowMaxCounter = 2;              // Securite au cas ou SlowMaxCounter != 2

    temp->FlagActiveFast = 0;
    temp->FlagActiveSlow = 0;
    temp->CounterFast = temp->FastMaxCounter;
    temp->CounterSlow = temp->SlowMaxCounter;

    // EALLOW; // Enable write to EALLOW protected registers      // original settings with EPWM1 timer
    // PieVectTable.EPWM1_INT = &ISRKernel;                                   // original settings with EPWM1 timer
    // EDIS; // Disable write to EALLOW protected registers            // original settings with EPWM1 timer

    EALLOW;                                                   // Enable write to EALLOW protected registers
    PieVectTable.TINT0 = &ISRKernel;     // Permet normalement de "coller" IsrKernel sur CPU-Timer0
    EDIS;                                                          // Disable write to EALLOW protected registers

    // Interrupt where we will change the Compare Values
    EPwm1Regs.ETSEL.bit.INTSEL = 1;    // Select INT on Zero event : Enable event time-base counter equal to zero. (TBCTR = 0x0000)
    EPwm1Regs.ETSEL.bit.INTEN = 1;      // Enable INT : Enable EPWM1_INT generation
    EPwm1Regs.ETPS.bit.INTPRD = 1;    // Generate INT on 1st event : Generate an interrupt on the first event INTCNT = 01 (first event)

    // Enable TINT0 in the PIE: Group 1 interrupt 7 :
    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    IER |= M_INT1;

    // Enable EPWM1 INT in the PIE: Group 3 interrupt 1    // original settings with EPWM1 timer
    //PieCtrlRegs.PIEIER3.bit.INTx1 = 1;                                 // original settings with EPWM1 timer
    //IER |= M_INT3; // Enable CPU INT3 for EPWM1 INT     // original settings with EPWM1 timer
    }


    /********************************************************************************************************
    Routine Name: ISRKernel
    -----------------------
    Purpose: Speed & current loop interrupt routine
    Calling Convention: Interrupt Service Routine (no calling)
    Description: Real-time control interrupt routine. Executed at PWM timer underflow event. Launched
    from the monitor program. Calls the C functions RtcFast and RtcSlow at appropriate
    moments, based on slow and fast counters update values
    **********************************************************************************************************/
    interrupt void ISRKernel()
    {
    //**************** Randoom PWM*******************
    _aleat = 0;

    if (_aleat==1)
    {
    //------------------------------Compute PWM Parameters----------------------------------
    //_pwm_freq = 20000;
    _pwm_freq = (5000+(rand()%15000));                                       //Randoom PWM [5kHz ; 20kHz]
    _sym_pwm_per = (CPU_CLOCK_FREQ / _pwm_freq / 2);

    Re_InitTimer_ePWMx(&EPwm1Regs);       // Initialize ePWM1 module
    Re_InitTimer_ePWMx(&EPwm2Regs);       // Initialize ePWM2 module
    Re_InitTimer_ePWMx(&EPwm3Regs);       // Initialize ePWM3 module
    }

    // EPwm1Regs.ETCLR.bit.INT = 1;          // original settings with EPWM1 timer
    CpuTimer0Regs.TCR.bit.TIF = 1;
    CpuTimer0.InterruptCount++;

    // Acknowledge this interrupt to receive more interrupts from group 1
    // PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;    // original settings with EPWM1 timer
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    Kernel.CounterFast--;
    if (!(Kernel.CounterFast))
    {// Fast Interrupt function
    FlagADC = 1;                             // Signalize that the currents must be saved from RESULTx registers
    Kernel.FlagActiveFast = 1;    // Set FlagActivFast in order to flag the execution of RtcFast
    Kernel.CounterFast += Kernel.FastMaxCounter; // Reactualization of Counter Fast
    EINT;                // All mascable inerupts are enabled
    RtcFast();       // Call fast interrupt routine
    DINT;               // All mascable interupts are disabled
    Kernel.FlagActiveFast = 0;          // Reset FlagActivFast in order to flag the end of RtcFast
    }

    Kernel.CounterSlow--;
    if (!(Kernel.FlagActiveFast))    // If the RtcFast is not in execution
    {
    if (Kernel.CounterSlow <= 0)
    {// Slow Interrupt function
    Kernel.FlagActiveSlow = 1;         // Set FlagActivSlow in order to flag the executiona of RtcSlow
    Kernel.CounterSlow += Kernel.SlowMaxCounter;     // Reactualization of Counter Slow
    EINT;                // All mascable inerupts are enabled
    RtcSlow();      // Call slow interrupt routine
    DINT;               // All mascable interupts are disabled
    Kernel.FlagActiveSlow = 0;  // Reset FlagActivSlow in order to flag the end of RtcSlow
    }
    }
    }

    Regards

    Malory

  • Hi Malory!

    Thanks. While is not all clear...

    You read: "Since my project is still not working correctly". 

    I would like to clarify. What kind of problem do you have? Your  ISRKernel() is called at least once or he never called? Or it is called but with a different period which is not equal 200 us?

    Regards,

    igor



  • Hi Igor,

    My ISRKernel() does not seem to be assigned to the CPU-Timer0 --> never called. Have you seen strange things in my code ? Or some oversight ?

    Thank you again for your help in this matter.

    Regards,

    Malory

  • Hello!

    Sorry! So far I have not found somehing criminal in your code. But If I'd been in your shoes I would prefer to begin the development project from the very first on base http://e2e.ti.com/cfs-file.ashx/__key/communityserver-discussions-components-files/171/3326.Example_5F00_2833xCpuTimer.c. First, I would run an empty interrupt handler timer0 for 200 us and I would make sure that it works properly. And then I would be included to the your project the rest functions gradually.

    Regards,

    Igor

  • Hello Malory!

    How are you? Sorry to bother. Did you decide your timer's problem?

    Regards,

    Igor

  • Hello Igor,

    I have not yet decided my timer's problem. In fact I did some of acoustic noise measures this last week and I did not take time to look into my CPU-Timer problem. I will probably work on next week.

    I wil get you in touch about it.

    Regards,

    Malory

  • Hello Malory!

    The fact that I remembered about your problem when I was discussing a similar problem at this post http://e2e.ti.com/support/microcontrollers/c2000/f/171/t/269497.aspx. Maybe this post will be useful for you also.

    Regards,

    Igor

  • Hello Igor,

    I have not solved my problem yet. I wonder if my problem is due to priority between interrupt service routine...

    Have you any tips that could help me to solve this issue ?

    Thank you in advance

    Regards,

    Malory

  • Hello Malory!

    Have you tried to do what I suggested earlier? I mean to run only one ISR (an empty interrupt handler of timer0 for 200 us, maybe with use of any GPIO-pin to enable some hardware control).

    Regards,

    Igor

  • I did not try to run one ISR only. But I really think that I am about to overcome my problem. I am almost sure that I have to find the corresponding set up in order to replace these three lines bellow :

                EPwm1Regs.ETSEL.bit.INTSEL = 1;            // Select INT on Zero event

                EPwm1Regs.ETSEL.bit.INTEN = 1;          // Enable INT : Enable EPWM1_INT generation
                CpuTimer0Regs.TCR.bit.TIE = 1;

                EPwm1Regs.ETPS.bit.INTPRD = 1;          // Generate INT on 1st event 

    // Clear INT flag for this timer
                EPwm1Regs.ETCLR.bit.INT = 1;
                CpuTimer0Regs.TCR.bit.TIF = 1;

    I did not find the corresponding setting for INTSEL and INTPRD registers of EPWM1 and that's i am searching for...

    Regards,

  • Hi!

    Ok! By the way it seems it need to add the one line in your ISRKernel:

    interrupt void ISRKernel()
    {
    //**************** Randoom PWM*******************
    _aleat = 0;

    if (_aleat==1)
    {
    //------------------------------Compute PWM Parameters----------------------------------
    //_pwm_freq = 20000;
    _pwm_freq = (5000+(rand()%15000));                                       //Randoom PWM [5kHz ; 20kHz]
    _sym_pwm_per = (CPU_CLOCK_FREQ / _pwm_freq / 2);

    Re_InitTimer_ePWMx(&EPwm1Regs);       // Initialize ePWM1 module
    Re_InitTimer_ePWMx(&EPwm2Regs);       // Initialize ePWM2 module
    Re_InitTimer_ePWMx(&EPwm3Regs);       // Initialize ePWM3 module

    // Acknowledge this interrupt to receive more interrupts from group 1
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    }

    Also, I'm not sure, but maybe it will be useful http://e2e.ti.com/support/microcontrollers/c2000/f/171/p/270236/944737.aspx#944737.

    Good luck,

    Igor

  • Hi Igor,

    Thank you for your answer. Maybe you have a suggestion for me to realize this kind of running :

    In fact I would like to use the CPU-Timer0 to generate interruption which is associated to my ISRKernel Function. And I already use EPWM1 timer to generate my PWM_frequency. My real aim is to modify PWM frequency at each interruption of the CPU-Timer0.

    Actually, only the EPWM timer is used and so, The generation of interruption is linked to this timer. In this case, when I change the PWM frequency (at each interruption), I change the period of generation interruption. So I would like to separate the generation of interruption and the PWM generation.

    I hope that you could help me to overcome my issue.

    Thanks for your help in this matter.

    Malory

  • Hello Malory!

    If I understood you right you want to get FSK-signal. if so what are two frequencies you want to have and how often you want them to switch (i.e. what is desired timer0 interrupt interval?)?

    Regards,

    Igor

  • Hello Igor,

    One more time, thank you again for your help.

    In fact, I would like that the CPUtimer0 generates an interrupt every 50us. This timer will be used to compute parameters which allow the speed control and the current (so the torque) control of the motor.

    The EPWM timer (Which is already running correctly) is used to generate the PWM frequency (20kHz) of the motor. Actually It is used for both (PWM frequency, and control of the motor).

    So If I don't change the PWM frequency, It works well. But my real aim is to change the PWM frequency (in various way) at each interruption of the Timer (in the ISRKernel routine which is called at each interruption). Changing the pwm frequency while the motor is running is a method which allows to reduce the acoustic noise generate by the motor. So That is why I would like to do that.

    Regards

  • Hello Malory!

    I have looked at your picture and I have read your sentence : "My real aim is to modify PWM frequency at each interruption of the CPU-Timer0." Thus I have presumed you want to get FSK. But now I understand I was wrong. Clarify please what kind of changes of PWM frequency do you want to get at timer0-ISR (what is the law of PWM frequency changes at timer0-ISR? Or how timer0-ISR will decide what  frequency have to be set at each moment of timer0 interrupt?)?

    Regards,

    Igor

  • At the begining, I just want to change the PWM frequency with randoom function in the ISRKernel  : like that :

    interrupt void ISRKernel()
    {

    if (_aleat==1) // aleat value is defined previously...
    {
    //------------------------------Compute PWM parameters----------------------------------
    //_pwm_freq = 20000; // used for fixed PWM frequency
    _pwm_freq = (5000+(rand()%15000)); // randoom PWM between 5kHz and 10kHz
    _sym_pwm_per = (CPU_CLOCK_FREQ / _pwm_freq / 2);
    _ctrl_crt_sampling = ((100/50)*2*_sym_pwm_per);
    _ts_crt_sampling = ((float)1/(float)150000000)*_ctrl_crt_sampling;
    _ts_spd_sampling = (10*_ts_crt_sampling);
    _ctrl_ps_sampling = (_ts_spd_sampling * CPU_CLOCK_FREQ);
    _sat_umax_pwm = ((1.0 - (MIN_TIME / T1CLK_PER) / (2.0 * _sym_pwm_per)) * 32767.0);
    _crt_loop_per = _ts_crt_sampling;
    _c_f_const = (_crt_loop_per * 65536.0);


    Re_InitTimer_ePWMx(&EPwm1Regs); // Initialize ePWM1 module
    Re_InitTimer_ePWMx(&EPwm2Regs); // Initialize ePWM2 module
    Re_InitTimer_ePWMx(&EPwm3Regs); // Initialize ePWM3 module
    }
    //----------------------------------------------------------------------------------------------------------

    Here is the function which allows to modify the PWM frequency :

    void Re_InitTimer_ePWMx(volatile struct EPWM_REGS *ePWM_Regs)
    {
    ePWM_Regs->TBPRD = _sym_pwm_per; // Time-Base Period Register. Set the period of the time-base counter. This sets the PWM frequency.
    }

    Do not hesitate if you need more clarification that could allows you to understand my issue.

    I really appreciate your help in this matter

    Regards,

    Malory

  • Hi!

    Ok... Firstly. You have written  "I would like that the CPUtimer0 generates an interrupt every 50us". But if your PWM frequency 5-20 kHz then on my opinion timer0 had to generate interrupt with frequency < 5 kHz (i.e. interrupt's interval > 200 us, because at least between two timer0 interrupts one period of minim PWM frequency had to be - I think it will be right). Secondly.  What about the interrupt priorities at your system? Perhaps timer0 should be top priority. 

    It's all at now...

    Regards,

    Igor 

  • Hello Malory!

    Sorry! I made ​​a mess of some values (refer to post above) but I corrected.

    Regards,

    Igor

  • Hi Igor,

    You are right !

    Maybe the following picture will be more meaningful :

    So, at each interrupt of the CPU Timer 0, the PWM frequency have to change its value in a randoom way (between 5kHz and 20kHz). The CPUtimer0 must be configurated at a biggest value than the smallest value of the EPWM timer (i.e. EPWM min = 1/5kHz=200us, so CPUTimer0 >= 200us).

    So I totally agree with you.

    Regards

  • Hello Malory!

    Well,  now there is an understanding of your task in my mind. Could you please explain the following line of ISRKernel:

    _pwm_freq = (5000+(rand()%15000));

    I see there is some function rand() which return some value. This returned value affects the PWM frequency eventually.  Has this function some relation with feedback on speed or current? How does it works?

    Regards,

    Igor

  • Hello Igor,

    About line : _pwm_freq = (5000+(rand()%15000)); // the function rand() return a value between 5kHz and 20kHz.

    As you said, I compute the PWM Frequency (_pwm_freq) at each interruption of ISRKernel. The following lines in the ISRkernel Function use the new value of _pwm_freq :

    _sym_pwm_per = (CPU_CLOCK_FREQ / _pwm_freq / 2);

    ...

    Re_InitTimer_ePWMx(&EPwm1Regs);    // Initialize ePWM1 module
    Re_InitTimer_ePWMx(&EPwm2Regs);    // Initialize ePWM2 module
    Re_InitTimer_ePWMx(&EPwm3Regs);    // Initialize ePWM3 module


    void Re_InitTimer_ePWMx(volatile structEPWM_REGS *ePWM_Regs)  // This function Reinitialise the Time base period for PWM generation

    {
    ePWM_Regs->TBPRD = _sym_pwm_per; // Time-Base Period Register. Set the period of the time-base counter. This sets the PWM frequency.
    }

    Indeed, the original project uses only the EPWM timer to generate PWM and to control current and speed. Here is the function InitKernel() which initialize the ISRKernel() :

    void InitKernel(KERNEL *temp)
    {
       temp->FastMaxCounter = _ctrl_crt_sampling/(2*_sym_pwm_per);
       if( temp->FastMaxCounter <= 2 ) temp->FastMaxCounter = 2;
       temp->SlowMaxCounter = _ctrl_ps_sampling/(2*_sym_pwm_per);
       if( temp->SlowMaxCounter <= 2 ) temp->SlowMaxCounter = 2; 

       temp->FlagActiveFast = 0;
       temp->FlagActiveSlow = 0;
       temp->CounterFast = temp->FastMaxCounter;
       temp->CounterSlow = temp->SlowMaxCounter;

       EALLOW; // Enable write to EALLOW protected registers
       PieVectTable.EPWM1_INT = &ISRKernel;
       EDIS; // Disable write to EALLOW protected registers

       // Interrupt where we will change the Compare Values
       EPwm1Regs.ETSEL.bit.INTSEL = 1; // Select INT on Zero event : Enable event time-base counter equal to zero. (TBCTR = 0x0000)
       EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT : Enable EPWM1_INT generation
       EPwm1Regs.ETPS.bit.INTPRD = 1; // Generate INT on 1st event : Generate an interrupt on the first event INTCNT = 01 (first event)

       // Enable EPWM1 INT in the PIE: Group 3 interrupt 1
       PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
       IER |= M_INT3; // Enable CPU INT2 for EPWM1 INT:

    }

    Here is the ISRKernel function :

    interrupt void ISRKernel()
    {

    // 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;

    Kernel.CounterFast--;
       if (!(Kernel.CounterFast))
       {   // Fast Interrupt function
        FlagADC = 1;                                // Signalize that the currents must be saved from RESULTx registers
       Kernel.FlagActiveFast = 1;        //Set FlagActivFast in order to flag the execution of RtcFast
       Kernel.CounterFast += Kernel.FastMaxCounter;      //Reactualization of Counter Fast
       EINT;                              //All mascable inerupts are enabled
       RtcFast();                    //Call fast interrupt routine for current control
       DINT;                            //All mascable interupts are disabled
       Kernel.FlagActiveFast = 0;       //Reset FlagActivFast in order to flag the end of RtcFast
    }

    Kernel.CounterSlow--;
       if (!(Kernel.FlagActiveFast))    // If the RtcFast is not in execution
      {
       if (Kernel.CounterSlow <= 0)
       {     // Slow Interrupt function
       Kernel.FlagActiveSlow = 1;                  //Set FlagActivSlow in order to flag the executiona of RtcSlow
       Kernel.CounterSlow += Kernel.SlowMaxCounter;                //Reactualization of Counter Slow
       EINT;                                             //All mascable inerupts are enabled
       RtcSlow();                                  //Call slow interrupt routine for speed control
       DINT;                                             //All mascable interupts are disabled
       Kernel.FlagActiveSlow = 0;     //Reset FlagActivSlow in order to flag the end of RtcSlow
       }
     }
    }

    With this configuration, when I change the TBPRD register in order to change the PWM frequency, I also change the generation of interruption of ISRkernel() :

    PieVectTable.EPWM1_INT = &ISRKernel;

    That is why I would like to use the CPUTimer0 to associate it to the ISRKernel() :

    PieVectTable.TINT0 = &ISRKernel;

    And as you know, I did not manage to associate it correctly and I don't know why because I made my setting thanks to the controlSUITE examples. I really hope that we will manage to solve my problem.

    Regards,

    Malory

  • Hello Malory!

    Before we go further I would like to get some clarification about rand(). The fact is that if this function performs some PID-algorithm (or doesn't?) one requires some time resources. I mean the running time of rand() must be < 200 us for our case. Is there confidence that this condition is satisfied?

    Regards,

    Igor

  • Hello Igor,

    I currently use a U/F motion control for the motor. So find out the control scheme of the U/F motion control:

    So in that case, I don't use PID algorithm. The progam compare the real speed to the reference and compute a new value of V/F factor in order to keep the real speed close to the reference that we have imposed.

    So I don't know how many times does the running of the rand() function take.

    Is it a problem to configurate the CPU-Timer0 ?

    Regards

    Malory

  • Hi Malory!

    In principle, it is not a big problem. But before configuring the timer0 it is better to get rid of any uncertainties. Let's hope that rand()-function is performed for time<<200 us. I have written already that the best way to begin with empty ISR-timer0. You can use some GPIO-pin for hardware control. For example:

    interrupt void cpu_timer0_isr(void)
    {
    CpuTimer0.InterruptCount++;// you can check this variable at debugger

    // here one may toggle GPIO-pin and check with oscilloscope

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

    When timer0 will work then one may add the functionality (rest code).

    By the way about PID-regulator. You have written: "The progam compare the real speed to the reference and compute a new value of V/F factor in order to keep the real speed close to the reference that we have imposed". Thus you have feedback on speed. So your program executes the automatic control algorithm (maybe not PID but P-regulator( v/f =ct )). Or I don't understand something at your figure?

    Regards,

    Igor

  • Hello Igor,

    I am going to run the cpu_timer0_isr() alone. I will keep you in touch about it.

    Inded, according to the figure which describe the U/F motion control, the U/F motion control can be assimilate to a P regulator.

    Have you some examples about GPIO-pin in order to check the correct running with an oscilloscope ?

    Thank you again for your help

    Malory

  • Hello Malory!

    In principle, the use of the GPIO-pin is not required. Watching Cpu Timer0.Interrupt Count++ at debugger -  it is enough. For the use GPIO-pin (for example - choose GPIO-pin that is comfortable for you):

    EALLOW; // below registers are "protected", allow access.

    GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0; // 0=GPIO, 1=ECAP1, 2=Resv, 3=Resv
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // 1=OUTput, 0=INput

    EDIS; // Disable register access

    interrupt void cpu_timer0_isr(void)
    {
    CpuTimer0.InterruptCount++;// you can check this variable at debugger

    GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1; // here one may check GPIO-pin with oscilloscope

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

    On other hand the use of GPIO-pin and an oscilloscope will be usefull when you will add your code at ISR-timer0.

    Regards,

    Igor

  • Hello Igor,

    Thank you for your answer.

    About CPU-Timer definition in TI examples : Could you please tell me what are these following lines are supposed to do :

    // Reload Timer With period Value:
    #define ReloadCpuTimer1() CpuTimer1Regs.TCR.bit.TRB = 1
    #define ReloadCpuTimer2() CpuTimer2Regs.TCR.bit.TRB = 1

    // Read 32-Bit Timer Value:
    #define ReadCpuTimer1Counter() CpuTimer1Regs.TIM.all
    #define ReadCpuTimer2Counter() CpuTimer2Regs.TIM.all

    // Read 32-Bit Period Value:
    #define ReadCpuTimer1Period() CpuTimer1Regs.PRD.all
    #define ReadCpuTimer2Period() CpuTimer2Regs.PRD.all

    In addition to that, Why are theses following ISR are not defined in the same way ? (I mean that the cpu_timer1_isr uses EDIS only, and the cpu_timer2_isr uses EALLOW + EDIS)

    interrupt void cpu_timer0_isr(void)
    {
    CpuTimer0.InterruptCount++;

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

    interrupt void cpu_timer1_isr(void)
    {
    CpuTimer1.InterruptCount++;
    // The CPU acknowledges the interrupt.
    EDIS;
    }

    interrupt void cpu_timer2_isr(void)
    { EALLOW;
    CpuTimer2.InterruptCount++;
    // The CPU acknowledges the interrupt.
    EDIS;
    }

    Thank you in adavance

    Regards

    Malory

  • Hello Malory!

    Unfortunately I was not engaged in deep study of resources of TMS320F28335. I work with C2000-series of MCU 3 mouths only. To work with a timer, I used only 1462.DSP2833x_CpuTimers.h

    //###########################################################################
    //
    // FILE:    DSP2833x_CpuTimers.c
    //
    // TITLE:   CPU 32-bit Timers Initialization & Support Functions.
    //
    // NOTES:   CpuTimer2 is reserved for use with DSP BIOS and
    //          other realtime operating systems.
    //
    //          Do not use these this timer in your application if you ever plan
    //          on integrating DSP-BIOS or another realtime OS.
    //
    //###########################################################################
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    #include "DSP2833x_Device.h"     // Headerfile Include File
    #include "DSP2833x_Examples.h"   // Examples Include File
    
    struct CPUTIMER_VARS CpuTimer0;
    
    // When using DSP BIOS & other RTOS, comment out CPU Timer 2 code.
    struct CPUTIMER_VARS CpuTimer1;
    struct CPUTIMER_VARS CpuTimer2;
    
    //---------------------------------------------------------------------------
    // InitCpuTimers:
    //---------------------------------------------------------------------------
    // This function initializes all three CPU timers to a known state.
    //
    void InitCpuTimers(void)
    {
        // CPU Timer 0
        // Initialize address pointers to respective timer registers:
        CpuTimer0.RegsAddr = &CpuTimer0Regs;
        // Initialize timer period to maximum:
        CpuTimer0Regs.PRD.all  = 0xFFFFFFFF;
        // Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
        CpuTimer0Regs.TPR.all  = 0;
        CpuTimer0Regs.TPRH.all = 0;
        // Make sure timer is stopped:
        CpuTimer0Regs.TCR.bit.TSS = 1;
        // Reload all counter register with period value:
        CpuTimer0Regs.TCR.bit.TRB = 1;
        // Reset interrupt counters:
        CpuTimer0.InterruptCount = 0;
    
    
    // CpuTimer2 is reserved for DSP BIOS & other RTOS
    // Do not use this timer if you ever plan on integrating
    // DSP-BIOS or another realtime OS.
    
        // Initialize address pointers to respective timer registers:
        CpuTimer1.RegsAddr = &CpuTimer1Regs;
        CpuTimer2.RegsAddr = &CpuTimer2Regs;
        // Initialize timer period to maximum:
        CpuTimer1Regs.PRD.all  = 0xFFFFFFFF;
        CpuTimer2Regs.PRD.all  = 0xFFFFFFFF;
        // Make sure timers are stopped:
        CpuTimer1Regs.TCR.bit.TSS = 1;
        CpuTimer2Regs.TCR.bit.TSS = 1;
        // Reload all counter register with period value:
        CpuTimer1Regs.TCR.bit.TRB = 1;
        CpuTimer2Regs.TCR.bit.TRB = 1;
        // Reset interrupt counters:
        CpuTimer1.InterruptCount = 0;
        CpuTimer2.InterruptCount = 0;
    
    }
    
    //---------------------------------------------------------------------------
    // ConfigCpuTimer:
    //---------------------------------------------------------------------------
    // This function initializes the selected timer to the period specified
    // by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz"
    // and the period in "uSeconds". The timer is held in the stopped state
    // after configuration.
    //
    void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
    {
        Uint32  temp;
    
        // Initialize timer period:
        Timer->CPUFreqInMHz = Freq;
        Timer->PeriodInUSec = Period;
        temp = (long) (Freq * Period);
        Timer->RegsAddr->PRD.all = temp;
    
        // Set pre-scale counter to divide by 1 (SYSCLKOUT):
        Timer->RegsAddr->TPR.all  = 0;
        Timer->RegsAddr->TPRH.all  = 0;
    
        // Initialize timer control register:
        Timer->RegsAddr->TCR.bit.TSS = 1;      // 1 = Stop timer, 0 = Start/Restart Timer
        Timer->RegsAddr->TCR.bit.TRB = 1;      // 1 = reload timer
        Timer->RegsAddr->TCR.bit.SOFT = 1;
        Timer->RegsAddr->TCR.bit.FREE = 1;     // Timer Free Run
        Timer->RegsAddr->TCR.bit.TIE = 1;      // 0 = Disable/ 1 = Enable Timer Interrupt
    
        // Reset interrupt counter:
        Timer->InterruptCount = 0;
    }
    
    //===========================================================================
    // End of file.
    //===========================================================================
    
    . Also I used the cpu_timer example project from controlSUITE. I think the data sheet SPRS439M can answer these deep questions. But in my opinion it will take added time which can be used for experiments.

    Regards,

    Igor