lispBM: A Lisp for Microcontrollers

LispBM (LBM) is a Lisp or Scheme-like programming language for microcontrollers. LispBM also borrows a couple of ideas from Erlang when it comes to concurrency, message passing, pattern matching and process monitoring. The LispBM runtime system can be compiled for either 32 or 64-bit platforms and runs on a wide range of hardware such as, for example, STM32, NRF52, ESP32 or X86. When running the LispBM runtime system on a microcontroller, it can be built on top of ChibiOS, FreeRTOS or ZephyrOS or, if you are adventurous, on bare-metal. LispBM can also be built to run on top of regular Linux (and now even Windows).

Who wouldn’t want a REPL (read eval print loop) on their embedded platform? This is what LispBM is for!

Want to get involved and help out?

There are lots of interesting things to code on in and around the LispBM runtime system. I would love to interact with people who are interested in high-level programming languages on microcontrollers (or elsewhere) so please do not be shy to make contact. Together we can make great stuff happen ;)

  1. Are you interested in microcontrollers and programming languages?
  2. Do you like both imperative and functional programming?
  3. Clone the repository and join the fun!
  4. Join the Discord server

There are areas where insights and help would matter greatly. Some I can think of are:

  1. Running LispBM on system simulators.
  2. LispBM efficiency.
  3. Code size optimization. Do more with less, while maintaining performance.
  4. Documentation and testing.
  5. Useful extension libraries.
  6. Lisp scriptable home automation.
  7. Lisp scriptable MIDI sequencers.
  8. Lisp scriptable Audio synthesizers.
  9. (WIP) Porting the Linux REPL to Windows.
  10. Interface with Rust as a language for writing LBM extensions.
  11. Partial-evaluation, supercompilation and byte-code compilation.
  12. Real-time garbage collection.
  13. Linter/code-preprocessor/checker tailored to LBM idiosyncrasies.
  14. Quickcheck-like property based testing of programs written in LBM.
  15. Formal verification of properties of the runtime system using Frama-C.

Contributors

LispBM is made possible by an amazing community of developers who contribute their time, expertise, and passion. You can meet our contributors to see the people behind the project.

Want to join this incredible community? Check out the section above on how to get involved, or dive straight into the GitHub repository. Every contribution, no matter how small, is valued and appreciated!

Getting started with LispBM

The LispBM source code is available on GitHub, and the LispBM community is available on Discord.

Getting started on embedded: easy

The easiest way to get started with LispBM programming is to use VESC Tool together with the VESC EXPRESS Firmware on an esp32c3.

VESC-Tool gives you access to a very capable IDE for Lisp programming on embedded systems and the VESC Express firmware provides built-in functionality to interface with CAN, WiFi, BLE and UART as well as GPIO and display drivers.

Keep an eye on the VESC Labs website for devices that come with LispBM per default.

Getting started on embedded: easy (no vesc)

In the directory 'examples/esp32c3' there is an example setup targeting the esp32c3-devkitm-mini1 (available on Mouser or Digikey) and FreeRTOS.

This is a suitable starting point for integrating LispBM scripting into your own FreeRTOS based projects.

Precompiled Binaries

For quick testing, precompiled binaries are available: esp32c3-repl.zip

The precompiled binaries can be flashed onto the development kit with the following command:

esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 460800 write-flash \
    0x0 bootloader.bin \
    0x8000 partition-table.bin \
    0x10000 repl.bin

Building and Flashing

To build and flash the ESP32C3 example, follow these steps:

First, process the flash partition table:

idf.py partition-table

Then build the project:

idf.py build

Flash the firmware to your ESP32C3:

idf.py flash

Finally, connect to the development kit using a serial terminal (such as minicom) or run:

idf.py monitor

You can now interact with a simple REPL on your ESP32C3.

Getting started on embedded: hard

If you want to build your own lisp environment based on LispBM on top of ChibiOS, Zephyr, FreeRTOS or bare-metal then this is quite possible!

For a simple example using FreeRTOS, look at Getting started on embedded: easy (no vesc). Another source for information on how to do LispBM and FreeRTOS, look at VESC EXPRESS. For ChibiOS integration look at the benchmark runner bench-chibi or for a more thorough integration VESC BLDC. Finally there is also the Linux REPL that one can look at for ideas.

Getting started on Linux

Start by cloning the LispBM repository. Open a terminal and issue the command:

git clone https://github.com/svenssonjoel/lispBM.git

You should now have a directory called lispBM. Go into it and into the repl subdirectory.

cd lispBM
cd repl

Now, you have multiple choices on how to build the REPL. To build the 32-bit version (which is most similar to what you will run on a microcontroller), issue the make command.

make

If the make command above fails, it is most likely because there are some missing dependencies.

Building the 32-bit version of the REPL requires 32-bit libraries. If you are on an Ubuntu platform, you get 32-bit standard libraries by installing gcc-multilib.

In addition to gcc-multilib, the REPL requires libreadline and libpng. You need to get the 32-bit versions of these libraries. On Ubuntu, you can run the following commands:

sudo apt install gcc-multilib libreadline-dev:i386 libpng-dev:i386

If you were unable to install the 32-bit dependencies with the command above, you may need to instruct the package manager that you are interested in 32-bit packages as well:

sudo dpkg --add-architecture i386

Then retry the previous step to install the dependencies.

If installing the dependencies finished successfully, make should now work and the REPL executable should be built.

Start the REPL and explore!

./repl

You should now be greeted by the LispBM REPL in a way similar to what is shown below.

