From 025a38a1f743fd9e89cbd477abe3f79a8d098097 Mon Sep 17 00:00:00 2001
From: Vegard Storheil Eriksen <zyp@jvnv.net>
Date: Sat, 19 Nov 2011 17:21:31 +0100
Subject: Moved os and hal related files into subdirectories.

---
 hal/fault.cpp     |  41 +++++++++
 hal/i2c.cpp       | 194 ++++++++++++++++++++++++++++++++++++++++
 hal/i2c.h         |  40 +++++++++
 hal/interrupt.cpp | 157 ++++++++++++++++++++++++++++++++
 hal/interrupt.h   | 100 +++++++++++++++++++++
 hal/rcc.cpp       |  26 ++++++
 hal/rcc.h         |   6 ++
 hal/stm32.h       | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hal/usart.h       |  26 ++++++
 9 files changed, 852 insertions(+)
 create mode 100644 hal/fault.cpp
 create mode 100644 hal/i2c.cpp
 create mode 100644 hal/i2c.h
 create mode 100644 hal/interrupt.cpp
 create mode 100644 hal/interrupt.h
 create mode 100644 hal/rcc.cpp
 create mode 100644 hal/rcc.h
 create mode 100644 hal/stm32.h
 create mode 100644 hal/usart.h

(limited to 'hal')

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
-- 
cgit v1.2.3