GPIO++ Driver Porting Guide¶
In the 5.30 SDK an updated GPIO driver with native implementations on CC13xx and CC26xx devices was released. To avoid naming confusion, this page will generally refer to it as GPIO++. GPIO++ is a drop-in replacement for the existing driver. This guide will briefly outline the significant changes when porting from PIN (PIN.h) to GPIO++ and from GPIO (GPIO.h) to GPIO++.
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:
PIN_State pinState; PIN_Config i2cPinTable; 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:
/* 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);
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.
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.