diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 101bfe104..c86bf76d1 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -6,4 +6,17 @@ objs += $(addprefix ion/src/device/display/,\ spi.o\ st7789.o\ ) + +# When using the register.h C++ file in production mode, we expect the compiler +# to completely inline all bit manipulations. For some reason, if we build using +# the -Os optimization flag, GCC doesn't inline everything and and ends up +# emitting calls to aeabi_llsl for 64-bits registers. This is very sub-optimal +# so we're enforcing -O3 for this specific file. + +ifneq ($(DEBUG),1) +ifneq ($(COMPILER),llvm) +ion/src/device/led.o: SFLAGS+=-O3 +endif +endif + objs += $(addprefix ion/src/device/keyboard/, keyboard.o) diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index 26b63bcdb..309004fcb 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -25,11 +25,13 @@ void ion_led_gpio_init() { * which is an alternate function. */ GPIOA.MODER()->setMODER(8, GPIO::MODER::MODE::AlternateFunction); GPIOA.MODER()->setMODER(9, GPIO::MODER::MODE::AlternateFunction); + GPIOA.MODER()->setMODER(10, GPIO::MODER::MODE::AlternateFunction); /* More precisely, we will use AF01, which maps PA8 to TIM1_CH1, PA9 to * TIM1_CH2 and PA10 to TIM1_CH3. */ GPIOA.AFR()->setAFR(8, GPIO::AFR::AlternateFunction::AF1); GPIOA.AFR()->setAFR(9, GPIO::AFR::AlternateFunction::AF1); + GPIOA.AFR()->setAFR(10, GPIO::AFR::AlternateFunction::AF1); } void ion_led_timer_init() { @@ -41,20 +43,24 @@ void ion_led_timer_init() { * frequency determined by the value of the TIMx_ARR register and a duty cycle * determined by the value of the TIMx_CCRx register. */ TIM1.ARR()->set(40000); - TIM1.CCR1()->set(20000); + TIM1.CCR1()->set(15000); TIM1.CCR2()->set(20000); - + TIM1.CCR3()->set(8000); // Set Channel 1 as output, PWM mode 1 - TIM1.CCMR1()->setOC1M(TIM::CCMR1::OC1M::PWM1); - TIM1.CCMR1()->setOC2M(TIM::CCMR1::OC2M::PWM2); + //auto ccmr = *(uint32_t *)TIM1.CCMR(); + //auto ccmr = *(TIM1.CCMR()); + //class TIM::CCMR ccmr(*(TIM1.CCMR())); + TIM1.CCMR()->setOC1M(TIM::CCMR::OCM::PWM1); + TIM1.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); + TIM1.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); // Set Channel 2 as output, PWM mode 2 // REGISTER_SET_VALUE(TIM_CCMR1(TIM1), TIM_OC2M, 6); // Output preload enable for channel 1 and 2 - TIM1.CCMR1()->setOC1PE(true); - TIM1.CCMR1()->setOC2PE(true); - //FIXME: do OC2PE too + TIM1.CCMR()->setOC1PE(true); + TIM1.CCMR()->setOC2PE(true); + TIM1.CCMR()->setOC3PE(true); // Auto-reload preload enable TIM1.CR1()->setARPE(true); @@ -62,6 +68,7 @@ void ion_led_timer_init() { // Enable Capture/Compare channel 1 and channel 2 TIM1.CCER()->setCC1E(true); TIM1.CCER()->setCC2E(true); + TIM1.CCER()->setCC3E(true); TIM1.BDTR()->setMOE(true); diff --git a/ion/src/device/register.h b/ion/src/device/register.h index bd0cc51fe..89aaea6d4 100644 --- a/ion/src/device/register.h +++ b/ion/src/device/register.h @@ -6,23 +6,23 @@ public: Register() = delete; void set(T value) volatile { m_value = value; - }; + } T get() volatile { return m_value; - }; + } protected: static constexpr T bit_range_mask(uint8_t high, uint8_t low) { return ((((T)1)<<(high-low+1))-1)<> low; } @@ -32,6 +32,7 @@ private: typedef Register Register16; typedef Register Register32; +typedef Register Register64; // RCC @@ -84,7 +85,9 @@ public: void setMODER(int index, MODE mode) volatile { set(2*index+1, 2*index, (uint32_t)mode); }; }; - class AFR : Register { + class AFR : Register64 { + /* The AFR register doesn't exist per-se in the documentation. It is the + * consolidation of AFRL and AFRH which are two 32 bits registers. */ public: enum class AlternateFunction { AF0 = 0, AF1 = 1, AF2 = 2, AF3 = 3, @@ -100,7 +103,7 @@ public: }; }; - constexpr GPIO(int i) : m_index(i) {}; + constexpr GPIO(int i) : m_index(i) {} registerAt(MODER, 0x00); registerAt(AFR, 0x20); private: @@ -129,7 +132,12 @@ public: boolField(ARPE, 7); }; - class CCMR1 : Register16 { + class CCMR : Register64 { + /* We're declaring CCMR as a 64 bits register. CCMR doesn't exsist per se, + * it is in fact the consolidation of CCMR1 and CCMR2. Both are 16 bits + * registers, so one could expect the consolidation to be 32 bits. However, + * both CCMR1 and CCMR2 live on 32-bits boundaries, so the consolidation has + * to be 64 bits wide, even though we'll only use 32 bits out of 64. */ public: enum class CC1S : uint8_t { OUTPUT = 0, @@ -137,7 +145,7 @@ public: INPUT_TI1 = 2, INPUT_TRC = 3 }; - enum class OC1M : uint8_t { + enum class OCM : uint8_t { Frozen = 0, ActiveOnMatch = 1, InactiveOnMatch = 2, @@ -147,18 +155,26 @@ public: PWM1 = 6, PWM2 = 7 }; - typedef OC1M OC2M; - typeField(CC1S, 1, 0); + typedef OCM OC1M; + typedef OCM OC2M; + typedef OCM OC3M; + typedef OCM OC4M; boolField(OC1PE, 3); typeField(OC1M, 6, 4); boolField(OC2PE, 11); typeField(OC2M, 14, 12); + boolField(OC3PE, 35); + typeField(OC3M, 38, 36); + boolField(OC4PE, 43); + typeField(OC4M, 46, 44); }; class CCER : Register16 { public: boolField(CC1E, 0); boolField(CC2E, 4); + boolField(CC3E, 8); + boolField(CC4E, 12); }; class BDTR : Register16 { @@ -170,15 +186,17 @@ public: class ARR : public Register16 {}; class CCR1 : public Register16 {}; class CCR2 : public Register16 {}; + class CCR3 : public Register16 {}; - constexpr TIM(int i) : m_index(i) {}; + constexpr TIM(int i) : m_index(i) {} registerAt(CR1, 0x0); - registerAt(CCMR1, 0x18); + registerAt(CCMR, 0x18); registerAt(CCER, 0x20); registerAt(PSC, 0x28); registerAt(ARR, 0x2C); registerAt(CCR1, 0x34); registerAt(CCR2, 0x38); + registerAt(CCR3, 0x3C); registerAt(BDTR, 0x44); private: constexpr uint32_t Base() const {