mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Issue: Wrong InterruptIn with pullup configuration in NUCLEO-F103RB

Hi, I'm working with NUCLEO-F103RB and I've found problems setting InterruptIn with pullup using mbed-src source code. I'll try to explain what is happening:

InterruptInt trig(PA_4); 
void handleISR(){
}

int main(){
    trig.fall(&handleISR);
    trig.enable_irq();
    trig.mode(PullUp);
    while(1){
    }
}

The problem I've found is that, by default after reset, PA_4 as other input pins is setup as Input floating (you can see it in register bits GPIOA_CRL.CNF4[1:0] = 01.

When you select it as InterruptIn, this configuration is kept. Nevertheless when mode is changed to PullUp, only bit1 of GPIOA_CRL.CNF4[1:0] is set, but bit0 is not reset. So now, this register is changed to GPIOA_CRL.CNF4[1:0]=11. Which corresponds to "Reserved" in stead of "Input with pullup or pull down". And then PA_4 is not properly configured.

On the other hand, pull up/down is selected with register GPIOA_ODR, so if GPIOA_ODR.bit4 = 1 then pull up, else if GPIOA_ODR.bit4 = 0 then pull down. And this setup is never done in current mbed-src release.

Current gpio mode configuration in mbed-src is done in file pinmap.c, function: pin_mode, see below:

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 open-drain and pull-up/down
    switch (mode) {
        case PullNone:
            break;
        case PullUp:
        case PullDown:
            // Set pull-up / pull-down for Input mode
            if (pin_index < 8) {
                if ((gpio->CRL & (0x03 << (pin_index * 4))) == 0) { // MODE bits = Input mode
                    gpio->CRL |= (0x08 << (pin_index * 4)); // Set pull-up / pull-down
                }
            } else {
                if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) == 0) { // MODE bits = Input mode
                    gpio->CRH |= (0x08 << ((pin_index % 8) * 4)); // Set pull-up / pull-down
                }
            }
            break;
        case OpenDrain:
            // Set open-drain for Output mode (General Purpose or Alternate Function)
            if (pin_index < 8) {
                if ((gpio->CRL & (0x03 << (pin_index * 4))) > 0) { // MODE bits = Output mode
                    gpio->CRL |= (0x04 << (pin_index * 4)); // Set open-drain
                }
            } else {
                if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) > 0) { // MODE bits = Output mode
                    gpio->CRH |= (0x04 << ((pin_index % 8) * 4)); // Set open-drain
                }
            }
            break;
        default:
            break;
    }
}

In order to solve this configuration defect, I've modified this function by myself and now is working properly, see it below:

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 open-drain and pull-up/down
    switch (mode) {
        case PullNone:
            break;
        case PullUp:
        case PullDown:
            // Set pull-up / pull-down for Input mode
            if (pin_index < 8) {
                if ((gpio->CRL & (0x03 << (pin_index * 4))) == 0) { // MODE bits = Input mode
                    gpio->CRL |= (0x08 << (pin_index * 4)); // Set pull-up / pull-down
					gpio->CRL &= ~(0x08 << ((pin_index * 4)-1)); //<-- ADDED LINE:  ENSURES GPIOx_CRL.CNFx.bit0 = 0
                }
            } else {
                if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) == 0) { // MODE bits = Input mode
                    gpio->CRH |= (0x08 << ((pin_index % 8) * 4)); // Set pull-up / pull-down
					gpio->CRH &= ~(0x08 << (((pin_index % 8) * 4)-1)); //<-- ADDED LINE:  ENSURES GPIOx_CRH.CNFx.bit0 = 0
                }
            }
       //<-- ADDED LINES:  ENSURES GPIOx_ODR pull up/down is properly setup
			if(mode == PullUp)
				gpio->ODR |= (0x01 << (pin_index)); // Set pull-up 
			else
				gpio->ODR &= ~(0x01 << (pin_index)); // Set pull-down
            break;
        case OpenDrain:
            // Set open-drain for Output mode (General Purpose or Alternate Function)
            if (pin_index < 8) {
                if ((gpio->CRL & (0x03 << (pin_index * 4))) > 0) { // MODE bits = Output mode
                    gpio->CRL |= (0x04 << (pin_index * 4)); // Set open-drain
                }
            } else {
                if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) > 0) { // MODE bits = Output mode
                    gpio->CRH |= (0x04 << ((pin_index % 8) * 4)); // Set open-drain
                }
            }
            break;
        default:
            break;
    }
}

Just with those modifications, InterruptIn with PullUp mode is setup properly. Kind regards. Raul.

3 comments:

24 Apr 2015

Thanks for reporting. CAn you please add this to the issues on github https://github.com/mbedmicro/mbed/issues ? Or if you find time, you can send a pull request with your fix, the one you presented above.

I can add it there to the issues and reference this report there.

Regards, 0xc0170

24 Jun 2016

Did somebody notice if pin is Px8 / Px4, this, gpio->CRH &= ~ (0x08 << (((pin_index % 8) * 4)-1)), doesnt work ? It is like this : 8 % 8 = 0 * 4 = 0 - 1 = -1 and 0x08 << -1 = 0x08, and no back shifting occurs. It is more simple and intuitive like this: gpio->CRH &= ~ (0x04 << ((pin_index % 8) * 4));

15 Feb 2018

Hi, Just wondering if this bug has been squashed in the recent mbed builds? I dont have a the Nucleo at the moment to try it out. thanks.