Commit dd38a0a0 authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Imported reworked rtctime support.

parent 09410d55
// Headers to the various functions in the rom (as we discover them) // Headers to the various functions in the rom (as we discover them)
#ifndef _ROM_H_
#define _ROM_H_
// SHA1 is assumed to match the netbsd sha1.h headers // SHA1 is assumed to match the netbsd sha1.h headers
#define SHA1_DIGEST_LENGTH 20 #define SHA1_DIGEST_LENGTH 20
#define SHA1_DIGEST_STRING_LENGTH 41 #define SHA1_DIGEST_STRING_LENGTH 41
...@@ -103,3 +106,4 @@ typedef void (*exception_handler_fn) (struct exception_frame *ef, uint32_t cause ...@@ -103,3 +106,4 @@ typedef void (*exception_handler_fn) (struct exception_frame *ef, uint32_t cause
*/ */
exception_handler_fn _xtos_set_exception_handler (uint32_t cause, exception_handler_fn handler); exception_handler_fn _xtos_set_exception_handler (uint32_t cause, exception_handler_fn handler);
#endif
...@@ -9,14 +9,12 @@ ...@@ -9,14 +9,12 @@
#define RTC_TARGET_ADDR 0x04 #define RTC_TARGET_ADDR 0x04
#define RTC_COUNTER_ADDR 0x1c #define RTC_COUNTER_ADDR 0x1c
#define EARLY_ENTRY_ATTR __attribute__((section(".text"))) static inline uint32_t rtc_mem_read(uint32_t addr)
static inline uint32_t EARLY_ENTRY_ATTR rtc_mem_read(uint32_t addr)
{ {
return ((uint32_t*)RTC_USER_MEM_BASE)[addr]; return ((uint32_t*)RTC_USER_MEM_BASE)[addr];
} }
static inline void EARLY_ENTRY_ATTR rtc_mem_write(uint32_t addr, uint32_t val) static inline void rtc_mem_write(uint32_t addr, uint32_t val)
{ {
((uint32_t*)RTC_USER_MEM_BASE)[addr]=val; ((uint32_t*)RTC_USER_MEM_BASE)[addr]=val;
} }
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
// (9/10) are meaningless when (3) is zero // (9/10) are meaningless when (3) is zero
// //
#define RTC_FIFO_BASE 8 #define RTC_FIFO_BASE 10
#define RTC_FIFO_MAGIC 0x44695553 #define RTC_FIFO_MAGIC 0x44695553
// RTCFIFO storage // RTCFIFO storage
...@@ -85,6 +85,10 @@ ...@@ -85,6 +85,10 @@
#define RTC_DEFAULT_TAGCOUNT 5 #define RTC_DEFAULT_TAGCOUNT 5
#define RTC_DEFAULT_FIFO_LOC (RTC_DEFAULT_FIFO_START + (RTC_DEFAULT_FIFO_END<<8) + (RTC_DEFAULT_TAGCOUNT<<16)) #define RTC_DEFAULT_FIFO_LOC (RTC_DEFAULT_FIFO_START + (RTC_DEFAULT_FIFO_END<<8) + (RTC_DEFAULT_TAGCOUNT<<16))
#ifndef RTCTIME_SLEEP_ALIGNED
# define RTCTIME_SLEEP_ALIGNED rtc_time_deep_sleep_until_aligned
#endif
typedef struct typedef struct
{ {
uint32_t timestamp; uint32_t timestamp;
...@@ -340,7 +344,8 @@ static int32_t rtc_fifo_delta_t(uint32_t t, uint32_t ref_t) ...@@ -340,7 +344,8 @@ static int32_t rtc_fifo_delta_t(uint32_t t, uint32_t ref_t)
static uint32_t rtc_fifo_construct_entry(uint32_t val, uint32_t tagindex, uint32_t decimals, uint32_t deltat) static uint32_t rtc_fifo_construct_entry(uint32_t val, uint32_t tagindex, uint32_t decimals, uint32_t deltat)
{ {
return val+(deltat<<16)+(decimals<<25)+(tagindex<<28); return (val & 0xffff) + ((deltat & 0x1ff) <<16) +
((decimals & 0x7)<<25) + ((tagindex & 0xf)<<28);
} }
static inline void rtc_fifo_store_sample(const sample_t* s) static inline void rtc_fifo_store_sample(const sample_t* s)
...@@ -467,10 +472,10 @@ static inline void rtc_fifo_unset_magic(void) ...@@ -467,10 +472,10 @@ static inline void rtc_fifo_unset_magic(void)
rtc_mem_write(RTC_FIFO_MAGIC_POS,0); rtc_mem_write(RTC_FIFO_MAGIC_POS,0);
} }
static inline void rtc_fifo_deep_sleep_until_sample(uint32_t min_sleep_us, uint32_t mhz) static inline void rtc_fifo_deep_sleep_until_sample(uint32_t min_sleep_us)
{ {
uint32_t align=rtc_mem_read(RTC_ALIGNMENT_POS); uint32_t align=rtc_mem_read(RTC_ALIGNMENT_POS);
rtc_time_deep_sleep_until_aligned(align,min_sleep_us,mhz); RTCTIME_SLEEP_ALIGNED(align,min_sleep_us);
} }
static inline void rtc_fifo_prepare(uint32_t samples_per_boot, uint32_t us_per_sample, uint32_t tagcount) static inline void rtc_fifo_prepare(uint32_t samples_per_boot, uint32_t us_per_sample, uint32_t tagcount)
......
...@@ -28,485 +28,32 @@ ...@@ -28,485 +28,32 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @author Bernd Meyer <bmeyer@dius.com.au>
* @author Johny Mattsson <jmattsson@dius.com.au> * @author Johny Mattsson <jmattsson@dius.com.au>
*/ */
#ifndef _RTCTIME_H_
#define _RTCTIME_H_
#ifndef RTCTIME_H /* We don't want to expose the raw rtctime interface as it is heavily
#define RTCTIME_H * 'static inline' and used by a few things, so instead we wrap the
* relevant functions and expose these instead, through the rtctime.c module.
#include "rtcaccess.h" */
// Layout of the RTC storage space:
//
// 0: Magic. If set to RTC_TIME_MAGIC, the rest is valid. If not, continue to proper boot
//
// 1: cycle counter offset, lower 32 bit
// 2: cycle counter offset, upper 32 bit
//
// 3: cached result of sleep clock calibration. Has the format of system_rtc_clock_cali_proc(),
// or 0 if not available (see 4/5 below)
// 4: Number of microseconds we tried to sleep, or 0 if we didn't sleep since last calibration, ffffffff if invalid
// 5: Number of RTC cycles we decided to sleep, or 0 if we didn't sleep since last calibration, ffffffff if invalid
// 6: Number of microseconds which we add to (1/2) to avoid time going backwards
// 7: microsecond value returned in the last gettimeofday() to "user space".
//
// (1:2) set to 0 if no time information is available.
// Entries 4-7 are needed because the RTC cycles/second appears quite temperature dependent,
// and thus is heavily influenced by what else the chip is doing. As such, any calibration against
// the crystal-provided clock (which necessarily would have to happen while the chip is active and
// burning a few milliwatts) will be significantly different from the actual frequency during deep
// sleep.
// Thus, in order to calibrate for deep sleep conditions, we keep track of total sleep microseconds
// and total sleep clock cycles between settimeofday() calls (which presumably are NTP driven), and
// adjust the calibration accordingly on each settimeofday(). This will also track frequency changes
// due to ambient temperature changes.
// 6/7 get used when a settimeofday() would result in turning back time. As that can cause all sorts
// of ugly issues, we *do* adjust (1/2), but compensate by making the same adjustment to (6). Then each
// time gettimeofday() is called, we inspect (7) and determine how much time has passed since the last
// call (yes, this gets it wrong if more than a second has passed, but not in a way that causes issues)
// and try to take up to 6% of that time away from (6) until (6) reaches 0. Also, whenever we go to
// deep sleep, we add (6) to the sleep time, thus catching up all in one go.
// Note that for calculating the next sample-aligned wakeup, we need to use the post-adjustment
// timeofday(), but for calculating actual sleep time, we use the pre-adjustment one, thus bringing
// things back into line.
//
#define RTC_TIME_BASE 0 // Where the RTC timekeeping block starts in RTC user memory slots
#define RTC_TIME_MAGIC 0x44695573
#define RTC_TIME_MAGIC_SLEEP 0x64697573
// What rate we run the CPU at most of the time, and thus the rate at which we keep our time data
#define CPU_DEFAULT_MHZ 80
#define CPU_BOOTUP_MHZ 52
#define RTC_TIME_CCOMPARE_INT 6 // Interrupt cause for CCOMPARE0 match
// RTCTIME storage
#define RTC_TIME_MAGIC_POS (RTC_TIME_BASE+0)
#define RTC_CYCLEOFFSETL_POS (RTC_TIME_BASE+1)
#define RTC_CYCLEOFFSETH_POS (RTC_TIME_BASE+2)
#define RTC_SLEEPTOTALUS_POS (RTC_TIME_BASE+3)
#define RTC_SLEEPTOTALCYCLES_POS (RTC_TIME_BASE+4)
#define RTC_TODOFFSETUS_POS (RTC_TIME_BASE+5)
#define RTC_LASTTODUS_POS (RTC_TIME_BASE+6)
#define RTC_CALIBRATION_POS (RTC_TIME_BASE+7)
static inline uint64_t rtc_time_get_now_us_adjusted(uint32_t mhz); #include <c_types.h>
#ifndef _RTCTIME_INTERNAL_H_
struct rtc_timeval struct rtc_timeval
{ {
uint32_t tv_sec; uint32_t tv_sec;
uint32_t tv_usec; uint32_t tv_usec;
}; };
static inline bool EARLY_ENTRY_ATTR rtc_time_check_sleep_magic(void)
{
if (rtc_mem_read(RTC_TIME_MAGIC_POS)==RTC_TIME_MAGIC_SLEEP)
return 1;
return 0;
}
static inline bool EARLY_ENTRY_ATTR rtc_time_check_wake_magic(void)
{
if (rtc_mem_read(RTC_TIME_MAGIC_POS)==RTC_TIME_MAGIC)
return 1;
return 0;
}
static inline bool EARLY_ENTRY_ATTR rtc_time_check_magic(void)
{
return rtc_time_check_wake_magic() || rtc_time_check_sleep_magic();
}
static inline void EARLY_ENTRY_ATTR rtc_time_set_wake_magic(void)
{
rtc_mem_write(RTC_TIME_MAGIC_POS,RTC_TIME_MAGIC);
}
static inline void rtc_time_set_sleep_magic(void)
{
rtc_mem_write(RTC_TIME_MAGIC_POS,RTC_TIME_MAGIC_SLEEP);
}
static inline void rtc_time_unset_magic(void)
{
rtc_mem_write(RTC_TIME_MAGIC_POS,0);
}
static inline uint32_t rtc_time_read_raw(void)
{
return rtc_reg_read(RTC_COUNTER_ADDR);
}
static inline uint32_t rtc_time_read_raw_ccount(void)
{
return xthal_get_ccount();
}
static inline uint64_t rtc_time_unix_ccount(uint32_t mhz)
{
// Do *not* cache this, as it can change before the read(s) inside the loop
if (!rtc_mem_read64(RTC_CYCLEOFFSETL_POS))
return 0;
uint64_t result=0;
// Need to be careful here of race conditions
while (!result)
{
uint32_t before=rtc_time_read_raw_ccount();
uint64_t base=rtc_mem_read64(RTC_CYCLEOFFSETL_POS);
uint32_t after=rtc_time_read_raw_ccount();
if (before<after)
{
uint64_t ccount80;
if (mhz==CPU_DEFAULT_MHZ)
ccount80=((uint64_t)before+after)/2;
else
ccount80=((uint64_t)before+after)*CPU_DEFAULT_MHZ/(2*mhz);
result=base+ccount80;
}
}
return result;
}
static inline uint64_t rtc_time_unix_us(uint32_t mhz)
{
return rtc_time_unix_ccount(mhz)/CPU_DEFAULT_MHZ;
}
static inline void rtc_time_register_time_reached(uint32_t s, uint32_t us)
{
rtc_mem_write(RTC_LASTTODUS_POS,us);
}
static inline uint32_t rtc_time_us_since_time_reached(uint32_t s, uint32_t us)
{
uint32_t lastus=rtc_mem_read(RTC_LASTTODUS_POS);
if (us<lastus)
us+=1000000;
return us-lastus;
}
// A small sanity check so sleep times go completely nuts if someone
// has provided wrong timestamps to gettimeofday.
static inline bool rtc_time_calibration_is_sane(uint32_t cali)
{
return (cali>=(4<<12)) && (cali<=(10<<12));
}
static inline void rtc_time_settimeofday(const struct rtc_timeval* tv)
{
if (!rtc_time_check_magic())
return;
uint32_t sleep_us=rtc_mem_read(RTC_SLEEPTOTALUS_POS);
uint32_t sleep_cycles=rtc_mem_read(RTC_SLEEPTOTALCYCLES_POS);
// At this point, the CPU clock will definitely be at the default rate (nodemcu fully booted)
uint64_t now_esp_us=rtc_time_get_now_us_adjusted(CPU_DEFAULT_MHZ);
uint64_t now_ntp_us=((uint64_t)tv->tv_sec)*1000000+tv->tv_usec;
int64_t diff_us=now_esp_us-now_ntp_us;
// Store the *actual* time.
uint64_t target_ccount=now_ntp_us*CPU_DEFAULT_MHZ;
// again, be mindful of race conditions
while (1)
{
uint32_t before=rtc_time_read_raw_ccount();
rtc_mem_write64(RTC_CYCLEOFFSETL_POS,target_ccount-before);
uint32_t after=rtc_time_read_raw_ccount();
if (before<after)
break;
}
// calibrate sleep period based on difference between expected time and actual time
if (sleep_us>0 && sleep_us<0xffffffff &&
sleep_cycles>0 && sleep_cycles<0xffffffff)
{
uint64_t actual_sleep_us=sleep_us-diff_us;
uint32_t cali=(actual_sleep_us<<12)/sleep_cycles;
if (rtc_time_calibration_is_sane(cali))
rtc_mem_write(RTC_CALIBRATION_POS,cali);
}
rtc_mem_write(RTC_SLEEPTOTALUS_POS,0);
rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,0);
// Deal with time adjustment if necessary
if (diff_us>0) // Time went backwards. Avoid that....
{
if (diff_us>0xffffffffULL)
diff_us=0xffffffffULL;
now_ntp_us+=diff_us;
}
else
diff_us=0;
rtc_mem_write(RTC_TODOFFSETUS_POS,diff_us);
uint32_t now_s=now_ntp_us/1000000;
uint32_t now_us=now_ntp_us%1000000;
rtc_time_register_time_reached(now_s,now_us);
}
static inline uint32_t rtc_time_get_calibration(void)
{
uint32_t cal=rtc_time_check_magic()?rtc_mem_read(RTC_CALIBRATION_POS):0;
if (!cal)
{
// Make a first guess, most likely to be rather bad, but better then nothing.
#ifndef BOOTLOADER_CODE // This will pull in way too much of the system for the bootloader to handle.
ets_delay_us(200);
cal=system_rtc_clock_cali_proc();
rtc_mem_write(RTC_CALIBRATION_POS,cal);
#else
cal=6<<12;
#endif #endif
}
return cal;
}
static inline void rtc_time_invalidate_calibration(void)
{
rtc_mem_write(RTC_CALIBRATION_POS,0);
}
static inline uint64_t rtc_time_us_to_ticks(uint64_t us) void TEXT_SECTION_ATTR rtctime_early_startup (void);
{ void rtctime_late_startup (void);
uint32_t cal=rtc_time_get_calibration(); void rtctime_gettimeofday (struct rtc_timeval *tv);
void rtctime_settimeofday (const struct rtc_timeval *tv);
return (us<<12)/cal; bool rtctime_have_time (void);
} void rtctime_deep_sleep_us (uint32_t us);
void rtctime_deep_sleep_until_aligned_us (uint32_t align_us, uint32_t min_us);
static inline uint64_t rtc_time_get_now_us_raw(uint32_t mhz)
{
if (!rtc_time_check_magic())
return 0;
return rtc_time_unix_us(mhz);
}
static inline uint64_t rtc_time_get_now_us_adjusted(uint32_t mhz)
{
uint64_t raw=rtc_time_get_now_us_raw(mhz);
if (!raw)
return 0;
return raw+rtc_mem_read(RTC_TODOFFSETUS_POS);
}
static inline void rtc_time_gettimeofday(struct rtc_timeval* tv, uint32_t mhz)
{
uint64_t now=rtc_time_get_now_us_adjusted(mhz);
uint32_t sec=now/1000000;
uint32_t usec=now%1000000;
uint32_t to_adjust=rtc_mem_read(RTC_TODOFFSETUS_POS);
if (to_adjust)
{
uint32_t us_passed=rtc_time_us_since_time_reached(sec,usec);
uint32_t adjust=us_passed>>4;
if (adjust)
{
if (adjust>to_adjust)
adjust=to_adjust;
to_adjust-=adjust;
now-=adjust;
now/1000000;
now%1000000;
rtc_mem_write(RTC_TODOFFSETUS_POS,to_adjust);
}
}
tv->tv_sec=sec;
tv->tv_usec=usec;
rtc_time_register_time_reached(sec,usec);
}
static inline void rtc_time_add_sleep_tracking(uint32_t us, uint32_t cycles)
{
if (rtc_time_check_magic())
{
// us is the one that will grow faster...
uint32_t us_before=rtc_mem_read(RTC_SLEEPTOTALUS_POS);
uint32_t us_after=us_before+us;
uint32_t cycles_after=rtc_mem_read(RTC_SLEEPTOTALCYCLES_POS)+cycles;
if (us_after<us_before) // Give up if it would cause an overflow
{
us_after=cycles_after=0xffffffff;
}
rtc_mem_write(RTC_SLEEPTOTALUS_POS, us_after);
rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,cycles_after);
}
}
static void rtc_time_enter_deep_sleep_us(uint32_t us)
{
if (rtc_time_check_wake_magic())
rtc_time_set_sleep_magic();
rtc_reg_write(0,0);
rtc_reg_write(0,rtc_reg_read(0)&0xffffbfff);
rtc_reg_write(0,rtc_reg_read(0)|0x30);
rtc_reg_write(0x44,4);
rtc_reg_write(0x0c,0x00010010);
rtc_reg_write(0x48,(rtc_reg_read(0x48)&0xffff01ff)|0x0000fc00);
rtc_reg_write(0x48,(rtc_reg_read(0x48)&0xfffffe00)|0x00000080);
rtc_reg_write(RTC_TARGET_ADDR,rtc_time_read_raw()+136);
rtc_reg_write(0x18,8);
rtc_reg_write(0x08,0x00100010);
ets_delay_us(20);
rtc_reg_write(0x9c,17);
rtc_reg_write(0xa0,3);
rtc_reg_write(0x0c,0x640c8);
rtc_reg_write(0,rtc_reg_read(0)&0xffffffcf);
uint32_t cycles=rtc_time_us_to_ticks(us);
rtc_time_add_sleep_tracking(us,cycles);
rtc_reg_write(RTC_TARGET_ADDR,rtc_time_read_raw()+cycles);
rtc_reg_write(0x9c,17);
rtc_reg_write(0xa0,3);
// Clear bit 0 of DPORT 0x04. Doesn't seem to be necessary
// wm(0x3fff0004,bitrm(0x3fff0004),0xfffffffe));
rtc_reg_write(0x40,-1);
rtc_reg_write(0x44,32);
rtc_reg_write(0x10,0);
rtc_reg_write(0x18,8);
rtc_reg_write(0x08,0x00100000); // go to sleep
}
static inline void rtc_time_deep_sleep_us(uint32_t us, uint32_t mhz)
{
if (rtc_time_check_magic())
{
uint32_t to_adjust=rtc_mem_read(RTC_TODOFFSETUS_POS);
if (to_adjust)
{
us+=to_adjust;
rtc_mem_write(RTC_TODOFFSETUS_POS,0);
}
uint64_t now=rtc_time_get_now_us_raw(mhz); // Now the same as _adjusted()
if (now)
{ // Need to maintain the clock first. When we wake up, counter will be 0
uint64_t wakeup=now+us;
uint64_t wakeup_cycles=wakeup*CPU_DEFAULT_MHZ;
rtc_mem_write64(RTC_CYCLEOFFSETL_POS,wakeup_cycles);
}
}
rtc_time_enter_deep_sleep_us(us);
}
static inline void rtc_time_deep_sleep_until_aligned(uint32_t align, uint32_t min_sleep_us, uint32_t mhz)
{
uint64_t now=rtc_time_get_now_us_adjusted(mhz);
uint64_t then=now+min_sleep_us;
if (align)
{
then+=align-1;
then-=(then%align);
}
rtc_time_deep_sleep_us(then-now,mhz);
}
static inline void EARLY_ENTRY_ATTR rtc_time_reset(bool clear_cali)
{
rtc_mem_write64(RTC_CYCLEOFFSETL_POS,0);
rtc_mem_write(RTC_SLEEPTOTALUS_POS,0);
rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,0);
rtc_mem_write(RTC_TODOFFSETUS_POS,0);
rtc_mem_write(RTC_LASTTODUS_POS,0);
if (clear_cali)
rtc_mem_write(RTC_CALIBRATION_POS,0);
}
static inline void EARLY_ENTRY_ATTR rtc_time_register_bootup(void)
{
uint32_t reset_reason=rtc_get_reset_reason();
#ifndef BOOTLOADER_CODE
static const bool erase_calibration=true;
#else
// In the boot loader, any leftover calibration is going to be better than anything we can
// come up with....
static const bool erase_calibration=false;
#endif
if (rtc_time_check_sleep_magic())
{
if (reset_reason!=2) // This was *not* a proper wakeup from a deep sleep. All our time keeping is f*cked!
rtc_time_reset(erase_calibration); // Possibly keep the calibration, it should still be good
rtc_time_set_wake_magic();
return;
}
if (rtc_time_check_wake_magic())
{
// This was *not* a proper wakeup from rtc-time initiated deep sleep. All our time keeping is f*cked!
rtc_time_reset(erase_calibration); // Possibly keep the calibration, it should still be good
}
}
static inline void EARLY_ENTRY_ATTR rtc_time_switch_to_default_clock(uint32_t mhz)
{
if (rtc_time_check_magic())
{
uint64_t cycles=rtc_time_read_raw_ccount();
uint64_t missing_cycles=cycles*(CPU_DEFAULT_MHZ-mhz)/mhz;
uint64_t offset=rtc_mem_read64(RTC_CYCLEOFFSETL_POS);
if (offset)
{
rtc_mem_write64(RTC_CYCLEOFFSETL_POS,offset+missing_cycles);
}
}
}
static inline void rtc_time_ccount_wrap_handler(void* dst_v, uint32_t sp)
{
uint32_t off_h=rtc_mem_read(RTC_CYCLEOFFSETH_POS);
if (rtc_time_check_magic() && off_h)
{
rtc_mem_write(RTC_CYCLEOFFSETH_POS,off_h+1);
}
xthal_set_ccompare(0,0); // This resets the interrupt condition
}
static inline void EARLY_ENTRY_ATTR rtc_time_install_wrap_handler(void)
{
xthal_set_ccompare(0,0); // Recognise a ccounter wraparound
ets_isr_attach(RTC_TIME_CCOMPARE_INT,rtc_time_ccount_wrap_handler,NULL);
ets_isr_unmask(1<<RTC_TIME_CCOMPARE_INT);
}
// Call this from the nodemcu entry point, i.e. just before we switch from 52MHz to 80MHz
static inline void EARLY_ENTRY_ATTR rtc_time_switch_clocks(void)
{
rtc_time_install_wrap_handler();
rtc_time_switch_to_default_clock(CPU_BOOTUP_MHZ);
}
static inline bool rtc_time_have_time(void)
{
return (rtc_time_check_magic() && rtc_mem_read64(RTC_CYCLEOFFSETL_POS)!=0);
}
static inline void rtc_time_prepare(void)
{
rtc_time_reset(true);
rtc_time_set_wake_magic();
}
#endif #endif
This diff is collapsed.
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "user_modules.h" #include "user_modules.h"
#include "rtc/rtctime.h"
#define RTCTIME_SLEEP_ALIGNED rtctime_deep_sleep_until_aligned_us
#include "rtc/rtcfifo.h" #include "rtc/rtcfifo.h"
// rtcfifo.prepare ([{sensor_count=n, interval_us=m, storage_begin=x, storage_end=y}]) // rtcfifo.prepare ([{sensor_count=n, interval_us=m, storage_begin=x, storage_end=y}])
...@@ -67,12 +69,8 @@ static int rtcfifo_put (lua_State *L) ...@@ -67,12 +69,8 @@ static int rtcfifo_put (lua_State *L)
sample_t s; sample_t s;
s.timestamp = luaL_checknumber (L, 1); s.timestamp = luaL_checknumber (L, 1);
double val = luaL_checknumber (L, 2); s.value = luaL_checknumber (L, 2);
s.decimals = luaL_checknumber (L, 3); s.decimals = luaL_checknumber (L, 3);
uint32_t i = s.decimals;
while (i--)
val *= 10;
s.value = val;
size_t len; size_t len;
const char *str = luaL_checklstring (L, 4, &len); const char *str = luaL_checklstring (L, 4, &len);
union { union {
...@@ -90,11 +88,7 @@ static int rtcfifo_put (lua_State *L) ...@@ -90,11 +88,7 @@ static int rtcfifo_put (lua_State *L)
static int extract_sample (lua_State *L, const sample_t *s) static int extract_sample (lua_State *L, const sample_t *s)
{ {
lua_pushnumber (L, s->timestamp); lua_pushnumber (L, s->timestamp);
double val = s->value; lua_pushnumber (L, s->value);
int i;
for (i = 0; i < s->decimals; ++i)
val /= 10;
lua_pushnumber (L, val);
lua_pushnumber (L, s->decimals); lua_pushnumber (L, s->decimals);
union { union {
uint32_t u; uint32_t u;
...@@ -164,7 +158,7 @@ static int rtcfifo_dsleep_until_sample (lua_State *L) ...@@ -164,7 +158,7 @@ static int rtcfifo_dsleep_until_sample (lua_State *L)
check_fifo_magic (L); check_fifo_magic (L);
uint32_t min_us = luaL_checknumber (L, 1); uint32_t min_us = luaL_checknumber (L, 1);
rtc_fifo_deep_sleep_until_sample (min_us, CPU_DEFAULT_MHZ); // no return rtc_fifo_deep_sleep_until_sample (min_us); // no return
return 0; return 0;
} }
#endif #endif
......
// Module for RTC time keeping // Module for RTC time keeping
#include "lauxlib.h" #include "lauxlib.h"
#include "rtc/rtctime_internal.h"
#include "rtc/rtctime.h" #include "rtc/rtctime.h"
// rtctime.settimeofday (sec, usec)
static int rtctime_settimeofday (lua_State *L) // ******* C API functions *************
void rtctime_early_startup (void)
{
Cache_Read_Enable (0, 0, 1);
rtc_time_register_bootup ();
rtc_time_switch_clocks ();
Cache_Read_Disable ();
}
void rtctime_late_startup (void)
{
rtc_time_switch_system ();
}
void rtctime_gettimeofday (struct rtc_timeval *tv)
{
rtc_time_gettimeofday (tv);
}
void rtctime_settimeofday (const struct rtc_timeval *tv)
{
if (!rtc_time_check_magic ())
rtc_time_prepare ();
rtc_time_settimeofday (tv);
}
bool rtctime_have_time (void)
{
return rtc_time_have_time ();
}
void rtctime_deep_sleep_us (uint32_t us)
{
rtc_time_deep_sleep_us (us);
}
void rtctime_deep_sleep_until_aligned_us (uint32_t align_us, uint32_t min_us)
{
rtc_time_deep_sleep_until_aligned (align_us, min_us);
}
// ******* Lua API functions *************
// rtctime.set (sec, usec)
static int rtctime_set (lua_State *L)
{ {
if (!rtc_time_check_magic ()) if (!rtc_time_check_magic ())
rtc_time_prepare (); rtc_time_prepare ();
...@@ -15,16 +64,16 @@ static int rtctime_settimeofday (lua_State *L) ...@@ -15,16 +64,16 @@ static int rtctime_settimeofday (lua_State *L)
usec = lua_tonumber (L, 2); usec = lua_tonumber (L, 2);
struct rtc_timeval tv = { sec, usec }; struct rtc_timeval tv = { sec, usec };
rtc_time_settimeofday (&tv); rtctime_settimeofday (&tv);
return 0; return 0;
} }
// sec, usec = rtctime.gettimeofday () // sec, usec = rtctime.get ()
static int rtctime_gettimeofday (lua_State *L) static int rtctime_get (lua_State *L)
{ {
struct rtc_timeval tv; struct rtc_timeval tv;
rtc_time_gettimeofday (&tv, CPU_DEFAULT_MHZ); rtctime_gettimeofday (&tv);
lua_pushnumber (L, tv.tv_sec); lua_pushnumber (L, tv.tv_sec);
lua_pushnumber (L, tv.tv_usec); lua_pushnumber (L, tv.tv_usec);
return 2; return 2;
...@@ -46,8 +95,7 @@ static int rtctime_dsleep (lua_State *L) ...@@ -46,8 +95,7 @@ static int rtctime_dsleep (lua_State *L)
{ {
uint32_t us = luaL_checknumber (L, 1); uint32_t us = luaL_checknumber (L, 1);
do_sleep_opt (L, 2); do_sleep_opt (L, 2);
// does not return rtctime_deep_sleep_us (us); // does not return
rtc_time_deep_sleep_us (us, CPU_DEFAULT_MHZ);
return 0; return 0;
} }
...@@ -55,14 +103,13 @@ static int rtctime_dsleep (lua_State *L) ...@@ -55,14 +103,13 @@ static int rtctime_dsleep (lua_State *L)
// rtctime.dsleep_aligned (aligned_usec, min_usec, option) // rtctime.dsleep_aligned (aligned_usec, min_usec, option)
static int rtctime_dsleep_aligned (lua_State *L) static int rtctime_dsleep_aligned (lua_State *L)
{ {
if (!rtc_time_have_time ()) if (!rtctime_have_time ())
return luaL_error (L, "time not available, unable to align"); return luaL_error (L, "time not available, unable to align");
uint32_t align_us = luaL_checknumber (L, 1); uint32_t align_us = luaL_checknumber (L, 1);
uint32_t min_us = luaL_checknumber (L, 2); uint32_t min_us = luaL_checknumber (L, 2);
do_sleep_opt (L, 3); do_sleep_opt (L, 3);
// does not return rtctime_deep_sleep_until_aligned_us (align_us, min_us); // does not return
rtc_time_deep_sleep_until_aligned (align_us, min_us, CPU_DEFAULT_MHZ);
return 0; return 0;
} }
...@@ -72,8 +119,8 @@ static int rtctime_dsleep_aligned (lua_State *L) ...@@ -72,8 +119,8 @@ static int rtctime_dsleep_aligned (lua_State *L)
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE rtctime_map[] = const LUA_REG_TYPE rtctime_map[] =
{ {
{ LSTRKEY("settimeofday"), LFUNCVAL(rtctime_settimeofday) }, { LSTRKEY("set"), LFUNCVAL(rtctime_set) },
{ LSTRKEY("gettimeofday"), LFUNCVAL(rtctime_gettimeofday) }, { LSTRKEY("get"), LFUNCVAL(rtctime_get) },
{ LSTRKEY("dsleep"), LFUNCVAL(rtctime_dsleep) }, { LSTRKEY("dsleep"), LFUNCVAL(rtctime_dsleep) },
{ LSTRKEY("dsleep_aligned"), LFUNCVAL(rtctime_dsleep_aligned) }, { LSTRKEY("dsleep_aligned"), LFUNCVAL(rtctime_dsleep_aligned) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
......
...@@ -131,7 +131,7 @@ static void sntp_dosend (lua_State *L) ...@@ -131,7 +131,7 @@ static void sntp_dosend (lua_State *L)
req.mode = 3; // client req.mode = 3; // client
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
struct rtc_timeval tv; struct rtc_timeval tv;
rtc_time_gettimeofday (&tv, CPU_DEFAULT_MHZ); rtctime_gettimeofday (&tv);
req.xmit.sec = htonl (tv.tv_sec); req.xmit.sec = htonl (tv.tv_sec);
req.xmit.frac = htonl (tv.tv_usec); req.xmit.frac = htonl (tv.tv_usec);
#else #else
...@@ -221,7 +221,7 @@ static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_a ...@@ -221,7 +221,7 @@ static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_a
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
struct rtc_timeval tv; struct rtc_timeval tv;
rtc_time_gettimeofday (&tv, CPU_DEFAULT_MHZ); rtctime_gettimeofday (&tv);
ntp_timestamp_t dest; ntp_timestamp_t dest;
dest.sec = tv.tv_sec; dest.sec = tv.tv_sec;
dest.frac = (MICROSECONDS * tv.tv_usec) / UINT32_MAXI; dest.frac = (MICROSECONDS * tv.tv_usec) / UINT32_MAXI;
...@@ -248,8 +248,7 @@ static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_a ...@@ -248,8 +248,7 @@ static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_a
tv.tv_sec = dest.sec - NTP_TO_UNIX_EPOCH; tv.tv_sec = dest.sec - NTP_TO_UNIX_EPOCH;
tv.tv_usec = (MICROSECONDS * dest.frac) / UINT32_MAXI; tv.tv_usec = (MICROSECONDS * dest.frac) / UINT32_MAXI;
rtc_time_set_wake_magic (); rtctime_settimeofday (&tv);
rtc_time_settimeofday (&tv);
if (have_cb) if (have_cb)
{ {
......
...@@ -36,18 +36,15 @@ os_event_t *taskQueue; ...@@ -36,18 +36,15 @@ os_event_t *taskQueue;
* by the time it is invoked the irom has not yet been mapped. This naturally * by the time it is invoked the irom has not yet been mapped. This naturally
* also goes for anything the trampoline itself calls. * also goes for anything the trampoline itself calls.
*/ */
void user_start_trampoline (void) TEXT_SECTION_ATTR; void TEXT_SECTION_ATTR user_start_trampoline (void)
void user_start_trampoline (void)
{ {
__real__xtos_set_exception_handler ( __real__xtos_set_exception_handler (
EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler); EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler);
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
rtc_time_register_bootup ();
// Note: Keep this as close to call_user_start() as possible, since it // Note: Keep this as close to call_user_start() as possible, since it
// is where the cpu clock actually gets bumped to 80MHz. // is where the cpu clock actually gets bumped to 80MHz.
rtc_time_switch_clocks (); rtctime_early_startup ();
#endif #endif
call_user_start (); call_user_start ();
} }
...@@ -153,6 +150,9 @@ void nodemcu_init(void) ...@@ -153,6 +150,9 @@ void nodemcu_init(void)
*******************************************************************************/ *******************************************************************************/
void user_init(void) void user_init(void)
{ {
#ifdef LUA_USE_MODULES_RTCTIME
rtctime_late_startup ();
#endif
// NODE_DBG("SDK version:%s\n", system_get_sdk_version()); // NODE_DBG("SDK version:%s\n", system_get_sdk_version());
// system_print_meminfo(); // system_print_meminfo();
// os_printf("Heap size::%d.\n",system_get_free_heap_size()); // os_printf("Heap size::%d.\n",system_get_free_heap_size());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment