Peeling off layers of complexity Dec 2016

As you know, compilers generate code. They take one or more source files and turn them into an executable. In the case of embedded software development, the compiler is actually a cross-compiler because it’s not generating code for the machine it’s running on (your laptop), but for the attached board (a little “target” microcontroller).

The generated code is simply a chunk of binary data - gibberish, as far as we humans are concerned. We upload it to the target board, and then it presumably starts doing what we instructed it to do in the original source code. We rely totally on this 1-to-1 mapping.

There are several implications and drawbacks with this widely-used approach:

But there’s a way to avoid such complexity – and it was invented half a century ago.

It’s called “Forth”. Here’s how Forth manages to avoid the issues mentioned above:

The central theme is: “learn as you go”. Go ahead: try something, crash, learn, tweak, repeat. Or to put it even more succinctly: Fail Fast! - there is no big wheel turning - sure, there is a workflow, but you can forget about the “work” part of it, it’s all about staying in the flow!

In Forth, there’s no fundamental distinction between compilation, running, and debugging. It’s all interaction, and everything “does something”. Some effects will be internal: viewing or changing values, other effects will be more permanent: defining new functions (Forth calls them “words”) in RAM or in flash memory, and yet other effects will cause I/O pins to change, some data to be sent or received, etc.

Forth is a programming language with its own syntax and conventions (to be described in an upcoming article), but it’s also a programming environment in that it prescribes how the entire development process takes place. All of it - yes, all of it! - lives on the microcontroller.

In a way, there are no safety nets - programming errors and even small mistakes can lead to fatal crashes where the µC stops responding with no clue as to what happened. But while this could be a hassle with a compiled approach, it’s very easily overcome in Forth: reset, and retry things in smaller steps, then inspect what is going on just before the failure you just ran into.

Yet – surprising as it may sound – an embedded Forth environment is also extra-ordinarily robust: all that can happen is that it stops. Simply reset the µC and you’re back on track!

Since the host is no more than a view into the microcontroller, there is no state on the host which can be affected by crashes or resets on the target board. There’s no toolchain, there are no apps to launch or re-launch when the target fails.

What about source code? And editing that code? And version control? And backups?

Ah, this is where we leave the realm of the actual Forth setup. There’s a tool called Folie which addresses all that. The name “Folie” stands for “Forth Live Explorer” – it acts as the terminal and bridge from host to target. In essence, Folie is simply a line-oriented terminal emulator.

But Folie also adds a number of features to make life in Forth-land more convenient:

That last feature is what brings the target board into the 21st century. While you could just manually enter all your code and get it working and saved in flash memory that way, it would be extremely inconvenient to not have a permanent record of the final version saved on file.

With Folie, the idea is to write the main parts of your application as source code in your own preferred editor on your own comfortable host system. Then send this over to Forth and start using it. There are various ways to streamline this, so that the actual sending only takes place occasionally. In short: think on the target, try out things there (using the command line), but as soon as you have some code which is working well, enter it as source code definitions in the editor, and send these definitions over as needed - and whenever they need to be updated.

The normal modus operandi is to keep both your editor and a Folie session open, side by side.

There’s a lot more to say about Folie and the Mecrisp Forth implementation by Matthias Koch, which we’ll be using on ARM microcontrollers (Mecrisp is also available for ARM Linux, and there are variants for MSP430 and even FPGA’s). But that’ll have to wait for another time.

Anyway - the point of this story is that the traditional edit, compile, link, upload, run, debug cycle is not the only way to do things. The next few articles will try to illustrate how Forth’s interactive approach can be very effective and great fun for embedded software development.

Weblog © Jean-Claude Wippler. Generated by Hugo.