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 ...

  • We're at STM8 eForth 2.2.28 now ... :-)

    Thomas3 days ago 0 comments

    With release STM8 eForth 2.2.28 this "Small Forth" is more "Forth-Standard" leaning. One notable change is the usage of the POSTPONE method instead of COMPILE and [COMPILE]. In fact, the new method for extending the Forth compiler is not only more elegant, it's also more code efficient. The words DEFER ... IS were added - these words facilitate an interactive stile of top-down programming. 

    Since this is an embedded Forth for small µCs full standard compliance will be out of reach unless there is a standard for implementations that keep their dictionary in an executable ROM. Where code size or speed is concerned compatibility will always be an option to facilitate porting code. A good example is using 1-Wire code for DS18B20 that Brad Rodriguez wrote for CamelForth.

    There is an open issue that collects small Forth-Standard compatibility additions.

    So far we're here:

    One notable difference will be "pictured number output": Forth Standard compliance requires # ( ud -- ud) instead of # ( u -- u) (double instead of single math). Although this increases the code size only marginally it makes printing numbers in a background process slower. Instead there will be a change in the upcoming release 2.2.29 that speeds up printing numbers (by a factor of 2.5 to 7). Words for dealing with double numbers will be added as an option.

    Another notable change is a re-write of CREATE ... DOES> that makes using this key feature both code efficient and fast.

  • STM8 eForth 2.2.27 released

    Thomas03/15/2021 at 18:51 0 comments

    Last week I released the 27th release of the this Small Forth for simple µCs (by today's standards - what's "simple" today would have been the stuff of dreams in the 1990s).

    STM8 eForth 2.2.27 contains nifty features, e.g. an easy to use "compiler overlay" for structure words (e.g. IF ... ELSE ... THEN) with relative branches. This is useful for e.g. for the ISR programming or for relocatable code. Mixing Forth code with assembler instructions is now an really easy thing to do.

    That 40 years old bug in UM/MOD I wrote about the other day: it's been fixed now, but it almost deserves a place in a museum of computer history!

  • Using the 1-Wire Thermometer Chip DS18B20 with STM8 eForth

    Thomas03/04/2021 at 20:12 0 comments

    I was asked whether STM8 eForth can support Brad Rodriguez 1-Wire code which was written for the MSP430 and I had a look into it. After familiarizing myself with the time-honored 1-Wire protocol (which I read for the first time at least 20 years ago) I quickly hacked some low-level routines:

    That's indeed all that's needed for basic operations.

    Brad Rodriguez, a well known name in the Forth scene, did some more than that: he also implemented the ROMSEARCH algorithm, needed for getting all devices on a bus. The code is part of his CamelForth repository.

    CamelForth code looks very similar to eForth code (indeed I just had to provide INVERT as an "alias" of NOT, and implement a few words like LSHIFT. 

    A write-up is here:

  • A big fat bug in double/word division... lingering in the code for nearly 10 years!

    Thomas02/09/2021 at 17:31 0 comments

    What happens when a user tells you about a bug in a completely inconspicuous part of a software, one that you never touched and that you'd thought of as reliable since you'd been working with the software? It happened to me last week, and disbelieve was naturally my first reaction but the problem in UM/MOD, the "32/16bit-division-with-remainder" was real!

    The same user quickly found a bug and provided a fix. I then informed the owner of another project, that started off of Dr. Ting's "STM8EF for the STM8S Discovery", also had never noticed any problem although he had identified and fixed another unrelated bug in UM/MOD!

    What started then was a thorough analysis of the code, which unearthed yet another bug related to an edge case. Automated testing with a Python script makes more bugs in that code very unlikely.

    The moral is this: bugs happen, and they can be very well hidden under other layers of code that "rescues" the expected behavior but open source software not only leads to much better testing for unexpected things but it can also make skilled teams appear out of thin air!

  • New e4thcom features (matched by

    Thomas01/24/2021 at 21:48 0 comments

    Manfred Mahlow published version 0.8.5 of the embedded Forth terminal and programming tool e4thcom which introduces the source file level keywords #ifdef <name> and #ifndef <name>: they make e4thcom check if <name> is defined in the target dictionary and transfer the rest of the line on that condition

    The following example shows the source level keywords supported by e4thcom and :

    #include hw/pd8544.fs \ unconditional uploading
    #require ALIAS \ conditional uploading if the word ALIAS isn't in the dictionary
    \res MCU: STM8S103  \ use the STM8S103.efr symbol/address file
    \ get GPIO registers addresses, insert definitions like `hex 5000 CONSTANT PA_ODR`
    \res export PA_ODR PA_IDR PA_DDR PA_CR1 PA_CR2
    #ifndef OUT! \res export PB_ODR
    #ifndef OUT! : OUT! ( f -- ) PB_ODR 4 B! ;
    \\ ignore the rest
     of the file

    This feature is useful for testing target properties while sending code to the target. Writing device independent low-level code is among possible use cases.

    The in the STM8 eForth tools folder, very useful for transferring code to the target from the command line, now also supports this feature. There are some more improvements, e.g. better newline handling, better error messages and support of Python3 by default.

  • 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.

View all 170 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?



niuyingxian wrote 01/28/2021 at 22:48 point

My intention now is to make the stm8s001rs485 hardware operate normally according to the modbus protocol you introduced. How do I proceed? Is there any related video operation that is helpful to me, thank you

  Are you sure? yes | no

Thomas wrote 01/29/2021 at 19:50 point

  Are you sure? yes | no

niuyingxian wrote 01/27/2021 at 23:09 point

STM8S001J3rs485 What modbus rtu firmware should I download for this hardware to make it work? Thank you

  Are you sure? yes | no

Thomas wrote 01/28/2021 at 05:30 point

Hi - Right now you can't just download a firmware, you'll have to build it first.

As I wrote in my answer to your question in the "Modbus Things" project, please open an issue at the link below. I'll send you a first binary and walk you through the process where necessary.

  Are you sure? yes | no

niuyingxian wrote 01/28/2021 at 08:39 point

Thank you, how do I want to make the stm8s001rs485 hardware work normally and send data through modbus protocol, what do I need to do in the first step? I come from China

  Are you sure? yes | no

Thomas wrote 01/28/2021 at 19:19 point

The first thing will be to click on the link above and create an "Issue", a ticket on GitHub :-)
There I can help you better.

  Are you sure? yes | no

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

Similar Projects

Does this project spark your interest?

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