eForth for cheap STM8S gadgets

Turn cheap modules from AliExpress into interactive development kits!

Similar projects worth following
STM8 eForth is a compact interactive Forth programming platform for STM8S and STM8L µCs. Code and binaries support many low-cost modules, e.g. the W1209 thermostat or the C0135 MODBUS relay board, and a layered build system makes it easy to add yours.

The project supports all STM8 devices, provides a library and serial interface options, uses test automation with uCsim and Docker on Travis-CI, and has e4thcom support for interactive programming.

The list of features includes Idle- and Background Tasks, interrupt handlers, I/O redirection, 7S LED or LCD drivers, analog and digital I/O, string evaluation, the VOC dictionary extension, and ALIAS for temporary dictionary entries.

STM8 eForth is based on Dr. C.H. Ting's STM8EF, an STC Forth that compiles machine code. Since the SDCC assembler and linker are used for building the Forth core, embedding it in C applications is possible. e.g. as a scripting engine.

What is it?

STM8 eForth is among the smallest user friendly Forth systems for µCs: it brings the simplicity of a 1980s style Forth to today's low-cost controllers. The project provides code for STM8 variants, board support for selected low cost targets, and docs. STM8 eForth has a long feature list but it uses very little memory. Innovative solutions, steady support, and an active community makes using it for new projects easy!

The code and binaries on GitHub can be used in many ways:

  • as an alternative firmware for Chinese commodity boards (e.g. thermostats, DCDC converters, and relay boards)
  • build embedded systems with an interactive shell (scriptable and extensible)
  • for creating smart sensors with SPI, I2C, or RS232 and a scripting shell, e.g. for RaspberryPi, Arduino, or ESP8266
  • as an interactive environment for exploring the STM8 architecture
  • for learning Forth - it's easy and fun (find out why in the text below!)
  • ...

Why a Forth for Cheap Chinese boards?

Because it's fun: cheap mass-produced imperfection is a playground for creativity :-)

The W1209 has long been my favourite target: it's a rather complete embedded control board with a UI at a very good price. It's as cheap as it looks, and the challenge is in it's imperfections: the guy who designed the board clearly didn't have a connected application in mind, and I had a lot of fun making it do things it was never intended to do.

There are challenges, like the lack of communication ports. The "sensor connector" can either be used as a a 2-wire RS232 "bus" or for sensing. If you need sensing and communication at the same time the project also provides a full-duplex 3-wire RS232 interface through the key pins (while keeping the keys functional). A plug-in system makes it easy to test new ideas, like using the "update connector" as a home brew field bus interface!

Which target boards are supported?

Besides generic targets for STM8S001, STM8S103, STM8S105, STM8S207 and STM8L051, there is currently support for the following boards:

Some more boards can be supported on request, e.g.

@Elliot Williams worked on using the ESP-14 as an IoT deviced (the ESP-14 module combines an ESP8266 with an STM8S003F3P6).

Programmable power supplies based on the XH-M188 and a cheap DC/DC converter are both work in progress. There are also several types of STM8S003F3 based voltmeters that are known to work.

Read more about possible future targets below.

Why Forth?

Again, because it's fun!

Forth starts out as a stack machine with a tiny instruction set and minimal hardware requirements. It fits in a few KiB, and the target, even a lowly µC, can even be used as the development system. The Forth stack machine is a minimalistic VM on a standard CPU, but there are also hardware implementations (e.g. for FPGAs, or a 144 core Forth processor). The VM is ideal for fast context switching and Forth easily meets hard-real-time requirements. It's no surprise that Forth was used in many NASA projects.

Consider this:

  • compared to other programming environments Forth is easy to understand fully
  • like Lisp, Forth has a REPL (Read-Evaluate-Print-Loop) which enables software testing in a way impossible with "Edit-Compile-Run-Debug" (e.g. Arduino)
  • it's easy to build Domain Specific Languages (one can literally program the compiler!)
  • the stack-oriented "factoring" method results in implicit data flow and modular code
  • Interpreter-compiler, basic OS functions fit in just 4K code :-)

A Forth programmer is in control of all levels of problem abstraction, a unique advantage in a...

Read more »

Original version of STM8EFalong with docs as received from Dr. C.H. Ting on 21/Nov/2016. The docs are worth reading, the eForth binary will run on the STM8S Discovery.

Zip Archive - 21.97 kB - 11/21/2016 at 20:13


  • 1 × ST-Link V2 ICP adapter (e.g. $2.00 from AliExpress) The ST-Link on an STM8S Discovery Board can be used, too
  • 1 × serial interface adapter /w 3.3V signal level (e.g. $0.60) e.g a USB interfacea with a CH340, or better a PL2303, chip
  • 1 × STM8S target device as listed in the GitHub Wiki (e.g. a $0.70 "STM8S103F3P6 minimal system board") e.g. "STM8S103F3P6 STM8S development board" from your favorite China source
  • 1 × Some headers, patchwires, breadboard etc (about $2.00) and other things you fancy, e.g. a RC-servo, SPI display, LEDs ...

  • Docs for "STM8 eForth Compiler and Assembly" updated

    Thomas12/24/2020 at 08:05 0 comments

    After the recent introduction of >REL for control structures with relative addressing the docs for the STM8 eForth Assembler Interface were in need of an update.

    I used the opportunity to restructure the paragraphs a bit. Feedback is welcome!

  • STM8 eForth Pre-Release 2.2.27.pre1 is out

    Thomas12/22/2020 at 15:42 0 comments

    I just published STM8 eForth 2.2.27.pre1:

    the GitHub release notes list the most important features, e.g. optional relative addressing for IF .. ELSE .. THEN, support for defining the "Background Task" event in user code (e.g. the RTC alarm).

  • STM8 eForth: IR Remote Controll for an RGBW LED Bulb

    Thomas12/20/2020 at 06:04 0 comments

    Today, IR remote control is by far the cheapest option for consumer electronics. I've long had the idea that Forth is ideal for interactive scripting of IR remote-controlled devices, and I used the light bulb at my desk to learn how to do it with STM8 eForth.

    imagePulseView and an IR receiver (a rather dated SHARP GP1UD272XK) revealed that the protocol is a "NEC" variant: some learning, thinking and coding, entering "7 ir<enter>" is all it takes for switching this $2 miracle on. The solution is quite generic and controlling other devices shouldn't be difficult.

    I made a write-up of what I learned, including surprisingly simple working code in this GitHub Gist.

  • Easy I2C with STM8 eForth

    Thomas12/03/2020 at 21:42 0 comments

    I had some fun experimenting with the STM8 I2C peripheral. Working around its quirks and designing a code efficient yet reliable and easy to use I2C driver was a challenge. In my previous log entry I mentioned improvements for mixing control structures with optimized assembler code in ISRs.

    After testing some alternatives I ended up with a very simple approach:

    • Device initialization and buffer definition in user code in user code
    • An ISR with a simple API
      • variable I2ISR as configuration "registers" for the ISR
      • I2S ( c -- ) start I2C transmission sequence with device address c
      • I2W ( -- ) wait for end of transmission (optional)

    The ISR is now really easy to use. Here is the code for a 24C64 EEPROM:

    \res MCU: STM8S103
    \ Initialization code, e.g. for 100kBit
    #require I2I
    \ ISR based I2C "Master transmitter/receiver"
    #require I2CMA
    \ temporary constants for the I2C user code
    I2ISR 2 + CONSTANT TCOUNT  \ char number of bytes TX
    I2ISR 3 + CONSTANT RCOUNT  \ char number of bytes RX
    I2ISR 4 + CONSTANT TPOINT  \ points to TX buffer, starting with CMD/ADDR
    I2ISR 6 + CONSTANT RPOINT  \ points to RX buffr
    80 CONSTANT SA24C64
    : write ( a c -- )
      \  BUFFER follows EADDR, c=0 at least writes the address
      ( c ) 2+ TCOUNT C!   \ TCOUNT, # bytes incl. EADDR
      ( a ) EADDR !        \ set EEPROM address
      EADDR TPOINT !       \ initialize transfer pointer
      SA24C64 I2S
    : read ( a c -- )
      BUFFER RPOINT !      \ set read pointer to buffer
      ( c ) RCOUNT C!      \ RCOUNT
      ( a ) 0 write        \ zero-write sets EADDR and starts the read sequence
    \\ Example
    $AA55 BUFFER !
    $0011 2 write
    $0011 2 read

    The ISR deals with the different even sequences in the reference manual and it also catches errors.

    Using the error event writing a simple I2C scanner is very easy:

    \res MCU: STM8S103
    \ Initialization code, e.g. for 100kBit
    #require I2I
    \ ISR based I2C "Master transmitter/receiver"
    #require I2ISR
    : scan ( -- )
      127 FOR 
        I 16 MOD 15 = IF CR THEN 
        I2S I2W  \ send address and wait for ACK/NACK
        I2ISR @ 0< IF ."  --" ELSE I . THEN  
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 80
     79 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ok

    A negative value in I2ISR indicates that there was a transmission error (the MSB also contains the error event flags). In the listing above shows replies from a DS1621 at A2:0=7 (79) and from a 24C64 EEPROM at A2:0=0 (80).

    I also wrote test code for the DS1621 temperature sensor (which has a 8 bit command instead of the 16 bit address in the case of the EEPROM) which was just a few lines of code. Accessing any 7bit I2C device should be really easy now.

    Edit: @Eelco did some serious testing with the well known SSD1306 128x64 OLED display.  After discussing a slightly more involved API (extra command interface) it was decided to keep the original simple API. Working code for the SSD1306 is in this GitHub Gist comment.

  • IF .. ELSE .. THEN with Relative Addressing - Changing the Compiler during Compilation

    Thomas11/26/2020 at 06:32 0 comments

    When implementing a driver for the STM8 I2C peripheral I needed BTJx and JREQ branches in Forth code. This wasn't the first time I did that and I had prepared some code to calculated and fix the relative address at the target "label". When I also needed an ELSE block it struck me that this had been solved before - in IF ... ELSE ... THEN.

    Here is the code:

    \ STM8eForth : control structures with relative addressing         TG9541-201124
    \ ------------------------------------------------------------------------------
    #require >Y
    : >REL ( -- ) HERE 0 C, ;  \ like >MARK for rel. branch
    : ELSE ( -- )  [COMPILE] [ $20 C, [COMPILE] ] >REL   \ JRA rel
    : JREQ ( F:Z -- ) [COMPILE] [ $27 C, [COMPILE] ] >REL ; IMMEDIATE

    After loading this redefinition of IF .. ELSE .. THEN to RAM, Forth code can be written just like before. When it's no longer needed the temporary compiler change can be discarded and the code using relative addressing remains valid.

    The real difference is that now machine code for branch instructions can be used that work like the library words ]C! or ]B!:

    #require >REL
    : ]B@IF ( -- ) 2* $7201 + , , ] >REL ;  \ BTJF  a,#bit,rel
    : ]@IF  ( -- ) $90CE , , ( LDW Y,a ) ] [COMPILE] JREQ ;
    : testb  [ vt 1 ]B@IF ."  set" ELSE ."  not set" THEN ;
    : testNZ [ vt ]@IF ."  not " THEN ."  zero" ;

    The word ]B@IF compiles to "BTJF addr,#bit,rel" and ]@IF compiles to  "LDW Y,#n  JREQ rel".

    I plan to add these words and others like ]C@IF (LD A,addr  JREQ rel) or ]A<IF (CP A,#c JRPL rel) to the library that directly load >REL.

  • STM8L051F3: Experimenting with LSE, BEEP and RTC

    Thomas10/29/2020 at 08:38 0 comments

    I made a write-up about my experiments the STM8L LSE (Low Speed External) oscillator that uses a 32.768kHz crystal to clock peripherals like the RTC.

    For my experiments I used the nrf24stm8l board that I made some time ago but a chip on a standard "green TSSOP20 breakout PCB" for $0.10 with a crystal soldered to pins 1 and 2 also works (caps were not needed when I tried it):

    The write-up gets started with the LSE and the beeper peripheral. Using the beeper is a good test for a crystal oscillator since one can hear the crystal start up! The next experiment introduces the RTC peripheral with a basic example for configuration, initialization and use.

  • A debug console in 4 lines of code

    Thomas10/25/2020 at 08:23 0 comments

    A Forth system on a $0.20 MCU like the STM8S003F3 with 8K ROM and 1K RAM can offer surprising advantages. Based on an idea I found in the ROBOFORTH II tutorial I added of just 4 lines to the latest STM8 eForth release to provide a very simple debug console that allows examining the state of a Forth program in the middle of the execution

    Here is a simple example:

    #require BYE
    : test ( n -- )
        I DUP . 2 MOD 0= IF
          CR ."  Break - mind the stack - continue with BYE" CR
          OUTER THEN
      NEXT ."  done"

    A debug session on a STM8S003F3, where a "FOR ... NEXT" loop is terminated manually by changing the loop counter on the return stack ($3FF growing down), may look like this:

    66 7 test 7 6
     Break - mind the stack - continue with BYE
    $03F0 10 dump
     3F0  23  0  0  A 8D 1E 8D 12  1 1D  0  6 8D 1E 8D 12  1_______________ ok
    bye 5 4      
     Break - mind the stack - continue with BYE
    $03F0 10 dump
     3F0  23  0  0  A 8D 1E 8D 12  1 1D  0  4 8D 1E 8D 12  1_______________ ok
    $3FA ? 4 ok
    0 $3FA ! ok  
    bye done ok
    . 66 ok

    Note that a single misspelled word will clear both the data and the return stacks. This will not only reset the console but it will terminate the program and typing BYE in this situation will crash the system! There is clearly room for improvement in the implementation of the library word BYE here.

    Edit: here is an improved version of BYE, one that will show a more friendly behavior:

    #require OUTER
    : BYE ( -- ) [
      \ exit the interpreter on the condition that OUTER was called
      $1605 ,           \ LDW Y,(5,SP)
      $905A ,           \ DECW Y
      $905A ,           \ DECW Y
      $90FE ,           \ LDW  Y,(Y)
      $90A3 , ' OUTER , \ CPW Y,#OUTER
      $2604 ,           \ JRNE +4
      $9085 ,           \ POPW Y
      $9085 ,           \ POPW Y

  • STM8 eForth 2.2.26: The STM8L Release

    Thomas10/24/2020 at 09:26 0 comments

    I released STM8 eForth 2.2.26 that adds support for all STM8S "Mainstream" and STM8L "Low Power" devices, at least that's what I assume.

    No, I didn't test all the 40 STM8S variants, 37 STM8L variants and none of the 47 STM8AF or STM8AL variants listed here. Instead I looked for evidence what's really the difference between all those devices and thus identified two-and-a-half families (STM8S, STM8L and RM0013-STM8L) with "Low", "Medium" and "High density" devices - and that amounts to just 7 STM8 configurations. The rest is specs and marketing "Product Lines". 

    Read more about this in the STM8 eForth 2.2.26 Release Notes!

  • A new STM8 eForth pre-release 2.2.26.pr3 is available

    Thomas09/27/2020 at 12:49 0 comments

    The goal of this release to improve STM8L, and to support all STM8L devices, is getting closer.

    I could need some help with testing support for STM8L High Density devices: there is test code in the repository but I don't have a board (yet). 

    So, if you have a NUCLEO-8L152R8 or a similar board with an STM8L High Density chip (e.g. the STM8L152R8 or a also a similar STM8L Medium+ Density chip) I'd be happy to hear from you.

    The GitHub issue is here.

  • OpenOCD config files for STM8L Low Density Devices

    Thomas09/25/2020 at 05:32 0 comments

    For RM0031 STM8L Low Density devices (e.g. STM8L051F3 or STM8L050J3) I'm using the following OpenOCD target configuration:

    #config script for STM8L051
    set FLASHEND 0x9FFF
    set BLOCKSIZE 0x40
    set EEPROMSTART 0x1000
    set EEPROMEND 0x10ff
    proc stm8_reset_rop {} {
       mwb 0x4800 0xaa
       mwb 0x4800 0xaa
       reset halt
    source [find target/stm8l.cfg]

    For STM8L101 family devices (i.e. STM8L101F3 or STM8L001J3) the following configuration works for me:

    #config script for STM8L101
    set FLASHEND 0x9FFF
    set BLOCKSIZE 0x40
    proc stm8_reset_rop {} {
       mwb 0x4800 0x00
       reset halt
    source [find target/stm8l.cfg]

     I didn't bother about the EEPROM because for all practical purposes the memory blocks designated as "DATA EEPROM" behave like Flash ROM.

    My OpenOCD version is "Open On-Chip Debugger 0.10.0+dev-01404-g3934483-dirty". Using OpenOCD I could reset chips such that they consequently worked with STM8FLASH.

View all 165 project logs

  • 1
    Step 1

    Get some cheap hardware (e.g. a STM8S103F3P6 breakout board for $0.65 and a ST-Link V2 dongle for $2). download the binary release, flash it, and have fun!

    If you like it, and you want to hack board support code for your favorite STM8China gadget, you need:

  • 2
    Step 2

    a Linux SDCC tool chain installation (installation instructions for SDCC & stm8flash are in the Wiki)

  • 3
    Step 3

    Clone the project on GitHub

View all 4 instructions

Enjoy this project?



Elliot Williams wrote 12/22/2020 at 21:36 point

I haven't been active in this project since forever, but I should touch base and say that it rocks!  

My washer-dryer power monitor project on the ESP14 ( is still chunking along after all these years.  

I logged into it last week, tweaked a couple things to reflect changes in our home automation system, and logged back out.  It was easy and painless. 

Having a shell on a remote micorcontroller-based system (over WiFi / telnet no less) is absolutely marvelous. 

Thanks again, Thomas.  I'm stoked to see this project continuing to thrive!

  Are you sure? yes | no

Thomas wrote 12/23/2020 at 12:52 point

Hi @Elliot Williams  - nice hearing from you!

To tell the truth, your initial coverage in HaD, e.g. the ESP14 washer-dryer project, and some of your early feature requests contributed a lot to the good fortune of STM8 eForth!

After all these years, and after the arrival of the Nuvoton N76E003 that made initial hacks simple, working on this small Forth is still a good hobby.

If I've learned one thing in the last 4 years then it's that finding a balance between simplicity and accessibility to new users has to be balanced with features, bells and whistles. The most powerful system that's off the trodden path has no chance at all if it's not super accessible and appears to be dead simple.

So, how should the docs be structured that experienced users find what they need without asking too much from new users?  Which channels for making it project known look promising? How to measure that?

The best help I've got, though has always been from the community - and there's been quite some exchange going on in the background :-)

  Are you sure? yes | no

Ken Yap wrote 05/17/2020 at 03:15 point

For what it's worth, I've contributed a wizard to the code::blocks IDE to handle stm8 projects for people who like IDEs. I still do a lot with a text editor and Makefiles.

At the moment you have to install it yourself in your C::B wizard directory, but hopefully some C::B developer will adopt it for a future release. They invited me to submit a patch, but I didn't want to download the whole SVN tree or get involved in C::B development. So many interesting projects, so little time.

C::B is:

  Are you sure? yes | no

Thomas wrote 05/17/2020 at 05:53 point

Hi Ken, thanks! I had a look at code::blocks - I loved using SVN and I still miss the clarity and ease-of-use it provides for centrally hosting repositories. Collaboration and integration in a community is a different beast, though and I wouldn't want to go back :-)

For the code::blocks IDE some OS/desktop environments appear to be more equal than others (e.g. TurtoiseSVN integration). It might be interesting if a Forth terminal or a ST-LINK debug interface can be integrated. I didn't find anything on "tethered development". How do you use it for µCs like the STM8?

  Are you sure? yes | no

Ken Yap wrote 05/17/2020 at 06:04 point

At the moment the only integration I have is a Makefile rule to call stmflash.  😁 It's a weak point of the OSS stm8 tools that there isn't a debugger or simulator or ICE. Perhaps an onboard stmforth monitor can be part of the solution?

  Are you sure? yes | no

Thomas wrote 05/17/2020 at 15:52 point

As far as I know no-support is a thing of the past. I've never tried it (since I have Forth as a "monitor" and uCsim for the rare cases when it really got difficult).

You're right, using Forth as a driver for unit testing C routines can be useful. So far, however, I didn't have an STM8 application that would have required using C...

  Are you sure? yes | no

Ken Yap wrote 05/17/2020 at 23:09 point

C::B is supposed to support gdb but I haven't got around to trying that. I just noted a couple of days back that there wasn't a wizard to start stm8 projects and whipped up one by hacking the mcs51 one. My next stm8 project is still on my ever expanding queue. I ought to finish a few projects before I add new ones. The C::B wizard was a quick hack so I couldn't resist.

  Are you sure? yes | no

marian2002go wrote 05/12/2020 at 01:42 point

Hi, Thomas! Do you think it's possible to program the W1209 thermostat to have the following values hard coded:

1. Heater mode

2. Trigger offset 1°C

3. Minimum temperature 15°C

4. Maximum temperature 35°C

When the SET button gets pushed, the current set temperature will start blinking. Adjusting the preferred temperature using + and - buttons. When the SET button gets pushed the second time, the value gets saved.

Please let me know if this would be possible to achieve and if you are interested in helping me. If yes, we'll speak about the costs in private. Thank you! Dumitru

  Are you sure? yes | no

mikael_lundgren_ak wrote 07/01/2018 at 17:21 point

Thanks for your good answer. 

For beginers a well dokumentet memory map for ram flash and eeprom if used for dichenary would be helpful. also a map of how dichenary entries are saved in ram ore flash. i have read the eforth dokumentation but i still is not totaly clear to me. wbr Mikael.

  Are you sure? yes | no

Thomas wrote 07/01/2018 at 17:53 point

Hi Mikael,

did you check the (rather lengthy) explanation in the Wiki?

The STM8 eForth method is rather unique (at least that's what seasoned Forthers say), but it's also robust and, due to ALIAS words, even the EEPROM can be used to increase the available dictionary space.

Have a look at this page:

Besides NVM and RAM there is a number of helper words, e.g. WIPE, PERSIST, :NVM, or EEALIAS. Please have a look at the example code in the lib/ folder.

  Are you sure? yes | no

mikael_lundgren_ak wrote 06/18/2018 at 07:28 point

how can I check all the different usage of memory; flash ram dictionary space user variable space etc. I would like to monitor the memory space automaticly used by the forth vm to understand more and know when i have consumed some area of memory. wbr mikael.

  Are you sure? yes | no

Thomas wrote 06/18/2018 at 21:17 point

Check this out:

 To check the free flash area I always use "NVM $A000 here - . RAM"

FYI: WIPE removes the dictionary entries in RAM, and, after defining variables in NVM mode, also moves up the dictionary start in RAM.

Regards, Thomas

  Are you sure? yes | no

mikael_lundgren_ak wrote 04/10/2018 at 13:57 point

Thanks for a good and fast answer, now I have som nice testing to do.

  Are you sure? yes | no

mikael_lundgren_ak wrote 04/09/2018 at 13:42 point

Hi Thomas 

I have been playing with your fantastic eforth now for a while and must say it is both extremly fanny/addictive yet powerful. For me the whole forth concept was new but quickly i got to like the speed of testing and clean way of writing the code. So thank you. I have som questions: for the real beginners more example code with comment would be great specially for using hardware like spi i2c timmers and more. If I build a program but then realize that one of my earliest building words need to be altered, how can i manage this? Is it possible to edit a word by decompiling with SEE and then edit and recompiling ? wbr Mikael

  Are you sure? yes | no

Thomas wrote 04/09/2018 at 18:45 point

Hi Mikael,

it's great to hear that you have fun with STM8 eForth!

Here is a (certainly incomplete) list of example code:

If you need to recompile a word at the base of your dictionary, the Forth development cycle usually requires re-compiling code from the source. Since the source code in most cases isn't stored on the µC, tools like e4thcom, Manfred Marlow's nifty Forth terminal, or, can be used to upload code efficiently (take note of the #include, #require, and \res statements in the examples). It's also possible to change existing code in-place, e.g. by replacing the code of an existing word with a JP to a new word (this has a twist due to the STM8 eForth ALIAS feature!). For a rather elaborate example check out the lib/CURRENT and lib/VOC implementations.

The STM8 eForth core consists of optimized assembly code (even the compiler does some optimizations), and therefore a simple SEE implementation will fail. In order to understand the core it's easiest to compare it with the code in Dr. C.H. Ting's "eForth Overview",

Best Regards

  Are you sure? yes | no

BigVulcanDeal wrote 02/03/2018 at 13:23 point

'You haven't lived until this thing has thrown a 8" pair of vise-grips at you'

It seems the controller for many of the Harbor Freight cordless tools uses an STM8 mcu of some sort.


  Are you sure? yes | no

Thomas wrote 02/03/2018 at 15:09 point

STM8S are used frequently, but I'd like to see some evidence before I buy that it's "likely a genericized or pin-and-code compatible version available on the Chinese market".
The Meloncraft, however, isn't half bad.

  Are you sure? yes | no

Eelco wrote 01/24/2018 at 22:47 point

Hi Thomas

I am having an issue with MARKER. Compilation stops when I call a word that is defined just before in the same file. If I use MARKER from version 2.2.19 it works fine. Did I miss something, once again?

  Are you sure? yes | no

Thomas wrote 01/25/2018 at 03:25 point

Hi Eelco, could you please let me know the version or git hash you're using? Also please provide a code example, e.g. in a GitHub Gist or even better, as an Issue :-)

  Are you sure? yes | no

Thomas wrote 01/25/2018 at 06:27 point

On a second thought... could it be that you ran out of RAM? The available RAM didn't change much since 2.2.19 but its usage by library words might have changed.

  Are you sure? yes | no

Eelco wrote 01/25/2018 at 08:31 point

OK, I found what I was doing wrong: I forgot to define a dummy word before calling MARKER. In version 2.2.18 ( I mentioned 2.2.19 but that should be 2.2.18, I skipped 2.2.19) this was done when you uploaded MARKER, in version 2.2.20 you must do it yourself.

My apologies.

  Are you sure? yes | no

Thomas wrote 01/26/2018 at 05:40 point

No need to apologize, I still take the blame!
MARKER needs at least one word definition in RAM to operate, and that's not obvious. I'm rarely ever confronted to that because of the "#include STARTTEMP ... TARGET ... ENDTEMP"  template I apply. In my main.fs, TARGET is usually defined as ": TARGET NVM ;"  before STARTEMP in the first module even issues "#require MARKER" ( ).
Maybe I should  re-introduce a dummy word in MARKER. 

  Are you sure? yes | no

Eelco wrote 11/18/2017 at 14:09 point

Hi Thomas

I am encountering strange behavior when allocating ram to variable arrays.

e.g.  NVM variable qqq variable zzz RAM

qqq $20 allot drop

zzz $20 allot drop

qqq $20 $AA fill

zzz $20 $BB fill

qqq $40 dump

  80  AA AA BB BB BB BB BB BB BB BB BB BB BB BB BB BB  ________________
  90  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  ________________
  A0  BB BB  0  0  0  0  5 61 6C 6C 6F 74  0  0  0  0  _______allot____
  B0   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ________________ ok

It seems the second array is using the same space as the first one.

I am trying to communicate with sdhc cards FAT32 file systems in SPI mode. Using one array for 512 byte data buffer works great but now I try to define a second array as a filename buffer and I run into this problem. Do you have a solution? Btw I tried with the latest version, 2.2.20.

  Are you sure? yes | no

Thomas wrote 11/18/2017 at 15:48 point

Hi Eelco,

there are two issues with your code:

One is related to how VARIABLE works in NVM mode: memory is allocated from a small pool (just 32 bytes) which is reserved during COLD. The implementation is described here: [ ]. Of course you can allocate more memory than there is in the pool, but then you'll have to cycle through cold before using it.

The second is a "Forth thing". You'll have to allocate memory directly after defining the variable. Of course it's possible to create a malloc()-like device, but variables are static.

The following log shows the procedure:

STM8eForth 2.2.20
here . 160 ok
nvm variable qqq $1e allot ram ok
nvm variable zzz $1e allot ram ok
STM8eForth 2.2.20
here . 224 ok
qqq $20 $aa fill ok
zzz $20 $bb fill ok
qqq $30 dump    
  80  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ________________
  90  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ________________
  A0  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  ________________
  B0  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  ________________ ok

I assume that you use a low density device with just 1KiB RAM. You can try using the EEPROM for storing the second buffer - writing it is slow but for manipulating the FAT it might be sufficient.

  Are you sure? yes | no

Eelco wrote 11/18/2017 at 17:05 point

OK, thank you very much, this works. I will study the link again. I am using a board with stm8s103f, 1KiB ram indeed.

  Are you sure? yes | no

Roy wrote 11/17/2017 at 14:22 point

Just hooked up a MINDEV STM8S103 directly to an HC12 wireless serial communication module at 9600 baud and have 100% console eForth results over many hundreds of metres.

HC12      STM8S

TXD        RX  PD6

RXD        TX  PD5

  Are you sure? yes | no

Thomas wrote 11/17/2017 at 20:02 point

The HC12 is quite good! I experimented with running Forth on the STM8S003F3P6 that powers the HC12. Maybe I'll continue with it at the end of the year.

  Are you sure? yes | no

Roy wrote 11/12/2017 at 12:02 point

\ C0135 display data 4 bits and power relays with LED for HI nibble

\ 12 NOV 2017 RS
VARIABLE Startaddr

$1000 Var ! \ inner delay
$40 Varloop ! \ outer delay
$8090 Finaddr !
$8080 Startaddr !

: vardelay Varloop @ 0 DO Var @ 0 DO LOOP LOOP ;
: newflasher2
 Finaddr @
 Startaddr @ DUP addr !
  Addr @ DUP . C@ DUP . Byte ! CR
  Byte @ $F0 AND $10 / \ mask and rotate hi nibble
  $10 OR OUT! \ also turn on LED
  Byte @ $F AND OUT!
  Addr @ 1 + Addr !


8080 0
8081 0
8082 5A
8083 26
8084 F7
8085 CC
8086 80
8087 68
8088 CC
8089 80
808A EC
808B 5A
808C 5A
808D 1F
808E 3
808F 51

  Are you sure? yes | no

Thomas wrote 11/12/2017 at 18:31 point

Got one? A nice little board, isn't it?
Also have a look at this one:
I don't know why they call it "5 way relay time control panel" when it has 6 relays, but I ordered one yesterday. The 11.11 price was just $10.35 (€8.87, ₤7.85).

  Are you sure? yes | no

Eelco wrote 10/28/2017 at 14:19 point

Hi Thomas 

I am trying to use a timer interrupt similar to your description ( .

I think I had to rewrite IVEC!:    (: IVEC! 2* 2* $8008 +  ULOCK ! LOCKF ; )  to be able to write to the interrupt vector address. 

: timer_4_interrupt SAVEC 0 $5344 0 b! OUT! IRET ;    \ Simple interrupt routine.

' timer_4_interrupt 23 IVEC!    \ Link interrupt routine to IRQ23 (TIM4 update).

But as soon as an interrupt occurs the chip reboots. How should I proceed to use timer interrupts?

  Are you sure? yes | no

Thomas wrote 10/28/2017 at 18:31 point

Hi Eelco,

what a coincidence! I continued working on the interrupt features, and I also got reboots. I'm currently debugging, and as soon as I've figured out what goes wrong I'll let you know!


  Are you sure? yes | no

Thomas wrote 10/28/2017 at 19:53 point

OK, that was easy but I've got no idea why it ever worked. 

Here is the fix (a new pre-release will be out soonish):

;       SAVEC ( -- )
;       Minimal context switch for low level interrupt code
;       This should be the first word called in the interrupt handler

        POPW    Y
        LDW     X,YTEMP
        PUSHW   X
        LDW     X,#(ISPP)       ; init data stack for interrupt ISPP
        JP      (Y)

;       IRET ( -- )
;       Restore context and return from low level interrupt code
;       This should be the last word called in the interrupt handler

        POPW    X               ; discard CALL return address
        POPW    X
        LDW     YTEMP,X         ; restore context

Edit: the bug was even worse than I thought - the above code does the job.

By the way: you don't need ULOCKF / LOCKF if you set the interrupt vector in NVM mode. I'll also put the interrupt vector addresses into the STM8S103.efr file so that setting an interrupt works with a simple ! (store), and IVEC! is no longer needed.

  Are you sure? yes | no

Eelco wrote 10/29/2017 at 09:59 point

Hi Thomas

Wow, that was really fast. I should have asked you a week ago, would have saved me a lot of time.

I tried setting the interrupt vector in nvm mode but with 2.2.17 this forced the chip in a strange loop, even after a power cycle. I then had to reflash the mindev board. (I think I really need to get into assembly). 

Thank you very much for solving this issue.


  Are you sure? yes | no

Thomas wrote 10/29/2017 at 20:22 point

The bug clearly was on the silly side. Next time please drop me note when it looks like you're stuck :-)

  Are you sure? yes | no

Thomas wrote 10/28/2017 at 21:11 point

I updated the example code:

I used a headerless interrupt handler but with the patch above your code should now work as intended :-)

  Are you sure? yes | no

Thomas wrote 10/28/2017 at 22:08 point

  Are you sure? yes | no

Roy wrote 10/06/2017 at 09:31 point

Microchip produced a humorous self-critical video about the failings of the PICkit 3 vs the older 2. Perhaps ST Micro should be shamed to do the same with their products. I realise that this is off topic but still a good example of how not to do things and take ownership for getting it wrong. My ST Visual Programmer is 3.4.0 Jul 12 2017.

  Are you sure? yes | no

Roy wrote 10/04/2017 at 17:23 point

Having lived in Quebec a long time ago, there is a local swear word that sounds like ST. This is what I say every time I use ST software and hardware. STVP does not even show the latest factory ST-LINK/V2 as an option - 'ST-LINK All Versions' would be useful. The thing never connected as I tried a few times a year over many years. They do nothing to alert you that the target device needs external power. I always had clones that did the job so there was no great urgency to learn it.

Many (all?) of the cheaper USB - STM programming adaptors had figured this out a very long time ago. Even Microchip PICkit 2/3 monitors power on the target but gives the option to power their external devices.

Simply logging in to ST to get free software goes into an email / validation death spiral loop that is a complete waste of our valuable time. If the people of ST responsible for this nonsense worked for me, then they would be all unemployed.  


  Are you sure? yes | no

Eelco wrote 09/30/2017 at 16:11 point

Hi Thomas

I saw you solved the issue. Great! Thanks.

  Are you sure? yes | no

Eelco wrote 09/27/2017 at 18:13 point

Hi Thomas, I am enjoying your project for more then a year now. Today I joined hackaday to be able to participate. I bought a couple of W1209 and mindev boards to play with. I also have an ssd1306 i2c oled display (about $3 at Aliexpress). I managed to drive it using the i2c capabilities of the chip, no bit-banging. This was a few months ago, with version stm8ef-bin.2.2.8 and a MINDEV board. I used $" to compile the text to be send to the display (e.g. : txt $" text" ;) I upgraded to more recent versions, up to 2.2.16, but executing a word that contains $" freezes (or reinitilizes, as with COLD) the board. What am I doing wrong here? Do I have to raise a flag in Can you point me in the right direction?

Btw, I'm happy to share the code if anyone is interested.

  Are you sure? yes | no

Thomas wrote 09/28/2017 at 06:07 point

Hoi Eelco,

thanks for letting us know about your work! Your contribution in the I2C field would be very much appreciated!

Also thanks for reporting the issue with $": this is a regression. It's tracked here, and I'll fix it as soon as possible.

The root cause is insufficient testing. Some of the progress for building a test infrastructure is tracked here:

I would love to have you in the team at GitHub. I'm quite sure that the other team members would say the same.

Met friendelijke groeten,

  Are you sure? yes | no

Eelco wrote 09/28/2017 at 08:43 point

Hallo Thomas

Thank you for your kind reply and invitation, I would like to join. I have to warn you though that I have little coding experience but I am learning thanks to projects like yours. How do I proceed to upload the code?

I just saw you have a separate project with W1209 thermostat boards. I use two of such devices in my household: one as a replacement thermostat in a refrigarator. The other one in the boiler of the central heating unit. Maybe I can make small contributions on that project too.

mit freundlichen Grüßen


  Are you sure? yes | no

Thomas wrote 09/30/2017 at 12:20 point

Hi Eelco,

the only way to gain coding experience is coding. There is still a lot you can do, e.g. write tests (which improves coding skills significantly!), or write library code (e.g. I2C), or do a review (also a great way to learn), or spread the word... Please let us know your GitHub ID, and you'll receive an invite!

A warning about W1209 in safety critical applications:
* only use hobby stuff for adding features that aren't safety critical
* always rely on built-in safety features of the product
* make sure to get a review of your design from someone who knows safety

Creating a HaD-project is a great way to get feedback from experts!

  Are you sure? yes | no

richard wrote 10/05/2017 at 03:08 point

Hi Eelco,

I would welcome seeing your code. I'm likely to use i2c one day and your code will give me a head start.



  Are you sure? yes | no

Eelco wrote 10/05/2017 at 08:47 point

Hi Richard

Here is the link:

Please let me know if  you have recommendations for improvement.



  Are you sure? yes | no

richard wrote 10/05/2017 at 15:04 point

Hi Eelco,

thanks for the code below. Already I have learned about the B! word from reviewing your code. That's going to help me enormously with my W1209 project where I want to turn an input port into an output port for some of the time.

You've done a much better job than I would have. Thanks again


  Are you sure? yes | no

Eelco wrote 10/05/2017 at 21:59 point

Hi Richard

You're welcome, I am glad it is of use to you. I uploaded another file on my github account with io-manipulating words: io.fs. These words use a numbering of the gpio-portpins. The word io. displays the state of the IDR,ODR,DDR,CR1 and CR2 for a portpin. (e.g. $15 io.  displays these bit states for the  second port (Port B), pin 5. Maybe useful for you as well.

  Are you sure? yes | no

Peter wrote 08/21/2017 at 14:11 point

I'm a newbie and have implemented eForth on a STM8S103F3. While I have successfully implemented the "mystart" boot example which remains in NVM  following a power reset, I just can't seem to get any other created word to be available. Could I have some guidance please? 

  Are you sure? yes | no

Thomas wrote 09/24/2017 at 07:24 point

Hi @Peter, sorry, I noticed your message just now, which is very unfortunate. Yesterday I independently found the problem you were facing. The problem, which existed since 5/August/2017, has been fixed. A new binary release is being prepared.

  Are you sure? yes | no

Thomas wrote 09/24/2017 at 08:38 point

I just released v2.2.16 to fix this issue.

  Are you sure? yes | no

Peter wrote 09/25/2017 at 20:56 point

Hi Thomas. On my second MinDev I was able to re-programme it using STVP ID 3.4.0. However as it says "stm8eForth v2.2" which is identical to other boards, how do I distinguish it elegantly via communication? Incidentally the first board which has been running a blink programme as an endless loop on "problem 2.2.13" refuses to re-programme via SWIM reporting not blank though ROP is off. Any suggestions on recovering it?

  Are you sure? yes | no

Thomas wrote 09/29/2017 at 18:06 point

Hi Peter,
you have a point there.  @barewires already filed an issue. I'll be looking into it!

  Are you sure? yes | no

Peter wrote 10/13/2017 at 13:50 point

Hi Thomas, small update to follow. I don't know whether it's my ignorance but I was expecting to be able to reply as another indent to your reply 09/29/2017 at 18:06 but replying via 09/24/2017 at 07:24.

  Are you sure? yes | no

Peter wrote 10/13/2017 at 14:28 point

To cover my experience described earlier I'll split it into two responses in case anybody wants to work on that part of it. I have not been doing any compiling but just running STVP in windows burning IHX files as required. Any compiling I'm likely to do will be in Windows as I've found setting up a Linux similar to what I use a challenge (...ST). Zorin I'd suggest is a better start that many.

I solved how to re-programme a stubborn STM8S103F3P6 mentioned by specifically selecting the Option Byte window tab and then using Program > Current Tab.  Then I was able to program as I normally do so by using Program > All tabs.  Possibly a glitch but nothing else worked.

  Are you sure? yes | no

Peter wrote 10/13/2017 at 17:59 point

To distinguish between the different versions of 2.2.xx appearing as v2.2 I've started to modify the IHX file so that the same 4 bytes now display 2v17 for example. I'll explain the procedure for newbies like me used to Windows.

1. Copy the IHX file and rename including the version and change the file type to HEX. e.g. C0135.IHX becomes C0135-2v17.HEX.

2. Open the file using STVP and choose the Program Memory tab to display both the hexadecimal and ascii contents.

3. Go to around line 000081E0 and you should see in the ascii columns on the right  stm8 eForth v2.2. Put the cusor on the v and update. The hexadecimal will change.

4. Save

Now on STVP default settings the files are easily accessible. For me the approach above is easier than directly locating the file with STVP and using the Save As to create the HEX copy. 

  Are you sure? yes | no

Thomas wrote 10/13/2017 at 20:25 point

Hi Peter, thanks for updating on the Windows tools!

I'm currently working on `` - it should mirror the properties of e4thcom (require, \ res, \\ Example). Maybe the same is achievable on Windows with ``.

  Are you sure? yes | no

jeff1937 wrote 07/29/2017 at 07:38 point

Just wondering does anyone know if it could it be possible to read the temperature of a W1209 via wire serial communication ?

In other words I just want to log the temperature to a computer, but still leave the W1209 to function as a thermostat.

  Are you sure? yes | no

Thomas wrote 08/05/2017 at 13:08 point

Yes, that's possible. The steps are as follows:

1. determine the R_ntc to voltage function (e.g. using a trimmer and an unmodified W1209, 5 values, e.g. 0 deg C, 80 deg C, and 3 values around (and including) the temperature you care most about)

2. flash W1209-FD from the v2.2.13 release

3. determine the ADC6 values for relevant R_ntc from 1.

4. create an interpolation function from 3.

5. write a simple background task that does thermostat control by reading ADC6 and using 4.

6. read the temperature value from 5. using console commands from your computer. Alternatively send the values in the background task

If you describe your use case more precisely, I can write something to get you started

  Are you sure? yes | no

jeff1937 wrote 08/06/2017 at 00:47 point

Thanks Thomas for the helpful reply.

My applications are to turn off a immersion heating element in a cooking pot when the water reaches near to boiling and secondly to operate a fan in a solar dryer at a temperature around 100C, with computer logging every 10 minutes or so.

Thanks for your kind offer of assistance, but I will try to get some unmodified W1209s operating in a circuit, just to get started first.

If I was able to reflash them, I would hope to retain the 3 digit temperature display.  Which sounds easy as you say they are fully supported by STM8EF vectored I/O.

I guess the key pins don't operate when they are used for serial connection, which is OK because the temperature points could be hard coded in software.

  Are you sure? yes | no

Thomas wrote 08/06/2017 at 05:07 point

Jeff1937, thanks for the info! How do you think about making a small project out of this? I've got a feeling that quite some people would be interested in using this :-)

Know what, I've got a couple of spare W1209 boards here. I'll start a new project, and invite you as a team member. Does this sound good?

  Are you sure? yes | no

jeff1937 wrote 08/06/2017 at 06:54 point

Also was thinking that you could use a datasheet for an NTC 10K.

It shows a resistance table between -55 to 125°C.

eg 25°C = 10,000Ω, 80°C = 1,068Ω,  100°C = 549Ω

Then calculate the theoretical voltage at PD6 with a 20k pull-up to 5V.

This would need a later calibration correction adjustment, but should give a good starting point.

  Are you sure? yes | no

jeff1937 wrote 08/06/2017 at 06:59 point

Yes I would like to have a go at making this a project, or helping.

My W1209 boards haven't arrived yet, but there's plenty to learn in the meantime.

  Are you sure? yes | no

Thomas wrote 08/06/2017 at 07:02 point

Good idea, at least to validate the temperature readings we get.

By the way, I started a HaD project for this. Let's continue with our discussion there!

  Are you sure? yes | no

Thomas wrote 08/06/2017 at 07:16 point

Ok, great! Get's let started. Please visit the project page, and "Follow" the project to get a notification when there is something new.

There is a first project log, where you can add comments. I also added a GitHub project for code and docs.

See you there!

  Are you sure? yes | no

jeff1937 wrote 08/06/2017 at 08:02 point

OK, will follow you there, thanks Thomas

  Are you sure? yes | no

richard wrote 07/22/2017 at 02:02 point

My first attempt at using a W1209 board has been very rewarding. A couple of suggestions for anyone starting out and for the project team:


1. I had no success flashing the board with the suggested ST software on  You may also consider the ST software used by the person who published the schematic of the W1209. It can be found at


2. When putting the header on for the SWIM connector use 5 pins instead of 4. The 5th pin is a convenient place to tie one end of the diode to for the half duplex link.


3. While the SWIMCOM binary may work on the W1209 board, for the newcomer there is a lot of reward in seeing the "4th" string on the LED display once the binary is flashed. With that feedback you know it is just a matter of getting the serial comms to work.


4. With the extra pin the SWIM connection would be a much better place to have half duplex communications. It would prevent the serial communication from disrupting measurements on the sensor pin while debugging and gives you a pin that your push on connector holds better.


5. Is there a place to share code snippets? For instance, I wanted to blank the display before sending another character to it. I used

 : Clrdisplay \ clear anything showing

        32 E7S 32 E7S 32 E7S ;


I also wanted a delay between displaying “On” and “Off”. I used the following but I suspect there is an easier way:


variable bigtimer


: tSet TIM 1000 + timer ! ;

: tTest TIM timer @ - 0 < ;

: delayInner tSet begin ttest until ;

: delay 0 bigtimer ! begin delayInner 1 bigtimer +! 25000 bigtimer @ - 0 < until ;


If there was a way to share these snippets it may prove useful to the newcomer. Maybe I just don’t understand the features of github well enough *grin*.


Anyway, I can recommend this forth implementation to anyone looking to hack one of these boards. I’m having a blast . I only wish I had found about this project before I built my electric gate controller with an atmel avr chip programmed in assembly. I could have just brought a cheap relay board and achieved the same thing without having to fabricate a board, populate it then program it in assembly.


Keep up the great work team.


Kind regards


  Are you sure? yes | no

Thomas wrote 07/22/2017 at 08:49 point

Hello Richard, thanks for your comment, it's higly appreciated!
Here are a few pointers to related actions, some new, some in the making.

1: the Wiki is updated

2, 3, 4: using a 5-pin header and a diode is a good idea! I'm currently experimenting with using the W1209 key GPIOs (PC4, PC5) for full-duplex communication, which has several advantages. What do you think?

The usability of STM8EF programming is currently under active development.   Especially a. and b. should be helpful for new users:

  a. improved full-duplex serial code, e.g. for W1209
  b. e4thcom support with libraries
  c. temporay "scaffolding" code in RAM
  d. board hex file generation in uCsim

5: I created a GitHub Gist with your code snippets - let's see if that works as advertised: 

I created an issue on GitHub
It would be great if you could contribute to  taking the decisions for a better W1209 support. Also feel free to open an issue on GitHub for topic oriented discussion.

Thanks again for your contribution.

  Are you sure? yes | no

richard wrote 07/22/2017 at 10:04 point


great stuff. I've been at it all day so real life drags me away for now. I don't have much to contribute on full or half duplex serial. I used Teraterm and slowed it down (25ms each character, 500ms for each line return) so the compiling could keep up. I was happy with that.

The Github Gist is interesting. Over time it could be really useful. Perhaps the main Github wiki needs to alert readers to it's existence?

I'm happy to help out with the W1209 where I can. You've no doubt heard of the saying "the blind leading the blind". 

The W1209 is a great platform and it is very exciting to think that much of what I used F-PC for years ago I could do on something costing so little. I plan to contribute as much as I can. 



  Are you sure? yes | no

Thomas wrote 07/22/2017 at 12:59 point


the voice of users is important, especially in a hobby project where there is no such thing as "market research" - users know very well what makes a product  useful for them. One I'd like to figure out is if connecting a serial interface to the keys "+" and "-" is acceptable (the keys will remain usable), at last during interactive programming. The other thing is whether support for "sensor header COM" needs to be maintained, or if I can simply replace it with something better :-)

  Are you sure? yes | no

Thomas wrote 07/22/2017 at 17:06 point

FYI: issue #41 is closed (which means that full duplex communication now works without character delays). I'll make a pre-release.

EDIT: please check the project log

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates