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.

[参考译文] TMS320F280049:CPU 带宽较高时缺少 ISR

Guru**** 2040210 points
Other Parts Discussed in Thread: C2000WARE
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/972003/tms320f280049-missing-isr-when-cpu-bandwidth-is-high

器件型号:TMS320F280049
主题中讨论的其他器件:C2000WARE

您好专家、

我的客户正在使用 ePWM 载波以连续模式触发 ADC ISR、而 ADC ISR 在2.5us 间隔内触发。

当它们在 ISR 中添加代码时、我们可以发现 ISR 将在 ISR 执行时间接近2.3us 时丢失(彼此跳过)。

在我们的侦察中、我们仍有0.2 us 的时间用于进入和退出 ISR、但为什么我们在这个负载下开始错过 ISR?

我们用 GPIO 切换、将 ISR - GPIO 输入为高电平、将 ISR GPIO 输出为低电平来标记 CPU 执行。 在本例中、我们可以了解运行 ISR 需要多长时间以及是否缺少 ISR。 (在正常情况下、高 ISR/CPU 负载、我们应该会看到 GPIO 上的低电压较窄)

您能帮我们进一步了解它是否正常? 为什么?

谢谢

谢尔登

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Sheldon、

    根据您所说的内容、似乎由于以下原因之一而跳过 ISR:

    1. PIEIFR 被软件清零。 如果在软件中清除 PIEIFR、则可能会丢失中断、这就是为什么永远不应在软件中清除中断的原因。 相反、您应该让 CPU 获取中断以使其清除。 请检查您的代码中正在修改 PIEIFR 的所有实例、并确保没有地方可以通过软件手动清除 PIEIFR。

    2.意外的嵌套中断。 默认情况下、不能嵌套中断。 如果在 ISR 中更改了全局优先级或组优先级、则可能会无意中嵌套中断。 有关我通过嵌套中断描述的内容的更多信息、请在 C2000Ware 中查看中断嵌套文档:  \docs\C28x_interrupt_besting\html\index.html。

    3.如果您每次在 CCS 中单步执行一行代码、可能会发生一些奇怪的行为。 如果使用调试器、请删除所有断点并让程序自由运行、然后查看这是否也解决了问题。

    这些是我可以认为可能导致完全错过中断的主要原因、因此请在您检查这些内容后告知我、这是否可以解决您的问题! 唯一真正的另一种可能是触发器本身不会发生、但只要您正确配置了 ADC/ePWM ISR 及其设置、就可能不会发生此问题。

    此致、

    Vince

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vince:

    对于第2点和第3点、我们的代码中没有以下设置。

    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    PieCtrlRegs.PIEACk.bit.ACK1=1; 

    我们的事情做得正确吗?

    谢谢

    谢尔登

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Sheldon、

    如果该代码位于 ISR 末尾、则看起来正确。

    我还想说的是、假设 ISR 只剩下0.2us 的时间、并且您使用的是20MHz 时钟频率、那么对于 ISR 所需的时间、有一件事可以发挥作用:

       从技术上讲、仅中断内部部分的中断延迟最多可以达到32个周期(考虑到最小14个周期+ 8个定点推入+ 10个浮点推入)。 在20MHz 频率下、这将是~1.6us。 这意味着在这段时间内一个较高优先级的中断有可能挤占。 如果考虑 RPT 指令、多周期指令、等待内存中的代码执行等项目、从技术上讲、周期数可能会更高

    要检查是否存在这种情况、是否确定中断不是在另一个中断之后发生? 这意味着您是否看到 ISR 刚刚发生得晚? 还是真的完全被跳过了?

    我还不知道会像您描述的那样导致中断丢失、那么您能提供更多详细信息吗?

    1. 要确保使用了嵌套中断、还是未使用?
    2. 您能否提供代码中 PIEACk.bit.ACK1行发生位置的上下文?
    3. 您能否提供有关您拥有的 ePWM 和 ADC 设置的更多详细信息? 根据我的理解、您每2.5us 使用 ePWM 触发一次 ADC SOC。 如果我理解正确、ADC 转换本身将花费2.3us。 您会说、如果转换超过2.2us (接近2.3us)、则为 ePWM  
    4. 您能否澄清以下引述的含义? ePWM 是否变为2.3us? 为什么 ISR 执行时间会改变? [引用]当 ISR 中添加代码时、我们可以发现 ISR 在 ISR 执行时间接近2.3us 时会丢失(彼此跳过)。
    5. 您可以提供的任何其他信息和详细信息也会很好、有助于进一步调试!

    此致、

    Vince

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vince:

    感谢您在此处提供非常详细的解释!

    我们已经看到 ISR 完全跳过、而不是只是晚了。

    我们在这里不使用嵌套 ISR、代码中只有一个 ISR、配置如下所示:

    EALLOW;
    PieVectTable.ADCA1_INT =&adca_ISR;
    EDIS;
    
    EALLOW;
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;//启用 PIE 块
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;//启用 ADCA1中断
    //PieCtrlRegs.PIEIER1.bit.INTx3=1;//启用 ADCC1中断
    EDIS;
    
    IER |= M_INT1;
    EINT;
    ERTM; 

    关于 ACK1的上下文、请参阅下面的 ISR:

    // ADC 中断服务例程、由 ADC EOC
    #pragma CODE_SECTION (adca_ISR、".TI.ramfunc")
    _interrupt void adca_ISR (void)
    {
    GpioDataRegs.GPASET.BIT.GPIO7 = 1;
    
    // AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    // PieCtrlRegs.PIEACK.bit.ACK1 = 1;
    // ADC 输入范围= 0到4096
    //使用偏移减法,范围将为-2048到+2047
    InputADC =(Int16_t)(AdcResultRegs.ADCRESULT0 - ADC_OFFSET); // offset
    
    // temp_val[0]=(uint16)(single_Turn >> 16);
    // temp_val[1]=(uint16) single_Turn;
    //强制 CLA 任务
    // Cla1ForceTask1 ();
    
    #ifdef 欠采样
    switch (demo_i){
    情况0:
    DualFilter.InFilter1 = 0;
    DualFilter.InFilter2 = InputADC;
    DEMO_I = 1;
    中断;
    案例1:
    DualFilter.InFilter1 = InputADC;
    DualFilter.InFilter2 = 0;
    DEMO_I = 2;
    中断;
    案例2:
    DualFilter.InFilter1 = 0;
    DualFilter.InFilter2 =-InputADC;
    DEMO_I = 3;
    中断;
    案例3:
    DualFilter.InFilter1 =-InputADC;
    DualFilter.InFilter2 = 0;
    DEMO_I = 0;
    中断;
    }
    其他
    DualFilter.InFilter1 =(Int16_t)((InputADC * sinVal[demo_i])>> 19);
    DualFilter.InFilter2 =(Int16_t)((InputADC * cosVal[demo_i])>> 19);
    
    
    DEMO_I++;
    DEMO_I =(DEMO_I <= 7)? DEMO_I:0;
    #endif
    
    DualFIRCAL_V1 (DualFilter);
    
    #ifndef Algorithm2//
    OutFilter1_CPU_TO_CLA = DualFilter.OutFilter1;
    // OutFilter2_CPU_TO_CLA = DualFilter.OutFilter2;
    Theta =__atan2puf32 (((float) DualFilter.OutFilter1、(float) DualFilter.OutFilter2);
    
    单个=(单个和0x1E0000)+θ* 131071 + 5535;
    
    if (pre_theta > 98304 && tmp_theta < 32767)
    单通道=单通道+ 131072;
    否则{
    if (tmp_theta > 98304 && pre_theta < 32767)
    单个=单个- 131072;
    }
    
    pre_theta = tmp_theta;
    
    
    #else
    switch (demo_i2){
    情况0:
    DualFilter2.InFilter1 = 0;
    DualFilter2.InFilter2 = 0;
    DEMO_i2 = 1;
    中断;
    案例1:
    DualFilter2.InFilter1 = DualFilter.OutFilter1;
    DualFilter2.InFilter2 = DualFilter.OutFilter2;
    DEMO_i2 = 2;
    中断;
    案例2:
    DualFilter2.InFilter1 = 0;
    DualFilter2.InFilter2 = 0;
    DEMO_i2 = 3;
    中断;
    案例3:
    DualFilter2.InFilter1 =-DualFilter.OutFilter1;
    DualFilter2.InFilter2 =-DualFilter.OutFilter2;
    DEMO_i2 = 0;
    中断;
    }
    
    DualFIRCALC_V1 (DualFilter2);
    
    OutFilter1_CPU_TO_CLA =(浮点) DualFilter2.OutFilter1;
    OutFilter2_CPU_TO_CLA =(浮点) DualFilter2.OutFilter2;
    #endif
    
    temp_val[0]=(UINT16)(单路>> 16);
    temp_val[1]=(uint16)单通道;
    
    //重新初始化中断
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    PieCtrlRegs.PIEACk.bit.ACK1=1;
    GpioDataRegs.GPACLEAR.bit.GPIO7=1;
    } 

    要继续...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、我每2.5us 触发一次具有 ePWM 的 ADC SOC。

    ePWM 设置为:

    // EPWM1 A/B 和 EPWM2 A/B 执行 SVPWM 输出
    // EPWM3 SOCA 触发 ADC S + H
    void ConfigureEPWM (void)
    {
    // PWM 时钟设置为100MHz,愚蠢的复位值
    EPwm1Regs.TBCTL.bit.CLKDIV = 0;
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADODE;//必须使用影子模式
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    
    EPwm2Regs.TBCTL.bit.CLKDIV = 0;
    EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0;
    EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADODE;//必须使用影子模式
    EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    
    EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADODE;//必须使用影子模式
    EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm3Regs.TBCTL.bit.CLKDIV = 0;
    EPwm3Regs.TBCTL.bit.HSPCLKDIV = 0;
    
    EPwm4Regs.TBCTL.bit.CLKDIV = 7; //设置/128
    EPwm4Regs.TBCTL.bit.HSPCLKDIV = 5; //设置/10
    EPwm4Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; //必须使用阴影模式
    EPwm4Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    
    //停止 ePWM 时钟
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC=0;
    EDIS;
    
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; //反向向上向下计数模式
    
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; //主设备:CTR = 0时输出 SYNC 信号
    EPwm1Regs.TBPRD = PERIOD_50K_UD; //载波周期
    EPwm1Regs.CMPA.bit.CMPA = PERIOD_50K_UD / 2;
    EPwm1Regs.CMPB.bit.CMPB = PERIOD_50K_UD / 2;
    
    EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;
    EPwm1Regs.AQCTLA.bit.CBD = AQ_CLEAR;
    EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR;
    EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;
    
    EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE;
    EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;//计数器向上向下计数模式
    
    EPwm2Regs.TBPRD = PERIOD_50K_UD; //载波周期
    EPwm2Regs.CMPA.bit.CMPA = PERIOD_50K_UD / 2;
    EPwm2Regs.CMPB.bit.CMPB = PERIOD_50K_UD / 2;
    
    EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
    EPwm2Regs.AQCTLA.bit.PRD = AQ_SET;
    EPwm2Regs.AQCTLB.bit.ZRO = AQ_SET;
    EPwm2Regs.AQCTLB.bit.PRD = AQ_CLEAR;
    
    EPwm3Regs.TBCTL.bit.PHSEN = TB_DISABLE;
    
    EPwm3Regs.ETSEL.bit.SOCAEN = 1; //启用 EPWMxSOCA 脉冲
    EPwm3Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; //在向上计数时选择 SOC
    EPwm3Regs.ETPS.bit.SOCAPRD = ET_1ST; //在第1个偶数时生成脉冲
    EPwm3Regs.ETCNTINITCTL.bit.SOCAINITEN = 1;
    
    EPwm3Regs.TBPRD = Sampling_RATE 400K; //设置采样率
    
    EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; //递增计数模式
    EPwm3Regs.CMPA.bit.CMPA = 10;
    // EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET;
    // EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
    
    EPwm4Regs.ETSEL.bit.SOCAEN = 1;//启用 EPWMxSOCA 脉冲
    EPwm4Regs.ETSEL.bit.SOCASEL = 1;//在递增计数时选择 SOC
    EPwm4Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;//计数器递增模式
    EPwm4Regs.ETPS.bit.SOCAPRD = 1; //在发生第一个事件时生成脉冲
    EPwm4Regs.TBPRD = 39061; // SOC 为2Hz
    
    } 

    ADC 配置:

    void ConfigureADC (void)
    {
    // ADC
    SetVREF (ADC_ADCA、ADC_EXTERNAL、ADC_VREF2P5);
    EALLOW;
    AdcaRegs.ADCCTL2.bit.prescale = 6; //除以4
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;// EOC 中断脉冲
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; //已通电
    DELAY_US (1000); //等待初始化
    
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 2; // SOC0将转换引脚 A2
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 39; //采样窗口为40个 SYSCLK 周期
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 9;//在 ePWM3 SOCA 上触发
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0;// EOC0将设置 INT1标志
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;//启用 INT1标志
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;//确保 INT1标志被清除
    EDIS;
    
    // ADC 测量温度
    SetVREF (ADC_ADCC、ADC_EXTERNAL、ADC_VREF2P5);
    EALLOW;
    AdccRegs.ADCCTL2.bit.prescale = 6; //除以4
    AdccRegs.ADCCTL1.bit.INTPULSEPOS = 1;// EOC 中断脉冲
    AdccRegs.ADCCTL1.bit.ADCPWDNZ = 1; //已通电
    DELAY_US (1000); //等待初始化
    
    AdccRegs.ADCSOC1CTL.bit.CHSEL = 0; // SOC1将转换引脚 C0
    AdccRegs.ADCSOC1CTL.bit.ACQPS = 99; //采样窗口为100个 SYSCLK 周期
    AdccRegs.ADCSOC1CTL.bit.TRIGSEL = 11;//在 ePWM4 SOCA 上触发
    AdccRegs.ADCINTSEL1N2.bit.INT1SEL = 0;// EOC1将设置 INT1标志
    AdccRegs.ADCINTSEL1N2.bit.INT1E = 0;//启用 INT1标志
    AdccRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;//确保 INT1标志被清除
    EDIS;
    } 

    为了回答问题3、我们的 ePWM 触发器始终是固定的、变量是我们希望在 ISR 中执行的操作量或我们希望在 ISR 中运行的代码量。 ISR 检测时间随我们在每个构建中添加的内容而变化。 在同一个构建中、ISR 执行时间是固定的。

    我想澄清一下、ADC 转换本身非常短、即在 ADC ISR 中运行的代码会耗费大量时间。

    BTW、我们以100M 系统时钟运行、中断进入时间可能长达0.32us。 我的理解是否正确?

    谢谢

    谢尔登

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Sheldon、

    感谢详细的跟进! 感谢您提供 ISR 代码、因为这现在澄清了中断进入时间+ ISR 时间可能是导致这种情况的原因。 我将在内部对此进行讨论、并将在星期二之前回复您。

    此致、

    Vince

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Sheldon、

    在讨论之后、您可能会在另一个中断仍在处理时(如果我正确理解了您的问题)通过写入 ADC 中断缓冲区而使其溢出。 换句话说、如果您的中断请求(req2)在第一个请求(req1)正在处理时进入、那么在中断结束时、两个标志都会被清除。

    编辑:此外、我想指出、如果由于等待状态存储器、 RPT 指令、多周期指令等而导致流水线延迟、那么理论上前面提到的周期数(32)可能会更高 因此、中断本身(从请求到完成执行)的时间肯定会超过2.5us。 例如、如果它是前面提到的最少32个周期、那么0.32us 将用于进入、加上 ISR 进程本身的2.3us、这将比2.5us 周期长。 必须认识到这些项目。

    请告诉我、这是否提供了一点更清晰的信息。

    此致、

    Vince

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vince:

    感谢您的详细解释和跟进。 我想我现在对此很清楚。

    谢尔登