Fast Atomic Access of PIC32 SFRs

Like other Microchip devices, PIC32 devices use special function registers (SFRs) to interact with peripherals. These registers can be accessed like ordinary variables in C source code when using the MPLAB® XC32 compiler, but since they directly affect or are directly affected by hardware, there can be read-modify-write problems associated with code that might normally be used to change individual bits with these registers.

To get around this problem, virtually all registers have an alternate register set that can be used to set, clear, or toggle the bits within the primary register. The names of the alternate registers consist of the primary register name appended with SET, CLR, or INV. Each of these alternate registers can be assigned a value in the usual way, but this write operation will instead set, clear, or toggle (respectively) bits within the primary register. Where a bit in the written value is 1, this will trigger the appropriate operation in the primary register at the corresponding bit position. Thus, a plain assignment to the alternate registers can be used to replace assignment-OR, assignment-AND or assignment-XOR (respectively) operations directly on the primary register.

The code to assign a value to an alternate register takes fewer instructions than performing the relevant operation on the primary register, and, importantly, a simple assignment is an atomic operation. Atomic operations cannot be interrupted and are safe to use in situations where the content of the destination register could be changed by interrupt code or by hardware.

Consider, for example, the LATA latch register. It can be read and written in the usual way, but in addition to this register is defined its alternate registers: LATASET, LATACLR, and LATAINV. The following table shows the operation performed when writing to these alternate registers and the equivalent code which acts on the primary register and which this write replaces.

Operation on LATA Alternate register usage Replaces
set bit #6 LATASET = 0x40; LATA |= 0x40;
clear bit #6 LATACLR = 0x40; LATA &= ~0x40;
toggle bit #6 LATAINV = 0x40; LATA ^= 0x40;

To make these statements more readable, predefined masks (accessible via <xc.h>) can be used rather than you having to use literal constants. The code in the above table could use the macro _LATA_LATA6_MASK instead of the literal constant 0x40.

Since bit masks are used with these registers, you can control as many bits as you like in the one operation, as long as it is the same operation to be performed on each bit. To change two bits simultaneously, you could use the following code examples.

where the two masks are first OR-ed together to form the required bit mask. (Do not use the logical OR operator, ||.)

The values read back from the alternate registers are undefined, which means that you must only write to these registers and always read the primary register to obtain its content.

© 2017 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.