helixwmonkey 发表于 2014-4-10 18:40:35

【STM32F103疑问】定时器1比较输出产生2路脉冲

找到原因了。但是没有全部解决。
对于我之前提出的问题,原因是:当产生了CC2中断,且正要进入程序段2时,此时发生了CC1中断。由于CC2IF是1,则TIM1_CC的中断悬停位不会被置一,此情况如下图所示:


然而当程序段2执行后,CC2IF标志被清除,则此时来了CC1中断后,TIM1_CC的中断悬停位会被再次置一。这也是为什么从来不会进入test=5的断点。
参见我的程序:
void TIM1_CC_IRQHandler(void)
{
        vu8 test=1;
        //程序段1
        if (TIM1_CC1IF)
        {
                TIM1_CC1IF = 0;
                CCR_Mask_x += CCR_Acc_x;
                TIM1->CCR1 = CCR_Mask_x;
        }
        //程序段2:
        if (TIM1_CC2IF)
        {
                TIM1_CC2IF = 0;
                CCR_Mask_y += CCR_Acc_y;
                TIM1->CCR2 = CCR_Mask_y;
        }
        //程序段3:
        if (1==TIM1_CC1IF)//6clk
        {
                if (NVIC_GetPendingIRQ(TIM1_CC_IRQn))
                {
                        test = 2;        //说明发生了CC1中断,且硬件自动置1了Pending位。这个断点有40%的机会进入//3clk
                }
                if (!NVIC_GetPendingIRQ(TIM1_CC_IRQn))//22clk
                {
                        test = 3;        //说明发生了CC1中断,但是硬件没有置一Pending位。这个断点也有40%的机会进入
                }
        }
        //程序段4:
        if (test==1 && TIM1_CC1IF==1)
        {
                if (NVIC_GetPendingIRQ(TIM1_CC_IRQn))
                {        
                        test = 4;        //说明发生了CC1中断,且硬件置1了Pending位。这个断点有20%的机会进入
                }
                if (!NVIC_GetPendingIRQ(TIM1_CC_IRQn))
                {
                        test = 5;        //★令人同样奇怪的是,这个断点不会进入★
                }
        }
}
因此,需要采取的措施是:在进入中断,对各个CCxIF做判断之前,必须一次性把TIM1->SR读取到内存变量,然后清零SR,然后根据内存变量来判断。
于是产生了新的问题:
ISR中,第一步先要读取寄存器SR到内存变量,第二步写SR为0,其间仍然有可能硬件改变SR,即:

于是我采用了流水线指令隔离ISB + 互斥访问LDREX/STREX来保护:
void TIM1_CC_ISR(void)
{
        vu8 test=0;
        u32 TIM1_SR_mask;
__TRY_:
        TIM1_SR_mask = __LDREXH(&(TIM1->SR));
        __asm("isb");
        TIM1->SR = 1;
        if (__STREXH(0,&(TIM1->SR)))
        {
                goto __TRY_;
        }
于是出现的新问题是:即使我在LDREX和STREX之间手动添加一个测试语句TIM1->SR = 1;,STREX的执行总是成功的。
是我使用LDREX和STREX有误吗?
各位大虾求指点啊。。


=============================分割线,以下是之前发的问题,上面的问题解决的当前进度=========================
遇到一个很诡异的问题
问题描述:
芯片:STM32F103 ZET6
工程中使用TIM1的CCR1和CCR2作为输出比较模式(在TIM1_CNT和TIM1_CCRx匹配时翻转电平,并触发TIM1_CC_IRQHandler中断进行处理,即使用TIM1来输出两路不同频率的脉冲信号来控制电机)。
当一个CCR2匹配的中断到来时,进入该中断后,TIM1_CC的中断悬停位自动被硬件清零;(注意CCR1和CCR2共用一个TIM1_CC中断)
★此时又来了CCR1匹配中断,此时按照Cortex-M3技术规范,硬件应该再次置一TIM1_CC的中断悬停位;★
然而在实际使用中(使用Keil MDK, JLink连接芯片进行调试,且工程使用了DBGMCU_Config(DBGMCU_TIM1_STOP, ENABLE);来保证Core进入断点后Timer1停止运行),发现此种情况下,(称之为情况①,即——由CCR2触发了中断,在中断处理程序TIM1_CC_ISR中又发生了CCR1匹配中断),硬件有时可以自动置一TIM1_CC的中断悬停位,有时却不可以,从而导致了程序将错过一次CCR1匹配中断,在实际使用中是一个严重的问题。
在此请教的问题是:如何设置,才能在情况①下,能够让硬件一定置一TIM1_CC的中断悬停位,从而保证CCR1引起的中断能够使得本次中断结束后立即被执行?或者说,这是STM32硬件本身的问题?
这里附上我特意编写的测试工程、测试截图、和详细说明。
 

 
工程环境:Keil MDK 4.73,下载器:J-Link 4.76d
main.c 中的TIM1_CC_ISR(void)函数是故障所在的文件。
System_Init.c 是系统初始化文件。
需要说明一点:采用 CCR_Acc_x 等于 562,CCR_Acc_y 等于 18000。
如果使用相同的562或者18000,则不会出现该现象。
实际运行情况:

模拟运行Simulation亦如此:

期待各路高手能给出解答!
谢谢大家!
 


 

发表于 2014-4-11 14:08:23

RE:【STM32F103疑问】定时器1比较输出产生2路脉冲

TIM1_CC1F是一个自己定义的标志位吗?这段代码是在中断中跑的,还是在其他函数中跑的。

helixwmonkey 发表于 2014-4-11 15:42:29

回复:【STM32F103疑问】定时器1比较输出产生2路脉冲

回复第 2 楼 于2014-04-11 14:08:23发表:
TIM1_CC1F是一个自己定义的标志位吗?这段代码是在中断中跑的,还是在其他函数中跑的。
对,TIM1_CC1F是一个位带定义,指向TIM1->SR的CC1F。这段代码是在中断里的。我那个工程是特意写出来可以直接测试用的。。要是方便的话可以帮忙看一下吗。。程序很短。
 

发表于 2014-4-12 11:38:37

RE:【STM32F103疑问】定时器1比较输出产生2路脉冲

TIM1-SR只能由硬件产生,软件不能设置的。

helixwmonkey 发表于 2014-4-12 16:00:30

回复:【STM32F103疑问】定时器1比较输出产生2路脉冲

回复第 4 楼 于2014-04-12 11:38:37发表:
TIM1-SR只能由硬件产生,软件不能设置的。
 
一语道破梦中人啊~ 多谢。
那有什么办法完成对TIM1_SR同时的读和写吗。
因为我需要在将SR读取到内存变量TIM1_SR_mask中,然后再清零SR,然而在这两个操作之间,硬件仍然会改变SR的值,则TIM1_SR_mask不能如实的反应SR的正真状态。且第二句话又清零了SR,这样SR将无法被还原。
 

 
页: [1]
查看完整版本: 【STM32F103疑问】定时器1比较输出产生2路脉冲