diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 6fe1064ae..e7202dd73 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -35,6 +35,36 @@ void Ion::Device::init() { } void Ion::Device::initClocks() { +#define USE_96MHZ_SYSTEM_CLOCK 0 +#if USE_96MHZ_SYSTEM_CLOCK + /* System clock + * Configure the CPU at 96 MHz, APB2 and USB at 48 MHz. */ + + /* After reset the Flash runs as fast as the CPU. When we clock the CPU faster + * the flash memory cannot follow and therefore flash memory accesses need to + * wait a little bit. + * The spec tells us that at 2.8V and over 90MHz the flash expects 3 WS. */ + FLASH.ACR()->setLATENCY(3); + + /* We're using the high-speed internal oscillator as a clock source. It runs + * at a fixed 16 MHz frequency, but by piping it through the PLL we can derive + * faster oscillations. Combining default values and a PLLQ of 4 can provide + * us with a 96 MHz frequency for SYSCLK. */ + RCC.PLLCFGR()->setPLLQ(4); + RCC.PLLCFGR()->setPLLSRC(RCC::PLLCFGR::PLLSRC::HSI); + // 96 MHz is too fast for APB1. Divide it by two to reach 48 MHz + RCC.CFGR()->setPPRE1(RCC::CFGR::AHBRatio::DivideBy2); + + // Enable the PLL and wait for it to be ready + RCC.CR()->setPLLON(true); + while(!RCC.CR()->getPLLRDY()) { + } + + // Last but not least, use the PLL output as a SYSCLK source + RCC.CFGR()->setSW(RCC::CFGR::SW::PLL); + while (RCC.CFGR()->getSWS() != RCC::CFGR::SW::PLL) { + } +#endif // Peripheral clocks diff --git a/ion/src/device/regs/flash.h b/ion/src/device/regs/flash.h new file mode 100644 index 000000000..39c21c7b3 --- /dev/null +++ b/ion/src/device/regs/flash.h @@ -0,0 +1,23 @@ +#ifndef REGS_FLASH_H +#define REGS_FLASH_H + +#include "register.h" + +class FLASH { +public: + class ACR : public Register32 { + public: + REGS_FIELD(LATENCY, uint8_t, 3, 0); + }; + + constexpr FLASH() {}; + REGS_REGISTER_AT(ACR, 0x00); +private: + constexpr uint32_t Base() const { + return 0x40023C00; + } +}; + +constexpr FLASH FLASH; + +#endif diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 5be8b3f3f..5de2cb48c 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -5,6 +5,45 @@ class RCC { public: + class CR : public Register32 { + public: + REGS_BOOL_FIELD(PLLRDY, 25); + REGS_BOOL_FIELD(PLLON, 24); + }; + + class PLLCFGR : public Register32 { + public: + REGS_FIELD(PLLM, uint8_t, 5, 0); + REGS_FIELD(PLLN, uint16_t, 14, 6); + REGS_FIELD(PLLP, uint8_t, 17, 16); + enum class PLLSRC { + HSI = 0, + HSE = 1 + }; + void setPLLSRC(PLLSRC s) volatile { setBitRange(22, 22, (uint8_t)s); } + REGS_FIELD(PLLQ, uint8_t, 27, 24); + REGS_FIELD(PLLR, uint8_t, 30, 28); + }; + + class CFGR : public Register32 { + public: + enum class SW { + HSI = 0, + HSE = 1, + PLL = 2 + }; + void setSW(SW s) volatile { setBitRange(1, 0, (uint8_t)s); } + SW getSWS() volatile { return (SW)getBitRange(3,2); } + enum class AHBRatio { + One = 0, + DivideBy2 = 4, + DivideBy4 = 5, + DivideBy8 = 6, + DivideBy16 = 7 + }; + void setPPRE1(AHBRatio r) volatile { setBitRange(12, 10, (uint32_t)r); } + }; + class AHB1ENR : public Register32 { public: AHB1ENR(uint32_t v) : Register32(v) {} @@ -40,6 +79,9 @@ public: }; constexpr RCC() {}; + REGS_REGISTER_AT(CR, 0x00); + REGS_REGISTER_AT(PLLCFGR, 0x04); + REGS_REGISTER_AT(CFGR, 0x08); REGS_REGISTER_AT(AHB1ENR, 0x30); REGS_REGISTER_AT(AHB3ENR, 0x38); REGS_REGISTER_AT(APB1ENR, 0x40); diff --git a/ion/src/device/regs/regs.h b/ion/src/device/regs/regs.h index 586b84e16..88aea9162 100644 --- a/ion/src/device/regs/regs.h +++ b/ion/src/device/regs/regs.h @@ -5,6 +5,7 @@ #include "exti.h" #include "cm4.h" #include "fsmc.h" +#include "flash.h" #include "rcc.h" #include "gpio.h" #include "syscfg.h"