The MODE register serves as a pointer to all port control registers. The control registers for the ports are denoted as !Rx (!RA, !RB, or !RC) but writing to !RA may set the input/output configuration or the TTL/CMOS, or the pull-up/hi-z configuration depending on the setting of the MODE register.
In order to write or read any ports control register, the MODE register must contain the appropriate value to point to that port register. The W register is used to write into the MODE register.
The format of the MODE register is shown below. The four least significant bits serve as the pointer to the set of port registers to be accessed. Upon reset, the MODE register is initialized to 0Fh. In this default configuration, the program can access the !RA, !RB, and !RC (data direction) registers.
0 | 0 | 0 | 0 | M3 | M2 | M1 | M0 | |
bit 7 | bit 0 |
In order for the program to gain access to the other port control registers (to set the pullup resistor, input voltage levels, Schmitt triggers, etc.), the program must write a different value into the MODE register. Figure 3-3 shows how the MODE register controls access to the port registers.
Example:
Mode = 0F writing to !RA, !RB or !RC will affect the direction of the port pins. A 1 will set that port pin to an input. A 0 will set it to an output
Mode = 0E writing to !RA, !RB or !RC will affect the use of the weak pullup resister on this port. A 1 will disable it and a 0 will enable it.
Mode = 0D writing to !RA, !RB or !RC will affect the input level for each port pin. A 1 will set the level to TTL and a 0 will set it to CMOS.
Mode = 0C writing to !RB or !RC will affect the trigger mode of the port pin. A 1 will disable Schmitt-Trigger input and a 0 will enable it.
Mode = 0B writing to !RB will affect the Wake Up mode for that pin. A 1 will disable multi-input wake up (MIWU)
Mode = 0A writing to !RB will affect the Wake Up Edge Selection for that pin. A 1 will select falling edge detection and a 0 will selecte rising edge detection
Mode = 09 !RB Multi Input Wake Up Pending Register
Mode = 08 !RB Comparator Enable Register. Bit 7 is the comparator enable bit. A 1 will disable the comparator and a 0 will enable it if port B pins 1 and 2 are configured as inputs. Pin 1 is used as the negative input and pin 2 as the positive input. Bit 0 of the !RB register is the result of the comparison. Bit 6 is the comparator output enable. A 1 will disable output of the comparitor result on port B pin 0 and a 0 will enable it if pin 0 has been configured as an output. Bit 0 of the !RB register is the result of the comparison even if output on pin 0 is not enabled by Bit 6
The following example shows common code used to configure the ports:
mov W,#0Fh mov M,W ;Set up MODE for Data ;Direction configuration mov !RA,#03h ;RA3, RA2 are Outputs, ;RA1, RA0 are Inputs mov W,#0Eh mov M,W ;Set up MODE for Pull-Up ;configuration mov !RA,#01h ;RA3, RA1 Unaffected, ;Pull-up enabled on RA0 mov W,#0Dh mov M,W ;Set up MODE for ;TTL/CMOS configuration mov !RA,#02h ;RA3,RA2,RA0 unaffected, ;RA1 has CMOS voltage level
The following Macro will setup the ports using a simpler command:
in EQU $FF out EQU $F0 pull EQU $E0 float EQU $EF cmos EQU $D0 ttl EQU $DF reghelp MACRO ERROR 'USAGE: reg r[a,b,c] [in,out,pull,float,cmos,ttl] bits' ENDM reg MACRO IF \1=RA OR \1=RB OR \1=RC ELSE reghelp ENDIF IF \2=in OR \2=out OR \2=pull OR \2=float OR \2=cmos OR \2=ttl ELSE reghelp ENDIF mov w, #(\2 / $10) mov m,w mov !\1,\3 ENDM noexpand reg RA, in, 1
Michael Rigby-Jones [mrjones@NORTELNETWORKS.COM] says: When you perform any operation, apart from a MOVWF on a register that changes it's contents, the PIC {or SX} first reads the register, then it performs the operation on the number it has just read and finally it write the number back to the register. This is fine when dealing with normal registers and most special function registers. However, if you perform RMW (read modify write) operation on a port register (PORTA PORTB etc) then you are heading for trouble. Why? Because when the PIC reads a port register, it reads the actual state of the pins, rather than the output latch. This can cause two problems:
bsf portb,0 bsf portb,1
Which *might* work. However, if pin B0 is loaded in any way, then it may not have time to respond to the first instruction before the second one is executed. The second instruction reads the port and sees that the pin B0 is low (because it hasn't got time to go high) and writes the low state back into the output latch. The result would be that B0 never gets set.
How do you avoid this issue? Well, it's bad practice to use RMW instructions directly on a port. So you use whats known as a shadow register. The shadow register is simply a ram location you reserve. All operations are performed on this register, and when you are finished, you copy it to the port register. It's a bit more trouble, and it can slow things down a tiny bit, but the effort is worth it for reliable operation.
Note that it's not only bsf and bcf that are RMW instructions, although they are the most common. Other examples are
andwf portb,f xorwf portb,f