Forget what you know, please Feb 2016

In the beginning, there were computers. Programmed with wires, then with binary data (the “stored-program” computer), then with assembly language, and from there on, a relentless stream of new programming languages. Today’s web browsers all “run” JavaScript.

Here’s a summary of that evolution again, in terms of technology:

The story could end here, but then there is that embedded microcontroller world, with smart chips in just about anything powered by electricity. While powerful and capable of generating byte code and even machine code, they do not have the storage and memory to run a high-end optimising compiler. Even if projects such as Espruino and MicroPython have come a long way to bring complete self-contained environments to the µC world - they still depend heavily on a larger machine to produce those run-time environments we can flash into the µC.

This has an important implication: everything not implemented and linked into Espruino or MicroPython has to be written in the higher-level language (JavaScript or Python, respectively). That works and can be quite convenient, but you lose performance big time (think 1000-fold and more) - these are still interpreted languages, after all. For some cases, this is irrelevant - reading out an I2C sensor and analysing its values can easily be done slowly, if the I2C support is present and if we’re only reading out that sensor once a second or so.

But what if we want more performance? - or run on a smaller µC with 32..128 KB of flash?

One solution is the Arduino IDE: a cross compiler which runs on a large “host” and generates code for our very limited “target” µC. Or some similar “ARM embedded gcc toolchain”.

Which is where we stand today, in 2016: tethered software development, with the source code and tools living in one world (our laptops or the web), and the µC being sent a firmware upload to perform the task we’ve coded up for it, after translation by our toolchain:

What if we just want to investigate the hardware, check out a few settings in the chip, briefly toggle a pin or adjust a hardware register setting? Tough luck: you have to leave the flow of design and implementation, and enter the (completely different) world of remote debugging.

Our µC might as well be on Mars. With all our fancy tools (constantly updated, improved, changed) we’re virtually coding in the dark nowadays. We’re adding layer upon layer of technology and infrastructure, just to make that darn LED blink! Or read out a sensor, or make something turn, or respond to sensor changes, whatever. Does it really have to be so hard?

(speaking of Mars: Forth has been used in several NASA space missions)

What if we could talk to an embedded µC directly over a serial port connection, give it simple commands, tell it things to do now, or save for later, or do continuously. As we gradually build up our application, the µC records what we’ve done, lets us change things as much and as often as we like, selectively wiping some previously saved definitions.

Forth can do that. It’s a programming language, but it’s also a full-blown development system. Once you store the Forth “core” into the µC, you’re done. From then on, you can type at it, make it do things, and go wild. If you make a mistake (as we all do, especially while trying out stuff), you simply press reset to return to a stable system.

There is hardly a toolchain involved. The Mecrisp Forth core is written in GNU “assembler”, producing a 16..20 KB “.bin” or “.hex” file, and that’s it. You never need to go back and change it. Everything else can be built on top. Mecrisp Forth is extremely fast, so what you write can also be. There’s an assembler for the ARM Cortex written in Forth: if you load it in, you can extend the core by adding assembler code (using a Forth-like syntax). There’s even a disassembler…

(please note that assembly language is there if you want it, but hardly ever needed in Forth)

But there is one major (and very painful) drawback, in today’s world with millions of lines of code written in C and C++: Forth and C don’t really mix. A µC running the Forth core cannot easily interoperate with C code, although it can be tricked into calling external routines with C linkage (Forth can generate assembler instructions for any purpose, after all).

To sum it all up: think of the Mecrisp Forth core as a boot loader - you have to get it onto the µC once, and then it becomes the new “communication language” for the chip. From there on, this µC will understand plain text Forth commands, including saving potentially large amounts of (your!) Forth definitions after its own flash memory area. All you need, is a serial port + terminal interface, plus a robust way to send larger amounts of Forth source code to the chip.

With Forth, you don’t have a “build environment”. Forth is the environment and it’s running on the chip you’re programming for. It’s intensely interactive and there are no layers of complexity. There is no compiler, no linker, no uploader (other than a text-mode send tool), no bytecode, no firmware image, no object code, there are no binary libraries, no conditionals, no build flags.

For turnkey use, you can define a function called “init” and save it in flash memory. Then your chip will run that code on every reset. But beware: if you don’t include a mechanism to get back to command mode, then the only way to get back control is to reflash the chip with a fresh core…

There is one other “drawback”: Forth blows away every notion of language syntax and software development methodology you’re probably used to - but that’s for the next articles…

Weblog © Jean-Claude Wippler. Generated by Hugo.