eForth1  v2.4
eForth1 - eForth for Arduino UNO

Dr. Chen-Hanson Ting, the creator of eForth and one of the inspiring figures of Forth community, wrote: >*In all these years, I have thought that the eForth Model is a good model useful for all different processors and microcontrollers, and for all different applications. It is a very simple model for anybody who like to learn Forth and to use it for their own applications.*

In 2011, Dr. Ting created *328eForth* to run Forth on Arduino UNO and wrote in his ceForth_33 document:

I was attracted to Arduino Uno Kit and ported eForth to it as 328eForth...writing to flash memory, I had to take over the bootload section which was monopolized by Arduino IDE...I extended Forth dictionary in the RAM memory. It worked. ...., it was only a teaser to entice new people to try Forth on Arduino Uno.

Personnally, I enjoyed the beauty of working on something small and simple, so decided to pick up Dr. Ting's eForth Model to push it beyond being a teaser. Here we go...

What is eForth1?

  • An eForth for Arduino UNO/Nano implemented in C.
  • .ino sketch file can be openned in Arduino IDE, no programmer to overwrite bootloader needed.
  • Has 16-bit cells and stacks.
  • Can read/write Arduino GPIO pins.
  • Supports Arduino Timer and Pin Change Interrupts.
  • Has C API to interface with user defined functions written in .ino.
  • Can save/restore app to/from EEPROM.
  • Can be embeded with other Arduino applications.
  • Can become a turnkey system booting from saved EEPROM or enscripted Forth code.

How to install eForth1?

  • From Arduino IDE's Library Manager

    Make sure you've hooked up one of Arduino Nano/Uno, or a development board that hosts ATmega328

    > from Arduino IDE > Tools > Manage Libraries, enter FORTH in search box

    > find eForth1 in the short list, select the latest version, and click the Install button

    > from Files > Examples, find eForth1 in Examples from Custom Libraries at very buttom section

    > load one of the eForth1 examples, such as 0_hello

    > open Serial Monitor, set baud rate to 115200, and line ending to Both NL & CR

    > hit compile and upload. You should see the 'ok' prompt

  • Or, from GitHub directly, if you prefer managing source codes manually

    > git clone *https://github.com/chochain/eForth1* onto your local Sketch directory

    > copy examples/0_hello/0_hello.ino from sub-directory, then rename it as eforth1.ino

    > open eforth1.ino with Arduino IDE, and setup your Nano/Uno (or ATmega328) development board

    > in eforth1.ino, change the #include <eforth1.h> to #include "./src/eforth1.h"

    > open Serial Monitor, set baud rate to 115200, and line ending to Both NL & CR

    > compile and upload, you should see the 'ok' prompt

Hopefully, thing goes well and you get something like the snip below if eForth1 is uploaded successfully.

  • >

Now type WORDS in the input bar and hit <return> to list all the words supprted by eForth1. It is ready to serve your future fun projects.

  • >

Different from Dr. Ting's

  • Instead of the original 32-bit, CELL is 16-bit, and prmitives are 8-bit opcodes.
  • To save space, primitives are compiled as bytecode and composite words are flagged address pointers.
  • For speed, use direct threading model instead of original subroutine threaded,
  • Instead of raw GPIO port read/write, eForth1 calls Arduino library functions i.g. PINMODE = pinMode, IN = digitalRead, OUT = digitalWrite, ...
  • Support multi-tasking. Timer2 sliced at 1ms as the heart-beat with 8 ISR handler slots provided which Forth words can be assigned to. Timer1 is left free for Servo or other libraries.
  • Support Delay (sleep). It does not pause the MCU nor does it interfer with interrupts. 16-bit delay max 32767ms, longer delay can be have by defining word that loops.
  • Support Pin Change Interrupts. ISR handler slots are provided for each of Port B,C, and D.
  • Support 32-bit clock (in ms). It takes 2 cells off 16-bit stack. Arithmetics for double are also provided. DNEGATE, D+, or D- plus the conversion words D>S, S>D.

Demos

  • LED blinker (assume you have a blue LED on pin 6, or try *this Wokwi project*)
        > 1 6 PINMODE⏎                           \ set pin 6 for OUTPUT, i.e. pinMode(6, OUTPUT=1)
        > : blue 6 IN 1 XOR 6 OUT ;⏎             \ create a word to toggle the blue LED
        > : blink FOR blue 500 DELAY NEXT ;⏎     \ create a word to blink (i.e. 500ms delay)
        > 9 blink⏎                               \ run 10 cycles (i.e. 9,8,7,...,2,1,0 to on/off 5 times)
        
  • Timer Interrupt Service Routine (a red LED on pin 5)
        > 1 5 PINMODE⏎                           \ set pin 5 for OUTPUT
        > : red 5 IN 1 XOR 5 OUT ;⏎              \ create an interrupt service routine (just a regular word)
        > ' red 200 0 TMISR⏎                     \ make the ISR ticked every 0.2 seconds (= 200ms)
        > 1 TIMER⏎                               \ enable timer, now you should see red LED blinking continuously
        > 19 blink⏎                              \ let's have them both blink (blue LED 10 times) 
        
Blinker Interrupt Service
  • Drives 8 Servos. Demo at *this Wokwi project*
  • Controls 4-legged Robot (8 servos) with ultrasound and IR remote. Demo code in ~/examples/8_kame
Ultrasound Ranging Walking
  • Bluetooth (HC-05) communication. Demo code in ~/examples/9_bluetooth
  • WiFi (nRF24L01s) communication. Demo code in ~/examples/11_rf

Benchmark

  • Classic 1 million cycles
        > : inner 999 FOR 34 DROP NEXT ;⏎          \ inner loop (put 34 on stack then drop it)
        > : outer 999 FOR inner NEXT ;⏎            \ create the outer loop
        > : bench CLOCK DNEGATE outer CLOCK D+ ;⏎  \ CLOCK returns a double value
        > zz⏎                                      \ benchmark the 1000x1000 cycles
        > 25492 0 ok>                              \ 25492ms =~ 25.5us/cycle (with one blinking ISR running in the background)
        

#

To Learn More About Forth?

If your programming language exposure has been with C, Java, or even Python so far, FORTH is quite different. Quote Nick: "It's no functional or object oriented, it doesn't have type-checking, and it basically has zero syntax". No syntax? So, anyway, before you dive right into the deep-end, here's a good online materials.

To understand the philosophy of FORTH, excellent online e-books are here free for you.

Build your own Forth

Traditionally, the Forth image is build from low-level assembly and high-level Forth via a process called meta-compilation. See details here. Latest eForth, from Dr. Ting, changed the process to build the entire image with C only. I follow the same philosophy.

> git clone *https://github.com/chochain/eForth1* onto your local directory

> make rom # to create src/eforth_rom.c

study how src/eforth_asm.h, and src/eforth_asm.c create Forth image

study how vm_outer() in src/eforth_vm.cpp interacts with the ROM image

modify src/eforth_asm.c to build your version of eForth

> make # to generate tests/eforth1 for debugging, or

use Arduino IDE to compile and upload

Performance Tuning (~15% faster)

  • Check your Arduino IDE installed directory, say C:\Users\myname\AppData\Local\Arduino... on Windows or /home/myname/Arduino/... on Linux,
  • Find the directory hardware -> arduino -> avr,
  • With an editor, open the 'platform.txt' file,
  • Find all three -Os compiler options (i.g. compiler.c.flags=-c -g -Os ...)

    change them to -O3 for speed, -Os (default) for smallest size, -O2 for somewhere in-between

References to Dr. Ting's Original

For Projects small and large