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
Steven Cooreman 2018-03-27 10:55:46 +02:00 committed by Bartek Szatkowski
parent 5590f2b495
commit 1448f81620
5 changed files with 109 additions and 308 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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": {