应用场合:电机控制,脉冲输出,TIM1的CH1和CH2输出2个不同频率的脉冲来控制两个电机。其他TIM有其他用处,因此不能再被使用。
问题描述:
芯片:STM32F103 ZET6
工程中使用TIM1的CCR1和CCR2作为输出比较模式(在TIM1_CNT和TIM1_CCR1、2匹配时翻转电平,并触发TIM1_CC_IRQHandler中断进行处理,以给定间隔增加CCR1和CCR2的值,从而使用TIM1来输出两路不同频率的脉冲信号来控制电机,CCR1每次增加562,CCR2每次增加18000)。
测试工程已经添加到附件,直接运行就可以到我设置的断点,表明问题已经出现。
问题所在程序段位于测试工程的stm32f10x_it.c文件中,出现问题的代码如下:
void TIM1_CC_IRQHandler(void) { unsigned char test=1; unsigned long TIM1_SR_mask; __TRY_: TIM1_SR_mask = __LDREXH(&(TIM1->SR)); TIM1->SR = 1; //即使不添加这句话,上下两个语句之间仍然可能发生SR被硬件修改的情况。可以根据进入中断test=6来证明。 if (__STREXH(0,&(TIM1->SR))) { goto __TRY_; //因为TIM1->SR被修改了,本来应该__STREXH返回失败并进入这个断点的,但是却没有进入。 } //程序段1 if (TIM1_SR_mask&(1<<1)) //CC1IF { CCR_Mask_x += CCR_Acc_x; TIM1->CCR1 = CCR_Mask_x; } //程序段2: if (TIM1_SR_mask&(1<<2)) //CC2IF { CCR_Mask_y += CCR_Acc_y; TIM1->CCR2 = CCR_Mask_y; } if (CCR_Mask_x_last2==CCR_Mask_x_last && CCR_Mask_x_last==CCR_Mask_x) { test = 6; //进入这个断点,可以说明确实会发生丢失CC1中断的情况。因为CCR1的匹配间隔为562,而CCR2的匹配间隔为18000,正常情况下绝对不会发生连续三次中断里面CCR1都相等的情况。 } CCR_Cnt_last2 = CCR_Cnt_last; CCR_Cnt_last = TIM1->CNT; CCR_Mask_x_last2 = CCR_Mask_x_last; CCR_Mask_x_last = CCR_Mask_x; }
程序解释:
程序关键代码在于__LDREXH(&(TIM1->SR));和__STREXH(0,&(TIM1->SR));
使用互斥的目的是:
在将SR读取到内存变量TIM1_SR_mask中,然后再清零SR,然而在这两个操作之间,硬件仍然会改变SR的值,则TIM1_SR_mask不能如实的反应SR的正真状态。且第二句话又清零了SR,这样SR将无法被还原。
这种情况如下所示:
在此请教的问题是:
①如何保证Exclusively Read/Write TIM1_SR?即如何保证先读寄存器TIM1_SR,然后再写TIM1_SR,在此期间是一个独占的访问?按我的理解,可以使用LDREX和STREX来实现这种功能,并写出了上述的代码,但是我的代码没有达到预期的效果。是我使用LDREX/STREX有误吗?
②我做了测试:即在LDREX和STREX之间人为的改变了TIM1->SR的值,按理来说,STREX一定会失败,但是STREX却总是成功的。难道STM32芯片不支持STREX指令?我想应该是我对这个指令的理解不够深刻,请问怎样才能正确使用这对指令来处理我现在的这个情况。
TIM1_SR_mask = __LDREXH(&(TIM1->SR));
TIM1->SR = 1;
__STREXH(0,&(TIM1->SR)); // 应该失败才对,结果还是成功的
谢谢!