diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2021-01-16 01:25:21 +0100 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2021-01-16 01:25:21 +0100 |
commit | 172d694cf7ba582635ac38454bad0f0fdaa14773 (patch) | |
tree | efb0d145ed7fb3eeb44541714568680a6451ab3d | |
parent | 9921c9db409ad5b00fe4a43a2459e2fd2de6b0cf (diff) |
interrupt: Generate interrupts from platform spec.
-rw-r--r-- | SConscript | 12 | ||||
-rw-r--r-- | i2c/i2c.cpp | 10 | ||||
-rw-r--r-- | i2c/i2c.h | 4 | ||||
-rw-r--r-- | interrupt/SConscript | 18 | ||||
-rw-r--r-- | interrupt/default_handlers.cpp.j2 | 19 | ||||
-rw-r--r-- | interrupt/fault.cpp | 45 | ||||
-rw-r--r-- | interrupt/interrupt.cpp | 159 | ||||
-rw-r--r-- | interrupt/interrupt.h | 87 | ||||
-rw-r--r-- | interrupt/interrupt_enums.h.j2 | 13 | ||||
-rw-r--r-- | interrupt/vectors_nvic.cpp.j2 | 28 | ||||
-rw-r--r-- | platforms/cortex-m.yaml | 12 | ||||
-rw-r--r-- | platforms/stm32/f4.yaml | 93 |
12 files changed, 204 insertions, 296 deletions
@@ -4,10 +4,14 @@ Import('env') Export('env') env.SConscript('ld_scripts/SConscript') -env.SConscript('usb/SConscript') env.Append( - LIB_SOURCES = Glob('*.cpp') + Glob('*/*.cpp'), + LIB_SOURCES = [ + env.SConscript('interrupt/SConscript'), + env.SConscript('usb/SConscript'), + Glob('startup/*.cpp'), + Glob('i2c/*.cpp'), + Glob('os/*.cpp'), + Glob('rcc/*.cpp'), + ], ) - -# vim: syn=python diff --git a/i2c/i2c.cpp b/i2c/i2c.cpp index 36ce972..3039e47 100644 --- a/i2c/i2c.cpp +++ b/i2c/i2c.cpp @@ -4,12 +4,12 @@ #include <os/thread.h> #if defined(STM32F1) -I2C_t I2C1(0x40005400, 36000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER); -I2C_t I2C2(0x40005800, 36000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER); +I2C_t I2C1(0x40005400, 36000000); +I2C_t I2C2(0x40005800, 36000000); #elif defined(STM32F4) -I2C_t I2C1(0x40005400, 42000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER); -I2C_t I2C2(0x40005800, 42000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER); -//I2C_t I2C3(0x40005c00, 42000000, Interrupt::I2C3_EV, Interrupt::I2C3_ER); +I2C_t I2C1(0x40005400, 42000000); +I2C_t I2C2(0x40005800, 42000000); +//I2C_t I2C3(0x40005c00, 42000000); #endif #if defined(STM32F1) || defined(STM32F4) @@ -29,10 +29,8 @@ class I2C_t { public: I2C_reg_t& reg; const uint32_t clk; - Interrupt::IRQ irq_ev_n; - Interrupt::IRQ irq_er_n; - I2C_t(uint32_t reg_addr, uint32_t bus_clk, Interrupt::IRQ ev_n, Interrupt::IRQ er_n) : reg(*(I2C_reg_t*)reg_addr), clk(bus_clk), irq_ev_n(ev_n), irq_er_n(er_n) { + I2C_t(uint32_t reg_addr, uint32_t bus_clk) : reg(*(I2C_reg_t*)reg_addr), clk(bus_clk) { reading = writing = 0; } diff --git a/interrupt/SConscript b/interrupt/SConscript new file mode 100644 index 0000000..c94bde8 --- /dev/null +++ b/interrupt/SConscript @@ -0,0 +1,18 @@ +Import('env') + +sources = [] + +interrupt_controller = env['PLATFORM_SPEC'].get('interrupt_controller') + +exceptions = env['PLATFORM_SPEC'].get('exception', {}) +irqs = env['PLATFORM_SPEC'].get('irq', {}) + +env.Jinja2('interrupt_enums.h', 'interrupt_enums.h.j2', exceptions = exceptions, irqs = irqs), + +if interrupt_controller == 'nvic': + sources.extend([ + env.Jinja2('vectors_nvic.cpp', 'vectors_nvic.cpp.j2', exceptions = exceptions, irqs = irqs), + env.Jinja2('default_handlers.cpp', 'default_handlers.cpp.j2', exceptions = exceptions, irqs = irqs), + ]) + +Return('sources') diff --git a/interrupt/default_handlers.cpp.j2 b/interrupt/default_handlers.cpp.j2 new file mode 100644 index 0000000..cc4c16d --- /dev/null +++ b/interrupt/default_handlers.cpp.j2 @@ -0,0 +1,19 @@ +#include "interrupt.h" + +extern "C" void default_blocking_handler() { + while(1); +} + +{% for exc in exceptions.values() %} +template<> +[[gnu::weak, gnu::alias("default_blocking_handler")]] +void interrupt<Exception::{{ exc }}>(); + +{% endfor %} + +{% for irq in irqs.values() %} +template<> +[[gnu::weak, gnu::alias("default_blocking_handler")]] +void interrupt<IRQ::{{ irq }}>(); + +{% endfor %} diff --git a/interrupt/fault.cpp b/interrupt/fault.cpp deleted file mode 100644 index 0d91c1d..0000000 --- a/interrupt/fault.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "interrupt.h" -#include <os/thread.h> -#include <os/time.h> - -inline void __attribute__((naked)) switch_context() { - #if ! (defined(STM32F0) || defined(STM32L0)) // TODO: cortex-m0/+ unsupported for now. - - 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"); - - #endif -} - -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 deleted file mode 100644 index b50c01e..0000000 --- a/interrupt/interrupt.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "interrupt.h" - -void entry(); - -extern "C" void unused_interrupt() { - //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)(); - -extern uint32_t _ram_end; - -vector_t vectors[] __attribute__((section(".vectors"))) = { - (vector_t)&_ram_end, - 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>, -}; diff --git a/interrupt/interrupt.h b/interrupt/interrupt.h index 0851c87..b87abef 100644 --- a/interrupt/interrupt.h +++ b/interrupt/interrupt.h @@ -3,6 +3,8 @@ #include <stdint.h> +#include "interrupt_enums.h" + struct NVIC_t { volatile uint32_t ISER[32]; volatile uint32_t ICER[32]; @@ -34,98 +36,23 @@ struct SCB_t { 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); + NVIC.ISER[int(n) >> 5] = 1 << (int(n) & 0x1f); } inline void set_priority(Exception n, uint8_t priority) { - SCB.SHPR[n - 4] = priority; + SCB.SHPR[int(n) - 4] = priority; } inline void set_priority(IRQ n, uint8_t priority) { - NVIC.IPR[n] = priority; + NVIC.IPR[int(n)] = priority; } }; -template<Interrupt::Exception> +template<Exception> void interrupt(); -template<Interrupt::IRQ> +template<IRQ> void interrupt(); #endif diff --git a/interrupt/interrupt_enums.h.j2 b/interrupt/interrupt_enums.h.j2 new file mode 100644 index 0000000..cc05100 --- /dev/null +++ b/interrupt/interrupt_enums.h.j2 @@ -0,0 +1,13 @@ +#pragma once + +enum class Exception { + {% for num, name in exceptions.items() %} + {{ name }} = {{ num }}, + {% endfor %} +}; + +enum class IRQ { + {% for num, name in irqs.items() %} + {{ name }} = {{ num }}, + {% endfor %} +}; diff --git a/interrupt/vectors_nvic.cpp.j2 b/interrupt/vectors_nvic.cpp.j2 new file mode 100644 index 0000000..e4293f3 --- /dev/null +++ b/interrupt/vectors_nvic.cpp.j2 @@ -0,0 +1,28 @@ +#include "interrupt.h" + +void entry(); +extern uint32_t _ram_end; + +typedef void (*vector_t)(); + +[[gnu::section(".vectors")]] +vector_t vectors[] = { + (vector_t)&_ram_end, + entry, + + {% for i in range(2, 16) %} + {% if i in exceptions %} + interrupt<Exception::{{ exceptions[i] }}>, + {% else %} + 0, + {% endif %} + {% endfor %} + + {% for i in range(irqs | max + 1 if irqs else 0) %} + {% if i in irqs %} + interrupt<IRQ::{{ irqs[i] }}>, + {% else %} + 0, + {% endif %} + {% endfor %} +}; diff --git a/platforms/cortex-m.yaml b/platforms/cortex-m.yaml index d1612b2..c0aa8bd 100644 --- a/platforms/cortex-m.yaml +++ b/platforms/cortex-m.yaml @@ -1,6 +1,18 @@ - match: cpu: cortex-m4f + interrupt_controller: nvic + + exception: + 2: NMI + 3: HardFault + 4: MemManage + 5: BusFault + 6: UsageFault + 11: SVCall + 14: PendSV + 15: SysTick + cflags: - -mcpu=cortex-m4 - -mfloat-abi=hard diff --git a/platforms/stm32/f4.yaml b/platforms/stm32/f4.yaml index dccffe9..c132524 100644 --- a/platforms/stm32/f4.yaml +++ b/platforms/stm32/f4.yaml @@ -34,6 +34,99 @@ OTG_HS: offset: 0x40040000 + irq: + 0: WWDG + 1: PVD + 2: TAMP_STAMP + 3: RTC_WKUP + 4: FLASH + 5: RCC + 6: EXTI0 + 7: EXTI1 + 8: EXTI2 + 9: EXTI3 + 10: EXTI4 + 11: DMA1_Stream0 + 12: DMA1_Stream1 + 13: DMA1_Stream2 + 14: DMA1_Stream3 + 15: DMA1_Stream4 + 16: DMA1_Stream5 + 17: DMA1_Stream6 + 18: ADC + 19: CAN1_TX + 20: CAN1_RX0 + 21: CAN1_RX1 + 22: CAN1_SCE + 23: EXTI9_5 + 24: TIM1_BRK_TIM9 + 25: TIM1_UP_TIM10 + 26: TIM1_TRG_COM_TIM11 + 27: TIM1_CC + 28: TIM2 + 29: TIM3 + 30: TIM4 + 31: I2C1_EV + 32: I2C1_ER + 33: I2C2_EV + 34: I2C2_ER + 35: SPI1 + 36: SPI2 + 37: USART1 + 38: USART2 + 39: USART3 + 40: EXTI15_10 + 41: RTC_Alarm + 42: OTG_FS_WKUP + 43: TIM8_BRK_TIM12 + 44: TIM8_UP_TIM13 + 45: TIM8_TRG_COM_TIM14 + 46: TIM8_CC + 47: DMA1_Stream7 + 48: FSMC + 49: SDIO + 50: TIM5 + 51: SPI3 + 52: UART4 + 53: UART5 + 54: TIM6_DAC + 55: TIM7 + 56: DMA2_Stream0 + 57: DMA2_Stream1 + 58: DMA2_Stream2 + 59: DMA2_Stream3 + 60: DMA2_Stream4 + 61: ETH + 62: ETH_WKUP + 63: CAN2_TX + 64: CAN2_RX0 + 65: CAN2_RX1 + 66: CAN2_SCE + 67: OTG_FS + 68: DMA2_Stream5 + 69: DMA2_Stream6 + 70: DMA2_Stream7 + 71: USART6 + 72: I2C3_EV + 73: I2C3_ER + 74: OTG_HS_EP1_OUT + 75: OTG_HS_EP1_IN + 76: OTG_HS_WKUP + 77: OTG_HS + 78: DCMI + 79: CRYP + 80: HASH_RNG + 81: FPU + 82: UART7 + 83: UART8 + 84: SPI4 + 85: SPI5 + 86: SPI6 + 87: SAI1 + 88: LCD_TFT + 89: LCD_TFT_ERR + 90: DMA2D + define: - STM32F4 |