[ion] Add RTC subsystem

This commit is contained in:
Jean-Baptiste Boric
2020-06-07 15:20:26 +02:00
parent 07da4831b1
commit 2fd15b7d7f
31 changed files with 743 additions and 9 deletions

View File

@@ -25,6 +25,7 @@ apps_src += $(addprefix apps/,\
backlight_dimming_timer.cpp \
battery_timer.cpp \
battery_view.cpp \
clock_timer.cpp \
empty_battery_window.cpp \
exam_pop_up_controller.cpp \
exam_mode_configuration_official.cpp:+official \

View File

@@ -31,6 +31,7 @@ AppsContainer::AppsContainer() :
m_batteryTimer(),
m_suspendTimer(),
m_backlightDimmingTimer(),
m_clockTimer(ClockTimer(this)),
m_homeSnapshot(),
m_onBoardingSnapshot(),
m_hardwareTestSnapshot(),
@@ -304,6 +305,10 @@ void AppsContainer::run() {
switchTo(nullptr);
}
bool AppsContainer::updateClock() {
return m_window.updateClock();
}
bool AppsContainer::updateBatteryState() {
bool batteryLevelUpdated = m_window.updateBatteryLevel();
bool pluggedStateUpdated = m_window.updatePluggedState();
@@ -409,11 +414,11 @@ Window * AppsContainer::window() {
}
int AppsContainer::numberOfContainerTimers() {
return 3;
return 4;
}
Timer * AppsContainer::containerTimerAtIndex(int i) {
Timer * timers[3] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer};
Timer * timers[4] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_clockTimer};
return timers[i];
}

View File

@@ -17,6 +17,7 @@
#include "backlight_dimming_timer.h"
#include "shared/global_context.h"
#include "on_boarding/pop_up_controller.h"
#include "clock_timer.h"
#include <ion/events.h>
@@ -39,6 +40,7 @@ public:
bool dispatchEvent(Ion::Events::Event event) override;
bool switchTo(App::Snapshot * snapshot) override;
void run() override;
bool updateClock();
bool updateBatteryState();
void refreshPreferences();
void reloadTitleBarView();
@@ -76,6 +78,7 @@ private:
BatteryTimer m_batteryTimer;
SuspendTimer m_suspendTimer;
BacklightDimmingTimer m_backlightDimmingTimer;
ClockTimer m_clockTimer;
Home::App::Snapshot m_homeSnapshot;
OnBoarding::App::Snapshot m_onBoardingSnapshot;
HardwareTest::App::Snapshot m_hardwareTestSnapshot;

View File

@@ -3,6 +3,7 @@
extern "C" {
#include <assert.h>
}
#include <ion/rtc.h>
AppsWindow::AppsWindow() :
Window(),
@@ -19,6 +20,11 @@ bool AppsWindow::updateBatteryLevel() {
return m_titleBarView.setChargeState(Ion::Battery::level());
}
bool AppsWindow::updateClock() {
Ion::RTC::DateTime dateTime = Ion::RTC::dateTime();
return m_titleBarView.setClock(dateTime.tm_hour, dateTime.tm_min);
}
bool AppsWindow::updateIsChargingState() {
return m_titleBarView.setIsCharging(Ion::Battery::isCharging());
}

View File

@@ -9,6 +9,7 @@ public:
AppsWindow();
void setTitle(I18n::Message title);
bool updateBatteryLevel();
bool updateClock();
bool updateIsChargingState();
bool updatePluggedState();
void refreshPreferences();

12
apps/clock_timer.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "clock_timer.h"
#include "apps_container.h"
ClockTimer::ClockTimer(AppsContainer * container) :
Timer(1),
m_container(container)
{
}
bool ClockTimer::fire() {
return m_container->updateClock();
}

16
apps/clock_timer.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef APPS_CLOCK_TIMER_H
#define APPS_CLOCK_TIMER_H
#include <escher.h>
class AppsContainer;
class ClockTimer : public Timer {
public:
ClockTimer(AppsContainer * container);
private:
bool fire() override;
AppsContainer * m_container;
};
#endif

