Initial commit of firmware

This commit is contained in:
2025-04-12 13:30:57 +01:00
commit 264a3462e0
374 changed files with 332649 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,381 @@
/***************************************************************************//**
* @file
* @brief SLEEPTIMER Hardware abstraction implementation for BURTC.
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "em_device.h"
#if defined(_SILICON_LABS_32B_SERIES_2) || defined(_SILICON_LABS_32B_SERIES_3)
// Define module name for Power Manager debug feature
#define CURRENT_MODULE_NAME "SLEEPTIMER_BURTC"
#include "sl_sleeptimer.h"
#include "sli_sleeptimer_hal.h"
#include "sl_core.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_burtc.h"
#define sleeptimer_hal_burtc_get_counter() BURTC_CounterGet()
#define sleeptimer_hal_burtc_get_compare() BURTC_CompareGet(0U)
#define sleeptimer_hal_burtc_set_compare(compare) BURTC_CompareSet(0, compare)
#define sleeptimer_hal_burtc_get_interrupts() BURTC_IntGet()
#define sleeptimer_hal_burtc_set_interrupts(flags) BURTC_IntSet(flags)
#define sleeptimer_hal_burtc_enable_interrupts(interrupts) BURTC_IntEnable(interrupts)
#define sleeptimer_hal_burtc_disable_interrupts(interrupts) BURTC_IntDisable(interrupts)
#define sleeptimer_hal_burtc_clear_interrupts(flags) BURTC_IntClear(flags)
#elif defined(_SILICON_LABS_32B_SERIES_3)
#include "sl_hal_burtc.h"
#define sleeptimer_hal_burtc_get_counter() sl_hal_burtc_get_counter()
#define sleeptimer_hal_burtc_get_compare() sl_hal_burtc_get_compare()
#define sleeptimer_hal_burtc_set_compare(compare) sl_hal_burtc_set_compare(compare)
#define sleeptimer_hal_burtc_get_interrupts() sl_hal_burtc_get_pending_interrupts()
#define sleeptimer_hal_burtc_set_interrupts(flags) sl_hal_burtc_set_interrupts(flags)
#define sleeptimer_hal_burtc_enable_interrupts(interrupts) sl_hal_burtc_enable_interrupts(interrupts)
#define sleeptimer_hal_burtc_disable_interrupts(interrupts) sl_hal_burtc_disable_interrupts(interrupts)
#define sleeptimer_hal_burtc_clear_interrupts(flags) sl_hal_burtc_clear_interrupts(flags)
#endif
#include "sl_clock_manager.h"
#include "sl_device_peripheral.h"
#include "sl_interrupt_manager.h"
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_BURTC
#if defined(_SILICON_LABS_32B_SERIES_0)
#error BURTC implementation of the sleeptimer not available on Series 0 chips
#endif
// Minimum difference between current count value and what the comparator of the timer can be set to.
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
#define SLEEPTIMER_COMPARE_MIN_DIFF (5 + 1)
#else
#define SLEEPTIMER_COMPARE_MIN_DIFF (4 + 1)
#endif
#define SLEEPTIMER_TMR_WIDTH (_BURTC_CNT_MASK)
static uint32_t get_time_diff(uint32_t a, uint32_t b);
/******************************************************************************
* Convert HAL interrupt flag BURTC-interrupt-enable bitmask
*****************************************************************************/
static uint32_t irqien_hal2burtc(uint8_t hal_flag)
{
uint32_t burtc_if = 0u;
if (hal_flag & SLEEPTIMER_EVENT_OF) {
burtc_if |= BURTC_IEN_OF;
}
if (hal_flag & SLEEPTIMER_EVENT_COMP) {
burtc_if |= BURTC_IEN_COMP;
}
return burtc_if;
}
/******************************************************************************
* Convert BURTC interrupt flags to HAL events
*****************************************************************************/
static uint8_t irqflags_burtc2hal(uint32_t burtc_flag)
{
uint8_t hal_if = 0u;
if (burtc_flag & BURTC_IF_OF) {
hal_if |= SLEEPTIMER_EVENT_OF;
}
if (burtc_flag & BURTC_IF_COMP) {
hal_if |= SLEEPTIMER_EVENT_COMP;
}
return hal_if;
}
/******************************************************************************
* Initializes BURTC sleep timer.
*****************************************************************************/
void sleeptimer_hal_init_timer()
{
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_BURTC);
#if defined(_SILICON_LABS_32B_SERIES_2)
BURTC_Init_TypeDef burtc_init = BURTC_INIT_DEFAULT;
burtc_init.start = false;
burtc_init.clkDiv = SL_SLEEPTIMER_FREQ_DIVIDER;
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
burtc_init.debugRun = true;
#endif
BURTC_Init(&burtc_init);
BURTC_IntDisable(_BURTC_IEN_MASK);
BURTC_IntClear(_BURTC_IF_MASK);
BURTC_CounterReset();
BURTC_Start();
BURTC_SyncWait();
#elif defined(_SILICON_LABS_32B_SERIES_3)
sl_hal_burtc_init_config_t burtc_init = SL_HAL_BURTC_INIT_DEFAULT;
burtc_init.clock_divider = SL_SLEEPTIMER_FREQ_DIVIDER;
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
burtc_init.debug_run = true;
#endif
sl_hal_burtc_init(&burtc_init);
sl_hal_burtc_enable();
sl_hal_burtc_disable_interrupts(_BURTC_IEN_MASK);
sl_hal_burtc_clear_interrupts(_BURTC_IF_MASK);
sl_hal_burtc_reset_counter();
sl_hal_burtc_start();
sl_hal_burtc_wait_sync();
#endif
// Setup BURTC interrupt
sl_interrupt_manager_clear_irq_pending(BURTC_IRQn);
sl_interrupt_manager_enable_irq(BURTC_IRQn);
}
/******************************************************************************
* Gets BURTC counter.
*****************************************************************************/
uint32_t sleeptimer_hal_get_counter(void)
{
return sleeptimer_hal_burtc_get_counter();
}
/******************************************************************************
* Gets BURTC compare value
*****************************************************************************/
uint32_t sleeptimer_hal_get_compare(void)
{
return sleeptimer_hal_burtc_get_compare();
}
/******************************************************************************
* Sets BURTC compare value
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the BURTC compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
*****************************************************************************/
void sleeptimer_hal_set_compare(uint32_t value)
{
CORE_DECLARE_IRQ_STATE;
uint32_t counter;
uint32_t compare_current;
uint32_t compare_new = value;
CORE_ENTER_CRITICAL();
counter = sleeptimer_hal_get_counter();
compare_current = sleeptimer_hal_get_compare();
if ((((sleeptimer_hal_burtc_get_interrupts()) & _BURTC_IF_COMP_MASK) != 0)
|| get_time_diff(compare_current, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|| compare_current == counter) {
// Add margin if necessary
if (get_time_diff(compare_new, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
compare_new = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
}
// wrap around if necessary
compare_new %= SLEEPTIMER_TMR_WIDTH;
sleeptimer_hal_burtc_set_compare(compare_new - 1);
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
}
CORE_EXIT_CRITICAL();
}
/******************************************************************************
* Enables BURTC interrupts.
*****************************************************************************/
void sleeptimer_hal_enable_int(uint8_t local_flag)
{
sleeptimer_hal_burtc_enable_interrupts(irqien_hal2burtc(local_flag));
}
/******************************************************************************
* Disables BURTC interrupts.
*****************************************************************************/
void sleeptimer_hal_disable_int(uint8_t local_flag)
{
sleeptimer_hal_burtc_disable_interrupts(irqien_hal2burtc(local_flag));
}
/*******************************************************************************
* Hardware Abstraction Layer to set timer interrupts.
******************************************************************************/
void sleeptimer_hal_set_int(uint8_t local_flag)
{
sleeptimer_hal_burtc_set_interrupts(irqien_hal2burtc(local_flag));
}
/******************************************************************************
* Gets status of specified interrupt.
*
* Note: This function must be called with interrupts disabled.
*****************************************************************************/
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
{
bool int_is_set = false;
uint32_t irq_flag = sleeptimer_hal_burtc_get_interrupts();
switch (local_flag) {
case SLEEPTIMER_EVENT_COMP:
int_is_set = (irq_flag & BURTC_IF_COMP);
break;
case SLEEPTIMER_EVENT_OF:
int_is_set = (irq_flag & BURTC_IF_OF);
break;
default:
break;
}
return int_is_set;
}
/*******************************************************************************
* Gets BURTC timer frequency.
******************************************************************************/
uint32_t sleeptimer_hal_get_timer_frequency(void)
{
uint32_t frequency;
sl_clock_branch_t clock_branch;
clock_branch = sl_device_peripheral_get_clock_branch(SL_PERIPHERAL_BURTC);
sl_clock_manager_get_clock_branch_frequency(clock_branch, &frequency);
return (frequency >> (sleeptimer_hal_presc_to_log2(SL_SLEEPTIMER_FREQ_DIVIDER - 1)));
}
/*******************************************************************************
* BURTC interrupt handler.
******************************************************************************/
void BURTC_IRQHandler(void)
{
CORE_DECLARE_IRQ_STATE;
uint8_t local_flag = 0;
uint32_t irq_flag;
CORE_ENTER_ATOMIC();
irq_flag = sleeptimer_hal_burtc_get_interrupts();
local_flag = irqflags_burtc2hal(irq_flag);
sleeptimer_hal_burtc_clear_interrupts(irq_flag & (BURTC_IF_OF | BURTC_IF_COMP));
process_timer_irq(local_flag);
CORE_EXIT_ATOMIC();
}
/*******************************************************************************
* Computes difference between two times taking into account timer wrap-around.
*
* @param a Time.
* @param b Time to substract from a.
*
* @return Time difference.
******************************************************************************/
static uint32_t get_time_diff(uint32_t a, uint32_t b)
{
return (a - b);
}
/*******************************************************************************
* @brief
* Gets the precision (in PPM) of the sleeptimer's clock.
*
* @return
* Clock accuracy, in PPM.
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void)
{
uint16_t precision;
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_EM4GRPACLK, &precision);
return precision;
}
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void)
{
// Invalid for BURTC peripheral
EFM_ASSERT(0);
return 0;
}
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void)
{
// Invalid for BURTC peripheral
EFM_ASSERT(0);
}
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*
* @note If power_manager_no_deepsleep component is included in a project, the
* lowest possible energy mode is EM1, else lowest energy mode is
* determined by clock source.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_set_pm_em_requirement(void)
{
switch (CMU->EM4GRPACLKCTRL & _CMU_EM4GRPACLKCTRL_CLKSEL_MASK) {
case CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO:
case CMU_EM4GRPACLKCTRL_CLKSEL_LFXO:
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
break;
default:
break;
}
}
#endif
#endif
#endif

View File

@@ -0,0 +1,443 @@
/***************************************************************************//**
* @file
* @brief SLEEPTIMER hardware abstraction implementation for SYSRTC.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
// Define module name for Power Manager debug feature
#define CURRENT_MODULE_NAME "SLEEPTIMER_SYSRTC"
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
#include "sl_hal_sysrtc.h"
#include "sl_sleeptimer.h"
#include "sli_sleeptimer_hal.h"
#include "sl_code_classification.h"
#include "sl_core.h"
#include "sl_clock_manager.h"
#include "sl_interrupt_manager.h"
#include "sl_device_peripheral.h"
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) || defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_prs.h"
#else
#include "sl_hal_prs.h"
#endif
#endif
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC
// Minimum difference between current count value and what the comparator of the timer can be set to.
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
#define SLEEPTIMER_COMPARE_MIN_DIFF (2 + 1)
#define SLEEPTIMER_TMR_WIDTH (_SYSRTC_CNT_MASK)
static bool cc_disabled = true;
static bool cc1_disabled = true;
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
uint32_t b);
/******************************************************************************
* Initializes SYSRTC sleep timer.
*****************************************************************************/
void sleeptimer_hal_init_timer(void)
{
sl_hal_sysrtc_config_t sysrtc_config = SYSRTC_CONFIG_DEFAULT;
sl_hal_sysrtc_group_config_t group_config = SYSRTC_GROUP_CONFIG_DEFAULT;
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_SYSRTC0);
// Make sure the bus clock enabling is done.
__DSB();
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
sysrtc_config.enable_debug_run = true;
#endif
sl_hal_sysrtc_init(&sysrtc_config);
group_config.compare_channel0_enable = false;
sl_hal_sysrtc_init_group(0u, &group_config);
sl_hal_sysrtc_disable_group_interrupts(0u, _SYSRTC_GRP0_IEN_MASK);
sl_hal_sysrtc_clear_group_interrupts(0u, _SYSRTC_GRP0_IF_MASK);
sl_hal_sysrtc_enable();
sl_hal_sysrtc_set_counter(0u);
sl_interrupt_manager_clear_irq_pending(SYSRTC_APP_IRQn);
sl_interrupt_manager_enable_irq(SYSRTC_APP_IRQn);
}
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to Power Manager.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_hal_power_manager_integration_init(void)
{
// Initialize PRS to start HFXO for early wakeup
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_PRS);
#if defined(_SILICON_LABS_32B_SERIES_2)
PRS_ConnectSignal(1UL, prsTypeAsync, prsSignalSYSRTC0_GRP0OUT1);
PRS_ConnectConsumer(1UL, prsTypeAsync, prsConsumerHFXO0_OSCREQ);
#else
sl_hal_prs_async_connect_channel_producer(1UL, SL_HAL_PRS_ASYNC_SYSRTC0_GRP0OUT1);
sl_hal_prs_connect_channel_consumer(1UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_HFXO0_OSCREQ);
#endif
// Set SYSRTC Compare Channel 1
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CMP1CMOA_CMPIF << _SYSRTC_GRP0_CTRL_CMP1CMOA_SHIFT);
}
#endif
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to HFXO Manager.
******************************************************************************/
#if defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
void sli_sleeptimer_hal_hfxo_manager_integration_init(void)
{
// Set PRS signal from HFXO to SYSRTC capture channel
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_PRS);
#if defined(_SILICON_LABS_32B_SERIES_2)
PRS_ConnectSignal(2UL, prsTypeAsync, prsSignalHFXO0L_STATUS1);
PRS_ConnectConsumer(2UL, prsTypeAsync, prsConsumerSYSRTC0_SRC0);
#else
sl_hal_prs_async_connect_channel_producer(2UL, SL_HAL_PRS_ASYNC_SYXO0L_STATUS1);
sl_hal_prs_connect_channel_consumer(2UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_SYSRTC0_IN0);
#endif
// Set SYSRTC Capture Channel
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CAP0EDGE_RISING << _SYSRTC_GRP0_CTRL_CAP0EDGE_SHIFT);
}
#endif
/******************************************************************************
* Gets SYSRTC counter value.
*****************************************************************************/
uint32_t sleeptimer_hal_get_counter(void)
{
return sl_hal_sysrtc_get_counter();
}
/******************************************************************************
* Gets SYSRTC channel zero's compare value.
*****************************************************************************/
uint32_t sleeptimer_hal_get_compare(void)
{
return sl_hal_sysrtc_get_group_compare_channel_value(0u, 0u);
}
/******************************************************************************
* Sets SYSRTC channel zero's compare value.
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the SYSRTC compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
*****************************************************************************/
void sleeptimer_hal_set_compare(uint32_t value)
{
CORE_DECLARE_IRQ_STATE;
uint32_t counter;
uint32_t compare;
uint32_t compare_value = value;
CORE_ENTER_CRITICAL();
counter = sleeptimer_hal_get_counter();
compare = sleeptimer_hal_get_compare();
if (((sl_hal_sysrtc_get_group_interrupts(0u) & SYSRTC_GRP0_IEN_CMP0) != 0)
|| get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|| compare == counter) {
// Add margin if necessary
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
}
compare_value %= SLEEPTIMER_TMR_WIDTH;
sl_hal_sysrtc_set_group_compare_channel_value(0u, 0u, compare_value - 1);
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
}
CORE_EXIT_CRITICAL();
if (cc_disabled) {
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP0EN;
cc_disabled = false;
}
}
/*******************************************************************************
* Sets SYSRTC channel one's compare value.
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the SYSRTC compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
******************************************************************************/
void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value)
{
CORE_DECLARE_IRQ_STATE;
uint32_t counter;
uint32_t compare_value;
CORE_ENTER_CRITICAL();
counter = sleeptimer_hal_get_counter();
compare_value = value + counter;
// Add margin if necessary
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
}
compare_value %= SLEEPTIMER_TMR_WIDTH;
sl_hal_sysrtc_set_group_compare_channel_value(0u, 1u, compare_value - 1);
CORE_EXIT_CRITICAL();
if (cc1_disabled) {
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP1EN;
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CAP0EN;
cc1_disabled = false;
}
}
/******************************************************************************
* Enables SYSRTC interrupts.
*****************************************************************************/
void sleeptimer_hal_enable_int(uint8_t local_flag)
{
uint32_t sysrtc_ien = 0u;
if (local_flag & SLEEPTIMER_EVENT_OF) {
sysrtc_ien |= SYSRTC_GRP0_IEN_OVF;
}
if (local_flag & SLEEPTIMER_EVENT_COMP) {
sysrtc_ien |= SYSRTC_GRP0_IEN_CMP0;
}
sl_hal_sysrtc_enable_group_interrupts(0u, sysrtc_ien);
}
/******************************************************************************
* Disables SYSRTC interrupts.
*****************************************************************************/
void sleeptimer_hal_disable_int(uint8_t local_flag)
{
uint32_t sysrtc_int_dis = 0u;
if (local_flag & SLEEPTIMER_EVENT_OF) {
sysrtc_int_dis |= SYSRTC_GRP0_IEN_OVF;
}
if (local_flag & SLEEPTIMER_EVENT_COMP) {
sysrtc_int_dis |= SYSRTC_GRP0_IEN_CMP0;
cc_disabled = true;
SYSRTC0->GRP0_CTRL &= ~_SYSRTC_GRP0_CTRL_CMP0EN_MASK;
}
sl_hal_sysrtc_disable_group_interrupts(0u, sysrtc_int_dis);
}
/*******************************************************************************
* Hardware Abstraction Layer to set timer interrupts.
******************************************************************************/
void sleeptimer_hal_set_int(uint8_t local_flag)
{
if (local_flag & SLEEPTIMER_EVENT_COMP) {
SYSRTC0->GRP0_IF_SET = SYSRTC_GRP0_IF_CMP0;
}
}
/******************************************************************************
* Gets status of specified interrupt.
*
* Note: This function must be called with interrupts disabled.
*****************************************************************************/
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
{
bool int_is_set = false;
uint32_t irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
switch (local_flag) {
case SLEEPTIMER_EVENT_COMP:
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_CMP0) == SYSRTC_GRP0_IF_CMP0);
break;
case SLEEPTIMER_EVENT_OF:
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_OVF) == SYSRTC_GRP0_IF_OVF);
break;
default:
break;
}
return int_is_set;
}
/*******************************************************************************
* SYSRTC interrupt handler.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER,
SL_CODE_CLASS_TIME_CRITICAL)
void SYSRTC_APP_IRQHandler(void)
{
CORE_DECLARE_IRQ_STATE;
uint8_t local_flag = 0;
uint32_t irq_flag;
CORE_ENTER_ATOMIC();
irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
if (irq_flag & SYSRTC_GRP0_IF_OVF) {
local_flag |= SLEEPTIMER_EVENT_OF;
}
if (irq_flag & SYSRTC_GRP0_IF_CMP0) {
local_flag |= SLEEPTIMER_EVENT_COMP;
}
sl_hal_sysrtc_clear_group_interrupts(0u, irq_flag & (SYSRTC_GRP0_IF_OVF | SYSRTC_GRP0_IF_CMP0));
process_timer_irq(local_flag);
CORE_EXIT_ATOMIC();
}
/*******************************************************************************
* Gets SYSRTC timer frequency.
******************************************************************************/
uint32_t sleeptimer_hal_get_timer_frequency(void)
{
uint32_t frequency;
sl_clock_branch_t clock_branch;
clock_branch = sl_device_peripheral_get_clock_branch(SL_PERIPHERAL_SYSRTC0);
sl_clock_manager_get_clock_branch_frequency(clock_branch, &frequency);
return frequency;
}
/*******************************************************************************
* Computes difference between two times taking into account timer wrap-around.
*
* @param a Time.
* @param b Time to substract from a.
*
* @return Time difference.
******************************************************************************/
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
uint32_t b)
{
return (a - b);
}
/*******************************************************************************
* @brief
* Gets the precision (in PPM) of the sleeptimer's clock.
*
* @return
* Clock accuracy, in PPM.
*
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void)
{
uint16_t precision;
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_SYSRTCCLK, &precision);
return precision;
}
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void)
{
if ((sl_hal_sysrtc_get_group_interrupts(0) & _SYSRTC_GRP0_IF_CAP0_MASK) != 0) {
sl_hal_sysrtc_clear_group_interrupts(0, _SYSRTC_GRP0_IF_CAP0_MASK);
return sl_hal_sysrtc_get_group_capture_channel_value(0);
} else {
return 0;
}
}
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void)
{
sl_hal_sysrtc_clear_group_interrupts(0, SYSRTC_GRP0_IF_CMP1);
}
/*******************************************************************************
* Hardware Abstraction Layer to disable PRS compare and capture channel.
******************************************************************************/
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void)
{
if (!cc1_disabled) {
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CMP1EN;
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CAP0EN;
cc1_disabled = true;
}
}
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*
* @note If power_manager_no_deepsleep component is included in a project, the
* lowest possible energy mode is EM1, else lowest energy mode is
* determined by clock source.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_set_pm_em_requirement(void)
{
switch (CMU->SYSRTC0CLKCTRL & _CMU_SYSRTC0CLKCTRL_CLKSEL_MASK) {
case CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO:
case CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO:
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
break;
default:
break;
}
}
#endif
#endif

