Input-only pin? More like Input/Output pin
I’m currently developing a hardware project around the PIC24F128GA202
micro
and while designing the circuit board I just connected pins to peripherals
(modems, control signals, memories…) using whichever GPIO was available close
by. Well… That proved to be (almost) a catastrophe.
Anyone that has worked with PIC microcontrollers should know that the pin shared
with the !MCLR
can function as an input-only pin if you disable the !MCLR
functionality, while all the other GPIO are available for general purpose
input/output, so is just a matter of avoiding !MCLR
right?
Wrong!
This PIC24, unlike most other PIC18 micros that I use more often,
sometimes have remappable pins which may work as input-only besides the !MCLR
pin. These pins are the pins shared with the secondary oscillator, namely
RB4
and RA4
on the current micro. By sheer luck I connected a serial port
RX to one of those pins, so crisis averted there, but the other pin has been
connected to a MOSFET gate, used to enable the modem power supply. Well, that
sucks.
My options at that time were tying the power supply enable to ground and lose control of the line, essentially permanently enabling the power supply, or finding a way to regain control of that line in a way as painless as possible considering a few dozen boards were already being produced.
Pulling a workaround
Checking the datasheet, the offending pins were part of the interrupt-on-change pins which have programmable pull-ups and pull-downs. Since this particular signal goes to the gate of a MOSFET, virtually no current is needed to open or close the MOSFET, just a voltage level, the pull-up might just be enough to regain control on that pin without requiring any hardware hack or soldering on the already produced boards.
What should have been as simple as this on a GPIO pin:
void enable_modem(uint8_t v){
LATA4bits.RA4 = v ? 1 : 0;
}
Became this on a GPI pin:
void enable_modem(uint8_t v){
if(v){
//Pull the pin UP
//Disable pull-down resistor
CNPD1bits.CN0PDE = 0;
//Enable pull-up resistor
CNPU1bits.CN0PUE = 1;
}
else{
//Pull the pin DOWN
//Disable pull-up resistor
CNPU1bits.CN0PUE = 0;
//Enable pull-down resistor
CNPD1bits.CN0PDE = 1;
}
}
It is not the most elegant thing, after all is fixing in software what is a design flaw I introduced in the first place, but for the particular case of controlling a MOSFET, where virtually no current is needed, and the signal itself doesn’t change that much… It just works! And no hardware mods were needed!