.. _sec-cc23xx-gpio++-porting-guide:

GPIO++ Driver Porting Guide
===========================
Recently an updated GPIO driver with was released to replace the older GPIO (:tidrivers_api:`PIN.h`) driver.
To avoid naming confusion, this page will generally refer to the new GPIO driver as GPIO++. 
GPIO++ is a drop-in replacement for the existing driver. This guide will briefly outline the significant 
changes when porting from PIN (:tidrivers_api:`PIN.h`) to GPIO++ and from GPIO (:tidrivers_api:`GPIO.h`) to GPIO++.

The |DEVICE| devices do not support the older :tidrivers_api:`PIN.h` library and projects being ported to this device
that make use of the older library must be ported to use the newer GPIO++ library.

.. note::
  The PIN and GPIO drivers will be deprecated in the 6.20 (2Q22) SDK release. New devices will only support the GPIO++ driver.

Porting PIN code to GPIO++
--------------------------

Existing code using PIN will have a few components:

.. code-block:: c

    PIN_State pinState;
    PIN_Config i2cPinTable[3];
    i2cPinTable[i++] = i2cPins.pinSDA | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN;
    i2cPinTable[i++] = i2cPins.pinSCL | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN;
    i2cPinTable[i++] = PIN_TERMINATE;
    
    PIN_Handle handle = PIN_open(&pinState, i2cPinTable);
    
    PINCC26XX_setMux(handle, i2cPins.pinSDA, IOC_PORT_MCU_I2C_MSSDA);
    PINCC26XX_setMux(handle, i2cPins.pinSCL, IOC_PORT_MCU_I2C_MSSCL);
    
    /* Resets configs back to original board file values */
    PIN_close(handle);

Much of this code is no longer needed in GPIO++, because it has no concept of pin ownership. The equivalent code is:

.. code-block:: c

    /* We can omit these calls entirely, since the setMux call will take ownership of the pin immediately. 
    See the notes for details. */

    // GPIO_setConfig(i2cPins.pinSDA, GPIO_CFG_IN_PU);
    // GPIO_setConfig(i2cPins.pinSCL, GPIO_CFG_IN_PU);
    
    GPIO_setMux(i2cPins.pinSDA, IOC_PORT_MCU_I2C_MSSDA);
    GPIO_setMux(i2cPins.pinSCL, IOC_PORT_MCU_I2C_MSSCL);
    
    /* Resets configs back to original board file values */
    GPIO_resetConfig(i2cPins.pinSDA)
    GPIO_resetConfig(i2cPins.pinSCL);

Practical considerations:

    * Since there is no 'close' function, you need to keep track of indexes if you want to later 
      reset the configured pins with GPIO_resetConfig(). This usually means keeping a few index 
      variables instead of the PIN_Handle - in the example above, the indexes are tracked as part 
      of the i2cPins object.
    * If you were configuring pins with high/low/pullup/pulldown values when calling PIN_open() 
      and muxing them immediately after, you can entirely omit the setConfig call
        
        * This was needed because PIN_open() set the pin configurations and could cause line glitches. 
          You can now mux without configuring at all.
        * For example, if you had UART_TX configured as floating or pull down, it might change value 
          between PIN_open() and PIN_setMux() and cause UART framing errors
    
    * Pin IDs and GPIO++ indexes are both 1-1 with DIO numbers, so no need to change indexing strategy
    * If your callbacks make use of PIN's userArg feature, replace this with GPIO_setPinUserArg() 
      in your configuration code and GPIO_getPinUserArg() from the callback to access the value```

Porting GPIO code to GPIO++
---------------------------

Existing GPIO code is directly compatible with GPIO++ code, except that the indexes passed to each API 
are now device DIOs instead of GPIO pinConfig indexes. If you use syscfg, this detail is handled for you - 
continue to use CONFIG_GPIO_XYZ as normal.

Practical considerations:

    * The ti_drivers_config layout is very different for GPIO++ and is not compatible with existing code. 
      GPIO.h has examples of how to set it up if you are working from scratch, otherwise you have to 
      regenerate your sysconfig files.
    * GPIO++ is smaller and significantly faster, but lacks runtime pin checking. If you pass in pin index 
      130, you will either get a hardfault or memory corruption.
        
        * If you would like to do some range checking in your callsite (to e.g. validate untrusted inputs), 
          you can extern the symbols GPIO_pinUpperBound and GPIO_pinLowerBound, which are generated by syscfg.

Updating existing sysconfig files
----------------------------------

In some cases, modifications may be required to existing sysconfig files. If the sysconfig tool displays 
an error when opened in the GUI, open the file with a text editor instead and look for the following:

    * Existing GPIO instances with configured pin instances. All lines where the file has 
      GPIOn.pinInstance.xxx must be removed, for example GPIO1.pinInstance.$name = "CONFIG_PIN_1".
    * Note that some drivers may also have pinInstances, for example UART1.txPinInstance.xxx; 
      these accesses are backwards-compatible and should be left alone.

