eForth for cheap STM8S Value Line gadgets

Turn cheap stuff from AliExpress into interactive development kits!

Similar projects worth following
This project turns cheap "Value Line" STM8S µC boards into interactive Forth development kits by learning how a board works, and writing board support code and docs. Using the SDCC tool chain it's possible to combine C code with a Forth shell for testing, setting control parameters, or as a scripting engine!

The code is based on the STM8EF eForth Demo by Dr. C.H. Ting for STM8S Discovery. Kernel, interpreter, compiler, and debug tools used to fit in 5.5K Flash. Most of it was rewritten for low-end STM8S µCs (1K RAM, 8K Flash), and a core system now requires less than 4K Flash!

New features include compile to Flash, driver code (e.g. for 7S-LED displays, analog and digital I/O), improved core vocabulary (DO .. LOOP, CREATE .. DOES>), a concurrent background task, vectored I/O, and flexible configuration.

Check out the Wiki, get some cheap hardware, clone the code on GitHub, and enjoy interactive µC hacking!

What is it good for?

The project deliverables are configurable board support code as source and binary release for "interesting targets" and documentation. Using the code for specific embedded control applications is subject to new projects.

The code provided in this project can be used in many ways:

  • for embedded systems with an interactive core (scriptable and extensible),
  • for creating smart SPI, I2C, or RS232 connected peripherals with a scripting shell, e.g. for RaspberryPi, Arduino, or ESP8266,
  • as an interactive environment for exploring the STM8 architecture,
  • for learning Forth,
  • ...

Why a Forth for Cheap Chinese boards?

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

Right now, the W1209 is my favorite 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 obviously 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 still challenges, like the lack of communication ports. The "sensor connector" can either be used for communicating, or for sensing. What if you need sensing and communication at the same time? Maybe the "update connector" can be used as a home brew field bus interface? A lot is possible with the right idea, and the right software!

The ESP-14 (ESP8266 and STM8S003F3P6) is in the queue but the requirements for this one are a bit more involved (e.g. power supply). Please drop me a note if you're working on the ESP-14.

Which target boards are supported?

Besides generic CORE target for STM8S003F3P6, there is currently support for the following boards:

XH-M188 is work in progress, and I also ordered the following SmartClima control boards for tests:

Read more about likely future targets below.

Why Forth?

Again, because it's fun!

Consider this:

  • compared to other programming environments the core of Forth is easy to fully understand
  • 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 (you can literally program the compiler!)
  • the stack-centered "factoring" approach provides implicit data flow which leads to maintainable code
  • Interpreter-compiler, basic OS functions fit in just 4K code :-)

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. Usually the Forth stack machine is a minimalistic VM on a standard CPU but hardware implementations also exist (e.g. for a modest FPGA, or as a 144 core Forth processor). The VM is ideal for fast context switching, thus Forth easily meets hard-real-time requirements. It's no surprise that Forth was used in many NASA projects.

A Forth programmer is in control of all levels of problem abstraction, a unique advantage in a world where layer on layer of 2nd hand solutions leads to ever growing complexity (compilers, libraries, operating systems, drivers,frameworks, IDEs... ). I'm convinced that "Thinking Forth" will make anybody a better programmer, not just in the domain of embedded control!

Why STM8S003F3 or STM8S103F3?

Low-end "STM8S Value Line" STM8 µCs are very cheap (less than $0.25 in hobby quantities), and that's why they appear in many cheap gadgets:

  • a simple STM8S103F3P6 breakout board costs less than $0.70,
  • a W1209 thermostat (STM8S003F3P6, relay, 3 digit display, 3 keys) costs...
Read more »

The latest release is on GitHub. Release v2.2.0

Zip Archive - 18.94 kB - 12/04/2016 at 23:22


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


