Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ElapseTimer class, update HardwareTimer #1442

Merged
merged 5 commits into from
Sep 21, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Sming/Services/Profiling/ElapseTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/****
* Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
* Created 2015 by Skurydin Alexey
* http://github.com/SmingHub/Sming
* All files of the Sming Core are provided under the LGPL v3 license.
*
* Simple class for elapse timing
*
****/

#ifndef __ELAPSETIMER_H
#define __ELAPSETIMER_H

#include "HardwareTimer.h"

/*
* Microsecond elapse timer.
*/
class ElapseTimer
{
public:
ElapseTimer()
{
start();
}

void start()
{
_start = NOW();
}

uint32_t elapsed()
{
return timerTicksToUs(NOW() - _start);
}

private:
uint32_t _start;
};

#endif // __ELAPSETIMER_H
41 changes: 35 additions & 6 deletions Sming/SmingCore/HardwareTimer.cpp
Original file line number Diff line number Diff line change
@@ -9,11 +9,40 @@

#include "HardwareTimer.h"

#define US_TO_RTC_TIMER_TICKS(t) \
((t) ? (((t) > 0x35A) \
? (((t) >> 2) * ((APB_CLK_FREQ >> 4) / 250000) + ((t)&0x3) * ((APB_CLK_FREQ >> 4) / 1000000)) \
: (((t) * (APB_CLK_FREQ >> 4)) / 1000000)) \
: 0)
/*
* eagle_soc.h defines TIMER_CLK_FREQ using a divisor of 256, but Sming calls system_timer_reinit() in user_main()
* which changes it to 4. Fortunately, we can find out which value is in use by querying the timer2_ms_flag.
*
* (Found this in LWIP core)
*/
extern bool timer2_ms_flag;

// Get current timer frequency, which is variable
static __forceinline uint32_t getTimerClockFreq()
{
return timer2_ms_flag ? (APB_CLK_FREQ / 256) : (APB_CLK_FREQ / 16);
}

uint32_t IRAM_ATTR usToTimerTicks(uint32_t us)
{
if(us == 0)
return 0;

// Get current timer frequency, which is variable
uint32_t freq = getTimerClockFreq();

// Larger values may overflow
if(us > 0x35A)
return (us / 4) * (freq / 250000) + (us % 4) * (freq / 1000000);

return us * freq / 1000000;
}

uint32_t IRAM_ATTR timerTicksToUs(uint32_t ticks)
{
// Be careful to avoid overflows
return 10000 * ticks / (getTimerClockFreq() / 100);
}

#define FRC1_ENABLE_TIMER BIT7
#define FRC1_AUTO_LOAD BIT6
@@ -85,7 +114,7 @@ bool Hardware_Timer::start(bool repeating /* = true*/)
ETS_FRC1_INTR_ENABLE();
started = true;

RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(interval));
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, usToTimerTicks(interval));
return started;
}

10 changes: 10 additions & 0 deletions Sming/SmingCore/HardwareTimer.h
Original file line number Diff line number Diff line change
@@ -21,6 +21,16 @@
#define MAX_HW_TIMER_INTERVAL_US 0x7fffff ///< Maximum timer interval in microseconds
#define MIN_HW_TIMER_INTERVAL_US 0x32 ///< Minimum hardware interval in microseconds

/** @brief Convert microseconds into timer ticks.
* @note Replaces the previous US_TO_RTC_TIMER_TICKS macro to guarantee we use the correct timer prescale value.
*/
uint32_t IRAM_ATTR usToTimerTicks(uint32_t us);

/** @brief Convert timer ticks into microseconds
* @note accounts for current timer prescale setting
*/
uint32_t IRAM_ATTR timerTicksToUs(uint32_t ticks);

/** @brief Delegate callback type for timer trigger
*/
typedef Delegate<void()> TimerDelegate;
58 changes: 58 additions & 0 deletions samples/Basic_ProgMem/app/TestProgmem.cpp
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
#include "TestProgmem.h"
#include "FlashData.h"
#include "Print.h"
#include "Services/Profiling/ElapseTimer.h"

// Note: contains nulls which won't display, but will be stored
#define DEMO_TEST_TEXT "This is a flash string -\0Second -\0Third -\0Fourth."
@@ -131,8 +132,65 @@ void testFSTR(Print& out)
out.println("< testFSTR() end\n");
}

/*
* Run a load of iterations for PSTR/FSTR options to illustrate relative performance.
*/
void testSpeed(Print& out)
{
const unsigned iterations = 200;

out.printf("Speed tests, %u iterations, times in microseconds\n", iterations);
ElapseTimer timer;
unsigned tmp = 0;
uint32_t baseline, elapsed;

_FPUTS("Baseline test, read string in RAM...");
timer.start();
for(unsigned i = 0; i < iterations; ++i)
tmp += sumBuffer(demoText, sizeof(demoText));
baseline = timer.elapsed();
out.printf("Elapsed: %u\n", baseline);

#define END() \
elapsed = timer.elapsed(); \
out.printf("Elapsed: %u (baseline + %u)\n", elapsed, elapsed - baseline);

_FPUTS("Load PSTR into stack buffer...");
timer.start();
for(unsigned i = 0; i < iterations; ++i) {
LOAD_PSTR(buf, demoPSTR1);
tmp += sumBuffer(buf, sizeof(buf));
}
END()

_FPUTS("Load PSTR into String...");
timer.start();
for(unsigned i = 0; i < iterations; ++i) {
String s(demoFSTR1.data());
tmp += sumBuffer(s.c_str(), s.length() + 1);
}
END()

_FPUTS("Load FlashString into stack buffer...");
timer.start();
for(unsigned i = 0; i < iterations; ++i) {
LOAD_FSTR(buf, demoFSTR1);
tmp += sumBuffer(buf, sizeof(buf));
}
END()

_FPUTS("Load FlashString into String...");
timer.start();
for(unsigned i = 0; i < iterations; ++i) {
String s(demoFSTR1);
tmp += sumBuffer(s.c_str(), s.length() + 1);
}
END()
}

void testProgmem(Print& out)
{
testPSTR(out);
testFSTR(out);
testSpeed(out);
}