ryansuchocki / microscheme

A Scheme subset for Atmel microcontrollers.
http://ryansuchocki.github.io/microscheme/
MIT License
300 stars 20 forks source link

Difference of behaviour when using map #28

Closed YPares closed 8 years ago

YPares commented 8 years ago

The following code works:

(define led1 (output 3))
(define led2 (output 13))

(define (loop)
  (toggle led1)
  (toggle led2)
  (pause 500))

(toggle led2)
(forever loop)

But if I replace loop by:

(define (loop)
  (map toggle (list led1 led2))
  (pause 500))

then it starts OK, and after 40 seconds, led1 just remains lit up and led2 blinks 4 times, misses a blink, blinks 4 times, etc. It happens both on my Duemilanove and Nano (both with a 328p), same time before it acts weird, same behaviour. Does it work OK on the UNO? (Using microscheme 0.9.3)

YPares commented 8 years ago

I checked with for-each instead of map, it also start to behave weirdly after a time, but this time led1 just remains off.

YPares commented 8 years ago

Ok, with

(define (loop)
  (for-each-vector toggle (vector led1 led2))
  (call-c-func "my_write" 70)
  (pause 500))

it flashes 6 times. It's on led2 which is on pin13 so I guess I'm getting NOT A PAIR/ OOB exceptions. I plugged another led so as to leave pin13 only for exceptions, and yes it's definitely an OOB.

ryansuchocki commented 8 years ago

This is a known problem when you call lambda, cons, list or vector within any infinite or high-frequency loop.

Please read: http://microscheme.org/documentation#memman

In this example:

(define (loop)
  (map toggle (list led1 led2))
  (pause 500))

list is using some memory on every allocation of the loop, which is never recovered. 2 to 8 KB quickly runs out... The best solution is to do it like you said in the first snippet. Otherwise, you can free that memory manually like this:

(define (loop)
  (free! (map toggle (list led1 led2)))
  (pause 500))

In the second example, vector is causing the same problem. Again, you can either move the allocation out of the loop, or manually free the memory...

(define (loop)
  (free! (for-each-vector toggle (vector led1 led2)))
  (call-c-func "my_write" 70)
  (pause 500))
(let ((myleds (vector led1 led2)))
  (define (loop)
    (for-each-vector toggle myleds)
    (call-c-func "my_write" 70)
    (pause 500))
ryansuchocki commented 8 years ago

Sorry, I got that very last bit wrong. define must be top-level, so it has to be:

(define myleds (vector led1 led2))

(define (loop)
  (for-each-vector toggle myleds)
  (call-c-func "my_write" 70)
  (pause 500))
YPares commented 8 years ago

Oh, ok thanks! I shouldn't have skimmed over this part when reading the docs the first time. Great!