diff options
Diffstat (limited to 'hal')
-rw-r--r-- | hal/fault.cpp | 41 | ||||
-rw-r--r-- | hal/i2c.cpp | 194 | ||||
-rw-r--r-- | hal/i2c.h | 40 | ||||
-rw-r--r-- | hal/interrupt.cpp | 157 | ||||
-rw-r--r-- | hal/interrupt.h | 100 | ||||
-rw-r--r-- | hal/rcc.cpp | 26 | ||||
-rw-r--r-- | hal/rcc.h | 6 | ||||
-rw-r--r-- | hal/stm32.h | 262 | ||||
-rw-r--r-- | hal/usart.h | 26 |
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 = ® + 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 |