这是禁用 PIC24 中断的安全方法吗?

Is this a safe way to disable interrupts on PIC24?

我正在从事一个使用 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 在 read txLen 期间偶尔会被调用,因此 copyOfTxLen 最终成为 txLen 在调用 ISR 之前,但关键部分的其余部分看到的变量处于调用 ISR 之后的状态。

问题:我的代码有问题吗?如果是,如何避免故障?

一些背景:

问题中的代码有误。 要修复它,请将旨在禁用中断的表达式包装在这样的宏中,例如 IEC1bits.U2TXIE = 0

__write_to_IEC(IEC1bits.U2TXIE = 0);

XC16 compiler release notes 说:

__write_to_IEC(X) - a macro that wraps the expression X with an appropriate number of nop instructions to ensure that the write to the IEC register has taken effect before the program executes. For example, __write_to_IEC(IEC0bits.T1IE = 0); will not progress until the device has disabled the interrupt enable bit for T1 (Timer1).

在XC16编译器自带的p24FJ256GA702.h中定义了宏:

#define __write_to_IEC(X) \
   ( (void)(X), \
     __builtin_nop() \
   )

因此,尽管 PIC24FJ256GA705 FAMILY datasheet or in the separate Interrupts document 中的任何地方都没有提及,但很明显这张图片需要一个 NOP

更新:我在 dsPIC33EP256MU806(dsPIC33E 系列)上发现了完全相同的问题,它需要两条 NOP 指令。