View File

@@ -0,0 +1,393 @@
/***************************************************************************//**
* @file
* @brief SLEEPTIMER hardware abstraction implementation for TIMER.
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
// Define module name for Power Manager debug feature
#define CURRENT_MODULE_NAME "SLEEPTIMER_TIMER"
#include "em_device.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_timer.h"
#elif defined(_SILICON_LABS_32B_SERIES_3)
#include "sl_hal_timer.h"
#endif
#include "sl_sleeptimer.h"
#include "sli_sleeptimer_hal.h"
#include "sl_core.h"
#include "sl_clock_manager.h"
#include "sl_interrupt_manager.h"
#include "sl_device_peripheral.h"
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif
#if (SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_TIMER)
// Minimum difference between current count value and what the comparator of the timer can be set to.
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
#define SLEEPTIMER_COMPARE_MIN_DIFF (1 + 1)
// Macros used to constructs TIMER instance
#define _CONCAT_TWO_TOKENS(token_1, token_2) token_1 ## token_2
#define _CONCAT_THREE_TOKENS(token_1, token_2, token_3) token_1 ## token_2 ## token_3
#define CONCAT_TWO_TOKENS(token_1, token_2) _CONCAT_TWO_TOKENS(token_1, token_2)
#define CONCAT_THREE_TOKENS(token_1, token_2, token_3) _CONCAT_THREE_TOKENS(token_1, token_2, token_3)
#if defined(TIMER_PRESENT) \
&& (SL_SLEEPTIMER_TIMER_INSTANCE < TIMER_COUNT) \
&& (TIMER_CNTWIDTH(SL_SLEEPTIMER_TIMER_INSTANCE) == 0x20)
#define SLEEPTIMER_TIMER_INSTANCE TIMER(SL_SLEEPTIMER_TIMER_INSTANCE)
#define SLEEPTIMER_TIMER_CHANNEL 0
#define SLEEPTIMER_PERIPHERAL_TIMER CONCAT_TWO_TOKENS(SL_PERIPHERAL_TIMER, SL_SLEEPTIMER_TIMER_INSTANCE)
#define SLEEPTIMER_TIMER_IRQ CONCAT_THREE_TOKENS(TIMER, SL_SLEEPTIMER_TIMER_INSTANCE, _IRQn)
#define SLEEPTIMER_TIMER_IRQHandler CONCAT_THREE_TOKENS(TIMER, SL_SLEEPTIMER_TIMER_INSTANCE, _IRQHandler)
#define SLEEPTIMER_TIMER_IEN_COMPARE TIMER_IEN_CC0
#define SLEEPTIMER_TIMER_CLK CONCAT_TWO_TOKENS(SL_BUS_CLOCK_TIMER, SL_SLEEPTIMER_TIMER_INSTANCE)
#define SLEEPTIMER_TIMER_TOP_MAX _TIMER_TOP_MASK
#define SLEEPTIMER_TMR_WIDTH _TIMER_CNT_MASK
#else
#define TIMER_UNSUPORTED
#endif
#if defined(TIMER_UNSUPORTED)
#error "The TIMER peripheral instance or channel is not supported. It must be a valid 32-bits size instance."
#endif
#if defined(_SILICON_LABS_32B_SERIES_2)
#define sleeptimer_hal_timer_get_counter(timer_instance) TIMER_CounterGet(timer_instance)
#define sleeptimer_hal_timer_get_compare(timer_instance, channel) TIMER_CaptureGet(timer_instance, channel)
#define sleeptimer_hal_timer_set_compare(timer_instance, channel, compare) TIMER_CompareSet(timer_instance, channel, compare)
#define sleeptimer_hal_timer_get_interrupt(timer_instance) TIMER_IntGet(timer_instance)
#define sleeptimer_hal_timer_set_interrupt(timer_instance, flags) TIMER_IntSet(timer_instance, flags)
#define sleeptimer_hal_timer_enable_interrupt(timer_instance, flags) TIMER_IntEnable(timer_instance, flags)
#define sleeptimer_hal_timer_disable_interrupt(timer_instance, flags) TIMER_IntDisable(timer_instance, flags)
#define sleeptimer_hal_timer_clear_interrupt(timer_instance, flags) TIMER_IntClear(timer_instance, flags)
#else
#define sleeptimer_hal_timer_get_counter(timer_instance) sl_hal_timer_get_counter(timer_instance)
#define sleeptimer_hal_timer_get_compare(timer_instance, channel) sl_hal_timer_channel_get_compare(timer_instance, channel)
#define sleeptimer_hal_timer_set_compare(timer_instance, channel, compare) sl_hal_timer_channel_set_compare(timer_instance, channel, compare)
#define sleeptimer_hal_timer_get_interrupt(timer_instance) sl_hal_timer_get_pending_interrupts(timer_instance)
#define sleeptimer_hal_timer_set_interrupt(timer_instance, flags) sl_hal_timer_set_interrupts(timer_instance, flags)
#define sleeptimer_hal_timer_enable_interrupt(timer_instance, flags) sl_hal_timer_enable_interrupts(timer_instance, flags)
#define sleeptimer_hal_timer_disable_interrupt(timer_instance, flags) sl_hal_timer_disable_interrupts(timer_instance, flags)
#define sleeptimer_hal_timer_clear_interrupt(timer_instance, flags) sl_hal_timer_clear_interrupts(timer_instance, flags)
#endif
static bool comp_int_disabled = true;
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
uint32_t b);
/******************************************************************************
* Initializes TIMER sleep timer.
*****************************************************************************/
void sleeptimer_hal_init_timer(void)
{
sl_clock_manager_enable_bus_clock(SLEEPTIMER_TIMER_CLK);
#if defined(_SILICON_LABS_32B_SERIES_2)
TIMER_Init_TypeDef init_config = TIMER_INIT_DEFAULT;
TIMER_InitCC_TypeDef init_config_cc = TIMER_INITCC_DEFAULT;
init_config_cc.mode = timerCCModeCompare;
init_config.prescale = timerPrescale1024;
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
init_config.debugRun = true;
#endif
TIMER_InitCC(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, &init_config_cc);
TIMER_TopSet(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_TOP_MAX);
TIMER_Init(SLEEPTIMER_TIMER_INSTANCE, &init_config);
#if defined(TIMER_STATUS_SYNCBUSY)
TIMER_SyncWait(SLEEPTIMER_TIMER_INSTANCE);
#endif
TIMER_IntDisable(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
TIMER_IntClear(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
TIMER_CompareSet(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, 0UL);
#elif defined(_SILICON_LABS_32B_SERIES_3)
sl_hal_timer_config_t init_config = SL_HAL_TIMER_CONFIG_DEFAULT;
sl_hal_timer_channel_config_t init_config_cc = SL_HAL_TIMER_CHANNEL_CONFIG_DEFAULT;
init_config_cc.channel_mode = SL_HAL_TIMER_CHANNEL_MODE_COMPARE;
init_config.prescaler = SL_HAL_TIMER_PRESCALER_DIV1024;
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
init_config.debugRun = true;
#endif
sl_hal_timer_channel_init(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, &init_config_cc);
sl_hal_timer_init(SLEEPTIMER_TIMER_INSTANCE, &init_config);
sl_hal_timer_disable_interrupts(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
sl_hal_timer_clear_interrupts(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
sl_hal_timer_enable(SLEEPTIMER_TIMER_INSTANCE);
sl_hal_timer_wait_sync(SLEEPTIMER_TIMER_INSTANCE);
sl_hal_timer_set_top(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_TOP_MAX);
sl_hal_timer_channel_set_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, 0UL);
sl_hal_timer_start(SLEEPTIMER_TIMER_INSTANCE);
#endif
sl_interrupt_manager_clear_irq_pending(SLEEPTIMER_TIMER_IRQ);
sl_interrupt_manager_enable_irq(SLEEPTIMER_TIMER_IRQ);
}
/******************************************************************************
* Gets TIMER counter value.
*****************************************************************************/
uint32_t sleeptimer_hal_get_counter(void)
{
return sleeptimer_hal_timer_get_counter(SLEEPTIMER_TIMER_INSTANCE);
}
/******************************************************************************
* Gets TIMER compare value.
*****************************************************************************/
uint32_t sleeptimer_hal_get_compare(void)
{
return sleeptimer_hal_timer_get_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL);
}
/******************************************************************************
* Sets TIMER compare value.
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the TIMER compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
*****************************************************************************/
void sleeptimer_hal_set_compare(uint32_t value)
{
CORE_DECLARE_IRQ_STATE;
uint32_t counter;
uint32_t compare;
uint32_t compare_value = value;
CORE_ENTER_CRITICAL();
counter = sleeptimer_hal_get_counter();
compare = sleeptimer_hal_get_compare();
if (((sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE) & SLEEPTIMER_TIMER_IEN_COMPARE) != 0)
|| get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|| compare == counter) {
// Add margin if necessary
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
}
compare_value %= SLEEPTIMER_TMR_WIDTH;
sleeptimer_hal_timer_set_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, compare_value - 1);
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
comp_int_disabled = false;
}
CORE_EXIT_CRITICAL();
}
/******************************************************************************
* Enables TIMER interrupts.
*****************************************************************************/
void sleeptimer_hal_enable_int(uint8_t local_flag)
{
uint32_t timer_ien = 0UL;
if (local_flag & SLEEPTIMER_EVENT_OF) {
timer_ien |= TIMER_IEN_OF;
}
if (local_flag & SLEEPTIMER_EVENT_COMP) {
if (comp_int_disabled == true) {
sleeptimer_hal_timer_clear_interrupt(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_IEN_COMPARE);
comp_int_disabled = false;
}
timer_ien |= SLEEPTIMER_TIMER_IEN_COMPARE;
}
sleeptimer_hal_timer_enable_interrupt(SLEEPTIMER_TIMER_INSTANCE, timer_ien);
}
/******************************************************************************
* Disables TIMER interrupts.
*****************************************************************************/
void sleeptimer_hal_disable_int(uint8_t local_flag)
{
uint32_t timer_int_dis = 0UL;
if (local_flag & SLEEPTIMER_EVENT_OF) {
timer_int_dis |= TIMER_IEN_OF;
}
if (local_flag & SLEEPTIMER_EVENT_COMP) {
timer_int_dis |= SLEEPTIMER_TIMER_IEN_COMPARE;
comp_int_disabled = true;
}
sleeptimer_hal_timer_disable_interrupt(SLEEPTIMER_TIMER_INSTANCE, timer_int_dis);
}
/*******************************************************************************
* Hardware Abstraction Layer to set timer interrupts.
******************************************************************************/
void sleeptimer_hal_set_int(uint8_t local_flag)
{
if (local_flag & SLEEPTIMER_EVENT_COMP) {
sleeptimer_hal_timer_set_interrupt(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_IEN_COMPARE);
}
}
/******************************************************************************
* Gets status of specified interrupt.
*
* Note: This function must be called with interrupts disabled.
*****************************************************************************/
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
{
bool int_is_set = false;
uint32_t irq_flag = sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE);
switch (local_flag) {
case SLEEPTIMER_EVENT_COMP:
int_is_set = ((irq_flag & SLEEPTIMER_TIMER_IEN_COMPARE) == SLEEPTIMER_TIMER_IEN_COMPARE);
break;
case SLEEPTIMER_EVENT_OF:
int_is_set = ((irq_flag & TIMER_IEN_OF) == TIMER_IEN_OF);
break;
default:
break;
}
return int_is_set;
}
/*******************************************************************************
* TIMER interrupt handler.
******************************************************************************/
void SLEEPTIMER_TIMER_IRQHandler(void)
{
CORE_DECLARE_IRQ_STATE;
uint8_t local_flag = 0;
uint32_t irq_flag;
CORE_ENTER_ATOMIC();
irq_flag = sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE);
if (irq_flag & TIMER_IEN_OF) {
local_flag |= SLEEPTIMER_EVENT_OF;
}
if (irq_flag & SLEEPTIMER_TIMER_IEN_COMPARE) {
local_flag |= SLEEPTIMER_EVENT_COMP;
}
sleeptimer_hal_timer_clear_interrupt(SLEEPTIMER_TIMER_INSTANCE, irq_flag & (TIMER_IEN_OF | SLEEPTIMER_TIMER_IEN_COMPARE));
process_timer_irq(local_flag);
CORE_EXIT_ATOMIC();
}
/*******************************************************************************
* Gets TIMER timer frequency.
******************************************************************************/
uint32_t sleeptimer_hal_get_timer_frequency(void)
{
// Returns source frequency divided by max prescaler value 1024.
uint32_t freq;
sl_clock_branch_t clock_branch;
clock_branch = sl_device_peripheral_get_clock_branch(SLEEPTIMER_PERIPHERAL_TIMER);
sl_clock_manager_get_clock_branch_frequency(clock_branch, &freq);
return (freq >> 10UL);
}
/*******************************************************************************
* Computes difference between two times taking into account timer wrap-around.
*
* @param a Time.
* @param b Time to substract from a.
*
* @return Time difference.
******************************************************************************/
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
uint32_t b)
{
return (a - b);
}
/*******************************************************************************
* @brief
* Gets the precision (in PPM) of the sleeptimer's clock.
*
* @return
* Clock accuracy, in PPM.
*
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void)
{
uint16_t precision;
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_EM01GRPACLK, &precision);
return precision;
}
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
*
* @return Capture value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void)
{
// Invalid for TIMER peripheral
EFM_ASSERT(0);
return 0;
}
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void)
{
// Invalid for TIMER peripheral
EFM_ASSERT(0);
}
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*
* @note Lowest possible energy mode for TIMER peripheral is EM1.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_set_pm_em_requirement(void)
{
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
}
#endif
#endif

View File

@@ -0,0 +1,189 @@
/***************************************************************************//**
* @file
* @brief SLEEPTIMER hardware abstraction layer definition.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_SLEEPTIMER_HAL_H
#define SL_SLEEPTIMER_HAL_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "em_device.h"
#include "sli_sleeptimer.h"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
* Hardware Abstraction Layer of the sleep timer init.
******************************************************************************/
void sleeptimer_hal_init_timer(void);
/*******************************************************************************
* Hardware Abstraction Layer to get the current timer count.
*
* @return Value in ticks of the timer counter.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sleeptimer_hal_get_counter(void);
/*******************************************************************************
* Hardware Abstraction Layer to get a timer comparator value.
*
* @return Value in ticks of the timer comparator.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sleeptimer_hal_get_compare(void);
/*******************************************************************************
* Hardware Abstraction Layer to set a timer comparator value.
*
* @param value Number of ticks to set.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_set_compare(uint32_t value);
/*******************************************************************************
* Hardware Abstraction Layer to set a comparator value to trigger a
* peripheral request signal to initialize.
*
* @param value Number of ticks to set.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value);
/*******************************************************************************
* Hardware Abstraction Layer to get the timer frequency.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sleeptimer_hal_get_timer_frequency(void);
/*******************************************************************************
* Hardware Abstraction Layer to enable timer interrupts.
*
* @param local_flag Internal interrupt flag.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_enable_int(uint8_t local_flag);
/*******************************************************************************
* Hardware Abstraction Layer to disable timer interrupts.
*
* @param local_flag Internal interrupt flag.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_disable_int(uint8_t local_flag);
/*******************************************************************************
* Hardware Abstraction Layer to set timer interrupts.
*
* @param local_flag Internal interrupt flag.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_set_int(uint8_t local_flag);
/*******************************************************************************
* Hardware Abstraction Layer to get the sleeptimer's clock accuracy.
*
* @return Clock accuracy in PPM.
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void);
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
*
* @note Not supported by all peripherals Sleeptimer can use.
*
* @return Capture value.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sleeptimer_hal_get_capture(void);
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
*
* @note Not supported by all peripherals Sleeptimer can use.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_reset_prs_signal(void);
/*******************************************************************************
* Hardware Abstraction Layer to disable PRS compare and capture channel.
*
* @note Not supported by all peripherals Sleeptimer can use.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void);
/*******************************************************************************
* Process the timer interrupt.
*
* @param flags Internal interrupt flag.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
void process_timer_irq(uint8_t local_flag);
/***************************************************************************//**
* @brief
* Convert prescaler divider to a logarithmic value. It only works for even
* numbers equal to 2^n.
*
* @param[in] presc
* Prescaler value used to set the frequency divider. The divider is equal to
* ('presc' + 1). If a divider value is passed for 'presc', 'presc' will be
* equal to (divider - 1).
*
* @return
* Logarithm base 2 (binary) value, i.e. exponent as used by fixed
* 2^n prescalers.
******************************************************************************/
__STATIC_INLINE uint32_t sleeptimer_hal_presc_to_log2(uint32_t presc)
{
uint32_t log2;
// Integer prescalers take argument less than 32768.
EFM_ASSERT(presc < 32768U);
// Count leading zeroes and "reverse" result. Consider divider value to get
// exponent n from 2^n, so ('presc' +1).
log2 = 31UL - __CLZ(presc + (uint32_t) 1);
// Check that prescaler is a 2^n number.
EFM_ASSERT(presc == (SL_Log2ToDiv(log2) - 1U));
return log2;
}
#ifdef __cplusplus
}
#endif
#endif /* SL_SLEEPTIMER_HAL_H */