Quantcast
Channel: Articles on JeeLabs
Viewing all 296 articles
Browse latest View live

Multi-platform development

$
0
0

The title of this article is perhaps a bit misleading: it’s not just about developing code which needs to run on different platforms, it’s also about using different programming languages.

Over the years, here at JeeLabs s/w development has always been about more than getting stuff working on one CPU: we want display and control tied to our laptops and mobile devices.

With µCs which collect and exchange data, multi-platform development is inevitable.

At some point, it might have been worth considering writing everything in C/C++, from the embedded µC to say a central Raspberry Pi, with server-side rendering of pages (as is still the model for PHP). But we’ve all seen the benefit of running something other than C on the server, and of course the browser world has been completely taken over by JavaScript. With rich “single-page applications” (SPA) taking over more and more of the user experience. And for good reason: we get astonishingly powerful and intuitive user interfaces (and eye-candy…).

It might seem that writing at least the server- and client-side using the same language is a good way forward. IOW: NodeJS on the server and JavaScript in the browser. And while JavaScript on a µC is definitely feasible, it’s not a convincing match in terms of performance and code size.

Meteor is one well-known example which tries to merge server- and client-side development, to the point that you can develop both sides as a single system, sharing code as much as possible.

There are some caveats with that approach: 1) developing in the same language on both sides ignores the fact that they deal with completely different problems (and that staying in the same context can actually be very confusing!), and 2) even NodeJS is a bit hefty for low-power Linux boxes such as Raspberry Pi or CHIP (it tends to fill up RAM when running for months on end).

So if JavaScript 1) can’t be avoided in the browser, 2) is not a great fit for low-power central always-on servers, and 3) doesn’t fit on low-end remote µC nodes, what’s the alternative?

My choices

Here’s the solution I’ve been moving towards for quite some time now:

  1. Use Forth or C/C++ for remote embedded µCs
  2. Use the Go language on the server side (it was actuallymade for that purpose)
  3. Use JavaScript or a language which generates JavaScript in the browser

Both Forth and C/C++ fit easily, even on small µCs. They are both compiled code, so they don’t waste time running an interpreter. And they both go all the way down to the bare metal, so that full control of all the embedded hardware is always possible.

Go could be called “modern C/C++ for servers”: garbage collected, modern interface-based composition, and channels plus “goroutines” to tame multi-threading and asynchronous tasks. Without the race-condition risks that usually come with threads and interrupts. As bonus, it’s trivial toproduce stand-alone executables in Go for over a dozen platform / OS combinations.

And JavaScript… needs no explanation. Browsers dig JavaScript, period.

To borrow and re-purpose a phrase fromClojureScript somewhat:

  • Forth and C/C++ scale downwards
  • Go gets (parallel) work done
  • JavaScript reaches

Which brings me to the main topic of this article: how to deal with all this, as a developer?

My setup

The answer is: with a bit of care, the entire development process can be streamlined to a very comfortable level. Here’s what it comes down to (a lot of this is personal preference, of course):

  • Laptop - everything can be done with a single laptop (Win/Mac/Lin, your pick)
  • Source code - all source code is tracked in git for total recall and tamper-proof storage
  • Collaboration - use GitHub orGogs (self-hosted) for repositories and issue tracking
  • Forth - source code in Git, µC interface using Folie and… look ma, no toolchain!
  • C/C++ - the usual suspects: Arduino,STM32duino,libopencm3 - a plethora of choices
  • Go - source code in Git, cross-compile to ARM with GOOS=linux GOARCH=arm go build
  • JavaScript - probably via ClojureScript withReagent (i.e.React wrapper) andFigwheel

I very much prefer to work on Mac, although I’ve been using Linux (and Unix) longer than I can remember, and feel very much at home on its command line (GUIs are another story: too inconsistent and quirky for my tastes). Here’s the screen layout I use most often on my laptop:

For purely text-based work, I’m still considering using thei3 window manager, on a screen of its own in Linux. But as soon as browsers and other GUI tools are involved, the Mac has my vote.