View File

@@ -10,8 +10,12 @@ using namespace Poincare;
TitleBarView::TitleBarView() :
View(),
m_titleView(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, Palette::ToolbarText, Palette::Toolbar),
m_preferenceView(KDFont::SmallFont, 1.0f, 0.5, Palette::ToolbarText, Palette::Toolbar)
m_preferenceView(KDFont::SmallFont, 1.0f, 0.5, Palette::ToolbarText, Palette::Toolbar),
m_clockView(KDFont::SmallFont, 0.5f, 0.5f, Palette::ToolbarText, Palette::Toolbar),
m_hours(-1),
m_mins(-1)
{
setClock(0, 0);
m_examModeIconView.setImage(ImageStore::ExamIcon);
}
@@ -25,6 +29,25 @@ void TitleBarView::setTitle(I18n::Message title) {
m_titleView.setMessage(title);
}
bool TitleBarView::setClock(int hours, int mins) {
if (m_hours != hours || m_mins != mins) {
char buf[6], *ptr = buf;
*ptr++ = (hours / 10) + '0';
*ptr++ = (hours % 10) + '0';
*ptr++ = ':';
*ptr++ = (mins / 10) + '0';
*ptr++ = (mins % 10) + '0';
*ptr = '\0';
m_clockView.setText(buf);
m_hours = hours;
m_mins = mins;
return true;
}
return false;
}
bool TitleBarView::setChargeState(Ion::Battery::Charge chargeState) {
return m_batteryView.setChargeState(chargeState);
}
@@ -42,7 +65,7 @@ bool TitleBarView::setShiftAlphaLockStatus(Ion::Events::ShiftAlphaStatus status)
}
int TitleBarView::numberOfSubviews() const {
return 5;
return 6;
}
View * TitleBarView::subviewAtIndex(int index) {
@@ -58,6 +81,9 @@ View * TitleBarView::subviewAtIndex(int index) {
if (index == 3) {
return &m_shiftAlphaLockView;
}
if (index == 4) {
return &m_clockView;
}
return &m_batteryView;
}
@@ -69,19 +95,21 @@ void TitleBarView::layoutSubviews(bool force) {
* translate the frame of the title downwards.*/
m_titleView.setFrame(KDRect(0, 2, bounds().width(), bounds().height()-2), force);
m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height()), force);
KDSize clockSize = m_clockView.minimalSizeForOptimalDisplay();
m_clockView.setFrame(KDRect(bounds().width() - clockSize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- clockSize.height())/2, clockSize), force);
KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay();
m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize), force);
m_batteryView.setFrame(KDRect(bounds().width() - clockSize.width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize), force);
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
m_examModeIconView.setFrame(KDRect(bounds().width() - batterySize.width() - k_examIconWidth - k_alphaRightMargin - Metric::TitleBarExternHorizontalMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight), force);
m_examModeIconView.setFrame(KDRect(bounds().width() - clockSize.width() - batterySize.width() - k_examIconWidth - k_alphaRightMargin - Metric::TitleBarExternHorizontalMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight), force);
} else {
m_examModeIconView.setFrame(KDRectZero, force);
}
KDSize shiftAlphaLockSize = m_shiftAlphaLockView.minimalSizeForOptimalDisplay();
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
// The Shift/Alpha frame is shifted when examination mode is active
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-k_examIconWidth-Metric::TitleBarExternHorizontalMargin-2*k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-clockSize.width()-batterySize.width()-k_examIconWidth-Metric::TitleBarExternHorizontalMargin-2*k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
} else {
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-clockSize.width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
}
}

View File

@@ -11,6 +11,7 @@ public:
TitleBarView();
void drawRect(KDContext * ctx, KDRect rect) const override;
void setTitle(I18n::Message title);
bool setClock(int hours, int mins);
bool setChargeState(Ion::Battery::Charge chargeState);
bool setIsCharging(bool isCharging);
bool setIsPlugged(bool isPlugged);
@@ -30,6 +31,9 @@ private:
ShiftAlphaLockView m_shiftAlphaLockView;
BufferTextView m_preferenceView;
ImageView m_examModeIconView;
BufferTextView m_clockView;
int m_hours;
int m_mins;
};
#endif

