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!