There are two ways to run Linux on this same machine:

  • Docker for Mac uses macOS’s newnative“Hypervisor” framework. It’s as close as you can get to running Linux code with macOS managing the machine and the GUI. There is no need to install a VM like VirtualBox, Parallels, or VMware - a fascinating trend!

  • Running a Virtual Machine is the more traditional way to run macOS and Linux in parallel, with the ability to integrate a Linux GUI into the Mac’s. This leads to a more pure Linux setup.

In both cases, it’s easy to call into Linux using SSH and have it show up in a terminal window on the Mac side, as shown in the blue box above. Both can be configured to share areas of the underlying macOS file system, so you don’t have to copy stuff across - you can just “cd” to the right place. Source code can be edited on macOS and Linux will see the changes, and vice versa.

A virtual machine could also be used to run Windows (at the same time, if you have enough memory), but there’s little incentive for me to go there - other than to try out a Go application built for Windows, perhaps (using“GOOS=windows go build”).

Virtual machines have come a long way, at least with Parallels Desktop for Mac version 12. And it shows - on the USB side, for example: when plugging a USB device into the laptop, you can choose whether to connect it to macOS or to one of the running VMs. This now works so well that where FTDI caused infinite grief (in the form of kernel panics!) for many years, all of these issues go away when the device is tied to the Linux VM, making it do things the Mac (or rather: FTDI) never got right, like controlling both the DTR and the RTS pins over a serial USB link.

As a result, I can now launch Folie on Linux, while working on the Mac laptop, and all is well: Ctrl-C to reset the attached µC and “!u 6” to upload Mecrisp to a JeeNode Zero - \o/ - yeay!

Another aspect of Linux is that it can run qemu-user-static, which can launch an ARM-based executable on Intel hardware. This offers an astonishingly transparent form of emulation: once installed, Linux will automatically recognise the ARM file format and insert the Qemu layer.

Quite a convenient setup, all in all: macOS, Linux, Windows even, and the ability to run ARM executables, like the Linux build of Mecrisp Forth. All on one laptop, using a single file system.

Docker example

To give you an idea of what Docker can do, let’s create a “container” withqemu-user-static and Mecrisp for Linux (i.e. ARM), which will be launched every time we fire up the container:

$ cat Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install -y qemu-user-static
ADD mecrisp-stellaris-linux mecrisp
CMD "./mecrisp"
$

With that Dockerfile, and a copy of mecrisp-stellaris-linux in the current dir, we can do:

$ docker build .
Sending build context to Docker daemon 63.49 kB
Step 1/5 : FROM ubuntu
---> ebcd9d4fca80
Step 2/5 : RUN apt-get update
---> Running in 3c06495691ab
Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
[...etc...]
Step 3/5 : RUN apt-get install -y qemu-user-static
---> Running in e1651fff44b9
Reading package lists...
[...etc...]
The following NEW packages will be installed:
binfmt-support libpipeline1 qemu-user-static
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 7879 kB of archives.
After this operation, 86.1 MB of additional disk space will be used.
[...etc...]
Step 4/5 : ADD mecrisp-stellaris-linux mecrisp
---> 88249491f198
Removing intermediate container 2148b8a50044
Step 5/5 : CMD "./mecrisp"
---> Running in 5e75eef61d34
---> 11e4ed2299dd
Removing intermediate container 5e75eef61d34
Successfully built 11e4ed2299dd
$

Lets give it a friendlier name:

$ docker tag 11e4ed2299dd mecrisp

The result is a “container” image, which is Docker’s terminology for a snapshot of the state after the above process completes (i.e. a download plus apt-get to install qemu-user-static). Now that we have such an image, we can launch the Mecrisp setup almost like any other application:

$ time docker run -it --rm mecrisp
Mecrisp-Stellaris RA 2.3.6 for Linux by Matthias Koch

real    0m1.203s
user    0m0.015s
sys     0m0.013s

That’s really all it takes: just over a second to bring up a Ubuntu context (within the Mac!), launch Mecrisp (emulating the ARM code via Qemu), stop the whole process again (since I typed ctrl-d right away), and clean everything up. Should also work on Docker for Windows.

