wokwi / avr8js

Arduino (8-bit AVR) simulator, written in JavaScript and runs in the browser / Node.js
https://blog.wokwi.com/avr8js-simulate-arduino-in-javascript/
MIT License
462 stars 73 forks source link

millis() & delay() reflecting real time #86

Closed hapiel closed 3 years ago

hapiel commented 3 years ago

I'm having an issue with the speed AVR8js runs. I'm making some games, and for this it is ideal if the speed is always constant, but I noticed that in AVR8js functions like millis() or delay() don't portrait time realistically.

I've played around with the board clock speed but this of course doesn't change much. I suppose millis() is based on the amount of ticks the virtual cpu has ran, and that the virtual cpu speed is varying?

Do you have advice on how we could link time in the virtual board to the real time as given by the browser, so that our emulated games will run at the same speed on every system?

urish commented 3 years ago

Basically, the trick would be to cap the number of cycles emulated, so you never go past 100%. This method I'm currently using on wokwi.com, starting from last weekend:

  1. Use requestAnimationFrame() to schedule the simulation chunks
  2. In each simulation chunks run a number of cycles that corresponds to a single frame, that is 1/60 of a second.
  3. In case the simulation chunks runs for longer than a single frame, use the TaskScheduler to schedule the next frame immediately, and increase the number of simulation cycles that will be run in the next frame.

I created for you a demo with a simplified version (parts 1/2), which should suffice for simple simulations:

https://stackblitz.com/edit/avr8js-stable-speed?file=execute.ts

You can find the algorithm in the execute() method of the AVRRunner class