I really like MicroPython and I use it a lot. But sometimes I want to implement something that has to be done in C++. Of course I like the automatic memory management and dynamic typing of Python more than the low level nature and static typing of C++. How to have the cake and eat it?
As I don't want to fork MicroPython, I remembered that I wrote a Lisp interpreter in C when I was a student. So my idea was to do a project like MicroPython, but with Lisp and the possibility to interface with C++ code easily.
Here is the prototype of Micro Lisp running on Odroid Go :-)
1. Install Micro Lisp on your Odroid GoDownload the latest release of MicroLisp.fw
fresh from the output of the CI/CD pipeline here https://bitbucket.org/amotzek/micro-lisp/downloads/.
Take the micro SD card of your Odroid Go and copy MicroLisp.fw
into the folder odroid/firmware
. Insert the SD card, press the "B" button and then switch on your Odroid Go.
Select Micro Lisp in the onscreen menu and follow the steps to activate it.
2. Install Micro Lisp Tool on your PCIf you have no Python 3 installation on your computer please download the installer from https://www.python.org/downloads/ and execute it.
Then install the Micro Lisp Tool with pip3 install micro-lisp-tool-amotzek --user
.
From the Code section of this project copy the file dragon-curve.lisp
to your computer.
Connect your Odroid Go to your computer via USB. If you connect it the first time wait a little until Windows installed the driver. Open the Windows Device Manager and look into "COM & LPT" to find the correct COM port, e.g. COM3.
Then use the Micro Lisp Tool to execute the Lisp program on your Odroid Go with python3 -m micro_lisp_tool run dragon-curve.lisp --port COM3
.
The Lisp program starts executing and displays bigger and bigger dragon curves on your Odroid Go.
If you switch off the Odroid Go the program will be gone. If you want to store it permanently, use python3 -m micro_lisp_tool put dragon-curve.lisp --port COM3
.
Using the display:
(setq black (list 0 0 0))
- Colors are represented by lists of RGB values(setq white (list 255 255 255))
(defdisplay display ili9341 odroid-go)
- Nowdisplay
represents the ILI9341 display of an Odroid Go(fill display black)
- The display is filled with black color(set-pen-color display white)
- Pen color is white(set-position display 0 210)
- Pen position is (0, 210)(pen-down display)
- If the pen is moved it draws a line(pen-down? display)
- Returns true if the pen is down(label display "Franz jagt im verwahrlosten" 24)
- Draws a string at the position of the pen; currently only font sizes 12 and 24 are supported(pen-up display)
- If the pen is moved it will not draw a line(pen-up? display)
- Returns true if the pen is up(set-heading display 0)
- Sets the heading of the pen movement in degrees; 0 is along the x axis(towards display 160 120)
- Sets the heading of the pen movement to a direction from the current position of the pen towards (160, 120)(forward display 40)
- Moves the pen forward 40 pixels in the direction of the heading(right display 72)
- Changes the heading 72 degrees to the right (clockwise)(back display 40)
- Moves the pen against the direction of the heading 40 pixels(left display 90)
- Changes the heading 90 degrees to the left(get-bounds display)
- Returns a list with four elements: x origin, y origin, width, height(create-display (quote bounds))
- Returns an in-memory display that does nothing but records the size of the drawing, for use withget-bounds
Using GPIOs:
(defgpio led 2 digital-output)
- Nowled
represents GPIO 2 configured as digital output; be careful, if you use GPIOs as output that are inputs in reality, you can damage your hardware(write-gpio led t)
- Switches the GPIO represented byled
to high(write-gpio led nil)
- Switches the GPIO represented byled
to low(defgpio sensor 35 analog-input)
- Nowsensor
represents GPIO 35 configured as analog input(read-gpio sensor)
- Returns the measurement of the GPIO represented bysensor
as integer value(defgpio button 32 digital-input)
- Nowbutton
represents GPIO 32 configured as digital input(read-gpio button)
-- Returns the state of the GPIO represented bybutton
as boolean value (t or nil)
Using tasks for cooperative multitasking and scheduling:
(now <code>)
- Puts<code>
to the front of the task queue for immediate execution(after 3000 <code>)
-<code>
will be executed after 3 seconds(when-then <condition> <code>)
- repeatedly checks<condition>
(e.g. reading a GPIO) and when it is true, then execute<code>
once(when-for-then <condition> 500 <code>)
- when<condition>
is continuously true for half a second, then execute<code>
once(priority-now 2 <code>)
- Enqueues<code>
for immediate execution with priority 2; tasks with higher priority are preferred(priority-after 10 5000 <code>)
-<code>
will be executed after 5 seconds, priority is 10(priority-when-then <prio> <condition> <code>)
- like when-then but with priority(priority-when-for-then <prio> <condition> <duration> <code>)
- like when-for-then but with priority(only-one-of <task1> <task2>)
- only the task that runs first is executed, the other task is canceled; for up to 4 tasks
For a documentation of the Lisp core language, please have a look at https://bitbucket.org/amotzek/micro-lisp/src/master/.
What's coming next?Micro Lisp is still a prototype. It is slow. It will crash in low memory conditions. And much hardware support is missing, e.g. for WLAN. So keep an eye on updates. Until then: Happy hacking!
Comments