mirror of https://github.com/ARMmbed/mbed-os.git
Re-implement us_ticker and lp_ticker for Silicon Labs targets
Re-implemented both us_ticker and lp_ticker to match the new API and specifications. Details: * On EFM32GG, EFM32WG, EFM32LG, EFM32HG, EFM32ZG: Use the RTC peripheral to back lp_ticker, and a TIMER to back us_ticker. * On EFM32PG, EFR32MG, EFM32PG12, EFR32MG12: Use the RTCC peripheral to back lp_ticker (dual-purpose, also used to back RTC), and a TIMER to back us_ticker.pull/7009/head
parent
5590f2b495
commit
1448f81620
|
|
@ -106,12 +106,12 @@
|
|||
#endif
|
||||
|
||||
/* Adjust this to change speed of RTC and LP ticker ticks */
|
||||
#define RTC_CLOCKDIV cmuClkDiv_8
|
||||
#define RTC_CLOCKDIV cmuClkDiv_1
|
||||
/* Adjust this to match RTC_CLOCKDIV as integer value */
|
||||
#define RTC_CLOCKDIV_INT 8U
|
||||
#define RTC_CLOCKDIV_INT 1U
|
||||
/* Adjust this to match RTC_CLOCKDIV as shift for 1 second worth of ticks.
|
||||
* E.g. with 32768 Hz crystal and CLOCKDIV of 8, 1 second is 4096 ticks.
|
||||
* 4096 equals 1 << 12, so RTC_FREQ_SHIFT needs to be 12. */
|
||||
#define RTC_FREQ_SHIFT 12U
|
||||
#define RTC_FREQ_SHIFT 15U
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,71 +65,53 @@
|
|||
#define RTC_MAX_VALUE (0xFFFFFFUL)
|
||||
|
||||
static bool rtc_inited = false;
|
||||
static time_t time_base = 0;
|
||||
static uint32_t time_extend = 0;
|
||||
static uint32_t extended_comp0 = 0;
|
||||
|
||||
const ticker_info_t* lp_ticker_get_info(void)
|
||||
{
|
||||
static const ticker_info_t rtc_info = {
|
||||
LOW_ENERGY_CLOCK_FREQUENCY,
|
||||
RTC_BITS
|
||||
};
|
||||
return &rtc_info;
|
||||
}
|
||||
|
||||
void RTC_IRQHandler(void)
|
||||
{
|
||||
uint32_t flags;
|
||||
flags = RTC_IntGet();
|
||||
if (flags & RTC_IF_OF) {
|
||||
RTC_IntClear(RTC_IF_OF);
|
||||
/* RTC has overflowed (24 bits). Use time_extend as software counter for 32 more bits. */
|
||||
time_extend += 1;
|
||||
}
|
||||
if (flags & RTC_IF_COMP0) {
|
||||
if ((flags & RTC_IF_COMP0) && rtc_inited) {
|
||||
RTC_IntClear(RTC_IF_COMP0);
|
||||
if (lp_ticker_irq_handler != NULL && time_extend == extended_comp0) {
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t rtc_get_full(void)
|
||||
{
|
||||
uint64_t ticks = 0;
|
||||
|
||||
do
|
||||
{
|
||||
/* In case someone's trying to read time in a critical section */
|
||||
if (RTC_IntGet() & RTC_IF_OF) {
|
||||
RTC_IntClear(RTC_IF_OF);
|
||||
time_extend += 1;
|
||||
}
|
||||
|
||||
ticks = (uint64_t)time_extend << RTC_BITS;
|
||||
ticks += RTC_CounterGet();
|
||||
}
|
||||
while ( (ticks & RTC_MAX_VALUE) != RTC_CounterGet() );
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
void lp_ticker_init()
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (!rtc_inited) {
|
||||
CMU_ClockEnable(cmuClock_RTC, true);
|
||||
|
||||
/* Scale clock to save power */
|
||||
CMU_ClockDivSet(cmuClock_RTC, RTC_CLOCKDIV);
|
||||
|
||||
/* Initialize RTC */
|
||||
RTC_Init_TypeDef init = RTC_INIT_DEFAULT;
|
||||
init.enable = 1;
|
||||
/* Don't use compare register 0 as top value */
|
||||
init.comp0Top = 0;
|
||||
|
||||
/* Initialize */
|
||||
RTC_Init(&init);
|
||||
RTC_CounterSet(20);
|
||||
|
||||
/* Enable Interrupt from RTC */
|
||||
RTC_IntEnable(RTC_IEN_OF);
|
||||
RTC_IntDisable(RTC_IF_COMP0);
|
||||
RTC_IntClear(RTC_IF_COMP0);
|
||||
NVIC_SetVector(RTC_IRQn, (uint32_t)RTC_IRQHandler);
|
||||
NVIC_EnableIRQ(RTC_IRQn);
|
||||
|
||||
/* Initialize */
|
||||
RTC_Init(&init);
|
||||
|
||||
rtc_inited = true;
|
||||
} else {
|
||||
/* Cancel current interrupt by virtue of calling init again */
|
||||
RTC_IntDisable(RTC_IF_COMP0);
|
||||
RTC_IntClear(RTC_IF_COMP0);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
|
@ -145,90 +127,38 @@ void lp_ticker_free()
|
|||
}
|
||||
}
|
||||
|
||||
void rtc_enable_comp0(bool enable)
|
||||
{
|
||||
RTC_FreezeEnable(true);
|
||||
if (!enable) {
|
||||
RTC_IntDisable(RTC_IF_COMP0);
|
||||
} else {
|
||||
RTC_IntEnable(RTC_IF_COMP0);
|
||||
}
|
||||
RTC_FreezeEnable(false);
|
||||
}
|
||||
|
||||
void rtc_set_comp0_value(uint64_t value, bool enable)
|
||||
{
|
||||
rtc_enable_comp0(false);
|
||||
|
||||
/* Set callback */
|
||||
RTC_FreezeEnable(true);
|
||||
extended_comp0 = (uint32_t) (value >> RTC_BITS);
|
||||
RTC_CompareSet(0, (uint32_t) (value & RTC_MAX_VALUE));
|
||||
RTC_FreezeEnable(false);
|
||||
|
||||
rtc_enable_comp0(enable);
|
||||
}
|
||||
|
||||
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
uint64_t rtc_compare_value;
|
||||
uint64_t current_ticks = rtc_get_full();
|
||||
timestamp_t current_time = lp_ticker_read();
|
||||
|
||||
/* calculate offset value */
|
||||
timestamp_t offset = timestamp - current_time;
|
||||
|
||||
/* If the requested timestamp is too far in the future, we might not be able
|
||||
* to set the interrupt accurately due to potentially having ticked between
|
||||
* calculating the timestamp to set and us calculating the offset. */
|
||||
if(offset > 0xFFFF0000) offset = 100;
|
||||
|
||||
/* map offset to RTC value */
|
||||
// ticks = offset * RTC frequency div 1000000
|
||||
rtc_compare_value = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000;
|
||||
|
||||
/* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */
|
||||
if(rtc_compare_value < 2) {
|
||||
rtc_compare_value = 2;
|
||||
}
|
||||
|
||||
rtc_compare_value += current_ticks;
|
||||
|
||||
rtc_set_comp0_value(rtc_compare_value, true);
|
||||
RTC_IntDisable(RTC_IF_COMP0);
|
||||
RTC_IntClear(RTC_IF_COMP0);
|
||||
RTC_FreezeEnable(true);
|
||||
RTC_CompareSet(0, (uint32_t) (timestamp & RTC_MAX_VALUE));
|
||||
RTC_FreezeEnable(false);
|
||||
RTC_IntEnable(RTC_IF_COMP0);
|
||||
}
|
||||
|
||||
void lp_ticker_fire_interrupt(void)
|
||||
{
|
||||
RTC_IntSet(RTC_IFS_COMP0);
|
||||
RTC_IntEnable(RTC_IF_COMP0);
|
||||
RTC_IntSet(RTC_IF_COMP0);
|
||||
}
|
||||
|
||||
void lp_ticker_disable_interrupt()
|
||||
{
|
||||
rtc_enable_comp0(false);
|
||||
RTC_IntDisable(RTC_IF_COMP0);
|
||||
}
|
||||
|
||||
void lp_ticker_clear_interrupt()
|
||||
{
|
||||
/* No need to clear interrupt flag, since that already happens at RTC level */
|
||||
RTC_IntClear(RTC_IF_COMP0);
|
||||
}
|
||||
|
||||
timestamp_t lp_ticker_read()
|
||||
{
|
||||
lp_ticker_init();
|
||||
|
||||
uint64_t ticks_temp;
|
||||
uint64_t ticks = rtc_get_full();
|
||||
|
||||
/* ticks = counter tick value
|
||||
* timestamp = value in microseconds
|
||||
* timestamp = ticks * 1.000.000 / RTC frequency
|
||||
*/
|
||||
|
||||
ticks_temp = (ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT);
|
||||
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
|
||||
return (timestamp_t) RTC_CounterGet();
|
||||
}
|
||||
|
||||
#elif defined(RTCC_PRESENT)
|
||||
/* lp_ticker api is implemented in rtc_rtcc.c */
|
||||
#endif /* RTC_PRESENT */
|
||||
#endif /* DEVICE_LOWPOWERTIMER */
|
||||
#endif /* DEVICE_LPTICKER */
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
static bool lptick_inited = false;
|
||||
static uint32_t lptick_offset = 0;
|
||||
static uint32_t extended_comp0 = 0;
|
||||
|
||||
void rtc_init(void)
|
||||
{
|
||||
|
|
@ -79,30 +78,32 @@ void rtc_write(time_t t)
|
|||
{
|
||||
core_util_critical_section_enter();
|
||||
uint32_t diff = t - RTCC_CounterGet();
|
||||
if (extended_comp0 != 0xFFFFFFFFUL) {
|
||||
extended_comp0 += diff;
|
||||
}
|
||||
lptick_offset += diff;
|
||||
|
||||
if(RTCC_IntGetEnabled() & RTCC_IF_CC0) {
|
||||
RTCC->CC[0].CCV += diff << 15;
|
||||
}
|
||||
|
||||
RTCC_CounterSet(t);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/************************* LP_TICKER **************************/
|
||||
const ticker_info_t* lp_ticker_get_info(void)
|
||||
{
|
||||
static const ticker_info_t rtc_info = {
|
||||
LOW_ENERGY_CLOCK_FREQUENCY,
|
||||
32
|
||||
};
|
||||
return &rtc_info;
|
||||
}
|
||||
|
||||
void RTCC_IRQHandler(void)
|
||||
{
|
||||
uint32_t flags;
|
||||
flags = RTCC_IntGet();
|
||||
if (flags & RTCC_IF_CC0) {
|
||||
RTCC_IntClear(RTCC_IF_CC0);
|
||||
if ((RTCC_CounterGet() - lptick_offset) == extended_comp0) {
|
||||
RTCC_IntDisable(RTCC_IF_CC0);
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
if (0xFFFFFFFFUL == extended_comp0) {
|
||||
RTCC_IntDisable(RTCC_IF_CC0);
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,12 +114,17 @@ void lp_ticker_init()
|
|||
lptick_offset = RTCC_CounterGet();
|
||||
RTCC_CCChConf_TypeDef lp_chan_init = RTCC_CH_INIT_COMPARE_DEFAULT;
|
||||
lp_chan_init.compBase = rtccCompBasePreCnt;
|
||||
lp_chan_init.compMask = 17;
|
||||
lp_chan_init.compMask = 0;
|
||||
RTCC_ChannelInit(0, &lp_chan_init);
|
||||
lptick_inited = true;
|
||||
|
||||
/* Enable Interrupt from RTCC */
|
||||
/* Enable Interrupt from RTCC in NVIC, but don't start generating them */
|
||||
RTCC_IntDisable(RTCC_IF_CC0);
|
||||
RTCC_IntClear(RTCC_IF_CC0);
|
||||
NVIC_EnableIRQ(RTCC_IRQn);
|
||||
} else {
|
||||
RTCC_IntDisable(RTCC_IF_CC0);
|
||||
RTCC_IntClear(RTCC_IF_CC0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,45 +139,13 @@ void lp_ticker_free()
|
|||
|
||||
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
uint64_t rtc_compare_value;
|
||||
uint64_t current_ticks = 0;
|
||||
do
|
||||
{
|
||||
current_ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15;
|
||||
current_ticks += RTCC_PreCounterGet();
|
||||
}
|
||||
while ( (current_ticks & 0x7FFF) != RTCC_PreCounterGet() );
|
||||
|
||||
uint64_t ticks_temp = (current_ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY;
|
||||
timestamp_t current_time = ticks_temp & 0xFFFFFFFF;
|
||||
|
||||
/* calculate offset value */
|
||||
timestamp_t offset = timestamp - current_time;
|
||||
|
||||
/* If the requested timestamp is too far in the future, we might not be able
|
||||
* to set the interrupt accurately due to potentially having ticked between
|
||||
* calculating the timestamp to set and us calculating the offset. */
|
||||
if(offset > 0xFFFF0000) offset = 100;
|
||||
|
||||
/* map offset to RTC value */
|
||||
// ticks = offset * RTC frequency div 1000000
|
||||
rtc_compare_value = ((uint64_t)offset * LOW_ENERGY_CLOCK_FREQUENCY) / 1000000;
|
||||
|
||||
/* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */
|
||||
if(rtc_compare_value < 2) {
|
||||
rtc_compare_value = 2;
|
||||
}
|
||||
|
||||
rtc_compare_value += current_ticks;
|
||||
|
||||
extended_comp0 = rtc_compare_value >> 15;
|
||||
RTCC_ChannelCCVSet(0, rtc_compare_value & 0xFFFFFFFFUL);
|
||||
RTCC_ChannelCCVSet(0, timestamp + (lptick_offset << 15));
|
||||
RTCC_IntEnable(RTCC_IF_CC0);
|
||||
}
|
||||
|
||||
void lp_ticker_fire_interrupt(void)
|
||||
{
|
||||
extended_comp0 = 0xFFFFFFFFUL;
|
||||
RTCC_IntEnable(RTCC_IF_CC0);
|
||||
RTCC_IntSet(RTCC_IF_CC0);
|
||||
}
|
||||
|
||||
|
|
@ -187,25 +161,11 @@ void lp_ticker_clear_interrupt()
|
|||
|
||||
timestamp_t lp_ticker_read()
|
||||
{
|
||||
lp_ticker_init();
|
||||
core_util_critical_section_enter();
|
||||
uint32_t ticks = RTCC_CombinedCounterGet() - (lptick_offset << 15);
|
||||
core_util_critical_section_exit();
|
||||
|
||||
uint64_t ticks_temp;
|
||||
uint64_t ticks = 0;
|
||||
|
||||
do
|
||||
{
|
||||
ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15;
|
||||
ticks += RTCC_PreCounterGet();
|
||||
}
|
||||
while ( (ticks & 0x7FFF) != RTCC_PreCounterGet() );
|
||||
|
||||
/* ticks = counter tick value
|
||||
* timestamp = value in microseconds
|
||||
* timestamp = ticks * 1.000.000 / RTC frequency
|
||||
*/
|
||||
|
||||
ticks_temp = (ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY;
|
||||
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
|
||||
return (timestamp_t) (ticks);
|
||||
}
|
||||
#endif /* RTCC_PRESENT */
|
||||
#endif /* DEVICE_RTC */
|
||||
|
|
@ -29,80 +29,42 @@
|
|||
#include "em_timer.h"
|
||||
#include "clocking.h"
|
||||
|
||||
/**
|
||||
* Timer functions for microsecond ticker.
|
||||
* mbed expects a 32-bit timer. Since the EFM32 only has 16-bit timers,
|
||||
* the upper 16 bits are implemented in software.
|
||||
*/
|
||||
#define TICKER_FREQUENCY ((REFERENCE_FREQUENCY > 24000000) ? REFERENCE_FREQUENCY / 16 : REFERENCE_FREQUENCY / 8)
|
||||
|
||||
static uint8_t us_ticker_inited = 0; // Is ticker initialized yet
|
||||
|
||||
static volatile uint32_t ticker_cnt = 0; // Internal overflow count, used to extend internal 16-bit counter to (MHz * 32-bit)
|
||||
static volatile uint32_t ticker_int_cnt = 0; // Amount of overflows until user interrupt
|
||||
static volatile uint32_t ticker_freq_khz = 0; // Frequency of timer in MHz
|
||||
static volatile uint32_t ticker_top_ms = 0; // Amount of ms corresponding to the top value of the timer
|
||||
static volatile uint32_t soft_timer_top = 0; // When to wrap the software counter
|
||||
|
||||
void us_ticker_irq_handler_internal(void)
|
||||
const ticker_info_t* us_ticker_get_info(void)
|
||||
{
|
||||
/* Handle timer overflow */
|
||||
if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
|
||||
ticker_cnt++;
|
||||
|
||||
/* Wrap ticker_cnt when we've gone over 32-bit us value */
|
||||
if (ticker_cnt >= soft_timer_top) {
|
||||
ticker_cnt = 0;
|
||||
}
|
||||
|
||||
TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_OF);
|
||||
}
|
||||
|
||||
/* Check for user interrupt expiration */
|
||||
if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_CC0) {
|
||||
if (ticker_int_cnt > 0) {
|
||||
ticker_int_cnt--;
|
||||
TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_CC0);
|
||||
} else {
|
||||
us_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
static const ticker_info_t info = {
|
||||
TICKER_FREQUENCY,
|
||||
16
|
||||
};
|
||||
return &info;
|
||||
}
|
||||
|
||||
static bool us_ticker_inited = false; // Is ticker initialized yet
|
||||
|
||||
void us_ticker_init(void)
|
||||
{
|
||||
if (us_ticker_inited) {
|
||||
/* calling init again should cancel current interrupt */
|
||||
us_ticker_disable_interrupt();
|
||||
return;
|
||||
}
|
||||
us_ticker_inited = 1;
|
||||
us_ticker_inited = true;
|
||||
|
||||
/* Enable clock for TIMERs */
|
||||
CMU_ClockEnable(US_TICKER_TIMER_CLOCK, true);
|
||||
|
||||
if (REFERENCE_FREQUENCY > 24000000) {
|
||||
US_TICKER_TIMER->CTRL = (US_TICKER_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (4 << _TIMER_CTRL_PRESC_SHIFT);
|
||||
} else {
|
||||
US_TICKER_TIMER->CTRL = (US_TICKER_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (3 << _TIMER_CTRL_PRESC_SHIFT);
|
||||
}
|
||||
|
||||
/* Clear TIMER counter value */
|
||||
TIMER_CounterSet(US_TICKER_TIMER, 0);
|
||||
|
||||
/* Get frequency of clock in kHz for scaling ticks to microseconds */
|
||||
ticker_freq_khz = (REFERENCE_FREQUENCY / 1000);
|
||||
MBED_ASSERT(ticker_freq_khz > 0);
|
||||
|
||||
/*
|
||||
* Calculate maximum prescaler that gives at least 1 MHz frequency, giving us 1us resolution.
|
||||
* Limit prescaling to maximum prescaler value, which is 10 (DIV1024).
|
||||
*/
|
||||
uint32_t prescaler = 0;
|
||||
while((ticker_freq_khz >= 2000) && prescaler <= 10) {
|
||||
ticker_freq_khz = ticker_freq_khz >> 1;
|
||||
prescaler++;
|
||||
}
|
||||
|
||||
/* Set prescaler */
|
||||
US_TICKER_TIMER->CTRL = (US_TICKER_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (prescaler << _TIMER_CTRL_PRESC_SHIFT);
|
||||
|
||||
/* calculate top value.*/
|
||||
ticker_top_ms = (uint32_t) 0x10000 / ticker_freq_khz;
|
||||
|
||||
/* calculate software timer overflow */
|
||||
soft_timer_top = ((0xFFFFFFFFUL / 1000UL) / ticker_top_ms) + 1;
|
||||
/* Start TIMER */
|
||||
TIMER_Enable(US_TICKER_TIMER, true);
|
||||
|
||||
/* Select Compare Channel parameters */
|
||||
TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
|
||||
|
|
@ -112,98 +74,47 @@ void us_ticker_init(void)
|
|||
TIMER_InitCC(US_TICKER_TIMER, 0, &timerCCInit);
|
||||
|
||||
/* Enable interrupt vector in NVIC */
|
||||
TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_OF);
|
||||
NVIC_SetVector(US_TICKER_TIMER_IRQ, (uint32_t) us_ticker_irq_handler_internal);
|
||||
TIMER_IntClear(US_TICKER_TIMER, TIMER_IEN_CC0);
|
||||
NVIC_SetVector(US_TICKER_TIMER_IRQ, (uint32_t) us_ticker_irq_handler);
|
||||
NVIC_EnableIRQ(US_TICKER_TIMER_IRQ);
|
||||
}
|
||||
|
||||
/* Set top value */
|
||||
TIMER_TopSet(US_TICKER_TIMER, (ticker_top_ms * ticker_freq_khz) - 1);
|
||||
void us_ticker_free(void)
|
||||
{
|
||||
if (us_ticker_inited) {
|
||||
us_ticker_disable_interrupt();
|
||||
NVIC_DisableIRQ(US_TICKER_TIMER_IRQ);
|
||||
|
||||
/* Start TIMER */
|
||||
TIMER_Enable(US_TICKER_TIMER, true);
|
||||
TIMER_Enable(US_TICKER_TIMER, false);
|
||||
|
||||
CMU_ClockEnable(US_TICKER_TIMER_CLOCK, false);
|
||||
|
||||
us_ticker_inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t us_ticker_read()
|
||||
{
|
||||
uint32_t countH_old, countH;
|
||||
uint32_t countL;
|
||||
|
||||
if (!us_ticker_inited) {
|
||||
us_ticker_init();
|
||||
}
|
||||
|
||||
/* Avoid jumping in time by reading high bits twice */
|
||||
do {
|
||||
countH_old = ticker_cnt;
|
||||
if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
|
||||
countH_old++;
|
||||
}
|
||||
countL = US_TICKER_TIMER->CNT;
|
||||
countH = ticker_cnt;
|
||||
if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
|
||||
countH++;
|
||||
}
|
||||
} while (countH_old != countH);
|
||||
|
||||
/* Timer count value needs to be div'ed by the frequency to get to 1MHz ticks.
|
||||
* For the software-extended part, the amount of us in one overflow is constant.
|
||||
*/
|
||||
return ((countL * 1000UL) / ticker_freq_khz) + (countH * ticker_top_ms * 1000);
|
||||
return US_TICKER_TIMER->CNT;
|
||||
}
|
||||
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
uint32_t goal = timestamp;
|
||||
uint32_t trigger;
|
||||
|
||||
TIMER_IntDisable(US_TICKER_TIMER, TIMER_IEN_CC0);
|
||||
|
||||
/* convert us delta value back to timer ticks */
|
||||
trigger = us_ticker_read();
|
||||
if (trigger < goal) {
|
||||
goal -= trigger;
|
||||
} else {
|
||||
goal = (0xFFFFFFFFUL - (trigger - goal));
|
||||
}
|
||||
trigger = US_TICKER_TIMER->CNT;
|
||||
|
||||
/* Catch "Going back in time" */
|
||||
if(goal < 10 ||
|
||||
goal >= 0xFFFFFF00UL) {
|
||||
TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
|
||||
TIMER_CompareSet(US_TICKER_TIMER, 0, (US_TICKER_TIMER->CNT + 3 >= US_TICKER_TIMER->TOP ? 3 : US_TICKER_TIMER->CNT + 3));
|
||||
TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_CC0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t timer_top = TIMER_TopGet(US_TICKER_TIMER);
|
||||
uint32_t top_us = 1000 * ticker_top_ms;
|
||||
|
||||
/* Amount of times we expect to overflow: us offset / us period of timer */
|
||||
ticker_int_cnt = goal / top_us;
|
||||
|
||||
/* Leftover microseconds need to be converted to timer timebase */
|
||||
trigger += (((goal % top_us) * ticker_freq_khz) / 1000);
|
||||
|
||||
/* Cap compare value to timer top */
|
||||
if (trigger >= timer_top) {
|
||||
trigger -= timer_top;
|
||||
}
|
||||
|
||||
/* Set compare channel 0 to (current position + lower 16 bits of target).
|
||||
* When lower 16 bits match, run complete cycles with ticker_int_rem as trigger value
|
||||
* for ticker_int_cnt times. */
|
||||
TIMER_IntClear(US_TICKER_TIMER, TIMER_IEN_CC0);
|
||||
|
||||
TIMER_CompareSet(US_TICKER_TIMER, 0, trigger);
|
||||
TIMER_CompareSet(US_TICKER_TIMER, 0, timestamp);
|
||||
|
||||
TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_CC0);
|
||||
}
|
||||
|
||||
void us_ticker_fire_interrupt(void)
|
||||
{
|
||||
ticker_int_cnt = 0;
|
||||
TIMER_IntSet(US_TICKER_TIMER, TIMER_IF_CC0);
|
||||
NVIC_SetPendingIRQ(US_TICKER_TIMER_IRQ);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2907,7 +2907,7 @@
|
|||
"EFM32GG_STK3700": {
|
||||
"inherits": ["EFM32GG990F1024"],
|
||||
"progen": {"target": "efm32gg-stk"},
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH", "ITM"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH", "ITM"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -2960,7 +2960,7 @@
|
|||
},
|
||||
"EFM32LG_STK3600": {
|
||||
"inherits": ["EFM32LG990F256"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"],
|
||||
"forced_reset_timeout": 2,
|
||||
"device_name": "EFM32LG990F256",
|
||||
"config": {
|
||||
|
|
@ -3015,7 +3015,7 @@
|
|||
"EFM32WG_STK3800": {
|
||||
"inherits": ["EFM32WG990F256"],
|
||||
"progen": {"target": "efm32wg-stk"},
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3069,7 +3069,7 @@
|
|||
},
|
||||
"EFM32ZG_STK3200": {
|
||||
"inherits": ["EFM32ZG222F32"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3123,7 +3123,7 @@
|
|||
},
|
||||
"EFM32HG_STK3400": {
|
||||
"inherits": ["EFM32HG322F64"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3176,7 +3176,7 @@
|
|||
},
|
||||
"EFM32PG_STK3401": {
|
||||
"inherits": ["EFM32PG1B100F256GM32"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3239,7 +3239,7 @@
|
|||
},
|
||||
"EFR32MG1_BRD4150": {
|
||||
"inherits": ["EFR32MG1P132F256GM48"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3282,7 +3282,7 @@
|
|||
},
|
||||
"TB_SENSE_1": {
|
||||
"inherits": ["EFR32MG1P233F256GM48"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"],
|
||||
"forced_reset_timeout": 5,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3330,7 +3330,7 @@
|
|||
},
|
||||
"EFM32PG12_STK3402": {
|
||||
"inherits": ["EFM32PG12B500F1024GL125"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"],
|
||||
"forced_reset_timeout": 2,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
@ -3384,7 +3384,7 @@
|
|||
"TB_SENSE_12": {
|
||||
"inherits": ["EFR32MG12P332F1024GL125"],
|
||||
"device_name": "EFR32MG12P332F1024GL125",
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"],
|
||||
"forced_reset_timeout": 5,
|
||||
"config": {
|
||||
"hf_clock_src": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue