Page 1 of 1

Call next() from a callback

Posted: Fri Aug 02, 2019 1:38 pm
by jaggr
I want to get the values of a cosine function in small steps and a regular interval.
To not calculate all values in advance and overfill the memory, I use a generator.
To get a regular value I use a timer as trigger.
Now my problem is, if I call next value in the callback function, I get the following error:
[code]
Traceback (most recent call last):
File "<stdin>", line 13, in get_cos_value
File "<stdin>", line 6, in cosine_generator
MemoryError: memory allocation failed, heap is locked
[/code]

My code:

[code]
import pyb
import math
from math import pi

def cosine_generator(n):
dx = 2*pi/(n-1)
for i in range(n):
yield math.cos(i*dx)

cos = cosine_generator(3000)

def get_cos_value(timer):
print(next(cos))

tim = pyb.Timer(3)
tim.init(freq=10)
tim.callback(get_cos_value)
[/code]

Re: Call next() from a callback

Posted: Fri Aug 02, 2019 10:02 pm
by jimmo
Because interrupts run at an unknown point innthe Python VM's cycle, they disable memory allocation (otherwise the GC would have to be reentrant). Unfortunately, the generator needs to do an allocation (I'm unsure if this is related to the floating point calculation or the generator itself).

The easiest way around this is to use micropython.schedule from the interrupt handler to set a callback (a "soft" interrupt) that will be executed by the VM between instructions ASAP. These soft handlers can do everything that normal code can do.

See https://docs.micropython.org/en/latest/ ... rules.html for more info

Re: Call next() from a callback

Posted: Sat Aug 03, 2019 6:29 am
by pythoncoder
jimmo wrote:
Fri Aug 02, 2019 10:02 pm
...I'm unsure if this is related to the floating point calculation or the generator itself)...
Floating point operations always allocate and are therefore not allowed in interrupt handlers.

Re: Call next() from a callback

Posted: Mon Aug 05, 2019 5:03 am
by jaggr
jimmo wrote:
Fri Aug 02, 2019 10:02 pm
...
The easiest way around this is to use micropython.schedule from the interrupt handler to set a callback (a "soft" interrupt) that will be executed by the VM between instructions ASAP. These soft handlers can do everything that normal code can do.

See https://docs.micropython.org/en/latest/ ... rules.html for more info
Thanks for your quick reply.
My quick and dirty solution was to set a flag in the callback and look after it and call next() afterwards from the outside.
But that does not feel right ;)
These soft handlers could fix several issues :D
I'll try it asap.