How deterministic is setWatch?

Posted on
  • I'm working on a project idea for the Pico that will have a slide potentiometer and a couple buttons. I intended to use setWatch to watch for the pins that are connected to the pot and buttons, but I'm wondering how responsive my code will be, especially regarding the pot. I plan on setting the watches for 10ms, but I don't know if having 3 separate 10ms watches on 3 input pins will create unpredictable latency (i.e. will my code get called at unpredictable intervals, ruining the real-time feel to the user).

    And of course, the code will be acting on these timers, sending data out a USART, receiving commands on that USART...so quite a bit going on. I'm also wondering if all that other activity could impact the determinism of the watches.

    Any thoughts on that? Suggestions for improvement?

  • You may have some trouble using watches on the potentiometer - setWatch is generally only for digital inputs.

    But generally:

    • setWatch queues an event basically immediately with a timestamp, which is very deterministic
    • Espruino executes that event the next time around the idle loop, which depends on what JS you're currently executing

    So as long as you keep the tasks that you're running reasonably short then your code is going to be executed within just a few milliseconds.

    The only gotcha is if for example you're blasting the UART with data faster than it can transmit then that could fill the output buffer and stop a function executing quickly, which could slow things down.

    However if you're talking about buttons and user input, setWatch is basically immediate - pretty much whatever you do it'll be executing the JS before you know it :)

  • Tue 2019.07.23

    '(i.e. will my code get called at unpredictable intervals. . .'

    Hi @indianajones, with the concept presented, it's more likely that setInterval() will be of concern.

    Excellent article:

    How JavaScript Timers Work

    https://johnresig.com/blog/how-javascrip­t-timers-work/

  • Thanks everyone for taking the time for thoughtful replies.

    I have a little-more-than-basic understanding of js and node, which is what prompted the questions. Of course, I've never run this on a microcontroller, where there is no mouse, hard drive, display, etc to manage at the same time -- which gives one hope! Because I have no plans for any code to be long-running (just "get in and get out"), I'm hopeful that the js code will be able to perform with a real-time feel to it.

    The USART will be communicating with another microcontroller, sending and receiving messages at -- hopefully -- 10ms intervals. It will never be a stream of data, just a message payload sent at a pre-determined interval. The payload would be less than 1kb always, and frequently be less than 100 bytes. So I doubt I'll have problems overloading the buffer (unless I do something in the code that's long-running). BUT, there are commands in that buffer which the javascript will be executing: perhaps turning on/off an LED, bits like that. So there IS work in there, I just don't think I'm I/O constrained.

    At the moment, I have no code that needs to run every XX milliseconds "just because"; I'll only have code that will run as a response to external stimuli (button press, that darn slider pot), and to commands from the USART. So I chose setWatch.

    Yeah that slide pot is the big worry, because the code to handle a change in the pot would be something like:
    potCallback() {

    receive_pot_value();
    send_56_byte_message_to_USART();
    

    }

    If the user is just reaming on the slider, generating tons of these callbacks, while messages are coming IN to the USART, that's where I worry about latency becoming a concern.

    I could also slow down the watches and USART to 15ms to allow for more breathing room - that's still 66 updates per second.

  • The setWatch() documentation says this, regarding the 'options' field:

    // Advanced: If the function supplied is a 'native' function (compiled or assembly)
    // setting irq:true will call that function in the interrupt itself
    irq : false(default)

    Does that mean that the compiled code would NOT be executed by the node event loop?
    And as a result, instead of the event being put in an event queue, and possibly held up by other javascript code running, the code would run immediately?

    Could that be a better way to handle the pot (as compiled code)?

  • Is the slide potentiometer a digital input?

  • @maze1980, no, it's a legit pot, power, ground, third pin for resistance. https://www.sparkfun.com/products/10976

  • Tue 2019.07.23

    above #4 'The USART will be communicating with another microcontroller'

    @indianajones, I started a project with the same/similar requirement just two weeks ago:

    http://forum.espruino.com/conversations/­336061/

    Running low on available pins, so searching for another solution. It appears I may have to resort back to the USART solution, but without a signalling pin. Still a couple of weeks out on getting back to that. Should you find some success, would you mind posting a few snippets to present some ideas please? That would improve my awareness on how to find the solution to this goal. When completed, I'd be willing to create a tutorial for this very subject, unless of course, someone has the desire and beats me to that completion.   wink, wink


    http://www.espruino.com/Reference#l__glo­bal_setWatch

     

    ' be executed by the node event loop'

    No experience with node, but is your question base on the similar loop function concept that Arduino uses? I stay away from the loop concept with Espruino, favoring the setInterval() function instead. And link in #3

    http://www.espruino.com/Reference#t_l__g­lobal_setInterval

    For #5 The next comment beneath the one you referenced,

    '// Advanced: If specified, the given pin will be read whenever the watch is called
    // and the state will be included as a 'data' field in the callback'

    I've not used that option, so I'm unsure. My impression is that the compiled code is just referenced/utilized within the hardware interrupt, at that level, when it occurs. The same callback that is provided will be executed either way.

    I'll defer to @Gordon as he would be the better source to answer your #5 question. Please be patient waiting for an answer as new Espruino features are his main priority currently.

  • @Robin thanks for the reply, and @Gordon thanks for taking the time to help. RE: node event loop, it's not quite like the Arduino loop - I wasn't referring to Arduino's loop(), but rather how I believe the underlying Espruino code works. And even now I'm not sure that this clarification is helpful. Apologies for that.

    At any rate, what I hope the code will be able to accomplish is this:

    1) Read a pot's value every 10ms using setWatch
        a) Send that pot's value on Serial1 at the next serial message setInterval (every 10ms)
    2) Read a button press every 20ms using setWatch
        a) Send the button state on Serial1 at the next serial message setInterval (every 10ms)
        b) Enable/Disable the button's LED
    3) Receive a series of messages, totaling 100-ish bytes, on Serial1 from a sender, every 10ms
        a) if the message is present, move the pot's fader (motorized fader)
        b) if the message is present, send LED on/off commands to LED strip via SPI
        c) if the message is present, enable/disable that button's LED (from #2 above)
    

    That's the entire project. One setWatch(10ms), one setWatch(20ms), and one setInterval(10ms), each doing a small task or three and then getting out. With all that going on, my question was essentially "will the button's LED light immediately, when I press the button?", and "when I yank the fader back and forth, will the messages get sent with a real-time feel? Or will the messages stack up and have more of a burst-y feel?" I think I may have to write it all to find out, but any tips that helps minimize latency would be awesome.

  • setWatch calls a function when the digital input changes, from low to high, from high to low, or in both cases. If you want to read a value every 20ms you'll have to use setInterval. I'd change to:
    1) Run every 10ms using setInterval
    a) read pot
    b)read button/set led
    c) send data

    If you move your fader or not, messages are sent every 10ms.

  • @maze1980 I can live with that. Thanks!

  • I think realistically you want setWatch for the button and setInterval for the potentiometer.

    I see no problem at all with what you're doing - just be aware that the UART's default is 9600 baud - so ~960 bytes per second. So 56 bytes 100 times a second is more than that - you'll need to use a higher baud rate - maybe 115200?

    edit: about the irqs - yes, that would make your code run instantly but it only works for C functions, not JS (and introduces a lot more stuff you have to worry about). For what you're doing the 100% standard setWatch will work perfectly

  • I think I've talked myself out of USART - not because of this conversation, but because I thought I could connect multiple Picos a la RS485 via USART, but I think that wouldn't be very easy to accomplish. So instead of USART, I'm considering other options. I2C or USB perhaps.

  • Ok, thanks for the update.

    I thought I could connect multiple Picos a la RS485 via USART, but I think that wouldn't be very easy to accomplish.

    That's actually pretty easy and it works really nicely - I posted some example code on your new post about this here: http://forum.espruino.com/conversations/­336570/#comment14837888

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How deterministic is setWatch?

Posted by Avatar for indianajones @indianajones

Actions