1 Reply Latest reply on Jul 22, 2015 12:29 PM by gdepaula

    GPIO usage in WICED Smart SDK

    OceanS_76

      Overview

      The BCM2073x supports up to 40 GPIOs, the majority of GPIOs have multiple functions. About more information about GPIOs, please refer to the section” GPIO” in “WICED-Smart-Hardware-Interfaces.pdf” in SDK doc directory.

      In WICED Smart SDK, some GPIOs can be configured to the predefined function, these GPIOs is initialized and controlled by ROM code. Besides these GPIOs, developers configure the other GPIOs for any purpose as they want. This document describes these two types of GPIO and APIs.

       

      GPIO that Configured to Predefined Usage

       

      Predefined Usage

      The GPIOs that used for predefined usage are identified by ROM code to implement the corresponding action.

      The following predefined usage is in bleprofile.h.

      #define GPIO_WP              0x0010
      #define GPIO_BAT             0x0020
      #define GPIO_BUTTON          0x0100
      #define GPIO_BUTTON1         0x0100
      #define GPIO_BUTTON2         0x0200
      #define GPIO_BUTTON3         0x0400
      #define GPIO_LED             0x1000
      #define GPIO_BUZ             0x2000
      
      
      
      

      GPIO_WP is used for EEPROM write protection.

      GPIO_BAT is used for battery ADC.

      GPIO_BUTTONx is used for button. WICED Smart SDK max support 3 buttons.

      GPIO_LED is used to control LED.

      GPIO_BUZ is used to control buzzer.

       

      Configure GPIOs to Predefined Usage

      WICED Smart SDK provides the structure BLE_PROFILE_GPIO_CFG to configure these GPIOs and GPIO’s settings.

      The following code is in platform.h, the GPIO PIN and GPIO setting is declared.

      //GPIO-0 used for GPIO_BUTTON function, GPIO settings:  input, initialization level is low, interrupt
      #define GPIO_PIN_BUTTON        0
      #define GPIO_SETTINGS_BUTTON  (GPIO_INPUT  | GPIO_INIT_LOW  | GPIO_BUTTON | GPIO_INT)
      //GPIO-1 used for GPIO_WP function, GPIO settings: output, initialization level is low
      #define GPIO_PIN_WP            1  
      #define GPIO_SETTINGS_WP       (GPIO_OUTPUT | GPIO_INIT_LOW  | GPIO_WP)
      //GPIO-14 used for GPIO_LED function, GPIO settings: output, initialization level is high
      #define GPIO_PIN_LED           14
      #define GPIO_SETTINGS_LED      (GPIO_OUTPUT | GPIO_INIT_HIGH | GPIO_LED)
      //GPIO-15 used for GPIO_BAT function, GPIO settings: input, initialization level is low
      #define GPIO_PIN_BATTERY   15
      #define GPIO_SETTINGS_BATTERY (GPIO_INPUT  | GPIO_INIT_LOW  | GPIO_BAT)
      //GPIO-28 used for GPIO_BUZ function, GPIO settings: output, initialization level is low
      #define GPIO_PIN_BUZZER          28
      #define GPIO_SETTINGS_BUZZER (GPIO_OUTPUT | GPIO_INIT_LOW | GPIO_BUZ)
      
      
      
      

       

      The following sample code if in hello_sensor.c,
      the GPIO PIN number and GPIO setting is filled to structure BLE_PROFILE_GPIO_CFG.

      const BLE_PROFILE_GPIO_CFG hello_sensor_gpio_cfg =
      {
          /*.gpio_pin =*/
          {
           GPIO_PIN_WP,            // This need to be used to enable/disable NVRAM write protect
           GPIO_PIN_BUTTON,   // Button GPIO is configured to trigger either direction of interrupt
           GPIO_PIN_LED,            // LED GPIO, optional to provide visual effects
           GPIO_PIN_BATTERY,   // Battery monitoring GPIO.
           GPIO_PIN_BUZZER,     // Buzzer GPIO, optional to provide audio effects
           -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      // other GPIOs are not used
          },
          /*.gpio_settings =*/
          {
           GPIO_SETTINGS_WP,
           GPIO_SETTINGS_BUTTON,
           GPIO_SETTINGS_LED,
           GPIO_SETTINGS_BATTERY,
           GPIO_SETTINGS_BUZZER,
           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
          }
      };
      
      
      
      

                         

      APIs

      The following APIs for predefined GPIOs function is in bleprofile.h.

       

      void bleprofile_GPIOInit(BLE_PROFILE_GPIO_CFG *p_gpio_cfg);

      Initialize all GPIOs that configured to predefined usages, it should be called in application creation function.

      The following code is hello_sensor.c.

      void hello_sensor_create(void)
      {
           …
        
           //initialize the GPIOs that used for predefined usages
          bleprofile_GPIOInit(bleprofile_gpio_p_cfg);
          …
      }
      
      
      
      

       

      void bleprofile_regIntCb(BLEPROFILE_SINGLE_PARAM_CB callback);

      Register callback function for the interrupt of predefined GPIO, the GPIO usually is used for button.

      The following sample code is in platform.h, the button GPIO is configured an interrupt PIN.

      //GPIO-0 used for GPIO_BUTTON function, has interrupt
      #define GPIO_PIN_BUTTON       0
      #define GPIO_SETTINGS_BUTTON  (GPIO_INPUT  | GPIO_INIT_LOW  | GPIO_BUTTON | GPIO_INT)
      
      
      
      

      The following code is in hello_sensor.c.

      // Following structure defines GPIO configuration used by the application
      const BLE_PROFILE_GPIO_CFG hello_sensor_gpio_cfg =
      {
          /*.gpio_pin =*/
          {
           …
           GPIO_PIN_BUTTON,  // Button GPIO is configured to trigger either direction of interrupt
           …
          },
          /*.gpio_flag =*/
          {
           …
           GPIO_SETTINGS_BUTTON,
           …
          }
      };
      
      void hello_sensor_create(void)
      {
          …
          // register the callback function for button interrupt
          bleprofile_regIntCb((BLEPROFILE_SINGLE_PARAM_CB) hello_sensor_interrupt_handler);
          … 
      }
         //the callback function for button interrupt
      void hello_sensor_interrupt_handler(UINT8 value)
      {
          BLEPROFILE_DB_PDU db_pdu;
      
          ble_trace3("\r(INT)But1:%d But2:%d But3:%d", value&0x01, (value& 0x02) >> 1, (value & 0x04) >> 2);
          …
      }
      
      
      
      

       

      GPIO that NOT Configured to Predefined Usages

       

      The GPIOs that not configured to predefined usages can be configured and controlled by user application, these APIs that declared in gpiodriver.h.

       

      APIs

       

      voidm gpio_configurePin(BYTE port, BYTE pin, UINT16 config, BYTE outputVal);

      void gpio_configurePinWithSingleBytePortPinNum(BYTE gpio, UINT16 config, BYTE outputVal);

      UINT16 gpio_getPinConfig(BYTE port, BYTE pin);

        Set/Get GPIO configuration by pin or port.

        The “config” can set multiple GPIO features, such as input, output, interrupt trigger, pull up, pull down, driver strength etc. The following features are defined in gpiodriver.h.

      enum
      {
          /// GPIO configuration bit 0, Interrupt type defines
          GPIO_EDGE_TRIGGER_MASK       = 0x0001,
          GPIO_EDGE_TRIGGER            = 0x0001,
          GPIO_LEVEL_TRIGGER           = 0x0000,
          /// GPIO configuration bit 1, Interrupt polarity defines
          GPIO_TRIGGER_POLARITY_MASK   = 0x0002,
          GPIO_TRIGGER_NEG             = 0x0002,
          /// GPIO configuration bit 2, single/dual edge defines
          GPIO_DUAL_EDGE_TRIGGER_MASK  = 0x0004,
          GPIO_EDGE_TRIGGER_BOTH       = 0x0004,
          GPIO_EDGE_TRIGGER_SINGLE     = 0x0000,
          /// GPIO configuration bit 3, interrupt enable/disable defines
          GPIO_INTERRUPT_ENABLE_MASK   = 0x0008,
          GPIO_INTERRUPT_ENABLE        = 0x0008,
          GPIO_INTERRUPT_DISABLE       = 0x0000,
          /// GPIO configuration bit 0:3, Summary of Interrupt enabling type
          GPIO_EN_INT_MASK = GPIO_EDGE_TRIGGER_MASK | GPIO_TRIGGER_POLARITY_MASK | GPIO_DUAL_EDGE_TRIGGER_MASK |                GPIO_INTERRUPT_ENABLE_MASK,
          GPIO_EN_INT_LEVEL_HIGH       = GPIO_INTERRUPT_ENABLE | GPIO_LEVEL_TRIGGER,
          GPIO_EN_INT_LEVEL_LOW        = GPIO_INTERRUPT_ENABLE | GPIO_LEVEL_TRIGGER | GPIO_TRIGGER_NEG,
          GPIO_EN_INT_RISING_EDGE      = GPIO_INTERRUPT_ENABLE | GPIO_EDGE_TRIGGER,
          GPIO_EN_INT_FALLING_EDGE   = GPIO_INTERRUPT_ENABLE | GPIO_EDGE_TRIGGER | GPIO_TRIGGER_NEG,
          GPIO_EN_INT_BOTH_EDGE        = GPIO_INTERRUPT_ENABLE | GPIO_EDGE_TRIGGER | GPIO_EDGE_TRIGGER_BOTH,
          /// GPIO configuration bit 4:5,and 14 output enable control and muxing control
          GPIO_INPUT_ENABLE            = 0x0000,
          GPIO_OUTPUT_DISABLE          = 0x0000,
          GPIO_OUTPUT_ENABLE           = 0x4000,
          GPIO_KS_OUTPUT_ENABLE        = 0x0010, //Keyscan Output enable
          GPIO_OUTPUT_FN_SEL_MASK      = 0x0030,
          GPIO_OUTPUT_FN_SEL_SHIFT     = 4,
      
          /// GPIO configuration bit 6, "Global_input_disable" Disable bit
          GPIO_GLOBAL_INPUT_ENABLE     = 0x0000,
          GPIO_GLOBAL_INPUT_DISABLE    = 0x0040,
          /// GPIO configuration bit 9 and bit 10, pull- up and pull-down enable
          GPIO_PULL_UP_DOWN_NONE       = 0x0000,   //[0,0]
          GPIO_PULL_UP                 = 0x0400,   //[1,0]
          GPIO_PULL_DOWN               = 0x0200,   //[0,1]
          GPIO_INPUT_DISABLE           = 0x0600,   //[1,1] //input disables the GPIO
          /// iocfg_p0[11] controls the drive strength of the following GPIOs p[0:25], p[30:39];
          /// iocfg_p26[11] controls the drive strength of the GPIOs p[26:29]
          GPIO_DRIVE_SEL_MASK         = 0x0800,
          GPIO_DRIVE_SEL_LOWEST       = 0x0000,  // 2mA @ 1.8V
          GPIO_DRIVE_SEL_MIDDLE_0     = 0x0000,  // 4mA @ 3.3v
          GPIO_DRIVE_SEL_MIDDLE_1     = 0x0800,  // 4mA @ 1.8v
          GPIO_DRIVE_SEL_HIGHEST      = 0x0800,  // 8mA @ 3.3v
          /// iocfg_p0[13] controls the hysteresis of the following GPIOs p[0:25], p[30:39];
          /// iocfg_p26[13] controls the hysteresis of the GPIOs p[26:29]
          GPIO_HYSTERESIS_MASK         = 0x2000,
          GPIO_HYSTERESIS_ON           = 0x2000,
          GPIO_HYSTERESIS_OFF          = 0x0000,
      };
      
      
      
      

       

        void gpio_setPinOutput(BYTE port, BYTE pin, BYTE val);

      void gpio_setPortOutput(BYTE port, UINT16 val) ;

      BYTE gpio_getPinOutput(BYTE port, BYTE pin);

      UINT16 gpio_getPortOutput(BYTE port);

        Set or Get GPIO output value by pin or port.

       

      UINT16 gpio_getPortInput(BYTE port);

      BYTE gpio_getPinInput(BYTE port, BYTE pin);

        Get the GPIO input value by pin or port.

       

      void gpio_registerForInterrupt(UINT16 masks[], void (*userfn)(void*, UINT8), void* userdata);

        Register the callback function for GPIO interrupt.

       

      BYTE gpio_getPinInterruptStatus(BYTE port, BYTE pin)

      UINT16 gpio_getPortInterruptStatus(BYTE port);

        Get GPIO interrupt status by pin or port, returns 1 if an interrupt is detected.

       

      void gpio_clearPinInterruptStatus(BYTE port, BYTE pin);

      void gpio_clearPortInterruptStatus(BYTE port, UINT16 mask);

        Clear GPIO interrupt status by pin or port.

       

      Sample Code

      Input GPIO, no interrupt

      #define TEST_PIN           28                               // test PIN 
      #define TEST_PIN2         29                               // test PIN 2
      #define PORT_ TEST      (TEST _PIN >> 4)       // PORT number of test PIN
      #define PIN_ TEST          (TEST _PIN & 0x0f)   // PIN number in PORT
      //configure the PIN28  to input, pull down
      gpio_configurePin( PORT_ TEST , PIN_TEST, GPIO_INPUT_ENABLE | GPIO_PULL_DOWN,    GPIO_PIN_OUTPUT_HIGH );
      //configure the PIN29 to input, pull up
      gpio_configurePinWithSingleBytePortPinNum( GPIO_INPUT_ENABLE | GPIO_PULL_UP,    GPIO_PIN_OUTPUT_HIGH );
      //get the value of input GPIO
      value 1= gpio_getPinInput(PORT_ TEST , PORT_PIN);
      value2 = gpio_getPinInput( TEST_PIN2 >>4, TEST_PIN2 &0x0f);
      
      
      
      

       

       

      Input GPIO, have interrupt

      The following sample code of GPIO interrupt is in i2c_temperature_sensor.c.

      // The GPIO port number to which the ALERT pin is connected.
      #define LM73_ALERT_INTERRUPT_PORT                (0)
      // The GPIO pin number to which the ALERT pin is connected
      #define LM73_ALERT_INTERRUPT_PIN                    (4)
      UINT8 temperature_sensor_initialize(void)
      {
          …
          // Set up the interrupt mask for the GPIO interrupt
          interrupt_handler_mask[LM73_ALERT_INTERRUPT_PORT] |= (1 << LM73_ALERT_INTERRUPT_PIN);
          // Now register the interrupt handler.
          gpio_registerForInterrupt(interrupt_handler_mask, temperature_sensor_gpio_interrupt_handler, NULL);
          // Now configure the pin. We will use both edges so that we know when the upper and lower thresholds are crossed.
          gpio_configurePin(LM73_ALERT_INTERRUPT_PORT, LM73_ALERT_INTERRUPT_PIN,
                  GPIO_EN_INT_BOTH_EDGE | GPIO_PULL_UP, GPIO_PIN_OUTPUT_LOW);
         …
      }
      //the callback function for GPIO interrupt
      void temperature_sensor_gpio_interrupt_handler(void* parameter, UINT8 arg)
      {
      …
      //clear the interrupt status
          gpio_clearPinInterruptStatus(LM73_ALERT_INTERRUPT_PORT, LM73_ALERT_INTERRUPT_PIN);
          …
      }
      
      
      
      

       

      About how to use one callback function to handle multi GPIO interrupts, please refer to forum link http://community.broadcom.com/thread/1994 .

       

       

      Output GPIO

      The following code is in bleaio.c.

      // use P15 for CS
      #define CS_PORT      0
      #define CS_PIN       15
      // CS is active low
      #define CS_ASSERT    0
      #define CS_DEASSERT  1
      void spiffy2_master_initialize(void)
      {
      …
          // Configure the CS pin to output, the initialized level is high.
          // If enabling output, you only need to configure once. Use gpio_setPinOutput to toggle value
          gpio_configurePin(CS_PORT, CS_PIN, GPIO_OUTPUT_ENABLE | GPIO_INPUT_DISABLE, CS_DEASSERT);
          …
        }
      void cmd_reset(void)
      {
         …
          // pull CSB low to start the command
          gpio_setPinOutput(CS_PORT, CS_PIN, CS_ASSERT);     // Assert chipselect, CS pin output low
          bleapputils_delayUs(1000);
          spiffyd_txData(SPIFFYD_2, 1 ,&byteToSend); // send reset sequence
          bleapputils_delayUs(3000);  // wait for the reset sequence timing
          // pull CSB high to finish the command
          gpio_setPinOutput(CS_PORT, CS_PIN, CS_DEASSERT);   // Deassert chipselect, CS pin output high
      }