diff --git a/apps/Makefile b/apps/Makefile index 6249c5f29..3caf32a26 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -22,7 +22,6 @@ app_objs += $(addprefix apps/,\ exam_pop_up_controller.o\ global_preferences.o\ i18n.o\ - led_timer.o\ lock_view.o\ main.o\ math_toolbox.o\ diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 4c15fdfb6..d86310887 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -16,7 +16,6 @@ AppsContainer::AppsContainer() : m_variableBoxController(&m_globalContext), m_examPopUpController(this), m_updateController(), - m_ledTimer(LedTimer()), m_batteryTimer(BatteryTimer(this)), m_suspendTimer(SuspendTimer(this)), m_backlightDimmingTimer(), @@ -230,11 +229,11 @@ Window * AppsContainer::window() { } int AppsContainer::numberOfContainerTimers() { - return 3+(GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate); + return 3; } Timer * AppsContainer::containerTimerAtIndex(int i) { - Timer * timers[4] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_ledTimer}; + Timer * timers[3] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer}; return timers[i]; } diff --git a/apps/apps_container.h b/apps/apps_container.h index eb1b75516..a6b343ea8 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -12,7 +12,6 @@ #include "variable_box_controller.h" #include "exam_pop_up_controller.h" #include "exam_pop_up_controller_delegate.h" -#include "led_timer.h" #include "battery_timer.h" #include "suspend_timer.h" #include "backlight_dimming_timer.h" @@ -69,7 +68,6 @@ private: VariableBoxController m_variableBoxController; ExamPopUpController m_examPopUpController; OnBoarding::UpdateController m_updateController; - LedTimer m_ledTimer; BatteryTimer m_batteryTimer; SuspendTimer m_suspendTimer; BacklightDimmingTimer m_backlightDimmingTimer; diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index c4821007f..47ab4629b 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -58,7 +58,10 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : AppsContainer * container = (AppsContainer *)controller->app()->container(); if (controller->isActivatingExamMode()) { container->reset(); + Ion::LED::setBlinking(0.5, true, false, false); + Ion::LED::setLockState(true); } else { + Ion::LED::setLockState(false); Ion::LED::setColor(KDColorBlack); } container->refreshPreferences(); diff --git a/apps/led_timer.cpp b/apps/led_timer.cpp deleted file mode 100644 index d462ca6c7..000000000 --- a/apps/led_timer.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "led_timer.h" - -LedTimer::LedTimer() : - Timer(1), - m_on(false) -{ -} - -bool LedTimer::fire() { - m_on = !m_on; - KDColor ledColor = m_on ? KDColorRed : KDColorBlack; - Ion::LED::setColor(ledColor); - return false; -} diff --git a/apps/led_timer.h b/apps/led_timer.h deleted file mode 100644 index 17f221e48..000000000 --- a/apps/led_timer.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef APPS_LED_TIMER_H -#define APPS_LED_TIMER_H - -#include - -class LedTimer : public Timer { -public: - LedTimer(); -private: - bool fire() override; - bool m_on; -}; - -#endif - diff --git a/build/config.mak b/build/config.mak index 2b6e610a3..4d4b73a68 100644 --- a/build/config.mak +++ b/build/config.mak @@ -7,6 +7,7 @@ EPSILON_VERSION ?= 1.6.0 EPSILON_ONBOARDING_APP ?= 1 EPSILON_SOFTWARE_UPDATE_PROMPT ?= 1 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings +EPSILON_LED_WHILE_CHARGING = 1 EPSILON_I18N ?= en fr es de pt EPSILON_GETOPT ?= 0 @@ -24,3 +25,4 @@ SFLAGS += -DDEBUG=$(DEBUG) SFLAGS += -DEPSILON_ONBOARDING_APP=$(EPSILON_ONBOARDING_APP) SFLAGS += -DEPSILON_SOFTWARE_UPDATE_PROMPT=$(EPSILON_SOFTWARE_UPDATE_PROMPT) SFLAGS += -DEPSILON_GETOPT=$(EPSILON_GETOPT) +SFLAGS += -DEPSILON_LED_WHILE_CHARGING=$(EPSILON_LED_WHILE_CHARGING) diff --git a/ion/include/ion/led.h b/ion/include/ion/led.h index 8ca251504..b2d40cad7 100644 --- a/ion/include/ion/led.h +++ b/ion/include/ion/led.h @@ -7,6 +7,15 @@ namespace Ion { namespace LED { void setColor(KDColor c); +void setBlinking(float blinkLength, bool red, bool green, bool blue); +void setCharging(bool isPluggedIn, bool isCharging); + +/* + * This is just a flag to see if we should mess with the LEDs on our own. + * Especially useful for keeping the LED blinking while in exam mode. + */ +bool getLockState(); +void setLockState(bool state); } } diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index aacb7215f..348aafafc 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -20,15 +20,20 @@ extern "C" { // Public Ion methods -/* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the - * optimizations chosen by the compiler. To prevent that and to gain in - * precision, we could use the controller cycle counter (Systick). */ - void Ion::msleep(long ms) { - for (volatile long i=0; i<8852*ms; i++) { - __asm volatile("nop"); - } + // We need a frequency high enough to not overflow the prescaler, + // which is 16 bits wide. + constexpr int TIM6_FREQ = 4*1000; + + Ion::Device::waitTIM6(Ion::Device::SYSBUS_FREQ / TIM6_FREQ, ms * TIM6_FREQ / 1000); } + +/* TODO: The delay method 'usleep' is currently dependent on the optimizations + * chosen by the compiler. To prevent that and to gain in precision, we could + * use the controller cycle counter (Systick). We can't use a regular timer + * (like TIM6) for this since setting it up takes a significant amount of time + * in these timescales. + */ void Ion::usleep(long us) { for (volatile long i=0; i<9*us; i++) { __asm volatile("nop"); @@ -265,8 +270,10 @@ void initClocks() { RCC.AHB3ENR()->setFSMCEN(true); // APB1 bus - // We're using TIM3 + // We're using TIM3 for the LEDs RCC.APB1ENR()->setTIM3EN(true); + // We're using TIM6 for sleeping + RCC.APB1ENR()->setTIM6EN(true); RCC.APB1ENR()->setPWREN(true); // APB2 bus @@ -283,8 +290,9 @@ void shutdownClocks() { // APB2 bus RCC.APB2ENR()->set(0x00008000); // Reset value - // AHB1 - RCC.APB1ENR()->set(0x00000400); + // APB1 + RCC.APB1ENR()->set(0x00000402); + RCC.APB1LPENR()->setTIM3LPEN(true); // Keep the LED going // AHB1 bus RCC.AHB1ENR()->set(0); // Reset value @@ -292,5 +300,31 @@ void shutdownClocks() { RCC.AHB3ENR()->setFSMCEN(false); } +void waitTIM6(unsigned short prescaler, long cycles) { + while (cycles > 0) { + // TIM6 counts up to 2^16-1, make sure we won't overflow the counter. + uint16_t iterCycles = (cycles > 0xFFFF ? 0xFFFF : cycles); + + // Initialize TIM6 + TIM6.PSC()->set(prescaler); + TIM6.CNT()->set(0); + TIM6.ARR()->set(iterCycles); + TIM6.EGR()->setUG(true); + TIM6.SR()->setUIF(false); + TIM6.CR1()->setCEN(true); + + // Wait until the timer elapses + do { + // TODO: Use interrupts instead of busy-waiting + __asm volatile("nop"); + } while (TIM6.SR()->getUIF() == false); + + // Stop TIM6 + TIM6.CR1()->setCEN(false); + + cycles -= iterCycles; + } +} + } } diff --git a/ion/src/device/device.h b/ion/src/device/device.h index b227f1aa7..4757ff3ba 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -4,6 +4,8 @@ namespace Ion { namespace Device { +constexpr int SYSBUS_FREQ = 96*1000*1000; + void init(); void shutdown(); @@ -23,6 +25,45 @@ void shutdownClocks(); constexpr static int SerialNumberLength = 16; void copySerialNumber(char * buffer); +void waitTIM6(unsigned short prescaler, long cycles); + +/* Pin | Role | Mode | Function + * -----+-------------------+-----------------------+---------- + * PA0 | Battery sensing | | + * PA2 | LCD D4 | Alternate Function 12 | FMSC_D4 + * PA3 | LCD D5 | Alternate Function 12 | FSMC_D5 + * PA4 | LCD D6 | Alternate Function 12 | FSMC_D6 + * PA5 | LCD D7 | Alternate Function 12 | FSMC_D7 + * PA6 | LED red | Alternate Function XX | TIM3_CH1 + * PA7 | LED green | Alternate Function XX | TIM3_CH2 + * PA9 | USB VBUS prob | Input, pulled down | + * PB0 | LED blue | Alternate Function XX | TIM3_CH3 + * PB1 | Keyboard row A | Output, open-drain | + * PB2 | Keyboard row B | Output, open-drain | + * PB3 | Keyboard row C | Output, open-drain | + * PB4 | Keyboard row D | Output, open-drain | + * PB5 | Keyboard row E | Output, open-drain | + * PB6 | Keyboard row F | Output, open-drain | + * PB7 | Keyboard row G | Output, open-drain | + * PB8 | Keyboard row H | Output, open-drain | + * PB9 | Keyboard row I | Output, open-drain | + * PB10 | Keyboard row J | Output, open-drain | + * PB14 | LCD D0 | Alternate Function 12 | FSMC_D0 + * PC0 | Keyboard column 1 | Input, pulled-up | + * PC1 | Keyboard column 2 | Input, pulled-up | + * PC3 | LCD data/command | Alternate Function 12 | FSMC_A0 + * PC4 | LCD chip select | Alternate Function 12 | FSMC_NE4 + * PC5 | LCD read signal | Alternate Function 12 | FSMC_NOE + * PC6 | LCD D1 | Alternate Function 12 | FSMC_D7 + * PC9 | LCD backlight | Alternate Function 12 | TIM3_CH4 + * PC11 | LCD D2 | Alternate Function 12 | FSMC_D2 + * PC12 | LCD D3 | Alternate Function 12 | FSMC_D3 + * PC13 | Keyboard column 3 | Input, pulled-up | + * PC14 | Keyboard column 4 | Input, pulled-up | + * PC15 | Keyboard column 5 | Input, pulled-up | + * PD2 | LCD write signal | Alternate Function 12 | FSMC_NWE + */ + } } diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index f4c7037ee..3557ffe79 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -1,16 +1,63 @@ #include #include +#include "device.h" #include "led.h" #include "regs/regs.h" // Public Ion::LED methods void Ion::LED::setColor(KDColor c) { + if (getLockState()) { + return; + } + + initTimer(Ion::LED::Device::Mode::PWM); + + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, true); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, true); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, true); + TIM3.CCR2()->set(Device::dutyCycleForUInt8(c.red())); TIM3.CCR3()->set(Device::dutyCycleForUInt8(c.blue())); TIM3.CCR4()->set(Device::dutyCycleForUInt8(c.green())); } +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { + if (getLockState()) { + return; + } + + initTimer(Ion::LED::Device::Mode::BLINK, blinkPeriod); + + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, red); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, green); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, blue); +} + +void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { + if (!isPluggedIn) { + Ion::LED::setColor(KDColorBlack); + } + else { + if (isCharging) { + Ion::LED::setColor(KDColorRed); + } + else { + Ion::LED::setColor(KDColorGreen); + } + } +} + +static bool lockState = false; + +bool Ion::LED::getLockState() { + return lockState; +} + +void Ion::LED::setLockState(bool state) { + lockState = state; +} + // Private Ion::Device::LED methods namespace Ion { @@ -19,12 +66,9 @@ namespace Device { void init() { initGPIO(); - initTimer(); } void shutdown() { - shutdownTimer(); - shutdownGPIO(); } void initGPIO() { @@ -44,7 +88,56 @@ void shutdownGPIO() { } } -void initTimer() { +void initTimer(Mode mode, float blinkPeriod) { + constexpr int TIM3_FREQ = 4*1000; + + /* Pulse width modulation mode allows you to generate a signal with a + * frequency determined by the value of the TIMx_ARR register and a duty cycle + * determined by the value of the TIMx_CCRx register. */ + switch (mode) { + case Ion::LED::Device::Mode::PWM: + /* Let's set the prescaler to 1. Increasing the prescaler would slow down the + * modulation, which can be useful when debugging. */ + TIM3.PSC()->set(1); + TIM3.ARR()->set(PWMPeriod); + TIM3.CCR2()->set(0); + TIM3.CCR3()->set(0); + TIM3.CCR4()->set(0); + break; + case Ion::LED::Device::Mode::BLINK: + /* We still want to do PWM, but at a rate slow enough to blink. */ + TIM3.PSC()->set(Ion::Device::SYSBUS_FREQ / TIM3_FREQ); + TIM3.ARR()->set(blinkPeriod * TIM3_FREQ); + TIM3.CCR2()->set(blinkPeriod * TIM3_FREQ / 2); + TIM3.CCR3()->set(blinkPeriod * TIM3_FREQ / 2); + TIM3.CCR4()->set(blinkPeriod * TIM3_FREQ / 2); + break; + } + + // Set Channels 2-4 as outputs, PWM mode 1 + TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); + + // Output preload enable for channels 2-4 + TIM3.CCMR()->setOC2PE(true); + TIM3.CCMR()->setOC3PE(true); + TIM3.CCMR()->setOC4PE(true); + + // Auto-reload preload enable + TIM3.CR1()->setARPE(true); + + // Enable Capture/Compare for channel 2 to 4 + TIM3.CCER()->setCC2E(true); + TIM3.CCER()->setCC3E(true); + TIM3.CCER()->setCC4E(true); + + TIM3.BDTR()->setMOE(true); + + TIM3.CR1()->setCEN(true); +} + +void initTimerColor() { /* Let's set the prescaler to 1. Increasing the prescaler would slow down the * modulation, which can be useful when debugging. */ TIM3.PSC()->set(1); @@ -57,11 +150,6 @@ void initTimer() { TIM3.CCR3()->set(0); TIM3.CCR4()->set(0); - // Set Channels 2-4 as outputs, PWM mode 1 - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); - // Output preload enable for channels 2-4 TIM3.CCMR()->setOC2PE(true); TIM3.CCMR()->setOC3PE(true); @@ -81,9 +169,23 @@ void initTimer() { } void shutdownTimer() { - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::ForceInactive); + setColorStatus(Ion::LED::Device::Color::RED, false); + setColorStatus(Ion::LED::Device::Color::GREEN, false); + setColorStatus(Ion::LED::Device::Color::BLUE, false); +} + +void setColorStatus(Color color, bool enable) { + switch (color) { + case Ion::LED::Device::Color::RED: + TIM3.CCMR()->setOC2M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + case Ion::LED::Device::Color::GREEN: + TIM3.CCMR()->setOC4M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + case Ion::LED::Device::Color::BLUE: + TIM3.CCMR()->setOC3M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + } } void enforceState(bool red, bool green, bool blue) { diff --git a/ion/src/device/led.h b/ion/src/device/led.h index b4b368c5e..19a918366 100644 --- a/ion/src/device/led.h +++ b/ion/src/device/led.h @@ -14,14 +14,26 @@ namespace Device { * PC7 | LED red | Alternate Function 2 | TIM3_CH2 */ +enum Mode { + PWM, + BLINK +} ; + +enum Color { + RED, + GREEN, + BLUE +} ; + void init(); void shutdown(); +void setColorStatus(Color color, bool enable); /* This call bypasses the timer, and immediately enforces a given LED state. */ void enforceState(bool red, bool green, bool blue); void initGPIO(); void shutdownGPIO(); -void initTimer(); +void initTimer(Mode mode, float blinkPeriod = 0); void shutdownTimer(); constexpr static GPIOPin RGBPins[] = { diff --git a/ion/src/device/power.cpp b/ion/src/device/power.cpp index 948b9eb89..0d0cacf93 100644 --- a/ion/src/device/power.cpp +++ b/ion/src/device/power.cpp @@ -21,22 +21,22 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { PWR.CR()->setLPDS(true); // Turn the regulator off. Takes longer to wake up. PWR.CR()->setFPDS(true); // Put the flash to sleep. Takes longer to wake up. - CM4.SCR()->setSLEEPDEEP(true); + CM4.SCR()->setSLEEPDEEP(!Ion::LED::getLockState()); - WakeUp::Device::onUSBPlugging(); -#if LED_WHILE_CHARGING - WakeUp::Device::onChargingEvent(); -#endif while (1) { -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING /* Update LEDS * if the standby mode was stopped due to a "stop charging" event, we wait * a while to be sure that the plug state of the USB is up-to-date. */ msleep(200); - LED::Device::enforceState(Battery::isCharging(), USB::isPlugged(), false); + Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif WakeUp::Device::onPowerKeyDown(); + WakeUp::Device::onUSBPlugging(); +#if EPSILON_LED_WHILE_CHARGING + WakeUp::Device::onChargingEvent(); +#endif Device::shutdownClocks(); @@ -47,7 +47,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { * to clear it, and then a second WFE to wait for a _new_ event. */ asm("sev"); asm("wfe"); - msleep(1); + asm("nop"); asm("wfe"); Device::initClocks(); diff --git a/ion/src/device/regs/pwr.h b/ion/src/device/regs/pwr.h index 089d72e18..60fe325ff 100644 --- a/ion/src/device/regs/pwr.h +++ b/ion/src/device/regs/pwr.h @@ -9,11 +9,19 @@ public: public: REGS_BOOL_FIELD(LPDS, 0); REGS_BOOL_FIELD(PPDS, 1); + REGS_BOOL_FIELD(DBP, 8); REGS_BOOL_FIELD(FPDS, 9); }; + class CSR : Register32 { + public: + REGS_BOOL_FIELD(BRE, 9); + REGS_BOOL_FIELD_R(BRR, 3); + }; + constexpr PWR() {}; REGS_REGISTER_AT(CR, 0x00); + REGS_REGISTER_AT(CSR, 0x04); private: constexpr uint32_t Base() const { return 0x40007000; diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 4ef6ffbea..576a98c5f 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -7,11 +7,16 @@ class RCC { public: class CR : public Register32 { public: - REGS_BOOL_FIELD(HSION, 0); - REGS_BOOL_FIELD(HSEON, 16); - REGS_BOOL_FIELD(HSERDY, 17); - REGS_BOOL_FIELD(PLLON, 24); + REGS_BOOL_FIELD_R(PLLI2SRDY, 27); + REGS_BOOL_FIELD(PLLI2SON, 26); REGS_BOOL_FIELD(PLLRDY, 25); + REGS_BOOL_FIELD(PLLON, 24); + REGS_BOOL_FIELD(CSSON, 19); + REGS_BOOL_FIELD(HSEBYP, 18); + REGS_BOOL_FIELD_R(HSERDY, 17); + REGS_BOOL_FIELD(HSEON, 16); + REGS_BOOL_FIELD_R(HSIRDY, 1); + REGS_BOOL_FIELD(HSION, 0); }; class PLLCFGR : public Register32 { @@ -56,7 +61,9 @@ public: AHBDividedBy8 = 6, AHBDividedBy16 = 7 }; - void setPPRE1(APBPrescaler p) volatile { setBitRange(12, 10, (uint32_t)p); } + void setPPRE2(APBPrescaler r) volatile { setBitRange(15, 13, (uint32_t)r); } + void setPPRE1(APBPrescaler r) volatile { setBitRange(12, 10, (uint32_t)r); } + REGS_FIELD(RTCPRE, uint8_t, 4, 0); }; class AHB1ENR : public Register32 { @@ -90,7 +97,16 @@ public: class APB1ENR : public Register32 { public: using Register32::Register32; + REGS_BOOL_FIELD(TIM2EN, 0); REGS_BOOL_FIELD(TIM3EN, 1); + REGS_BOOL_FIELD(TIM4EN, 2); + REGS_BOOL_FIELD(TIM5EN, 3); + REGS_BOOL_FIELD(TIM6EN, 4); + REGS_BOOL_FIELD(TIM7EN, 5); + REGS_BOOL_FIELD(TIM12EN, 6); + REGS_BOOL_FIELD(TIM13EN, 7); + REGS_BOOL_FIELD(TIM14EN, 8); + REGS_BOOL_FIELD(RTCAPB, 10); REGS_BOOL_FIELD(SPI3EN, 15); REGS_BOOL_FIELD(USART3EN, 18); REGS_BOOL_FIELD(PWREN, 28); @@ -100,11 +116,52 @@ public: public: using Register32::Register32; REGS_BOOL_FIELD(TIM1EN, 0); + REGS_BOOL_FIELD(TIM8EN, 1); REGS_BOOL_FIELD(USART1EN, 4); REGS_BOOL_FIELD(ADC1EN, 8); REGS_BOOL_FIELD(SDIOEN, 11); REGS_BOOL_FIELD(SPI1EN, 12); REGS_BOOL_FIELD(SYSCFGEN, 14); + REGS_BOOL_FIELD(TIM9EN, 16); + REGS_BOOL_FIELD(TIM10EN, 17); + REGS_BOOL_FIELD(TIM11EN, 18); + }; + + class APB1LPENR : public Register32 { + public: + using Register32::Register32; + REGS_BOOL_FIELD(TIM2LPEN, 0); + REGS_BOOL_FIELD(TIM3LPEN, 1); + REGS_BOOL_FIELD(TIM4LPEN, 2); + REGS_BOOL_FIELD(TIM5LPEN, 3); + REGS_BOOL_FIELD(TIM6LPEN, 4); + REGS_BOOL_FIELD(TIM7LPEN, 5); + REGS_BOOL_FIELD(TIM12LPEN, 6); + REGS_BOOL_FIELD(TIM13LPEN, 7); + REGS_BOOL_FIELD(TIM14LPEN, 8); + REGS_BOOL_FIELD(RTCAPBEN, 10); + REGS_BOOL_FIELD(SPI3LPEN, 15); + REGS_BOOL_FIELD(USART3LPEN, 18); + REGS_BOOL_FIELD(PWRLPEN, 28); + }; + + class BDCR : public Register32 { + public: + REGS_BOOL_FIELD(BDRST, 16); + REGS_BOOL_FIELD(RTCEN, 15); + enum class RTCSel { + RTC_NoClock = 0, + RTC_LSEClock = 1, + RTC_LSIClock = 2, + RTC_HSEClock = 3 + }; + void setRTCSel(RTCSel s) volatile { setBitRange(9, 8, (uint32_t)s); } + }; + + class CSR : public Register32 { + public: + REGS_BOOL_FIELD(LSION, 0); + REGS_BOOL_FIELD_R(LSIRDY, 1); }; class DCKCFGR2 : Register32 { @@ -122,6 +179,9 @@ public: REGS_REGISTER_AT(AHB3ENR, 0x38); REGS_REGISTER_AT(APB1ENR, 0x40); REGS_REGISTER_AT(APB2ENR, 0x44); + REGS_REGISTER_AT(APB1LPENR, 0x60); + REGS_REGISTER_AT(BDCR, 0x70); + REGS_REGISTER_AT(CSR, 0x74); REGS_REGISTER_AT(DCKCFGR2, 0x94); private: constexpr uint32_t Base() const { diff --git a/ion/src/device/regs/regs.h b/ion/src/device/regs/regs.h index 4f7cd9d2e..0c8062d0e 100644 --- a/ion/src/device/regs/regs.h +++ b/ion/src/device/regs/regs.h @@ -15,6 +15,7 @@ #include "rcc.h" #include "rng.h" #include "otg.h" +#include "rtc.h" #include "sdio.h" #include "spi.h" #include "syscfg.h" diff --git a/ion/src/device/regs/rtc.h b/ion/src/device/regs/rtc.h new file mode 100644 index 000000000..3a2007dd1 --- /dev/null +++ b/ion/src/device/regs/rtc.h @@ -0,0 +1,99 @@ +#ifndef REGS_RTC_H +#define REGS_RTC_H + +#include "register.h" + +class RTC { +public: + class TR : public Register32 { + public: + using Register32::Register32; + REGS_BOOL_FIELD(PM, 22); + REGS_FIELD(HT, uint8_t, 21, 20); + REGS_FIELD(HU, uint8_t, 19, 16); + REGS_FIELD(MNT, uint8_t, 14, 12); + REGS_FIELD(MNU, uint8_t, 11, 8); + REGS_FIELD(ST, uint8_t, 6, 4); + REGS_FIELD(SU, uint8_t, 3, 0); + }; + + class DR : public Register32 { + public: + using Register32::Register32; + REGS_FIELD(YT, uint8_t, 23, 20); + REGS_FIELD(YU, uint8_t, 19, 16); + REGS_FIELD(WDU, uint8_t, 15, 13); + REGS_FIELD(MT, uint8_t, 12, 12); + REGS_FIELD(MU, uint8_t, 11, 8); + REGS_FIELD(DT, uint8_t, 5, 4); + REGS_FIELD(DU, uint8_t, 3, 0); + }; + + class CR : Register32 { + public: + REGS_BOOL_FIELD(COE, 23); + REGS_FIELD(OSEL, uint8_t, 22, 21); + REGS_BOOL_FIELD(POL, 20); + REGS_BOOL_FIELD(COSEL, 19); + REGS_BOOL_FIELD(BKP, 18); + REGS_BOOL_FIELD_W(SUB1H, 17); + REGS_BOOL_FIELD_W(ADD1H, 16); + REGS_BOOL_FIELD(TSIE, 15); + REGS_BOOL_FIELD(WUTIE, 14); + REGS_BOOL_FIELD(ALRBIE, 13); + REGS_BOOL_FIELD(ALRAIE, 12); + REGS_BOOL_FIELD(TSE, 11); + REGS_BOOL_FIELD(WUTE, 10); + REGS_BOOL_FIELD(ALRBE, 9); + REGS_BOOL_FIELD(ALRAE, 8); + REGS_BOOL_FIELD(DCE, 7); + REGS_BOOL_FIELD(FMT, 6); + REGS_BOOL_FIELD(BYPSHAD, 5); + REGS_BOOL_FIELD(REFCKON, 4); + REGS_BOOL_FIELD(TSEDGE, 3); + REGS_FIELD(WUCKSEL, uint8_t, 2, 0); + }; + + class ISR : Register32 { + public: + REGS_BOOL_FIELD_R(RECALPF, 16); + REGS_BOOL_FIELD(INIT, 7); + REGS_BOOL_FIELD_R(INITF, 6); + REGS_BOOL_FIELD(RSF, 5); + REGS_BOOL_FIELD_R(INITS, 4); + }; + + class PRER : public Register32 { + public: + using Register32::Register32; + REGS_FIELD(PREDIV_A, uint8_t, 22, 16); + REGS_FIELD(PREDIV_S, uint16_t, 14, 0); + }; + + class WPR : Register32 { + public: + REGS_FIELD_W(KEY, uint8_t, 7, 0); + }; + + class CALR : Register32 { + public: + REGS_FIELD(CALM, uint8_t, 8, 0); + }; + + constexpr RTC() {} + REGS_REGISTER_AT(TR, 0x00); + REGS_REGISTER_AT(DR, 0x04); + REGS_REGISTER_AT(CR, 0x08); + REGS_REGISTER_AT(ISR, 0x0C); + REGS_REGISTER_AT(PRER, 0x10); + REGS_REGISTER_AT(WPR, 0x24); + REGS_REGISTER_AT(CALR, 0x3C); +private: + constexpr uint32_t Base() const { + return 0x40002800; + }; +}; + +constexpr RTC RTC; + +#endif diff --git a/ion/src/device/regs/tim.h b/ion/src/device/regs/tim.h index c614c82f1..fc285941d 100644 --- a/ion/src/device/regs/tim.h +++ b/ion/src/device/regs/tim.h @@ -3,14 +3,40 @@ #include "register.h" +template class TIM { public: class CR1 : Register16 { public: REGS_BOOL_FIELD(CEN, 0); + REGS_BOOL_FIELD(URS, 1); + REGS_BOOL_FIELD(UDIS, 1); REGS_BOOL_FIELD(ARPE, 7); }; + class SR : Register16 { + public: + REGS_BOOL_FIELD(CC4OF, 12); + REGS_BOOL_FIELD(CC3OF, 11); + REGS_BOOL_FIELD(CC2OF, 10); + REGS_BOOL_FIELD(CC1OF, 9); + REGS_BOOL_FIELD(CC4IF, 4); + REGS_BOOL_FIELD(CC3IF, 3); + REGS_BOOL_FIELD(CC2IF, 2); + REGS_BOOL_FIELD(CC1IF, 1); + REGS_BOOL_FIELD(UIF, 0); + }; + + class EGR : Register16 { + public: + REGS_BOOL_FIELD(UG, 0); + }; + + class DIER : Register16 { + public: + REGS_BOOL_FIELD(UIE, 0); + }; + 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 @@ -24,6 +50,12 @@ public: INPUT_TI1 = 2, INPUT_TRC = 3 }; + enum class CC4S : uint8_t { + OUTPUT = 0, + INPUT_TI4 = 1, + INPUT_TI3 = 2, + INPUT_TRC = 3 + }; enum class OCM : uint8_t { Frozen = 0, ActiveOnMatch = 1, @@ -44,6 +76,8 @@ public: REGS_TYPE_FIELD(OC2M, 14, 12); REGS_BOOL_FIELD(OC3PE, 35); REGS_TYPE_FIELD(OC3M, 38, 36); + REGS_TYPE_FIELD(CC4S, 41, 40); + REGS_FIELD(IC4PSC, uint8_t, 43, 42); REGS_BOOL_FIELD(OC4PE, 43); REGS_TYPE_FIELD(OC4M, 46, 44); }; @@ -61,17 +95,33 @@ public: REGS_BOOL_FIELD(MOE, 15); }; + class CNT : public RegisterWidth {}; class PSC : public Register16 {}; - class ARR : public Register16 {}; - class CCR1 : public Register16 {}; - class CCR2 : public Register16 {}; - class CCR3 : public Register16 {}; - class CCR4 : public Register16 {}; + class ARR : public RegisterWidth {}; + class CCR1 : public RegisterWidth {}; + class CCR2 : public RegisterWidth {}; + class CCR3 : public RegisterWidth {}; + class CCR4 : public RegisterWidth {}; + + class OR : Register16 { + public: + enum class TI4_RMP { + GPIO = 0, + LSI = 1, + LSE = 2, + WAKEUP = 3 + }; + void setTI4RMP(TI4_RMP r) volatile { setBitRange(7, 6, (uint32_t)r); } + }; constexpr TIM(int i) : m_index(i) {} REGS_REGISTER_AT(CR1, 0x0); + REGS_REGISTER_AT(DIER, 0xC); + REGS_REGISTER_AT(SR, 0x10); + REGS_REGISTER_AT(EGR, 0x14); REGS_REGISTER_AT(CCMR, 0x18); REGS_REGISTER_AT(CCER, 0x20); + REGS_REGISTER_AT(CNT, 0x24); REGS_REGISTER_AT(PSC, 0x28); REGS_REGISTER_AT(ARR, 0x2C); REGS_REGISTER_AT(CCR1, 0x34); @@ -79,14 +129,35 @@ public: REGS_REGISTER_AT(CCR3, 0x3C); REGS_REGISTER_AT(CCR4, 0x40); REGS_REGISTER_AT(BDTR, 0x44); + REGS_REGISTER_AT(OR, 0x50); private: constexpr uint32_t Base() const { - return (m_index == 1 ? 0x40010000 : 0x40000000 + 0x400*(m_index-2)); - }; + return (m_index == 1 ? 0x40010000 : + (m_index <= 7 ? 0x40000000 + 0x400*(m_index-2) : + (m_index == 8 ? 0x40010400 : + (m_index <= 11 ? 0x40014000 + 0x400*(m_index-9) : + 0x40001800 + 0x400*(m_index-12) + ) + ) + ) + ); + } int m_index; }; -constexpr TIM TIM1(1); -constexpr TIM TIM3(3); +constexpr TIM TIM1(1); +constexpr TIM TIM2(2); +constexpr TIM TIM3(3); +constexpr TIM TIM4(4); +constexpr TIM TIM5(5); +constexpr TIM TIM6(6); +constexpr TIM TIM7(7); +constexpr TIM TIM8(8); +constexpr TIM TIM9(9); +constexpr TIM TIM10(10); +constexpr TIM TIM11(11); +constexpr TIM TIM12(12); +constexpr TIM TIM13(13); +constexpr TIM TIM14(14); #endif diff --git a/ion/src/device/wakeup.cpp b/ion/src/device/wakeup.cpp index d54ea0f83..3582d6ad3 100644 --- a/ion/src/device/wakeup.cpp +++ b/ion/src/device/wakeup.cpp @@ -31,7 +31,7 @@ void onUSBPlugging() { SYSCFG.EXTICR3()->setEXTI(USB::Device::VbusPin.pin(), USB::Device::VbusPin.group()); EXTI.EMR()->set(USB::Device::VbusPin.pin(), true); -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING EXTI.FTSR()->set(USB::Device::VbusPin.pin(), true); #endif EXTI.RTSR()->set(USB::Device::VbusPin.pin(), true); diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index 12452f37b..985b049a2 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -2,3 +2,16 @@ void Ion::LED::setColor(KDColor c) { } + +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { +} + +void Ion::LED::setCharging(bool isPlugged, bool isCharging) { +} + +bool Ion::LED::getLockState() { + return false; +} + +void Ion::LED::setLockState(bool state) { +} diff --git a/ion/src/simulator/led.cpp b/ion/src/simulator/led.cpp index a48d4ca13..985b049a2 100644 --- a/ion/src/simulator/led.cpp +++ b/ion/src/simulator/led.cpp @@ -3,4 +3,15 @@ void Ion::LED::setColor(KDColor c) { } +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { +} +void Ion::LED::setCharging(bool isPlugged, bool isCharging) { +} + +bool Ion::LED::getLockState() { + return false; +} + +void Ion::LED::setLockState(bool state) { +}