So now there’s a way to try out Forth code from the Mac command line - look ma, no hands!


Meet the new RF73 driver

$
0
0

There’s a new wireless radio driver in town for the JeeNode Zero and other µC boards running Mecrisp Forth. It’s calledRF73 but it is in fact intended to be used with the RFM70, RFM73, and RFM75. These are low-cost 2.4 GHz wireless modules made by HopeRF, the same supplier as for RFM12 and RFM69. These modules are derived from designs created by Silicon Labs.

The currentrf73.fs code is still very young, and not quite ready for general use. Part of this is due to the fact that the RFM7x’s use a slightly different routing model: each unit has the ability to receive data on 6 specific addresses, and is meant to be used in a 1:6 mesh topology. What this means is that the RF12/69’s idea of node IDs and net groups is slightly different. It’s going to take a little more head scratching to map the RF73 to a reasonably generic model and API.

The RFM7x’s can receive packets up to at most 32 bytes, but they do have 3 buffers, so more packets can be in-transit as the driver works its way through the send and receive data. This is important because the maximum data rate of these modules is a whopping 2 Mb/sec: you can send and receive a lot of data with these, plenty for audio and text streams over 115,200 baud.

The flip side (yes, everything is a trade-off), is that the range of the RFM7x is only 5..10 meter, especially indoor and when there are walls involved. Fine for a room, not for an entire house.

Here is the setup which was used to develop this first iteration of the RF73 driver:

(these are older “v1” versions of the JeeNode Zero, each with an RFM70 mounted on them)

The Quad Serial shown above is a 4-port FTDI interface, with support for the DTR + RTS pins needed to reset and re-flash attached µC boards. A custom-made plug-in board converts the header pinouts to four standard 6-pin FTDI ports, as used by JeeNodes and many others.

Writing a wireless driver from scratch and debugging it can be a challenge: you have to figure out which side of the RF link is not working. Without aMixed-Domain Oscilloscope, it’s hard to tell what’s going on (even that high-end scope is not capable of capturing 2.4 GHz, by the way!).

There already was an older driver written in C++, with a test program for two LPC824-based boards, and they were happily exchanging test messages. In that context, with known valid packets flying around, the first coding task was simply a matter of picking up those messages.

After that, things went fairly smoothly, leading to a138-line driver written in Forth, which can send and receive individual 1..32-byte packets. Almost half of that code is for initialisation.

The RFM7x series has one very interesting feature: there’s an optional “auto-ack” mechanism, whereby the receiver immediately sends an ACK on proper reception, with the sender timing out and retrying a few times if it doesn’t see that ACK. Very much like the Easy Transmission mechanism implemented in software for the RF12 driver inJeeLib, but now all in hardware.

The performance with a 2 MB/s data rate and optional fast ACKs is quite impressive:

  • sending a 10-byte packet without ACK takes some 300 µS
  • sending that same packet and waiting for the ACK takes ≈ 500 µs

With ACKs, you get a reliable communication channel, since transmission errors lead to retries and much lower error rates. There will be a delay with retries, up to 60 ms with the maximum 4 ms timeout using 15 retries. Failures are still possible, of course - just considerably less likely.

The RFM7x modules are very similar to the nRF24L01 (and maybe even compatible on-air?). Both have been widely used in RF-based wireless audio headsets, for example.

So there you go: a new choice, for when you need more speed and can live with a lower range. And the JeeNode Zero already includes the proper footprint for these RFM7x’s on its PCB.

Interactive Forth over RF?

$
0
0

Since Mecrisp Forth uses the serial port as its interactive console, the most direct way of connecting to a µC board is as follows (double-line arrows represent wired connections):

When using some widely available low-cost STM32F103 boards with built-in USB port, we can in fact simplify this considerably by using a USB console driver instead of that FTDI adapter:

But what if we could also re-apply the same trick using wireless radio modules?

This requires an extra µC on the “central” side to bridge between USB and RF, but it would add the ability to talk to one or more remote wireless nodes - interactively!

Note that such a central bridging node plays more or less the same role as an FTDI adapter, but using an RF-based packet link instead of the FTDI’s 6-wire hookup.

