Page 1 of 1

Timer interrupt service routine memory issue

Posted: Sun Feb 26, 2017 8:12 pm
by artur
Hello,

originally I intended to use a timer ISR to send out periodic CAN messages. The timer callback was a class method. However, this did not work, giving "heap allocation not allowed" error messages.

I understand that no heap can be allocated in an ISR and that it should be as short as possible a function. But is really the only solution then to use flags (e.g. and then to check the flag in main routine and send CAN message if set)?

Also, I wonder how to determine when heap gets allocated. For example, I run the code provided in the docs (http://docs.micropython.org/en/latest/p ... #pyb-timer), namely:

Code: Select all

def tick(timer):               
    print(timer.counter())    
tim = pyb.Timer(4, freq=1)      
tim.callback(tick)


This only provides '0' as output on the screen. So apparently there is a memory issue with the print during ISR, but no heap allocation message is thrown.

Re: Timer interrupt service routine memory issue

Posted: Sun Feb 26, 2017 11:40 pm
by dhylands
You are allowed to have class methods as timer callbacks, as this example shows:
https://github.com/dhylands/upy-example ... eat_irq.py

The way that the timers work is that they are sourced by a clock (frequency can be determined by the source_freq() function). That is then divided by a prescaler and causes the timer to increment until it hits a reload value (period), and then the counter gets reset to zero.

So if I modify your example slightly:

Code: Select all

import pyb

def tick(timer):               
    print(timer.counter())   

tim = pyb.Timer(4, freq=1)     
print("tim.source_freq() =", tim.source_freq());
print("tim.prescaler()  =", tim.prescaler());
print("tim.period()  =", tim.period());
tim.callback(tick)
then I get this output:

Code: Select all

>>> import tick
tim.source_freq() = 84000000
tim.prescaler()  = 3124
tim.period()  = 26879
>>> 0
0
So the 84 MHz clock is getting divided by 3125 which results in 26880 ticks per second. (the period and prescaler are both stored as the actual prescaler and period minus one). So the counter will increment from 0 to 26879 and then it will reset to zero, causing the timer interrupt to fire. This is why the counter is always being read as a zero.

You can read more about writing interrupt handlers here: http://docs.micropython.org/en/latest/p ... rules.html

Basically small ints (signed ints which fit in 31 bits) don't require heap allocation. The statment x = 1 will not require memory allocation. The statement x = 1.0 or x = 0x123456789 will require memory allocation. Lots of other things require memory allocation.

Re: Timer interrupt service routine memory issue

Posted: Mon Feb 27, 2017 9:40 am
by artur
Thanks for the explanations.
In your code example, I replaced the LED toggle with a print statement:

Code: Select all

def heartbeat_cb(self, tim):
        if self.tick <= 3:
            #self.led.toggle()
            print(tim.counter)
        self.tick = (self.tick + 1) % 10
This results in "Memory Error: memory allocation failed, heap is locked". So, really I can't do much in an ISR, can I?

Re: Timer interrupt service routine memory issue

Posted: Mon Feb 27, 2017 10:18 am
by dhylands
You asked to print tim.counter which is a bound function pointer. Creating bound function pointers requires a memory allocation.

I suspect that you intended to actually call the tim.counter function, in which case you need to add some parenthesis. I.e. use tim.counter()