Configuring a pin as open drain on a photon [Solved]

I am trying to control a mosfet that requires an open drain to switch off the power to peripherals. I am using pin A1 to control the circuit.

Turning it on works using pinMode(pin, OUTPUT) and digitalWrite(pin, LOW).

However, using digitalWrite(pin, HIGH) results in the switched power initially going off then being switched on again. I understand from the electronics guys that I need to set the A1 pin into open drain mode and the way to do this (from another thread) is to call a custom pinMode() routine.

void Pin_Mode_Open_Drain(pin_t pin)
    STM32_Pin_Info* PIN_MAP = HAL_Pin_Map();
    GPIO_TypeDef *gpio_port = PIN_MAP[pin].gpio_peripheral;
    pin_t gpio_pin = PIN_MAP[pin].gpio_pin;
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    if (gpio_port == GPIOA)
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    else if (gpio_port == GPIOB)
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    else if (gpio_port == GPIOC)
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    else if (gpio_port == GPIOD)
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    GPIO_InitStructure.GPIO_Pin = gpio_pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    PIN_MAP[pin].pin_mode = OUTPUT;
    GPIO_Init(gpio_port, &GPIO_InitStructure);

This is not working - any clues as to why? Thanks

@armor, the reason you need Open Drain mode on the GPIO pin is the fact that you pull up the mosfet gate to 5v. Thus when you output a HIGH (3.3v) to pin A1, there will be a voltage difference across R21 creating a current back into the GPIO pin. One way to avoid this is to pull R21 to 3.3v. You could then use the typical pinMode(A1, OUTPUT) to control the mosfet. Just make sure your load GND and Photon GND are common.

If this is not possible, then you can put A1 into OPEN_DRAIN mode using pinMode(A1, AF_OUTPUT_DRAIN). I would recommend the first solution over the second.

@peekay123, Thanks for the super fast reply. I would like to understand what you mean by the first solution - pull R21 to 3.3V. Do you mean a voltage divider resistor between the mosfet gate and the photon pin? The load GND and Photon GND are common.

Why do you recommend the first solution over using pinMode(A1, AF_OUTPUT_DRAIN)?

Later when I turn the power on do I need to use pinMode(A1, OUTPUT) before digitalWrite(A1, LOW)?

@armor, your circuit is implementing “high side” power control. The mosfet isolates the power you are switching (5v) from the Photon in this case. All you need to do is to ground the gate for the transistor to switch ON. In order to keep it OFF otherwise, especially if you put the Photon in deep sleep and all pins “float”, a pull-up resistor is used. In your case, again to isolate the switched power versus the switching power, you can pull the gate HIGH via a resistor to the Photon’s 3.3v. This allows you to use regular OUTPUT for pinMode without a voltage conflict at the gate or open drain pinMode. Either way will work and thinking about it, I can’t justify my preference! :stuck_out_tongue_winking_eye:

@peekay123, I have tried the pinMode(A1, AF_OUTPUT_DRAIN) and this does not appear to fully work. I am wondering if something is going on with the opto-reflective sensor that is one of peripherals switched but is also connected to a GPIO expander input pin. I will go back to the electronics people and get the schematic you have suggested tried. Thanks for your help.

Perhaps you can share your schematics?

@peekay, The problem turned out to be that whilst the simple schematic for switching the 5V net did eventually work, it was not reliable/robust. An SD card reader and TFT screen are attached via SPI bus. Also, the passive devices/sensors attached to the switched 5V managed to find power from the photon (still powered as in sleep mode) via the SPI pins. This went back through the LDO (5V to 3V3) which was supplying the SD card reader.

It has been necessary to:

  1. Change the schematic for the 5V switched to isolate the supplied and switched 5V from the photon controlling output pin thus:
  2. As well as putting the tft to sleep, and switching off the 5V or 3V3 supply to the others; to stop SPI with SPI.end(); and set the hardware SPI pins set as OUTPUT to be INPUTS using pinMode() to avoid power leaking back.
  3. The wake-up process after the power supply is restored is then somewhat more complicated and I have had to play around to get the time critical peripherals (SD card reader) initialised first.

@armor, the parasitic power issue is something I didn’t mention. I ended up doing a low-side (GND) switch on a microSD to remove the parasitic power path. Your approach is sound and thanks for sharing! :yum:

@peekay123, The parasitic power issue didn’t end there! The main PCB with the photon is connected with an I2C to another board with a GPIO (MCP23008) - that board has a battery backed power supply and when the AC supply is off the battery was still supplying power to the GPIO. The I2C lines had pull-up resistors to the 5V supply and that was the final cause. Removing the pull-ups has removed the route to the power.

@armor, ain’t hardware design fun!:stuck_out_tongue_winking_eye: