[ion] Change LED API

This commit is contained in:
Émilie Feral
2018-08-23 16:05:52 +02:00
parent 5eb18c601c
commit 4613dd9d8f
10 changed files with 97 additions and 158 deletions

View File

@@ -58,10 +58,9 @@ 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);
Ion::LED::setColor(KDColorRed);
Ion::LED::setBlinking(1.0f, 0.1f);
} else {
Ion::LED::setLockState(false);
Ion::LED::setColor(KDColorBlack);
}
container->refreshPreferences();

View File

@@ -6,16 +6,9 @@
namespace Ion {
namespace LED {
KDColor getColor();
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);
void setBlinking(float period, float dutyCycle);
}
}

View File

@@ -169,7 +169,7 @@ void initPeripherals() {
SWD::Device::init();
}
void shutdownPeripherals() {
void shutdownPeripherals(bool keepLEDAwake) {
SWD::Device::shutdown();
Console::Device::shutdown();
#if USE_SD_CARD
@@ -177,7 +177,9 @@ void shutdownPeripherals() {
#endif
USB::Device::shutdown();
Battery::Device::shutdown();
LED::Device::shutdown();
if (!keepLEDAwake) {
LED::Device::shutdown();
}
Keyboard::Device::shutdown();
Backlight::Device::shutdown();
Display::Device::shutdown();
@@ -279,16 +281,33 @@ void initClocks() {
RCC.APB2ENR()->set(apb2enr);
}
void shutdownClocks() {
void shutdownClocks(bool keepLEDAwake) {
// APB2 bus
RCC.APB2ENR()->set(0x00008000); // Reset value
// APB1
RCC.APB1ENR()->set(0x00000402);
RCC.APB1LPENR()->setTIM3LPEN(true); // Keep the LED going
if (keepLEDAwake) {
/* TODO: enter sleep mode even if the LED is used and enable LED in low
* power mode. */
// Keep the LED going: peripheral clock enable in low power mode register
/*RCC.APB1LPENR()->setTIM3LPEN(true);
RCC.AHB1LPENR()->setGPIOBLPEN(true);
RCC.AHB1LPENR()->setGPIOCLPEN(true);*/
// AHB1 bus
RCC.AHB1ENR()->set(0); // Reset value
// APB1
class RCC::APB1ENR apb1enr(0x00000400);
apb1enr.setTIM3EN(true);
RCC.APB1ENR()->set(apb1enr);
// AHB1 bus
class RCC::AHB1ENR ahb1enr(0); // Reset value
ahb1enr.setGPIOBEN(true);
ahb1enr.setGPIOCEN(true);
RCC.AHB1ENR()->set(ahb1enr);
} else {
// APB1
RCC.APB1ENR()->set(0x00000400);
// AHB1 bus
RCC.AHB1ENR()->set(0); // Reset value
}
RCC.AHB3ENR()->setFSMCEN(false);
}

View File

@@ -14,9 +14,9 @@ void coreReset();
void jumpReset();
void initPeripherals();
void shutdownPeripherals();
void shutdownPeripherals(bool keepLEDAwake = false);
void initClocks();
void shutdownClocks();
void shutdownClocks(bool keepLEDAwake = false);
/* The serial number is 96 bits long. That's equal to 16 digits in base 64. We
* expose a convenient "copySerialNumber" routine which can be called without

View File

@@ -6,35 +6,32 @@
// Public Ion::LED methods
void Ion::LED::setColor(KDColor c) {
if (getLockState()) {
return;
}
static KDColor sLedColor = KDColorBlack;
initTimer(Ion::LED::Device::Mode::PWM);
KDColor Ion::LED::getColor() {
return sLedColor;
}
void Ion::LED::setColor(KDColor c) {
sLedColor = c;
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()));
constexpr float maxColorValue = (float)((1 << 8) -1);
Device::setPeriodAndDutyCycles(Device::Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue);
}
void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) {
if (getLockState()) {
return;
}
void Ion::LED::setBlinking(float period, float dutyCycle) {
Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, sLedColor.red() > 0);
Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, sLedColor.green() > 0);
Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, sLedColor.blue() > 0);
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);
Device::setPeriodAndDutyCycles(Device::Mode::BLINK, dutyCycle, dutyCycle, dutyCycle, period);
}
void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) {
/*void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) {
if (!isPluggedIn) {
Ion::LED::setColor(KDColorBlack);
}
@@ -46,17 +43,7 @@ void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) {
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
@@ -66,9 +53,12 @@ namespace Device {
void init() {
initGPIO();
initTimer();
}
void shutdown() {
shutdownTimer();
shutdownGPIO();
}
void initGPIO() {
@@ -88,68 +78,7 @@ void shutdownGPIO() {
}
}
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<Register16>::CCMR::OCM::PWM1);
TIM3.CCMR()->setOC3M(TIM<Register16>::CCMR::OCM::PWM1);
TIM3.CCMR()->setOC4M(TIM<Register16>::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);
/* 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. */
TIM3.ARR()->set(PWMPeriod);
TIM3.CCR2()->set(0);
TIM3.CCR3()->set(0);
TIM3.CCR4()->set(0);
void initTimer() {
// Output preload enable for channels 2-4
TIM3.CCMR()->setOC2PE(true);
TIM3.CCMR()->setOC3PE(true);
@@ -174,6 +103,33 @@ void shutdownTimer() {
setColorStatus(Ion::LED::Device::Color::BLUE, false);
}
/* 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. */
void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period) {
constexpr int TIM3_FREQ = 4*1000;
switch (mode) {
case 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);
period = PWMPeriod;
break;
case 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(period * TIM3_FREQ);
period *= TIM3_FREQ; // as we pre-scaled, we update the period
break;
}
TIM3.CCR2()->set(dutyCycleRed*period);
TIM3.CCR3()->set(dutyCycleBlue*period);
TIM3.CCR4()->set(dutyCycleGreen*period);
}
void setColorStatus(Color color, bool enable) {
switch (color) {
case Ion::LED::Device::Color::RED:
@@ -188,7 +144,7 @@ void setColorStatus(Color color, bool enable) {
}
}
void enforceState(bool red, bool green, bool blue) {
/*void enforceState(bool red, bool green, bool blue) {
bool states[3] = {red, green, blue};
for (int i=0; i<3; i++) {
GPIOPin p = RGBPins[i];
@@ -200,7 +156,7 @@ void enforceState(bool red, bool green, bool blue) {
p.group().PUPDR()->setPull(p.pin(), GPIO::PUPDR::Pull::None);
}
}
}
}*/
}
}

View File

@@ -17,23 +17,24 @@ namespace Device {
enum Mode {
PWM,
BLINK
} ;
};
enum Color {
RED,
GREEN,
BLUE
} ;
};
void init();
void shutdown();
void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period = 0.0f);
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 enforceState(bool red, bool green, bool blue);
void initGPIO();
void shutdownGPIO();
void initTimer(Mode mode, float blinkPeriod = 0);
void initTimer();
void shutdownTimer();
constexpr static GPIOPin RGBPins[] = {
@@ -43,11 +44,6 @@ constexpr static GPIOPin RGBPins[] = {
constexpr uint16_t PWMPeriod = 40000;
inline uint16_t dutyCycleForUInt8(uint8_t value) {
/* This function is a linear function from colors [0->255] to duty cycles [0->PWMPeriod].*/
return ((uint32_t)value)*(PWMPeriod/255);
}
}
}
}

