Here is what we’re after, as Forth Development Environment (would that be an“FDE”?):
![]()
There are a number of steps needed to use Mecrisp-Stellaris
Forth in your own projects (for these
articles, we’ll be focusing on theSTM32F103µC
series with 64..512 KB flash memory):
- getting the Mecrisp core “flashed” onto the microcontroller
- setting up a convenient connection between your laptop and the µC board
- streamlining the iterative coding cycle as much as possible
Note that this is in some way quite similar to hooking up an Arduino or
JeeNode, and developing software for it through the Arduino IDE. But there also
some substantial differences:
- pick your own editor, “whatever works for you” is by far the best choice
- no compilers, no debuggers, no toolchain - just a simple way to talk to
the µC
- no binary code, no runtime libraries, just you, your code, and your terminal
The Arduino approach puts all complexity in the “host” laptop setup. The Mecrisp
approach builds words in the µC, on the fly, when they’re typed in (or
uploaded, i.e. “simulated typing”).
Installing Mecrisp
Step 1) is not Mecrisp-specific. It’s the same stumbing block with everyµC
setup which needs specific firmware. You need to download the latest
Mecrisp-Stellaris release from
SourceForge, and “get it onto
that darn chip… somehow” !
Here are some ways to do this, depending on what interface tools you have and
your O/S:
The firmware in the Mecrisp distribution is available in two versions, a“.bin
” and a “.hex
” file:
stm32f103/mecrisp-stellaris-stm32f103.bin
stm32f103/mecrisp-stellaris-stm32f103.hex
It depends on the upload mechanism as to which one you need. With a Black Magic
Probe (BMP) and arm-none-eabi-gdb
, for example, the following commands should
do the trick:
% arm-none-eabi-gdb
[...]
(gdb) tar ext /dev/cu.usbmodemD5D1AAB1 (adjust as needed, of course)
(gdb) mon swdp
(gdb) at 1
(gdb) mon erase (essential for Mecrisp!)
(gdb) load mecrisp-stellaris-stm32f103.hex
(gdb) q
Then, again if you are using a BMP and running on Mac OSX or Linux:
% screen /dev/cu.usbmodemD5D1AAB3 115200
Mecrisp-Stellaris 2.2.1a for STM32F103 by Matthias Koch
ok.
(quit with "ctrl-a ctrl-\" or "ctrl-a \" - depending on your setup)
The serial connection must be set up as 115200 Baud for Mecrisp - 8 bits, no
parity, 1 stop bit.
If you’re using an ST-Link to upload the firmware, these two commands will do
the trick:
st-flash erase # essential for Mecrisp!
st-flash write mecrisp-stellaris-stm32f103.bin 0x08000000
It’s very simple and quick, but only · a f t e r · you’ve got all those Pesky
Little Details just right. Getting firmware onto a bare STM32F103 µC can
still be a hit-and-miss affair. There are simply too many variables involved
to come up with a procedure here which will work for everyone.
The good news is that with a little care, you will not have to repeat this
step again. Mecrisp is quite good at keeping itself intact (it refuses to
re-flash itself, for example).
Installing PicoCom
One of the things you’ll notice if you try out the above setup with screen
, is
that it doesn’t quite get the line endings right (which are bare LFs in Mecrisp,
not CR+LF). It’s better to install a slightly more elaborate terminal emulator -
and PicoCom is in fact a very good
option for Mac OSX and Linux, as will become clear below. For Windows, there isTeraTerm.
To install PicoCom on Mac OSX with Homebrew, enter this in a command shell:
brew install picocom
To install PicoCom on Debian/Raspbian/Ubuntu Linux, type:
sudo apt-get install picocom
The benefit of PicoCom is that it allows specifying a program to use for
uploads. We don’t want to manually enter text, we also need to send entire
source files to Mecrisp Forth over serial. The problem is that a bare Mecrisp
installation only supports polled serial I/O without handshake. This can only
handle text if it’s not coming in “too fast”. In
Mecrisp, each word on a line needs to be looked up and compiled, and it all
happens on a line-by-line basis. This means that you have to wait for its“ok.
” prompt after each line, before sending more text.
One solution is to send all text · v e r y · s l o w l y · but
that’ll make it extremely time-consuming.
Installing msend
A better solution is to send full speed and wait for that final prompt before
sending the next line, to avoid input characters getting lost. This little
utility has been created to do just that:msend.
If you have Go installed, getting msend (Mac OSX and Linux
only, for now) is again a one-liner:
go get github.com/jeelabs/embello/tools/msend
Otherwise, you can get the latest binary release for a few platforms fromGitHub.
With “msend” installed, PicoCom can now be started up as follows:
picocom -b 115200 --imap lfcrlf -s msend /dev/cu.usbmodemD5D1AAB3
Or even as “mcom /dev/cu.usbmodemD5D1AAB3
” - if you add an alias to your.bashrc
init file:
alias mcom='picocom -b 115200 --imap lfcrlf -s msend'
And now line endings not only work properly, you also get a very effective
upload facility. This will be worth its own article, but you can see a
transcript of an upload with includes over
here.
Sending a file with PicoCom is triggered by typing “ctrl-a ctrl-s
”.
To quit PicoCom, type “ctrl-a ctrl-x
” - see also the manual
page for further details.
Windows
Neither PicoCom nor msend are available for Windows, but there’s another
solution:
- install TeraTerm, which is a terminal
emulator for Windows
- look at this script
file
for TeraTerm, by Jean Jonethal
This combination should accomplish more or less the same as picocom + msend,
i.e. terminal access, throttling text sends, and inserting “include” files.
Optimising workflow
Forth software development is aboutflow and insanely fast
turnaround times between coming up with an idea and trying it out. There are
no compilers or other tools to slow you down, and as a result you can type and
try out an idea the moment it pops into your head. Total interactivity!
At the same time, the last thing we want, is to constantly re-enter
code, let alone lose it for good if the µC crashes. The challenge is to
find a proper balance between volatile commands (typed in directly at
the Mecrisp prompt, on the µC) and re-sending lots of text from a laptop all
the time.
Mecrisp has an elegant and simple approach to help with this:
- when you power it up, Mecrisp remembers only what it had stored in flash
memory
- all new definitions (i.e. “
: myword ... ;
”) are added and compiled into RAM - stack underflows (a common mistake) clear the stack but won’t lose RAM
- a reset (whether in hardware or using the “
reset
” word) will lose everything
in RAM - you can save your next definitions to flash memory by typing“
compiletoflash
“ - this will continue until you press reset or enter “
compiletoram
“
The thing is that in Mecrisp Forth, a hard crash is no big deal - youshould expect to run into stuck code, awful crashes, weird things happening,
non-responsive terminal I/O, etc. There’s a reset button on the µC
which will get you back to a working state the (sub-) second you use it.
It could be a typo. There could be a hint in what’s on the screen. But even if
not, if you make your coding cycles short and frequent,
then chances are that you’ll quickly discover what went wrong.
Otherwise… the interactive Forth prompt is your friend: examine the values
of variables, or the settings in hardware registers, and invent whatever words
you need to help figure out this issue. Words can be one-liners,
written only for use in the next few minutes of your investigation!
The more loosely coupled your words are, i.e. called in sequence, not nested
too deeply, the easier it will be to set up the stack and call any one of them,
in isolation, from the prompt. If something fails, you can take over and repeat
the rest of the words by hand, verifying that the stack is as expected (check
out the “.s
” word!), and peeking around to see what’s going on.
Looking at the diagram above, you’ll see that there are two kinds ofpermanence in this context: source code in files, and words defined in flash
memory. The latter cannot easily be turned back into source, alas. That means
they should be either one-offs or created by an earlier upload.
Although the best workflow has yet to be found, some comments on
what is likely to work well:
- new code, especially when it’s about getting the hardware interface right,
needs to run on the µC and can be quickly explored ad-hoc - at the Forth
prompt, no definitions needed
- you can read / write to registers with “
io@
” / “io!
” commands in a“peek and poke” style - lengthy setup code can be written in your editor, and then
uploaded and saved to flash
- hardware addresses are a lot easier to use as pre-defined Forth words (i.e.“
constant
”) - if you make uploaded code store itself in flash, you won’t have to re-upload
it after a reset
- the “
cornerstone
” word can partially unwind definitions from
flash - great for uploads - make sure your terminal window keeps a lot of history - it’s a very effective
historical log
Maybe the rlwrap tool
can be made to work with PicoCom - for command history and editing.
There is a lot more to say about this. The “msend” utility recognizes lines
starting with the word “include
” as special requests to fetch a file from
the system and send its contents (this can be nested). This allows keeping
various word sets in their own files, and then selectively include them
in each project. You can add “compiletoflash
”
to save the more stable words in flash.
For more ideas on how to organise the code, see theREADME
in the Embello area on GitHub.
There is no need for large nested source file trees. Forth source code tends to
be very compact - a single page of code is usually more than enough to
implement a complete well-defined
module. One directory with a few dozen files is plenty. Put them
under source code control in GitHub or elsewhere, and you’ll have your entire
project under control for the long-term. Each project can contain all the files
it needs to be re-created (i.e. re-uploaded to a µC running Mecrisp Forth).
Enough for now, this’ll get you started. Now go Forth, and
create lots of embedded µC projects!