View all 2 files

  • 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 /w 3.3V level (e.g. a $0.60 CH340 USB adapter) e.g a CH340 USB interface
  • 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)

  • STM8EF v2.2.6.Snapshot: embarrassing hotfix (and new features)

    Thomas2 days ago 0 comments

    A long time ago, I proudly released the "DO .. LEAVE .. LOOP" feature. I should better have spent more time testing, and less time announcing, since LEAVE was all but working. For some reason, my test cases worked, and some change to the code base must have exposed the bug. The new (pre-) release 2.2.6.Snapshot with the bug fix (and some more features) is here.

    I noticed the bug during tests of new features for code size optimization, like a DOLIT implemented with TRAP, and relative addressing of CALL (now, depending on the code, STC can now be as compact as DTC).

    Release of support of new boards (like W1401 and DCDC) will have to wait a little bit longer, just like introducing the W1219, or a voltmeter with very friendly breakouts that I had in the mail last week. At least, the code in the GitHub "develop" branch contains some initial board support for the W1401 (without keys and outputs), and for the DCDC converter (the serial interface isn't fully usable yet).

  • The code densitiy TRAP

    Thomas3 days ago 0 comments

    Fusing code to improve code density has a high potential of making refactoring very difficult. In this project I took the freedom to fuse core code when I saw a size (sometimes also a speed) advantage, and where I didn't see possible future variation points. In some cases I un-fused code from the original STM8EF source to get desired variation points (e.g. vectored I/O). This was easy since much of the eForth source code is written in Forth, and fusing code is no problem as there are no fundamental changes to the design of eForth.

    So, where is the point? It's a pun. I used the TRAP instruction to improve the code density of Forth user code :-)

    Please let me explain by diving a bit into how the Forth VM, the virtual CPU that drive a Forth systems works. When Forth compiles a "word", it creates a thread of tokens for consecutive execution by the Inner Interpreter, the execution unit of the Forth VM.

    The Inner Interpreter can be implemented in hardware (a Forth CPU), or in software. There are established coding techniques for general purpose CPUs, like the often used Direct Threaded Code (DTC) where tokens are pointers to the so called "Code Field Address" of words.

    Tokens can represent any of the following:

    • other Forth words like DUP, SWAP, or other user words, that get executed in sequence
    • the DOLIT instruction to push an literal integer, following the token, to the Data Stack
    • the EXIT instruction that ends a thread, to return to the calling thread, or to end execution
    • the BRANCH instruction to move the instruction pointer to a different point in the same thread
    • ?BRANCH, DONEXT, or DOLOOP which are similar to BRANCH but conditional (using data on the Data or Return Stack)

    Words like DOLIT or ?BRANCHdiffer from ordinary Forth words in that they manipulate the Inner Interpreter, and don't just work with the stacks of the Forth VM, and therefor the implementation of this class of words dependents on the coding technique used for implementing the Forth VM. Only a small number of such words is necessary, and most of them are core words.

    STM8EF uses Subroutine Threaded Code (STC). Here, the Inner Interpreter is implemented by the CALL instruction of the CPU, the instruction pointer is the program counter, and the CPU's return stack is used as the Return Stack of the Forth VM. Words that need to manipulate the instruction pointer, like DOLIT, do this by changing the CPU's PC value on the return stack (the one that the CALL pushes for use by RET).

    The advantage of STC is speed and simplicity of implementation. Context switching for multi-tasking is also easy to achieve (I took advantage of this). The disadvantage is code size: compared to DTC a simple STC implementation needs at least one more byte for representing a token, the CALL instruction. And this is before we even use words like DOLIT and EXIT to make the Inner Interpreter change the sequence of execution.

    Since we're using the CPU as the Inner Interpreter there are other some more analogies between the CPU and the Forth VM that we can exploit for optimization:

    Token Optimization measure for increasing code density Trade-Off Done
    any Many CPUs have CALL instruction that uses some form of relative or segmented addressing for improving code density, and an optimizing compiler can take advantage. The STM8S CALLR instruction is used if the call distance is less than 128 bytes (2 instead of 3 bytes). Some code generator complexity.
    EXIT EXIT can be coded as native RET (1 instead of 3 bytes) None
    BRANCH Branch can be coded as native JP (3 instead of 5 bytes) None
    ?BRANCH That's very hard since manipulation of the Data Stack is required (DONEXT and DOLOOP even manipulate data on the Forth VM Return Stack ). In Machine Forth, Chuck Moore changed the rules of the game to make this easier. Be like Chuck Moore.

    Read more »

  • Getting shared GPIO serial right, and other nuts to crack

    Thomas5 days ago 0 comments

    If you're following this little project you may have noticed that I take pride in adjusting the code for supporting almost any type of cheap STM8S Value Line device.

    Here is a number of constraints:

    1. in most cases UART pins are not broken out
    2. in some cases UART pins are used for communication
    3. in most cases there is no accessible "unused" GPIO
    4. in some cases there is no ICP connector, PD1 is used, and NRST isn't accessible

    I did the following to meet constraints 1. and 2.:

    • there is a simple "half-duplex" single GPIO configuration for the console
    • the serial line simulation for interactive console can be configured for any GPIO (assumption: port change interrupt requirements of other GPIOs on the used port can be met with "falling-edge")
    • two instances of serial com "devices" can be used in Forth code, one for the application, one for the console

    However, I'm still working on some edge cases constraint 3:

    • Sharing a GPIO for the console with the application requires priority for communication (e.g. the DP segment of an 7S-LED doesn't work while the console is being used)
    • the "interactive" state has to be detected, stored, and maintained for a convenient period of time

    I'm working on a solution that doesn't lead to much entanglement between communication and board support code. I'd like to restrict it to cases where the "background task" option is enabled.

    Constraint 4 is a bit more complicated to meet as I learned yesterday:

    • When the NRST pin is not accessible PD1/SWIM must be in input mode at least for some time

    I've got it working in cases where PD1/SWIM is used for digits or segments of the 7S/LED display even if it's not used for the serial communication code (where the constraint is implicitly met).

    Anther thing I've been working on is the code density of Forth user code: having literals (constants, addresses) in STC (subroutine threaded code) is quite expensive: a call to DOLIT followed by a 16 bit constant, that's 5 bytes. In the core code I got that down to 4, 3, 2, or even 1 bytes in many cases (CALLR DOLIT for 16 bit, CALLR DOLITC for 8bit constants, and LDW Y,#W and LD A,#C, or CLRW Y and CLR A with TOS in a register). This method contributes to quite some binary size reduction in the core, but it can't be used easily in user code (one work around is to use words like "0" for frequently used constants).

    I now experimented with the STM8 TRAP instruction to build a native DOLIT which is just TRAP MSB LSB. It works nicely, but it takes 3 µs to execute. An 80's programmer would have been happy with that, but today it's a "size over speed" decision.

  • News on "LM2596 with voltmeter"

    Thomas01/15/2017 at 13:17 0 comments

    Yesterday I had another specimen of the prolific cheap LM2596 based "buck converter with voltmeter" in the mail, and it's actually worth writing about!

    The first obvious thing, already visible on the vendor's pictures, is that the 7S-LED display nicely covers the voltmeter part including all the passive components.

    Underneath the LED display we find this nice arrangement:

    The LM317 in TO92 package is directly connected to the voltage divider R4/R3 (the LM317 lacks the recommended capacitor Cout, Cin is shared with the LM2596). C13 is connected to Vcap (STM8 1.8V core supply circuit). R1/R2-C4 and R8/R9-C5 are the "voltmeter inputs" (PC4 Vin, and PD3 Vout).

    PC3 is connected to LED "in", and PB4 to LED "out" without current limiting resistor (the same as the 7S-LED display). Like in the first variant, the "design" relies on the limited current driving capability, and on the surprising robustness of the STM8S outputs. The LED power dissipation is limited by a 4% duty cycle (there is a risk of accelerated degradation). R5 is connected to the green power LED.

    Isn't there anything else missing? Yes, a bypass capacitor for the STM8S003F3P6 - there is none!

    So, if you ever had any doubt about the robustness of the STM8S: it's unfounded. It will tolerate circuit bending practices on a mass production scale ;-)

    I first assumed that the GPIOs used for the 7S-LED display are the same but they're not since the STM8S003F3P6 is rotated by 90º with respect to the first variant.

    Although the LEDs "in" and "out" are now connected to dedicated GPIOs, the keys are still connected to segment LED outputs (PC5/SegE and PD2/SegG), this means that the display should be blanked during a key-press. It would have been really easy to use PB5 for reading the keys but it was left unconnected.

    As mentioned in my last post there is a thing I learned about the STM8 ICP interface: it will work without the NRST pin if SWIM hasn't been disabled in software or in the configuration bits. This means that one can get Forth onto it without soldering (PD1/SIM is connected to Pin4 of the LED display)! It will only work one out of three times, but that's OK for our needs, and once we have a Forth console we don't need the NRST anymore.

    Now, what can we do with it this knowledge?

    • for reading ADC values of any accuracy all LEDs should be switched off
    • Vin is easily accessible on the backside of the PCB, and after cutting the trace it can be used for measuring anything else
    • PC3 can be exposed by removing LED "in" (there is no resistor!)
    • LM2596 Pin 5 "/ON-OFF" can be cut and connected to PB4 for controlling power out (even without removing LED "out")
    • PB4/ can be exposed by removing LED "out"
    • for controlling the LM2596 feedback loop the pot wiper can be connected to GPIO PC3
    • The Vout ADC can be used for closing an output voltage (or current) control loop

    Controlling a DC motor or a hydraulic valve solenoid with this variant of the "DC/DC converter with voltmeter" module appears to be very feasible.

    Other applications might be:

    • Precision temperature control (i.e. not switching-mode but by setting the power!)
    • Low-grade lab power supply with some control features (scripting, monitoring, synchronization, maybe even fold-back current limiting)
    • LED power supply with current control
    • battery charging
    • ..

    Who said that a piece of electronics with a horrible design can't be turned into something useful? I hereby put this $1.52 gadget on "strong buy" ;-)

    I don't plan to support the first variant of the board as it lacks LED GPIOs that can be easily repurposed. So, if you want to buy one, better make sure to get this second variant (not the one in the first post). On AliExpress search for "LM2596 DC 4.0-40 to 1.3-37V Adjustable Step-Down". I've seen a green and a blue variant,...

    Read more »

  • XH-W1401: PD1 quadruple play

    Thomas01/12/2017 at 23:08 0 comments

    When I first examined the cheap XH-W1401 thermostat module (6 digit 7S-LED display, 4 keys, 2 LEDs, relay, and buzzer) I quickly noticed that using the GPIO PD1/SWIM for 3 tasks (SWIM for flashing, half-duplex RX and TX) wouldn't be that easy since it already serves for SWIM and to clock the 74HC164 shift register.

    Now I found a solution: the shift register clock pulse can be short with respect to a UART bit time. I tested it with a two cycle operation (125ns) which a CH340 UART chip filtered out. First tests look promising!

    It's also possible to generate the clock with one cycle (64ns) and to use a very simple RC filter (e.g. 47R/10nF) to hide it even from an unfiltered UART like the interrupt driven implementation in this project.

    It's further complicated by the fact that the 74HC164 is unlatched which means that any transition on the serial line alters the LED pattern of a currently displayed digit. This can be countered by refreshing the display contents in the stop bit (sometimes even a software UART has an advantage ;-) ). The GPIO will then serve 4 needs concurrently: quadruple play ;-)

    It looks like the XH-W1401 has the potential to be a supported gadget (there are variants with a front panel, and at a price of about $2.60 it's still very cheap). The schematics still has some mysteries (e.g. what they did at the sensor input, and which STM8s pins are assigned to keys, relay and buzzer) but if you follow this little project ordering a W1401 now wouldn't be all too risky.

    Edit1: I tested optimized assembly code for feeding the 74HC164 with 62ns pulses, and I was mildly surprised by the bit rate. Depending on instruction alignment with 32bit boundaries I get 1.75 to 2 Mbit/sec with looped code (data shift out, clock creation, counting, branching). In my youth that would have been ... fast ;-)

    Edit2: the multiplexed LED display and the serial interface on the same port appear to work. For now, the display is off while a byte is being transmitted through Rx or Tx. One of the next things will be more examination of the circuit. Especially the NTC sensor input is unexpected, and a huge capacitor at NRST made me learn a new thing about ICP through SWIM: NRST isn't always neded!

  • UART for application, serial console through SWIM

    Thomas01/10/2017 at 06:35 0 comments

    With the following configuration the latest code on GitHub has the option to use the UART for other things than a Forth console:

             HALF_DUPLEX      = 1    ; Use EMIT/?KEY in half duplex mode
             HAS_TXUART       = 1    ; No UART TXD, word TX!
             HAS_RXUART       = 1    ; No UART RXD, word ?RX
             HAS_TXSIM        = 2    ; Enable TxD via GPIO/TIM4, word TXGP!
             PDTX             = 1    ; Port D GPIO for HAS_TXDSIM
             HAS_RXSIM        = 2    ; Enable RxD via GPIO/TIM4, word ?RXGP
             PDRX             = 1    ; Port D GPIO for HAS_RXDSIM
    I used a higher flag value for HAS_TXSIM and TXRXSIM to indicate that it should be used for the console. In this configuration the UART can be used with TX! and ?RX while the EMIT and ?KEY vectors point to TXP! and ?RXP. It would also have been possible to keep the simulated serial interface free by not using a higher flag value.
    Here is a test to copy chars from RX to TX in the background:
    : bcopy ?RX IF TX! THEN ; ok
    ' bcopy BG ! ok

    This works fine but for using it to automate an ESP8266 remote serial with background code we still need buffers for RX and TX. Next up: vectored I/O for the background and some kind of buffers. An input buffer is also necessary for using some of the interpreter code in the background.

    Edit1: of course, I/O in the background is already vectored, but the vectors used are fixed. The vectors can be changed at the start of the background task, and maybe I keep it that way.

    Edit2: I don't want to go for a multi-tasking/multi-user system, and changing the user context therefor isn't necessary (that would be interesting for a CPU with a vast amount of resources, e.g. an entry level Cortex M0 ;-) ). However, the eForth implementation of the words parse (single out words separated by a delimiter) and find (look up words in a linked-list or dictionary) use the temporary variable tmp, which is the only thing that binds the words to a user context (along with the compiler and the interpreter). I'm now removing the words from the implementation and use temporary storage on one of the stacks instead (the return stack). That's not much nicer than the tmp variable, but it provides a cheap multi-tasking context switch.

    Edit3: I was wrong - using the return stack instead of the tmp variable is much nicer (and a bit more compact, too). Now I've got to figure out how to implement buffered I/O in a multi-tasking friendly way.

  • A new gadget arrived today, and a bugfix

    Thomas01/09/2017 at 22:37 0 comments

    Today I received the first XH-W1401 specimen (mine has yellow instead of green 7S-LED displays).


    • The copper area that serves as a heat sink for the "AMS1117 5.0" linear regulator is too small (yes, it gets hot!)
    • The 74HC164 unbuffered shift register that drives the LED columns is clocked by PD1/SWIM (of all pins). Let's see what we can do with this.

    I didn't start experimenting with it because I had to fix a bug in the number conversion routine first. I added two features (more address words for peripheral devices, and lowercase numbers for base > 10) while I was at it. The new binary is at the usual location.

  • What's the difference between STM8S003F3P and STM8S103F3P6?

    Thomas01/06/2017 at 20:28 5 comments

    Today I worked a little on a more complete hardware register map. I copied the map data from the STM8S003 datasheet and converted it into a new file with a simple AWK script. Make failed because "PC_IDR" was rendered as "PB_IDR". Great, a human touch! After correcting the typo I got the same results as with my original register map file (that doesn't mean that all the map addresses I didn't use before are correct ;-)).

    In my little project I always had difficulties telling the "Value Line" STM8S003F3P6 and the "Access Line" STM8S103F3P6 apart. According to the front page of the datasheets the differences are :

    STM8S003F3P6 STM8S103F3P6
    Flash 8 Kbyte Flash memory; data retention 20 years at 55 °C after 100 cycles
    8 Kbyte Flash; data retention 20 years at 55 °C after 10 kcycle
    EEPROM 128 bytes true data EEPROM; endurance up to 100 k write/erase cycles
    640 byte true data EEPROM; endurance 300 kcycle
    Unique ID - 96-bit unique key for each device

    Shouldn't I have a different include file for the STM8S103F3P6 for the sake of consistency?

    Besides the wildly different specs for Flash, the different size of the EEPROM, and the guaranteed write cycles (what does "up to" mean in a datasheet?) there is that one "unique selling point" for an "Access Line" device: the "Unique ID".

    What's the "Unique ID" anyway? Using the Forth console on a STM8S103F3P6 I made a dump of the "Unique ID" address range :

    $4865 $F dump
    4865   0  7  0 3A  2 47 36 30 32 35 36 35 1F  0  0 1F  ___:_G602565__ ok

    According to the datasheet the numbers mean "xWafer=1792, yWafer=14600, wafer#=2, lot#=higherthanthereareatomsintheuniverse". Quite obviously the datasheet is wrong: ID = [ 7, 58, 2, "G602565" ] is more like it.

    Wafer number, lot number, position: all that sounds much more like the data the fab's QA is after. It would be a shame if such critical quality assurance data were not available for "Value Line" devices, wouldn't it?

    Let's run the same test on a STM8S003F3P6:

    $4865 $F dump
    4865   0 1C  0 46  6 47 35 34 37 36 37 37 1F  0  0 1F  ___F_G547677____ ok

    This looks familiar. Of course, it makes no sense to tailor QA process just for removing a feature that's not listed!

    Now I got curious: what about the 640 vs. 128 bytes EEPROM?

    hex ulock ok
    4000 &640 + . 4280 ok
    77EE 427E ! ok
    427E ? 77EE ok

    Guess what: the STM8S003F3P6 also has 640 bytes of EEPROM!

    Be advised: there is no easy way to tell a STM8S003F3P6 and a STM8S103F3P6 apart, and there is a very high risk that you receive fake STM8S103F3 chips when you source from the gray market!

    On the bright side, for hobby use you can put your trust in the outstanding quality record of ST, and simply ignore the intimidating reference to "100 cycles" in the Flash characterization. It's probably more like 10k, and then only if you have data retention requirements of "20 years@55 °C". Otherwise I'm, quite sure, the trusty device on the breadboard will tolerate 20k erase/write cycles (and if not, dump it).

    Ah yes, and you can use the additional 512 bytes EEPROM, too. Other than the QA guarantees, the front page of the data sheet, and the missing description of the "Unique ID" the devices are the same. The STM8103F3 datasheet even has the same error as that of it's cheaper twin: the symbol PC_IDR is missing in the port mapping. too ;-)

  • Bump to v2.2.4: adding the SWIMCOM target, and more

    Thomas01/05/2017 at 19:58 0 comments

    This release has been almost 10 days in the making.

    The most important changes are:

    • improved console communication options, e.g. through a single port D GPIO pin (like PD1/SWIM)
    • simultaneous communication in console and background task is possible
    • configurable character I/O code is now part of the core (no more merging into board code)
    • board I/O code (board key input, 7S-LED output) was split into core and board code
    • a new target SWIMCOM with console communication through PD1/SWIM was added for exploring unknown boards.

    With these changes it's much easier to support new boards without needing to merge core changes into board configurations all the time. I actually sacrificed 15 (fifteen) bytes in the W1209 target for avoiding another configuration tree bifurcation.

    The software serial I/O code is interrupt driven and rather fast (the overhead compared to using the UART is about 10µs). It's also possible to have two independent serial interfaces: the ESP-14 uses the STM8 UART for the ESP8266 but you can have RxD/TxD on one or two port pins for the Forth console. Through vectored I/O it's even possible to change the console I/O during operation! (@Elliot Williams, we discussed this some times ago)

    One of the most important functional changes the GPIO console support that was announced in a log. Basically any STM8003F3P6 based board with a Port D pin that's not always required for operation of the board can be reverse engineered and programmed with eForth now: any STM8S003F3P6 board with an ICP connector is now fair game, not just the 5% with broken out UART port pins!

    To make the threshold for exploring new cheap boards really, really low, I added the SWIMCOM target to the binary release (I assume that anybody here has an 1N4148 diode and some patch wires for an improvised half-duplex "console bus" handy).

    Before you do anything that you'd regret later (like breaking some stuff), please make sure to read the warnings in the!

  • Refectoring for better hardware support

    Thomas01/03/2017 at 21:38 0 comments

    I worked a bit on robust configurable serial I/O (UART, GPIO with interrupt, mixed, full/half duplex), and there will be some more work to do until I'm satisfied with the result. Currently I'm testing the W1209 with the new code.

    Many boards have a 7S-LED display and I doubt that many will have the same GPIO configuration. On Taobao and on AliExpress there are dozens, and I ordered a bunch in the lower single digit $ range to play with.

    My goal is to have a generic I/O module for the console, with little dependencies to board specific initialization and driver code. Serial I/O should be the first thing that works, and the last thing you should be required to change the code for supporting a new board.

View all 48 project logs

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

  • 2

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

    • a Linux SDCC tool chain installation: installation instructions for SDCC & stm8flash are in the Wiki
  • 3

    Clone the project on GitHub

View all 4 instructions

Enjoy this project?



Elliot Williams wrote a day ago point

Hiya Thomas,

Got an ESP-14-powered device up and running and installed in our basement.  Long story, must write up.

Have you played around with power saving modes on the STM8?  I'm trying to get the part into the AWU / active-halt mode.  

For one, I need the assembler's HALT command, which I've been doing in the worst brute-force means possible: HERE $8e81 , EXECUTE.  (That's HALT and RET in machine code.)  

It halts, at least.  :)  

Coming back out of halt is messy -- it looks like the clocks aren't returned to their original states and so on. I'm probably going to need to implement some start-up code.  Heck, for my purposes, hooking into COLD for a complete reset will work too... That's what I'll try next.

Just wondering if you've worked on any of the low-power modes.  Either WFI (wait-for-interrupt) or the active-halt/AWU look tasty.

  Are you sure? yes | no

Thomas wrote 14 hours ago point

That's great :-)

The power saving modes (like the watchdog) still are on my "important things that I plan to do" list. You know, that's the list on the sheet after "new and exciting things I want to play with", which in turn comes after "bugs I must fix now".

Let's put it on the "important new features for pilot applications" list :-) 

What we need is:

* a word HALT that contains the HALT instructionknow

* a word SLEEP, that stops unnecessary interrupts (user defined, and application specific). This word should run HALT. When the execution continues right after HALT, SLEEP shall re-enable "waking" interrupts

* if required a word to restore clock settings (RM0016 mentions something in 10.2.2 and in 9.9.4 "Clock master switch register (CLK_SWR)", but right now I don't undertsand why the clock changes)

Do you plan to trigger a wake-up through console events? The simulated COM port should support this use case!

  Are you sure? yes | no

Thomas wrote 13 hours ago point

I added the HALT word, and it works better than expected. Here is a demo with a blinky:

    : g tim 40 and 0= out! ; ok
    ' g bg ! ok
The when I press enter after HALT the LED stops flashing. The "ok" after HALT appears after I press enter a second time.

  Are you sure? yes | no

Thomas wrote 11 hours ago point

Changes are in the develpp branch on GitHub. The 2.2.6.snapshot release contains new binaries :-)

  Are you sure? yes | no

jaromir.sukuba wrote a day ago point

Another tip for *possible* STM8 target

I didn't buy this one, haven't seen the schematics, but to me it totally smells like it could have STM8 under the display. Googling for XK-001T-1 didn't bring much info, though.

  Are you sure? yes | no

Thomas wrote a day ago point

Yes, that's possible. In most cases one won't find any schematics, and also the XH-, XK, M- or B monikers aren't always used the same. There is a small list of modules that are very likely STM8S based in the Details Section of this project (in the section "How can I spot suitable boards?"). If there is any interest, I can publish a list with advertised properties and the "street price".
Edit: here is a link with a picture showing the PCB legend:
Based on the outline of the µC I would expect it's not STM8 but a STC15 based, a µC which I've seen several times on "timer" boards (MCS51-like

  Are you sure? yes | no

Elliot Williams wrote 12/13/2016 at 23:13 point

Got my ESP-14 up and running last week, and then got distracted.  :)

Short story: it's just a STM8 chip and an ESP8266, like it says on the package.  The TX/RX lines are internally connected, so I was running your Forth on the STM8 with the ESP8266 powered down, and running all manner of software on the ESP with the STM8 powered down.

Been thinking about how to use both at once. 

a) Jeelink is a nice transparent serial port over ESP8266, which would provide remote wireless development of the Forth system on the STM8.  The idea of telnetting over WiFi into an STM8 is funny enough that I'm definitely going to do this.

