Notes on Updating GPIO inside ISR for Microchip MCU
This may apply to a wide range of Microchip MCU, or even other manufactory’s MCU. But I only verified on PIC32MZ2048EFH100.
Writing to a GPIO, which is an SFR (Special Function Register, usually means it will take a few more clock cycles to complete a transaction), inside an ISR (Interrupt Service Routine) doesn’t seem to be very reliable when the very same GPIO is also updated by the other part of the main loop. This is possibly caused by the fact that writing to GPIO SFR takes multiple instructions (known as read-modify-write operation), so that the new value could be overwritten when the CPU jumps between the ISR and main loop. The Best the practice would be to update only a flag inside an ISR, and then to use the main loop to detect the flag and update the GPIO accordingly.
If updating a GPIO from within an ISR is unavoidable, e.g. in a time-sensitive application, care must be taken to ensure the very same GPIO is not accessed by the main loop immediately before or after the ISR.
Now let’s take a look at the following two seemingly same c codes to compare the read-modify-write operation:
LATASET = 1 << 7;
LATAbits.LATA7 = 1; (read-modify-write operation)
Both are trying to do the same thing: set GPIO A7 to 1.
Now let’s compare how the corresponding MIPS assembly codes actually work on the micro-controller. Open the disassembly list after compile (check out my previous post for how to generate the disassembly list)
LATASET = 1 << 7;
// disassembly list
lui v0,0xbf86 // Load value 0xBF86 to the upper 16bits of register v0
li v1,128 // Load value 128 (0xF0) to register v1
sw v1,56(v0)
// Store word of the value in v1 to 56 (0x38) offset of the value v0, refer to page 268 DS60001320H, 0x38 offset of the base 0xBF86, is 0x08 offset of the LATA virtual base, is the SET register of LATA. (Note 1 on the bottom of the page)
LATAbits.LATA7 = 1;
// disassembly list
lui v1,0xbf86 // Load value 0xBF86 to the upper 16bits of register v0
lhu v0,48(v1) // Load halfword unsigned located at 48 (0x30) offset v1, which is LATA virtual address to v0
li a0,1 // Load value 1 to register a0
ins v0,a0,0x3,0x1 // Insert bit field -> add 1 to the value of v0
sh v0,48(v1) // Store halfword of v0 to 48 (0x30) 0ffset v1
Apparently, the read-modify-write operation takes 5 instructions to execute the same thing, comparing to the methods that use LATASET or LATACLR, which only takes 3. So you’ve learned which method to use for better efficiency.