我正在做一个使用微芯片PIC24FJ256GA702的项目。几天来,我一直在寻找一个带有UART代码的间歇性错误。它使用中断服务例程(ISR)传输名为char txBuff[]的缓冲区及其长度int txLen。
在主代码(即非ISR)中,我偶尔访问缓冲区以添加字节或查看要传输的字节数。为了确保主代码看到缓冲区的干净副本,它在表单中有一个关键部分:
Disable interrupts
Read and write 'txBuff' and its length 'txLen'
Enable interrupt在此PIC上有几种禁用ISR的方法。包括:使用DISI指令,或清除GIE位,或更改中断优先级级别。
但我选择清除中断,以启用IECx中特定中断位的位。在本例中,它是IEC1bits.U2TXIE,因为我使用的是UART2。我这么做是因为它很简单,它不会禁用不相关的中断,而且它在我的其他项目中一直运行良好。所以在C中,关键部分是:
IEC1bits.U2TXIE = 0;
copyOfTxLen = txLen;
...
IEC1bits.U2TXIE = 1;拆卸清单开始:
BCLR 0x9B, #7 // disable interrupt
MOV txLen, W1 // read txLen
...The problem:我现在相当肯定的是,ISR在read txLen期间偶尔会被调用,这样copyOfTxLen最终会成为调用ISR之前的txLen值,但是关键部分的其余部分会看到在调用ISR之后它们所处状态的变量。
问题:我的代码有问题吗?如果是这样,怎样才能避免错误呢?
一些背景:
GIE,而不是U2TXIE,我不确定它是否会像我看到的那样导致问题,因为MOV指令是一个2周期指令。但无论如何,这似乎是一种狡猾的方法来诱捕粗心大意的程序员。NOP,而不知道我为什么要这样做,因为除非您确实修复了它们,否则竞争条件总是会对您不利。发布于 2020-07-02 11:25:17
问题中的代码是错误的。若要修复此问题,请将用于禁用中断(如IEC1bits.U2TXIE = 0 )的表达式包装在宏中,如下所示:
__write_to_IEC(IEC1bits.U2TXIE = 0);XC16编译器发布说明说:
__write_to_IEC(X)-一个宏,它用适当数量的nop指令包装表达式X,以确保对IEC寄存器的写入在程序执行之前生效。例如,__write_to_IEC(IEC0bits.T1IE = 0);将在设备禁用中断启用位( T1,Timer1)之前不会进行。
在与p24FJ256GA702.h编译器一起提供的XC16中,定义了宏:
#define __write_to_IEC(X) \
( (void)(X), \
__builtin_nop() \
)因此,尽管在PIC24FJ256GA705族数据表或单独中断文档中没有提到任何地方,但显然这里需要一个NOP。
更新:我在dsPIC33EP256MU806 (dsPIC33E系列)上发现了同样的问题,它需要两个NOP指令。
https://stackoverflow.com/questions/62681838
复制相似问题