knx/source/ti/drivers/timer/GPTimerCC26XX.c
Nanosonde e51b65f8c2 Squashed 'examples/knx-cc1310/coresdk_cc13xx_cc26xx/' content from commit 0d78d32
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx
git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
2020-10-21 10:00:49 +02:00

783 lines
27 KiB
C

/*
* Copyright (c) 2015-2018, 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.
*/
/*!*****************************************************************************
* @file GPTimerCC26XX.c
* @brief CC26XX/CC13XX driver implementation for GPTimer peripheral
*
*
*******************************************************************************
*/
#include <ti/drivers/dpl/DebugP.h>
#include <ti/drivers/dpl/HwiP.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/drivers/timer/GPTimerCC26XX.h>
#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(inc/hw_gpt.h)
#include DeviceFamily_constructPath(driverlib/timer.h)
/* GPTimer configuration array from application */
extern const GPTimerCC26XX_Config GPTimerCC26XX_config[];
/* Register masks used by GPTimerCC26XX_resetHw */
#define GPT_CTL_MASK (GPT_CTL_TASTALL_M | GPT_CTL_TAEVENT_M | GPT_CTL_TAPWML_M)
/* GPTimerCC26XX internal functions */
static void GPTimerCC26XX_initHw(GPTimerCC26XX_Handle handle, const GPTimerCC26XX_Params *params);
static void GPTimerCC26XX_resetHw(GPTimerCC26XX_Handle handle);
static void GPTimerCC26XXThreadsafeConstraintClr(GPTimerCC26XX_Handle handle);
static void GPTimerCC26XXThreadsafeConstraintSet(GPTimerCC26XX_Handle handle);
static void GPTimerCC26XXHwiFxn(uintptr_t a0);
static void GPTimerCC26XXSetLoadMatch(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Value loadMatchVal, uint32_t regPre, uint32_t regLoadMatch);
static GPTimerCC26XX_Value GPTimerCC26XX_getTimerValue(GPTimerCC26XX_Handle handle, uint32_t reg);
/* GPTimerCC26XX temporary internal functions.
Will be removed once they are added to driverlib
*/
static inline void TimerSetConfig(uint32_t ui32Base, uint32_t ui32Config);
static inline void TimerSetMode(uint32_t ui32Base, uint32_t timer, uint32_t mode);
/* Lookup table definition for interfacing driverlib and register fields.
Used to simplify code and to easily look up register fields as several fields
are not symmetric across timer A and timer B registers (interrupts & dma)
*/
typedef struct GPTimerCC26XX_LUT
{
uint16_t map; /* Timer argument in driverlib (TIMER_A / TIMER_B) */
uint16_t shift; /* Bit shift for registers shared between GPT_A / GPT_B */
uint16_t offset; /* Byte offset for registers sequentially in memory map for GPT_A/GPT_B */
uint16_t interrupts[GPT_NUM_INTS]; /* Interrupt bitfields for GPTA/B. Order must match GPTimerCC26XX_Interrupt */
} const GPTimerCC26XX_LUT;
/* Lookup table definition for interfacing driverlib and register fields. */
static const GPTimerCC26XX_LUT GPT_LUT[GPT_PARTS_COUNT] =
{
{
.map = TIMER_A,
.shift = 0,
.offset = 0,
.interrupts ={ GPT_MIS_TATOMIS, GPT_MIS_CAMMIS, GPT_MIS_CAEMIS, GPT_MIS_TAMMIS },
},
{
.map = TIMER_B,
.shift = 8,
.offset = 4,
.interrupts ={ GPT_MIS_TBTOMIS, GPT_MIS_CBMMIS, GPT_MIS_CBEMIS, GPT_MIS_TBMMIS },
},
};
/* Default GPTimer parameters */
static const GPTimerCC26XX_Params GPT_DefaultParams =
{
.width = GPT_CONFIG_32BIT,
.mode = GPT_MODE_PERIODIC,
.matchTiming = GPTimerCC26XX_SET_MATCH_NEXT_CLOCK,
.direction = GPTimerCC26XX_DIRECTION_UP,
.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF,
};
/*!
* @brief Generic bit vector to lookup table vector implementation
*
* Parses generic lookup table and checks whether inputs exists in lookup table.
*
* @param pLookup pointer to look-up table
* @param inputVector Input vector
* @param length Number of bits in lookup table
*
* @return A bit vector containing set fields in lookup table
*/
static uint16_t GPTimerCC26XXLookupMask(const uint16_t *pLookup, uint16_t inputVector, uint8_t length)
{
uint16_t maskLookup = 0;
uint32_t i;
/* Fetch data from lookup table */
for (i = 0; i < length; i++)
{
/* Check if current index of lookup table is in input vector */
if (inputVector & pLookup[i])
{
/* Add vector input to looked up mask. */
maskLookup |= 1 << i;
}
}
return maskLookup;
}
/*!
* @brief Generic lookup table to bit vector implementation
*
* Parses input vector and checks which input fields are set
*
* @param pLookup pointer to look-up table
* @param inputVector Input vector
* @param length Number of bits in lookup table
*
* @return A bit vector mapped from lookup table
*/
static uint16_t GPTimerCC26XXReverseLookupMask(const uint16_t *pLookup, uint16_t inputVector, uint8_t length)
{
uint16_t revMaskLookup = 0;
uint32_t i;
for (i = 0; i < length; i++)
{
/* Check if current index is set in input vector */
if (inputVector & (1 << i))
{
/* Add data from lookup table */
revMaskLookup |= pLookup[i];
}
}
return revMaskLookup;
}
/*!
* @brief Function to initialize the GPTimerCC26XX_Params struct to default
* values
*
* @param params An pointer to GPTimerCC26XX_Params structure for
* initialization
*
* Defaults values are:
* Timer width : 32 bits,
* Timer mode : Periodic mode counting upwards
* Timer debug stall mode: Disabled
*/
void GPTimerCC26XX_Params_init(GPTimerCC26XX_Params *params)
{
*params = GPT_DefaultParams;
}
/*!
* @brief This function opens the given GPTimer peripheral. It will set a
* dependency on the timer, configure the timer mode and set timer
* as open. If params is NULL default values will be used.
*
* @return A GPTimerCC26XX_Handle on success or NULL on error or if timer is
* already open. If NULL is returned further GPTimer API calls will
* result in undefined behaviour.
*
* @sa GPTimerCC26XX_close()
*/
GPTimerCC26XX_Handle GPTimerCC26XX_open(unsigned int index, const GPTimerCC26XX_Params *params)
{
unsigned int key;
GPTimerCC26XX_Handle handle = (GPTimerCC26XX_Handle) & GPTimerCC26XX_config[index];
/* Get the pointer to the object and hwAttrs and timer*/
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
/*
* Input argument checks
*/
/* Fail if no params supplied */
if (params == NULL)
{
DebugP_log1("Timer:(%p): No params supplied, using default.", hwAttrs->baseAddr);
params = &GPT_DefaultParams;
}
if (params->width == GPT_CONFIG_32BIT)
{
/* Fail if invalid combination of mode and configuration
32-bit config are only valid for periodic / oneshot modes */
if (params->mode != GPT_MODE_ONESHOT_UP &&
params->mode != GPT_MODE_PERIODIC_UP)
{
DebugP_log1("Timer:(%p): Invalid combination of mode and configuration", hwAttrs->baseAddr);
return(NULL);
}
/* Fail if invalid combination of timer unit and configuration.
32-bit config is only valid in combination with GPT A */
if (handle->timerPart != GPT_A)
{
DebugP_log1("Timer:(%p): Invalid combination of configuration and timer unit", hwAttrs->baseAddr);
return(NULL);
}
}
/*
* Check if Timer is already opened
*/
/* Disable preemption while checking */
key = HwiP_disable();
bool isOpen;
/* If trying to open a 32-bit mode timer then both A and B must be available */
if (params->width == GPT_CONFIG_32BIT)
{
/* Timer already opened if one unit opened */
isOpen = object->isOpen[GPT_A] | object->isOpen[GPT_B];
}
else
{
isOpen = object->isOpen[handle->timerPart];
}
/* Fail if corresponding timer is already open or if one of the two
units needed is taken for 32-bit mode */
if (isOpen)
{
HwiP_restore(key);
DebugP_log2("Timer:(%p), Unit: (%u): Already in use.", hwAttrs->baseAddr, handle->timerPart);
return NULL;
}
/*
* Open timer
*/
if (params->width == GPT_CONFIG_32BIT)
{
object->isOpen[GPT_A] = true;
object->isOpen[GPT_B] = true;
}
else
{
object->isOpen[handle->timerPart] = true;
}
/* Restore preemption again */
HwiP_restore(key);
/* Configure timer object */
object->width = params->width;
/* Register power dependency - i.e. power up and enable clock for GPTimer.
If both GPT_A and GPT_B is used then two dependencies will be set on GPTimer */
Power_setDependency(hwAttrs->powerMngrId);
/* Initialize HW */
GPTimerCC26XX_initHw(handle, params);
return handle;
}
/*!
* @brief This function closes an opened GPTimer peripheral defined by the
* handle. It will remove the dependency on the timer and write all
* configured timer registers to its default values. Timer must be
* stopped beforing closing it.
*
* @sa GPTimerCC26XX_stop()
* @sa GPTimerCC26XX_close()
*/
void GPTimerCC26XX_close(GPTimerCC26XX_Handle handle)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
/* Stop and reset timer */
GPTimerCC26XX_resetHw(handle);
/* Release dependency for timer */
Power_releaseDependency(hwAttrs->powerMngrId);
/* Mark the Timer unit as available */
uint32_t key = HwiP_disable();
/* Close Timer(s) */
if (object->width == GPT_CONFIG_32BIT)
{
object->isOpen[GPT_A] = false;
object->isOpen[GPT_B] = false;
}
else
{
object->isOpen[handle->timerPart] = false;
}
HwiP_restore(key);
}
/*!
* @brief This function will start a GPTimer defined by the handle.
* @sa GPTimerCC26XX_stop()
*/
void GPTimerCC26XX_start(GPTimerCC26XX_Handle handle)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
/* Enable timer */
uint32_t timer = GPT_LUT[handle->timerPart].map;
TimerEnable(hwAttrs->baseAddr, timer);
/* Set constraint to disallow standby while running */
GPTimerCC26XXThreadsafeConstraintSet(handle);
}
/*!
* @brief This function will stop a running GPTimer defined by the handle
* @sa GPTimerCC26XX_start()
*/
void GPTimerCC26XX_stop(GPTimerCC26XX_Handle handle)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
/* Disable timer */
uint32_t timer = GPT_LUT[handle->timerPart].map;
TimerDisable(hwAttrs->baseAddr, timer);
/* Clear constraint to allow standby again */
GPTimerCC26XXThreadsafeConstraintClr(handle);
}
/*!
* @brief Shared code to be used by GPTimerCC26XX_setLoadValue / GPTimerCC26XX_setMatchValue
* Sets load/match values using input value and register offset for
* prescaler and load/match register
* Functions calling this should specifiy which the register offset
* within the module base to the corresponding timer A register.
*/
static void GPTimerCC26XXSetLoadMatch(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Value loadMatchVal, uint32_t regPre, uint32_t regLoadMatch)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
uint32_t offset = GPT_LUT[handle->timerPart].offset;
/* Split value into correct timer and prescaler register for 16 bit modes. */
if (object->width == GPT_CONFIG_16BIT)
{
/* Upper byte is used by prescaler */
uint8_t prescaleValue = 0xFF & (loadMatchVal >> 16);
/* Discard upper byte (24 bits max) */
loadMatchVal &= 0xFFFF;
/* Set prescale value */
HWREG(hwAttrs->baseAddr + offset + regPre) = prescaleValue;
}
/* Set load / match value */
HWREG(hwAttrs->baseAddr + offset + regLoadMatch) = loadMatchVal;
}
/*!
* @brief Set GPTimer load value. For 32-bit configuration all 32 bits can
* be used. For split mode / 16-bit mode maximum value is 24 bits.
* Function concatenates prescaler functionality automatically
*/
void GPTimerCC26XX_setLoadValue(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Value loadValue)
{
GPTimerCC26XXSetLoadMatch(handle, loadValue, GPT_O_TAPR, GPT_O_TAILR);
}
/*!
* @brief Set GPTimer match value. For 32-bit configuration all 32 bits can
* be used. For split mode / 16-bit mode maximum value is 24 bits.
* Function concatenates prescaler functionality automatically
*/
void GPTimerCC26XX_setMatchValue(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Value matchValue)
{
GPTimerCC26XXSetLoadMatch(handle, matchValue, GPT_O_TAPMR, GPT_O_TAMATCHR);
}
/*!
* @brief Function to set which input event edge the GPTimer capture should
* use. Applies to edge-count and edge-time modes
* be called while GPTimer is running.
*/
void GPTimerCC26XX_setCaptureEdge(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Edge event)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
uint32_t shift = GPT_LUT[handle->timerPart].shift;
/* Disable interrupts during RMW operation */
uint32_t key = HwiP_disable();
uint32_t ctl = HWREG(hwAttrs->baseAddr + GPT_O_CTL);
/* Clear old setting */
ctl &= ~(GPT_CTL_TAEVENT_M << shift);
/* Apply new setting */
HWREG(hwAttrs->baseAddr + GPT_O_CTL) = ctl | (event << shift);
/* Restore HW interrupts */
HwiP_restore(key);
}
/*!
* @brief Shared code used to retrieve timer values by
* GPTimerCC26XX_getFreeRunValue and GPTimerCC26XX_getValue
* Functions calling this should specifiy which the register offset
* within the module base to the corresponding timer A register.
*/
static GPTimerCC26XX_Value GPTimerCC26XX_getTimerValue(GPTimerCC26XX_Handle handle, uint32_t reg)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
uint32_t offset = GPT_LUT[handle->timerPart].offset;
uint32_t value = HWREG(hwAttrs->baseAddr + offset + reg);
/* Correct for 16-bit mode (remove bits 31:24)
Supported 16-bit modes uses prescaler as timer extension only.
In 16-bit mode, current prescaler value is found in bits 23:16 of the timer value register
*/
if (object->width == GPT_CONFIG_16BIT)
{
/* Discard any upper byte */
value = value & 0xFFFFFF;
}
return (GPTimerCC26XX_Value)value;
}
/*!
* @brief Retrieve current free-running value from GPTimer
* In 16-bit modes the function will return a 24-bit word where the
* 8-bit prescaler value is included.
*/
GPTimerCC26XX_Value GPTimerCC26XX_getFreeRunValue(GPTimerCC26XX_Handle handle)
{
return GPTimerCC26XX_getTimerValue(handle, GPT_O_TAV);
}
/*!
* @brief Retrieve the current value of timer
* This returns the value of the timer in all modes except for
* input edge count and input edge time mode.
* In edge count mode, this register contains the number of edges that
* have occurred. In input edge time, this register contains the
* timer value at which the last edge event took place.
* In 16-bit modes the function will return a 24-bit word where the
* 8-bit prescaler value is included.
*/
GPTimerCC26XX_Value GPTimerCC26XX_getValue(GPTimerCC26XX_Handle handle)
{
return GPTimerCC26XX_getTimerValue(handle, GPT_O_TAR);
}
/*!
* @brief Register interrupts for timer handle.
* This function must only be called once after opening a timer.
* Interrupts should be unregistered again before closing
* the timer resource.
*/
void GPTimerCC26XX_registerInterrupt(GPTimerCC26XX_Handle handle, GPTimerCC26XX_HwiFxn callback, GPTimerCC26XX_IntMask intMask)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
/* Store callback function */
object->hwiCallbackFxn[handle->timerPart] = callback;
/* Construct RTOS HWI */
HwiP_Struct *pHwi = &object->hwi[handle->timerPart];
HwiP_Params hp;
HwiP_Params_init(&hp);
hp.arg = (uintptr_t)handle;
hp.enableInt = true;
hp.priority = hwAttrs->intPriority;
HwiP_construct(pHwi, hwAttrs->intNum, GPTimerCC26XXHwiFxn, &hp);
GPTimerCC26XX_enableInterrupt(handle, intMask);
}
/*!
* @brief Destruct interrupt for timer handle.
* This function must only be called once after opening a timer and
* should not be called before calling GPTimerCC26XX_registerInterrupt
*/
void GPTimerCC26XX_unregisterInterrupt(GPTimerCC26XX_Handle handle)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
uint32_t ui32Base = hwAttrs->baseAddr;
uint32_t timer = GPT_LUT[handle->timerPart].map;
/* Disable all timer unit interrupts, use "timer" variable as mask */
TimerIntDisable(ui32Base, timer);
/* Destroy callback function */
object->hwiCallbackFxn[handle->timerPart] = NULL;
/* Destruct HWI */
HwiP_Struct *pHwi = &object->hwi[handle->timerPart];
HwiP_destruct(pHwi);
}
/*!
* @brief Enable interrupt source for current GPTimer unit. CPU interrupt
* for timer will not be enabled before calling
* GPTimerCC26XX_registerInterrupt
*/
void GPTimerCC26XX_enableInterrupt(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask intMask)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
uint32_t ui32Base = hwAttrs->baseAddr;
/* Interrupt registers are shared by TA and TB but bit fields are not symmetric
Fetch mask from lookup table.*/
uint32_t intMaskLookup = GPTimerCC26XXReverseLookupMask(GPT_LUT[handle->timerPart].interrupts, intMask, GPT_NUM_INTS);
/* Enable interrupts in timer unit */
TimerIntEnable(ui32Base, intMaskLookup);
}
/*!
* @brief Disable interrupt source for current GPTimer unit. CPU interrupt
* for timer will not be disabled before calling GPTimerCC26XX_unregisterInterrupt
*/
void GPTimerCC26XX_disableInterrupt(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask intMask)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
uint32_t ui32Base = hwAttrs->baseAddr;
/* Interrupt registers are shared by TA and TB but bit fields are not symmetric
Fetch mask from lookup table. */
uint32_t intMaskLookup = GPTimerCC26XXReverseLookupMask(GPT_LUT[handle->timerPart].interrupts, intMask, GPT_NUM_INTS);
/* Enable interrupts in timer unit */
TimerIntDisable(ui32Base, intMaskLookup);
}
static void GPTimerCC26XX_initHw(GPTimerCC26XX_Handle handle, const GPTimerCC26XX_Params *params)
{
/* Get the pointer to the object and hwAttrs */
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object const *object = handle->object;
TimerSetConfig(hwAttrs->baseAddr, object->width);
uint32_t timer = GPT_LUT[handle->timerPart].map;
uint32_t mode = (uint32_t) params->mode;
if (params->matchTiming == GPTimerCC26XX_SET_MATCH_ON_TIMEOUT)
{
/* Same bit position is also valid for timer B in the TBMR register. */
mode |= GPT_TAMR_TAMRSU_TOUPDATE;
}
else
{
/* Same bit position is also valid for timer B in the TBMR register. */
mode |= GPT_TAMR_TAMRSU_CYCLEUPDATE;
}
if (params->direction == GPTimerCC26XX_DIRECTION_UP)
{
/* Same bit position also valid for timer B in the TBMR register. */
mode |= GPT_TAMR_TACDIR_UP;
}
else
{
/* Same bit position also valid for timer B in the TBMR register. */
mode |= GPT_TAMR_TACDIR_DOWN;
}
TimerSetMode(hwAttrs->baseAddr, timer, mode);
GPTimerCC26XX_configureDebugStall(handle, params->debugStallMode);
}
/*!
* @brief Restore GPTimer unit registers back to reset values.
* Needed since module does not have reset functionality.
*/
static void GPTimerCC26XX_resetHw(GPTimerCC26XX_Handle handle)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
uint32_t ui32Base = hwAttrs->baseAddr;
uint32_t timer = GPT_LUT[handle->timerPart].map;
uint32_t regMask;
/* Some registers are shared by TA and TB.
Shift bit fields by 1 byte for timer B. */
uint32_t shift = GPT_LUT[handle->timerPart].shift;
/* Some registers are offset by one word (4 bytes) for Timer B. */
uint32_t offset = GPT_LUT[handle->timerPart].offset;
/* Disable timer before configuring */
TimerDisable(ui32Base, timer);
/* Reset control regs for timer N (CTL) */
regMask = ~(GPT_CTL_MASK << shift);
HWREG(ui32Base + GPT_O_CTL) &= regMask;
/* Reset interrupt mask for Timer N (IMR).
Equivalent to TimerIntDisable(ui32Base, regMask) */
regMask = 0;
uint8_t i;
for (i = 0; i < GPT_NUM_INTS; i++)
{
regMask |= (uint32_t)(GPT_LUT[handle->timerPart].interrupts[i]);
}
HWREG(ui32Base + GPT_O_IMR) &= ~regMask;
/* Clear interrupts for Timer N ( ICLR). Same regMask as GPT_O_IMR.
Equivalent to TimerIntClear(ui32Base, regMask) */
HWREG(ui32Base + GPT_O_ICLR) = regMask;
/* Reset load register for timer N.
Equivalent to TimerLoadSet(ui32Base, timer, 0xFFFFFFF) */
HWREG(ui32Base + offset + GPT_O_TAILR) = 0xFFFFFFFF;
/* Reset match register for timer N.
Equivalent to TimerMatchSet(ui32Base, timer, 0xFFFFFFFF) */
HWREG(ui32Base + offset + GPT_O_TAMATCHR) = 0xFFFFFFFF;
/* Reset pre-scale register for timer N.
Equivalent to TimerPrescaleSet(ui32Base, timer, 0) */
HWREG(ui32Base + offset + GPT_O_TAPR) = 0;
/* Reset pre-scale match register for timer N.
Equivalent to TimerPrescaleMatchSet(ui32Base, timer, 0) */
HWREG(ui32Base + offset + GPT_O_TAPMR) = 0;
}
/*!
* @brief GPTimer interrupt handler - Clears corresponding interrupt(s)
* and calls callback function with handle and bitmask argument
* as given in implementation header file.
*/
static void GPTimerCC26XXHwiFxn(uintptr_t a0)
{
GPTimerCC26XX_Handle handle = (GPTimerCC26XX_Handle)a0;
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
GPTimerCC26XX_Object *object = handle->object;
GPTimerCC26XX_HwiFxn callbackFxn = object->hwiCallbackFxn[handle->timerPart];
uint32_t timer = GPT_LUT[handle->timerPart].map;
/* Full width raw interrupt status */
uint32_t interrupts = HWREG(hwAttrs->baseAddr + GPT_O_MIS);
/* Interrupt mask to clear (byte 0 or 1) */
uint32_t interruptClr = timer & interrupts;
/* Clear interrupts */
HWREG(hwAttrs->baseAddr + GPT_O_ICLR) = interruptClr;
/* Interrupt registers are shared by TA and TB but bit fields are not
symmetric. Need to go through LUT and fetch bit vector based on interrupts
*/
uint16_t intMaskLookup = GPTimerCC26XXLookupMask(GPT_LUT[handle->timerPart].interrupts, interrupts, GPT_NUM_INTS);
if (callbackFxn != NULL)
{
callbackFxn(handle, intMaskLookup);
}
}
/*!
* @brief Set Standby constraint while using timer to avoid TI RTOS
* going into standby when timer is running. As constraints are
* counting, store constraint status and access atomically and only
* once per timer resource.
*/
static inline void GPTimerCC26XXThreadsafeConstraintSet(GPTimerCC26XX_Handle handle)
{
GPTimerCC26XX_Object *object = handle->object;
uint32_t key = HwiP_disable();
/* Only set if not already set */
if (object->powerConstraint[handle->timerPart])
{
HwiP_restore(key);
return;
}
object->powerConstraint[handle->timerPart] = true;
HwiP_restore(key);
Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
}
/*!
* @brief Clear Standby constraint while using timer to avoid TI RTOS
* going into standby when timer is running. As constraints are
* counting, store constraint status and access atomically and only
* once per timer resource.
*/
static inline void GPTimerCC26XXThreadsafeConstraintClr(GPTimerCC26XX_Handle handle)
{
GPTimerCC26XX_Object *object = handle->object;
uint32_t key = HwiP_disable();
/* Only release if constraint set */
if (!object->powerConstraint[handle->timerPart])
{
HwiP_restore(key);
return;
}
object->powerConstraint[handle->timerPart] = false;
HwiP_restore(key);
Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY);
}
/*!
* @brief Configure debug stall mode in timer. When enabled the timer will
* stop when the CPU is halted by the debugger.
*/
void GPTimerCC26XX_configureDebugStall(GPTimerCC26XX_Handle handle, GPTimerCC26XX_DebugMode mode)
{
GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
uint32_t timer = GPT_LUT[handle->timerPart].map;
TimerStallControl(hwAttrs->baseAddr, timer, mode);
}
/*!
* @brief Set timer configuration. Will be moved to driverlib.
*/
static inline void TimerSetConfig(uint32_t ui32Base, uint32_t ui32Config)
{
HWREG(ui32Base + GPT_O_CFG) = ui32Config;
}
/*!
* @brief Set timer mode. Will be moved to driverlib.
*/
static inline void TimerSetMode(uint32_t ui32Base, uint32_t timer, uint32_t mode)
{
uint32_t addr = ui32Base;
if (timer == TIMER_B)
{
addr += GPT_O_TBMR;
}
else
{
addr += GPT_O_TAMR;
}
HWREG(addr) = mode;
}