unleashed-firmware/targets/f7/furi_hal/furi_hal_interrupt.c
hedger 380ec2ac46
Added -Wundef to compiler options (#3815)
* fbt: added -Wundef to compiler options; libs: various small fixes for missing defines; desktop: proper access to current RTOS config
* apps: fixes for FURI_DEBUG handling
* rpc: unified definition checks
* Cleanup various defines use
* Cleanup configs and move SVCall ISR priority configuration to furi_hal_interrupts

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-08-01 01:38:20 +09:00

537 lines
13 KiB
C

#include <furi_hal_interrupt.h>
#include <furi_hal_os.h>
#include <furi.h>
#include <FreeRTOS.h>
#include <stm32wbxx.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_cortex.h>
#define TAG "FuriHalInterrupt"
#define FURI_HAL_INTERRUPT_DEFAULT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 5)
#ifdef FURI_RAM_EXEC
#define FURI_HAL_INTERRUPT_ACCOUNT_START()
#define FURI_HAL_INTERRUPT_ACCOUNT_END()
#else
#define FURI_HAL_INTERRUPT_ACCOUNT_START() const uint32_t _isr_start = DWT->CYCCNT;
#define FURI_HAL_INTERRUPT_ACCOUNT_END() \
const uint32_t _time_in_isr = DWT->CYCCNT - _isr_start; \
furi_hal_interrupt.counter_time_in_isr_total += _time_in_isr;
#endif
typedef struct {
FuriHalInterruptISR isr;
void* context;
} FuriHalInterruptISRPair;
typedef struct {
FuriHalInterruptISRPair isr[FuriHalInterruptIdMax];
uint32_t counter_time_in_isr_total;
} FuriHalIterrupt;
static FuriHalIterrupt furi_hal_interrupt = {};
const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
// TIM1, TIM16, TIM17
[FuriHalInterruptIdTim1TrgComTim17] = TIM1_TRG_COM_TIM17_IRQn,
[FuriHalInterruptIdTim1Cc] = TIM1_CC_IRQn,
[FuriHalInterruptIdTim1UpTim16] = TIM1_UP_TIM16_IRQn,
// TIM2
[FuriHalInterruptIdTIM2] = TIM2_IRQn,
// DMA1
[FuriHalInterruptIdDma1Ch1] = DMA1_Channel1_IRQn,
[FuriHalInterruptIdDma1Ch2] = DMA1_Channel2_IRQn,
[FuriHalInterruptIdDma1Ch3] = DMA1_Channel3_IRQn,
[FuriHalInterruptIdDma1Ch4] = DMA1_Channel4_IRQn,
[FuriHalInterruptIdDma1Ch5] = DMA1_Channel5_IRQn,
[FuriHalInterruptIdDma1Ch6] = DMA1_Channel6_IRQn,
[FuriHalInterruptIdDma1Ch7] = DMA1_Channel7_IRQn,
// DMA2
[FuriHalInterruptIdDma2Ch1] = DMA2_Channel1_IRQn,
[FuriHalInterruptIdDma2Ch2] = DMA2_Channel2_IRQn,
[FuriHalInterruptIdDma2Ch3] = DMA2_Channel3_IRQn,
[FuriHalInterruptIdDma2Ch4] = DMA2_Channel4_IRQn,
[FuriHalInterruptIdDma2Ch5] = DMA2_Channel5_IRQn,
[FuriHalInterruptIdDma2Ch6] = DMA2_Channel6_IRQn,
[FuriHalInterruptIdDma2Ch7] = DMA2_Channel7_IRQn,
// RCC
[FuriHalInterruptIdRcc] = RCC_IRQn,
// COMP
[FuriHalInterruptIdCOMP] = COMP_IRQn,
// HSEM
[FuriHalInterruptIdHsem] = HSEM_IRQn,
// LPTIMx
[FuriHalInterruptIdLpTim1] = LPTIM1_IRQn,
[FuriHalInterruptIdLpTim2] = LPTIM2_IRQn,
// UARTx
[FuriHalInterruptIdUart1] = USART1_IRQn,
// LPUARTx
[FuriHalInterruptIdLpUart1] = LPUART1_IRQn,
};
FURI_ALWAYS_INLINE static void furi_hal_interrupt_call(FuriHalInterruptId index) {
const FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
furi_check(isr_descr->isr);
FURI_HAL_INTERRUPT_ACCOUNT_START();
isr_descr->isr(isr_descr->context);
FURI_HAL_INTERRUPT_ACCOUNT_END();
}
FURI_ALWAYS_INLINE static void
furi_hal_interrupt_enable(FuriHalInterruptId index, uint16_t priority) {
NVIC_SetPriority(
furi_hal_interrupt_irqn[index],
NVIC_EncodePriority(NVIC_GetPriorityGrouping(), priority, 0));
NVIC_EnableIRQ(furi_hal_interrupt_irqn[index]);
}
FURI_ALWAYS_INLINE static void furi_hal_interrupt_clear_pending(FuriHalInterruptId index) {
NVIC_ClearPendingIRQ(furi_hal_interrupt_irqn[index]);
}
FURI_ALWAYS_INLINE static void furi_hal_interrupt_get_pending(FuriHalInterruptId index) {
NVIC_GetPendingIRQ(furi_hal_interrupt_irqn[index]);
}
FURI_ALWAYS_INLINE static void furi_hal_interrupt_set_pending(FuriHalInterruptId index) {
NVIC_SetPendingIRQ(furi_hal_interrupt_irqn[index]);
}
FURI_ALWAYS_INLINE static void furi_hal_interrupt_disable(FuriHalInterruptId index) {
NVIC_DisableIRQ(furi_hal_interrupt_irqn[index]);
}
void furi_hal_interrupt_init(void) {
NVIC_SetPriority(
TAMP_STAMP_LSECSS_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn);
NVIC_SetPriority(SVCall_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
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();
LL_HANDLER_EnableFault(LL_HANDLER_FAULT_USG);
LL_HANDLER_EnableFault(LL_HANDLER_FAULT_BUS);
LL_HANDLER_EnableFault(LL_HANDLER_FAULT_MEM);
FURI_LOG_I(TAG, "Init OK");
}
void furi_hal_interrupt_set_isr(FuriHalInterruptId index, FuriHalInterruptISR isr, void* context) {
furi_hal_interrupt_set_isr_ex(index, FuriHalInterruptPriorityNormal, isr, context);
}
void furi_hal_interrupt_set_isr_ex(
FuriHalInterruptId index,
FuriHalInterruptPriority priority,
FuriHalInterruptISR isr,
void* context) {
furi_check(index < FuriHalInterruptIdMax);
furi_check(
(priority >= FuriHalInterruptPriorityLowest &&
priority <= FuriHalInterruptPriorityHighest) ||
priority == FuriHalInterruptPriorityKamiSama);
uint16_t real_priority = FURI_HAL_INTERRUPT_DEFAULT_PRIORITY - priority;
FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
if(isr) {
// Pre ISR set
furi_check(isr_descr->isr == NULL);
} else {
// Pre ISR clear
furi_hal_interrupt_disable(index);
furi_hal_interrupt_clear_pending(index);
}
isr_descr->isr = isr;
isr_descr->context = context;
__DMB();
if(isr) {
// Post ISR set
furi_hal_interrupt_clear_pending(index);
furi_hal_interrupt_enable(index, real_priority);
} else {
// Post ISR clear
}
}
/* Timer 2 */
void TIM2_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdTIM2);
}
/* Timer 1 Update */
void TIM1_UP_TIM16_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdTim1UpTim16);
}
void TIM1_TRG_COM_TIM17_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdTim1TrgComTim17);
}
void TIM1_CC_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdTim1Cc);
}
/* DMA 1 */
void DMA1_Channel1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch1);
}
void DMA1_Channel2_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch2);
}
void DMA1_Channel3_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch3);
}
void DMA1_Channel4_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch4);
}
void DMA1_Channel5_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch5);
}
void DMA1_Channel6_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch6);
}
void DMA1_Channel7_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma1Ch7);
}
/* DMA 2 */
void DMA2_Channel1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch1);
}
void DMA2_Channel2_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch2);
}
void DMA2_Channel3_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch3);
}
void DMA2_Channel4_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch4);
}
void DMA2_Channel5_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch5);
}
void DMA2_Channel6_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch6);
}
void DMA2_Channel7_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdDma2Ch7);
}
void HSEM_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdHsem);
}
void TAMP_STAMP_LSECSS_IRQHandler(void) {
if(LL_RCC_IsActiveFlag_LSECSS()) {
LL_RCC_ClearFlag_LSECSS();
if(!LL_RCC_LSE_IsReady()) {
FURI_LOG_E(TAG, "LSE CSS fired: resetting system");
NVIC_SystemReset();
} else {
FURI_LOG_E(TAG, "LSE CSS fired: but LSE is alive");
}
}
}
void RCC_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdRcc);
}
void NMI_Handler(void) {
if(LL_RCC_IsActiveFlag_HSECSS()) {
LL_RCC_ClearFlag_HSECSS();
FURI_LOG_E(TAG, "HSE CSS fired: resetting system");
NVIC_SystemReset();
}
}
void HardFault_Handler(void) {
furi_crash("HardFault");
}
void MemManage_Handler(void) {
if(FURI_BIT(SCB->CFSR, SCB_CFSR_MMARVALID_Pos)) {
uint32_t memfault_address = SCB->MMFAR;
if(memfault_address < (1024 * 1024)) {
// from 0x00 to 1MB, see FuriHalMpuRegionNULL
furi_crash("NULL pointer dereference");
} else {
// write or read of MPU region 1 (FuriHalMpuRegionThreadStack)
furi_crash("MPU fault, possibly stack overflow");
}
} else if(FURI_BIT(SCB->CFSR, SCB_CFSR_MSTKERR_Pos)) {
// push to stack on MPU region 1 (FuriHalMpuRegionThreadStack)
furi_crash("MemManage fault, possibly stack overflow");
}
furi_crash("MemManage");
}
void BusFault_Handler(void) {
furi_crash("BusFault");
}
void UsageFault_Handler(void) {
furi_crash("UsageFault");
}
void DebugMon_Handler(void) {
}
#include "usbd_core.h"
extern usbd_device udev;
extern void HW_IPCC_Tx_Handler(void);
extern void HW_IPCC_Rx_Handler(void);
void SysTick_Handler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
furi_hal_os_tick();
FURI_HAL_INTERRUPT_ACCOUNT_END();
}
void USB_LP_IRQHandler(void) {
#ifndef FURI_RAM_EXEC
FURI_HAL_INTERRUPT_ACCOUNT_START();
usbd_poll(&udev);
FURI_HAL_INTERRUPT_ACCOUNT_END();
#endif
}
void USB_HP_IRQHandler(void) { //-V524
#ifndef FURI_RAM_EXEC
FURI_HAL_INTERRUPT_ACCOUNT_START();
usbd_poll(&udev);
FURI_HAL_INTERRUPT_ACCOUNT_END();
#endif
}
void IPCC_C1_TX_IRQHandler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
HW_IPCC_Tx_Handler();
FURI_HAL_INTERRUPT_ACCOUNT_END();
}
void IPCC_C1_RX_IRQHandler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
HW_IPCC_Rx_Handler();
FURI_HAL_INTERRUPT_ACCOUNT_END();
}
void FPU_IRQHandler(void) {
furi_crash("FpuFault");
}
void LPTIM1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdLpTim1);
}
void LPTIM2_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdLpTim2);
}
void USART1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdUart1);
}
void LPUART1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdLpUart1);
}
// Potential space-saver for updater build
const char* furi_hal_interrupt_get_name(uint8_t exception_number) {
int32_t id = (int32_t)exception_number - 16;
switch(id) {
case -14:
return "NMI";
case -13:
return "HardFault";
case -12:
return "MemMgmt";
case -11:
return "BusFault";
case -10:
return "UsageFault";
case -5:
return "SVC";
case -4:
return "DebugMon";
case -2:
return "PendSV";
case -1:
return "SysTick";
case 0:
return "WWDG";
case 1:
return "PVD_PVM";
case 2:
return "TAMP";
case 3:
return "RTC_WKUP";
case 4:
return "FLASH";
case 5:
return "RCC";
case 6:
return "EXTI0";
case 7:
return "EXTI1";
case 8:
return "EXTI2";
case 9:
return "EXTI3";
case 10:
return "EXTI4";
case 11:
return "DMA1_Ch1";
case 12:
return "DMA1_Ch2";
case 13:
return "DMA1_Ch3";
case 14:
return "DMA1_Ch4";
case 15:
return "DMA1_Ch5";
case 16:
return "DMA1_Ch6";
case 17:
return "DMA1_Ch7";
case 18:
return "ADC1";
case 19:
return "USB_HP";
case 20:
return "USB_LP";
case 21:
return "C2SEV_PWR_C2H";
case 22:
return "COMP";
case 23:
return "EXTI9_5";
case 24:
return "TIM1_BRK";
case 25:
return "TIM1_UP_TIM16";
case 26:
return "TIM1_TRG_COM_TIM17";
case 27:
return "TIM1_CC";
case 28:
return "TIM2";
case 29:
return "PKA";
case 30:
return "I2C1_EV";
case 31:
return "I2C1_ER";
case 32:
return "I2C3_EV";
case 33:
return "I2C3_ER";
case 34:
return "SPI1";
case 35:
return "SPI2";
case 36:
return "USART1";
case 37:
return "LPUART1";
case 38:
return "SAI1";
case 39:
return "TSC";
case 40:
return "EXTI15_10";
case 41:
return "RTC_Alarm";
case 42:
return "CRS";
case 43:
return "PWR_SOTF_BLE";
case 44:
return "IPCC_C1_RX";
case 45:
return "IPCC_C1_TX";
case 46:
return "HSEM";
case 47:
return "LPTIM1";
case 48:
return "LPTIM2";
case 49:
return "LCD";
case 50:
return "QUADSPI";
case 51:
return "AES1";
case 52:
return "AES2";
case 53:
return "RNG";
case 54:
return "FPU";
case 55:
return "DMA2_Ch1";
case 56:
return "DMA2_Ch2";
case 57:
return "DMA2_Ch3";
case 58:
return "DMA2_Ch4";
case 59:
return "DMA2_Ch5";
case 60:
return "DMA2_Ch6";
case 61:
return "DMA2_Ch7";
case 62:
return "DMAMUX1_OVR";
default:
return NULL;
}
}
uint32_t furi_hal_interrupt_get_time_in_isr_total(void) {
return furi_hal_interrupt.counter_time_in_isr_total;
}