mbed official / mbed

Dependents:   hello SerialTestv11 SerialTestv12 Sierpinski ... more

Issue: Calling DigitalOut ctor with PinName parameter "NC" crashes application (Closed: Fixed)

  • The DigitalOut constructor just calls _gpio_init_out(...) via gpio_init_out(...) in /common/gpio.c

/api/DigitalOut.h

    DigitalOut(PinName pin) {
        gpio_init_out(&gpio, pin);
    }

/common/gpio.c

void gpio_init_out(gpio_t* gpio, PinName pin) {
    gpio_init_out_ex(gpio, pin, 0);
}
void gpio_init_out_ex(gpio_t* gpio, PinName pin, int value) {
    _gpio_init_out(gpio, pin, PullNone, value);
}
static inline void _gpio_init_out(gpio_t* gpio, PinName pin, PinMode mode, int value)
{
    gpio_init(gpio, pin);
    gpio_write(gpio, value);  
    gpio_dir(gpio, PIN_OUTPUT);
    gpio_mode(gpio, mode);
}
  • from now on the code is target dependent, but it looks almost the same for the targets that I have checked.
  • The call of init() doesn't harm since it is "NC"-guarded. It just does nothing, i.e. leaves the register pointers of the gpio_t struct uninitialized ... the pin ID too.

e.g. /targets/hal/TARGET_NXP/TARGET_LPC408X/gpio_api.c

void gpio_init(gpio_t *obj, PinName pin) {
    if (pin == NC) return;
    
    obj->pin = pin;
    obj->mask = gpio_set(pin);
    
    LPC_GPIO_TypeDef *port_reg = (LPC_GPIO_TypeDef *) ((int)(LPC_GPIO0_BASE+pin) & ~0x1F);
    
    obj->reg_set = &port_reg->SET;
    obj->reg_clr = &port_reg->CLR;
    obj->reg_in  = &port_reg->PIN;
    obj->reg_dir = &port_reg->DIR;
}
  • But then the call of gpio_write(...) in _gpio_init_out(...) will write some nonsense to the uninitialized register pointers: Ouch!

/targets/hal/TARGET_NXP/TARGET_LPC408X/gpio_object.h

static inline void gpio_write(gpio_t *obj, int value) {
    if (value)
        *obj->reg_set = obj->mask;
    else
        *obj->reg_clr = obj->mask;
}
  • This happened to me when I called the constructor of following TFT interface class defined in http://mbed.org/users/ttodorov/code/TFTLCD/, using the latest revisions of the pre-compiled mbed- or the mbed-src lib. My LPC4088 just freezes. With older revisions of the mbed lib, e.g. rev 65 (first one with LPC4088 support), everything seems to be fine.

HX8340S_LCD::HX8340S_LCD( PinName CS, PinName RESET, PinName SCL, PinName SDI, PinName BL, backlight_t blType, float defaultBackLightLevel )
    : LCD( 176, 220, CS,  /*OUCH*/ NC  /*OUCH*/ , RESET, BL, blType, defaultBackLightLevel ), _lcd_pin_scl( SCL ), _lcd_pin_sdi( SDI )
{}

LCD::LCD( unsigned short width, unsigned short height ,PinName CS, PinName RS, PinName RESET, PinName BL, backlight_t blType, float defaultBacklight )
    : _disp_width( width ),
 _disp_height( height ),
 _lcd_pin_cs( CS ),
   /*OUCH*/   _lcd_pin_rs( RS )       /*OUCH*/,
 _lcd_pin_reset( RESET ),
 _bl_type( blType )
{ ...
  • Possible fixes:
    • Also "NC"-guard the dangerous functions of the gpio-c-api, like gpio_dir(), gpio_write, ... others?
    • Initialize the registers to a safe static dump variable (see code below)
  • Unfortunately this would have been done for each platform ...
  • A preliminary fix could be to add a big fat warning to the DigitalOut API and throwing an error if it is called with parameter NC. This would be at least more user friendly than a sporadically crashing application.

void gpio_init(gpio_t *obj, PinName pin)
{
    static uint32_t dumpItOrPayAFine = 0;
    if (pin == NC) {
        obj->pin = pin;
        obj->reg_set = &dumpItOrPayAFine;
        obj->reg_clr = &dumpItOrPayAFine;
        obj->reg_in  = &dumpItOrPayAFine;
        obj->reg_dir = &dumpItOrPayAFine;
        return;
    }
    obj->pin = pin;
    obj->mask = gpio_set(pin);

    LPC_GPIO_TypeDef *port_reg = (LPC_GPIO_TypeDef *) ((int)(LPC_GPIO0_BASE+pin) & ~0x1F);

    obj->reg_set = &port_reg->SET;
    obj->reg_clr = &port_reg->CLR;
    obj->reg_in  = &port_reg->PIN;
    obj->reg_dir = &port_reg->DIR;
}

4 comments:

27 Mar 2014

I think either an error or the dump variable are fine. NC guards in GPIO shouldn't slow it down alot, but it is something, and personally I would prefer avoiding that as much as possible.

27 Mar 2014

It seems to me that defining a pin as NC should not throw an error nor crash the application. There are several examples of code where a pin is optional and has a default value of NC in the header file. Take for example the 'Backlight = BL' parameter in the LCD constructor above. Obviously, you should not call a method to activate the backlight when the pin has not been defined and the code will/might crash when you do it anyway, but it would not make sense when you are not able to use NC and you are always forced to define/waste a pin for a display that does not even have a backlight.

03 Apr 2014

FYI I just made a pull request which at least brings back the old behavior: Pins with NC can still be constructed, when trying to write it still crashes, but it doesn't try to write in the constructor anymore. Not perfect, but this could be added easily in the common code without giving a performance penalty, and at least it brings back the old behavior.

14 May 2014

Hello,

This should be fixed soon. I am closing it as Erik already fixed part of it and the second part will come. Thanks for understanding.