[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:
Georgii Surkov 2022-04-21 16:15:19 +03:00 committed by GitHub
parent ad1ee8a5c6
commit df66f4f6ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 140 additions and 162 deletions

View File

@ -18,7 +18,7 @@ extern uint32_t SystemCoreClock;
#define configUSE_IDLE_HOOK 0 #define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0 #define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ (SystemCoreClock) #define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ ((TickType_t)1024) #define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES (56) #define configMAX_PRIORITIES (56)
#define configMINIMAL_STACK_SIZE ((uint16_t)128) #define configMINIMAL_STACK_SIZE ((uint16_t)128)

View File

@ -6,32 +6,31 @@
#define TAG "Main" #define TAG "Main"
#ifdef FURI_RAM_EXEC static const osThreadAttr_t init_thread_attr = {
int main() { .name = "Init",
// Initialize FURI layer .stack_size = 4096,
furi_init(); };
// Flipper critical FURI HAL
furi_hal_init_early();
void init_task() {
// Flipper FURI HAL // Flipper FURI HAL
furi_hal_init(); furi_hal_init();
// Init flipper // Init flipper
flipper_init(); flipper_init();
furi_run(); osThreadExit();
while(1) {
}
} }
#else
int main() { int main() {
// Initialize FURI layer // Initialize FURI layer
furi_init(); furi_init();
// Flipper critical FURI HAL // Flipper critical FURI HAL
furi_hal_init_early(); furi_hal_init_early();
#ifdef FURI_RAM_EXEC
osThreadNew(init_task, NULL, &init_thread_attr);
#else
furi_hal_light_sequence("RGB"); furi_hal_light_sequence("RGB");
// Delay is for button sampling // Delay is for button sampling
@ -52,21 +51,16 @@ int main() {
furi_hal_power_reset(); furi_hal_power_reset();
} else { } else {
furi_hal_light_sequence("rgb G"); furi_hal_light_sequence("rgb G");
osThreadNew(init_task, NULL, &init_thread_attr);
// Flipper FURI HAL
furi_hal_init();
// Init flipper
flipper_init();
furi_run();
} }
while(1) {
}
}
#endif #endif
// Run Kernel
furi_run();
furi_crash("Kernel is Dead");
}
void Error_Handler(void) { void Error_Handler(void) {
furi_crash("ErrorHandler"); furi_crash("ErrorHandler");
} }

View File

@ -10,6 +10,8 @@ void furi_hal_init_early() {
furi_hal_clock_init_early(); furi_hal_clock_init_early();
furi_hal_delay_init(); furi_hal_delay_init();
furi_hal_os_init();
furi_hal_resources_init_early(); furi_hal_resources_init_early();
furi_hal_spi_init_early(); furi_hal_spi_init_early();
@ -75,9 +77,6 @@ void furi_hal_init() {
furi_hal_bt_init(); furi_hal_bt_init();
furi_hal_compress_icon_init(); furi_hal_compress_icon_init();
// FreeRTOS glue
furi_hal_os_init();
// FatFS driver initialization // FatFS driver initialization
MX_FATFS_Init(); MX_FATFS_Init();
FURI_LOG_I(TAG, "FATFS OK"); FURI_LOG_I(TAG, "FATFS OK");

View File

@ -9,13 +9,15 @@
#define TAG "FuriHalClock" #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 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()) #define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady())
void furi_hal_clock_init_early() { void furi_hal_clock_init_early() {
LL_Init1msTick(4000000); LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY);
LL_SetSystemCoreClock(4000000); LL_Init1msTick(SystemCoreClock);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); 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_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); 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_I2C1);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
} }
@ -47,7 +51,7 @@ void furi_hal_clock_deinit_early() {
} }
void furi_hal_clock_init() { 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); LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
while(LL_FLASH_GetLatency() != 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) */ /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
LL_SetSystemCoreClock(64000000); LL_SetSystemCoreClock(CPU_CLOCK_HZ_MAIN);
/* Update the time base */ /* Update the time base */
LL_InitTick(64000000, 1000); LL_Init1msTick(SystemCoreClock);
LL_SYSTICK_EnableIT(); 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); NVIC_EnableIRQ(SysTick_IRQn);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
@ -175,7 +180,6 @@ void furi_hal_clock_init() {
// APB1 GRP2 // APB1 GRP2
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2);
// APB2 // APB2
// LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); // 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) 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);
}

View File

@ -14,3 +14,9 @@ void furi_hal_clock_switch_to_hsi();
/** Switch to PLL clock */ /** Switch to PLL clock */
void furi_hal_clock_switch_to_pll(); 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();

View File

