mirror of https://github.com/ARMmbed/mbed-os.git
Rework us_ticker and rtc_api/lp_ticker
Simplify tickers to stop emulating 1us ticks by using native timer resolutions. Implement ticker get info functions. Separate rtc and lp ticker init status by implementing separate functions.pull/6605/head
parent
278707518c
commit
098c2cf756
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2016,2018 Maxim Integrated Products, Inc., All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -36,33 +36,24 @@
|
|||
#include "rtc.h"
|
||||
#include "lp.h"
|
||||
|
||||
#define PRESCALE_VAL RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
|
||||
#define SHIFT_AMT (RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)
|
||||
// LOG2 for 32-bit powers of 2
|
||||
#define LOG2_1(n) (((n) >= (1 << 1)) ? 1 : 0)
|
||||
#define LOG2_2(n) (((n) >= (1 << 2)) ? ( 2 + (LOG2_1((n) >> 2))) : LOG2_1(n))
|
||||
#define LOG2_4(n) (((n) >= (1 << 4)) ? ( 4 + (LOG2_2((n) >> 4))) : LOG2_2(n))
|
||||
#define LOG2_8(n) (((n) >= (1 << 8)) ? ( 8 + (LOG2_4((n) >> 8))) : LOG2_4(n))
|
||||
#define LOG2(n) (((n) >= (1 << 16)) ? (16 + (LOG2_8((n) >> 16))) : LOG2_8(n))
|
||||
|
||||
#define WINDOW 1000
|
||||
#define LP_TIMER_FREQ_HZ 4096
|
||||
#define LP_TIMER_PRESCALE RTC_PRESCALE_DIV_2_0
|
||||
#define LP_TIMER_RATE_HZ (LP_TIMER_FREQ_HZ >> LP_TIMER_PRESCALE)
|
||||
#define LP_TIMER_WIDTH 32
|
||||
|
||||
static int rtc_inited = 0;
|
||||
static volatile uint32_t overflow_cnt = 0;
|
||||
|
||||
static uint64_t rtc_read64(void);
|
||||
static volatile int rtc_inited = 0;
|
||||
static volatile int lp_ticker_inited = 0;
|
||||
|
||||
//******************************************************************************
|
||||
static void overflow_handler(void)
|
||||
static void init_rtc(void)
|
||||
{
|
||||
overflow_cnt++;
|
||||
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void rtc_init(void)
|
||||
{
|
||||
if (rtc_inited) {
|
||||
return;
|
||||
}
|
||||
rtc_inited = 1;
|
||||
|
||||
overflow_cnt = 0;
|
||||
|
||||
/* Enable power for RTC for all LPx states */
|
||||
MXC_PWRSEQ->reg0 |= (MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN |
|
||||
MXC_F_PWRSEQ_REG0_PWR_RTCEN_SLP);
|
||||
|
@ -70,21 +61,12 @@ void rtc_init(void)
|
|||
/* Enable clock to synchronizers */
|
||||
CLKMAN_SetClkScale(CLKMAN_CLK_SYNC, CLKMAN_SCALE_DIV_1);
|
||||
|
||||
// Prepare interrupt handlers
|
||||
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
|
||||
NVIC_EnableIRQ(RTC0_IRQn);
|
||||
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
||||
NVIC_EnableIRQ(RTC3_IRQn);
|
||||
|
||||
// Enable wakeup on RTC rollover
|
||||
LP_ConfigRTCWakeUp(0, 0, 0, 1);
|
||||
|
||||
/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
|
||||
* if it is already running.
|
||||
*/
|
||||
if (!RTC_IsActive()) {
|
||||
rtc_cfg_t cfg = {0};
|
||||
cfg.prescaler = PRESCALE_VAL;
|
||||
rtc_cfg_t cfg = { 0 };
|
||||
cfg.prescaler = LP_TIMER_PRESCALE;
|
||||
cfg.snoozeMode = RTC_SNOOZE_DISABLE;
|
||||
|
||||
int retval = RTC_Init(&cfg);
|
||||
|
@ -96,163 +78,128 @@ void rtc_init(void)
|
|||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_init(void)
|
||||
static void overflow_handler(void)
|
||||
{
|
||||
rtc_init();
|
||||
MXC_RTCTMR->comp[1] += ((UINT32_MAX >> LOG2(LP_TIMER_RATE_HZ)) + 1);
|
||||
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void rtc_init(void)
|
||||
{
|
||||
if (rtc_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
||||
NVIC_EnableIRQ(RTC3_IRQn);
|
||||
// Enable wakeup on RTC overflow
|
||||
LP_ConfigRTCWakeUp(lp_ticker_inited, 0, 0, 1);
|
||||
init_rtc();
|
||||
rtc_inited = 1;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void rtc_free(void)
|
||||
{
|
||||
if (RTC_IsActive()) {
|
||||
// Clear and disable RTC
|
||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR;
|
||||
RTC_Stop();
|
||||
if (rtc_inited) {
|
||||
rtc_inited = 0;
|
||||
if (lp_ticker_inited) {
|
||||
RTC_DisableINT(MXC_F_RTC_FLAGS_OVERFLOW);
|
||||
} else {
|
||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR;
|
||||
RTC_Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
int rtc_isenabled(void)
|
||||
{
|
||||
return RTC_IsActive();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
time_t rtc_read(void)
|
||||
{
|
||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||
uint32_t ovf1, ovf2;
|
||||
|
||||
// Make sure RTC is setup before trying to read
|
||||
if (!rtc_inited) {
|
||||
rtc_init();
|
||||
}
|
||||
|
||||
// Ensure coherency between overflow_cnt and timer
|
||||
do {
|
||||
ovf_cnt_1 = overflow_cnt;
|
||||
ovf1 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||
timer_cnt = RTC_GetCount();
|
||||
ovf2 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||
ovf_cnt_2 = overflow_cnt;
|
||||
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||
|
||||
// Account for an unserviced interrupt
|
||||
if (ovf1) {
|
||||
ovf_cnt_1++;
|
||||
}
|
||||
|
||||
return (timer_cnt >> SHIFT_AMT) + (ovf_cnt_1 << (32 - SHIFT_AMT));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
static uint64_t rtc_read64(void)
|
||||
{
|
||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||
uint32_t ovf1, ovf2;
|
||||
uint64_t current_us;
|
||||
|
||||
// Make sure RTC is setup before trying to read
|
||||
if (!rtc_inited) {
|
||||
rtc_init();
|
||||
}
|
||||
|
||||
// Ensure coherency between overflow_cnt and timer
|
||||
do {
|
||||
ovf_cnt_1 = overflow_cnt;
|
||||
ovf1 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||
timer_cnt = RTC_GetCount();
|
||||
ovf2 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||
ovf_cnt_2 = overflow_cnt;
|
||||
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||
|
||||
// Account for an unserviced interrupt
|
||||
if (ovf1) {
|
||||
ovf_cnt_1++;
|
||||
}
|
||||
|
||||
current_us = (((uint64_t)timer_cnt * 1000000) >> SHIFT_AMT) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - SHIFT_AMT));
|
||||
|
||||
return current_us;
|
||||
return rtc_inited;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void rtc_write(time_t t)
|
||||
{
|
||||
// Make sure RTC is setup before accessing
|
||||
if (!rtc_inited) {
|
||||
rtc_init();
|
||||
}
|
||||
|
||||
RTC_Stop();
|
||||
RTC_SetCount(t << SHIFT_AMT);
|
||||
overflow_cnt = t >> (32 - SHIFT_AMT);
|
||||
RTC_Start();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
uint32_t comp_value;
|
||||
uint64_t curr_ts64;
|
||||
uint64_t ts64;
|
||||
|
||||
// Note: interrupts are disabled before this function is called.
|
||||
|
||||
// Disable the alarm while it is prepared
|
||||
RTC_DisableINT(MXC_F_RTC_INTEN_COMP0);
|
||||
|
||||
curr_ts64 = rtc_read64();
|
||||
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
|
||||
|
||||
// If this event is older than a recent window, it must be in the future
|
||||
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
|
||||
ts64 += 0x100000000ULL;
|
||||
}
|
||||
|
||||
uint32_t timer = RTC_GetCount();
|
||||
if (ts64 <= curr_ts64) {
|
||||
// This event has already occurred. Set the alarm to expire immediately.
|
||||
comp_value = timer + 1;
|
||||
} else {
|
||||
comp_value = (ts64 << SHIFT_AMT) / 1000000;
|
||||
}
|
||||
|
||||
// Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
|
||||
if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) {
|
||||
comp_value = timer + 2;
|
||||
}
|
||||
|
||||
MXC_RTCTMR->comp[0] = comp_value;
|
||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
||||
RTC_EnableINT(MXC_F_RTC_INTEN_COMP0);
|
||||
|
||||
// Enable wakeup from RTC
|
||||
LP_ConfigRTCWakeUp(1, 0, 0, 1);
|
||||
MXC_RTCTMR->comp[1] = t - (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ));
|
||||
|
||||
// Wait for pending transactions
|
||||
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
time_t rtc_read(void)
|
||||
{
|
||||
if (!rtc_inited) {
|
||||
rtc_init();
|
||||
}
|
||||
|
||||
return (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)) + MXC_RTCTMR->comp[1];
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_init(void)
|
||||
{
|
||||
if (lp_ticker_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
|
||||
NVIC_EnableIRQ(RTC0_IRQn);
|
||||
init_rtc();
|
||||
lp_ticker_inited = 1;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
uint32_t lp_ticker_read(void)
|
||||
{
|
||||
return MXC_RTCTMR->timer;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
MXC_RTCTMR->comp[0] = timestamp;
|
||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
||||
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
|
||||
|
||||
// Enable wakeup from RTC compare 0
|
||||
LP_ConfigRTCWakeUp(1, 0, 0, rtc_inited);
|
||||
|
||||
// Wait for pending transactions
|
||||
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_disable_interrupt(void)
|
||||
{
|
||||
RTC_DisableINT(MXC_F_RTC_INTEN_COMP0);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_clear_interrupt(void)
|
||||
{
|
||||
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void lp_ticker_fire_interrupt(void)
|
||||
{
|
||||
NVIC_SetPendingIRQ(RTC0_IRQn);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
inline void lp_ticker_disable_interrupt(void)
|
||||
const ticker_info_t *lp_ticker_get_info(void)
|
||||
{
|
||||
RTC_DisableINT(MXC_F_RTC_INTEN_COMP0);
|
||||
}
|
||||
static const ticker_info_t info = {
|
||||
LP_TIMER_RATE_HZ,
|
||||
LP_TIMER_WIDTH
|
||||
};
|
||||
|
||||
//******************************************************************************
|
||||
inline void lp_ticker_clear_interrupt(void)
|
||||
{
|
||||
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
inline uint32_t lp_ticker_read(void)
|
||||
{
|
||||
return rtc_read64();
|
||||
return &info;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
|
||||
* Copyright (c) 2016,2018 Maxim Integrated Products, Inc., All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -32,251 +32,84 @@
|
|||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_critical.h"
|
||||
#include "us_ticker_api.h"
|
||||
#include "PeripheralNames.h"
|
||||
#include "tmr.h"
|
||||
#include "assert.h"
|
||||
|
||||
#define US_TIMER MXC_TMR0
|
||||
#define US_TIMER_IRQn TMR0_0_IRQn
|
||||
#define US_TIMER MXC_TMR0
|
||||
#define US_TIMER_IRQn TMR0_0_IRQn
|
||||
#define US_TIMER_PRESCALE TMR_PRESCALE_DIV_2_5
|
||||
#define US_TIMER_MODE TMR32_MODE_COMPARE
|
||||
#define US_TIMER_WIDTH 32
|
||||
|
||||
static int us_ticker_inited = 0;
|
||||
static uint32_t ticks_per_us;
|
||||
static uint32_t tick_win;
|
||||
static volatile uint64_t current_cnt; // Hold the current ticks
|
||||
static volatile uint64_t event_cnt; // Holds the value of the next event
|
||||
|
||||
#define MAX_TICK_VAL ((uint64_t)0xFFFFFFFF * ticks_per_us)
|
||||
|
||||
//******************************************************************************
|
||||
static inline void inc_current_cnt_no_crit(uint32_t inc)
|
||||
{
|
||||
// Overflow the ticker when the us ticker overflows
|
||||
current_cnt += inc;
|
||||
if (current_cnt > MAX_TICK_VAL) {
|
||||
current_cnt -= (MAX_TICK_VAL + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
static inline void inc_current_cnt(uint32_t inc)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
inc_current_cnt_no_crit(inc);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
static inline int event_passed(uint64_t current, uint64_t event)
|
||||
{
|
||||
// Determine if the event has already happened.
|
||||
// If the event is behind the current ticker, within a window,
|
||||
// then the event has already happened.
|
||||
if (((current < tick_win) && ((event < current) ||
|
||||
(event > (MAX_TICK_VAL - (tick_win - current))))) ||
|
||||
((event < current) && (event > (current - tick_win)))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
static inline uint64_t event_diff(uint64_t current, uint64_t event)
|
||||
{
|
||||
// Check to see if the ticker will overflow before the event
|
||||
if(current <= event) {
|
||||
return (event - current);
|
||||
}
|
||||
|
||||
return ((MAX_TICK_VAL - current) + event);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
static void tmr_handler(void)
|
||||
{
|
||||
uint32_t cmp = TMR32_GetCompare(US_TIMER);
|
||||
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // reset to max value to prevent further interrupts
|
||||
if (TMR32_GetFlag(US_TIMER)) {
|
||||
inc_current_cnt_no_crit(cmp);
|
||||
}
|
||||
TMR32_ClearFlag(US_TIMER);
|
||||
NVIC_ClearPendingIRQ(US_TIMER_IRQn);
|
||||
|
||||
if (event_passed(current_cnt + TMR32_GetCount(US_TIMER), event_cnt)) {
|
||||
// the timestamp has expired
|
||||
event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
|
||||
us_ticker_irq_handler();
|
||||
} else {
|
||||
uint64_t diff = event_diff(current_cnt, event_cnt);
|
||||
if (diff < (uint64_t)0xFFFFFFFF) {
|
||||
// the event occurs before the next overflow
|
||||
TMR32_SetCompare(US_TIMER, diff);
|
||||
|
||||
// Since the timer keeps counting after the terminal value is reached, it is possible that the new
|
||||
// terminal value is in the past.
|
||||
if (TMR32_GetCompare(US_TIMER) < TMR32_GetCount(US_TIMER)) {
|
||||
// the timestamp has expired
|
||||
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // reset to max value to prevent further interrupts
|
||||
TMR32_ClearFlag(US_TIMER);
|
||||
NVIC_ClearPendingIRQ(US_TIMER_IRQn);
|
||||
event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
|
||||
us_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static volatile int us_ticker_inited = 0;
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_init(void)
|
||||
{
|
||||
tmr32_cfg_t cfg;
|
||||
|
||||
if (us_ticker_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
us_ticker_inited = 1;
|
||||
current_cnt = 0;
|
||||
event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
|
||||
ticks_per_us = SystemCoreClock / 1000000;
|
||||
tick_win = SystemCoreClock / 100; // Set the tick window to 10ms
|
||||
|
||||
int retval = TMR_Init(US_TIMER, TMR_PRESCALE_DIV_2_0, NULL);
|
||||
MBED_ASSERT(retval == E_NO_ERROR);
|
||||
|
||||
tmr32_cfg_t cfg;
|
||||
cfg.mode = TMR32_MODE_CONTINUOUS;
|
||||
cfg.mode = US_TIMER_MODE;
|
||||
cfg.polarity = TMR_POLARITY_UNUSED;
|
||||
cfg.compareCount = 0xFFFFFFFF;
|
||||
cfg.compareCount = UINT32_MAX;
|
||||
|
||||
TMR_Init(US_TIMER, US_TIMER_PRESCALE, NULL);
|
||||
TMR32_Config(US_TIMER, &cfg);
|
||||
|
||||
NVIC_SetVector(US_TIMER_IRQn, (uint32_t)tmr_handler);
|
||||
NVIC_SetVector(US_TIMER_IRQn, (uint32_t)us_ticker_irq_handler);
|
||||
NVIC_EnableIRQ(US_TIMER_IRQn);
|
||||
TMR32_EnableINT(US_TIMER);
|
||||
|
||||
TMR32_Start(US_TIMER);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_deinit(void)
|
||||
{
|
||||
TMR32_Stop(US_TIMER);
|
||||
TMR32_DisableINT(US_TIMER);
|
||||
TMR32_ClearFlag(US_TIMER);
|
||||
us_ticker_inited = 0;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
uint32_t us_ticker_read(void)
|
||||
{
|
||||
uint64_t current_cnt1, current_cnt2;
|
||||
uint32_t cmp, cnt;
|
||||
uint32_t flag1, flag2;
|
||||
static uint32_t last = 0;
|
||||
|
||||
if (!us_ticker_inited) {
|
||||
us_ticker_init();
|
||||
}
|
||||
|
||||
// Ensure coherency between current_cnt and TMR32_GetCount()
|
||||
do {
|
||||
current_cnt1 = current_cnt;
|
||||
flag1 = TMR32_GetFlag(US_TIMER);
|
||||
cmp = TMR32_GetCompare(US_TIMER);
|
||||
cnt = TMR32_GetCount(US_TIMER);
|
||||
flag2 = TMR32_GetFlag(US_TIMER);
|
||||
current_cnt2 = current_cnt;
|
||||
} while ((current_cnt1 != current_cnt2) || (flag1 != flag2));
|
||||
|
||||
// Account for an unserviced interrupt
|
||||
if (flag1) {
|
||||
// Clear peripheral interrupt flag; leaving NVIC pending set
|
||||
TMR32_ClearFlag(US_TIMER);
|
||||
// Advance global count
|
||||
inc_current_cnt(cmp + cnt);
|
||||
|
||||
current_cnt1 += cmp;
|
||||
}
|
||||
|
||||
current_cnt1 += cnt;
|
||||
|
||||
assert(last <= (current_cnt1 / ticks_per_us));
|
||||
last = (current_cnt1 / ticks_per_us);
|
||||
return last;
|
||||
return US_TIMER->count32;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
// Note: interrupts are disabled before this function is called.
|
||||
|
||||
TMR32_Stop(US_TIMER);
|
||||
|
||||
if (TMR32_GetFlag(US_TIMER)) {
|
||||
TMR32_ClearFlag(US_TIMER);
|
||||
NVIC_ClearPendingIRQ(US_TIMER_IRQn);
|
||||
inc_current_cnt(TMR32_GetCompare(US_TIMER));
|
||||
}
|
||||
|
||||
// add and reset the current count value
|
||||
inc_current_cnt(TMR32_GetCount(US_TIMER));
|
||||
TMR32_SetCount(US_TIMER, 0);
|
||||
|
||||
// add the number of cycles that the timer is disabled here for
|
||||
inc_current_cnt(200);
|
||||
|
||||
event_cnt = (uint64_t)timestamp * ticks_per_us;
|
||||
|
||||
// Check to see if the event has already passed
|
||||
if (!event_passed(current_cnt, event_cnt)) {
|
||||
uint64_t diff = event_diff(current_cnt, event_cnt);
|
||||
if (diff < (uint64_t)0xFFFFFFFF) {
|
||||
// the event occurs before the next overflow
|
||||
TMR32_SetCompare(US_TIMER, diff);
|
||||
} else {
|
||||
// the event occurs after the next overflow
|
||||
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // set to max
|
||||
}
|
||||
} else {
|
||||
// the requested timestamp occurs in the past
|
||||
// set the timer up to immediately expire
|
||||
TMR32_SetCompare(US_TIMER, 1);
|
||||
}
|
||||
|
||||
TMR32_Start(US_TIMER);
|
||||
US_TIMER->ctrl = 0;
|
||||
US_TIMER->term_cnt32 = timestamp;
|
||||
US_TIMER->inten = MXC_F_TMR_INTEN_TIMER0;
|
||||
US_TIMER->ctrl = MXC_F_TMR_CTRL_ENABLE0 |
|
||||
(US_TIMER_MODE << MXC_F_TMR_CTRL_MODE_POS) |
|
||||
(US_TIMER_PRESCALE << MXC_F_TMR_CTRL_PRESCALE_POS);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_fire_interrupt(void)
|
||||
{
|
||||
TMR32_SetCompare(US_TIMER, 1);
|
||||
NVIC_SetPendingIRQ(US_TIMER_IRQn);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_disable_interrupt(void)
|
||||
{
|
||||
// There are no more events, set timer overflow to the max
|
||||
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF);
|
||||
US_TIMER->inten = 0;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_clear_interrupt(void)
|
||||
{
|
||||
// cleared in the local handler
|
||||
US_TIMER->intfl = MXC_F_TMR_INTFL_TIMER0;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
void us_ticker_set(timestamp_t timestamp)
|
||||
const ticker_info_t* us_ticker_get_info(void)
|
||||
{
|
||||
TMR32_Stop(US_TIMER);
|
||||
current_cnt = (uint64_t)timestamp * ticks_per_us;
|
||||
TMR32_SetCount(US_TIMER, 0);
|
||||
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF);
|
||||
TMR32_Start(US_TIMER);
|
||||
static const ticker_info_t info = {
|
||||
RO_FREQ >> US_TIMER_PRESCALE,
|
||||
US_TIMER_WIDTH
|
||||
};
|
||||
|
||||
if (((uint64_t)timestamp * ticks_per_us) >= event_cnt) {
|
||||
// The next timestamp has elapsed. Trigger the interrupt to handle it.
|
||||
NVIC_SetPendingIRQ(US_TIMER_IRQn);
|
||||
}
|
||||
return &info;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue