[FL-2480] Use SysTick as the main OS timer (#1140)
* Use SysTick as OS tick timer * Use LPTIM2 as tickless idle timer * Remove dummy LPTIM2 IRQ handler * Clean up clock init code * Rename os timer to idle timer * Advance hal ticks along with FreeRTOS's * Improve SysTick control during tickless idle * Improve idle timer precision * Correct SysTick IRQ priority * Main, FuriHal: move system startup to separate thread * Minor code cleanup Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
ad1ee8a5c6
commit
df66f4f6ba
@ -18,7 +18,7 @@ extern uint32_t SystemCoreClock;
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCPU_CLOCK_HZ (SystemCoreClock)
|
||||
#define configTICK_RATE_HZ ((TickType_t)1024)
|
||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||
#define configMAX_PRIORITIES (56)
|
||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||
|
||||
|
@ -6,32 +6,31 @@
|
||||
|
||||
#define TAG "Main"
|
||||
|
||||
#ifdef FURI_RAM_EXEC
|
||||
int main() {
|
||||
// Initialize FURI layer
|
||||
furi_init();
|
||||
|
||||
// Flipper critical FURI HAL
|
||||
furi_hal_init_early();
|
||||
static const osThreadAttr_t init_thread_attr = {
|
||||
.name = "Init",
|
||||
.stack_size = 4096,
|
||||
};
|
||||
|
||||
void init_task() {
|
||||
// Flipper FURI HAL
|
||||
furi_hal_init();
|
||||
|
||||
// Init flipper
|
||||
flipper_init();
|
||||
|
||||
furi_run();
|
||||
|
||||
while(1) {
|
||||
}
|
||||
osThreadExit();
|
||||
}
|
||||
#else
|
||||
|
||||
int main() {
|
||||
// Initialize FURI layer
|
||||
furi_init();
|
||||
|
||||
// Flipper critical FURI HAL
|
||||
furi_hal_init_early();
|
||||
|
||||
#ifdef FURI_RAM_EXEC
|
||||
osThreadNew(init_task, NULL, &init_thread_attr);
|
||||
#else
|
||||
furi_hal_light_sequence("RGB");
|
||||
|
||||
// Delay is for button sampling
|
||||
@ -52,21 +51,16 @@ int main() {
|
||||
furi_hal_power_reset();
|
||||
} else {
|
||||
furi_hal_light_sequence("rgb G");
|
||||
|
||||
// Flipper FURI HAL
|
||||
furi_hal_init();
|
||||
|
||||
// Init flipper
|
||||
flipper_init();
|
||||
|
||||
furi_run();
|
||||
osThreadNew(init_task, NULL, &init_thread_attr);
|
||||
}
|
||||
|
||||
while(1) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run Kernel
|
||||
furi_run();
|
||||
|
||||
furi_crash("Kernel is Dead");
|
||||
}
|
||||
|
||||
void Error_Handler(void) {
|
||||
furi_crash("ErrorHandler");
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ void furi_hal_init_early() {
|
||||
furi_hal_clock_init_early();
|
||||
furi_hal_delay_init();
|
||||
|
||||
furi_hal_os_init();
|
||||
|
||||
furi_hal_resources_init_early();
|
||||
|
||||
furi_hal_spi_init_early();
|
||||
@ -75,9 +77,6 @@ void furi_hal_init() {
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FreeRTOS glue
|
||||
furi_hal_os_init();
|
||||
|
||||
// FatFS driver initialization
|
||||
MX_FATFS_Init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
|
@ -9,13 +9,15 @@
|
||||
|
||||
#define TAG "FuriHalClock"
|
||||
|
||||
#define TICK_INT_PRIORITY 0U
|
||||
#define CPU_CLOCK_HZ_EARLY 4000000
|
||||
#define CPU_CLOCK_HZ_MAIN 64000000
|
||||
#define TICK_INT_PRIORITY 15U
|
||||
#define HS_CLOCK_IS_READY() (LL_RCC_HSE_IsReady() && LL_RCC_HSI_IsReady())
|
||||
#define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady())
|
||||
|
||||
void furi_hal_clock_init_early() {
|
||||
LL_Init1msTick(4000000);
|
||||
LL_SetSystemCoreClock(4000000);
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY);
|
||||
LL_Init1msTick(SystemCoreClock);
|
||||
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
|
||||
@ -27,6 +29,8 @@ void furi_hal_clock_init_early() {
|
||||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
|
||||
|
||||
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2);
|
||||
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
}
|
||||
@ -47,7 +51,7 @@ void furi_hal_clock_deinit_early() {
|
||||
}
|
||||
|
||||
void furi_hal_clock_init() {
|
||||
/* Prepare Flash memory for 64mHz system clock */
|
||||
/* Prepare Flash memory for 64MHz system clock */
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
|
||||
;
|
||||
@ -116,12 +120,13 @@ void furi_hal_clock_init() {
|
||||
;
|
||||
|
||||
/* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
|
||||
LL_SetSystemCoreClock(64000000);
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_HZ_MAIN);
|
||||
|
||||
/* Update the time base */
|
||||
LL_InitTick(64000000, 1000);
|
||||
LL_Init1msTick(SystemCoreClock);
|
||||
LL_SYSTICK_EnableIT();
|
||||
NVIC_SetPriority(SysTick_IRQn, TICK_INT_PRIORITY);
|
||||
NVIC_SetPriority(
|
||||
SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TICK_INT_PRIORITY, 0));
|
||||
NVIC_EnableIRQ(SysTick_IRQn);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
@ -175,7 +180,6 @@ void furi_hal_clock_init() {
|
||||
|
||||
// APB1 GRP2
|
||||
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
|
||||
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2);
|
||||
|
||||
// APB2
|
||||
// LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC);
|
||||
@ -217,3 +221,11 @@ void furi_hal_clock_switch_to_pll() {
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
|
||||
;
|
||||
}
|
||||
|
||||
void furi_hal_clock_suspend_tick() {
|
||||
CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
|
||||
}
|
||||
|
||||
void furi_hal_clock_resume_tick() {
|
||||
SET_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
|
||||
}
|
||||
|
@ -14,3 +14,9 @@ void furi_hal_clock_switch_to_hsi();
|
||||
|
||||
/** Switch to PLL clock */
|
||||
void furi_hal_clock_switch_to_pll();
|
||||
|
||||
/** Stop SysTick counter without resetting */
|
||||
void furi_hal_clock_suspend_tick();
|
||||
|
||||
/** Continue SysTick counter operation */
|
||||
void furi_hal_clock_resume_tick();
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#define TAG "FuriHalDelay"
|
||||
|
||||
static volatile uint32_t tick_cnt = 0;
|
||||
|
||||
void furi_hal_delay_init() {
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
@ -18,12 +16,8 @@ uint32_t furi_hal_delay_instructions_per_microsecond() {
|
||||
return SystemCoreClock / 1000000;
|
||||
}
|
||||
|
||||
void furi_hal_tick(void) {
|
||||
tick_cnt++;
|
||||
}
|
||||
|
||||
uint32_t furi_hal_get_tick(void) {
|
||||
return tick_cnt;
|
||||
return osKernelGetTickCount();
|
||||
}
|
||||
|
||||
uint32_t furi_hal_ms_to_ticks(float milliseconds) {
|
||||
|
55
firmware/targets/f7/furi_hal/furi_hal_idle_timer.h
Normal file
55
firmware/targets/f7/furi_hal/furi_hal_idle_timer.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_lptim.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Timer used for tickless idle
|
||||
#define FURI_HAL_IDLE_TIMER_MAX 0xFFFF
|
||||
#define FURI_HAL_IDLE_TIMER LPTIM2
|
||||
#define FURI_HAL_IDLE_TIMER_IRQ LPTIM2_IRQn
|
||||
|
||||
static inline void furi_hal_idle_timer_init() {
|
||||
// Configure clock source
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
// Set interrupt priority and enable them
|
||||
NVIC_SetPriority(
|
||||
FURI_HAL_IDLE_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
NVIC_EnableIRQ(FURI_HAL_IDLE_TIMER_IRQ);
|
||||
}
|
||||
|
||||
static inline void furi_hal_idle_timer_start(uint32_t count) {
|
||||
count--;
|
||||
// Enable timer
|
||||
LL_LPTIM_Enable(FURI_HAL_IDLE_TIMER);
|
||||
while(!LL_LPTIM_IsEnabled(FURI_HAL_IDLE_TIMER))
|
||||
;
|
||||
|
||||
// Enable compare match interrupt
|
||||
LL_LPTIM_EnableIT_CMPM(FURI_HAL_IDLE_TIMER);
|
||||
|
||||
// Set compare, autoreload and start counter
|
||||
// Include some marging to workaround ARRM behaviour
|
||||
LL_LPTIM_SetCompare(FURI_HAL_IDLE_TIMER, count - 3);
|
||||
LL_LPTIM_SetAutoReload(FURI_HAL_IDLE_TIMER, count);
|
||||
LL_LPTIM_StartCounter(FURI_HAL_IDLE_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT);
|
||||
}
|
||||
|
||||
static inline void furi_hal_idle_timer_reset() {
|
||||
// Hard reset timer
|
||||
// THE ONLY RELIABLE WAY to stop it according to errata
|
||||
LL_LPTIM_DeInit(FURI_HAL_IDLE_TIMER);
|
||||
// Prevent IRQ handler call
|
||||
NVIC_ClearPendingIRQ(FURI_HAL_IDLE_TIMER_IRQ);
|
||||
}
|
||||
|
||||
static inline uint32_t furi_hal_idle_timer_get_cnt() {
|
||||
uint32_t counter = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER);
|
||||
uint32_t counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER);
|
||||
while(counter != counter_shadow) {
|
||||
counter = counter_shadow;
|
||||
counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER);
|
||||
}
|
||||
return counter;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include "furi_hal_interrupt.h"
|
||||
#include "furi_hal_delay.h"
|
||||
#include "furi_hal_os.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
@ -249,7 +250,7 @@ extern void HW_IPCC_Tx_Handler();
|
||||
extern void HW_IPCC_Rx_Handler();
|
||||
|
||||
void SysTick_Handler(void) {
|
||||
furi_hal_tick();
|
||||
furi_hal_os_tick();
|
||||
}
|
||||
|
||||
void USB_LP_IRQHandler(void) {
|
||||
|
@ -1,17 +1,22 @@
|
||||
#include <furi_hal_os.h>
|
||||
#include <furi_hal_os_timer.h>
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_delay.h>
|
||||
#include <furi_hal_idle_timer.h>
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "FuriHalOs"
|
||||
|
||||
#define FURI_HAL_OS_CLK_FREQUENCY 32768
|
||||
#define FURI_HAL_OS_TICK_PER_SECOND 1024
|
||||
#define FURI_HAL_OS_CLK_PER_TICK (FURI_HAL_OS_CLK_FREQUENCY / FURI_HAL_OS_TICK_PER_SECOND)
|
||||
#define FURI_HAL_OS_TICK_PER_EPOCH (FURI_HAL_OS_TIMER_MAX / FURI_HAL_OS_CLK_PER_TICK)
|
||||
#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_OS_TICK_PER_EPOCH - 1)
|
||||
#define FURI_HAL_IDLE_TIMER_CLK_HZ 32768
|
||||
#define FURI_HAL_OS_TICK_HZ configTICK_RATE_HZ
|
||||
|
||||
#define FURI_HAL_OS_IDLE_CNT_TO_TICKS(x) ((x * FURI_HAL_OS_TICK_HZ) / FURI_HAL_IDLE_TIMER_CLK_HZ)
|
||||
#define FURI_HAL_OS_TICKS_TO_IDLE_CNT(x) ((x * FURI_HAL_IDLE_TIMER_CLK_HZ) / FURI_HAL_OS_TICK_HZ)
|
||||
|
||||
#define FURI_HAL_IDLE_TIMER_TICK_PER_EPOCH (FURI_HAL_OS_IDLE_CNT_TO_TICKS(FURI_HAL_IDLE_TIMER_MAX))
|
||||
#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_IDLE_TIMER_TICK_PER_EPOCH - 1)
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
@ -30,48 +35,37 @@ void furi_hal_os_timer_callback() {
|
||||
|
||||
extern void xPortSysTickHandler();
|
||||
|
||||
volatile uint32_t furi_hal_os_skew = 0;
|
||||
static volatile uint32_t furi_hal_os_skew = 0;
|
||||
|
||||
void furi_hal_os_init() {
|
||||
LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP);
|
||||
|
||||
furi_hal_os_timer_init();
|
||||
furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK);
|
||||
furi_hal_idle_timer_init();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
LL_GPIO_SetPinMode(LED_SLEEP_PORT, LED_SLEEP_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
|
||||
osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND);
|
||||
osTimerStart(second_timer, FURI_HAL_OS_TICK_HZ);
|
||||
#endif
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void LPTIM2_IRQHandler(void) {
|
||||
// Autoreload
|
||||
if(LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER)) {
|
||||
LL_LPTIM_ClearFLAG_ARRM(FURI_HAL_OS_TIMER);
|
||||
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
void furi_hal_os_tick() {
|
||||
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN);
|
||||
LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN);
|
||||
#endif
|
||||
xPortSysTickHandler();
|
||||
}
|
||||
}
|
||||
if(LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER)) {
|
||||
LL_LPTIM_ClearFLAG_CMPM(FURI_HAL_OS_TIMER);
|
||||
xPortSysTickHandler();
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
// Stop ticks
|
||||
furi_hal_os_timer_reset();
|
||||
LL_SYSTICK_DisableIT();
|
||||
furi_hal_clock_suspend_tick();
|
||||
|
||||
// Start wakeup timer
|
||||
furi_hal_os_timer_single(expected_idle_ticks * FURI_HAL_OS_CLK_PER_TICK);
|
||||
furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks));
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
LL_GPIO_ResetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN);
|
||||
@ -85,21 +79,19 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
#endif
|
||||
|
||||
// Calculate how much time we spent in the sleep
|
||||
uint32_t after_cnt = furi_hal_os_timer_get_cnt() + furi_hal_os_skew;
|
||||
uint32_t after_tick = after_cnt / FURI_HAL_OS_CLK_PER_TICK;
|
||||
furi_hal_os_skew = after_cnt % FURI_HAL_OS_CLK_PER_TICK;
|
||||
uint32_t after_cnt = furi_hal_idle_timer_get_cnt() + furi_hal_os_skew;
|
||||
uint32_t after_tick = FURI_HAL_OS_IDLE_CNT_TO_TICKS(after_cnt);
|
||||
furi_hal_os_skew = after_cnt - (after_cnt / after_tick);
|
||||
|
||||
bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER);
|
||||
bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER);
|
||||
bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_IDLE_TIMER);
|
||||
bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_IDLE_TIMER);
|
||||
if(cmpm && arrm) after_tick += expected_idle_ticks;
|
||||
|
||||
// Prepare tick timer for new round
|
||||
furi_hal_os_timer_reset();
|
||||
furi_hal_idle_timer_reset();
|
||||
|
||||
// Resume ticks
|
||||
LL_SYSTICK_EnableIT();
|
||||
furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK);
|
||||
|
||||
furi_hal_clock_resume_tick();
|
||||
return after_tick;
|
||||
}
|
||||
|
||||
@ -109,7 +101,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit mount of ticks to maximum that timer can count
|
||||
// Limit amount of ticks to maximum that timer can count
|
||||
if(expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) {
|
||||
expected_idle_ticks = FURI_HAL_OS_MAX_SLEEP;
|
||||
}
|
||||
@ -125,14 +117,9 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
|
||||
// Sleep and track how much ticks we spent sleeping
|
||||
uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks);
|
||||
|
||||
// Notify system about time spent in sleep
|
||||
if(completed_ticks > 0) {
|
||||
if(completed_ticks > expected_idle_ticks) {
|
||||
vTaskStepTick(expected_idle_ticks);
|
||||
} else {
|
||||
vTaskStepTick(completed_ticks);
|
||||
}
|
||||
vTaskStepTick(MIN(completed_ticks, expected_idle_ticks));
|
||||
}
|
||||
|
||||
// Reenable IRQ
|
||||
|
@ -11,6 +11,10 @@ extern "C" {
|
||||
*/
|
||||
void furi_hal_os_init();
|
||||
|
||||
/* Advance OS tick counter
|
||||
*/
|
||||
void furi_hal_os_tick();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_lptim.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Timer used for system ticks
|
||||
#define FURI_HAL_OS_TIMER_MAX 0xFFFF
|
||||
#define FURI_HAL_OS_TIMER_REG_LOAD_DLY 0x1
|
||||
#define FURI_HAL_OS_TIMER LPTIM2
|
||||
#define FURI_HAL_OS_TIMER_IRQ LPTIM2_IRQn
|
||||
|
||||
static inline void furi_hal_os_timer_init() {
|
||||
// Configure clock source
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
// Set interrupt priority and enable them
|
||||
NVIC_SetPriority(
|
||||
FURI_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
NVIC_EnableIRQ(FURI_HAL_OS_TIMER_IRQ);
|
||||
}
|
||||
|
||||
static inline void furi_hal_os_timer_continuous(uint32_t count) {
|
||||
count--;
|
||||
// Enable timer
|
||||
LL_LPTIM_Enable(FURI_HAL_OS_TIMER);
|
||||
while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER))
|
||||
;
|
||||
|
||||
// Enable rutoreload match interrupt
|
||||
LL_LPTIM_EnableIT_ARRM(FURI_HAL_OS_TIMER);
|
||||
|
||||
// Set autoreload and start counter
|
||||
LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count);
|
||||
LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
|
||||
}
|
||||
|
||||
static inline void furi_hal_os_timer_single(uint32_t count) {
|
||||
count--;
|
||||
// Enable timer
|
||||
LL_LPTIM_Enable(FURI_HAL_OS_TIMER);
|
||||
while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER))
|
||||
;
|
||||
|
||||
// Enable compare match interrupt
|
||||
LL_LPTIM_EnableIT_CMPM(FURI_HAL_OS_TIMER);
|
||||
|
||||
// Set compare, autoreload and start counter
|
||||
// Include some marging to workaround ARRM behaviour
|
||||
LL_LPTIM_SetCompare(FURI_HAL_OS_TIMER, count - 3);
|
||||
LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count);
|
||||
LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT);
|
||||
}
|
||||
|
||||
static inline void furi_hal_os_timer_reset() {
|
||||
// Hard reset timer
|
||||
// THE ONLY RELIABLEWAY to stop it according to errata
|
||||
LL_LPTIM_DeInit(FURI_HAL_OS_TIMER);
|
||||
}
|
||||
|
||||
static inline uint32_t furi_hal_os_timer_get_cnt() {
|
||||
uint32_t counter = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER);
|
||||
uint32_t counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER);
|
||||
while(counter != counter_shadow) {
|
||||
counter = counter_shadow;
|
||||
counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER);
|
||||
}
|
||||
return counter;
|
||||
}
|
@ -18,11 +18,6 @@ void furi_hal_delay_init();
|
||||
/** Get instructions per microsecond count */
|
||||
uint32_t furi_hal_delay_instructions_per_microsecond();
|
||||
|
||||
/** Increase tick counter.
|
||||
* Should be called from SysTick ISR
|
||||
*/
|
||||
void furi_hal_tick(void);
|
||||
|
||||
/** Get current tick counter
|
||||
*
|
||||
* System uptime, may overflow.
|
||||
|
Loading…
Reference in New Issue
Block a user