View File

@@ -31,6 +31,7 @@ ion_src += $(addprefix ion/src/shared/, \
events_keyboard.cpp \
events_modifier.cpp \
platform_info.cpp \
rtc.cpp \
storage.cpp \
unicode/utf8_decoder.cpp\
unicode/utf8_helper.cpp\

View File

@@ -10,6 +10,7 @@
#include <ion/keyboard.h>
#include <ion/led.h>
#include <ion/power.h>
#include <ion/rtc.h>
#include <ion/storage.h>
#include <ion/timing.h>
#include <ion/usb.h>

38
ion/include/ion/rtc.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef ION_RTC_H
#define ION_RTC_H
#include <stdint.h>
namespace Ion {
namespace RTC {
struct DateTime {
int tm_sec;
int tm_min;
int tm_hour; // 0-23
int tm_mday; // 1-31
int tm_mon; // 1-12
int tm_year;
int tm_wday; // 0-6, 0 is Monday
};
enum class Mode {
Disabled = 0,
LSI = 1,
HSE = 2,
} ;
void setMode(Mode mode);
Mode mode();
void setDateTime(DateTime dateTime);
DateTime dateTime();
bool parseDate(const char * text, DateTime & target);
bool parseTime(const char * text, DateTime & target);
void toStringDate(DateTime dateTime, char *text);
void toStringTime(DateTime dateTime, char *text);
}
}
#endif

View File

@@ -15,6 +15,7 @@ ion_src += $(addprefix ion/src/shared/, \
timing.cpp \
dummy/backlight.cpp \
dummy/battery.cpp \
dummy/rtc.cpp \
dummy/display.cpp \
dummy/events_modifier.cpp \
dummy/exam_mode.cpp \

View File

@@ -121,6 +121,7 @@ void initClocks() {
// We're using TIM3 for the LEDs
RCC.APB1ENR()->setTIM3EN(true);
RCC.APB1ENR()->setPWREN(true);
RCC.APB1ENR()->setRTCAPB(true);
// APB2 bus
class RCC::APB2ENR apb2enr(0x00008000); // Reset value

View File

@@ -251,6 +251,8 @@ void initClocks() {
// APB1 bus
// We're using TIM3 for the LEDs
RCC.APB1ENR()->setTIM3EN(true);
RCC.APB1ENR()->setPWREN(true);
RCC.APB1ENR()->setRTCAPB(true);
// APB2 bus
class RCC::APB2ENR apb2enr(0); // Reset value

33
ion/src/device/regs/pwr.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef REGS_PWR_H
#define REGS_PWR_H
#include "register.h"
class PWR {
public:
class CR : Register32 {
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;
};
};
constexpr PWR PWR;
#endif

133
ion/src/device/regs/rcc.h Normal file
View File

@@ -0,0 +1,133 @@
#ifndef REGS_RCC_H
#define REGS_RCC_H
#include "register.h"
class RCC {
public:
class CR : public Register32 {
public:
REGS_BOOL_FIELD(PLLRDY, 25);
REGS_BOOL_FIELD(PLLON, 24);
};
class PLLCFGR : public Register32 {
public:
REGS_FIELD(PLLM, uint8_t, 5, 0);
REGS_FIELD(PLLN, uint16_t, 14, 6);
REGS_FIELD(PLLP, uint8_t, 17, 16);
enum class PLLSRC {
HSI = 0,
HSE = 1
};
void setPLLSRC(PLLSRC s) volatile { setBitRange(22, 22, (uint8_t)s); }
REGS_FIELD(PLLQ, uint8_t, 27, 24);
REGS_FIELD(PLLR, uint8_t, 30, 28);
};
class CFGR : public Register32 {
public:
enum class SW {
HSI = 0,
HSE = 1,
PLL = 2
};
void setSW(SW s) volatile { setBitRange(1, 0, (uint8_t)s); }
SW getSWS() volatile { return (SW)getBitRange(3,2); }
enum class AHBRatio {
One = 0,
DivideBy2 = 4,
DivideBy4 = 5,
DivideBy8 = 6,
DivideBy16 = 7
};
void setPPRE1(AHBRatio r) volatile { setBitRange(12, 10, (uint32_t)r); }
};
class AHB1ENR : public Register32 {
public:
using Register32::Register32;
REGS_BOOL_FIELD(GPIOAEN, 0);
REGS_BOOL_FIELD(GPIOBEN, 1);
REGS_BOOL_FIELD(GPIOCEN, 2);
REGS_BOOL_FIELD(GPIODEN, 3);
REGS_BOOL_FIELD(GPIOEEN, 4);
REGS_BOOL_FIELD(GPIOFEN, 5);
REGS_BOOL_FIELD(GPIOGEN, 6);
REGS_BOOL_FIELD(GPIOHEN, 7);
REGS_BOOL_FIELD(CRCEN, 12);
REGS_BOOL_FIELD(DMA1EN, 21);
REGS_BOOL_FIELD(DMA2EN, 22);
};
class AHB2ENR : Register32 {
public:
REGS_BOOL_FIELD(RNGEN, 6);
};
class AHB3ENR : Register32 {
public:
REGS_BOOL_FIELD(FSMCEN, 0);
REGS_BOOL_FIELD(QSPIEN, 1);
};
class APB1ENR : public Register32 {
public:
using Register32::Register32;
REGS_BOOL_FIELD(TIM3EN, 1);
REGS_BOOL_FIELD(RTCAPB, 10);
REGS_BOOL_FIELD(SPI3EN, 15);
REGS_BOOL_FIELD(USART3EN, 18);
REGS_BOOL_FIELD(PWREN, 28);
};
class APB2ENR : public Register32 {
public:
using Register32::Register32;
REGS_BOOL_FIELD(TIM1EN, 0);
REGS_BOOL_FIELD(USART1EN, 4);
REGS_BOOL_FIELD(ADC1EN, 8);
REGS_BOOL_FIELD(SDIOEN, 11);
REGS_BOOL_FIELD(SYSCFGEN, 14);
};
class BDCR : public Register32 {
public:
REGS_BOOL_FIELD(BDRST, 16);
REGS_BOOL_FIELD(RTCEN, 15);
REGS_FIELD(RTCSEL, uint8_t, 9, 8);
};
class CSR : public Register32 {
public:
REGS_BOOL_FIELD(LSION, 0);
REGS_BOOL_FIELD_R(LSIRDY, 1);
};
class DCKCFGR2 : Register32 {
public:
REGS_BOOL_FIELD(CK48MSEL, 27);
REGS_BOOL_FIELD(CKSDIOSEL, 28);
};
constexpr RCC() {};
REGS_REGISTER_AT(CR, 0x00);
REGS_REGISTER_AT(PLLCFGR, 0x04);
REGS_REGISTER_AT(CFGR, 0x08);
REGS_REGISTER_AT(AHB1ENR, 0x30);
REGS_REGISTER_AT(AHB2ENR, 0x34);
REGS_REGISTER_AT(AHB3ENR, 0x38);
REGS_REGISTER_AT(APB1ENR, 0x40);
REGS_REGISTER_AT(APB2ENR, 0x44);
REGS_REGISTER_AT(BDCR, 0x70);
REGS_REGISTER_AT(CSR, 0x74);
REGS_REGISTER_AT(DCKCFGR2, 0x94);
private:
constexpr uint32_t Base() const {
return 0x40023800;
}
};
constexpr RCC RCC;
#endif

View File

@@ -3,6 +3,7 @@
#include <string.h>
#include <ion.h>
#include "../drivers/board.h"
#include "../drivers/rtc.h"
#include "../drivers/reset.h"
#include "../drivers/timing.h"

View File

@@ -17,6 +17,7 @@ ion_device_src += $(addprefix ion/src/device/shared/drivers/, \
power.cpp\
random.cpp\
reset.cpp \
rtc.cpp \
serial_number.cpp \
swd.cpp \
timing.cpp \

View File

@@ -7,6 +7,7 @@
#include <drivers/external_flash.h>
#include <drivers/keyboard.h>
#include <drivers/led.h>
#include <drivers/rtc.h>
#include <drivers/swd.h>
#include <drivers/timing.h>
#include <drivers/usb.h>

View File

@@ -1,6 +1,7 @@
#include <ion/battery.h>
#include <ion/keyboard.h>
#include <ion/led.h>
#include <ion/rtc.h>
#include <ion/usb.h>
#include <drivers/board.h>
#include <drivers/battery.h>
@@ -39,7 +40,7 @@ void suspend(bool checkIfOnOffKeyReleased) {
isLEDActive = LED::updateColorWithPlugAndCharge() != KDColorBlack;
// Configure low-power mode
if (isLEDActive) {
if (isLEDActive || Ion::RTC::mode() == Ion::RTC::Mode::HSE) {
Device::Power::sleepConfiguration();
} else {
Device::Power::stopConfiguration();

View File

@@ -0,0 +1,169 @@
#include <ion/rtc.h>
#include <ion/timing.h>
#include <drivers/rtc.h>
#include <drivers/config/clocks.h>
#include "regs/regs.h"
constexpr int yearEpoch = 2000;
static int bcdToBinary(int tens, int units) {
return tens * 10 + units;
}
static int dayOfWeek(int y, int m, int d)
{
const static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return ((y + y/4 - y/100 + y/400 + t[m-1] + (d-1)) % 7) + 1;
}
// Public Ion methods
namespace Ion {
namespace RTC {
static void rtcSetWriteEnable(bool status) {
if (status) {
Device::Regs::PWR.CR()->setDBP(true);
Device::Regs::RTC.WPR()->setKEY(0xCA);
Device::Regs::RTC.WPR()->setKEY(0x53);
}
else {
Device::Regs::RTC.WPR()->setKEY(0xFF);
Device::Regs::PWR.CR()->setDBP(false);
}
}
void setMode(Mode mode) {
DateTime prevDateTime = dateTime();
Ion::Device::RTC::init(mode != Mode::Disabled, mode == Mode::HSE);
setDateTime(prevDateTime);
}
Mode mode() {
if (!Ion::Device::Regs::RCC.BDCR()->getRTCEN()) {
return Mode::Disabled;
}
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() == 0x3) {
return Mode::HSE;
}
return Mode::LSI;
}
DateTime dateTime() {
if (mode() == Mode::Disabled) {
return DateTime { 0, 0, 0, 1, 1, 2000, 6 };
}
Device::Regs::RTC.ISR()->setRSF(false);
for (int cpt = 0; cpt < 100; cpt++) {
if (Device::Regs::RTC.ISR()->getRSF() == true)
break;
Ion::Timing::usleep(5);
}
return DateTime {
bcdToBinary(Device::Regs::RTC.TR()->getST(), Device::Regs::RTC.TR()->getSU()),
bcdToBinary(Device::Regs::RTC.TR()->getMNT(), Device::Regs::RTC.TR()->getMNU()),
bcdToBinary(Device::Regs::RTC.TR()->getHT(), Device::Regs::RTC.TR()->getHU()),
bcdToBinary(Device::Regs::RTC.DR()->getDT(), Device::Regs::RTC.DR()->getDU()),
bcdToBinary(Device::Regs::RTC.DR()->getMT(), Device::Regs::RTC.DR()->getMU()),
bcdToBinary(Device::Regs::RTC.DR()->getYT(), Device::Regs::RTC.DR()->getYU()) + yearEpoch,
Device::Regs::RTC.DR()->getWDU() - 1,
};
}
void setDateTime(DateTime dateTime) {
if (mode() == Mode::Disabled) {
return;
}
rtcSetWriteEnable(true);
Device::Regs::RTC.ISR()->setINIT(true);
for (int cpt = 0; cpt < 100; cpt++) {
if (Device::Regs::RTC.ISR()->getINITF() == true)
break;
Ion::Timing::usleep(10);
}
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() == 0x2) {
// LSI is ~32 kHz
Device::Regs::RTC.PRER()->setPREDIV_S(249);
Device::Regs::RTC.PRER()->setPREDIV_A(127);
}
else {
// HSE's divided down to 1 MHz
Device::Regs::RTC.PRER()->setPREDIV_S(7999);
Device::Regs::RTC.PRER()->setPREDIV_A(124);
}
Device::Regs::RTC.CR()->setFMT(false);
class Device::Regs::RTC::TR tr(0);
tr.setPM(false);
tr.setHT(dateTime.tm_hour / 10);
tr.setHU(dateTime.tm_hour % 10);
tr.setMNT(dateTime.tm_min / 10);
tr.setMNU(dateTime.tm_min % 10);
tr.setST(dateTime.tm_sec / 10);
tr.setSU(dateTime.tm_sec % 10);
Device::Regs::RTC.TR()->set(tr);
class Device::Regs::RTC::DR dr(0);
dr.setYT((dateTime.tm_year - yearEpoch) / 10);
dr.setYU((dateTime.tm_year - yearEpoch) % 10);
dr.setWDU(dayOfWeek(dateTime.tm_year, dateTime.tm_mon, dateTime.tm_mday));
dr.setMT(dateTime.tm_mon / 10);
dr.setMU(dateTime.tm_mon % 10);
dr.setDT(dateTime.tm_mday / 10);
dr.setDU(dateTime.tm_mday % 10);
Device::Regs::RTC.DR()->set(dr);
Device::Regs::RTC.ISR()->setINIT(true);
rtcSetWriteEnable(false);
}
}
}
// Private Ion::Device::RTC methods
namespace Ion {
namespace Device {
namespace RTC {
void init(bool enable, bool useHighPrecisionClock) {
const int rtcSource = useHighPrecisionClock ? 0x3 : 0x2;
Ion::Device::Regs::RCC.CFGR()->setRTCPRE(Ion::Device::Clocks::Config::HSE);
Ion::RTC::rtcSetWriteEnable(true);
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() != rtcSource) {
// Initialize backup domain for RTC
Ion::Device::Regs::RCC.BDCR()->setBDRST(true);
Ion::Timing::usleep(250);
Ion::Device::Regs::RCC.BDCR()->setBDRST(false);
Ion::Timing::usleep(250);
Ion::RTC::rtcSetWriteEnable(true);
}
Ion::Device::Regs::RCC.BDCR()->setRTCSEL(rtcSource);
Ion::Device::Regs::RCC.BDCR()->setRTCEN(enable);
// Enable/disable LSI clock
if (enable && useHighPrecisionClock) {
Ion::Device::Regs::RCC.CSR()->setLSION(false);
}
else {
Ion::Device::Regs::RCC.CSR()->setLSION(true);
while (Ion::Device::Regs::RCC.CSR()->getLSIRDY() != true);
}
Ion::RTC::rtcSetWriteEnable(false);
}
}
}
}

View File

@@ -0,0 +1,16 @@
#ifndef ION_DEVICE_RTC_H
#define ION_DEVICE_RTC_H
#include "regs/regs.h"
namespace Ion {
namespace Device {
namespace RTC {
void init(bool enabled, bool useHighPrecisionClock);
}
}
}
#endif

View File

@@ -15,6 +15,7 @@ public:
REGS_BOOL_FIELD(LPDS, 0);
REGS_BOOL_FIELD(PPDS, 1);
REGS_BOOL_FIELD(CSBF, 3);
REGS_BOOL_FIELD(DBP, 8);
REGS_BOOL_FIELD(FPDS, 9);
REGS_BOOL_FIELD(LPUDS, 10); // Called LPLVDS in N0100
REGS_BOOL_FIELD(MRUDS, 11); // Called MRLVDS in N100
@@ -39,6 +40,7 @@ public:
public:
REGS_BOOL_FIELD_R(WUIF, 0);
REGS_BOOL_FIELD_R(SBF, 1);
REGS_BOOL_FIELD_R(BRR, 3);
REGS_BOOL_FIELD_W(EIWUP, 8);
REGS_BOOL_FIELD_W(BRE, 9);
REGS_BOOL_FIELD_R(VOSRDY, 14);

View File

@@ -70,6 +70,7 @@ public:
};
void setPPRE1(APBPrescaler r) volatile { setBitRange(12, 10, (uint32_t)r); }
void setPPRE2(APBPrescaler r) volatile { setBitRange(15, 13, (uint32_t)r); }
REGS_FIELD(RTCPRE, uint8_t, 20, 16);
};
class AHB3RSTR : Register32 {
@@ -111,6 +112,7 @@ public:
public:
using Register32::Register32;
REGS_BOOL_FIELD(TIM3EN, 1);
REGS_BOOL_FIELD(RTCAPB, 10);
REGS_BOOL_FIELD(SPI3EN, 15);
REGS_BOOL_FIELD(USART3EN, 18);
REGS_BOOL_FIELD(PWREN, 28);
@@ -264,6 +266,19 @@ public:
REGS_BOOL_FIELD(SSCGEN, 31);
};
class BDCR : public Register32 {
public:
REGS_BOOL_FIELD(BDRST, 16);
REGS_BOOL_FIELD(RTCEN, 15);
REGS_FIELD(RTCSEL, uint8_t, 9, 8);
};
class CSR : public Register32 {
public:
REGS_BOOL_FIELD(LSION, 0);
REGS_BOOL_FIELD_R(LSIRDY, 1);
};
class DCKCFGR2 : Register32 {
public:
REGS_BOOL_FIELD(CK48MSEL, 27);
@@ -285,6 +300,8 @@ public:
REGS_REGISTER_AT(AHB3LPENR, 0x58);
REGS_REGISTER_AT(APB1LPENR, 0x60);
REGS_REGISTER_AT(APB2LPENR, 0x64);
REGS_REGISTER_AT(BDCR, 0x70);
REGS_REGISTER_AT(CSR, 0x74);
REGS_REGISTER_AT(SSCGR, 0x80);
REGS_REGISTER_AT(DCKCFGR2, 0x94);
private:

View File

@@ -17,6 +17,7 @@
#include "rng.h"
#include "otg.h"
#include "quadspi.h"
#include "rtc.h"
#include "sdio.h"
#include "spi.h"
#include "syscfg.h"

View File

@@ -0,0 +1,99 @@
#ifndef REGS_RTC_H
#define REGS_RTC_H
#include "register.h"
namespace Ion {
namespace Device {
namespace Regs {
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(INIT, 7);
REGS_BOOL_FIELD_R(INITF, 6);
REGS_BOOL_FIELD(RSF, 5);
REGS_BOOL_FIELD_R(INITS, 4);
};
class PRER : Register32 {
public:
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);
};
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);
private:
constexpr uint32_t Base() const {
return 0x40002800;
};
};
constexpr RTC RTC;
}
}
}
#endif

