Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework main and loop logic #2

Open
PMunch opened this issue Feb 8, 2022 · 4 comments
Open

Rework main and loop logic #2

PMunch opened this issue Feb 8, 2022 · 4 comments

Comments

@PMunch
Copy link
Owner

PMunch commented Feb 8, 2022

As mentioned in the FOSDEM presentation something should probably be done around the proc main() {.exportc.} and noMain which are currently required to get the really small code sizes that Ratel enjoys. After a nice conversation with @yglukhov about this and some preliminary testing it seems that what is actually causing the extra size even without global memory and such is the use of volatile in NimMain and friends. The reason why it uses volatile is to make sure that parts of the code isn't inlined as it tries to set the stack frame to scan for the mark and sweep pass of the GC. This is however not required for ARC which we're using at the moment. It might be required by ORC however. I will probably make a PR to the main Nim repository in the coming days which adds in a check for the C code generation that avoids creating the volatile part. I manually wrote a small NimMain which did the same things for my module, but avoided those and the code size was the same as it is currently. I'm basically just writing this issue to track progress on this issue. This would allow the example code to simply be written as:

import board
import board / [times, serial, progmem]

Serial.init(9600.Hz)
Serial.send p"Hello world\n"
Led.output()

while true:
  Led.high()
  Serial.send p"Led is on\n"
  delayMs(1000)
  Led.low()
  Serial.send p"Led is off\n"
  delayMs(1000)

The second part of this issue is that while true loop. Some platform (the ESP8266 for example) has a hardware watchdog in order to make sure that they don't accidentally enter an infinite loop. This means that code like the above would run until the watchdog fired and then the board would reboot (assuming that delayMs didn't feed the watchdog and sleep the system in a more logical way, which it probably would). I plan on adding a loop construct which would essentially do the same thing as the while true loop, but have small template calls which would bind to templates in the board definition and allow it to insert logic before the loop, and before and after each loop iteration. This should provide the necessary flexibility to implement such boards, but comments are appreciated if you see other issues with this. The final resulting code would then look like this:

import board
import board / [times, serial, progmem]

Serial.init(9600.Hz)
Serial.send p"Hello world\n"
Led.output()

loop:
  Led.high()
  Serial.send p"Led is on\n"
  delayMs(1000)
  Led.low()
  Serial.send p"Led is off\n"
  delayMs(1000)

With NimMain working properly it should also allow modules to have their own initialisation logic in the global scope, if e.g. a board requires some particular things to be done on boot. These should then of course be put behind a compile-time switch if the user wished to do these things manually instead.

@dumblob
Copy link

dumblob commented Feb 16, 2022

Nice ideas. It's interesting to see how advanced macros can really help in the embedded world!

The second part of this issue is that while true loop. Some platform (the ESP8266 for example) has a hardware watchdog in order to make sure that they don't accidentally enter an infinite loop. This means that code like the above would run until the watchdog fired and then the board would reboot (assuming that delayMs didn't feed the watchdog and sleep the system in a more logical way, which it probably would). I plan on adding a loop construct which would essentially do the same thing as the while true loop, but have small template calls which would bind to templates in the board definition and allow it to insert logic before the loop, and before and after each loop iteration. This should provide the necessary flexibility to implement such boards, but comments are appreciated if you see other issues with this. The final resulting code would then look like this:

import board
import board / [times, serial, progmem]

Serial.init(9600.Hz)
Serial.send p"Hello world\n"
Led.output()

loop:
  Led.high()
  Serial.send p"Led is on\n"
  delayMs(1000)
  Led.low()
  Serial.send p"Led is off\n"
  delayMs(1000)

I'm not sure this is a good idea. For the simple reason of hiding of the expected and distinguishing (among different MCUs) behavior. In other words I find it much clearer to write resetWatchdog(watchdog_id_or_object_instance) (this call could actually be standardized in Ratel along with some DEFAULT_WATCHDOG_ID) at the end of the while loop than to use loop.

But maybe I'm missing something important which would defend such "extreme" level of abstraction 😉.

What do you think?

@PMunch
Copy link
Owner Author

PMunch commented Feb 16, 2022

The reason I didn't want to do this is to increase the potential for sharing code between controllers. The Arduino Uno for example doesn't require a watchdog reset, so a programmer running code on that controller would simply never think to include a resetWatchdog call at the end of their loop (even if it would just be a noop). This means that code written for the Arduino Uno wouldn't be able to run on the ESP8266 without modification. The idea is that loop (and the various delay procedures) would feed the watchdog. This way the above snippet should run on both the Arduino Uno and the ESP8266. If you wrote code specifically for the ESP8266 and wanted more granular control over the watchdog you would change your loop to something like loop(noWatchdogReset): and then call resetWatchdog manually. Flags which aren't implemented for the chosen board are simply ignored, so this should still compile and run fine on the Arduino Uno.

@dumblob
Copy link

dumblob commented Feb 16, 2022

Thanks for explanation @PMunch . I've given it some thought and think you're right - at least this lib could/should explore how such level of abstraction would pay off in practice.

So, yeah, let's do that!

Btw. I've finally found some time to take a look at your presentation on FOSDEM - nicely explained, thanks!

@PMunch
Copy link
Owner Author

PMunch commented Feb 16, 2022

Thanks for listening to my talk :) Hopefully I'll be able to get my suggestions implemented this weekend!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants