summaryrefslogtreecommitdiff
path: root/interrupt
diff options
context:
space:
mode:
Diffstat (limited to 'interrupt')
-rw-r--r--interrupt/fault.cpp41
-rw-r--r--interrupt/interrupt.cpp187
-rw-r--r--interrupt/interrupt.h151
3 files changed, 379 insertions, 0 deletions
diff --git a/interrupt/fault.cpp b/interrupt/fault.cpp
new file mode 100644
index 0000000..016b74b
--- /dev/null
+++ b/interrupt/fault.cpp
@@ -0,0 +1,41 @@
+#include "interrupt.h"
+#include <os/thread.h>
+#include <os/time.h>
+
+inline void __attribute__((naked)) switch_context() {
+ asm volatile ("cpsid i");
+
+ // Save unsaved registers.
+ asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" ::: "memory");
+
+ // Store stack pointer for old thread.
+ asm volatile ("str sp, [%0]" :: "r" (&Thread::active_thread->sp));
+
+ // Update running thread.
+ Thread::active_thread = Thread::active_thread->next;
+
+ // Fetch stack pointer for new thread.
+ asm volatile ("ldr sp, [%0]" :: "r" (&Thread::active_thread->sp));
+
+ asm volatile ("cpsie i");
+
+ // Load registers and return.
+ asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" ::: "memory");
+}
+
+template<>
+void interrupt<Interrupt::SVCall>() {
+ switch_context();
+}
+
+template<>
+void interrupt<Interrupt::SysTick>() {
+ Time::tick();
+}
+
+template<> void interrupt<Interrupt::NMI>() { while(1); }
+template<> void interrupt<Interrupt::HardFault>() { while(1); }
+template<> void interrupt<Interrupt::MemManage>() { while(1); }
+template<> void interrupt<Interrupt::BusFault>() { while(1); }
+template<> void interrupt<Interrupt::UsageFault>() { while(1); }
+template<> void interrupt<Interrupt::PendSV>() { while(1); }
diff --git a/interrupt/interrupt.cpp b/interrupt/interrupt.cpp
new file mode 100644
index 0000000..cebfed7
--- /dev/null
+++ b/interrupt/interrupt.cpp
@@ -0,0 +1,187 @@
+#include "interrupt.h"
+
+namespace Interrupt {
+ MFP mf_vectors[16 + NUM_IRQs];
+};
+
+void entry();
+
+void member_function_interrupt_gate() {
+ uint32_t interrupt_num;
+ asm ("mrs %0, ipsr" : "=r" (interrupt_num));
+
+ Interrupt::mf_vectors[interrupt_num].func_p(Interrupt::mf_vectors[interrupt_num].instance_p);
+}
+
+extern "C" void unused_interrupt() {
+ member_function_interrupt_gate();
+ //while(1);
+}
+
+template<> void interrupt<Interrupt::NMI>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::HardFault>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::MemManage>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::BusFault>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::UsageFault>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SVCall>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::PendSV>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SysTick>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::WWDG>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::PVD>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TAMPER>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::RTC>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::FLASH>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::RCC>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI0>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI4>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel4>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel5>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel6>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA1_Channel7>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::ADC1_2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USB_HP_CAN_TX>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USB_LP_CAN_RX0>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::CAN_RX1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::CAN_SCE>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI9_5>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM1_BRK>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM1_UP>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM1_TRG_COM>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM1_CC>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM4>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::I2C1_EV>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::I2C1_ER>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::I2C2_EV>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::I2C2_ER>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SPI1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SPI2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USART1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USART2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USART3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::EXTI15_10>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::RTCAlarm>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::USBWakeup>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM8_BRK>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM8_UP>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM8_TRG_COM>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM8_CC>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::ADC3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::FSMC>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SDIO>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM5>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::SPI3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::UART4>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::UART5>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM6>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::TIM7>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA2_Channel1>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA2_Channel2>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA2_Channel3>() __attribute__ ((weak, alias ("unused_interrupt")));
+template<> void interrupt<Interrupt::DMA2_Channel4_5>() __attribute__ ((weak, alias ("unused_interrupt")));
+
+typedef void (*vector_t)();
+
+vector_t vectors[] __attribute__((section(".vectors"))) = {
+ (vector_t)0x20004ffc,
+ entry,
+ interrupt<Interrupt::NMI>,
+ interrupt<Interrupt::HardFault>,
+ interrupt<Interrupt::MemManage>,
+ interrupt<Interrupt::BusFault>,
+ interrupt<Interrupt::UsageFault>,
+ 0,
+ 0,
+ 0,
+ 0,
+ interrupt<Interrupt::SVCall>,
+ 0,
+ 0,
+ interrupt<Interrupt::PendSV>,
+ interrupt<Interrupt::SysTick>,
+ interrupt<Interrupt::WWDG>,
+ interrupt<Interrupt::PVD>,
+ interrupt<Interrupt::TAMPER>,
+ interrupt<Interrupt::RTC>,
+ interrupt<Interrupt::FLASH>,
+ interrupt<Interrupt::RCC>,
+ interrupt<Interrupt::EXTI0>,
+ interrupt<Interrupt::EXTI1>,
+ interrupt<Interrupt::EXTI2>,
+ interrupt<Interrupt::EXTI3>,
+ interrupt<Interrupt::EXTI4>,
+ interrupt<Interrupt::DMA1_Channel1>,
+ interrupt<Interrupt::DMA1_Channel2>,
+ interrupt<Interrupt::DMA1_Channel3>,
+ interrupt<Interrupt::DMA1_Channel4>,
+ interrupt<Interrupt::DMA1_Channel5>,
+ interrupt<Interrupt::DMA1_Channel6>,
+ interrupt<Interrupt::DMA1_Channel7>,
+ interrupt<Interrupt::ADC1_2>,
+ interrupt<Interrupt::USB_HP_CAN_TX>,
+ interrupt<Interrupt::USB_LP_CAN_RX0>,
+ interrupt<Interrupt::CAN_RX1>,
+ interrupt<Interrupt::CAN_SCE>,
+ interrupt<Interrupt::EXTI9_5>,
+ interrupt<Interrupt::TIM1_BRK>,
+ interrupt<Interrupt::TIM1_UP>,
+ interrupt<Interrupt::TIM1_TRG_COM>,
+ interrupt<Interrupt::TIM1_CC>,
+ interrupt<Interrupt::TIM2>,
+ interrupt<Interrupt::TIM3>,
+ interrupt<Interrupt::TIM4>,
+ interrupt<Interrupt::I2C1_EV>,
+ interrupt<Interrupt::I2C1_ER>,
+ interrupt<Interrupt::I2C2_EV>,
+ interrupt<Interrupt::I2C2_ER>,
+ interrupt<Interrupt::SPI1>,
+ interrupt<Interrupt::SPI2>,
+ interrupt<Interrupt::USART1>,
+ interrupt<Interrupt::USART2>,
+ interrupt<Interrupt::USART3>,
+ interrupt<Interrupt::EXTI15_10>,
+ interrupt<Interrupt::RTCAlarm>,
+ interrupt<Interrupt::USBWakeup>,
+ interrupt<Interrupt::TIM8_BRK>,
+ interrupt<Interrupt::TIM8_UP>,
+ interrupt<Interrupt::TIM8_TRG_COM>,
+ interrupt<Interrupt::TIM8_CC>,
+ interrupt<Interrupt::ADC3>,
+ interrupt<Interrupt::FSMC>,
+ interrupt<Interrupt::SDIO>,
+ interrupt<Interrupt::TIM5>,
+ interrupt<Interrupt::SPI3>,
+ interrupt<Interrupt::UART4>,
+ interrupt<Interrupt::UART5>,
+ interrupt<Interrupt::TIM6>,
+ interrupt<Interrupt::TIM7>,
+ interrupt<Interrupt::DMA2_Channel1>,
+ interrupt<Interrupt::DMA2_Channel2>,
+ interrupt<Interrupt::DMA2_Channel3>,
+ interrupt<Interrupt::DMA2_Channel4_5>,
+ 0, // 60
+ 0, // 61
+ 0, // 62
+ 0, // 63
+ 0, // 64
+ 0, // 65
+ 0, // 66
+ 0, // 67
+ 0, // 68
+ 0, // 69
+ 0, // 70
+ 0, // 71
+ 0, // 72
+ 0, // 73
+ 0, // 74
+ 0, // 75
+ 0, // 76
+ interrupt<(Interrupt::IRQ)77>, // 77
+};
diff --git a/interrupt/interrupt.h b/interrupt/interrupt.h
new file mode 100644
index 0000000..80ccb76
--- /dev/null
+++ b/interrupt/interrupt.h
@@ -0,0 +1,151 @@
+#ifndef INTERRUPT_H
+#define INTERRUPT_H
+
+#include <stdint.h>
+
+struct NVIC_t {
+ volatile uint32_t ISER[32];
+ volatile uint32_t ICER[32];
+ volatile uint32_t ISPR[32];
+ volatile uint32_t ICPR[32];
+ volatile uint32_t IABR[64];
+ volatile uint8_t IPR[2816];
+ volatile uint32_t STIR;
+};
+
+static NVIC_t& NVIC = *(NVIC_t*)0xe000e100;
+
+struct SCB_t {
+ volatile uint32_t CPUID;
+ volatile uint32_t ICSR;
+ volatile uint32_t VTOR;
+ volatile uint32_t AIRCR;
+ volatile uint32_t SCR;
+ volatile uint32_t CCR;
+ volatile uint8_t SHPR[12];
+ volatile uint32_t SHCSR;
+ volatile uint32_t CFSR;
+ volatile uint32_t HFSR;
+ volatile uint32_t DFSR;
+ volatile uint32_t MMAR;
+ volatile uint32_t BFAR;
+};
+
+static SCB_t& SCB = *(SCB_t*)0xe000ed00;
+
+namespace Interrupt {
+ enum Exception {
+ NMI = 2,
+ HardFault = 3,
+ MemManage = 4,
+ BusFault = 5,
+ UsageFault = 6,
+ SVCall = 11,
+ PendSV = 14,
+ SysTick = 15
+ };
+
+ enum IRQ {
+ WWDG,
+ PVD,
+ TAMPER,
+ RTC,
+ FLASH,
+ RCC,
+ EXTI0,
+ EXTI1,
+ EXTI2,
+ EXTI3,
+ EXTI4,
+ DMA1_Channel1,
+ DMA1_Channel2,
+ DMA1_Channel3,
+ DMA1_Channel4,
+ DMA1_Channel5,
+ DMA1_Channel6,
+ DMA1_Channel7,
+ ADC1_2,
+ USB_HP_CAN_TX,
+ USB_LP_CAN_RX0,
+ CAN_RX1,
+ CAN_SCE,
+ EXTI9_5,
+ TIM1_BRK,
+ TIM1_UP,
+ TIM1_TRG_COM,
+ TIM1_CC,
+ TIM2,
+ TIM3,
+ TIM4,
+ I2C1_EV,
+ I2C1_ER,
+ I2C2_EV,
+ I2C2_ER,
+ SPI1,
+ SPI2,
+ USART1,
+ USART2,
+ USART3,
+ EXTI15_10,
+ RTCAlarm,
+ USBWakeup,
+ TIM8_BRK,
+ TIM8_UP,
+ TIM8_TRG_COM,
+ TIM8_CC,
+ ADC3,
+ FSMC,
+ SDIO,
+ TIM5,
+ SPI3,
+ UART4,
+ UART5,
+ TIM6,
+ TIM7,
+ DMA2_Channel1,
+ DMA2_Channel2,
+ DMA2_Channel3,
+ DMA2_Channel4_5,
+ NUM_IRQs
+ };
+
+ inline void enable(IRQ n) {
+ NVIC.ISER[n >> 5] = 1 << (n & 0x1f);
+ }
+
+ inline void set_priority(Exception n, uint8_t priority) {
+ SCB.SHPR[n - 4] = priority;
+ }
+
+ inline void set_priority(IRQ n, uint8_t priority) {
+ NVIC.IPR[n] = priority;
+ }
+
+ struct MFP {
+ void (*func_p)(void*);
+ void* instance_p;
+ };
+
+ extern MFP mf_vectors[];
+
+ template<class T>
+ inline void set_handler(IRQ n, void (T::*f)(), T* i) {
+ MFP& mfp = mf_vectors[16 + n];
+ mfp.func_p = reinterpret_cast<void (*)(void*)>(f);
+ mfp.instance_p = i;
+ }
+
+ template<class T>
+ inline void enable(IRQ n, void (T::*f)(), T* i) {
+ set_handler(n, f, i);
+ enable(n);
+ }
+};
+
+template<Interrupt::Exception>
+void interrupt();
+
+template<Interrupt::IRQ>
+void interrupt();
+
+#endif