Skip to content

Commit

Permalink
Introduce Clock framework and Polled Timers (#1821)
Browse files Browse the repository at this point in the history
* Define Clocks and Polled Timers

`NanoTime` provides time calculation support and base template classes for Clocks and Time Sources.
`Platform/Clocks.h` parameterises all clock sources

`PolledTimer.h` provides template class for implementing polled (elapse and timeout) timers

`Platform/Timers.h` defines available timer types

Add implementation of `esp_get_count()' to `esp_clk.h`, together with `ets_get_cpu_frequency` declaration.

* Update documentation

* Simplify samples and framework code using polled timers

* Add clocks module to HostTests

* Add section on timer range checking to docs. and add PolledTimer::checkTime() method.

* Fix NanoTime::Ticks methods

* Revise hosttests display of clock limit values
  • Loading branch information
mikee47 authored and slaff committed Sep 13, 2019
1 parent 82d21e4 commit 1f77fe5
Show file tree
Hide file tree
Showing 20 changed files with 1,997 additions and 189 deletions.
22 changes: 22 additions & 0 deletions Sming/Arch/Esp8266/Components/esp8266/include/esp_clk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <stdint.h>
#include <sming_attr.h>

#ifdef __cplusplus
extern "C" {
#endif

// system_get_cpu_frequency is just a wrapper for this ROM function.
uint8_t ets_get_cpu_frequency(void);

__forceinline static uint32_t esp_get_ccount()
{
uint32_t ccount;
__asm__ __volatile__("rsr %0, ccount\n" : "=a"(ccount) : : "memory");
return ccount;
}

#ifdef __cplusplus
}
#endif
21 changes: 7 additions & 14 deletions Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@

#include "gdbuart.h"
#include "GdbPacket.h"
#include "driver/uart.h"
#include "driver/SerialBuffer.h"
#include "Platform/System.h"
#include "HardwareSerial.h"
#include <driver/hw_timer.h>
#include <driver/uart.h>
#include <driver/SerialBuffer.h>
#include <Platform/System.h>
#include <HardwareSerial.h>
#include <Platform/Timers.h>
#include "gdbsyscall.h"

#define GDB_UART UART0 // Only UART0 supports for debugging as RX/TX required
Expand Down Expand Up @@ -109,14 +109,7 @@ static size_t ATTR_GDBEXTERNFN gdb_uart_write_char(char c)

int ATTR_GDBEXTERNFN gdbReceiveChar()
{
#if GDBSTUB_UART_READ_TIMEOUT
constexpr uint32_t timeout = round(double(HW_TIMER2_CLK) * GDBSTUB_UART_READ_TIMEOUT / 1000);
auto startTicks = NOW();
#define checkTimeout() (NOW() - startTicks >= timeout)
#else
#define checkTimeout() (false)
#endif

OneShotElapseTimer<NanoTime::Milliseconds> timer(GDBSTUB_UART_READ_TIMEOUT);
do {
wdt_feed();
system_soft_wdt_feed();
Expand All @@ -127,7 +120,7 @@ int ATTR_GDBEXTERNFN gdbReceiveChar()
#endif
return c;
}
} while(!checkTimeout());
} while(GDBSTUB_UART_READ_TIMEOUT == 0 || !timer.expired());

return -1;
}
Expand Down
33 changes: 28 additions & 5 deletions Sming/Arch/Host/Components/esp_hal/clk.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
#include "include/esp_clk.h"
#include "include/esp_system.h"

// The current CPU frequency
static uint8_t __cpu_frequency = 80;
// The current CPU frequency in MHz (ticks per us)
static uint8_t cpu_frequency = SYS_CPU_80MHZ;

bool system_update_cpu_freq(uint8 freq)
{
if(freq == 80 || freq == 160) {
__cpu_frequency = freq;
if(freq == SYS_CPU_80MHZ || freq == SYS_CPU_160MHZ) {
cpu_frequency = freq;
return true;
} else {
return false;
}
}

uint8_t ets_get_cpu_frequency(void)
{
return cpu_frequency;
}

uint8 system_get_cpu_freq(void)
{
return __cpu_frequency;
return ets_get_cpu_frequency();
}

/*
* The 'correct' conversion is actually:
*
* `os_get_nanoseconds() / (1000UL * cpu_frequency)`
*
* However, in use this just ends up returning 0 all the time which is
* not particularly useful.
*
* On my dev. system a straight nanosecond count gives quite useful
* values when evaluating code paths. Try :sample:`Basic_Delegates`.
*
*/
uint32_t esp_get_ccount()
{
return os_get_nanoseconds();
}
6 changes: 5 additions & 1 deletion Sming/Arch/Host/Components/esp_hal/include/esp_clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ extern "C" {
#define SYS_CPU_160MHZ 160

bool system_update_cpu_freq(uint8 freq);
uint8 system_get_cpu_freq(void);
uint8_t ets_get_cpu_frequency(void);
uint8_t system_get_cpu_freq(void);

/* Emulation of CPU cycle count */
uint32_t esp_get_ccount();

#ifdef __cplusplus
}
Expand Down
6 changes: 3 additions & 3 deletions Sming/Arch/Host/Components/esp_hal/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <hostlib/hostapi.h>
#include <hostlib/threads.h>
#include <sys/time.h>
#include <Rational.h>
#include <Platform/Timers.h>

/* System time */

Expand Down Expand Up @@ -54,8 +54,8 @@ uint32_t system_get_time()

void os_delay_us(uint32_t us)
{
auto start = system_get_time();
while(system_get_time() - start < us) {
ElapseTimer timer(us);
while(!timer.expired()) {
//
}
}
Expand Down
10 changes: 4 additions & 6 deletions Sming/Arch/Host/Components/hostlib/startup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
#include "options.h"
#include <spi_flash/flashmem.h>
#include <driver/uart_server.h>
#include <driver/hw_timer.h>
#include <BitManipulations.h>
#include <esp_timer_legacy.h>
#include <esp_tasks.h>
#include <host_lwip.h>
#include <stdlib.h>

#include <Platform/System.h>
#include <Platform/Timers.h>

static int exitCode = 0;
static bool done = false;
Expand Down Expand Up @@ -237,15 +237,13 @@ int main(int argc, char* argv[])

init();

const uint32_t lwipServiceInterval = 50000;
uint32_t lwipNextService = 0;
OneShotElapseTimer<NanoTime::Milliseconds> lwipServiceTimer(50);
while(!done) {
auto now = system_get_time();
host_service_tasks();
host_service_timers();
if(lwip_initialised && (now >= lwipNextService)) {
if(lwip_initialised && lwipServiceTimer.expired()) {
host_lwip_service();
lwipNextService = now + lwipServiceInterval;
lwipServiceTimer.start();
}
system_soft_wdt_feed();
}
Expand Down
145 changes: 145 additions & 0 deletions Sming/Core/NanoTime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/****
* 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.
*
* NanoTime.cpp
*
* @author mikee47 <mike@sillyhouse.net>
*
****/

#include "NanoTime.h"

#include <WString.h>

namespace NanoTime
{
const char* unitToString(Unit unit)
{
switch(unit) {
case Nanoseconds:
return "ns";
case Microseconds:
return "us";
case Milliseconds:
return "ms";
case Seconds:
return "s";
case Minutes:
return "m";
case Hours:
return "h";
case Days:
return "d";
default:
return "?s";
}
}

const char* unitToLongString(Unit unit)
{
switch(unit) {
case Nanoseconds:
return "nanoseconds";
case Microseconds:
return "microseconds";
case Milliseconds:
return "milliseconds";
case Seconds:
return "seconds";
case Minutes:
return "minutes";
case Hours:
return "hours";
case Days:
return "days";
default:
return "?s";
}
}

String Frequency::toString() const
{
auto freq = frequency;
unsigned div = 0;
while(freq % 1000 == 0) {
freq /= 1000;
++div;
}
String s(freq);
if(div == 1) {
s += 'K';
} else if(div == 2) {
s += 'M';
} else if(div == 3) {
s += 'G';
}
s += "Hz";
return s;
}

template <unsigned BufSize> class FormatBuffer
{
public:
FormatBuffer()
{
buffer[0] = '\0';
}

void add(unsigned value, unsigned digits)
{
pos += strlen(ultoa_wp(value, &buffer[pos], 10, digits, '0'));
}

void add(char c)
{
buffer[pos++] = c;
}

operator String() const
{
return String(buffer, pos);
}

private:
char buffer[BufSize];
unsigned pos = 0;
};

String TimeValue::toString() const
{
if(overflow) {
return "(OVF)";
}

FormatBuffer<64> buf;

if(days != 0) {
buf.add(days, 0);
buf.add('d');
buf.add(' ');
}

buf.add(hours, 2);
buf.add(':');
buf.add(minutes, 2);
buf.add(':');
buf.add(seconds, 2);

if(unit < NanoTime::Seconds) {
buf.add('.');
buf.add(milliseconds, 3);
if(microseconds != 0 || nanoseconds != 0) {
buf.add(microseconds, 3);
if(nanoseconds != 0) {
buf.add(nanoseconds, 3);
}
}
}

return buf;
}

} // namespace NanoTime
Loading

0 comments on commit 1f77fe5

Please sign in to comment.