knx/kernel/nortos/dpl/TimerPCC26XX_nortos.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

386 lines
9.9 KiB
C

/*
* Copyright (c) 2017, 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.
*/
/*
* ======== TimerPCC26XX_nortos.c ========
*/
#include <stdlib.h>
#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(driverlib/aon_rtc.h)
#include DeviceFamily_constructPath(driverlib/aon_event.h)
#include DeviceFamily_constructPath(driverlib/interrupt.h)
#include <ti/drivers/dpl/HwiP.h>
#include "TimerP.h"
#define COMPARE_MARGIN 4
#define MAX_SKIP (0x7E9000000000) /* 32400 seconds (9 hours) */
#define TIMER_FREQ 65536
typedef struct _TimerP_Obj {
TimerP_StartMode startMode;
uint32_t period;
uintptr_t arg;
HwiP_Fxn tickFxn;
TimerP_FreqHz frequency;
uint64_t period64;
uint64_t savedCurrCount;
uint64_t prevThreshold;
uint64_t nextThreshold;
} TimerP_Obj;
static bool TimerP_initialized = false;
static TimerP_Obj *TimerP_handle;
static HwiP_Struct TimerP_hwiStruct;
//static unsigned int TimerP_availMask = 0x7;
static TimerP_Params TimerP_defaultParams = {
.startMode = TimerP_StartMode_AUTO,
.arg = 0,
.period = 10,
};
/*
* ======== TimerP_Params_init ========
*/
void TimerP_Params_init(TimerP_Params *params)
{
/* structure copy */
*params = TimerP_defaultParams;
}
/*
* ======== TimerP_construct ========
*/
TimerP_Handle TimerP_construct(TimerP_Struct *handle, TimerP_Fxn timerFxn, TimerP_Params *params)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
uintptr_t hwiKey;
if (handle != NULL) {
hwiKey = HwiP_disable();
if (!TimerP_initialized) {
HwiP_Params hwiParams;
HwiP_Params_init(&hwiParams);
hwiParams.priority = INT_PRI_LEVEL4;
HwiP_construct(&TimerP_hwiStruct, INT_AON_RTC_COMB,
TimerP_dynamicStub, &hwiParams);
TimerP_handle = (TimerP_Obj *)handle;
TimerP_initDevice(TimerP_handle);
TimerP_initialized = true;
}
HwiP_restore(hwiKey);
if (params == NULL) {
params = (TimerP_Params *)&TimerP_defaultParams;
}
obj->startMode = params->startMode;
obj->arg = params->arg;
obj->tickFxn = timerFxn;
obj->frequency.lo = TIMER_FREQ;
obj->frequency.hi = 0;
obj->period = (0x100000000UL * params->period) / 1000000U;
obj->period64 = obj->period;
obj->savedCurrCount = 0;
obj->prevThreshold = obj->period;
obj->nextThreshold = obj->period;
TimerP_startup();
}
return ((TimerP_Handle)handle);
}
/*
* ======== TimerP_create ========
*/
TimerP_Handle TimerP_create(TimerP_Fxn timerFxn, TimerP_Params *params)
{
TimerP_Handle handle;
handle = (TimerP_Handle)malloc(sizeof(TimerP_Obj));
/* TimerP_construct will check handle for NULL, no need here */
handle = TimerP_construct((TimerP_Struct *)handle, timerFxn, params);
return (handle);
}
/*
* ======== TimerP_getMaxTicks ========
*/
uint32_t TimerP_getMaxTicks(TimerP_Handle handle)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
uint32_t ticks;
uint64_t temp;
temp = (uint64_t)(MAX_SKIP) / obj->period64;
/* clip value to Clock tick count limit of 32-bits */
if (temp > 0xFFFFFFFF) {
ticks = 0xFFFFFFFF;
}
else {
ticks = (uint32_t)temp;
}
return (ticks);
}
/*
* ======== TimerP_setThreshold ========
*/
void TimerP_setThreshold(TimerP_Handle handle, uint32_t next, bool wrap)
{
uint32_t now;
/* get the current RTC count corresponding to compare window */
now = AONRTCCurrentCompareValueGet();
/* else if next is too soon, set at least one RTC tick in future */
/* assume next never be more than half the maximum 32 bit count value */
if ((next - now) > (uint32_t)0x80000000) {
/* now is past next */
next = now + COMPARE_MARGIN;
}
else if ((now + COMPARE_MARGIN - next) < (uint32_t)0x80000000) {
if (next < now + COMPARE_MARGIN) {
next = now + COMPARE_MARGIN;
}
}
/* set next compare threshold in RTC */
AONRTCCompareValueSet(AON_RTC_CH0, next);
}
/*
* ======== TimerP_setNextTick ========
*/
void TimerP_setNextTick(TimerP_Handle handle, uint32_t ticks)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
bool wrap = false;
uint32_t next;
uint64_t newThreshold;
/* calculate new 64-bit RTC count for next interrupt */
newThreshold = obj->savedCurrCount + (uint64_t)ticks * obj->period64;
/* isolate the new 32-bit compare value to write to RTC */
next = (uint32_t)(newThreshold >> 16);
/* set the compare threshold at the RTC */
TimerP_setThreshold(obj, next, wrap);
/* save the threshold for next interrupt */
obj->prevThreshold = newThreshold;
}
/*
* ======== TimerP_startup ========
* Here after call to main(). Called from BIOS_start().
*/
void TimerP_startup()
{
TimerP_Obj *obj;
obj = TimerP_handle;
/* if timer was statically created/constructed */
if (obj != NULL) {
if (obj->startMode == TimerP_StartMode_AUTO) {
TimerP_start(obj);
}
}
}
/*
* ======== TimerP_start ========
*
* 1. HwiP_disable()
* 2. Reset the RTC
* 3. Clear any RTC events
* 4. Set first compare threshold (per configured period)
* 5. Enable the compare channel
* 6. Enable the RTC to start it ticking
* 7. HwiP_restore()
*
*/
void TimerP_start(TimerP_Handle handle)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
uint32_t compare;
uintptr_t key;
key = HwiP_disable();
/* reset timer */
AONRTCReset();
AONRTCEventClear(AON_RTC_CH0);
IntPendClear(INT_AON_RTC_COMB);
/*
* set the compare register to the counter start value plus one period.
* For a very small period round up to interrupt upon 4th RTC tick
*/
if (obj->period < 0x40000) {
compare = 0x4; /* 4 * 15.5us ~= 62us */
}
/* else, interrupt on first period expiration */
else {
compare = obj->period >> 16;
}
/* set the compare value at the RTC */
AONRTCCompareValueSet(AON_RTC_CH0, compare);
/* enable compare channel 0 */
AONEventMcuWakeUpSet(AON_EVENT_MCU_WU0, AON_EVENT_RTC0);
AONRTCChannelEnable(AON_RTC_CH0);
AONRTCCombinedEventConfig(AON_RTC_CH0);
/* start timer */
AONRTCEnable();
HwiP_restore(key);
}
/*
* ======== TimerP_stop ========
*/
void TimerP_stop(TimerP_Handle handle)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
/* not implemented for this timer */
obj->savedCurrCount = 0;
}
/*
* ======== TimerP_setPeriod ========
*
* 1. Stop timer
* 2. Set period value in timer obj
*
*/
void TimerP_setPeriod(TimerP_Handle handle, uint32_t period)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
obj->period = period;
}
/*
* ======== TimerP_getCount64 ========
*/
uint64_t TimerP_getCount64(TimerP_Handle handle)
{
return(AONRTCCurrent64BitValueGet());
}
/*
* ======== TimerP_getFreq ========
*/
void TimerP_getFreq(TimerP_Handle handle, TimerP_FreqHz *freq)
{
freq->lo = TIMER_FREQ;
freq->hi = 0;
}
/*
* ======== TimerP_dynamicStub ========
*/
void TimerP_dynamicStub(uintptr_t arg)
{
TimerP_Obj *obj;
obj = TimerP_handle;
/* clear the RTC event */
AONRTCEventClear(AON_RTC_CH0);
/* call the tick function */
obj->tickFxn(obj->arg);
}
/*
* ======== TimerP_getCurrentTick ========
* Used by the Clock module for TickMode_DYNAMIC to query the corresponding
* Clock tick, as derived from the current timer count.
*/
uint32_t TimerP_getCurrentTick(TimerP_Handle handle, bool saveFlag)
{
TimerP_Obj *obj = (TimerP_Obj *)handle;
uint64_t tick, currCount;
currCount = (uint64_t)TimerP_getCount64(obj);
tick = currCount / obj->period64;
if (saveFlag != 0) {
/*
* to avoid accumulating drift, make currCount be an integer
* multiple of timer periods
*/
currCount = tick * obj->period64;
obj->savedCurrCount = currCount;
}
return ((uint32_t)tick);
}
/* ======== TimerP_initDevice ========
* Disable and reset the RTC.
*/
void TimerP_initDevice(TimerP_Handle handle)
{
AONRTCDisable();
AONRTCReset();
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC) = 1;
/* read sync register to complete reset */
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
AONRTCEventClear(AON_RTC_CH0);
IntPendClear(INT_AON_RTC_COMB);
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
}