6.1.9 CLR, SET and INV Registers

Every I/O module register has corresponding SET, CLR and INV registers, which provide atomic bit manipulations. As the name of the registers imply, a value written to a SET, CLR or INV register effectively performs the implied operation, but only on the corresponding base register and only bits specified as ‘1’ are modified. Bits specified as ‘0’ are not modified. For example,

  • Writing 0x0001 to the TRISASET register sets only bit 0 in the base register TRISA
  • Writing 0x0020 to the PORTBCLR register clears only bit 5 in the base register PORTB
  • Writing 0x9000 to the LATAINV register inverts only bits 15 and 12 in the base register LATA

Reading the SET, CLR and INV registers returns an undefined value. To see the influences of a write operation to a SET, CLR or INV register, the base register must be read instead.

A typical method to toggle an I/O pin requires a read-modify-write operation performed on a PORTx register in the software. For example, a read from a PORTx register, mask and modify the desired output bit or bits, and write the resulting value back to the PORTx register. This method is vulnerable to a read-modify-write issue where the port value may change after it is read and before the modified data can be written back, thus, changing the previous state. This method also requires more instructions.

A more efficient and atomic method uses the PORTxINV register. A write to the PORTxINV register effectively performs a read-modify-write operation on the target base register, equivalent to the software operation described previously; however, it is done in the hardware. To toggle an I/O pin using this method, a ‘1’ is written to the corresponding bit in the PORTxINV register. This operation reads the PORTx register, inverts only those bits specified as ‘1’, and writes the resulting value to the LATx register, thus, toggling the corresponding I/O pins all in a single atomic instruction cycle. PORTAINV = 0x0001.