b) Since the serial port is the only way in to the ESP8266, and the STM8 has only that one hardware serial port, I suppose that bit-banged serial or I2C/SPI could be used to talk to the console. I don't know how hard/easy this is. But then you'd have an STM8 that could issue AT WiFi commands, for instance, or run routines in NodeMCU, which might be very cool.

c) The other option is to code up the ESP and STM8 to take turns based on control characters: 0xFE toggles the ESP on/off the line, and 0xFF toggles the STM8, for instance.   This requires modifying _both_ firmwares, but would allow for the console, ESP, and STM8 to share the UART lines and talk to each other.

Just brainstorming so far. No real hacking yet. 

The breakout board I made for the module just fit it onto a breadboard, because I didn't really know what to expect from the module. It will probably want a transistor so that the STM8 can turn off the ESP8266 for power-saving when necessary, and will certainly want at least a jumper for flashing the ESP.  

Thanks for the case insensitive addition, and for do loops! This is a fun system to play around with.

  Are you sure? yes | no

Thomas wrote 12/14/2016 at 19:31 point

Options a) and b) look good to me, especially in combination. How about connecting a PNP transistor for the ESP8266 power supply to PD1/SWIM? Normally one would access the STM8 serial port through ESP-Link, and the ICP interface could be used for direct access to the ESP8266 serial interface by simply pulling down both NRST and PD1/SWIM. Direct serial access to the STM8 could be acchieved by telling it to power the ESP8266 down (this might even work using PD1/SWIM once more, e.g. by using an RC element which can be detected testing its timing).

