Initial commit of firmware
This commit is contained in:
1967
Libs/platform/service/sleeptimer/src/sl_sleeptimer.c
Normal file
1967
Libs/platform/service/sleeptimer/src/sl_sleeptimer.c
Normal file
File diff suppressed because it is too large
Load Diff
381
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_burtc.c
Normal file
381
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_burtc.c
Normal 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
|
||||
443
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_sysrtc.c
Normal file
443
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_sysrtc.c
Normal 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
|
||||
393
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_timer.c
Normal file
393
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_timer.c
Normal 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
|
||||
189
Libs/platform/service/sleeptimer/src/sli_sleeptimer_hal.h
Normal file
189
Libs/platform/service/sleeptimer/src/sli_sleeptimer_hal.h
Normal 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 */
|
||||
Reference in New Issue
Block a user