Here is a hacked-up central node based on theHyTiny board and some free-style soldering:

The above concoction is currently being used for development and testing, although a JeeNode Zero with FTDI would also work. Some bugs and puzzles still remain, but we’ll get there…

An RFM70 module is being used here, because its built-in auto-ack mechanism helps greatly to simplify initial development. The RF console will be ported to RFM69 once everything works.

There are some interesting uses for such an RF-based console driver in Mecrisp: perhaps most importantly, it enables remote configuration and debugging, especially in combination with the multitasker to keep both the interactive console and the application code running in parallel.

This RF link capability can also be used to upload new code or reload the on-board application.

Redesigning the JET model

$
0
0

The JET project (JeeLabs Embello Toolkit) is the continuation of the earlier HouseMon project (in turn the successor of JeeBus). It’s been a slow starter, but definitely not shelved. The JET “Hub” has been running for the past few years here at JeeLabs - dutifully collecting monitoring data from two different sensor networks, saving log files, and forwarding messages to MQTT.

The “Hub” was implemented with the assumption that a single process should be kept running at all times, with various “Packs” started and stopped on demand, as child processes.

But recent experience with Folie points to a much more practical design, with one process per external interface instead of this single monolithic hub. The always-on role can easily be taken over by the MQTT message broker, i.e. Mosquitto - which is widely use in today’s IoThype?

The Mosquitto background task consumes very few resources and can be kept running 24 / 7, acting as central switchboard and message exchange. Great for a low-end Linux board.

Mosquitto 1.4.8 and later include two major new features: 1) WebSocket support and 2) a built-in web server for static files. These can offer aperfect mechanism for rich and responsive web applications, together withPaho for MQTT message streams andReact for the user interface.

The core JET system is trivial to set up: install Mosquitto from whatever package manager you use (recent versions are available via apt-get on Linux, or homebrew on Mac, for example).

Since MQTT is based on TCP/IP sockets, its clients can be located anywhere on the network.

You can configure SSL-secured connections where needed - it’s all well-documented and very easy to set up. And here is how to activate the built-in HTTP server with WebSocket support:

listener 9001
http_dir /var/www/mosquitto
protocol websockets

Mosquitto supports listening on multiple ports and can restrict access to MQTT’s “topic tree”. These features are useful to expose only a subset of all your messages to the outside world.

What about the rest of JET?

Well… that’s mostly a matter of launching instances of Folie for each hardware interface, plus additional tasks to perform functions such as logging, database storage, and rule automation.

Each of these can then publish its results to MQTT and subscribe to specific MQTT topics (or wildcard topics) to be notified of events as they occur. There you go: messaging in action!

Turning JET into a live system

$
0
0

The previous article about the redesigned JET model mentioned Folie as sitting between a USB interface and MQTT, presumably to publish received RF messages on MQTT, and to subscribe to an MQTT topic so commands will be picked up and sent out over RF.

But that’s not quite how Folie works right now.

The current version of Folie is aimed at interactive command-line use, for directly-attached µC nodes, and hopefully soon also for remote RF nodes. As the name says, a Forth Live Explorer:

At some point, we’ll want to collect incoming data and to send out commands to specific nodes. This is a perfect task for MQTT - as always-on“message broker” between various processes:

Since MQTT is network based, it does not need to be running on the same machine as Folie.

But Folie is more than a front-end for Mecrisp Forth. It’s also able to send entire source files (and recursively expand further included files), it can upload new firmware to an STM32-based µC via its ROM boot loader, and it can connnect to a Telnet server such as ser2net oresp-link.

The question is: how to create a structure which supports gradual development and growth?

Because JET is not about installing a system, configuring it, and then just“letting it run”. What we need, is a design which lets us add features as the need arises - perhaps downloaded from the net, because somebody else had some neat idea, or else built ourselves as custom add-on.

Just like a city, JET should be able to grow organically, over a very long time, and evolve in ways which cannot be predicted up front: i.e. infra-structure which must be solid and stable.