@ -6,8 +6,6 @@
#define TAG "FuriHalDelay" #define TAG "FuriHalDelay"
static volatile uint32_t tick_cnt = 0;
void furi_hal_delay_init() { void furi_hal_delay_init() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
@ -18,12 +16,8 @@ uint32_t furi_hal_delay_instructions_per_microsecond() {
return SystemCoreClock / 1000000; return SystemCoreClock / 1000000;
} }
void furi_hal_tick(void) {
tick_cnt++;
}
uint32_t furi_hal_get_tick(void) { uint32_t furi_hal_get_tick(void) {
return tick_cnt; return osKernelGetTickCount();
} }
uint32_t furi_hal_ms_to_ticks(float milliseconds) { uint32_t furi_hal_ms_to_ticks(float milliseconds) {

View 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;
}

View File

@ -1,5 +1,6 @@
#include "furi_hal_interrupt.h" #include "furi_hal_interrupt.h"
#include "furi_hal_delay.h" #include "furi_hal_delay.h"
#include "furi_hal_os.h"
#include <furi.h> #include <furi.h>
@ -249,7 +250,7 @@ extern void HW_IPCC_Tx_Handler();
extern void HW_IPCC_Rx_Handler(); extern void HW_IPCC_Rx_Handler();
void SysTick_Handler(void) { void SysTick_Handler(void) {
furi_hal_tick(); furi_hal_os_tick();
} }
void USB_LP_IRQHandler(void) { void USB_LP_IRQHandler(void) {
@ -264,4 +265,4 @@ void IPCC_C1_TX_IRQHandler(void) {
void IPCC_C1_RX_IRQHandler(void) { void IPCC_C1_RX_IRQHandler(void) {
HW_IPCC_Rx_Handler(); HW_IPCC_Rx_Handler();
} }

View File

@ -1,17 +1,22 @@
#include <furi_hal_os.h> #include <furi_hal_os.h>
#include <furi_hal_os_timer.h> #include <furi_hal_clock.h>
#include <furi_hal_power.h> #include <furi_hal_power.h>
#include <furi_hal_delay.h>
#include <furi_hal_idle_timer.h>
#include <stm32wbxx_ll_cortex.h> #include <stm32wbxx_ll_cortex.h>
#include <furi.h> #include <furi.h>
#define TAG "FuriHalOs" #define TAG "FuriHalOs"
#define FURI_HAL_OS_CLK_FREQUENCY 32768 #define FURI_HAL_IDLE_TIMER_CLK_HZ 32768
#define FURI_HAL_OS_TICK_PER_SECOND 1024 #define FURI_HAL_OS_TICK_HZ configTICK_RATE_HZ
#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_IDLE_CNT_TO_TICKS(x) ((x * FURI_HAL_OS_TICK_HZ) / FURI_HAL_IDLE_TIMER_CLK_HZ)
#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_OS_TICK_PER_EPOCH - 1) #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 #ifdef FURI_HAL_OS_DEBUG
#include <stm32wbxx_ll_gpio.h> #include <stm32wbxx_ll_gpio.h>
@ -30,48 +35,37 @@ void furi_hal_os_timer_callback() {
extern void xPortSysTickHandler(); 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() { void furi_hal_os_init() {
LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); furi_hal_idle_timer_init();
furi_hal_os_timer_init();
furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK);
#ifdef FURI_HAL_OS_DEBUG #ifdef FURI_HAL_OS_DEBUG
LL_GPIO_SetPinMode(LED_SLEEP_PORT, LED_SLEEP_PIN, LL_GPIO_MODE_OUTPUT); 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_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_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); 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 #endif
FURI_LOG_I(TAG, "Init OK"); FURI_LOG_I(TAG, "Init OK");
} }
void LPTIM2_IRQHandler(void) { void furi_hal_os_tick() {
// Autoreload if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
if(LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER)) {
LL_LPTIM_ClearFLAG_ARRM(FURI_HAL_OS_TIMER);
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
#ifdef FURI_HAL_OS_DEBUG #ifdef FURI_HAL_OS_DEBUG
LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN); LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN);
#endif #endif
xPortSysTickHandler(); xPortSysTickHandler();
}
}
if(LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER)) {
LL_LPTIM_ClearFLAG_CMPM(FURI_HAL_OS_TIMER);
} }
} }
static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
// Stop ticks // Stop ticks
furi_hal_os_timer_reset(); furi_hal_clock_suspend_tick();
LL_SYSTICK_DisableIT();
// Start wakeup timer // 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 #ifdef FURI_HAL_OS_DEBUG
LL_GPIO_ResetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN); 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 #endif
// Calculate how much time we spent in the sleep // 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_cnt = furi_hal_idle_timer_get_cnt() + furi_hal_os_skew;
uint32_t after_tick = after_cnt / FURI_HAL_OS_CLK_PER_TICK; uint32_t after_tick = FURI_HAL_OS_IDLE_CNT_TO_TICKS(after_cnt);
furi_hal_os_skew = after_cnt % FURI_HAL_OS_CLK_PER_TICK; furi_hal_os_skew = after_cnt - (after_cnt / after_tick);
bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER); bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_IDLE_TIMER);
bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER); bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_IDLE_TIMER);
if(cmpm && arrm) after_tick += expected_idle_ticks; if(cmpm && arrm) after_tick += expected_idle_ticks;
// Prepare tick timer for new round // Prepare tick timer for new round
furi_hal_os_timer_reset(); furi_hal_idle_timer_reset();
// Resume ticks // Resume ticks
LL_SYSTICK_EnableIT(); furi_hal_clock_resume_tick();
furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK);
return after_tick; return after_tick;
} }
@ -109,7 +101,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
return; 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) { if(expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) {
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 // Sleep and track how much ticks we spent sleeping
uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks); uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks);
// Notify system about time spent in sleep // Notify system about time spent in sleep
if(completed_ticks > 0) { if(completed_ticks > 0) {
if(completed_ticks > expected_idle_ticks) { vTaskStepTick(MIN(completed_ticks, expected_idle_ticks));
vTaskStepTick(expected_idle_ticks);
} else {
vTaskStepTick(completed_ticks);
}
} }
// Reenable IRQ // Reenable IRQ

View File

@ -11,6 +11,10 @@ extern "C" {
*/ */
void furi_hal_os_init(); void furi_hal_os_init();
/* Advance OS tick counter
*/
void furi_hal_os_tick();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

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

View File

@ -18,11 +18,6 @@ void furi_hal_delay_init();
/** Get instructions per microsecond count */ /** Get instructions per microsecond count */
uint32_t furi_hal_delay_instructions_per_microsecond(); 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 /** Get current tick counter
* *
* System uptime, may overflow. * System uptime, may overflow.