TMS320F280025: Modify the value of the PHSDIR register within an interrupt service routine.

Part Number: TMS320F280025

Can the value of the PHSDIR register be modified in real time within an interrupt? I have attempted this and found that the corresponding ePWM module directly outputs a high level instead of a PWM signal with a specific duty cycle. If the value of PHSDIR is not modified in the interrupt service routine, a normal PWM signal can be generated properly.

  • Hello, we have received your case and the investigation will take some time. Thank you for your patience.

  • The value of PHSDIR can be modified within the interrupt. Can you be more specific about the particular condition that you were looking into. What was the configuration for action qualifier and the compare values? At what instant of the time period were you modifying the PHSDIR? Were you using up-down count mode?

  • Thank you for your reply.

    The issue I am currently facing is as follows: I am using a PWM wave with a fixed 50% duty cycle, controlled by phase shifting. However, I have found that the PWM can only perform normal phase shifting if TB_DOWN is written to the PHSDIR register during initialization.

    Conversely, if the PHSDIR register is initially set to TB_UP and then modified to TB_DOWN in an interrupt, the corresponding PWM will abnormally change from a 50% duty cycle to 100% duty cycle. Could you please explain the cause of this problem?

    The initialization code I used is attached. Among them, ePWM2 is the master ePWM, and ePWM1 is the slave ePWM.

    void Config_Epwm1()
    {
        EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;  //上下计数模式
        EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;        // 1分频(100M)
        EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
    
        EPwm1Regs.TBPRD = cPwmTBPRD;
        EPwm1Regs.TBCTR = 0x0000;
        EPwm1Regs.TBPHS.bit.TBPHS = 250;
        EPwm1Regs.TBCTL.bit.PHSEN = 1;
        EPwm1Regs.TBCTL.bit.PRDLD=TB_SHADOW;
        EPwm1Regs.TBCTL.bit.PHSDIR  = TB_DOWN;            //相移方向
        EPwm1Regs.EPWMSYNCINSEL.bit.SEL = 2;
    
    
        EPwm1Regs.CMPA.bit.CMPA = 384;
        EPwm1Regs.CMPB.bit.CMPB = 384;
    
    
        EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;     //影子寄存器
        EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;   // 计数到0时装载
        EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
    //    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; 
    //    EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;   
    //    EPwm1Regs.AQCTLB.bit.CAU = AQ_SET;              
    //    EPwm1Regs.AQCTLB.bit.CAD = AQ_CLEAR;           
    
    
        EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;            
        EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;          
        EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR;         
        EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET;            
    
    
    //    EPwm1Regs.DBCTL.bit.OUT_MODE = 0x3; // 使能死区
    //    EPwm1Regs.DBCTL.bit.POLSEL = 0x0;   // 极性选择
    //    EPwm1Regs.DBRED.bit.DBRED = 50;     // 上升沿死区时间
    //    EPwm1Regs.DBFED.bit.DBFED = 50;     // 下降沿死区时间
    
        EALLOW;
    
        EPwm1Regs.GLDCTL.bit.GLD = 1;//使能全局加载影子寄存器
        EPwm1Regs.GLDCTL.bit.GLDMODE = 0;//计数为0时装载
        EPwm1Regs.GLDCTL.bit.OSHTMODE = 1;//单次装载模式启动
    
    
        EPwm1Regs.GLDCFG.bit.CMPA_CMPAHR = 1;
        EPwm1Regs.GLDCFG.bit.CMPB_CMPBHR = 1;
        EPwm1Regs.GLDCFG.bit.TBPRD_TBPRDHR =1 ;
    
        EDIS;
    
        EPwm1Regs.DBRED.bit.DBRED = 20;
        EPwm1Regs.DBFED.bit.DBFED = 20;
    
        EPwm1Regs.DBCTL.bit.IN_MODE = DBB_ALL;
        EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;
        EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
        EPwm1Regs.DBCTL.bit.LOADREDMODE= CC_CTR_ZERO;
        EPwm1Regs.DBCTL.bit.LOADFEDMODE= CC_CTR_ZERO;
        EPwm1Regs.DBCTL.bit.SHDWDBREDMODE= CC_SHADOW;
        EPwm1Regs.DBCTL.bit.SHDWDBFEDMODE= CC_SHADOW;
    
        // EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;//计数到0时触发中断
        // EPwm1Regs.ETSEL.bit.INTEN = 1;//使能中断
        // EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;
    
        EALLOW;
        EPwm1Regs.GLDCTL2.bit.OSHTLD = 1;//产生一次事件后就触发中断
        EDIS; 
    
        EPwm1Regs.EPWMXLINK.bit.GLDCTL2LINK = 1;//链接到EPWM2
        EPwm1Regs.EPWMXLINK.bit.CMPALINK = 1;
        EPwm1Regs.EPWMXLINK.bit.CMPBLINK = 1;
        EPwm1Regs.EPWMXLINK.bit.TBPRDLINK = 1;
    
    }
    
    
    
    void Config_Epwm2()
    {
        EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;  // 增减计数
        EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
        EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
    
        EPwm2Regs.TBPRD = cPwmTBPRD;
        EPwm2Regs.TBCTR = 0x0000;
        EPwm2Regs.TBPHS.bit.TBPHS = 0;
        EPwm2Regs.TBCTL.bit.SWFSYNC = 1;
        EPwm2Regs.TBCTL.bit.PHSEN = 0;
        EPwm2Regs.TBCTL.bit.PRDLD=TB_SHADOW;
        EPwm2Regs.EPWMSYNCOUTEN.bit.ZEROEN = 1;
    
        EPwm2Regs.CMPA.bit.CMPA = 384;
        EPwm2Regs.CMPB.bit.CMPB = 384;
    
        EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;     // 影子寄存器
        EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;   // 计数到0装载
        EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
    //    EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;            
    //    EPwm2Regs.AQCTLA.bit.CAD = AQ_SET;              
    //    EPwm2Regs.AQCTLB.bit.CAU = AQ_SET;              
    //    EPwm2Regs.AQCTLB.bit.CAD = AQ_CLEAR;           
    
    
        EPwm2Regs.AQCTLA.bit.CAU = AQ_SET;            // 计数上升到比较值置高
        EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR;          // 0时置低
        EPwm2Regs.AQCTLB.bit.CAU = AQ_CLEAR;          //计数上升到比较值置高
        EPwm2Regs.AQCTLB.bit.ZRO = AQ_SET;            //0时置低
    
     
    //    EPwm2Regs.DBCTL.bit.OUT_MODE = 0x3; // 使能死区
    //    EPwm2Regs.DBCTL.bit.POLSEL = 0x2;   // 改变极性
    //    EPwm2Regs.DBRED.bit.DBRED = 50;     // 上升沿延迟时钟周期
    //    EPwm2Regs.DBFED.bit.DBFED = 50;
    
        EALLOW;
    
        EPwm2Regs.GLDCTL.bit.GLD = 1;//使能全局加载影子寄存器
        EPwm2Regs.GLDCTL.bit.GLDMODE = 0;//计数为0时加载
        EPwm2Regs.GLDCTL.bit.OSHTMODE = 1;//一次装载模式(one shoot mode)启动
    
    
        EPwm2Regs.GLDCFG.bit.CMPA_CMPAHR = 1;
        EPwm2Regs.GLDCFG.bit.CMPB_CMPBHR = 1;
        EPwm2Regs.GLDCFG.bit.TBPRD_TBPRDHR =1 ;
    
        EDIS;
    
        EPwm2Regs.DBRED.bit.DBRED = 20;
        EPwm2Regs.DBFED.bit.DBFED = 20;
    
        EPwm2Regs.DBCTL.bit.IN_MODE = DBB_ALL;
        EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;
        EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
        EPwm2Regs.DBCTL.bit.LOADREDMODE= CC_CTR_ZERO;
        EPwm2Regs.DBCTL.bit.LOADFEDMODE= CC_CTR_ZERO;
        EPwm2Regs.DBCTL.bit.SHDWDBREDMODE= CC_SHADOW;
        EPwm2Regs.DBCTL.bit.SHDWDBFEDMODE= CC_SHADOW;
    
        // EPwm2Regs.ETSEL.bit.INTSEL = 3;//计数器等于0或周期时触发
        // EPwm2Regs.ETSEL.bit.INTEN = 1;//中断使能
        // EPwm2Regs.ETPS.bit.INTPRD = ET_1ST;//每次事件都产生中断
    
       EPWM_setInterruptSource(EPWM2_BASE, EPWM_INT_TBCTR_ZERO_OR_PERIOD);
       EPWM_enableInterrupt(EPWM2_BASE);
       EPWM_setInterruptEventCount(EPWM2_BASE, 3);
    
    
        EPwm2Regs.ETSEL.bit.SOCAEN = 1;//使能ADC采样
        EPwm2Regs.ETSEL.bit.SOCASEL = 1;//计数器达到0时触发
        EPwm2Regs.ETPS.bit.SOCAPRD = 3;//每3次事件都产生一次采样
    
        EALLOW;
        EPwm2Regs.GLDCTL2.bit.OSHTLD = 1;//允许一次脉冲加载事件初始化
        EDIS; 
    
    }
    

  • What is the value of cPwmTBPRD? I am confused how are these AQCTLA and AQCLB configuration giving 50% duty cycle as it modifies at TBCTR=CMPA and TBTR=0 with up-down counter. One reason for missing a pulse is counter not reaching CMPA=384 when it transitions from PHSDIR=UP to PHSDIR=DOWN. Are you continuously updating the PHSDIR bit in every ISR, if yes is it updated with the same value. Can you also share the ISR part of the code where are you updating the PHSDIR bit and the waveform for the PWM signal.

  • Thank you for your reply. The answers to your questions are as follows:
    (1) The value assigned to TBPRD is kept consistent with those of CMPA and CMPB, since the project requires a 50% duty cycle on the premise of phase‑shifted frequency conversion. However, my search on the E2E forum found that triggering Action-Qualifier actions using CAU and CAD will limit the phase-shift range. It seems that the Action-Qualifier actions will be skipped once the value of TBPHS exceeds that of CMPA. Based on this, ZRO and CMPA are used in the code to trigger the Action-Qualifier operations.
    (2) The code used is attached. Once this code runs — that is, when case 1 in the switch statement is executed — EPWM3, EPWM4, EPWM5 and EPWM6 will output a sustained high level.
                       case 1:
                     {
    
    
                         EPwm3Regs.TBCTL.bit.PHSDIR  = TB_UP;
                         EPwm4Regs.TBCTL.bit.PHSDIR  = TB_UP;
                         EPwm5Regs.TBCTL.bit.PHSDIR  = TB_UP;
                         EPwm6Regs.TBCTL.bit.PHSDIR  = TB_UP;
      
                         
                         EPwm1Regs.TBPRD = fs_light_TBPRD;
                         EPwm2Regs.TBPRD = fs_light_TBPRD;
                         EPwm3Regs.TBPRD = fs_light_TBPRD;
                         EPwm4Regs.TBPRD = fs_light_TBPRD;
                         EPwm5Regs.TBPRD = fs_light_TBPRD;
                         EPwm6Regs.TBPRD = fs_light_TBPRD;
    
                        
                         EPwm1Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                         EPwm1Regs.CMPB.bit.CMPB = fs_light_TBPRD;
                         EPwm2Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                         EPwm2Regs.CMPB.bit.CMPB = fs_light_TBPRD;
    
    
                        
                         if (spll1 .sine> 0.0f)
                             {
    
                                 
                                 EPWM_setDeadBandDelayMode(EPWM3_BASE,EPWM_DB_RED,true);
                                 EPWM_setDeadBandDelayMode(EPWM3_BASE,EPWM_DB_FED,true);
                                 EPWM_setActionQualifierContSWForceAction(EPWM3_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_DISABLED);
    
    
                                 EPwm3Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                                 EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;           
                                 EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET;              
                                 EPwm3Regs.DBCTL.bit.OUT_MODE = 0x3; 
                                 EPwm3Regs.DBCTL.bit.POLSEL = 0x0;   
                                 EPwm3Regs.DBRED.bit.DBRED = 20;    
                                 EPwm3Regs.DBFED.bit.DBFED = 20;    
    
    
                                
                                 EPWM_setDeadBandDelayMode(EPWM5_BASE,EPWM_DB_RED,true);
                                 EPWM_setDeadBandDelayMode(EPWM5_BASE,EPWM_DB_FED,true);
                                 EPWM_setActionQualifierContSWForceAction(EPWM5_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_DISABLED);
    
    
                                 EPwm5Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                                 EPwm5Regs.AQCTLA.bit.CAU = AQ_SET;         
                                 EPwm5Regs.AQCTLA.bit.ZRO = AQ_CLEAR;              
                                 EPwm5Regs.AQCTLA.bit.CAD = AQ_NO_ACTION;
                                 EPwm5Regs.AQCTLA.bit.PRD = AQ_NO_ACTION; 
                                 EPwm5Regs.DBCTL.bit.OUT_MODE = 0x3; 
                                 EPwm5Regs.DBCTL.bit.POLSEL = 0x2;   
                                 EPwm5Regs.DBRED.bit.DBRED = 20;    
                                 EPwm5Regs.DBFED.bit.DBFED = 20;
    
                                
                                 EPWM_setDeadBandDelayMode(EPWM4_BASE,EPWM_DB_RED,false);
                                 EPWM_setDeadBandDelayMode(EPWM4_BASE,EPWM_DB_FED,false);
                                 EPWM_setActionQualifierContSWForceAction(EPWM4_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_OUTPUT_HIGH);
    
    
                                 
                                 EPWM_setDeadBandDelayMode(EPWM6_BASE,EPWM_DB_RED,false);
                                 EPWM_setDeadBandDelayMode(EPWM6_BASE,EPWM_DB_FED,false);
                                 EPWM_setActionQualifierContSWForceAction(EPWM6_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_OUTPUT_HIGH);
    
    
                             }
                             else if(spll1.sine < 0.0f)
                             {
    
                                
                                 EPWM_setDeadBandDelayMode(EPWM3_BASE,EPWM_DB_RED,false);
                                 EPWM_setDeadBandDelayMode(EPWM3_BASE,EPWM_DB_FED,false);
                                 EPWM_setActionQualifierContSWForceAction(EPWM3_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_OUTPUT_HIGH);
    
    
                                 
                                 EPWM_setDeadBandDelayMode(EPWM5_BASE,EPWM_DB_RED,false);
                                 EPWM_setDeadBandDelayMode(EPWM5_BASE,EPWM_DB_FED,false);
                                 EPWM_setActionQualifierContSWForceAction(EPWM5_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_OUTPUT_HIGH);
    
    
                                
                                 EPWM_setDeadBandDelayMode(EPWM4_BASE,EPWM_DB_RED,true);
                                 EPWM_setDeadBandDelayMode(EPWM4_BASE,EPWM_DB_FED,true);
                                 EPWM_setActionQualifierContSWForceAction(EPWM4_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_DISABLED);
    
    
                                 EPwm4Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                                 EPwm4Regs.AQCTLA.bit.CAU = AQ_SET;            
                                 EPwm4Regs.AQCTLA.bit.ZRO = AQ_CLEAR;           
                                 EPwm4Regs.DBCTL.bit.OUT_MODE = 0x3; 
                                 EPwm4Regs.DBCTL.bit.POLSEL = 0x2;   
                                 EPwm4Regs.DBRED.bit.DBRED = 20;    
                                 EPwm4Regs.DBFED.bit.DBFED = 20;
    
                               
                                 EPWM_setDeadBandDelayMode(EPWM6_BASE,EPWM_DB_RED,true);
                                 EPWM_setDeadBandDelayMode(EPWM6_BASE,EPWM_DB_FED,true);
                                 EPWM_setActionQualifierContSWForceAction(EPWM6_BASE,EPWM_AQ_OUTPUT_A,EPWM_AQ_SW_DISABLED);
    
    
                                 EPwm6Regs.CMPA.bit.CMPA = fs_light_TBPRD;
                                 EPwm6Regs.AQCTLA.bit.CAU = AQ_CLEAR;           
                                 EPwm6Regs.AQCTLA.bit.ZRO = AQ_SET;              
                                 EPwm6Regs.DBCTL.bit.OUT_MODE = 0x3; 
                                 EPwm6Regs.DBCTL.bit.POLSEL = 0x0;   
                                 EPwm6Regs.DBRED.bit.DBRED = 20;    
                                 EPwm6Regs.DBFED.bit.DBFED = 20;    
                             }
    
    
                          
    
                             EPwm1Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_in_light;
                             EPwm3Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
                             EPwm4Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
                             EPwm5Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
                             EPwm6Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
    
                             EALLOW;
                             EPwm2Regs.GLDCTL2.bit.OSHTLD = 1;              
                             EDIS;
    
                     }
                     break;
                     }                         
                             EPwm4Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
                             EPwm5Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
                             EPwm6Regs.TBPHS.bit.TBPHS = fs_light_TBPRD*phi_out_light;
    
    
    
                             EALLOW;
                             EPwm2Regs.GLDCTL2.bit.OSHTLD = 1;             
                             EDIS;
    
                     }
                     break;
    
  • Root cause of this mismatch between immediate and shadowed registers shown in table below is what causes the problem if you write them in the wrong order.

    Register Type Takes Effect
    TBCTL (PHSDIR, CTRMODE) Immediate Right when written
    TBPHS Immediate Right when written
    TBPRD Shadowed Next CTR=0 (or global load)
    CMPA, CMPB Shadowed Next CTR=0 (or global load)
    AQCTLA, AQCTLB Immediate Right when written
    AQCSFRC (software force) Immediate Right when written
    DBCTL Immediate Right when written
    DBRED, DBFED Shadowed Next CTR=0

    So the correct order need to be as follows in order to avoid the mismatch in the ePWM reconfiguration sequence in an ISR

    When reconfiguring ePWM settings (PHSDIR, AQ, Dead Band, CMPA, TBPRD) inside an interrupt service routine, the following 7-step sequence must be followed to prevent the output from becoming stuck at a sustained HIGH level. The root cause of the problem is that some registers take effect immediately when written, while others are buffered in shadow registers and only load at the next counter zero event. Writing them in the wrong order creates a window where the ePWM is partially configured, causing the output latch to get stuck HIGH.


    Step 1 — AQ Submodule: Apply Software Force (Safety Gate)

    Before making any changes, force all outputs being reconfigured to a known LOW state using the Action Qualifier Continuous Software Force register (AQCSFRC). This freezes the physical output pin so that no AQ event can change the output while configuration is in progress. This step must happen first, before any other register is touched.

    Step 2 — TB Submodule: Write Phase Values (Immediate Registers)

    Write the new TBPHS value first, then write the new PHSDIR value. The reason TBPHS must be written before PHSDIR is that both registers take effect immediately. If a sync pulse from the master ePWM arrives during the ISR execution, the slave ePWM will load TBPHS and start counting in the PHSDIR direction at that exact moment. Writing them in this order ensures the sync pulse always uses the correct phase value and direction together, never a mismatched combination.

    Step 3 — TB and CC Submodules: Write Period and Compare Values (Shadow Registers)

    Write the new TBPRD, CMPA, and CMPB values. These registers are shadowed, meaning they are queued in a buffer and will not become active until the next counter zero event or global load event. Writing them here is safe because they do not affect the running counter immediately.

    Step 4 — AQ Submodule: Reconfigure Action Qualifier Settings

    Write the new AQCTLA and AQCTLB settings (CAU, CAD, ZRO, PRD actions). Although these registers take effect immediately, it is safe to write them at this point because the output is still held LOW by the software force applied in Step 1. The AQ latch can be in any state and it does not matter, because the force is overriding it.

    Step 5 — DB Submodule: Reconfigure Dead Band Settings

    Write the new DBCTL settings for output mode, polarity select, and input mode. These take effect immediately and are safe because the output is still forced. Then write the new DBRED and DBFED delay values. These are shadowed registers and will load together with CMPA and TBPRD at the next counter zero event.

    Step 6 — TB Submodule: Arm the Shadow Load Trigger

    Set GLDCTL2.OSHTLD = 1 (inside EALLOW/EDIS) to arm the one-shot global load for ePWM1 and ePWM2. This causes all shadowed registers (TBPRD, CMPA, CMPB, DBRED, DBFED) to load together atomically at the next counter zero event, ensuring a clean and consistent update. For ePWM3 through ePWM6, if they are configured to use standard shadow mode (CC_CTR_ZERO), their shadow registers will load automatically at the next counter zero without needing a global load trigger.

    Step 7 — AQ Submodule: Release the Software Force

    Release the software force on the ePWMs that are intended to output a PWM signal, by setting AQCSFRC back to disabled. The AQ module now takes control of the output starting from a confirmed LOW state. The counter will count up to CMPA, the CAU event will fire and set the output HIGH, and the correct PWM pattern will begin cleanly. For ePWMs that are intended to stay permanently HIGH during this operating mode (such as the freewheeling leg in a half-bridge), set the software force to FORCE HIGH here instead of disabling it.


    Optional: For Large Frequency Step Changes

    When Step 6 arms the global load and Step 7 releases the force, both happen within the same ISR execution. This means the shadow registers (CMPA, TBPRD) have not yet loaded into their active registers at the moment the force is released. They will load at the next counter zero event, which occurs after the ISR has already exited. For small or moderate frequency changes where CMPA equals TBPRD (the relationship is preserved in both old and new values), the first cycle after force release will be based on the previous values for one cycle and then update correctly. This is generally acceptable.

    However, for large frequency step changes where the old TBPRD and new TBPRD are significantly different, even one transition cycle with the old compare value may cause an abnormal output pulse. To completely eliminate this, the force release in Step 7 should be deferred to the next ISR invocation rather than the current one.

    To implement this, set a boolean flag (for example, pending_release = true) at the end of Step 6 instead of immediately releasing the force. At the very beginning of the next ISR invocation, check this flag before anything else. If the flag is set, release the software force and clear the flag. By this point, the counter zero event has already occurred and all shadow registers have loaded with the new values. The AQ then takes over using fully updated and consistent compare and period values, with no transition glitch at all.