In JET, MQTT is the only fixed point in the system (along with naming choices for its topics and the message format). Everything else can be changed and replaced over time in case anyone comes up with a clever new way of doing things. With a bit of topic-prefix planning, a single MQTT instance can in fact support multiple approaches running in parallel.

But Folie v2 isn’t quite usable as is: it’s based on direct interactive use (great for development) and not really meant to be used unattended, when some parts of our setup are becoming useful and solid enough to keep them running all the time (e.g. some wireless sensor nodes).

This is about to change. The next major revision of Folie will allow both production mode and development mode to be mixed (and switched) as needed, using a new pass-through mode:

Note that Folie will continue to fully support the original development style, i.e. as interactive console front end for Mecrisp Forth µC nodes, both directly attached and via RF. What’s new, is that Folie v3 now adds SSH to the mix (both as server and as client), due to some terrific recent work by Thorsten von Eicken, who also re-factored the original code to prepare for changes like these (while keeping the !send and !upload functionality fully intact).

Since MQTT can be configured to use SSL connections, this creates anetwork-savvy context for all JET and JeeNode Zero development, which supportsprivate and secure connections from a development machine, including source code uploads and remote re-flashing.

The intended use is for a small Linux board such as a Raspberry Pi, Odroid, or CHIP to run MQTT and one or more instances of Folie, each talking to their own µC via a USB interface. All development access then takes place from your own cosy development machine, with your favourite code editor, version control tools, and personal backups.

And yet it’s still fully adjustable - nothing prevents you from setting up everything on a single laptop, plugging the µC board into USB, and doing everything off-line, i.e. anywhere you like.

Use any STM Nucleo as programmer

$
0
0
The Nucleo boards by STMicroelectronics cover a fascinating range of STM µC’s, and are provided for non-commercial use at very low cost. It’s a great way to get started, because they include a built-in “ST-Link V2.1” programmer: Actually, the programmer is the only part we’re interested in here. That’s why any Nucleo board will do here. You could saw the bottom part off (can’t break it easily, unfortunately). The first thing to do is remove those two jumpers.

From eBay "C8"µC to BMP tool

$
0
0
Next in line in the “let’s create an ARM programming tool” series is this little board: It’s basically a breakout for the “STM32F103C8T6” chip (yes, it does take getting used to). That’s 64 KB of flash and 20 KB of RAM memory - (just) enough to run the BMP software. Here’s a little PCB for it (also off to a prototype run at the time of this writing): This board goes on top.

The HY-Tiny can also act as BMP

$
0
0
As last example in this “let’s make an ARM programmer” series, the HY-TinySTM103T: It’s a great little STM32 board with a nice set of features: 128 KB flash, 20 KB RAM, the usual mix of peripheral interfaces, and a little programming + debugging header at the bottom. We’re going to turn the one below (on the right) into a Black Magic Probe:… which can then be used to program and develop code on the one on the left!

ARMinARM can set you free!

$
0
0
Software development for ARM µCs can be done in many ways. There is the Arduino IDE, and the Arduino-STM32 project specifically for STM32 microcontrollers, but there are more ways to skin this cat. One part of the work needed to get there, is to get the proper toolchain installed. Another piece of the puzzle is how to hook up the chip for development. The ARMinARM board by OnAndOffables deals with both.

A plethora of tools on the Pi

$
0
0
The ARMinARM code is available on GitHub, and is a major convenience for this particular approach. Just get a reasonably fresh install of Raspbian running and you should be all set to install lots of tools, by following that README on GitHub. The “setup” tool does all the hard work, and not only does it install all sorts of software, it also contains the logic to update to newer versions over time:

Developing in C/C++ for STM32

$
0
0
Let’s now use the ARMinARM setup to try out a few of the included example programs. CMSIS The CMSIS library is supplied by STM, as ARM partner and µC manufacturer: $ cd arminarm/src/CMSIS_StdPeriph/examples/leds/ $ make mkdir -p build/src/ arm-none-eabi-gcc -c -O0 -g -Wall -I. -mcpu=cortex-m3 -mthumb [...] [...] $ arminarm -f build/leds.bin flashing build/leds.bin using stm32flash [...] Wrote and verified address 0x08005a64 (100.00%) Done. Resetting device... done. That’s it, the red LED should now be flashing (occasionally, you may have to reset the STM32F103 chip before it lets you flash new code onto it, using: “arminarm -r”).

Developing in Lua for STM32

$
0
0
Lua is a very interesting small programming language, in the same way as Perl, Python, Ruby, and Tcl are - i.e. a dynamically-typed “scripting language”. Here’s the blurb: Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.

Developing in JavaScript for STM32

$
0
0
Last in this little series is another language: JavaScript. There is a mini-implementation of JavaScript called Espruino which can operate in even more cramped environments than Lua (and MicroPython, another language environment for the embedded world). Espruino runs on boards created via crowdfunding - the latest being the Espruino Pico. This is an absolutely tiny USB-stick like board, with a fairly powerful STM32F401 µC: But Espruino is also the name of the JavaScript environment itself, which is fully open source and embraces many other µCs, including the STM32F103 on the ARMinARM.

Tiny Basic with room to spare

$
0
0
One of the first tricks we teach a microcontroller (any computer really), is to raise its level of abstraction, by programming it in a “higher level language”. All computers are really awkward at birth: they only understand machine code, i.e. streams of bytes & numbers. Nobody does that anymore, there just wouldn’t be enough hours in a day to get anything done. Instead, we use tools like gcc and the Arduino IDE.

Creating a virtual 6502 chip

$
0
0
Ok, we’ve seen Tiny BASIC, and how it turned a µC into a complete, albeit limited, programming environment. It took a mere 17 KB of flash memory. Now watch this: [emu6502] 10496 bytes 6502 EhBASIC [C]old/[W]arm ? Memory size ? 15615 Bytes free Enhanced BASIC 2.22 Ready The code running on the Hy-Tiny STM32F103 uses some more resources, in particular because now the interpreter context grabs 16 KB RAM for emulation:

Altair BASIC via 8080 emulation

$
0
0
Some of this retrocomputing emulation goes quite far. Some emulators running code for these old machine can generate a video out signal - with an entire community around the computers people used to tinker & play with in their youth. See RetroPie, for example. Let’s not go there for now, but we could try an emulation of a more general-purpose low end machine, from the 1970..1980’s era. Such as this clunky beast, called the Altair 8800:

JavaScript in a 128 KB µC

$
0
0
As final entry in this episode of “fitting an interpreter into a 128K STM32F103”, there is one other very interesting development to consider. It’s called the Espruino project. Sure enough, we can fit this JavaScript interpreter into a µC with 128 KB flash and 20 KB RAM, albeit with not too much room to spare: $ HYTINY_STM103T=1 RELEASE=1 make 2>&1 | head Generating platform configs Generating pin info Generating JS wrappers WRAPPERSOURCES = src/jswrap_array.

TFoC - The Fabric of Computing

$
0
0
So what is it with computing with limited resources? How can kids with enough time on their hands, a dose of ingenuity, and access to very limited (in today’s terms) computers create all sorts of software which fits and runs in 2000 to 8000 bytes of memory? While everything we build today with something like the Arduino IDE takes at least that much before we even start adding our own code?

Move over, John von Neumann

$
0
0
Computers do their work one step at the time. Over, and over, and over, and over again. The breakthrough came when not only the data they manipulate but also the instructions that drive their actions were stored in memory. You take data from memory, you “process” them in some way, and at times you also put something back. Most of it used to be about doing arithmetic - nowadays it’s more about pushing bits around in interesting ways than true “computation”.

Building a MultiComp-based Z80

$
0
0
Let’s see if we can build an FPGA-based system. The biggest challenge is that everything involved is completely different from software and hardware design. It’s a new ball game! We will need: some hardware (evidently, an FPGA is still a chip, just a different one) a design, this is essentially the schematic and wiring diagram a software tool chain to “synthesise” the design into a “bit stream” a way to upload that bit stream into the FPGA a connection between the FPGA and the outside world a healthy dose of curiosity, concentration, and time… There are too many unknowns and new aspects to this to tackle it all at once.
Viewing all 296 articles
Browse latest View live


Latest Images