[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_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)
|
||||||
|
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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) {
|
||||||
|
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_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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
/** 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.
|
||||||
|
Loading…
Reference in New Issue
Block a user