Twice before, I’ve run into problems with the lines on the LogoChip’s port A not working the way I expected–while programming an interface to the A6276 LED driver, and again when trying to interface to the DS1302 real-time clock. The second time I ran into it, I fixed the problem by changing port A out of analog input mode–but didn’t know why that made a difference. Last week, poring over the PIC18F2320 datasheet, I finally figured out what’s going on and why the analog input mode matters.
I was working on output routines for TASD’s Thing 3: Simple Outputs, and we’re using port A because it’s the most conveniently placed on the LogoBoard. Every time I’d do a setbit
or clearbit
command against a line on port A, all the other outputs would change to 0.
Tom McGuire had run into this problem recently, and worked around it by reading and writing the port A latch, LATA, instead of the port register itself. But that still didn’t explain why it was happening in the first place. So I sat down with the datasheet and looked at the port operation diagrams.
Generic I/O Port
Here’s the diagram for a generic I/O port, from page 103 of the datasheet. Writing to the port or latch register (WR LAT or Port) puts data into the data latch, which is accessible by reading the latch (RD LAT) register. Additionally, when the data direction latch (TRIS latch) is in output mode, the data latch drives the I/O pin for output. Finally, the input buffer continually reads the I/O pin (even when outputting) and makes its current state accessible by reading the port register (RD Port).
So you can always write output data to the port or latch register; and when the port is in output mode, the last data written will be output to the pin. The last data written is always readable from the latch register; and when in output mode, the data is also readable from the port register.
Port A
Now look at port A, from page 103:
The most visible difference is that the simple output buffer from the data latch to the I/O pin has been replaced by an arrangment of an OR gate, an AND gate, and N- and P-channel FETs. As far as I can tell, there’s no operational difference between the two–Figure 10-2 simply shows what’s happening in more detail.
More significant is the addition of the Analog Input Mode line controlling the input buffer–this is the crux of my problem. When port A pins are receiving analog input, it doesn’t make sense to feed that input into a TTL register–in fact, it could cause excessive power draw and overheating. So the input signal is gated by the analog input mode before feeding to the port A read line (RD PORTA).
setbit
and clearbit
The reason this matters is that the LogoChip’s setbit
and clearbit
commands are read-modify-write operators–they read the value of their target, OR or AND that value with a constant, and write it back to the target. When that target is the port A latch register, all works as it should–the latch is read directly back out the RD LATA line.
When the target is the port A data register, however, the current value is read through the input buffer, which is gated by the analog input mode line. When the pin is set in analog input mode, even though the data direction is set to output, the port data cannot be read because the gate is off, and always returns a 0.
So when setbit <bit> porta
attempts to change one bit, it tries to read PORTA and returns %00000000 rather than the value of the data latch. It then sets one bit and writes the new (mostly-cleared) byte back out to the port A data latch–clearing every other bit of port A in the process.
Workarounds and Solution
Two workarounds are obvious. Tom’s method was to manipulate the port A latch (LATA) instead of the port A data register (PORTA). The latch can always be read and written directly, so this works flawlessly. My only objection is that porta
is already defined as a constant in LogoChip Logo. I’m not wild about having to teach students to define a new constant for lata
and then use lata
, portb
, and portc
.
The second workaround is also simple. When using the LogoChip setbit and
clearbit
commands, clear the analog input mode on any pin you want to use as an output. Because the order of analog input pins is predetermined (A0, A1, A2, A3, A5, . . .), this might mean rearranging the pinouts–you can no longer have A0 and A2 as analog inputs and A1 as an output, for example. But it’s a pretty easy method.
The true fix is equally simple. Where port A’s TTL input buffer is gated by (active-low) analog input mode, it should in fact by gated by (active-low) analog input mode OR (TRIS Latch is set for output). That is, any time the pin is NOT in analog input mode, OR the pin is set for output, pass the pin’s value to the port data read buffer. I don’t see any drawbacks to this solution, other than the cost of one additional OR gate.
Having taken the time to figure that out, I’m rather surprised that Microchip didn’t build the PIC that way.