Option c) would also be possible, but at least one of the devices would have to be able to swap RxD and TxD, and the other devices would need a "tristate" mode on TxD. The Bus approach I took for the W1209 might also work for more than two devices.

A fourth option could be to have a Forth word that issues the initialization AT commands on the STM8, and execute it with 'BOOT.

I hope to find the time for some hardware hacking in the holiday season :-)

  Are you sure? yes | no

Elliot Williams wrote 12/16/2016 at 21:22 point

"esp-link" not jeelink.  Tried it and had a telnet / web-console controllable STM8 running your Forth.  Took like 10 minutes.

Then I spent 3 hours trying to implement something like c) in NodeMCU.

First, I thought I'd set up two TCP connections: one for the ESP to be executed locally, and one to pass through to the STM8.  Didn't work b/c NodeMCU can only do one TCP connection, it seems.

Then I thought I'd use MQTT as the transport mechanism.  But there's some glitch there with MQTT and the UART port not working right.  I'll hack more at it before I give up, but it might be time to move on to MicroPython or ESP Basic for the interactive ESP part.

Anyway, try out the esp-link for the ESP when you get around to it.  It's kinda fun.  It _does_ however leave me wanting a more capable microchip on the remote end.  For another couple bucks, I could get a lot more flash, peripherals, and etc to tether to the ESP.

