mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[ion] Clean LED API
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
constexpr int SYSBUS_FREQ = 96*1000*1000;
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -9,7 +9,7 @@ KDColor getColor() {
|
||||
|
||||
void setColor(KDColor c) {}
|
||||
|
||||
void setBlinking(float period, float dutyCycle) {}
|
||||
void setBlinking(uint16_t period, float dutyCycle) {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user