mirror of
https://github.com/thelsing/knx.git
synced 2025-10-12 11:15:54 +02:00
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
685 lines
23 KiB
C
685 lines
23 KiB
C
/*
|
|
* Copyright (c) 2015-2019, Texas Instruments Incorporated
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of Texas Instruments Incorporated nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <ti/drivers/dpl/HwiP.h>
|
|
#include <ti/drivers/dpl/SemaphoreP.h>
|
|
#include <ti/drivers/dpl/SwiP.h>
|
|
|
|
#include <ti/drivers/pin/PINCC26XX.h>
|
|
#include <ti/drivers/Power.h>
|
|
#include <ti/drivers/power/PowerCC26XX.h>
|
|
|
|
#include <ti/devices/DeviceFamily.h>
|
|
#include DeviceFamily_constructPath(inc/hw_memmap.h)
|
|
#include DeviceFamily_constructPath(inc/hw_aon_event.h)
|
|
#include DeviceFamily_constructPath(inc/hw_aon_ioc.h)
|
|
#include DeviceFamily_constructPath(inc/hw_gpio.h)
|
|
#include DeviceFamily_constructPath(inc/hw_ioc.h)
|
|
#include DeviceFamily_constructPath(inc/hw_ints.h)
|
|
#include DeviceFamily_constructPath(inc/hw_ccfg.h)
|
|
#include DeviceFamily_constructPath(driverlib/driverlib_release.h)
|
|
#include DeviceFamily_constructPath(driverlib/chipinfo.h)
|
|
|
|
#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0)
|
|
#include DeviceFamily_constructPath(inc/hw_aon_sysctl.h)
|
|
#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
|
|
#include DeviceFamily_constructPath(inc/hw_aon_pmctl.h)
|
|
#endif
|
|
|
|
/*!*****************************************************************************
|
|
* @file PINCC26XX.c
|
|
* @brief Device-specific PIN & GPIO driver for CC26xx family [impl]
|
|
*
|
|
* # Overview #
|
|
* This is the device-specific implementation of the generic PIN driver for the
|
|
* CC26xx family of devices.
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
// Maximum number of pins (# available depends on package configuration)
|
|
#define MAX_NUM_PINS 31
|
|
|
|
/// Last DIO number available on package + device combination
|
|
uint32_t pinUpperBound = 0;
|
|
|
|
/// First DIO number available on package + device combination
|
|
uint32_t pinLowerBound = 0;
|
|
|
|
/// Array of handles, one per pin (pin id is index)
|
|
PIN_Handle pinHandleTable[MAX_NUM_PINS];
|
|
|
|
/// Pointer to GPIO configuration set by PIN_init(...), save state in order to revert when PIN_close(...)
|
|
static const PIN_Config *defaultPinConfig;
|
|
|
|
/// Array of indexes into GPIO configuration defaultPinConfig, one per pin (pin id is index)
|
|
static uint8_t pinGpioConfigTable[MAX_NUM_PINS];
|
|
|
|
/// HW interrupt structure for I/O interrupt handler
|
|
static HwiP_Struct pinHwi;
|
|
|
|
/// SWI structure for the followup of the I/O interrupt handler
|
|
static SwiP_Struct pinSwi;
|
|
|
|
/// PIN driver semaphore used to implement synchronicity for PIN_open()
|
|
static SemaphoreP_Struct pinSemaphore;
|
|
|
|
/// Hardware attribute structure populated in board.c to set HWI and SWI priorities
|
|
extern const PINCC26XX_HWAttrs PINCC26XX_hwAttrs;
|
|
|
|
// I/O SWI service routine that posts the callback in a SWI context
|
|
static void PIN_swi(uintptr_t arg0, uintptr_t arg1){
|
|
|
|
uint32_t eventMask;
|
|
unsigned char eventCounter;
|
|
PIN_Handle handle;
|
|
PIN_IntCb callbackFxn;
|
|
|
|
// Get the OR'd trigger value representing all events values prior to running the SWI
|
|
eventMask = SwiP_getTrigger();
|
|
|
|
// eventCounter cycles through all pins on the device up to the max number of pins
|
|
for(eventCounter = 0; eventCounter <= pinUpperBound; eventCounter++){
|
|
// Check if current eventCounter bit is set in eventMask
|
|
if(eventMask & (1 << eventCounter)){
|
|
// Get pin handle and registered callback function
|
|
// Double paranthesis to supress GCC warning
|
|
// Intentional assignment is intended, not the equality comparison
|
|
if((handle = pinHandleTable[eventCounter])) {
|
|
if((callbackFxn = handle->callbackFxn)) {
|
|
// Event from existing pin, with an associated handle and a
|
|
// registered callback -> call callback
|
|
// Run the callback function in a SWI context.
|
|
callbackFxn(handle, eventCounter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// I/O HWI service routine
|
|
static void PIN_hwi(uintptr_t arg) {
|
|
uint32_t eventMask;
|
|
|
|
// Get event flag with lowest index (also pin ID)
|
|
eventMask = HWREG(GPIO_BASE + GPIO_O_EVFLAGS31_0);
|
|
|
|
// Clear this event flag
|
|
HWREG(GPIO_NONBUF_BASE + GPIO_O_EVFLAGS31_0) = eventMask;
|
|
|
|
// Include all GPIO's currently triggered in the SWI
|
|
SwiP_or(&(pinSwi), eventMask);
|
|
}
|
|
|
|
// Internal utility function for setting IOCFG register for pin
|
|
static void PINCC26XX_setIoCfg(PIN_Config updateMask, PIN_Config pinCfg) {
|
|
uint32_t tmpConfig;
|
|
PIN_Id pinId = PIN_ID(pinCfg);
|
|
bool invertChanges;
|
|
|
|
if (pinCfg & PIN_GEN) {
|
|
// Translate from device-independent to device-specific PIN_Config values
|
|
pinCfg ^= PIN_GEN | PIN_BM_INPUT_EN | PIN_BM_PULLING;
|
|
}
|
|
// Get existing IOCFG, determine whether inversion changes, mask away what will be updated
|
|
tmpConfig = HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId);
|
|
invertChanges = (tmpConfig ^ pinCfg) & updateMask & PINCC26XX_INV_INOUT;
|
|
tmpConfig &= ~updateMask;
|
|
|
|
// Insert what we want to update, possibly revert IRQ edges, write back to IOCFG
|
|
tmpConfig |= (pinCfg & updateMask & PINCC26XX_BM_IOCFG);
|
|
if ((updateMask & PINCC26XX_BM_IRQ) == PINCC26XX_BM_IRQ && (tmpConfig & PINCC26XX_INV_INOUT) == 0) {
|
|
// We're changing IRQ options but inversion will not be enabled -> keep IRQ options
|
|
} else if ((updateMask & PINCC26XX_BM_IRQ) == 0 && !invertChanges) {
|
|
// We're not changing IRQ options and inversion remains unchanged -> keep IRQ options
|
|
} else {
|
|
// We're updating IRQ options and inversion will be enabled, OR
|
|
// we're not updating IRQ options but inversion settings change
|
|
// -> reverse polarity of edge detection when positive-only or negative-only
|
|
switch (tmpConfig & PINCC26XX_BM_IRQ) {
|
|
case PINCC26XX_IRQ_POSEDGE:
|
|
tmpConfig &= ~PINCC26XX_BM_IRQ;
|
|
tmpConfig |= PINCC26XX_IRQ_NEGEDGE;
|
|
break;
|
|
case PINCC26XX_IRQ_NEGEDGE:
|
|
tmpConfig &= ~PINCC26XX_BM_IRQ;
|
|
tmpConfig |= PINCC26XX_IRQ_POSEDGE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Clear any pending events from the previous pin configuration before we write the new interrupt settings */
|
|
PINCC26XX_clrPendInterrupt(pinId);
|
|
HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId) = tmpConfig;
|
|
|
|
// Update GPIO output value and enable depending on previous output mode (enabled or disabled)
|
|
{
|
|
bool outputEnabled = (HWREG(GPIO_BASE + GPIO_O_DOE31_0) & (1 << pinId)) ? true : false;
|
|
|
|
if(!outputEnabled) {
|
|
if (updateMask & PINCC26XX_BM_GPIO_OUTPUT_VAL) {
|
|
// Set GPIO output value
|
|
HWREGB(GPIO_BASE + GPIO_O_DOUT3_0 + pinId) = (pinCfg & PINCC26XX_BM_GPIO_OUTPUT_VAL) ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
if (updateMask & PINCC26XX_BM_GPIO_OUTPUT_EN) {
|
|
// Set GPIO output enable
|
|
uint32_t key = HwiP_disable();
|
|
HWREG(GPIO_BASE + GPIO_O_DOE31_0) =
|
|
(HWREG(GPIO_BASE + GPIO_O_DOE31_0) & ~(1 << pinId)) |
|
|
((pinCfg&PINCC26XX_BM_GPIO_OUTPUT_EN) ? (1 << pinId) : 0);
|
|
HwiP_restore(key);
|
|
}
|
|
|
|
if(outputEnabled) {
|
|
if (updateMask & PINCC26XX_BM_GPIO_OUTPUT_VAL) {
|
|
// Set GPIO output value
|
|
HWREGB(GPIO_BASE + GPIO_O_DOUT3_0 + pinId) = (pinCfg & PINCC26XX_BM_GPIO_OUTPUT_VAL) ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Clear any events from pin value changes as a result of the new configuration */
|
|
PINCC26XX_clrPendInterrupt(pinId);
|
|
}
|
|
|
|
|
|
|
|
// Internal utility function for setting mux setting in IOCFG register for pin
|
|
static void PINCC26XX_setIoCfgMux(PIN_Id pinId, int32_t mux) {
|
|
// Read in existing value in IOCFG register and update with supplied mux value
|
|
if (mux < 0) {
|
|
mux = PINCC26XX_MUX_GPIO;
|
|
}
|
|
uint32_t tmpConfig;
|
|
tmpConfig = HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId);
|
|
tmpConfig &= ~IOC_IOCFG0_PORT_ID_M;
|
|
tmpConfig |= mux & IOC_IOCFG0_PORT_ID_M;
|
|
HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId) = tmpConfig;
|
|
}
|
|
|
|
uint32_t PINCC26XX_getPinCount(){
|
|
// Get number of pins available on device (from HW register)
|
|
uint32_t pinCount = (( HWREG( FCFG1_BASE + FCFG1_O_IOCONF ) &
|
|
FCFG1_IOCONF_GPIO_CNT_M ) >>
|
|
FCFG1_IOCONF_GPIO_CNT_S ) ;
|
|
|
|
return pinCount;
|
|
}
|
|
|
|
PIN_Status PIN_init(const PIN_Config pinConfig[]) {
|
|
uint32_t i;
|
|
uint32_t pinConfigMask = 0; // Works as long as # pins <=32
|
|
HwiP_Params hwiParams;
|
|
SwiP_Params swiParams;
|
|
uint32_t reservedPinMask = 0;
|
|
|
|
// Its ok if Power init has already been called.
|
|
Power_init();
|
|
|
|
// Make sure we are using correct version of Driverlib
|
|
DRIVERLIB_ASSERT_CURR_RELEASE();
|
|
|
|
/* pinLowerBound is initialized to 0 by default.
|
|
* All cases where this is not the case are handled here.
|
|
*/
|
|
switch (ChipInfo_GetChipType()) {
|
|
case CHIP_TYPE_CC1310:
|
|
case CHIP_TYPE_CC1350:
|
|
case CHIP_TYPE_CC1312:
|
|
if (ChipInfo_GetPackageType() == PACKAGE_7x7) {
|
|
pinLowerBound = 1;
|
|
reservedPinMask |= 0x01;
|
|
}
|
|
break;
|
|
case CHIP_TYPE_CC1352:
|
|
pinLowerBound = 3;
|
|
reservedPinMask |= 0x07;
|
|
break;
|
|
case CHIP_TYPE_CC1352P:
|
|
pinLowerBound = 5;
|
|
reservedPinMask |= 0x1F;
|
|
break;
|
|
}
|
|
|
|
if ((HWREG(CCFG_BASE + CCFG_O_MODE_CONF) & CCFG_MODE_CONF_SCLK_LF_OPTION_M) >> CCFG_MODE_CONF_SCLK_LF_OPTION_S == 0x1) {
|
|
// An IO is used for LF clock input
|
|
reservedPinMask |= (1 << ((HWREG(CCFG_BASE+CCFG_O_EXT_LF_CLK) & CCFG_EXT_LF_CLK_DIO_M) >> CCFG_EXT_LF_CLK_DIO_S));
|
|
}
|
|
|
|
// Get the last addressable DIO number
|
|
pinUpperBound = pinLowerBound + PINCC26XX_getPinCount() - 1;
|
|
|
|
// Initialize table of pins that have default GPIO configuration
|
|
for (i = 0; i <= pinUpperBound; i++) {
|
|
pinGpioConfigTable[i] = PIN_UNASSIGNED;
|
|
}
|
|
|
|
|
|
// Read in pinConfig list and create bitmask of which IOs to initialize to
|
|
// default values and which to initialize from pinConfig
|
|
for (i = 0, pinConfigMask = 0; PIN_ID(pinConfig[i]) != PIN_TERMINATE; i++) {
|
|
// Ignore unassigned pins
|
|
if (PIN_ID(pinConfig[i]) == PIN_UNASSIGNED) {
|
|
continue;
|
|
}
|
|
// Check that pin exists and is available
|
|
if (PIN_ID(pinConfig[i]) > pinUpperBound || PIN_ID(pinConfig[i]) < pinLowerBound || reservedPinMask & (1 << PIN_ID(pinConfig[i]))) {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
// Mark pin as being in pinConfig
|
|
pinConfigMask |= (1 << PIN_ID(pinConfig[i]));
|
|
// For quick reference, store index i in table
|
|
pinGpioConfigTable[PIN_ID(pinConfig[i])] = i;
|
|
}
|
|
|
|
// Set Power dependecies & constraints
|
|
Power_setDependency(PowerCC26XX_PERIPH_GPIO);
|
|
|
|
// Save GPIO default setup
|
|
defaultPinConfig = pinConfig;
|
|
|
|
// Setup semaphore for sequencing accesses to PIN_open()
|
|
SemaphoreP_constructBinary(&pinSemaphore, 1);
|
|
|
|
// Loop thru all pins and configure
|
|
for (i = 0; i <= pinUpperBound; i++) {
|
|
if (reservedPinMask & (1 << i)) {
|
|
// Pin is reserved for other purposes -> setup dummy handle
|
|
pinHandleTable[i] = (PIN_State*)0x00000004;
|
|
}
|
|
else {
|
|
if (pinConfigMask & (1 << i)) {
|
|
// Setup all pins in pinConfig as instructed
|
|
PINCC26XX_setIoCfg(PIN_BM_ALL, pinConfig[pinGpioConfigTable[i]]);
|
|
}
|
|
else {
|
|
// Setup all pins not in pinConfig to default configuration:
|
|
// GPIO, input buffer disable, GPIO output disable, low GPIO output, no pull, no IRQ, no wakeup
|
|
PINCC26XX_setIoCfg(PIN_BM_ALL, PIN_ID(i) | PINCC26XX_NOPULL);
|
|
}
|
|
// Set pin as GPIO and clear pin handle
|
|
PINCC26XX_setIoCfgMux(PIN_ID(i), -1);
|
|
pinHandleTable[i] = NULL;
|
|
}
|
|
}
|
|
|
|
// Setup HWI handler
|
|
HwiP_Params_init(&hwiParams);
|
|
hwiParams.priority = PINCC26XX_hwAttrs.intPriority;
|
|
HwiP_construct(&pinHwi, INT_AON_GPIO_EDGE, PIN_hwi, &hwiParams);
|
|
|
|
// Setup SWI handler
|
|
SwiP_Params_init(&(swiParams));
|
|
swiParams.priority = PINCC26XX_hwAttrs.swiPriority;
|
|
swiParams.trigger = 0;
|
|
SwiP_construct(&pinSwi, PIN_swi, &(swiParams));
|
|
|
|
// Setup interrupts so that they wake up from standby (use MCU_WU1)
|
|
HWREG(AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL) =
|
|
(HWREG(AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL) & (~AON_EVENT_MCUWUSEL_WU1_EV_M)) |
|
|
AON_EVENT_MCUWUSEL_WU1_EV_PAD;
|
|
|
|
// Open latches out to I/Os
|
|
// This might be unnecessary, but isn't when you start from debugger
|
|
HWREG(AON_IOC_BASE + AON_IOC_O_IOCLATCH) = AON_IOC_IOCLATCH_EN;
|
|
|
|
// If we boot from shutdown, the IOs are latched, this opens the latches again
|
|
#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0)
|
|
HWREG(AON_SYSCTL_BASE + AON_SYSCTL_O_SLEEPCTL) = AON_SYSCTL_SLEEPCTL_IO_PAD_SLEEP_DIS;
|
|
#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
|
|
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_SLEEPCTL) = AON_PMCTL_SLEEPCTL_IO_PAD_SLEEP_DIS;
|
|
#endif
|
|
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Handle PIN_open(PIN_State* state, const PIN_Config pinList[]) {
|
|
uint32_t i;
|
|
bool pinsAllocated = true;
|
|
uint32_t portMask = 0;
|
|
PIN_Id pinId;
|
|
|
|
if ((state == NULL) || (pinList == NULL)) {
|
|
return (NULL);
|
|
}
|
|
|
|
// Ensure that only one client at a time can call PIN_open() or PIN_add()
|
|
SemaphoreP_pend(&pinSemaphore, SemaphoreP_WAIT_FOREVER);
|
|
|
|
// Check whether all pins in pinList are valid and available first
|
|
for (i = 0; (pinId = PIN_ID(pinList[i])) != PIN_TERMINATE; i++) {
|
|
/* Unassigned pins is allowed, but cannot generate a bitmask. */
|
|
if (pinId != PIN_UNASSIGNED) {
|
|
if ((pinId > pinUpperBound) ||
|
|
(pinId >= MAX_NUM_PINS) || // For Klocwork
|
|
pinHandleTable[pinId]) {
|
|
pinsAllocated = false;
|
|
break;
|
|
} else {
|
|
// Generate bitmask for port operations (always one port on CC26xx)
|
|
portMask |= (1 << pinId);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pinsAllocated) {
|
|
// Indicate that the pins were not allocatable
|
|
state = NULL;
|
|
} else {
|
|
// Setup state object
|
|
state->callbackFxn = NULL;
|
|
state->portMask = 0;
|
|
state->userArg = 0;
|
|
|
|
// Configure I/O pins according to pinList
|
|
for (i = 0; (pinId = PIN_ID(pinList[i])) != PIN_TERMINATE; i++) {
|
|
// Check pinId < MAX_NUM_PINS for Klocwork
|
|
if ((pinId != PIN_UNASSIGNED) && (pinId < MAX_NUM_PINS)) {
|
|
pinHandleTable[pinId] = state;
|
|
state->portMask |= (1 << pinId);
|
|
PIN_setConfig(state, PIN_BM_ALL, pinList[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
SemaphoreP_post(&pinSemaphore);
|
|
return state;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_add(PIN_Handle handle, PIN_Config pinCfg) {
|
|
PIN_Status returnStatus;
|
|
PIN_Id pinId = PIN_ID(pinCfg);
|
|
|
|
// Check that handle and pinId is valid
|
|
if (!handle || (pinId > pinUpperBound) || (pinId >= MAX_NUM_PINS)) {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
|
|
// Ensure that only one client at a time can call PIN_open() or PIN_add()
|
|
SemaphoreP_pend(&pinSemaphore, SemaphoreP_WAIT_FOREVER);
|
|
|
|
// Check whether pin is available
|
|
if (pinHandleTable[pinId]) {
|
|
// Pin already allocated -> do nothing
|
|
returnStatus = PIN_ALREADY_ALLOCATED;
|
|
} else {
|
|
// Allocate pin
|
|
pinHandleTable[pinId] = handle;
|
|
handle->portMask |= (1 << pinId);
|
|
PIN_setConfig(handle, PIN_BM_ALL, pinCfg);
|
|
returnStatus = PIN_SUCCESS;
|
|
}
|
|
|
|
SemaphoreP_post(&pinSemaphore);
|
|
return returnStatus;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_remove(PIN_Handle handle, PIN_Id pinId) {
|
|
if (handle && (handle->portMask & (1 << pinId))) {
|
|
// Deallocate pin
|
|
handle->portMask &= ~(1 << pinId);
|
|
pinHandleTable[pinId] = NULL;
|
|
// Find GPIO default value and revert to it
|
|
if (pinGpioConfigTable[pinId] == PIN_UNASSIGNED) {
|
|
// Revert pin to default configuration:
|
|
// GPIO, input buffer disable, GPIO output disable, low GPIO output, no pull, no IRQ, no wakeup
|
|
PINCC26XX_setIoCfg(PIN_BM_ALL, PIN_ID(pinId) | PIN_INPUT_DIS);
|
|
} else {
|
|
// Revert pin to previous GPIO configuration
|
|
PINCC26XX_setIoCfg(PIN_BM_ALL, defaultPinConfig[pinGpioConfigTable[pinId]]);
|
|
}
|
|
// Revert to GPIO
|
|
PINCC26XX_setIoCfgMux(PIN_ID(pinId), -1);
|
|
return PIN_SUCCESS;
|
|
} else {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PIN_close(PIN_Handle handle) {
|
|
uint32_t i;
|
|
|
|
// No need for sequencing accesses to PIN_close()
|
|
// For each pin in port bitmask
|
|
while (handle->portMask) {
|
|
// Find lowest index pin
|
|
i = PIN_ctz(handle->portMask);
|
|
// Deallocate pin
|
|
PIN_remove(handle, i);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
uint32_t PIN_getInputValue(PIN_Id pinId) {
|
|
return PINCC26XX_getInputValue(pinId);
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setOutputEnable(PIN_Handle handle, PIN_Id pinId, bool outputEnable) {
|
|
if (PIN_CHKEN && (pinId > pinUpperBound || pinHandleTable[pinId] != handle)) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setOutputEnable(pinId, outputEnable);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setOutputValue(PIN_Handle handle, PIN_Id pinId, uint32_t val) {
|
|
if (PIN_CHKEN && (pinId > pinUpperBound || pinHandleTable[pinId] != handle)) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setOutputValue(pinId, val);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
uint32_t PIN_getOutputValue(PIN_Id pinId) {
|
|
return PINCC26XX_getOutputValue(pinId);
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setInterrupt(PIN_Handle handle, PIN_Config pinCfg) {
|
|
if (PIN_CHKEN && ((PIN_ID(pinCfg) > pinUpperBound) ||
|
|
(PIN_ID(pinCfg) >= MAX_NUM_PINS) ||
|
|
(pinHandleTable[PIN_ID(pinCfg)] != handle))) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PIN_setConfig(handle, PIN_BM_IRQ, pinCfg);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_clrPendInterrupt(PIN_Handle handle, PIN_Id pinId) {
|
|
if (PIN_CHKEN && ((pinId > pinUpperBound) ||
|
|
(pinId >= MAX_NUM_PINS) ||
|
|
(pinHandleTable[pinId] != handle))) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_clrPendInterrupt(pinId);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_registerIntCb(PIN_Handle handle, PIN_IntCb pCb) {
|
|
if (handle) {
|
|
handle->callbackFxn = pCb;
|
|
return PIN_SUCCESS;
|
|
} else {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PIN_Config PIN_getConfig(PIN_Id pinId) {
|
|
// Translate from device-specific to device independent PIN_Config values
|
|
return PIN_GEN | (PINCC26XX_getConfig(pinId) ^ (PIN_BM_INPUT_EN | PIN_BM_PULLING));
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setConfig(PIN_Handle handle, PIN_Config updateMask, PIN_Config pinCfg) {
|
|
if (PIN_CHKEN && (PIN_ID(pinCfg) > pinUpperBound ||
|
|
(PIN_ID(pinCfg) >= MAX_NUM_PINS) ||
|
|
(pinHandleTable[PIN_ID(pinCfg)] != handle))) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setIoCfg(updateMask, pinCfg);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Config PINCC26XX_getConfig(PIN_Id pinId) {
|
|
// Get IOCFG register value and add in some extras:
|
|
// * pinId
|
|
// * pin GPIO output enable
|
|
// * pin GPIO output value
|
|
uint32_t tmpConfig;
|
|
|
|
tmpConfig = HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId);
|
|
tmpConfig &= PINCC26XX_BM_IOCFG;
|
|
tmpConfig |= PIN_ID(pinId);
|
|
tmpConfig |= (PINCC26XX_getOutputValue(pinId)) ? PINCC26XX_GPIO_HIGH : PINCC26XX_GPIO_LOW;
|
|
tmpConfig |= (HWREG(GPIO_BASE + GPIO_O_DOE31_0) & (1 << pinId)) ? PINCC26XX_GPIO_OUTPUT_EN : 0;
|
|
return tmpConfig;
|
|
}
|
|
|
|
|
|
|
|
int32_t PINCC26XX_getMux(PIN_Id pinId) {
|
|
if (PIN_CHKEN && pinId > pinUpperBound) {
|
|
// Non-existing pin
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
int32_t tmpConfig;
|
|
tmpConfig = HWREG(IOC_BASE + IOC_O_IOCFG0 + 4 * pinId);
|
|
tmpConfig &= IOC_IOCFG0_PORT_ID_M;
|
|
if (tmpConfig == PINCC26XX_MUX_GPIO) {
|
|
tmpConfig = -1;
|
|
}
|
|
return tmpConfig;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PINCC26XX_setMux(PIN_Handle handle, PIN_Id pinId, int32_t mux) {
|
|
// Add check for pinId >= MAX_NUM_PINS for Klocwork
|
|
if (PIN_CHKEN && ((pinId > pinUpperBound) ||
|
|
(pinId >= MAX_NUM_PINS) ||
|
|
(pinHandleTable[pinId] != handle))) {
|
|
// Non-existing pin or pin is not allocated to this client
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setIoCfgMux(pinId, mux);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PINCC26XX_setWakeup(const PIN_Config pinConfig[]) {
|
|
uint32_t i;
|
|
// TODO: is this enough?
|
|
|
|
for (i = 0; PIN_ID(pinConfig[i]) != PIN_TERMINATE; i++) {
|
|
PINCC26XX_setIoCfg(PINCC26XX_BM_ALL, pinConfig[i]);
|
|
}
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
uint32_t PIN_getPortMask(PIN_Handle handle) {
|
|
// On CC26xx there is only one port encompassing all pins
|
|
if (handle) {
|
|
return handle->portMask;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
uint32_t PIN_getPortInputValue(PIN_Handle handle) {
|
|
return PINCC26XX_getPortInputValue(handle);
|
|
}
|
|
|
|
|
|
|
|
uint32_t PIN_getPortOutputValue(PIN_Handle handle) {
|
|
return PINCC26XX_getPortOutputValue(handle);
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setPortOutputValue(PIN_Handle handle, uint32_t bmOutVal) {
|
|
if (PIN_CHKEN && (handle == NULL || pinHandleTable[PIN_ctz(handle->portMask)] != handle)) {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setPortOutputValue(handle, bmOutVal);
|
|
return PIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PIN_Status PIN_setPortOutputEnable(PIN_Handle handle, uint32_t bmOutEn) {
|
|
if (PIN_CHKEN && (handle == NULL || pinHandleTable[PIN_ctz(handle->portMask)] != handle)) {
|
|
return PIN_NO_ACCESS;
|
|
}
|
|
PINCC26XX_setPortOutputEnable(handle, bmOutEn);
|
|
return PIN_SUCCESS;
|
|
}
|