All of this playing around has helped me refine what's needed in a breakout board for this thing, though.  :)

  Are you sure? yes | no

Thomas wrote 12/16/2016 at 22:35 point

Again great news, and I'm going to test esp-link too. Multiplexing communication through MQTT topics was the first thing that came to my mind. About a year ago I tried working with MQTT and NodeMCU, but I was disappointed with the stability of the platform (though I really liked working with Lua).
I guess that the case for ESP-14 is rather thin: as I mentioned before, it looks more like proof that the ESP8266 wasn't able to meet customer requirements than like the solution the world's been waiting for. But who cares as long as it's fun hacking.
In my opinion, a decent Forth environment on the ESP8266 would be rather attractive: C.H. Ting hacked something recently, but it was just the kernel, not a complete framework with persistent vocabulary (and maybe even with source stored in the Flash memory, and maybe even a JavaScript based IDE served from an embedded web server on the chip).

  Are you sure? yes | no

Thomas wrote 11/28/2016 at 21:33 point

Hi Elliot, it's great to hear that someone got it running, and that the docs were good for a smooth start. Anyhow, congrats for the "STM8EF Blinky"! Did you try to do that BG style, too? 

I had a look at the CAPS issue (yes, I've been thinking about that for a while ;-) ). There are some potential clashes (e.g. PARSE/parse, NEXT,next, ABORT"/abort") but the lowercase words are the hidden "implementation part", and I don't see that their name is set in stone. I decided to name them after their assembly labels (pars, donxt, and aborq). 

New code with lowercase support is on GitHub (just set CASEINSENSITIVE = 1 in If you'd like to give it a try without building, please let me know (I can drop a binary into the files section here). If there are no issues I'll make it the default.

The ESP-14 will be one of my next targets. However, I didn't find the time to make a breakout PCBs with power supply for this module. Controlling the ESP8266 supply through the STM8S003F3 would be cool. If someone with good access to PCB prototyping could do that job I'd be more than happy to contribute some ideas about the schematics.

  Are you sure? yes | no

Elliot Williams wrote 11/29/2016 at 15:57 point

I just got an ESP-14 in the mail from ebay today.  I'll be making a breakout for it sometime in early Dec.  (Right now, I'm churning out HaD articles like mad.)  I'll share when I do.

I still have no idea if it makes any sense to run a (powerful) ESP8266 off of a (much smaller) STM8 chip.  But I'm willing to find out.  :)

I also ordered one of those LED/relay boards. Again, just for fun, but maybe I'll do something with it.

Thanks for thinking about caps.  I'll definitely rebuild and reflash. 

No, I didn't get into the multitasking / backgrounding. I just got the thing up and running, not much more.

  Are you sure? yes | no

Thomas wrote 11/29/2016 at 19:13 point

The ESP-14 is quite strange. I can only guess that an OEM required a solution from Espressif that meets non-functional constraints (e.g. dependability, power consumption, or periphery set) that could not be met by the ESP8266. I don't think that a lack of skilled programmers was the reason. The power consumption of the STM8S003F3 in "active halt mode" is quite low, and for a data logging sensor node a battery life of a year or more with a 100mAh battery might be feasible.

The W1209 boards are really fun, especially with a background task. When you try using STM8EF with it, please let me know if the docs for the single wire half-duplex solution are sufficient.

About the case-insensitive input: you're welcome (the option has a price tag with "23 bytes" on it :-) )

  Are you sure? yes | no

RigTig wrote 12/15/2016 at 10:44 point

I've created an adapter for ESP14 (and ESP12) to 22-pin DIL, if you haven't done anything else yet (see new project here called 'ESP-12 and ESP-14 adapter to DIL'). My ESP14s arrived today!

  Are you sure? yes | no

Elliot Williams wrote 11/28/2016 at 13:54 point

Hiya! Been following along, finally got a few minutes to flash stuff to one of those min-dev boards.  Great fun!  I haven't done anything useful with it yet, but I've gotten the LED blinking, naturally.

One thing that's driving me nuts is the ALL CAPS commands.  Is there an easy way to either a) lower-case them all or b) make it run case insensitively?  Or would that cause namespace clashes? It makes my shift-finger hurt. 

And that's it for now.  I have to say that your directions (combined with some of the links that you list) made it very easy to get up and running with the system.  Thanks!

I'm planning a few Forth columns for HaD, and I'm still collecting chips that have working implementations.  You've added one more to the list. 

Oh, and I've ordered an ESP-14.  We'll see how that goes.  Looks like fun. 

  Are you sure? yes | no

Does this project spark your interest?

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