Frequently Asked Questions
PyMite (also known as p14p, python-on-a-chip) is a great piece of software, and, while, it looks on the surface to be very similar to Micro Python (after all, it runs Python on a micro!), underneath the two are very different things. The following comparison of the two is rather technical, but hopefully makes clear my reason for writing Micro Python from scratch, rather than using, or building on, PyMite.
If there was to be any chance of running Python on a microcontroller for serious applications, one must be able to at least do basic operations, such as integer addition and calling methods, without allocating heap memory. Allocating heap memory is usually a large performance penalty, and consumes RAM, a scare resource on a microcontroller. But, most importantly, when using a garbage collector (which both PyMite and Micro Python use) allocating heap memory has the chance (and eventually it must occur) of inducing a garbage collection cycle.
If you are in the middle of doing some time critical processing (which is common on a microcontroller), you cannot afford to wait for a garbage collection. Also, if your code is running on an interrupt (that is, it has interrupted some other Python code halfway through some calculation) then it cannot allocate heap memory because it must not induce a garbage collection. It cannot, because the original code that it interrupted might have been in the middle of a garbage collection, and it is very difficult to make garbage collection re-entrant. Furthermore, an interrupt is supposed to run very quickly, and this will not be the case if a garbage collection needs to run which processing the interrupt.
In short, we don't want to garbage collect, and hence don't want to allocate from the heap, in a time critical function.
In PyMite (and CPython if I'm not mistaken), most integer operations, even a simple addition, require heap allocation. This is because everything in Python is an object, and objects (generally) need to be allocated on the heap. If you add two numbers (two objects), you first check they are integer objects, then extract their integer values, add them, and then put the result into a newly created object, which must be allocated on the heap. The same thing for subtraction, multiplication, division and bitwise operations, which are all very common in microcontroller code, especially low-level time-critical code.
Also, the read-only nature of Python integers means you can't mutate the object to reuse its heap memory.
Okay, that's one example of allocating heap memory that is unacceptable on a microcontroller. The other example that is important is the act of calling a method. In Python (CPython and PyMite), when you want to call a method foo.bar(), you first extract the attribute bar from foo. Since (in this case) foo is an instance of some class, you must pack together the result into a bound-method object. This is an object that has 2 elements: foo, the subject of the method call, and foo.bar, the actual function to call. Note that this object must be allocated on the heap. You then push this bound-method object onto the top of the stack. The next byte code will pop this off the top, and do a function-application on the bound-method object. The function-application will open up the bound-method object, take out the foo subject, and pass it as the first argument to the foo.bar function. This completes the execution of a method call.
So, we needed to allocate heap memory just to do a method call! Since method calls are everywhere in Python, this is going to lead to poor performance on a microcontroller, and will prevent you from calling methods in time critical places.
Micro Python solves these 2 problems, and does not need to allocate heap memory for integer operations and method calls (in contrast to PyMite).
In Micro Python, integers are still objects, but they are not stored on the heap. Rather we use a trick that I took from Smalltalk (probably some other languages use this trick too). If an integer is small enough to fit in 31 bits (which most are) then it is stored in the actual pointer itself. To distinguish a real object pointer from an integer, we use the least significant bit (LSB). If the LSB is set, then we have an integer object, whose value is stored in the top-most 31 bits. If the LSB is clear, then we have a real object, and the top-most 31 bits point to the memory location on the heap of that object.
With this scheme, integer operations such as addition and bitmanipulation require no heap allocation, and can be executed very quickly.
To solve the problem of method calls, we use the trick from PyPy (thanks PyPy!). That is, an attribute lookup followed directly by a function call is compiled to a new byte code called CALL_METHOD. This uses the stack to store the two values: the instance foo and the function foo.bar. So there is no heap allocation to call a simple method.
Thus, a lot of code in Micro Python can run in time critical places and on an interrupt without allocating heap memory. This is not true for PyMite.
Micro Python also includes a complete compiler (which is why we can do the CALL_METHOD trick), whereas PyMite does not. Micro Python can compile to native machine code.
Micro Python is called "Micro" Python because it is specifically designed from the ground up to run efficiently on a microcontroller. This means designing from the start the entire architecture of the program so it is suited to all these tricks and optimisations, two of which I have just described. This is why I wrote Micro Python from scratch.Last updated:
Tinypy's aim is to be a small implementation of Python, but it's not targeted at microcontrollers. Tinypy is Python version 2. Integers are represented internally as a C double (a good design decision for simplicity, but not a good one for a microcontroller) so it would need heap allocation for arithmetic, and be quite slow performing the operation (especially if the microcontroller doesn't have hardware floating point). An instance of the tinypy VM needs around 30KiB of RAM. Tinypy does include a parser and byte-code compiler, but they are written in Python themselves, so would take quite a bit of RAM and be orders of magnitude slower than a native parser/compiler (Micro Python's lexer/parser/compiler/emitter is native, written in C).
PyMCU is a "Python controlled microcontroller", not Python on a microcontroller. It runs Python on your PC, and communicates to a slave device (the microcontroller) over USB. Python running on your PC sends commands to the PyMCU board to tell it to, for example, turn on an LED.
PyPy is an amazing piece of work and executes Python at a blinding speed. But the image size (the executable) is gigantic (44MiB for me). If you ever managed to strip it down to fit on a microcontroller, you'd be left with something that in no way resembled the original PyPy.
Let me say that I do not want in any way to demote any of these projects, nor disregard the hard work that has been put into them. I just want to help you understand the different ways that Python has been implemented in the past, and why I decided to write Micro Python rather than adapt an existing piece of code.Last updated:
No. The Micro Python board has a small file system on the microcontroller itself. Out of the 1MiB flash memory on the STM32F405 chip, around 512KiB will be available to store Python scripts and data files. You only need to add an SD card if you want to store larger data files, or more easily transfer files to/from your PC.Last updated:
Yes, there is some information in "Update #4" and "Update #5" which is available for everyone to read.Last updated:
Yes, see "Update #7", accessible at the top of this page.Last updated:
Micro Python has exactly the same grammar (syntax) as Python version 3. This means that the way you write Python code is exactly the same in Micro Python (for loops, function definitions, classes, list comprehension, etc). Scripts that compile in normal Python will compile in Micro Python, and vice versa.
Micro Python does not at the moment implement all of Python's standard libraries. Some Python standard libraries are written in C and need to be re-written to work with Micro Python. I am currently working on this. Ultimately, not all Python libraries will be fully supported because they are not feasible to run on a microcontroller, either because the functionality is not available on the microcontroller, or because they take too much memory.Last updated:
Yes, see "Update #3" and "Update #10", accessible at the top of this page.Last updated:
On GitHub.Last updated:
The pin holes have standard 0.1 inch spacing (2.54mm), so you can easily use some header pins to connect it to bread board, vero board or any other prototyping PCB, or even your own "mother board".
Update #14 (accessible at the top of this page) shows how you can screw the board down without using the header pins.Last updated:
See Update #15, accessible at the top of this page.Last updated:
Don't see the answer to your question? Ask the project creator directly.Ask a question