Af_output_drain


#1

Hello,
I would like to clarify some discussion from another topic related to the behavior of AF_OUTPUT_DRAIN as a pinMode. The testing that I have done seems to show that AF_OUPUT_DRAIN does not behave as a high impedance line when A2 is set high:

pinMode(A2,AF_OUTPUT_DRAIN);
digitalWriteFast(A2,1); // should set to high impedance on A2

This is in contrast to when pinMode is set to input, where the line does behave as high impedance. I guess I would like A2 to act as a pulldown when set low, but high impedance otherwise.

Is this possible? Should I be looking at other functionality?

Edit for clarity: Switching the pinMode from input to output when I want to drive the circuit low seems to insert a delay/glitches that would be prohibitive.


#2

If you need tighter pin control, you should be able to control the pin registers directly. Arduino-type GPIO is notoriously slow, so this is a semi-common thing to do.

On further investigation, this should do what you want though. That pin is 5V tolerant, so voltage shouldn’t be an issue unless you’re trying to switch something higher than that.


#3

Hi @rtpavlovsky

If you can tell us how you intend to connect to that pin we can probably help more. As is, I can’t tell why you need a high impedance state versus a driven low state.

You can almost certainly solve your problem (whatever it is) with a $0.05 external transistor and a few resistors.


#4

@bko please see the image above. I know this may need an external open-drain circuit, which I am fine with. However the AF_OUTPUT_DRAIN configuration should support other hardware modes (such as SPI…) without the addition of components. My testing up to this point basically says that the AF_OUTPUT_DRAIN configuration sets the pin low with 30Ohms impedance (regardless of the write state).

I guess I might try with the lower level HAL commands but I am not really sure where the issue would be here.

Edit: The above works with A2 as an INPUT and then switched to OUTPUT, but like I said there are glitches/delays between the pinMode change. SPI should be I2C in the above.


#5

Hi @rtpavlovsky

The AF_OUTPUT_DRAIN mode is an output that only pulls low but cannot include pull-up or pull-down resistors on the this CPU chip. The PMOS transistor is still there, just never turned on, so there are some impedance and DC limits so I’m not surprised by your results. You do need external i2c pull-ups on STMicro parts for exactly this reason.

Did you want INPUT_PULLDOWN instead for your application?

Why did you choose an output mode? Are you driving this pin?


#6

image
@bko see my above circuit. The circuit is low regardless of the A2 pin state when configured as AF_OUTPUT_DRAIN. Lead 2 on the 330 ohm resistor is where I am probing.

Also in the previous circuit configuration, I am driving this pin after an initial trigger from the hardware.


#7

OK I understand your problem now and that is strange.

Are you also using SPI? The default SS pin for SPI is A2.

Can you try another pin?


#8

@bko Attempts on the D1 seem to produce the same result, pin held low.

#include "application.h"
#include "math.h"

SYSTEM_MODE(MANUAL);

int od_pin=D1;

void pinSetup(){

  pinMode(od_pin, AF_OUTPUT_DRAIN);

}

void setup()
{
  WiFi.off();
  pinSetup();
}

void loop(){

  digitalWrite(od_pin,1);

}

#9

I’d suggest you try configuring and driving the pin directly via registers rather than the wiring API to determine if it’s software or the actual hardware that’s your issue.


#10

Thanks @paulm. The HAL documentation is pretty awful but the STM32 RM0033 manual clarified this functionality. The AF_OUTPUT_DRAIN is special in the AF component as a buffer for other low level functionality, which does not include the output registers. See the AF configuration below, in that the circuit is not connected to register output.

I guess the AF is probably used for low-level hardware buffering from timer outputs etc.

Implementing the switch in …/hal/src/stm32f2xx/gpio_hal.c:

    GPIO_InitStructure.GPIO_Pin = gpio_pin;

    switch (setMode)
    {
        case OUTPUT:
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
            PIN_MAP[pin].pin_mode = OUTPUT;
            break;

// cut for brevity

          case OUTPUT_DRAIN:
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
            GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
            PIN_MAP[pin].pin_mode = AF_OUTPUT_DRAIN;
            break;

        default:
            break;
    }

along with a enumeration statement in …/hal/inc/pinmap_hal.h gives the desired behavior of open-drain without additional hw.

Solved, thanks to @HEng @bko and @paulm.