// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "board/irq_gpio.hpp" #include "board.h" #include "FreeRTOS.h" #include #include #include #include #include #include "board/rt1051/bsp/eink/bsp_eink.h" #include #include #include "board/BoardDefinitions.hpp" namespace bsp { void irq_gpio_Init() { DisableIRQ(GPIO1_Combined_0_15_IRQn); DisableIRQ(GPIO1_Combined_16_31_IRQn); DisableIRQ(GPIO2_Combined_0_15_IRQn); DisableIRQ(GPIO2_Combined_16_31_IRQn); DisableIRQ(GPIO3_Combined_16_31_IRQn); DisableIRQ(GPIO5_Combined_0_15_IRQn); DisableIRQ(TMR3_IRQn); DisableIRQ(RTWDOG_IRQn); DisableIRQ(ANATOP_EVENT0_IRQn); GPIO_PortDisableInterrupts(GPIO1, UINT32_MAX); GPIO_PortDisableInterrupts(GPIO2, UINT32_MAX); GPIO_PortDisableInterrupts(GPIO3, UINT32_MAX); GPIO_PortDisableInterrupts(GPIO5, UINT32_MAX); // Clear all IRQs GPIO_PortClearInterruptFlags(GPIO1, UINT32_MAX); GPIO_PortClearInterruptFlags(GPIO2, UINT32_MAX); GPIO_PortClearInterruptFlags(GPIO3, UINT32_MAX); GPIO_PortClearInterruptFlags(GPIO5, UINT32_MAX); QTMR_ClearStatusFlags(TMR3, kQTMR_Channel_0, kQTMR_CompareFlag | kQTMR_Compare1Flag | kQTMR_Compare2Flag | kQTMR_OverflowFlag | kQTMR_EdgeFlag); EnableIRQ(GPIO1_Combined_0_15_IRQn); NVIC_SetPriority(GPIO1_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); EnableIRQ(GPIO1_Combined_16_31_IRQn); NVIC_SetPriority(GPIO1_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); EnableIRQ(GPIO2_Combined_0_15_IRQn); NVIC_SetPriority(GPIO2_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); EnableIRQ(GPIO2_Combined_16_31_IRQn); NVIC_SetPriority(GPIO2_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); EnableIRQ(GPIO3_Combined_16_31_IRQn); NVIC_SetPriority(GPIO3_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); NVIC_ClearPendingIRQ(GPIO5_Combined_0_15_IRQn); EnableIRQ(GPIO5_Combined_0_15_IRQn); GPC_EnableIRQ(GPC, GPIO5_Combined_0_15_IRQn); EnableIRQ(TMR3_IRQn); NVIC_SetPriority(TMR3_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); NVIC_ClearPendingIRQ(RTWDOG_IRQn); NVIC_EnableIRQ(RTWDOG_IRQn); // Enable PMU brownout interrupt NVIC_ClearPendingIRQ(ANATOP_EVENT0_IRQn); NVIC_EnableIRQ(ANATOP_EVENT0_IRQn); } extern "C" { void GPIO1_Combined_0_15_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO1); if (irq_mask & (1 << static_cast(BoardDefinitions::BELL_BATTERY_CHARGER_CHGOK_PIN))) { xHigherPriorityTaskWoken |= hal::battery::charger_irq(); } if (irq_mask & (1 << static_cast(BoardDefinitions::BELL_FUELGAUGE_ALRT_PIN))) { xHigherPriorityTaskWoken |= hal::battery::fuel_gauge_irq(); } // Clear all IRQs GPIO_PortClearInterruptFlags(GPIO1, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void GPIO1_Combined_16_31_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO1); // Clear all IRQs GPIO_PortClearInterruptFlags(GPIO1, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void GPIO2_Combined_0_15_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO2); // Clear all IRQs GPIO_PortClearInterruptFlags(GPIO2, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void GPIO2_Combined_16_31_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO2); if (irq_mask & ((1 << static_cast(BoardDefinitions::BELL_SWITCHES_RIGHT)) | (1 << static_cast(BoardDefinitions::BELL_SWITCHES_LEFT)) | (1 << static_cast(BoardDefinitions::BELL_SWITCHES_LATCH)))) { xHigherPriorityTaskWoken |= hal::key_input::GPIO2SwitchesIRQHandler(irq_mask); } if (irq_mask & (1 << static_cast(BoardDefinitions::BELL_BATTERY_CHARGER_ACOK_PIN))) { xHigherPriorityTaskWoken |= hal::battery::charger_irq(); } // Clear all IRQs GPIO_PortClearInterruptFlags(GPIO2, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void GPIO3_Combined_16_31_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO3); if (irq_mask & (1 << BOARD_EINK_BUSY_GPIO_PIN)) { xHigherPriorityTaskWoken |= BSP_EinkBusyPinStateChangeHandler(); } // Clear all IRQs on the GPIO3 port GPIO_PortClearInterruptFlags(BOARD_EINK_BUSY_GPIO, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void GPIO5_Combined_0_15_IRQHandler(void) { uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO5); BaseType_t xHigherPriorityTaskWoken = hal::key_input::GPIO5SwitchesIRQHandler( 1 << static_cast(BoardDefinitions::BELL_CENTER_SWITCH)); // Clear all IRQs on the GPIO5 port GPIO_PortClearInterruptFlags(GPIO5, irq_mask); // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void TMR3_IRQHandler(void) { QTMR_ClearStatusFlags(TMR3, kQTMR_Channel_0, kQTMR_CompareFlag | kQTMR_Compare1Flag | kQTMR_Compare2Flag | kQTMR_OverflowFlag | kQTMR_EdgeFlag); hal::key_input::EncoderIRQHandler(); } /* RTWDOG's timeout asserts IRQ, then 255 bus clocks after interrupt vector fetch * forces CPU reset (see RT1050 RM, p.3120). However, this forced reset only * affects the CPU, it won't reset any external ICs. To resolve this limitation, * WDOG_B pin, which controls board's main DCDC converter, is asserted in RTWDOG * IRQ handler. Converter will be momentarily switched off and the whole board will * be power reset. * * The simplest way to do it is to configure the pin as WDOG_B and use WDOG1 built-in * assertion. * * Before proceeding to exception handler, CPU pushes the following registers * to the active stack: * r0, offset 0 (in words), * r1 offset 1, * r2, offset 2, * r3, offset 3, * r12, offset 4, * r14 (LR), offset 5, * r15 (PC), offset 6, * xPSR, offset 7. * Get the value of last PC state and store in non-volatile SNVS register * to have any data that can be used to debug if program died in IRQ or * critical section and neither log nor crashdump was created. */ __attribute__((used, noreturn)) void RTWDOG_Handler(const uint32_t *sp) { RTWDOG_ClearStatusFlags(RTWDOG, kRTWDOG_InterruptFlag); const uint32_t pc = sp[6]; SNVS->LPGPR[1] = pc; WDOG1->WCR &= ~WDOG_WCR_WDA_MASK; while (true) {}; // Execution should never reach this point, but just in case } /* This has to be done as naked function to be able to easily extract last * PC value before RTWDOG handler was called without having to deal with * function prologue. */ __attribute__((naked)) void RTWDOG_IRQHandler(void) { __asm__ __volatile__("tst lr, #4\n" // Determine which stack was used "ite eq\n" "mrseq r0, msp\n" "mrsne r0, psp\n" "b RTWDOG_Handler\n" // Jump to real handler ); } // Enable PMU brownout interrupt void ANATOP_EVENT0_IRQHandler(void) { const uint32_t status = PMU_GetStatusFlags(PMU); /* If the PMU brownout detects too low voltage * immediately reset board's main DCDC converter * using the WDOG_B pin. This will reset the * whole board. */ if (status & kPMU_1P1BrownoutOnOutput) { WDOG1->WCR &= ~WDOG_WCR_WDA_MASK; } if (status & kPMU_2P5BrownoutOnOutput) { WDOG1->WCR &= ~WDOG_WCR_WDA_MASK; } NVIC_ClearPendingIRQ(ANATOP_EVENT0_IRQn); } } } // namespace bsp