summaryrefslogtreecommitdiff
path: root/hal
diff options
context:
space:
mode:
Diffstat (limited to 'hal')
-rw-r--r--hal/fault.cpp41
-rw-r--r--hal/i2c.cpp194
-rw-r--r--hal/i2c.h40
-rw-r--r--hal/interrupt.cpp157
-rw-r--r--hal/interrupt.h100
-rw-r--r--hal/rcc.cpp26
-rw-r--r--hal/rcc.h6
-rw-r--r--hal/stm32.h262
-rw-r--r--hal/usart.h26
9 files changed, 852 insertions, 0 deletions
diff --git a/hal/fault.cpp b/hal/fault.cpp
new file mode 100644
index 0000000..a176ae6
--- /dev/null
+++ b/hal/fault.cpp
@@ -0,0 +1,41 @@
+#include "interrupt.h"
+#include "thread.h"
+#include "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/hal/i2c.cpp b/hal/i2c.cpp
new file mode 100644
index 0000000..cee72ec
--- /dev/null
+++ b/hal/i2c.cpp
@@ -0,0 +1,194 @@
+#include "i2c.h"
+
+#include "stm32.h"
+#include "thread.h"
+
+I2C* I2C::self;
+
+template <>
+void interrupt<Interrupt::I2C1_EV>() {
+ I2C::self->irq_ev();
+}
+
+template <>
+void interrupt<Interrupt::I2C1_ER>() {
+ I2C::self->irq_er();
+}
+
+void I2C::irq_ev() {
+ uint32_t sr1 = I2C1.SR1;
+ I2C1.SR2;
+
+ // EV5, SB = 1: Start condition sent.
+ if(sr1 & 0x01) {
+ // Send address.
+ I2C1.DR = (addr << 1) | (writing ? 0 : 1);
+ }
+
+ // EV6, ADDR = 1: Address sent.
+ if(sr1 & 0x02) {
+ if(writing) {
+ I2C1.DR = *write_p++;
+ writing--;
+ } else {
+ if(reading > 1) {
+ I2C1.CR1 |= 0x400; // Set ACK.
+ } else {
+ I2C1.CR1 |= 0x200; // Set STOP.
+ }
+ }
+ }
+
+ // EV7, RxNE = 1: Receive buffer not empty.
+ if(sr1 & 0x40) {
+ *read_p++ = I2C1.DR;
+ reading--;
+
+ if(reading == 1) {
+ // Unset ACK, set STOP.
+ I2C1.CR1 = (I2C1.CR1 & ~0x400) | 0x200;
+ }
+
+ if(reading == 0) {
+ busy = 0;
+ }
+ }
+
+ //I2C1.CR1 &= ~0x400;
+
+ // EV8, TxE = 1, BTF = 0: Transmit buffer empty, still writing.
+ if(sr1 & 0x80 && !(sr1 & 0x04)) {
+ if(writing) {
+ // Send data.
+ I2C1.DR = *write_p++;
+ writing--;
+ } else {
+ // All data sent.
+
+ if(reading) {
+ // Send repeat start.
+ I2C1.CR1 |= 0x100;
+ } else {
+ // Send stop.
+ I2C1.CR1 |= 0x200;
+ busy = 0;
+ }
+ }
+ }
+}
+
+void I2C::irq_er() {
+ handle_error();
+}
+
+void I2C::handle_error() {
+ I2C1.SR1;
+ I2C1.SR2;
+
+ //while(1);
+ I2C1.CR1 |= 0x200;
+ busy = 0;
+}
+
+void I2C::enable() {
+ RCC.enable(RCC.I2C1);
+ asm volatile("nop");
+
+ I2C1.CR1 = 0x8000;
+ I2C1.CR1 = 0;
+
+ I2C1.CR2 = 0x700 | 36;
+ I2C1.TRISE = 37;
+ I2C1.CCR = 180;
+
+ Interrupt::enable(Interrupt::I2C1_EV);
+ Interrupt::enable(Interrupt::I2C1_ER);
+
+ I2C1.CR1 = 1;
+}
+
+void I2C::write_reg(uint8_t addr_, uint8_t reg, uint8_t data) {
+ addr = addr_;
+ writing = 2;
+ reading = 0;
+ volatile uint8_t buf[] = {reg, data};
+ write_p = buf;
+ busy = 1;
+
+ I2C1.CR1 |= 0x100;
+
+ while(busy) {
+ Thread::yield();
+ }
+
+ /*
+ while(!(I2C1.SR1 & 0x01)); // Wait for SB.
+
+ I2C1.DR = (addr << 1) | 0;
+ while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
+ I2C1.SR2;
+
+ I2C1.DR = reg;
+ while (!(I2C1.SR1 & 0x80)); // Wait for TxE.
+
+ I2C1.DR = data;
+ while (!(I2C1.SR1 & 0x04)); // Wait for BTF.
+
+ I2C1.CR1 |= 0x200;*/
+}
+
+void I2C::read_reg(uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf) {
+ addr = addr_;
+ writing = 1;
+ reading = len;
+ write_p = &reg;
+ read_p = buf;
+ busy = 1;
+
+ I2C1.CR1 |= 0x100;
+
+ while(busy) {
+ Thread::yield();
+ }
+
+ /*
+ I2C1.CR1 |= 0x100;
+ while(!(I2C1.SR1 & 0x01)); // Wait for SB.
+
+ I2C1.DR = (addr << 1) | 0;
+ while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
+ I2C1.SR2;
+
+ I2C1.DR = reg;
+ while (!(I2C1.SR1 & 0x80)); // Wait for TxE.
+
+ I2C1.CR1 |= 0x100;
+ while(!(I2C1.SR1 & 0x01)); // Wait for SB.
+
+ I2C1.DR = (addr << 1) | 1;
+ while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
+ I2C1.SR2;
+
+ I2C1.CR1 |= 0x400; // Set ACK.
+
+ while(len) {
+ if(len == 3) {
+ while (!(I2C1.SR1 & 0x04)); // Wait for BTF.
+
+ I2C1.CR1 &= ~0x400; // Clear ACK.
+ *buf++ = I2C1.DR;
+ len--;
+
+ I2C1.CR1 |= 0x200; // Set STOP.
+ *buf++ = I2C1.DR;
+ len--;
+
+ } else {
+ while (!(I2C1.SR1 & 0x40)); // Wait for RxNE.
+
+ *buf++ = I2C1.DR;
+ len--;
+ }
+ }
+ */
+}
diff --git a/hal/i2c.h b/hal/i2c.h
new file mode 100644
index 0000000..3d58056
--- /dev/null
+++ b/hal/i2c.h
@@ -0,0 +1,40 @@
+#ifndef I2C_H
+#define I2C_H
+
+#include <stdint.h>
+
+#include "interrupt.h"
+
+class I2C {
+ friend void interrupt<Interrupt::I2C1_EV>();
+ friend void interrupt<Interrupt::I2C1_ER>();
+
+ private:
+ static I2C* self;
+
+ volatile uint8_t addr;
+ volatile uint8_t writing;
+ volatile uint8_t reading;
+ volatile uint8_t* write_p;
+ volatile uint8_t* read_p;
+
+ volatile bool busy;
+
+ void irq_ev();
+ void irq_er();
+ void handle_error();
+
+ public:
+ I2C() {
+ self = this;
+ }
+
+ void enable();
+
+ void write_reg(uint8_t addr_, uint8_t reg, uint8_t data);
+ void read_reg(uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf);
+};
+
+
+
+#endif
diff --git a/hal/interrupt.cpp b/hal/interrupt.cpp
new file mode 100644
index 0000000..e9e7b24
--- /dev/null
+++ b/hal/interrupt.cpp
@@ -0,0 +1,157 @@
+#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)();
+
+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>,
+};
diff --git a/hal/interrupt.h b/hal/interrupt.h
new file mode 100644
index 0000000..f817103
--- /dev/null
+++ b/hal/interrupt.h
@@ -0,0 +1,100 @@
+#ifndef INTERRUPT_H
+#define INTERRUPT_H
+
+#include "stm32.h"
+
+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
+ };
+
+ 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;
+ }
+};
+
+template<Interrupt::Exception>
+void interrupt();
+
+template<Interrupt::IRQ>
+void interrupt();
+
+#endif
diff --git a/hal/rcc.cpp b/hal/rcc.cpp
new file mode 100644
index 0000000..e3ae38d
--- /dev/null
+++ b/hal/rcc.cpp
@@ -0,0 +1,26 @@
+#include "rcc.h"
+#include "stm32.h"
+
+void rcc_init() {
+ // Set flash latency.
+ FLASH.ACR = 0x12;
+
+ // Enable HSE.
+ RCC.CR |= 0x10000;
+ while(RCC.CR & 0x20000);
+
+ // Configure and enable PLL.
+ RCC.CFGR = 0x1d0000;
+ RCC.CR |= 0x1000000;
+ while(RCC.CR & 0x2000000);
+
+ // Switch to PLL.
+ RCC.CFGR |= 0x2;
+ while(!(RCC.CFGR & 0x8));
+
+ // Set APB1 prescaler to /2.
+ RCC.CFGR |= 0x400;
+
+ // Set ADCCLK prescaler to /6.
+ RCC.CFGR |= 0x8000;
+}
diff --git a/hal/rcc.h b/hal/rcc.h
new file mode 100644
index 0000000..8c5fb86
--- /dev/null
+++ b/hal/rcc.h
@@ -0,0 +1,6 @@
+#ifndef RCC_H
+#define RCC_H
+
+void rcc_init();
+
+#endif
diff --git a/hal/stm32.h b/hal/stm32.h
new file mode 100644
index 0000000..8144e80
--- /dev/null
+++ b/hal/stm32.h
@@ -0,0 +1,262 @@
+#ifndef STM32_H
+#define STM32_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;
+
+struct RCC_t {
+ volatile uint32_t CR;
+ volatile uint32_t CFGR;
+ volatile uint32_t CIR;
+ volatile uint32_t APB2RSTR;
+ volatile uint32_t APB1RSTR;
+ volatile uint32_t AHBENR;
+ volatile uint32_t APB2ENR;
+ volatile uint32_t APB1ENR;
+ volatile uint32_t BDCR;
+ volatile uint32_t CSR;
+
+ enum AHB_dev {
+ DMA1 = 1 << 0,
+ DMA2 = 1 << 1,
+ SRAM = 1 << 2,
+ FLITF = 1 << 4,
+ CRC = 1 << 6,
+ FSMC = 1 << 8,
+ SDIO = 1 << 10
+ };
+
+ enum APB1_dev {
+ TIM2 = 1 << 0,
+ TIM3 = 1 << 1,
+ TIM4 = 1 << 2,
+ TIM5 = 1 << 3,
+ TIM6 = 1 << 4,
+ TIM7 = 1 << 5,
+ TIM12 = 1 << 6,
+ TIM13 = 1 << 7,
+ TIM14 = 1 << 8,
+ WWDG = 1 << 11,
+ SPI2 = 1 << 14,
+ SPI3 = 1 << 15,
+ USART2 = 1 << 17,
+ USART3 = 1 << 18,
+ UART4 = 1 << 19,
+ UART5 = 1 << 20,
+ I2C1 = 1 << 21,
+ I2C2 = 1 << 22,
+ USB = 1 << 23,
+ CAN = 1 << 25,
+ BKP = 1 << 27,
+ PWR = 1 << 28,
+ DAC = 1 << 29
+ };
+
+ enum APB2_dev {
+ AFIO = 1 << 0,
+ IOPA = 1 << 2,
+ IOPB = 1 << 3,
+ IOPC = 1 << 4,
+ IOPD = 1 << 5,
+ IOPE = 1 << 6,
+ IOPF = 1 << 7,
+ IOPG = 1 << 8,
+ ADC1 = 1 << 9,
+ ADC2 = 1 << 10,
+ TIM1 = 1 << 11,
+ SPI1 = 1 << 12,
+ TIM8 = 1 << 13,
+ USART1 = 1 << 14,
+ ADC3 = 1 << 15,
+ TIM9 = 1 << 19,
+ TIM10 = 1 << 20,
+ TIM11 = 1 << 21
+ };
+
+ inline void enable(AHB_dev dev) {
+ AHBENR |= dev;
+ }
+
+ inline void enable(APB1_dev dev) {
+ APB1ENR |= dev;
+ }
+
+ inline void enable(APB2_dev dev) {
+ APB2ENR |= dev;
+ }
+};
+
+static RCC_t& RCC = *(RCC_t*)0x40021000;
+
+struct STK_t {
+ volatile uint32_t CTRL;
+ volatile uint32_t LOAD;
+ volatile uint32_t VAL;
+ volatile uint32_t CALIB;
+};
+
+static STK_t& STK = *(STK_t*)0xe000e010;
+
+struct FLASH_t {
+ volatile uint32_t ACR;
+ volatile uint32_t KEYR;
+ volatile uint32_t OPTKEYR;
+ volatile uint32_t SR;
+ volatile uint32_t CR;
+ volatile uint32_t AR;
+ volatile uint32_t RESERVED;
+ volatile uint32_t OBR;
+ volatile uint32_t WRPR;
+};
+
+static FLASH_t& FLASH = *(FLASH_t*)0x40022000;
+
+struct GPIO_t {
+ volatile uint32_t CRL;
+ volatile uint32_t CRH;
+ volatile uint32_t IDR;
+ volatile uint32_t ODR;
+ volatile uint32_t BSRR;
+ volatile uint32_t BRR;
+ volatile uint32_t LCKR;
+};
+
+static GPIO_t& GPIOA = *(GPIO_t*)0x40010800;
+static GPIO_t& GPIOB = *(GPIO_t*)0x40010c00;
+static GPIO_t& GPIOC = *(GPIO_t*)0x40011000;
+
+struct I2C_t {
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t OAR1;
+ volatile uint32_t OAR2;
+ volatile uint32_t DR;
+ volatile uint32_t SR1;
+ volatile uint32_t SR2;
+ volatile uint32_t CCR;
+ volatile uint32_t TRISE;
+};
+
+static I2C_t& I2C1 = *(I2C_t*)0x40005400;
+static I2C_t& I2C2 = *(I2C_t*)0x40005800;
+
+struct USART_t {
+ volatile uint32_t SR;
+ volatile uint32_t DR;
+ volatile uint32_t BRR;
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t CR3;
+ volatile uint32_t GTPR;
+};
+
+static USART_t& USART1 = *(USART_t*)0x40013800;
+static USART_t& USART2 = *(USART_t*)0x40004400;
+static USART_t& USART3 = *(USART_t*)0x40004800;
+
+struct TIM_t {
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t SMCR;
+ volatile uint32_t DIER;
+ volatile uint32_t SR;
+ volatile uint32_t EGR;
+ volatile uint32_t CCMR1;
+ volatile uint32_t CCMR2;
+ volatile uint32_t CCER;
+ volatile uint32_t CNT;
+ volatile uint32_t PSC;
+ volatile uint32_t ARR;
+ volatile uint32_t RCR;
+ volatile uint32_t CCR1;
+ volatile uint32_t CCR2;
+ volatile uint32_t CCR3;
+ volatile uint32_t CCR4;
+ volatile uint32_t BDTR;
+ volatile uint32_t DCR;
+ volatile uint32_t DMAR;
+};
+
+static TIM_t& TIM1 = *(TIM_t*)0x40012c00;
+static TIM_t& TIM2 = *(TIM_t*)0x40000000;
+static TIM_t& TIM3 = *(TIM_t*)0x40000400;
+static TIM_t& TIM4 = *(TIM_t*)0x40000800;
+static TIM_t& TIM5 = *(TIM_t*)0x40000c00;
+static TIM_t& TIM6 = *(TIM_t*)0x40001000;
+static TIM_t& TIM7 = *(TIM_t*)0x40001400;
+static TIM_t& TIM8 = *(TIM_t*)0x40013400;
+
+struct ADC_t {
+ volatile uint32_t SR;
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t SMPR1;
+ volatile uint32_t SMPR2;
+ volatile uint32_t JOFR1;
+ volatile uint32_t JOFR2;
+ volatile uint32_t JOFR3;
+ volatile uint32_t JOFR4;
+ volatile uint32_t HTR;
+ volatile uint32_t LTR;
+ volatile uint32_t SQR1;
+ volatile uint32_t SQR2;
+ volatile uint32_t SQR3;
+ volatile uint32_t JSQR;
+ volatile uint32_t JDR1;
+ volatile uint32_t JDR2;
+ volatile uint32_t JDR3;
+ volatile uint32_t JDR4;
+ volatile uint32_t DR;
+};
+
+static ADC_t& ADC1 = *(ADC_t*)0x40012400;
+static ADC_t& ADC2 = *(ADC_t*)0x40012800;
+static ADC_t& ADC3 = *(ADC_t*)0x40013c00;
+
+struct DMA_t {
+ struct CH_t {
+ volatile uint32_t CCR;
+ volatile uint32_t CNDTR;
+ volatile uint32_t CPAR;
+ volatile uint32_t CMAR;
+ uint32_t _reserved;
+ };
+
+ volatile uint32_t ISR;
+ volatile uint32_t IFCR;
+ CH_t CH[7];
+};
+
+static DMA_t& DMA1 = *(DMA_t*)0x40020000;
+static DMA_t& DMA2 = *(DMA_t*)0x40020400;
+
+#endif
diff --git a/hal/usart.h b/hal/usart.h
new file mode 100644
index 0000000..8fde39a
--- /dev/null
+++ b/hal/usart.h
@@ -0,0 +1,26 @@
+#ifndef USART_H
+#define USART_H
+
+template<>
+void interrupt<Interrupt::USART1>() {
+ USART1.DR;
+ //GPIOB.ODR ^= 1 << 1;
+}
+
+void usart_enable() {
+ RCC.enable(RCC.USART1);
+ USART1.BRR = 625; // 115200 baud
+ USART1.CR1 = 0x202c;
+
+ Interrupt::enable(Interrupt::USART1);
+}
+
+void usart_send(uint8_t data) {
+ while(!(USART1.SR & 0x80)) {
+ Thread::yield();
+ } // Wait for TXE.
+
+ USART1.DR = data;
+}
+
+#endif