jsh time functions

Posted on
  • Where can I find information about what the various jsh time functions are intended to do? E.g. jshGetSystemTime, jshSetSystemTime, jshGetMillisecondsFromTime, jshGetTimeFromMilliseconds
    Specifically:

    • why are jshGetMillisecondsFromTime and jshGetTimeFromMilliseconds hardware dependent? It seems they just multiply/divide by 1000
    • is GetSystemTime supposed to be a RTC or just a us counter form boot? Is it to keep actual time-of-day in the end or to measure elapsed us, ms, or sec between events?
    • what is the purpose of jshSetSystemTime?
      Thanks!
  • There's just the header file documentation

    why are jshGetMillisecondsFromTime and jshGetTimeFromMilliseconds hardware dependent?

    On some STM32s they return a value based on the SYSTICK timer, which runs at the clock speed of the device. It means it's nice and quick to get the time as you're basically just reading my_big_64_bit_counter+SYSTICK to get the time.

    On Espruino boards there's some insanity that allows them to 'track' the RTC with SysTick - giving accurate times off an LSE crystal white also being accurate to uS.

    is GetSystemTime supposed to be a RTC or just a us counter form boot? Is it to keep actual time-of-day in the end or to measure elapsed us, ms, or sec between events?

    It's both \o/

    It's meant to be accurate down to a uS or so, while big enough to store the date since 1970. If you do new Date() the time in it comes from this counter.

    To be honest, given ESP8266 isn't going to be very real-time (no 'real' IRQs for GPIO changes(?), and no hardware timer) I'd just run it off the RTC.

    what is the purpose of jshSetSystemTime?

    It actually sets the time you get from jshGetSystemTime - so that new Date() works fine.

    Please could you update the header file with something that makes sense to you? It might help others in the future.

  • I added design thoughts on the clocks and timers to https://github.com/espruino/Espruino/wik­i/ESP8266-Design-Notes#system-time.

    I'll add comments to jshardware.h and you can then review and correct.

  • FYI. I implemented system time. Timers are next...
    https://github.com/tve/Espruino/blob/mas­ter/targets/esp8266/jshardware.c#L317-L4­70
    Feedback welcome.

  • Looks fine to me!

  • Question about timers: the hardware timer on the esp8266 cannot do intervals under 100us nor over 8388607 microseconds. I was naively going to use a busy-wait delay for stuff under 100us but that could cause recursive calling of jstUtilTimerInterruptHandler which is "not good". Suggestions? For example, should jshUtilTimerReschedule return false if it can't do the interval?
    I have a similar question at the long end. Do I need to handle very long intervals or is there a max that Espruino will ask for?

  • An issue I've run into in implementing the timers is that all functions executed at interrupt time need to be in IRAM. This means that I need to set some __attribute__ on each one in order to ensure that they get into the right segment. This means that jstUtilTimerInterruptHandler and everything it calls needs to be tagged as such. But that seems impractical. Thoughts?
    The fallback would be to just schedule a task and do the callback there, which will be less exact.

  • I implemented the utilityTimer functions, but I'm not so sure how to test them. I thought that setTimeout would call that, but it doesn't, so I'm a bit puzzled.

    I then noticed that jshSleep gets called with a delay of (2^63)-1 (-1?) from jsInterative. What is that supposed to do with such a value?
    Could you also explain a little what jshSleep should do in general? I have the feeling that it should suspend the idle loop for the time requested, is that correct? Is there a notion of canceling a sleep?

  • I was naively going to use a busy-wait delay for stuff under 100us

    That's fine. I'd do:

    var sleepTime = 0;
    function utilTimerReschedule(time) { sleeptime = time; }
    function handleIRQ() {
      do {
       handleTimer();
      while (sleepTime<100us and not_going_for_too_long);
    }
    

    Do I need to handle long intervals

    No - just schedule for the maximum and Espruino will just do the handler, realise nothing is needed, and do nothing.

    IRAM

    Wow, that sucks. Could be a pain trying to track that all down, although not as bad as if it executed JS!

    setTimeout

    Ahh, no - so setTimeout executes JS, but since the JS takes a while to execute I provided some utility stuff that you can use for doing pulses/etc via IRQ. Main one is digitalPulse, but also Waveform uses it for recording/playing back sound, and it's also used for analogWrite(...,{soft:true})

    jshSleep

    On STM32, jshSleep should put the processor to sleep for the amount of time given, so that it wakes either after that time or when there's an IRQ from Serial, GPIO, Utility Timer, SysTick, etc. If setDeepSleep is 1 and there's nothing in the utility timer then it'll go into proper low power sleep.

    If it's given 0xFFF..FFF then that means it should only wake up if there's an IRQ - not after a time period.

  • Thanks for the clarifications! WRT jshSleep, since there's this funny main loop task thing in the esp8266 that means that any esp8266 interrupt handler or network callback needs to somehow kick-start the main loop task again if it's asleep. That's gonna a bit a maintenance headache, but certainly doable.

  • To be honest I think a minor rewrite would fix it. I think it currently looks like:

    jsiIdle() {
      // ...
      jshSleep(sleepTime);
    }
    
    jsiLoop() {
      jsiIdle();
    }
    
    main() {
    while (1) jsiLoop();
    }
    

    But we could do:

    jsiIdle() {
      // ...
      return sleepTime;
    }
    
    jsiLoop() {
      return jsiIdle();
    }
    
    main() {
    while (1) jshSleep(jsiLoop());
    }
    

    In which case suddenly in ESP8266 you've got the sleep time available at the end, so you can reschedule the callback at the right time?

    You could hack it in right now just by doing the following though?

    function jshSleep(time) {
      sleepTime = time;
    }
    
    function idleCallback() {
      sleepTime = as_soon_as_possible;
      jsiLoop();
      reschedule(idleCallback, sleepTime);
    }
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

jsh time functions

Posted by Avatar for tve @tve

Actions