View File

@@ -0,0 +1,18 @@
#include <ion/rtc.h>
static Ion::RTC::Mode s_mode = Ion::RTC::Mode::HSE;
void Ion::RTC::setMode(Ion::RTC::Mode mode) {
s_mode = mode;
}
Ion::RTC::Mode Ion::RTC::mode() {
return s_mode;
}
void Ion::RTC::setDateTime(Ion::RTC::DateTime dateTime) {
}
Ion::RTC::DateTime Ion::RTC::dateTime() {
return Ion::RTC::DateTime { 0, 0, 0, 1, 1, 2000, 6 };
}

89
ion/src/shared/rtc.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include <ion/rtc.h>
namespace Ion {
namespace RTC {
static bool consumeDigit(char text, int & target)
{
if (text < '0' || text > '9') {
return false;
}
target = target * 10 + (text - '0');
return true;
}
bool parseDate(const char * text, DateTime & target)
{
target.tm_mday = 0;
target.tm_mon = 0;
target.tm_year = 0;
if (!consumeDigit(*text++, target.tm_mday)) return false;
if (*text != '/') {
if (!consumeDigit(*text++, target.tm_mday)) return false;
}
if (*text++ != '/') return false;
if (!consumeDigit(*text++, target.tm_mon)) return false;
if (*text != '/') {
if (!consumeDigit(*text++, target.tm_mon)) return false;
}
if (*text++ != '/') return false;
if (!consumeDigit(*text++, target.tm_year)) return false;
if (!consumeDigit(*text++, target.tm_year)) return false;
if (!consumeDigit(*text++, target.tm_year)) return false;
if (!consumeDigit(*text++, target.tm_year)) return false;
if (*text++ != '\0') return false;
return true;
}
bool parseTime(const char * text, DateTime & target)
{
target.tm_sec = 0;
target.tm_min = 0;
target.tm_hour = 0;
if (!consumeDigit(*text++, target.tm_hour)) return false;
if (!consumeDigit(*text++, target.tm_hour)) return false;
if (*text++ != ':') return false;
if (!consumeDigit(*text++, target.tm_min)) return false;
if (!consumeDigit(*text++, target.tm_min)) return false;
if (*text == '\0') return true;
if (*text++ != ':') return false;
if (!consumeDigit(*text++, target.tm_sec)) return false;
if (!consumeDigit(*text++, target.tm_sec)) return false;
if (*text++ != '\0') return false;
return true;
}
void toStringDate(DateTime dateTime, char *text)
{
*text++ = ((dateTime.tm_mday / 10) % 10) + '0';
*text++ = ((dateTime.tm_mday / 1) % 10) + '0';
*text++ = '/';
*text++ = ((dateTime.tm_mon / 10) % 10) + '0';
*text++ = ((dateTime.tm_mon / 1) % 10) + '0';
*text++ = '/';
*text++ = ((dateTime.tm_year / 1000) % 10) + '0';
*text++ = ((dateTime.tm_year / 100) % 10) + '0';
*text++ = ((dateTime.tm_year / 10) % 10) + '0';
*text++ = ((dateTime.tm_year / 1) % 10) + '0';
*text++ = '\0';
}
void toStringTime(DateTime dateTime, char *text)
{
*text++ = ((dateTime.tm_hour / 10) % 10) + '0';
*text++ = ((dateTime.tm_hour / 1) % 10) + '0';
*text++ = ':';
*text++ = ((dateTime.tm_min / 10) % 10) + '0';
*text++ = ((dateTime.tm_min / 1) % 10) + '0';
*text++ = ':';
*text++ = ((dateTime.tm_sec / 10) % 10) + '0';
*text++ = ((dateTime.tm_sec / 1) % 10) + '0';
*text++ = '\0';
}
}
}

