mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 00:18:35 -07:00
[FL-2399, FL-2261] Tickless sleep shenanigans (#1168)
* Disable USART in sleep * Restore UART state on suspend/resume * FuriHal: Enable stop mode and add insomnia to I2C and SPI * Remove IDLE interrupt * FuriHal: add FPU isr and disable all FPU interrupt, add core2 stop mode configuration on deep sleep * FuriHal: tie stop mode debug with debug rtc flag * FuriHal: adjust flash latency on clock switch, tie mcu debug with RTC debug flag * FuriHal: move resource init to early stage * Add EXTI pending check, enable debug traps with compile-time flag * Wrap sleep debug functions in conditional compilation * Remove erroneous changed * Do not use CSS, remove it from everywhere * Enable/disable USB on VBUS connect (prototype) * FuriHal: add LPMS and DEEPSLEEP magic, workaround state inconsistency between cores * FuriHal: honor c1 LMPS * USB mode switch fix * Applications: add flags and insomnia bypass system * Correct spelling * FuriHal: cleanup insomnia usage, reset sleep flags on wakeup, add shutdown api * FuriHal: extra check on reinit request * FuriHal: rename gpio_display_rst pin to gpio_display_rst_n * FuriHal: add debug HAL * FuriHal: add some magic to core2 reload procedure, fix issue with crash on ble keyboard exit * FuriHal: cleanup ble glue, add BLE_GLUE_DEBUG flag * FuriHal: ble reinit API, move os timer to LPTIM1 for deep sleep capability, shutdown that works * FuriHal: take insomnia while shutdown * Remove USB switch on/off on VBUS change * Better tick skew handling * Improve tick consistency under load * Add USB_HP dummy IRQ handler * Move interrupt check closer to sleep * Clean up includes * Re-enable Insomnia globally * FuriHal: enable CSS * FuriHal: remove questionable core2 clock shenanigans * FuriHal: use core1 RCC registers in idle timer config * FuriHal: return back CSS handlers, add lptim isr dispatching Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: nminaylov <nm29719@gmail.com>
This commit is contained in:
@@ -10,10 +10,10 @@ 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_os_init();
|
||||
|
||||
furi_hal_spi_init_early();
|
||||
|
||||
furi_hal_i2c_init_early();
|
||||
|
||||
@@ -134,7 +134,6 @@ bool furi_hal_bt_start_radio_stack() {
|
||||
// Wait until C2 is started or timeout
|
||||
if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) {
|
||||
FURI_LOG_E(TAG, "Core2 start failed");
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
ble_glue_thread_stop();
|
||||
break;
|
||||
}
|
||||
@@ -154,7 +153,6 @@ bool furi_hal_bt_start_radio_stack() {
|
||||
// Starting radio stack
|
||||
if(!ble_glue_start()) {
|
||||
FURI_LOG_E(TAG, "Failed to start radio stack");
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
ble_glue_thread_stop();
|
||||
ble_app_thread_stop();
|
||||
break;
|
||||
@@ -221,27 +219,39 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, GapEventCallback event_cb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_bt_reinit() {
|
||||
FURI_LOG_I(TAG, "Disconnect and stop advertising");
|
||||
furi_hal_bt_stop_advertising();
|
||||
|
||||
FURI_LOG_I(TAG, "Stop current profile services");
|
||||
current_profile->stop();
|
||||
|
||||
// Magic happens here
|
||||
hci_reset();
|
||||
|
||||
FURI_LOG_I(TAG, "Stop BLE related RTOS threads");
|
||||
ble_app_thread_stop();
|
||||
gap_thread_stop();
|
||||
|
||||
FURI_LOG_I(TAG, "Reset SHCI");
|
||||
furi_check(ble_glue_reinit_c2());
|
||||
|
||||
osDelay(100);
|
||||
ble_glue_thread_stop();
|
||||
|
||||
FURI_LOG_I(TAG, "Start BT initialization");
|
||||
furi_hal_bt_init();
|
||||
|
||||
furi_hal_bt_start_radio_stack();
|
||||
}
|
||||
|
||||
bool furi_hal_bt_change_app(FuriHalBtProfile profile, GapEventCallback event_cb, void* context) {
|
||||
furi_assert(event_cb);
|
||||
furi_assert(profile < FuriHalBtProfileNumber);
|
||||
bool ret = true;
|
||||
|
||||
FURI_LOG_I(TAG, "Stop current profile services");
|
||||
current_profile->stop();
|
||||
FURI_LOG_I(TAG, "Disconnect and stop advertising");
|
||||
furi_hal_bt_stop_advertising();
|
||||
FURI_LOG_I(TAG, "Shutdow 2nd core");
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
FURI_LOG_I(TAG, "Stop BLE related RTOS threads");
|
||||
ble_app_thread_stop();
|
||||
gap_thread_stop();
|
||||
FURI_LOG_I(TAG, "Reset SHCI");
|
||||
ble_glue_reinit_c2();
|
||||
osDelay(100);
|
||||
ble_glue_thread_stop();
|
||||
FURI_LOG_I(TAG, "Start BT initialization");
|
||||
furi_hal_bt_init();
|
||||
furi_hal_bt_start_radio_stack();
|
||||
furi_hal_bt_reinit();
|
||||
|
||||
ret = furi_hal_bt_start_app(profile, event_cb, context);
|
||||
if(ret) {
|
||||
current_profile = &profile_config[profile];
|
||||
|
||||
@@ -204,6 +204,8 @@ void furi_hal_clock_switch_to_hsi() {
|
||||
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
|
||||
;
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
||||
}
|
||||
|
||||
void furi_hal_clock_switch_to_pll() {
|
||||
@@ -215,6 +217,8 @@ void furi_hal_clock_switch_to_pll() {
|
||||
while(!LL_RCC_PLL_IsReady())
|
||||
;
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
||||
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
|
||||
|
||||
|
||||
20
firmware/targets/f7/furi_hal/furi_hal_debug.c
Normal file
20
firmware/targets/f7/furi_hal/furi_hal_debug.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
#include <stm32wbxx_ll_exti.h>
|
||||
#include <stm32wbxx_ll_system.h>
|
||||
|
||||
void furi_hal_debug_enable() {
|
||||
// Low power mode debug
|
||||
LL_DBGMCU_EnableDBGSleepMode();
|
||||
LL_DBGMCU_EnableDBGStopMode();
|
||||
LL_DBGMCU_EnableDBGStandbyMode();
|
||||
LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48);
|
||||
}
|
||||
|
||||
void furi_hal_debug_disable() {
|
||||
// Low power mode debug
|
||||
LL_DBGMCU_DisableDBGSleepMode();
|
||||
LL_DBGMCU_DisableDBGStopMode();
|
||||
LL_DBGMCU_DisableDBGStandbyMode();
|
||||
LL_EXTI_DisableIT_32_63(LL_EXTI_LINE_48);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <furi_hal_i2c.h>
|
||||
#include <furi_hal_delay.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <furi_hal_power.h>
|
||||
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
@@ -23,6 +24,7 @@ void furi_hal_i2c_init() {
|
||||
}
|
||||
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
|
||||
furi_hal_power_insomnia_enter();
|
||||
// Lock bus access
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
|
||||
// Ensuree that no active handle set
|
||||
@@ -46,6 +48,7 @@ void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||
handle->bus->current_handle = NULL;
|
||||
// Unlock bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||
furi_hal_power_insomnia_exit();
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_tx(
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
|
||||
// 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
|
||||
#define FURI_HAL_IDLE_TIMER LPTIM1
|
||||
#define FURI_HAL_IDLE_TIMER_IRQ LPTIM1_IRQn
|
||||
|
||||
static inline void furi_hal_idle_timer_init() {
|
||||
// Configure clock source
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE);
|
||||
// There is a theoretical possibility that we need it
|
||||
LL_APB1_GRP1_EnableClockSleep(LL_APB1_GRP1_PERIPH_LPTIM1);
|
||||
// Set interrupt priority and enable them
|
||||
NVIC_SetPriority(
|
||||
FURI_HAL_IDLE_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
|
||||
@@ -54,6 +54,10 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
|
||||
|
||||
// HSEM
|
||||
[FuriHalInterruptIdHsem] = HSEM_IRQn,
|
||||
|
||||
// LPTIMx
|
||||
[FuriHalInterruptIdLpTim1] = LPTIM1_IRQn,
|
||||
[FuriHalInterruptIdLpTim2] = LPTIM2_IRQn,
|
||||
};
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
@@ -82,6 +86,16 @@ void furi_hal_interrupt_init() {
|
||||
|
||||
NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
|
||||
NVIC_SetPriority(FPU_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
NVIC_EnableIRQ(FPU_IRQn);
|
||||
|
||||
LL_SYSCFG_DisableIT_FPU_IOC();
|
||||
LL_SYSCFG_DisableIT_FPU_DZC();
|
||||
LL_SYSCFG_DisableIT_FPU_UFC();
|
||||
LL_SYSCFG_DisableIT_FPU_OFC();
|
||||
LL_SYSCFG_DisableIT_FPU_IDC();
|
||||
LL_SYSCFG_DisableIT_FPU_IXC();
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
@@ -120,82 +134,82 @@ void furi_hal_interrupt_set_isr_ex(
|
||||
}
|
||||
|
||||
/* Timer 2 */
|
||||
void TIM2_IRQHandler(void) {
|
||||
void TIM2_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdTIM2);
|
||||
}
|
||||
|
||||
/* Timer 1 Update */
|
||||
void TIM1_UP_TIM16_IRQHandler(void) {
|
||||
void TIM1_UP_TIM16_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdTim1UpTim16);
|
||||
}
|
||||
|
||||
void TIM1_TRG_COM_TIM17_IRQHandler(void) {
|
||||
void TIM1_TRG_COM_TIM17_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdTim1TrgComTim17);
|
||||
}
|
||||
|
||||
void TIM1_CC_IRQHandler(void) {
|
||||
void TIM1_CC_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdTim1Cc);
|
||||
}
|
||||
|
||||
/* DMA 1 */
|
||||
void DMA1_Channel1_IRQHandler(void) {
|
||||
void DMA1_Channel1_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch1);
|
||||
}
|
||||
|
||||
void DMA1_Channel2_IRQHandler(void) {
|
||||
void DMA1_Channel2_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch2);
|
||||
}
|
||||
|
||||
void DMA1_Channel3_IRQHandler(void) {
|
||||
void DMA1_Channel3_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch3);
|
||||
}
|
||||
|
||||
void DMA1_Channel4_IRQHandler(void) {
|
||||
void DMA1_Channel4_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch4);
|
||||
}
|
||||
|
||||
void DMA1_Channel5_IRQHandler(void) {
|
||||
void DMA1_Channel5_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch5);
|
||||
}
|
||||
|
||||
void DMA1_Channel6_IRQHandler(void) {
|
||||
void DMA1_Channel6_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch6);
|
||||
}
|
||||
|
||||
void DMA1_Channel7_IRQHandler(void) {
|
||||
void DMA1_Channel7_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch7);
|
||||
}
|
||||
|
||||
/* DMA 2 */
|
||||
void DMA2_Channel1_IRQHandler(void) {
|
||||
void DMA2_Channel1_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch1);
|
||||
}
|
||||
|
||||
void DMA2_Channel2_IRQHandler(void) {
|
||||
void DMA2_Channel2_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch2);
|
||||
}
|
||||
|
||||
void DMA2_Channel3_IRQHandler(void) {
|
||||
void DMA2_Channel3_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch3);
|
||||
}
|
||||
|
||||
void DMA2_Channel4_IRQHandler(void) {
|
||||
void DMA2_Channel4_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch4);
|
||||
}
|
||||
|
||||
void DMA2_Channel5_IRQHandler(void) {
|
||||
void DMA2_Channel5_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch5);
|
||||
}
|
||||
|
||||
void DMA2_Channel6_IRQHandler(void) {
|
||||
void DMA2_Channel6_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch6);
|
||||
}
|
||||
|
||||
void DMA2_Channel7_IRQHandler(void) {
|
||||
void DMA2_Channel7_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch7);
|
||||
}
|
||||
|
||||
void HSEM_IRQHandler(void) {
|
||||
void HSEM_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdHsem);
|
||||
}
|
||||
|
||||
@@ -211,11 +225,11 @@ void TAMP_STAMP_LSECSS_IRQHandler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void RCC_IRQHandler(void) {
|
||||
void RCC_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdRcc);
|
||||
}
|
||||
|
||||
void NMI_Handler(void) {
|
||||
void NMI_Handler() {
|
||||
if(LL_RCC_IsActiveFlag_HSECSS()) {
|
||||
LL_RCC_ClearFlag_HSECSS();
|
||||
FURI_LOG_E(TAG, "HSE CSS fired: resetting system");
|
||||
@@ -223,23 +237,23 @@ void NMI_Handler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void HardFault_Handler(void) {
|
||||
void HardFault_Handler() {
|
||||
furi_crash("HardFault");
|
||||
}
|
||||
|
||||
void MemManage_Handler(void) {
|
||||
void MemManage_Handler() {
|
||||
furi_crash("MemManage");
|
||||
}
|
||||
|
||||
void BusFault_Handler(void) {
|
||||
void BusFault_Handler() {
|
||||
furi_crash("BusFault");
|
||||
}
|
||||
|
||||
void UsageFault_Handler(void) {
|
||||
void UsageFault_Handler() {
|
||||
furi_crash("UsageFault");
|
||||
}
|
||||
|
||||
void DebugMon_Handler(void) {
|
||||
void DebugMon_Handler() {
|
||||
}
|
||||
|
||||
#include "usbd_core.h"
|
||||
@@ -249,20 +263,35 @@ extern usbd_device udev;
|
||||
extern void HW_IPCC_Tx_Handler();
|
||||
extern void HW_IPCC_Rx_Handler();
|
||||
|
||||
void SysTick_Handler(void) {
|
||||
void SysTick_Handler() {
|
||||
furi_hal_os_tick();
|
||||
}
|
||||
|
||||
void USB_LP_IRQHandler(void) {
|
||||
void USB_LP_IRQHandler() {
|
||||
#ifndef FURI_RAM_EXEC
|
||||
usbd_poll(&udev);
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPCC_C1_TX_IRQHandler(void) {
|
||||
void USB_HP_IRQHandler() {
|
||||
}
|
||||
|
||||
void IPCC_C1_TX_IRQHandler() {
|
||||
HW_IPCC_Tx_Handler();
|
||||
}
|
||||
|
||||
void IPCC_C1_RX_IRQHandler(void) {
|
||||
void IPCC_C1_RX_IRQHandler() {
|
||||
HW_IPCC_Rx_Handler();
|
||||
}
|
||||
|
||||
void FPU_IRQHandler() {
|
||||
furi_crash("FpuFault");
|
||||
}
|
||||
|
||||
void LPTIM1_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdLpTim1);
|
||||
}
|
||||
|
||||
void LPTIM2_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdLpTim2);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ typedef enum {
|
||||
// HSEM
|
||||
FuriHalInterruptIdHsem,
|
||||
|
||||
// LPTIMx
|
||||
FuriHalInterruptIdLpTim1,
|
||||
FuriHalInterruptIdLpTim2,
|
||||
|
||||
// Service value
|
||||
FuriHalInterruptIdMax,
|
||||
} FuriHalInterruptId;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include <furi_hal_os.h>
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_delay.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_idle_timer.h>
|
||||
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <furi.h>
|
||||
@@ -18,32 +20,32 @@
|
||||
#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)
|
||||
|
||||
#define FURI_HAL_OS_NVIC_IS_PENDING() (NVIC->ISPR[0] || NVIC->ISPR[1])
|
||||
#define FURI_HAL_OS_EXTI_LINE_0_31 0
|
||||
#define FURI_HAL_OS_EXTI_LINE_32_63 1
|
||||
|
||||
// Arbitrary (but small) number for better tick consistency
|
||||
#define FURI_HAL_OS_EXTRA_CNT 3
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
|
||||
#define LED_SLEEP_PORT GPIOA
|
||||
#define LED_SLEEP_PIN LL_GPIO_PIN_7
|
||||
#define LED_TICK_PORT GPIOA
|
||||
#define LED_TICK_PIN LL_GPIO_PIN_6
|
||||
#define LED_SECOND_PORT GPIOA
|
||||
#define LED_SECOND_PIN LL_GPIO_PIN_4
|
||||
|
||||
void furi_hal_os_timer_callback() {
|
||||
LL_GPIO_TogglePin(LED_SECOND_PORT, LED_SECOND_PIN);
|
||||
furi_hal_gpio_write(&gpio_ext_pa4, !furi_hal_gpio_read(&gpio_ext_pa4));
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void xPortSysTickHandler();
|
||||
|
||||
static volatile uint32_t furi_hal_os_skew = 0;
|
||||
static volatile uint32_t furi_hal_os_skew;
|
||||
|
||||
void furi_hal_os_init() {
|
||||
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);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
|
||||
osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
|
||||
osTimerStart(second_timer, FURI_HAL_OS_TICK_HZ);
|
||||
#endif
|
||||
@@ -54,12 +56,61 @@ void furi_hal_os_init() {
|
||||
void furi_hal_os_tick() {
|
||||
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN);
|
||||
furi_hal_gpio_write(&gpio_ext_pa6, !furi_hal_gpio_read(&gpio_ext_pa6));
|
||||
#endif
|
||||
xPortSysTickHandler();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
// Find out the IRQ number while debugging
|
||||
static void furi_hal_os_nvic_dbg_trap() {
|
||||
for(int32_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) {
|
||||
if(NVIC_GetPendingIRQ(i)) {
|
||||
(void)i;
|
||||
// Break here
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find out the EXTI line number while debugging
|
||||
static void furi_hal_os_exti_dbg_trap(uint32_t exti, uint32_t val) {
|
||||
for(uint32_t i = 0; val; val >>= 1U, ++i) {
|
||||
if(val & 1U) {
|
||||
(void)exti;
|
||||
(void)i;
|
||||
// Break here
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool furi_hal_os_is_pending_irq() {
|
||||
if(FURI_HAL_OS_NVIC_IS_PENDING()) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_os_nvic_dbg_trap();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t exti_lines_active;
|
||||
if((exti_lines_active = LL_EXTI_ReadFlag_0_31(LL_EXTI_LINE_ALL_0_31))) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_os_exti_dbg_trap(FURI_HAL_OS_EXTI_LINE_0_31, exti_lines_active);
|
||||
#endif
|
||||
return true;
|
||||
} else if((exti_lines_active = LL_EXTI_ReadFlag_32_63(LL_EXTI_LINE_ALL_32_63))) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_os_exti_dbg_trap(FURI_HAL_OS_EXTI_LINE_32_63, exti_lines_active);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
// Stop ticks
|
||||
furi_hal_clock_suspend_tick();
|
||||
@@ -68,20 +119,20 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
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);
|
||||
furi_hal_gpio_write(&gpio_ext_pa7, 0);
|
||||
#endif
|
||||
|
||||
// Go to sleep mode
|
||||
furi_hal_power_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
LL_GPIO_SetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN);
|
||||
furi_hal_gpio_write(&gpio_ext_pa7, 1);
|
||||
#endif
|
||||
|
||||
// Calculate how much time we spent in the sleep
|
||||
uint32_t after_cnt = furi_hal_idle_timer_get_cnt() + furi_hal_os_skew;
|
||||
uint32_t after_cnt = furi_hal_idle_timer_get_cnt() + furi_hal_os_skew + FURI_HAL_OS_EXTRA_CNT;
|
||||
uint32_t after_tick = FURI_HAL_OS_IDLE_CNT_TO_TICKS(after_cnt);
|
||||
furi_hal_os_skew = after_cnt - (after_cnt / after_tick);
|
||||
furi_hal_os_skew = after_cnt - FURI_HAL_OS_TICKS_TO_IDLE_CNT(after_tick);
|
||||
|
||||
bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_IDLE_TIMER);
|
||||
bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_IDLE_TIMER);
|
||||
@@ -110,7 +161,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
__disable_irq();
|
||||
|
||||
// Confirm OS that sleep is still possible
|
||||
if(eTaskConfirmSleepModeStatus() == eAbortSleep) {
|
||||
if(eTaskConfirmSleepModeStatus() == eAbortSleep || furi_hal_os_is_pending_irq()) {
|
||||
__enable_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_bt.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_uart.h>
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
@@ -17,6 +18,12 @@
|
||||
|
||||
#define TAG "FuriHalPower"
|
||||
|
||||
#ifdef FURI_HAL_POWER_DEEP_SLEEP_ENABLED
|
||||
#define FURI_HAL_POWER_DEEP_INSOMNIA 0
|
||||
#else
|
||||
#define FURI_HAL_POWER_DEEP_INSOMNIA 1
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
volatile uint8_t insomnia;
|
||||
volatile uint8_t deep_insomnia;
|
||||
@@ -28,7 +35,7 @@ typedef struct {
|
||||
|
||||
static volatile FuriHalPower furi_hal_power = {
|
||||
.insomnia = 0,
|
||||
.deep_insomnia = 1,
|
||||
.deep_insomnia = FURI_HAL_POWER_DEEP_INSOMNIA,
|
||||
.suppress_charge = 0,
|
||||
};
|
||||
|
||||
@@ -70,11 +77,6 @@ const ParamCEDV cedv = {
|
||||
.DOD100 = 3299,
|
||||
};
|
||||
|
||||
void HAL_RCC_CSSCallback(void) {
|
||||
// TODO: notify user about issue with HSE
|
||||
furi_hal_power_reset();
|
||||
}
|
||||
|
||||
void furi_hal_power_init() {
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||
@@ -84,6 +86,11 @@ void furi_hal_power_init() {
|
||||
bq25896_init(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pb2, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull);
|
||||
#endif
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
@@ -140,12 +147,28 @@ void furi_hal_power_light_sleep() {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
static inline void furi_hal_power_suspend_aux_periphs() {
|
||||
// Disable USART
|
||||
furi_hal_uart_suspend(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_suspend(FuriHalUartIdLPUART1);
|
||||
// TODO: Disable USB
|
||||
}
|
||||
|
||||
static inline void furi_hal_power_resume_aux_periphs() {
|
||||
// Re-enable USART
|
||||
furi_hal_uart_resume(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_resume(FuriHalUartIdLPUART1);
|
||||
// TODO: Re-enable USB
|
||||
}
|
||||
|
||||
void furi_hal_power_deep_sleep() {
|
||||
furi_hal_power_suspend_aux_periphs();
|
||||
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID))
|
||||
;
|
||||
|
||||
if(!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) {
|
||||
if(LL_PWR_IsActiveFlag_C2DS()) {
|
||||
if(LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB()) {
|
||||
// Release ENTRY_STOP_MODE semaphore
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
|
||||
|
||||
@@ -163,7 +186,8 @@ void furi_hal_power_deep_sleep() {
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
// Prepare deep sleep
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
LL_LPM_EnableDeepSleep();
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
@@ -173,6 +197,15 @@ void furi_hal_power_deep_sleep() {
|
||||
|
||||
__WFI();
|
||||
|
||||
LL_LPM_EnableSleep();
|
||||
|
||||
// Make sure that values differ to prevent disaster on wfi
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
|
||||
LL_PWR_ClearFlag_C1STOP_C1STB();
|
||||
LL_PWR_ClearFlag_C2STOP_C2STB();
|
||||
|
||||
/* Release ENTRY_STOP_MODE semaphore */
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
|
||||
|
||||
@@ -184,13 +217,31 @@ void furi_hal_power_deep_sleep() {
|
||||
}
|
||||
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
furi_hal_power_resume_aux_periphs();
|
||||
}
|
||||
|
||||
void furi_hal_power_sleep() {
|
||||
if(furi_hal_power_deep_sleep_available()) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pc3, 1);
|
||||
#endif
|
||||
|
||||
furi_hal_power_deep_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pc3, 0);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pb2, 1);
|
||||
#endif
|
||||
|
||||
furi_hal_power_light_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pb2, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +266,38 @@ bool furi_hal_power_is_charging() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_shutdown() {
|
||||
furi_hal_power_insomnia_enter();
|
||||
|
||||
furi_hal_bt_reinit();
|
||||
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID))
|
||||
;
|
||||
|
||||
if(!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) {
|
||||
if(LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB()) {
|
||||
// Release ENTRY_STOP_MODE semaphore
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare Wakeup pin
|
||||
LL_PWR_SetWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2);
|
||||
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
|
||||
LL_C2_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
|
||||
|
||||
/* Release RCC semaphore */
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
LL_PWR_DisableBootC2();
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
LL_LPM_EnableDeepSleep();
|
||||
|
||||
__WFI();
|
||||
furi_crash("Insomniac core2");
|
||||
}
|
||||
|
||||
void furi_hal_power_off() {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_poweroff(&furi_hal_i2c_handle_power);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi.h>
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
|
||||
const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
|
||||
@@ -9,7 +12,7 @@ const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin};
|
||||
|
||||
const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin};
|
||||
const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin};
|
||||
const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin};
|
||||
const GpioPin gpio_display_rst_n = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin};
|
||||
const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin};
|
||||
const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin};
|
||||
const GpioPin gpio_sdcard_cd = {.port = SD_CD_GPIO_Port, .pin = SD_CD_Pin};
|
||||
@@ -72,14 +75,32 @@ const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin);
|
||||
|
||||
void furi_hal_resources_init_early() {
|
||||
furi_hal_gpio_init(&gpio_button_left, GpioModeInput, GpioPullUp, GpioSpeedLow);
|
||||
furi_hal_gpio_init_simple(&gpio_display_rst, GpioModeOutputPushPull);
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 1);
|
||||
furi_hal_gpio_init_simple(&gpio_display_rst_n, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull);
|
||||
|
||||
// Alternative pull configuration for shutdown
|
||||
SET_BIT(PWR->PUCRB, DISPLAY_RST_Pin);
|
||||
CLEAR_BIT(PWR->PDCRB, DISPLAY_RST_Pin);
|
||||
SET_BIT(PWR->CR3, PWR_CR3_APC);
|
||||
|
||||
// Hard reset USB
|
||||
furi_hal_gpio_init_simple(&gpio_usb_dm, GpioModeOutputOpenDrain);
|
||||
furi_hal_gpio_init_simple(&gpio_usb_dp, GpioModeOutputOpenDrain);
|
||||
furi_hal_gpio_write(&gpio_usb_dm, 0);
|
||||
furi_hal_gpio_write(&gpio_usb_dp, 0);
|
||||
|
||||
// External header pins
|
||||
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa6, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_resources_deinit_early() {
|
||||
@@ -92,19 +113,9 @@ void furi_hal_resources_init() {
|
||||
input_pins[i].gpio, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedLow);
|
||||
}
|
||||
|
||||
// External header pins
|
||||
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa6, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_init(&gpio_display_rst, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_display_rst, 0);
|
||||
furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 0);
|
||||
|
||||
furi_hal_gpio_init(&gpio_display_di, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_display_di, 0);
|
||||
|
||||
@@ -48,7 +48,7 @@ extern const GpioPin gpio_rf_sw_0;
|
||||
|
||||
extern const GpioPin gpio_subghz_cs;
|
||||
extern const GpioPin gpio_display_cs;
|
||||
extern const GpioPin gpio_display_rst;
|
||||
extern const GpioPin gpio_display_rst_n;
|
||||
extern const GpioPin gpio_display_di;
|
||||
extern const GpioPin gpio_sdcard_cs;
|
||||
extern const GpioPin gpio_sdcard_cd;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_light.h>
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
@@ -36,7 +37,6 @@ void furi_hal_rtc_init_early() {
|
||||
// LSE and RTC
|
||||
LL_PWR_EnableBkUpAccess();
|
||||
if(!RTC_CLOCK_IS_READY()) {
|
||||
// Start LSI1 needed for CSS
|
||||
LL_RCC_LSI1_Enable();
|
||||
// Try to start LSE normal way
|
||||
LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH);
|
||||
@@ -55,8 +55,6 @@ void furi_hal_rtc_init_early() {
|
||||
}
|
||||
// Set RTC domain clock to LSE
|
||||
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
|
||||
// Enable LSE CSS
|
||||
LL_RCC_LSE_EnableCSS();
|
||||
}
|
||||
// Enable clocking
|
||||
LL_RCC_EnableRTC();
|
||||
@@ -74,6 +72,12 @@ void furi_hal_rtc_init_early() {
|
||||
data->version = FURI_HAL_RTC_HEADER_VERSION;
|
||||
furi_hal_rtc_set_register(FuriHalRtcRegisterHeader, data_reg);
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
furi_hal_debug_enable();
|
||||
} else {
|
||||
furi_hal_debug_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_rtc_deinit_early() {
|
||||
@@ -126,6 +130,10 @@ void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
|
||||
DeveloperReg* data = (DeveloperReg*)&data_reg;
|
||||
data->flags |= flag;
|
||||
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
|
||||
|
||||
if(flag & FuriHalRtcFlagDebug) {
|
||||
furi_hal_debug_enable();
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
|
||||
@@ -133,6 +141,10 @@ void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
|
||||
DeveloperReg* data = (DeveloperReg*)&data_reg;
|
||||
data->flags &= ~flag;
|
||||
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
|
||||
|
||||
if(flag & FuriHalRtcFlagDebug) {
|
||||
furi_hal_debug_disable();
|
||||
}
|
||||
}
|
||||
|
||||
bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "furi_hal_spi.h"
|
||||
#include "furi_hal_resources.h"
|
||||
#include <furi_hal_power.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -55,6 +56,8 @@ void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
|
||||
void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
|
||||
furi_assert(handle);
|
||||
|
||||
furi_hal_power_insomnia_enter();
|
||||
|
||||
handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
|
||||
handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
|
||||
|
||||
@@ -75,6 +78,8 @@ void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
|
||||
// Bus events
|
||||
handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
|
||||
handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
|
||||
|
||||
furi_hal_power_insomnia_exit();
|
||||
}
|
||||
|
||||
static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal_delay.h>
|
||||
|
||||
static bool furi_hal_usart_prev_enabled[2];
|
||||
|
||||
static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context);
|
||||
static void* irq_ctx[2];
|
||||
|
||||
@@ -44,7 +46,6 @@ static void furi_hal_usart_init(uint32_t baud) {
|
||||
;
|
||||
|
||||
LL_USART_EnableIT_RXNE_RXFNE(USART1);
|
||||
LL_USART_EnableIT_IDLE(USART1);
|
||||
NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
}
|
||||
|
||||
@@ -81,7 +82,6 @@ static void furi_hal_lpuart_init(uint32_t baud) {
|
||||
furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud);
|
||||
|
||||
LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
|
||||
LL_LPUART_EnableIT_IDLE(LPUART1);
|
||||
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
}
|
||||
|
||||
@@ -136,6 +136,28 @@ void furi_hal_uart_deinit(FuriHalUartId ch) {
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_suspend(FuriHalUartId channel) {
|
||||
if(channel == FuriHalUartIdLPUART1 && LL_LPUART_IsEnabled(LPUART1)) {
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
furi_hal_usart_prev_enabled[channel] = true;
|
||||
} else if(channel == FuriHalUartIdUSART1 && LL_USART_IsEnabled(USART1)) {
|
||||
LL_USART_Disable(USART1);
|
||||
furi_hal_usart_prev_enabled[channel] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_resume(FuriHalUartId channel) {
|
||||
if(!furi_hal_usart_prev_enabled[channel]) {
|
||||
return;
|
||||
} else if(channel == FuriHalUartIdLPUART1) {
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
} else if(channel == FuriHalUartIdUSART1) {
|
||||
LL_USART_Enable(USART1);
|
||||
}
|
||||
|
||||
furi_hal_usart_prev_enabled[channel] = false;
|
||||
}
|
||||
|
||||
void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) {
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
if(LL_USART_IsEnabled(USART1) == 0) return;
|
||||
@@ -189,22 +211,15 @@ void LPUART1_IRQHandler(void) {
|
||||
if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
|
||||
uint8_t data = LL_LPUART_ReceiveData8(LPUART1);
|
||||
irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]);
|
||||
} else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) {
|
||||
irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdLPUART1]);
|
||||
LL_LPUART_ClearFlag_IDLE(LPUART1);
|
||||
} else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) {
|
||||
LL_LPUART_ClearFlag_ORE(LPUART1);
|
||||
}
|
||||
//TODO: more events
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void) {
|
||||
if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) {
|
||||
uint8_t data = LL_USART_ReceiveData8(USART1);
|
||||
irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]);
|
||||
} else if(LL_USART_IsActiveFlag_IDLE(USART1)) {
|
||||
irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdUSART1]);
|
||||
LL_USART_ClearFlag_IDLE(USART1);
|
||||
} else if(LL_USART_IsActiveFlag_ORE(USART1)) {
|
||||
LL_USART_ClearFlag_ORE(USART1);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
UartIrqEventRXNE,
|
||||
UartIrqEventIDLE,
|
||||
//TODO: more events
|
||||
} UartIrqEvent;
|
||||
|
||||
/**
|
||||
@@ -46,6 +44,20 @@ void furi_hal_uart_init(FuriHalUartId channel, uint32_t baud);
|
||||
*/
|
||||
void furi_hal_uart_deinit(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Suspend UART operation
|
||||
* Disables UART hardware, settings and callbacks are preserved
|
||||
* @param channel UART channel
|
||||
*/
|
||||
void furi_hal_uart_suspend(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Resume UART operation
|
||||
* Resumes UART hardware from suspended state
|
||||
* @param channel UART channel
|
||||
*/
|
||||
void furi_hal_uart_resume(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Changes UART baudrate
|
||||
* @param channel UART channel
|
||||
@@ -74,4 +86,4 @@ void furi_hal_uart_set_irq_cb(
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -76,7 +76,9 @@ void furi_hal_usb_init(void) {
|
||||
usb.enabled = false;
|
||||
usb.if_cur = NULL;
|
||||
NVIC_SetPriority(USB_LP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
NVIC_SetPriority(USB_HP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
NVIC_EnableIRQ(USB_HP_IRQn);
|
||||
|
||||
usb.thread = furi_thread_alloc();
|
||||
furi_thread_set_name(usb.thread, "UsbDriver");
|
||||
|
||||
Reference in New Issue
Block a user