Post
by Hanilein » Wed Apr 17, 2019 12:20 am
A simplified picture: Any conventional µC uses hardware interrupts as follows: When enabled, an occurring interrupt let the program branch to the dedicated Interrupt Service Routine. While in that ISR, any other interrupt is not served, but a flagbit is set, and the interrupt is served as soon as your ISR finishes. Only if you have more than one same interrupt while being in the ISR, you will lose that additoional Interrupt Request.
This is also one good reason, why Hardware ISR's should be as short as possible.
The challenge with Python on a µC is memory management, and that means access to the heap and garbage collection. To keep things simple, in Micropython any access to the heap is blocked while a Interrupt Service Routine is executed.
So, when a hardware interrupt occurs (your timer interrupt, for example), the system switches to the ISR, and you may access previous allocated global variables, but you cannot instantiate new variables or objects.
You can, however, instantiate variables and create objects while using callback functions invoked by the scheduler.
And that is the solution to both challenges you face here - having interrupts while being busy, and accessing memory:
In your ISR you invoke the scheduler with a proper callback, that will be able to access memory and also can be interrupted again by a hardware interrupt.
You just must assure that you are managing these interrupts, in other words, have your own (global) flag, that is used to prevent the ISR invoking the scheduler while the scheduled callback is still busy. The scheduler has a stack with a depth of eight (8), so as soon as you have eight calls scheduled, the ninth will face-plant the system.
On a side note: even "harmless" global integer variables can lead to trouble in an ISR, when they reach the limit of their size. In C/C++ for example, these variables would roll over. In Python, however, the systems assigns additionally memory and the variable just copes with the big numbers. But not in an ISR, because assigning additional memory to the variable involves access to the Heap, which is locked in an ISR.
That count variable in your code will exactly do that, if the timer runs long enough...
Ivo Gorny