Lisp REPL started! (LBM Version: 0.27.1)
Type :quit to exit.
     :info for statistics.
     :load [filename] to load lisp source.
#

Try to evaluate some expressions. Type (+ 1 2) and press enter.

Lisp REPL started! (LBM Version: 0.27.1)
Type :quit to exit.
     :info for statistics.
     :load [filename] to load lisp source.
# (+ 1 2)
> 3
# 

When you input code at the # prompt, LispBM answers on a new line starting with >.

Alternatively, the REPL can be built as a 64-bit binary. Building the 64-bit binary requires 64-bit versions of the readline and png libraries.

On Ubuntu, you get the dependencies by doing sudo apt install libreadline-dev libpng-dev. Then, to build the executable, you issue the following command:

make all64

Lastly, the REPL can be built with SDL (Simple Directmedia Layer) for graphical output. This is done by issuing the following command:

make sdl64 

Or for 32-bit:

make sdl

The REPL with SDL requires libsdl2-dev and libsdl2-image-dev libraries or the 32-bit versions (for 32-bit REPL binary) libsdl2-dev:i386 and libsdl2-image-dev:i386.

Getting started on Windows

There is a precompiled REPL for Windows here. This REPL is built using MINGW on a Linux machine and tested under WINE. The following DLLs are required (some are included in the zip file):
  • KERNEL32.dll, msvcrt.dll, WS2-32.dll (Windows system DLLs)
  • SDL2.dll, SDL2-image.dll, libpng16-16.dll
  • history5.dll, readline5.dll
  • zlib1.dll (may also be required)
To run the REPL, execute lbm32.exe in console (cmd) or PowerShell. If there are errors involving VirtualAlloc, try to run as administrator. Help with debugging and testing of the Windows version is much appreciated. If you want to help out with building and testing LBM on an actual Windows machine, let me know.

Documentation

Editor support

Presentations

Language Implementation

Texts about language development, implementation techniques, and the technical details behind LispBM.

Testing of LispBM

The table below contains test reports for the recent numbered releases of LispBM. The test reports apply to the tagged states with the same numbering on GitHub. Note that only versions X.Y.0 get a tag and a full run of all tests. Versions X.Y.Z for non-zero Z are experimental and in development, and are sporadically tested as part of development but not given a full testing log treatment. If you want to use LispBM for something serious, please use an X.Y.0 version and keep in mind that testing is never exhaustive and in no way a guarantee of correctness or suitability for any given purpose. A thorough safety and reliability analysis should be performed on the software system where LispBM is integrated as a whole.

The table of test-results is provided for traceability purposes and gives a snapshot of known problems with a given version of LispBM.

That said, we are very serious about our testing and we do want to make it possible to use LispBM as a scripting language integrated into any application. This is an ongoing effort and collaboration is most appreciated.

Please report bugs via the issues tracker on GitHub.

Testlog Tagged version
0.33.0 tag 0.33.0
0.32.0 tag 0.32.0
0.31.0 tag 0.31.0
0.30.0 tag 0.30.0
0.29.0 tag 0.29.0
0.28.0 tag 0.28.0
0.27.0 tag 0.27.0
0.26.0 tag 0.26.0
0.25.0 tag 0.25.0
0.24.0 tag 0.24.0
0.23.0 tag 0.23.0

NOTE: The scan-build directory is empty if the scan-build tool finds no issues with the code.

NOTE: The Infer result file infer-x.y.z.txt is empty if Infer finds no issues.


We expand on our testing from time to time but currently apply the following testing methods:

Leading up to version 0.33.0, focus was on improving test coverage. As can be seen from the images below, test coverage has increased drastically and we are now covering 97.4% of functions and 91.7% of lines. There are still improvements needed for branch coverage. Many of the uncovered branches are extremely hard to trigger and in a correctly set-up integration of LispBM it may be impossible to trigger these error conditions. The plan for future testing is to slowly increase coverage with tests designed to trigger even more unlikely edge cases, but overly defensive programming practices (such as conditions that cannot arise in a correctly configured LispBM system) will be removed.
LispBM testing coverage version 0.32.0
Test coverage for version 0.32.0
LispBM testing coverage version 0.33.0
Test coverage for version 0.33.0

LispBM Performance Evolution

The performance of the LispBM implementation continuously evolves as we introduce new features and engage in optimization efforts. We work to enhance its efficiency for microcontrollers, such as the STM32F4 running at 168MHz.

Below, you can find performance charts illustrating LispBM’s performance on a set of benchmarks:

LispBM performance benchmarks chart showing execution times
Performance benchmarks with linear scale
LispBM performance benchmarks chart with logarithmic scale
Performance benchmarks with logarithmic scale

If you’re interested in the technical details and benchmarks, you can explore our benchmark code here

Other Lisp-based Languages for Microcontrollers

Explore a range of Lisp-like programming languages that are tailored for microcontroller development. These languages are designed to thrive in resource-constrained environments, making them ideal choices for embedded systems. Whether you’re looking for a lightweight solution or a minimalist Lisp dialect, these languages offer unique approaches to microcontroller programming.

  • uLisp: A Lisp dialect specifically designed for microcontrollers. Learn more
  • FemtoLisp: A minimalistic Lisp designed for resource-constrained environments. Learn more
  • PicoLisp: A lightweight and minimalistic Lisp dialect for both server-side and embedded programming. Learn more

Is your favorite microcontroller Lisp missing from this list? Please send the details in an email to bo(dot)joel(dot)svensson(whirly-a)gmail(dot)com.