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.

CCS/TMS320F28035: In pwm up-down counter mode, set TBCTR = 0 Cause an error that is TBCTR > TBPRD

Part Number: TMS320F28035

Tool/software: Code Composer Studio

Hello to all members,

In pwm up-down counter mode,  I set a breakpoint after make TBCTR = 0 about several clocks, By observing register windows i can get the following information

1. BIT[2] in TBSTS  , CTRMAX == 1, It indicates that the time-base counter reached the max value 0xFFFF

2. BIT[0] in TBSTS  , CTRDIR == 0, It means Time-Base Counter is currently counting down

3. TBCTR == 65506

4. TBPRD == 30000

If i set the breakpoint before make TBCTR = 0, then step over one by one, it seems that TBCTR is a correct value, With one-step debugging, its value gradually increases。

I am very confused how this happened, what makes TBCTR bigger than TBPRD?

Any help would be appreciate

thanks in advance

  • Hi Soldier 76,

    The CTRMAX in the TBSTS is a Latched status bit as given in the description. Meaning, the CTRMAX once set will stay the same till its manually cleared (by writing a 1 to it). Since you have the TBPRD as 30000, I believe that you might have enabled the PWM prior to writing to the TBPRD register and the counter would have passed the TBPRD value by the time the TBPRD is updated. That is likely the cause for the CTRMAX to be 1. So that should not be setting I would be looking at to figure out what is going on.

     

    Having said that, I believe the issue you are facing is due to the ISRs in you code.

    Please check if you are tampering with the PWM configuration (especially TBCTR/TBPRD/TBCTL registers) in any of the ISRs.

    If that is not the case, check if the CPU getting enough bandwidth to make this write to TBCTR happen?

     

    I am asking this because you mentioned that it works as expected in the step debug mode. The CPU does not honor the interrupts which in debug mode by default. Only difference I see between your passing and failing scenarios are the ISR execution which does not seem to have happened in the working case.

     

    Hope this helps. Please click on the “verify answer” button if my reply resolves your confusion.

     

    Thanks & Regards

    Pramod

  • Thanks Pramod P for your reply,

    I checked it several times but still found no problem. So, I streamlined the code and it only have epwm1 module and DELAY_US() function,In addition, I blocked the global interruption.

    I found an obvious phenomenon. when TBCTR in count up direction, make TBCTR = 0 will not enter abnormal state. But when TBCTR in count down direction, make TBCTR = 0 will enter abnormal state that is TBCTR > TBPRD, I set the breakpoint as follows  screenshot,DELAY_US(600L) make a delay which make TBCRT in count down direction

    1. First picture, TBCTR is in count up direction when execute  <EPwm1Regs.TBCTR = 0x0000; > 

    2. Second picture, TBCTR is in count down direction when execute  <EPwm1Regs.TBCTR = 0x0000; > 

    Is there any other reason for this anomaly?

    void main(void)
    {

    // Only used if running from FLASH
    // Note that the variable FLASH is defined by the compiler with -d FLASH
    #ifdef FLASH
    // Copy time critical code and Flash setup code to RAM
    // The RamfuncsLoadStart, RamfuncsLoadEnd, and RamfuncsRunStart
    // symbols are created by the linker. Refer to the linker files.
    memcpy((uint16_t *)&RamfuncsRunStart,(uint16_t *)&RamfuncsLoadStart,
    (unsigned long)&RamfuncsLoadSize);

    // Call Flash Initialization to setup flash waitstates
    // This function must reside in RAM
    InitFlash(); // Call the flash wrapper init function
    #endif //(FLASH)


    Device_Init();

    // Timing sync for background loops
    // Timer period definitions found in PeripheralHeaderIncludes.h
    // CpuTimer0Regs.PRD.all = mSec1; // A tasks
    // CpuTimer1Regs.PRD.all = mSec5; // B tasks
    // CpuTimer2Regs.PRD.all = mSec100; // C tasks
    //
    //// Tasks State-machine init
    // Alpha_State_Ptr = &A0;
    // A_Task_Ptr = &A1;
    // B_Task_Ptr = &B1;
    // C_Task_Ptr = &C1;
    //
    // VTimer0[0] = 0;
    // VTimer1[0] = 0;
    // VTimer2[0] = 0;
    // LedBlinkCnt = 5;

    DELAY_US(9000L);


    // Pwm1_Logic_Init();
    Pwm1_3_Init();
    // EXT_Int1_Init();
    // Pwm2_Init();
    // sAdc_Init();

    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;//Enable epwm clock at the same time
    EDIS;

    //EINT; // Enable Global interrupt INTM
    //ERTM;
    DELAY_US(10L);

    //DELAY_US(600L);


    //below is reinit some registor for pan detect
    EPwm1Regs.TBCTR = 0x0000; // Clear counter

    DELAY_US(10L);
    while(1){;}

    }

    --------------------------------------------------------------------------------------------------------------------------------

    void Pwm1_3_Init(void)
    {
    /*********************************************************
    //pwm1 and pwm3 are configed in the same frequency, period.
    //except (EPwm1Regs.TBCTL.bit.PHSEN) is not same
    //pwm3 use its tz interrupt to record pwm1 ctr register to calculate driver delay, and record the count of pan detected pulse
    **********************************************************/

    //--------------------------------------------------
    //pwm1
    //---------------------------------------------------
    wPWM1Freq = 1000; // init Freq
    wPWM1Period = (Uint16)(60000000 / wPWM1Freq);


    EPwm1Regs.TBCTL.bit.PRDLD = TB_IMMEDIATE;//TB_SHADOW; // set load on CTR=0

    EPwm1Regs.TBPRD = wPWM1Period / 2; // PWM frequency = 1 / period
    EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
    EPwm1Regs.TBCTR = 0x0000; // Clear counter

    // Setup TBCLK
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count updown
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
    // EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; // set load on CTR=0
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // Clock ratio to SYSCLKOUT
    EPwm1Regs.TBCTL.bit.CLKDIV = 0; // Slow so we can observe on the scope

    //EPwm1Regs.TBCTL.bit.FREE_SOFT = 11; // XYN, Emulation Mode Bits 1X FREE RUN

    // Setup compare
    EPwm1Regs.CMPA.half.CMPA = wPWM1Period / 4;
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // load on CTR=Zero

    // // Set actions
    // EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set
    // EPwm1Regs.AQCTLA.bit.PRD = AQ_CLEAR; // Clear

    // Set actions
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
    EPwm1Regs.AQCTLA.bit.PRD = AQ_SET;

    // Active high complementary PWMs - Setup the deadband
    EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
    EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;
    EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;
    EPwm1Regs.DBRED = DB_2_5us;
    EPwm1Regs.DBFED = DB_2_5us;

    //config pwm1 isr
    //isr purpose:
    //1. turn off pwm1 output, this lead to a detected pulse
    //2. after some time ,turn off the isr, set the end of pan detect flag EOPD
    EALLOW;
    PieVectTable.EPWM1_INT = &EPWM1_INT_ISR; // Map PWM Interrupt
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1; // PIE level enable, Grp3 / Int1, ePWM1
    EDIS;

    EPwm1Regs.ETSEL.bit.INTSEL = 0;//ET_CTR_PRD; // INT on Counter-Zero event
    EPwm1Regs.ETSEL.bit.INTEN = 0; // Disable INT
    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on every 1st event


    IER |= M_INT3; // Enable CPU INT3 connected to EPWM1-6 INTs:


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

    //--------------------------------------------------
    //comp1 2
    //---------------------------------------------------
    //comp1 as a up half current limit
    //comp2 as a down half current limit
    //if current in not overcurrent, output of pin i/o should be low
    EALLOW;
    // Configure Analog Comparators
    Comp1Regs.COMPCTL.bit.SYNCSEL = 1; // Sync with SYSCLK / use Qualification
    Comp1Regs.COMPCTL.bit.QUALSEL = 3; // Require input be stable for 3 consecutive SYSCLKs
    Comp1Regs.COMPCTL.bit.CMPINV = 0; // Output Low when true
    Comp1Regs.COMPCTL.bit.COMPSOURCE = 0; // Use internal DAC
    Comp1Regs.COMPCTL.bit.COMPDACEN = 1; // Enable DAC
    Comp1Regs.DACVAL.bit.DACVAL = 821;//COMP1; // Trip Current = DACVAL/1023*82.5


    Comp2Regs.COMPCTL.bit.SYNCSEL = 1; // Sync with SYSCLK / use Qualification
    Comp2Regs.COMPCTL.bit.QUALSEL = 3; // Require input be stable for 3 consecutive SYSCLKs
    Comp2Regs.COMPCTL.bit.CMPINV = 1; // Output Low when true
    Comp2Regs.COMPCTL.bit.COMPSOURCE = 0; // Use internal DAC
    Comp2Regs.COMPCTL.bit.COMPDACEN = 1; // Enable DAC
    Comp2Regs.DACVAL.bit.DACVAL = 202;//COMP2; // Trip Current = DACVAL/1023*82.5


    // Define an event (DCAEVT1) based on TZ1 and TZ2
    EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL = DC_COMP1OUT; // DCAH = Comparator 1 output
    //EPwm1Regs.DCTRIPSEL.bit.DCALCOMPSEL = DC_TZ2; // DCAL = TZ2
    EPwm1Regs.TZDCSEL.bit.DCAEVT1 = TZ_DCAH_HI; // DCAEVT1 = DCAH low(will become active as Comparator output goes low)
    EPwm1Regs.DCACTL.bit.EVT1SRCSEL = DC_EVT1; // DCAEVT1 = DCAEVT1 (not filtered)
    EPwm1Regs.DCACTL.bit.EVT1FRCSYNCSEL = DC_EVT_ASYNC; // Take async path

    // Define an event (DCBEVT1) based on TZ1 and TZ2
    EPwm1Regs.DCTRIPSEL.bit.DCBHCOMPSEL = DC_COMP2OUT; // DCBH = Comparator 1 output
    //EPwm1Regs.DCTRIPSEL.bit.DCBLCOMPSEL = DC_TZ2; // DCAL = TZ2
    EPwm1Regs.TZDCSEL.bit.DCBEVT1 = TZ_DCBH_HI; // DCBEVT1 = (will become active as Comparator output goes low)
    EPwm1Regs.DCBCTL.bit.EVT1SRCSEL = DC_EVT1; // DCBEVT1 = DCBEVT1 (not filtered)
    EPwm1Regs.DCBCTL.bit.EVT1FRCSYNCSEL = DC_EVT_ASYNC; // Take async path

    // Enable DCAEVT1 and DCBEVT1 are one shot trip sources
    // Note: DCxEVT1 events can be defined as one-shot.
    // DCxEVT2 events can be defined as cycle-by-cycle.
    EPwm1Regs.TZSEL.bit.DCAEVT1 = 1;
    EPwm1Regs.TZSEL.bit.DCBEVT1 = 1;

    // What do we want the DCAEVT1 and DCBEVT1 events to do?
    // DCAEVTx events can force EPWMxA
    // DCBEVTx events can force EPWMxB
    EPwm1Regs.TZCTL.bit.TZA = TZ_FORCE_LO; // EPWM1A will go high
    EPwm1Regs.TZCTL.bit.TZB = TZ_FORCE_LO; // EPWM1B will go low

    EDIS;


    //--------------------------------------------------
    //comp3
    //---------------------------------------------------
    EALLOW;
    // Configure Analog Comparators
    Comp3Regs.COMPCTL.bit.SYNCSEL = 1; // Sync with SYSCLK / use Qualification
    Comp3Regs.COMPCTL.bit.QUALSEL = 3; // Require input be stable for 3 consecutive SYSCLKs
    Comp3Regs.COMPCTL.bit.CMPINV = 0; // Output Low when true
    Comp3Regs.COMPCTL.bit.COMPSOURCE = 0; // Use internal DAC
    Comp3Regs.COMPCTL.bit.COMPDACEN = 1; // Enable DAC
    Comp3Regs.DACVAL.bit.DACVAL = 496; //
    EDIS;


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

    }

    ------------------------------------------------------------------------------------------


    // DO NOT MODIFY THIS LINE.
    #define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)

  • Hi Soldier 76,

    I will try this once at my end to reproduce and investigate this behavior. 

    Please expect a response from me before 27th Aug as i am tied up with other activities right now.

    Meanwhile, if you can send out this project as an attachment, that would be great.

    Thanks & Regards

    Pramod

  • Hi, Pramod

    HB358K.rarThank you for your help. I'll wait for your answer.

  • Hi Soldier 76,

    I had some time I could spare and created a testcase and was able to see the same behavior.

    First of all, We don’t recommend doing a software write to the TBCTR directly and it can lead to inconsistent results just like the one you are seeing.

    Incidentally, this is not just a debug behavior and occurs without the debugger in picture as well. Just that you are not noticing it. Also this behavior of the unexpected TBCTR is not restricted to when the counter is counting down. It can happen when the counter is counting up and if you are trying to software force the TBCTR to TBPRD.

    Forcing the TBCTR as 0 or TBPRD via software, will have consequences of missing the CTR = 0 and CTR =PRDEQ events.

    One way to avoid this in your case is to make TBCTR = 1 (in you case instead of 0).

    Please click on the “verify answer” button if this fix resolves your issue.

    Thanks & Regards

    Pramod

     

  • Hi,Pramod

    Thank you very much for your timely reply.

  • Hi ,Pramod

    Could pleasure help me with another question?,It is also about PWM.

    The links are as follows

    Thanks & Regards

  • Hi Soldier76,

    Myself and my collegue will look into it and get back to you with a response. I am locking this thread as this has been resolved. We can continue on the other thread itself.

    Thanks & Regards

    Pramod