Accidental Modification of I/O Pins in PSoC1

Question: I am unable to modify the state of a PSoC pin using instructions like PRTxDR |= 0x01, PRTxDR &= ~0x01. What am I doing wrong?



If an IO register contains output pins that are configured as pull-ups or pull-downs, you can inadvertently drive values onto those pins that you may not desire to drive. This can happen when:

1) You use a CPU logic instruction on the output register to modify another output pin (or pins).
2) An external source is driving a pull-up or pull-down pin in the opposite direction that you want to drive it.

As an example, suppose you have an IO register with all eight pins configured as pull-up outputs. You have written a value of 0xFF to the data register so that you aren't driving any of the outputs low. At some point you want to drive bit 6 of this register low, so you use the instruction: AND REG[DATA_REG],0BFh. In order to execute this instruction, the CPU will read the data register, force the bit 6 value to 0, and the write the resulting value back to the data register. The problem that can occur happens if an external device is driving one or more of the other bits low when the CPU reads the IO port. When the port is read, those bits will be read as zeros. After you clear bit 6 and write the value back, you will be driving the other bits low too.

One way to overcome this is to always write pull-up and pull-down bits whenever you need to modify any other bit(s) in a register. In the previous example, you would use this instruction: MOV REG[DATA_REG],0BFh. The downside is you have to always know what value a pull-up or pull-down bit is supposed to have. The only practical way to do this is maintain a variable that reflects the port's bit settings and write the variable to the port (shadow register).

Refer to the PSoC Hacker blog, "PSoC 1 GPIO Demystified - Part 2" for a detailed explanation.