View File

@@ -9,6 +9,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \
dummy/stack.cpp \
dummy/usb.cpp \
console_stdio.cpp:-consoledisplay \
rtc.cpp \
crc32.cpp \
display.cpp:-headless \
events_keyboard.cpp:-headless \

View File

@@ -0,0 +1,32 @@
#include <ion/rtc.h>
#include <time.h>
#include <cstdio>
static Ion::RTC::Mode s_mode = Ion::RTC::Mode::HSE;
void Ion::RTC::setMode(Ion::RTC::Mode mode) {
s_mode = mode;
}
Ion::RTC::Mode Ion::RTC::mode() {
return s_mode;
}
void Ion::RTC::setDateTime(Ion::RTC::DateTime dateTime) {
printf("Ion::RTC::setDateTime(%02d:%02d:%02d %02d/%02d/%04d)\n", dateTime.tm_hour, dateTime.tm_min, dateTime.tm_sec, dateTime.tm_mday, dateTime.tm_mon, dateTime.tm_year);
}
Ion::RTC::DateTime Ion::RTC::dateTime() {
time_t localTime = time(nullptr);
struct tm *localTm = localtime(&localTime);
return DateTime {
localTm->tm_sec,
localTm->tm_min,
localTm->tm_hour,
localTm->tm_mday,
localTm->tm_mon + 1,
localTm->tm_year + 1900,
localTm->tm_wday != 0 ? localTm->tm_wday - 1 : 6,
};
}