[ion] Clean LED API

This commit is contained in:
Émilie Feral
2018-08-27 09:52:17 +02:00
parent 7d26412afb
commit 3177b26f30
7 changed files with 46 additions and 98 deletions

View File

@@ -59,7 +59,7 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) :
if (controller->isActivatingExamMode()) {
container->reset();
Ion::LED::setColor(KDColorRed);
Ion::LED::setBlinking(1.0f, 0.1f);
Ion::LED::setBlinking(1000, 0.1f);
} else {
Ion::LED::setColor(KDColorBlack);
}

View File

@@ -8,7 +8,7 @@ namespace LED {
KDColor getColor();
void setColor(KDColor c);
void setBlinking(float period, float dutyCycle);
void setBlinking(uint16_t periodInMilliseconds, float dutyCycle);
}
}

View File

@@ -285,29 +285,17 @@ void shutdownClocks(bool keepLEDAwake) {
// APB2 bus
RCC.APB2ENR()->set(0x00008000); // Reset value
// APB1
class RCC::APB1ENR apb1enr(0x00000400); // Reset value
// AHB1 bus
class RCC::AHB1ENR ahb1enr(0); // Reset value
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);*/
// 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.APB1ENR()->set(apb1enr);
RCC.AHB1ENR()->set(ahb1enr);
RCC.AHB3ENR()->setFSMCEN(false);
}

View File

@@ -4,8 +4,6 @@
namespace Ion {
namespace Device {
constexpr int SYSBUS_FREQ = 96*1000*1000;
void init();
void shutdown();

View File

@@ -15,41 +15,28 @@ KDColor Ion::LED::getColor() {
void Ion::LED::setColor(KDColor c) {
sLedColor = c;
/* Active RGB colors */
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);
/* Active all RGB colors */
TIM3.CCMR()->setOC2M(TIM<Register16>::CCMR::OCM::PWM1);
TIM3.CCMR()->setOC4M(TIM<Register16>::CCMR::OCM::PWM1);
TIM3.CCMR()->setOC3M(TIM<Register16>::CCMR::OCM::PWM1);
/* Set the PWM duty cycles to display the right color */
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 period, float dutyCycle) {
void Ion::LED::setBlinking(uint16_t period, float dutyCycle) {
/* We want to use the PWM at a slow rate to display a seeable blink.
* Consequently, we do not use PWM to display the right color anymore.
* Instead we 'project the color on 3 bits' : RED LED is active or not etc. */
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);
* Consequently, we do not use PWM to display the right color anymore but to
* blink. We cannot use the PWM to display the exact color so we 'project the
* color on 3 bits' : all colors have 2 states - active or not. */
TIM3.CCMR()->setOC2M(sLedColor.red() > 0 ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
TIM3.CCMR()->setOC4M(sLedColor.green() > 0 ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
TIM3.CCMR()->setOC3M(sLedColor.blue() > 0 ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
Device::setPeriodAndDutyCycles(Device::Mode::BLINK, dutyCycle, dutyCycle, dutyCycle, period);
Device::setPeriodAndDutyCycles(Device::Mode::Blink, dutyCycle, dutyCycle, dutyCycle, period);
}
/*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);
}
}
}*/
// Private Ion::Device::LED methods
namespace Ion {
@@ -103,30 +90,36 @@ void initTimer() {
}
void shutdownTimer() {
setColorStatus(Ion::LED::Device::Color::RED, false);
setColorStatus(Ion::LED::Device::Color::GREEN, false);
setColorStatus(Ion::LED::Device::Color::BLUE, false);
TIM3.CCMR()->setOC2M(TIM<Register16>::CCMR::OCM::ForceInactive);
TIM3.CCMR()->setOC4M(TIM<Register16>::CCMR::OCM::ForceInactive);
TIM3.CCMR()->setOC3M(TIM<Register16>::CCMR::OCM::ForceInactive);
}
/* 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;
void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period) {
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. */
/* Let's set the prescaler to 1. Increasing the prescaler would slow down
* the modulation, which can be useful when debugging or when we want an
* actual blinking. */
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
case Mode::Blink:
int systemClockFreq = 96;
/* We still want to do PWM, but at a rate slow enough to blink. Ideally,
* we want to pre-scale the period to be able to set it in milliseconds;
* however, as the prescaler is cap by 2^16-1, we divide it by a factor
* and correct the period consequently. */
int factor = 2;
// TODO: explain the 2 ?
TIM3.PSC()->set(systemClockFreq*1000/factor);
period *= factor;
TIM3.ARR()->set(period);
break;
}
@@ -135,34 +128,6 @@ void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen,
TIM3.CCR4()->set(dutyCycleGreen*period);
}
void setColorStatus(Color color, bool enable) {
switch (color) {
case Ion::LED::Device::Color::RED:
TIM3.CCMR()->setOC2M(enable ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
break;
case Ion::LED::Device::Color::GREEN:
TIM3.CCMR()->setOC4M(enable ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
break;
case Ion::LED::Device::Color::BLUE:
TIM3.CCMR()->setOC3M(enable ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
break;
}
}
/*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];
if (states[i]) {
p.group().MODER()->setMode(p.pin(), GPIO::MODER::Mode::Output);
p.group().ODR()->set(p.pin(), true);
} else {
p.group().MODER()->setMode(p.pin(), GPIO::MODER::Mode::Analog);
p.group().PUPDR()->setPull(p.pin(), GPIO::PUPDR::Pull::None);
}
}
}*/
}
}
}

View File

@@ -14,23 +14,20 @@ namespace Device {
* PC7 | LED red | Alternate Function 2 | TIM3_CH2
*/
enum Mode {
enum class Mode {
PWM,
BLINK
Blink
};
enum Color {
RED,
GREEN,
BLUE
enum class 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 setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period = 0);
void initGPIO();
void shutdownGPIO();

View File

@@ -9,7 +9,7 @@ KDColor getColor() {
void setColor(KDColor c) {}
void setBlinking(float period, float dutyCycle) {}
void setBlinking(uint16_t period, float dutyCycle) {}
}
}