From 940270e78a27ce1881ffe4fa9b4fd0d182db2961 Mon Sep 17 00:00:00 2001 From: Damien Nicolet Date: Thu, 9 Aug 2018 00:59:13 +0200 Subject: [PATCH] [ion] add millis() and micros() using systick on device --- ion/include/ion.h | 2 ++ ion/src/blackbox/ion.cpp | 14 +++++++++++++ ion/src/device/boot/isr.c | 2 +- ion/src/device/boot/rt0.cpp | 6 ++++++ ion/src/device/boot/rt0.h | 2 ++ ion/src/device/device.cpp | 24 +++++++++++++++++++++ ion/src/device/device.h | 2 ++ ion/src/device/regs/cm4.h | 35 ++++++++++++++++++++++++++----- ion/src/device/regs/register.h | 2 +- ion/src/device/usb/calculator.cpp | 2 ++ ion/src/emscripten/main.cpp | 7 +++++++ ion/src/simulator/init.cpp | 16 ++++++++++++++ 12 files changed, 107 insertions(+), 7 deletions(-) diff --git a/ion/include/ion.h b/ion/include/ion.h index 83cb25b36..bbd012cc7 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -27,6 +27,8 @@ namespace Ion { void msleep(long ms); void usleep(long us); +extern "C" long millis(); +extern "C" long micros(); const char * serialNumber(); const char * softwareVersion(); diff --git a/ion/src/blackbox/ion.cpp b/ion/src/blackbox/ion.cpp index d946ac29b..1f33fd800 100644 --- a/ion/src/blackbox/ion.cpp +++ b/ion/src/blackbox/ion.cpp @@ -3,3 +3,17 @@ void Ion::msleep(long ms) { } + +#include + +static auto start = std::chrono::high_resolution_clock::now(); + +long Ion::millis() { + auto elapsed = std::chrono::high_resolution_clock::now() - start; + return std::chrono::duration_cast(elapsed).count(); +} + +long Ion::micros() { + auto elapsed = std::chrono::high_resolution_clock::now() - start; + return std::chrono::duration_cast(elapsed).count(); +} diff --git a/ion/src/device/boot/isr.c b/ion/src/device/boot/isr.c index 276dfee2d..c313bf912 100644 --- a/ion/src/device/boot/isr.c +++ b/ion/src/device/boot/isr.c @@ -28,7 +28,7 @@ ISR InitialisationVector[INITIALISATION_VECTOR_SIZE] 0, // DebugMonitor service routine, 0, // Reserved 0, // PendSV service routine, - 0, // SysTick service routine + sysTick, // SysTick service routine 0, // WWDG service routine 0, // PVD service routine 0, // TampStamp service routine diff --git a/ion/src/device/boot/rt0.cpp b/ion/src/device/boot/rt0.cpp index f72aa4edd..7f92ad960 100644 --- a/ion/src/device/boot/rt0.cpp +++ b/ion/src/device/boot/rt0.cpp @@ -92,3 +92,9 @@ void start() { abort(); } + +volatile long millis_elapsed = 0; + +void __attribute__((interrupt)) sysTick() { + millis_elapsed++; +} diff --git a/ion/src/device/boot/rt0.h b/ion/src/device/boot/rt0.h index 65b2365a4..684085a2b 100644 --- a/ion/src/device/boot/rt0.h +++ b/ion/src/device/boot/rt0.h @@ -4,4 +4,6 @@ void start(); void abort(); +void sysTick(); + #endif diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index bfdc90ce1..ccac92576 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -39,6 +39,22 @@ void Ion::usleep(long us) { } } +extern volatile long millis_elapsed; + +long Ion::millis() { + return millis_elapsed; +} + +long Ion::micros() { + uint32_t c1 = CM4.STCVR()->getCURRENT(); + uint32_t ms1 = millis_elapsed; + uint32_t c2 = CM4.STCVR()->getCURRENT(); + uint32_t ms2 = millis_elapsed; + uint32_t load = CM4.STRVR()->getRELOAD(); + + return ((c1 > c2) ? ms1 : ms2) * 1000 + ((load - c2) * 1000) / (load + 1); +} + uint32_t Ion::crc32(const uint32_t * data, size_t length) { bool initialCRCEngineState = RCC.AHB1ENR()->getCRCEN(); RCC.AHB1ENR()->setCRCEN(true); @@ -184,9 +200,17 @@ void initPeripherals() { #endif Console::Device::init(); SWD::Device::init(); + + CM4.STRVR()->setRELOAD(11999); + CM4.STCVR()->setCURRENT(0); + CM4.STCSR()->setCLKSOURCE(CM4::STCSR::CLKSOURCE::AHB_DIV8); + CM4.STCSR()->setTICKINT(true); + CM4.STCSR()->setENABLE(true); } void shutdownPeripherals(bool keepLEDAwake) { + CM4.STCSR()->setENABLE(false); + SWD::Device::shutdown(); Console::Device::shutdown(); #if USE_SD_CARD diff --git a/ion/src/device/device.h b/ion/src/device/device.h index 099061ef7..3cfc242e9 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -19,6 +19,8 @@ void shutdownPeripherals(bool keepLEDAwake = false); void initClocks(); void shutdownClocks(bool keepLEDAwake = false); +void sysTick(); + /* 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 * using a static variable (and therefore without a .bss section). This is used diff --git a/ion/src/device/regs/cm4.h b/ion/src/device/regs/cm4.h index c803faa7f..030a25238 100644 --- a/ion/src/device/regs/cm4.h +++ b/ion/src/device/regs/cm4.h @@ -40,14 +40,39 @@ public: REGS_BOOL_FIELD(SLEEPDEEP, 2); }; + class STCSR : public Register32 { + public: + enum class CLKSOURCE : uint8_t { + AHB_DIV8 = 0, + AHB = 1 + }; + REGS_BOOL_FIELD(COUNTFLAG, 16); + REGS_TYPE_FIELD(CLKSOURCE, 2, 2); + REGS_BOOL_FIELD(TICKINT, 1); + REGS_BOOL_FIELD(ENABLE, 0); + }; + + class STRVR : public Register32 { + public: + REGS_FIELD(RELOAD, uint32_t, 23, 0); + }; + + class STCVR : public Register32 { + public: + REGS_FIELD(CURRENT, uint32_t, 23, 0); + }; + constexpr CM4() {}; - REGS_REGISTER_AT(VTOR, 0x08); - REGS_REGISTER_AT(AIRCR, 0x0C); - REGS_REGISTER_AT(SCR, 0x10); - REGS_REGISTER_AT(CPACR, 0x88); + REGS_REGISTER_AT(STCSR, 0x10); + REGS_REGISTER_AT(STRVR, 0x14); + REGS_REGISTER_AT(STCVR, 0x18); + REGS_REGISTER_AT(VTOR, 0xD08); + REGS_REGISTER_AT(AIRCR, 0xD0C); + REGS_REGISTER_AT(SCR, 0xD10); + REGS_REGISTER_AT(CPACR, 0xD88); private: constexpr uint32_t Base() const { - return 0xE000ED00; + return 0xE000E000; } }; diff --git a/ion/src/device/regs/register.h b/ion/src/device/regs/register.h index 541c39e69..5ed38d779 100644 --- a/ion/src/device/regs/register.h +++ b/ion/src/device/regs/register.h @@ -50,7 +50,7 @@ typedef Register Register32; typedef Register Register64; #define REGS_FIELD_R(name,type,high,low) type get##name() volatile { return (type)getBitRange(high,low); }; -#define REGS_FIELD_W(name,type,high,low) void set##name(type v) volatile { static_assert(sizeof(type) <= 2, "Invalid size"); setBitRange(high, low, static_cast(v)); }; +#define REGS_FIELD_W(name,type,high,low) void set##name(type v) volatile { static_assert(sizeof(type) <= 4, "Invalid size"); setBitRange(high, low, static_cast(v)); }; #define REGS_FIELD(name,type,high,low) REGS_FIELD_R(name,type,high,low); REGS_FIELD_W(name,type,high,low); #define REGS_TYPE_FIELD(name,high,low) REGS_FIELD(name,name,high,low) #define REGS_BOOL_FIELD(name,bit) REGS_FIELD(name,bool,bit,bit) diff --git a/ion/src/device/usb/calculator.cpp b/ion/src/device/usb/calculator.cpp index fc23c1512..55e6ae573 100644 --- a/ion/src/device/usb/calculator.cpp +++ b/ion/src/device/usb/calculator.cpp @@ -9,6 +9,7 @@ namespace USB { namespace Device { void Calculator::PollAndReset(bool exitWithKeyboard) { + CM4.STCSR()->setTICKINT(false); char serialNumber[Ion::Device::SerialNumberLength+1]; Ion::Device::copySerialNumber(serialNumber); Calculator c(serialNumber); @@ -37,6 +38,7 @@ void Calculator::PollAndReset(bool exitWithKeyboard) { * will enter the newly flashed firmware. */ Ion::Device::jumpReset(); } + CM4.STCSR()->setTICKINT(true); } Descriptor * Calculator::descriptor(uint8_t type, uint8_t index) { diff --git a/ion/src/emscripten/main.cpp b/ion/src/emscripten/main.cpp index c753d78af..c2fee90c4 100644 --- a/ion/src/emscripten/main.cpp +++ b/ion/src/emscripten/main.cpp @@ -2,6 +2,9 @@ #include "display.h" #include "events_keyboard.h" #include "../../../apps/global_preferences.h" +extern "C" { +#include +} extern "C" { const char * IonSoftwareVersion(); @@ -21,3 +24,7 @@ int main(int argc, char * argv[]) { void Ion::msleep(long ms) { } + +long Ion::millis() { + return SDL_GetTicks(); +} diff --git a/ion/src/simulator/init.cpp b/ion/src/simulator/init.cpp index d20630b14..f26123e9c 100644 --- a/ion/src/simulator/init.cpp +++ b/ion/src/simulator/init.cpp @@ -116,3 +116,19 @@ void Ion::msleep(long ms) { } } } + +static auto start = std::chrono::high_resolution_clock::now(); + +long Ion::millis() { + sDisplay->redraw(); + Fl::wait(0); + auto elapsed = std::chrono::high_resolution_clock::now() - start; + return std::chrono::duration_cast(elapsed).count(); +} + +long Ion::micros() { + sDisplay->redraw(); + Fl::wait(0); + auto elapsed = std::chrono::high_resolution_clock::now() - start; + return std::chrono::duration_cast(elapsed).count(); +}