我正在开发一个使用 Microchip 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
...
问题:我现在相当肯定 ISR 偶尔会在调用ISR 之前的read txLen
值copyOfTxLen
最终成为txLen
ISR 之前的值,但关键部分的其余部分会看到变量处于调用 ISR 之后的状态。
问题:我的代码有问题吗?如果是这样,如何避免故障?
一些背景:
- UART 以 8 MHz 的 PIC24 时钟高速(250 kBaud)运行,每 160 条指令一个字节,因此 ISR 非常繁忙,与我以前的项目相比,我认为这增加了达到竞争条件的机会。
- 我看到dsPIC33/PIC24 系列参考手册/中断,第 2.3.1 节注 2 说“在清除 GIE 位和禁用中断之间存在一个周期延迟。” 现在这是指
GIE
,不是U2TXIE
,我不确定它是否会导致我看到的问题,因为该MOV
指令是 2 周期指令。但是,这似乎是一种诱捕粗心的程序员的狡猾方法。 - 如果我尝试调试它或添加任何调试代码,那么已经非常间歇性的问题就会消失(感觉就像一个竞争条件)。我不想在
NOP
不知道为什么要添加的情况下添加一些 s,因为除非你真的修复它们,否则竞争条件总是会咬你。