9 years, 7 months ago.

Is the DigitalInOut broken on ST Nucleo platforms?

Hello everyone,

I think the DigitalInOut is broken on at least for some of the Nucleo platforms. Creating DigitalInOut on a pin and setting its mode to 'OpenDrain' should set the IO pin sink current when written 0 and stay HiZ when written 1. In my tests I concluded that the IO stayed in HiZ in both cases.

By looking the source code (#1) it is quite obvious why the DigitalInOut is not working as expected. gpio_dir() changes pin function to either output push-pull or input with out any pull. gpio_mode() changes pull configuration but does not change the pin function.

I reckon that this issue can be fixed by changing pin function to open drain in gpio_mode if the requested mode is OpenDrain.

Best regards, Chesterdam

  1. 1: https://github.com/mbedmicro/mbed/blob/f304c6ba83591678388024d30440e94781fa8d65/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F411RE/gpio_api.c

Question relating to:

Affordable and flexible platform to ease prototyping using a STM32F411RET6 microcontroller.

I think it's a problem with the type of the GPIO...you must set the type to open drain not to Push Pull. I've write this to drive a LCD

Configure pull-up/pull-down resistors uint32_t pupd = (uint32_t)mode; if (pupd == 2) { gpio->OTYPER &= (uint32_t)((GPIO_OTYPER_OT_0 << (pin_index))); gpio->OTYPER |= (uint32_t)(1 << (pin_index)); } if (pupd > 2) pupd = 0; Open-drain = No pull-up/No pull-down

Configure pull-up/pull-down resistors uint32_t pupd = (uint32_t)mode; if (pupd == 2) { gpio->OTYPER &= (uint32_t)((GPIO_OTYPER_OT_0 << (pin_index))); gpio->OTYPER |= (uint32_t)(1 << (pin_index)); } if (pupd > 2) pupd = 0; Open-drain = No pull-up/No pull-down

in the pin mode function

posted by Gilles LACAUD 03 Apr 2015

1 Answer

9 years, 7 months ago.

I already knew the dir function is ridiculous, and could be replaced by a single line of code which switches one bit. Instead if requires iirc around 500 clock cycles and overwrites alot of settings, such as pull mode settings. I didn't know yet that the OpenDrain function is also incorrect, but it seems you are right:

<<code>> void pin_mode(PinName pin, PinMode mode) { MBED_ASSERT(pin != (PinName)NC); uint32_t port_index = STM_PORT(pin); uint32_t pin_index = STM_PIN(pin);

Enable GPIO clock uint32_t gpio_add = Set_GPIO_Clock(port_index); GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add;

Configure pull-up/pull-down resistors uint32_t pupd = (uint32_t)mode; if (pupd > 2) pupd = 0; Open-drain = No pull-up/No pull-down gpio->PUPDR &= (uint32_t)((GPIO_PUPDR_PUPDR0 << (pin_index * 2))); gpio->PUPDR |= (uint32_t)(pupd << (pin_index * 2));

} <<.code>> If open drain it simply sets it as no-pull, and happily continues.

Accepted Answer

Obviously editing answers is STILL broken...

void pin_mode(PinName pin, PinMode mode) {
    MBED_ASSERT(pin != (PinName)NC);
    uint32_t port_index = STM_PORT(pin);
    uint32_t pin_index  = STM_PIN(pin);
 
    // Enable GPIO clock
    uint32_t gpio_add = Set_GPIO_Clock(port_index);
    GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add;
 
    // Configure pull-up/pull-down resistors
    uint32_t pupd = (uint32_t)mode;
    if (pupd > 2)
        pupd = 0; // Open-drain = No pull-up/No pull-down
    gpio->PUPDR &= (uint32_t)(~(GPIO_PUPDR_PUPDR0 << (pin_index * 2)));
    gpio->PUPDR |= (uint32_t)(pupd << (pin_index * 2));
 
}
posted by Erik - 31 Aug 2014

take a look at PortInOut, aside some small issue like "if the direction is out, the read() does read the output data register, not the input data register"(i want to read if the pin has reached the wanted state, if not = pin flamed), aside the small fact you have to remember to switch to input/output dir prior to read or write, aside the fact that if you have to re-set your pullup/down everytiem you switch to input, aside teh small overhead of calling Set_GPIO_Clock (which enables gpio bank clock) just to have back the GPIOx baseaddress, done for each change of dir or mode, multiply the overhead 16times if you work with portinout....and finally, since you are working on a bidirectional bus, expect host/device pins flamed as first compile :) The best would be to replace the output pushpull/opendrain with "always input" and "output" HI/LOW levels just enabling pullup/pulldown, at least it's what i used to do with LPCexpresso.

posted by Geremia G 15 Sep 2014