Timer callback ADC memory error

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
ulrich
Posts: 14
Joined: Thu Nov 27, 2014 7:17 pm

Timer callback ADC memory error

Post by ulrich » Thu Dec 18, 2014 10:35 pm

Good evening!

I'm experiencing a strange behaviour, wher I'd like to ask for your help! I want to start a timer which triggers a measurment with the ADC every second.

I run the following code on the board:
import pyb
from pyb import Pin, ADC, Timer
def getstrength(tmp):
import pyb
from pyb import Pin, ADC
blue = pyb.LED(4)
blue.on()
adc = ADC(Pin('X20'))
blue.off()


tim = Timer(1, freq = 1) #gives a trigger every 1 second
tim.callback(getstrength)

This results in:
uncaught exception in Timer(1) interrupt handler
MemoryError:

(There is nothing after the memory error)
If I run "getstrength(False)" by itself I do not obtain the error message.
If I run exactly the same except I do not include the adc = ADC(PIN....) , it works fine as well...

Anyone got a clue? Any hint is very much apprechiated!

Cheers,

Ulrich
Last edited by ulrich on Fri Dec 19, 2014 6:26 pm, edited 1 time in total.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Timer callback ADC memory error

Post by dhylands » Thu Dec 18, 2014 10:57 pm

Hey ulrich,

Currently, you're not allowed to allocate any memory from with ISR callbacks (ans the timer callback is an ISR callback).

You can get more details about exactly where the allocation is occuring by adding the following to your code:

Code: Select all

import micropython
micropython.alloc_emergency_exception_buf(100)
Even the exception handler can't allocate memory during an ISR, so its unable to report where the error occurred.

Adding the above call pre-allocates some memory that the exception handler will use when memory allocations fail, so that you can get some traceback information.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Timer callback ADC memory error

Post by dhylands » Thu Dec 18, 2014 11:01 pm

Calling adc = ADC(...) does, in fact, try to allocate memory.

So, the fix for this would be to do the allocation in the main part of your code. This would make adc be a global.

If you're averse to using globals, then you can also use a class. Here's an example:
https://github.com/dhylands/upy-example ... eat_irq.py

It allocates the led object in the Heartbeat constructor, and the callback just refers to the already allocated object.

ulrich
Posts: 14
Joined: Thu Nov 27, 2014 7:17 pm

Re: Timer callback ADC memory error

Post by ulrich » Fri Dec 19, 2014 6:24 pm

Hi,

Thanks a lot for the fast reply and this valuable hint!! - I manage to read the adc from within the callback function!

Unfortunately, this immediately triggers the next problem....

The memory allocation constraint seems to me to be quite heavy and renders timers almost useless as it now seems that performing even the most basic "math", triggerst a memory exception.

E.g. adding to the callbackfunction of your heartbeat example simply the line "self.k = 3 * 2/34" causes it to die... self.k = 3 alone seems to be possible. It seems to me that any division requires memory allocation (even if globally initialized variables are used).

Your command "micropython.alloc_emergency_exception_buf(100)" allows to allocate memory for some purpose, could this be generalized? I don't need to do too much math etc, but some basic division is needed...

Cheers,

ulrich

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Timer callback ADC memory error

Post by dhylands » Fri Dec 19, 2014 6:26 pm

You can do integer arithmetic // = integer divide, / = floating point divide.

ulrich
Posts: 14
Joined: Thu Nov 27, 2014 7:17 pm

Re: Timer callback ADC memory error

Post by ulrich » Fri Dec 19, 2014 8:06 pm

Thanks for the hint!

While this might get me one step further, I'll not get around using floats at some point further in the routine.

I see some projects using the pyboard to e.g. control multicopter - how do they manage this kind of stuff? I'd had thought that they use some timers to regualrily check e.g. the accelerometer and then correct to stabilize it etc...

Luckily my application is by itself very simple and precise timing is not a real issue, so I guess I'll just keep a loop running and use delays.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Timer callback ADC memory error

Post by dhylands » Fri Dec 19, 2014 11:56 pm

Normally you would use the ISR to trigger an event, which the main process would then pick up.

For example, you can simulate multi-threading by using generators, and the ISR might change a flag which causes one of your threads to run.

So the ISR wouldn't do the work, it would just determine when the work needs to be done.

ulrich
Posts: 14
Joined: Thu Nov 27, 2014 7:17 pm

Re: Timer callback ADC memory error

Post by ulrich » Sat Dec 20, 2014 9:45 am

Thanks again!

This sounds quite interesting. I knew that my programming skills are still quite limited - I'll have to have a look into this. Do you happen to know of a simple example for this/website explaining this concept further?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Timer callback ADC memory error

Post by dhylands » Sat Dec 20, 2014 4:58 pm

A very basic example was given here:
http://forum.micropython.org/viewtopic. ... &t=15#p208

There is also a method based on asyncio, which there is some support for in micropython, but I haven't played with it myself. There has been several discussions about it on this forum.

Post Reply