View File

@@ -9,6 +9,7 @@
#include "regs/regs.h"
void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
bool isLEDActive = Ion::LED::getColor() != KDColorBlack;
if (checkIfPowerKeyReleased) {
/* Wait until power is released to avoid restarting just after suspending */
bool isPowerDown = true;
@@ -17,11 +18,11 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
isPowerDown = scan.keyDown(Keyboard::Key::B2);
}
}
Device::shutdownPeripherals();
Device::shutdownPeripherals(isLEDActive);
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(!Ion::LED::getLockState());
CM4.SCR()->setSLEEPDEEP(!isLEDActive);
while (1) {
#if EPSILON_LED_WHILE_CHARGING
@@ -29,7 +30,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
* 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);
Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging());
//Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging());
#endif
WakeUp::Device::onPowerKeyDown();
@@ -38,7 +39,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
WakeUp::Device::onChargingEvent();
#endif
Device::shutdownClocks();
Device::shutdownClocks(isLEDActive);
/* To enter sleep, we need to issue a WFE instruction, which waits for the
* event flag to be set and then clears it. However, the event flag might

View File

@@ -1,17 +1,9 @@
#include <ion/led.h>
void Ion::LED::setColor(KDColor c) {
KDColor getColor() {
return KDColorBlack;
}
void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) {
}
void setColor(KDColor c) {}
void Ion::LED::setCharging(bool isPlugged, bool isCharging) {
}
bool Ion::LED::getLockState() {
return false;
}
void Ion::LED::setLockState(bool state) {
}
void setBlinking(float period, float dutyCycle) {}

View File

@@ -1,6 +1,5 @@
objs += $(addprefix ion/src/simulator/, \
init.o\
led.o\
)
objs += $(addprefix ion/src/simulator/boot/, main.o)
@@ -17,6 +16,7 @@ objs += $(addprefix ion/src/shared/, \
dummy/backlight.o \
dummy/battery.o \
dummy/fcc_id.o \
dummy/led.o \
dummy/serial_number.o \
dummy/usb.o \
)

View File

@@ -1,17 +0,0 @@
#include <ion/led.h>
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) {
}