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.
问题如下:
使用PWM1和PWM5各产生19.2KHz(52us)的中断(计数过零触发, 其他寄存器配置如下),并在中断中执行相关的算法。
当我在这两个中断中各对一个GPIO翻转来测试中断周期是否正确时,发现这两个中断的周期为一个随机变化的值(大约在50us~53us之间跳动),测试它们输出的PWM波是稳定的,duty改变符合要求。
我的程式中运行uCOS操作系统,当我把操作系统屏蔽,只跑中断程序时(main函数执行while),PWM中断周期又是稳定的52us。
我修改程式,只跑一个任务,任务不做任何事情,情况没有得到改善。
通过JTAG仿真,查看有OS和无OS时程序执行情况,观察PWM各个寄存器没有差异。
我又测试了两个中断中算法最长路径执行的时间:PWM1为11us左右,PWM5为12us左右, OS任务调度时间为5us左右,总共11+12+5=28us<52us, 中断时间有较大余量。
以上是我遇到的问题描述和处理过程,目前还没有头绪,请问大家之前是否遇到类似情况?非常感谢!
PWM配置如下(PWM1和PWM5中断使能,其他组PWM配置一致,但不使能中断):
// EPwm1Regs.TBPRD = 2083; //Set timer period: 80MHz*20.83us@19.2K
// EPwm1Regs.TBPHS.half.TBPHS = 0x00; //相位偏移0us
// EPwm1Regs.TBCTR = 0x00; //PWM计数器清零
// EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; //计数模式:上升+下降
// EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; //禁止相位偏移加载控制
// EPwm1Regs.TBCTL.bit.PHSDIR = TB_UP; //同步后向上计数
// EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; //周期值在过零时从缓冲区加载
// EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; //不输出同步信号
// EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; //计数时钟=系统时钟
// EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; //计数时钟=系统时钟
// EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; //双缓冲模式
// EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; //双缓冲模式
// EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_PRD; //周期值时加载比较值
// EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_PRD; //周期值时加载比较值
// EPwm1Regs.CMPA.half.CMPA = 1; //duty setting
// EPwm1Regs.CMPB = 1; //比较值B清零
// EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; //向上计数比较匹配清零
// EPwm1Regs.AQCTLA.bit.CAD = AQ_SET; //向下计数比较配置置位
// EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; //向上计数比较匹配清零
// EPwm1Regs.AQCTLB.bit.CBD = AQ_SET; //向下计数比较配置置位
// EPwm1Regs.AQCSFRC.all |= 0x0005; //禁止PWM输出
// EPwm1Regs.DBCTL.bit.OUT_MODE = DB_DISABLE; //PWM输出模式0:两路独立输出,disable deadtime
// EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; //Enable event TBCTR = 0
// EPwm1Regs.ETSEL.bit.INTEN = 1; //Enable EPWM1 INT generation
// EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; //1 event
Jacky
你有没有在PWM配置前加入时钟同步代码,然后在PWM配置后打开时钟使能。
//---------------------------------------------------------------------
//--- Must disable the clock to the ePWM modules if you
//--- want all ePMW modules synchronized.
//---------------------------------------------------------------------
asm(" EALLOW"); // Enable EALLOW protected register access
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
asm(" EDIS"); // Disable EALLOW protected register access
……
//---------------------------------------------------------------------
//--- Enable the clocks to the ePWM module.
//--- Note: this should be done after all ePWM modules are configured
//--- to ensure synchronization between the ePWM modules.
//---------------------------------------------------------------------
asm(" EALLOW"); // Enable EALLOW protected register access
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // TBCLK to ePWM modules enabled
asm(" EDIS"); // Disable EALLOW protected register access
首先注意一下,由于PWM1和PWM5代码几乎相同,但是PWM1和PWM5的中断优先级是不一样的,PWM1优先级高于PWM5,如果两个中断同时到来,那么CPU会先响应PWM1。
其次,你的操作代码是否有影响中断的相关代码,比如如果CPU要响应中断,需要保存一些数据。因为你描述把操作系统删除掉后,就不会影响中断周期,所以初步可以认为是操作系统影响了每次进入中断服务程序的时间。我建议你仔细检查这一点,或是上网查一下uCOS中断处理的资料。
Eric
1、 关于第1点,PWM配置的时钟同步,我是按照“0—>PWM配置代码—>1”的方式写的,和您说的一致。
2、 关于第2点,PWM1和PWM5的中断同时发生在我的程序中是允许的,因为两个中断服务程序执行的时间加起来小于52us(中断周期为52us),不会影响第2次中断的正常触发。 之前之前也怀疑是这个原因,然后尝试只使用PWM5一个PWM中断也还是有这样的问题。
3、 关于操作系统部分,使用的是timer2作为OS节拍,下面是任务堆栈保存的寄存器值,不知道有没有少了什么? 这部分似乎跟2809差异不大, 这个程序在2809上面跑没有这样的问题。
4、 在同样的程序,使用timer0和timer1定时的周期很准。
之前怀疑是PWM之间的同步引起的。如使能PWM1计数为0时发出同步信号,其他的PWM计数可以强制归0。后来我把同步的机制禁止了,没有改善。
OS_STK *OSTaskStkInit(void (*task)(void), OS_STK *ptos)
{
OS_STK *stk;
stk = ptos; //Load stack pointer
*stk++= (INTOS)0x0000; //ST0=0
*stk++= (INTOS)0x0000; //T=0
*stk++= (INTOS)0x0000; //AL=0
*stk++= (INTOS)0x0000; //AH=0
*stk++= (INTOS)0x0000; //PL=0
*stk++= (INTOS)0x0000; //PH=0
*stk++= (INTOS)0x0000; //AR0=0
*stk++= (INTOS)0x0000; //AR1=0
*stk++= (INTOS)0x0A0B; //ST1=0 Interrupts are enabled
*stk++= (INTOS)0x0000; //DP=0
*stk++= (INTOS)0x21AD; //IER
*stk++= (INTOS)0x0000; //DBGSTAT=0
*stk++= (INTOS)((uint32_t)task & 0x0000FFFF); //PC:L H
*stk++= (INTOS)((uint32_t)task >> 16);
*stk++= (INTOS)0x0A0B; //ST1=0 Interrupts are enabled
*stk++= (INTOS)0x0000; //DP=0
*stk++= (INTOS)0x0000; //RPC
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XT
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR7
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR6
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR5
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR4
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR3
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //XAR2
*stk++= (INTOS)0x0000;
*stk++= (INTOS)0x0000; //AR1H:AR0H
*stk++= (INTOS)0x0000;
stk++;
return(stk);
}