Close
0%
0%

eForth for cheap STM8S gadgets

Turn cheap stuff from AliExpress into interactive development kits!

Similar projects worth following
TG9541/STM8EF is based on Dr. C.H. Ting's STM8 eForth (a basic eForth in 5.5K Flash compiling to RAM). The now much smaller core is optimized for 20ct STM8S µCs with just 8K Flash.

A lot of features were added: background task, Forth interrupt handlers, vectored I/O, 7S-LED display drivers, analog and digital I/O, board support (e.g. W1209), a configuration framework with feature selection, and support for a wide range of STM8 devices.

STM8 eForth uses the SDCC tool chain: C can be mixed with Forth, e.g. as a shell for testing, parameter setting, or for scripting.

The project now targets usability: e4thcom for programming, a library, and test automation with uCsim and Travis-CI.

What is it?

STM8 eForth is among the smallest user friendly Forth systems for µCs: it brings best of early 1990s style Forth to low-cost contemporary embedded control. Focusing in usability, this project delivers configurable board support code for selected low cost targets and docs. STM8 eForth uses very little memory yet it has a long feature list. A small but active community ensures that using it for new projects is easy!

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

  • as an alternative firmware Chinese commodity boards (e.g. thermostats, DCDC converters, or relay boards)
  • for embedded systems with an interactive shell (scriptable and extensible)
  • for creating smart SPI, I2C, or RS232 smart sensors with 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 :-)

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 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. What if you need sensing and communication at the same time?  The project provides also provides a binary for full-duplex 3-wire RS232 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" can be used as a home brew field bus interface!

Which target boards are supported?

Besides generic CORE target for STM8S001, STM8S103 and STM8S105, there is currently support for the following boards:

Some more boards are supported on request, e.g.

@Elliot Williams worked on using the ESP-14 as an IoT deviced(the ESP-14 is an ESP8266 with an STM8S003F3P6 in a ESP-12 package).

Programmable power supplies based on theXH-M188, and a cheap DC/DC converter are work in progress. There are also several types of STM8S003F3 based voltmeters that can be supported.

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

Read more »

2157_stm8ef.zip

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

Download

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

  • STM8S903K3 and STM8S001J3

    Thomas06/24/2018 at 07:53 0 comments

    The STM8S903K3T6C is an upgraded "application specific" STM8S low-density device with 7 ADC channels, an internal bandgap reference, re-mappable UART pins, and the cascaded timer features of the medium/high-density devices. All other features are identical to the STM8S103K3T6C (pin-out, memory 8K Flash, 640 byte EEPROM).


    For the same unfathomable reason that now made the "Value Line" STM8S003F3P6 more expensive than the higher rated "Access Line" STM8S103F3P6 the upgraded low density chip is available for as little as $0.32/piece (I bought my supply at an even lower price), and low-cost break-out boards are suddenly appearing on AliExpress, TaoBao and the like.

    I updated the notes on the STM8S001J3 in the Wiki because, when comparing the datasheet, I noticed that this chip quite obviously is an STM8S903 and not an STM8S003: some of the additional features are listed, even if the docs were mostly copied from the STM8S003. I have no idea what this should be good for since a subset of STM8S903 features has been documented, and replacing the chip with generic low-density won't work. Using the bandgap reference works (at 3.3V supply 7 ADC! ADC@ . results in approx. 400), the specified 16bit timer Timer2 is indeed a Timer5 and the 8bit timer Timer4 is a Timer6 (the additional configuration bits are present). For hobby projects it should be safe to use both feature groups. For product use I would talk with the ST sales team first.

  • STM8 eForth 2.2.22 released

    Thomas05/28/2018 at 17:57 0 comments

    After 10 weeks, and 4 pre-releases, there is again a new STM8 eForth release. Most of the new features have already been presented here. New and noteworthy is the following:

    • XY-PWM (HW-0515): support for a cheap dual PWM board (thanks to @Ivan Alf ),
    • STM8L Discovery support (also thanks to Ivan), more driver code for the STM8L (e.g. RTC and SPI) (once more, thanks to Ivan).
    • The STM8S initialization word for SPI, SPIon, was changed to match the STM8L implementation, and example code for SPI, e.g. the Nokia 3310 display demo code, has been updated.

    Have a look at the release notes!

  • Making PCBs again: STM8L051F3P6 with nRF24L01+

    Thomas05/12/2018 at 22:53 2 comments

    Edit: I made a new HaD project for this :-)

    My first PCB after 25 years, and the first PCB I ordered ever.

    OK, just a breakout board, but at least I made it with KiCad 5.0.0.rc2, and I ordered it from @oshpark. I must say that PCB tools have come a long way since the humble version of EAGLE which I used in the early 90s. The KiCad tutorials I found are excellent (especially those by Contextual Electronics), but it was the Cern tutorials that convinced me that the hours learning would be well spent.

    I found the KiCad workflow natural, and the fact that symbols can be combined with footprints was a nice surprise. My first steps were with the stable KiCad4, but since KiCad5 is where the users are switched after a couple of hours.

    This schematic is battery powered STM8L051F3P6 with nRF24L01+ (or rather SI24R1) .

    Ordering PCBs was also much easier than I thought, and navigating the different cheapo PCB offers, including checking Gerber files was rather easy. However, for 3pcs small purple PCBs, OSHPark is as good as it gets (in case someone is interested, the PCBs are here).

    Edit: the KiCad files are here on GitHub.

  • Announcing XY-LPWM Board Support in STM8 eForth

    Thomas05/11/2018 at 10:01 4 comments

    EDIT: I received both the XY-LPWM and XY-PWM board yesterday. As expected, the Nuvoton chip on the XY-LPWM had to be replaced by a STM8S003F3P6, and a 1uF 0603 capacitor had to be added, but that was quickly done. The XY-PWM for $1.65 came with the required controller, and both worked right after flashing - nice work @Ivan Alf!

    =======================================================

    @Ivan Alf contributed board support for the Chinese board XY-LPWM in his GitHub fork plumbum/stm8ef:

    I never understood what people use "PWM boards" for, but this one, and the slightly cheaper 2CH PWM Generator board both provide a serial interface. Which is really nice for interactive Programming with Forth!

    The board provides a 2x4 digit LCD display with a HT1621 LCD controller:

    Like many STM8S003F3P6 based boards these days, there is a big risk that the board you rceive has a "pin compatible" Nuvoton N76E003AT20 µC, a controller with an 8051 like core. Better be prepared to do some soldering when you order this board!

    Hint: sometimes STM8S103F3P6 chips are cheaper than the lower rated STM8S003F3P6.

  • STM8 eForth with nRF24L01+

    Thomas04/29/2018 at 08:42 0 comments

      nRF24L01+ modules are ubiquitous, and cheap (very cheap: from $0.32/module!).

      @richard started a distributed sensor project, and provided STM8 eForth code for the nRF24L01+. I joined the effort. My development target is a "tiered approach" to STM8 eForth applications, and of course I always wanted to have a cheap "sensor mesh network".

      The tiered approach takes advantage of the STM8 eForth binary distribution (with Travis-CI), and it adds a middle layer for creating a "platform" image (e.g. STM8 eForth with nRF24L01+ library code) which is the basis for applications (e.g. a sensor node, or a base station). The approach takes full advantage of e4thcom, but writing application code a simple terminal program (e.g. under Windows) can be used.

      Another thing we want to test, is distributing "operational code" through the mesh network. That's a use case for the EVALUATE feature introduced in the last STM8 eForth release.

      So the tiers can be:

      1. STM8S eForth image
      2. Platform image
      3. Application image
      4. Operation code

      The operation code can, in fact, modify the application code in operation by transferring bits of source code, and it's always possible to fall back to the next lower tier.

  • XH-M194: STM8S105S4T6, Relays, Keys, RTC

    Thomas04/21/2018 at 19:36 0 comments

    I ordered an XH-M194 board  about half a year ago, and it remained shelfed for about 5 months. A GitHub user finally nudged me into writing board support code.

    The the guy who designed the board missed many opportunities, and it took me a while to decide how to implement the serial interface for the Forth console. The board offers a lot of outputs, more keys than most boards, and an RTC, but unfortunately no inputs.

    The controller, an STM8S105S4T6, is an STM8S medium density device with 2K RAM, 1K EEPROM and 16K Flash. The medium density device I tested all had 32K Flash, and it's quite possible that you won't find a chip with no more than the advertised amount of memory.

  • IDLE and EVALUATE

    Thomas04/10/2018 at 19:45 0 comments

    The HaD effect: people come with use-cases ans ideas, a creative exchange starts, and innovation takes place. In this project, this happened a lot.

    Recently @Richard needed a feature that I thought not to be possible with a µC as limited as a Low Density STM8S: the Forth interpreter should be running concurrent to the console!

    It turned to be that complicated: now an idle task, similar to the background task (but only running while the console is idle) provides some kind of non-preemptive multitasking with a limited context switch (i.e. the interpreter state is preserved).

    Consider the following example:

    #require EVALUATE
    
    : test $" 2 7 +" COUNT ;
    test EVALUATE . 9 ok

    EVALUATE relies on minuscule change in the STM8 eForth core: the address of the Terminal Input Buffer (TIB) is now a pointer, 12 bytes more code. The rest of the feature is optional Forth code.

    IDLE was even more simple: only 5 bytes more assembly were needed in KEY to make it work.

    Consider the following code running on STM8eForth 2.2.22:

    #require 'IDLE
    VARIABLE TALLY
    : t TALLY @ 1+ DUP TALLY ! $F000 AND 0= OUT! ;
    ' t 'IDLE !

    This flashes about 34 times per minute (unless the console has something better to do). One IDLE loop thus takes about 34s/(60*65536) = 8.65µs.

    I think that the 17 bytes in the core were well spent.

  • Forth Dictionary entries in the EEPROM

    Thomas03/25/2018 at 19:30 3 comments

    The low-cost STM8S Low Densitity devices don't have a lot of Flash (8K) and RAM (1K), but they have a surprisingly generous amount of EEPROM (640 Bytes). Ok, officially, the Value Line devices only have 128 Bytes EEPROM, but in practice the Value Line STM8S003F3 devices I tested all behaved like an Acces Line STM8S103F3.

    It's tempting to use the Flash Memory for storing code, but it turns out that jumping to an EEPROM address causes a reset!

    I now found a way to use EEPROM as a substitute for Flash memory: the ALIAS feature of STM8 eForth allows for splitting the Forth Dictionary from the code, and since an ALIAS is not executed but merrily interpreted it doen't matter where it's stored.

    For testing I stripped many dictionary entries from the CORE image for STM8S Low Density devices, and replaced them with ALIAS.

    Here is the result:

    WORDS
      RAM NVM WORDS .S DUMP IMMEDIATE VARIABLE CONSTANT CREATE ] : ; OVERT ." REPEAT WHILE BEGIN LITERAL C, , ' CR [ \ ( .( ? . U. KEY HEX HERE +! 0= ABS NOT 1+ 1- 2+ 2- 2* 2/ */ M* * / /MOD M/MOD UM/MOD < U< = ROT - 0< OR AND XOR + UM+ I OVER SWAP DUP DROP NIP >R R@ R> C! C@ ! @ 2@ 2! COLD 'BOOT U.R UNTIL UM* TYPE TX! THEN SPACE SIGN SAVEC #S ?RX RESET QUIT QUERY PICK PARSE PAD NEXT NEGATE NAME? NAME> MIN MAX ?KEY IRET IF HOLD FOR FILL EXTRACT EXIT EXECUTE EVAL EMIT ?DUP DOXCODE DNEGATE DIGIT DEPTH DECIMAL COUNT COMPILE? [COMPILE] COMPILE CMOVE CALL, BL ALLOT AHEAD AGAIN AFT ACCEPT ABORT 2DUP 2DROP #> # $" <#  ok
    NVM $A000 HERE - . 4461 ok

    Since more than half of the dictionary is stored in EEPROM (in bold text), a binary size of just 3731 Bytes offers a rich vocabulary!

    It's simple to use, too:

    \ EEPROM MODE:
    \ * define ALIAS words in the EEPROM, 
    \ * abort if a normal compilation (non-ALIAS words) is attempted
    \   note: the STM8 resets when executing plain compiled words from EEPROM!
    \ * return to RAM MODE with EECLOSE when done
    \ * remove ALIAS words in EEPROM from dictionary with EERESET
    
    #include EEALIAS
    
    \ load ALIAS words
    #require SPACES
    #require DIGIT
    #require DNEGATE
    
    \ done: return to normal, and WIPE RAM
    EECLOSE

     Check out the code of EEALIAS here - comments are, as always, appreciated!

    @RigTig : I guess that with this method a Forth not much larger than 3K is now possible. As I think about it, an interactive Forth for the STM8S103F2 (4K Flash) is now also possible - not very useful, but possible :-)

  • STM8 eForth at the German Forth Conference

    Thomas03/17/2018 at 11:32 0 comments

    The German Forth Conference is one of the better known venues in the international Forth scene. It will take place from 5 to 8 April 2018 in the Linuxhotel in Essen-Horst. The list of talks is here.

    Manfred Mahlow will talk about WORDLIST, a name-space-like approach in Forth, and demonstrate it with two µC Forth implementations, one of which, I've heard, might be STM8 eForth (at least, it's part of the STM8 eForth release 2.2.21).

    In a second talk, Manfred Mahlow will introduce STM8 eForth as a "semi-tethered" Forth, one that combines an embedded console with PC-side code. If you've followed this project on HaD, the idea should be familiar.

    Edit: video recordings of the talks are here.

  • STM8 eForth 2.2.21: New features, Improvements, and Bug-Fixes

    Thomas03/05/2018 at 21:21 0 comments

    The new release STM8 eForth 2.2.21 brings so many new features, improvements, and also bug-fixes, that it would be exceedingly boring to name them all. Some stuff is actually quite interesting :-)

    By the way, yesterday I started working on 2.2.22,pre, and the first preview already contains experimental support for STM8S High Density devices. STM8 eForth now runs on a chip with 6K RAM and 128K flash memory (remember that STM8 eForth works quite well on chips with 1K RAM and 8K flash). Only the lower 32K portion is directly usable for compiled Forth code but, given the density of Forth code, that's a lot.

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

Share

Discussions

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?

https://github.com/TG9541/stm8ef/wiki/STM8-eForth-Compile-to-Flash

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:

https://github.com/TG9541/stm8ef/wiki/STM8-eForth-Alias-Words

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:

https://gist.github.com/TG9541/e8b5abf014b37132471e4e42aace56c0

 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: https://github.com/TG9541/stm8ef/wiki/STM8-eForth-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 codeload.py, 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
Thomas

  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.

httpp://www.etotheipiplusone.net/?p=4187

  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" ( https://github.com/TG9541/stm8ef/blob/master/lib/STARTTEMP ).
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: [ https://github.com/TG9541/stm8ef/wiki/STM8-eForth-Compile-to-Flash#forth-variable-in-nvm-mode ]. 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:

reset
STM8eForth 2.2.20
here . 160 ok
nvm variable qqq $1e allot ram ok
nvm variable zzz $1e allot ram ok
cold
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
RAM
VARIABLE Var
VARIABLE Varloop
VARIABLE Byte
VARIABLE Addr
VARIABLE Startaddr
VARIABLE Finaddr

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

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

newflasher2

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
ok

  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:
https://www.aliexpress.com/item/Free-shipping-XH-M194-time-relay-control-module-Multiplex-timing-module-5-way-relay-time/32715874624.html
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 (https://github.com/TG9541/stm8ef/wiki/STM8S-eForth-Interrupts) .

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!

Thomas

  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

        HEADER  SAVEC "SAVEC"
SAVEC:
        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

        HEADER  RESTC "IRET"
RESTC:
        POPW    X               ; discard CALL return address
        POPW    X
        LDW     YTEMP,X         ; restore context
        IRET 

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.

Eelco

  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:

https://github.com/TG9541/stm8ef/wiki/STM8S-eForth-Interrupts

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.  

...ST

  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 globconf.inc? 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 https://github.com/TG9541/stm8ef/issues/75, 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: https://github.com/TG9541/stm8ef/issues/76

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,
Thomas

  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

Eelco

  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.

Regards

Richard

  Are you sure? yes | no

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

Hi Richard

Here is the link: https://github.com/Eelkhoorn/forth-oled-display

Please let me know if  you have recommendations for improvement.

Regards

Eelco

  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

Richard

  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!
https://github.com/TG9541/stm8ef/issues/68

  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 `codeloadTCP.py` - it should mirror the properties of e4thcom (require, \ res, \\ Example). Maybe the same is achievable on Windows with `loadserial.py`.

  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.

http://eecs.oregonstate.edu/education/docs/datasheets/10kThermistor.pdf

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!

https://hackaday.io/project/26258-w1209-data-logging-thermostat

  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 http://www.st.com/en/development-tools/st-link-v2.html.  You may also consider the ST software used by the person who published the schematic of the W1209. It can be found at http://www.st.com/en/development-tools/stvp-stm32.html

 

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 timer

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

Richard

  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 https://github.com/TG9541/stm8ef/wiki/STM8S-Programming

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 https://github.com/TG9541/stm8ef/issues/41
  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: https://gist.github.com/TG9541/69fa106e88f8ca3a482a79e572c45463 

I created an issue on GitHub https://github.com/TG9541/stm8ef/issues/42
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

Thomas,

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. 

Regards

Richard

  Are you sure? yes | no

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

Richard,

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

RigTig wrote 02/27/2017 at 21:59 point

Thomas mentioned that a better file loader would be nice. Here is my attempt. Simple to start with, but obviously capable of being expanded with features later. It is in Python2 and runs from the command line of the host machine (mine is LinuxMint).

<code>

#!/usr/bin/env python2

import serial
import sys
import time

port = serial.Serial(
    port='/dev/ttyACM0',
    baudrate=9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,    
    bytesize=serial.EIGHTBITS,
    timeout=5)

if len(sys.argv) < 2:
    print('Usage %s ... [fileN]' % (sys.argv[0]))
    sys.exit()

def upload(path):
    with open(path) as source:
        for line in source.readlines():
            time.sleep(0.2)        
            line = line.strip()
            if not line: continue
            if len(line) > 64:
                raise 'Line is too long: %s' % (line)
            print('\n\rsending: ' + line)
            port.write(line)        
            port.write('\n\r')
            chin = ''
            response_buffer = []
            while chin <> '\v':
                response_buffer.append(chin)
                while port.inWaiting() > 0:
                    chin = port.read(1)
            response = ''.join(response_buffer)
            sys.stdout.write(response)

for path in sys.argv[1:]:
    print('Uploading %s' % path)
    upload(path)

</code>

Usage: Save this code as a file (say named loadserial.py) and change its permissions to be executable (just the lines in between the code tags). I put loadserial.py in my local /bin folder. Edit loadserial.py so the port matches what you use when using a terminal console to connect to STM8 machine.

WARNING: I've just noticed that the indentation was inconsistently displayed, and python is indentation sensitive. So be very careful with just copy-and-paste. I'll put a copy of it up on RigTig's Big 3d Printer project here on hackaday.io.

Either put FILE on first line of the file to be sent, or type it into a terminal console and close it, then use a local command line interface thus: <code>  filename file2send </code>. Enjoy!

  Are you sure? yes | no

Thomas wrote 02/27/2017 at 22:26 point

Hi RigTig, this is cool! Now the last reason not to learn Python (the haploid language, as I use to say) has gone. I'm going to need it in my job, anyway ;-)

PS: I just added the tag v2.2.8.1.snapshot, and this means that the binary size of CORE is below 4096 bytes, complete with the new "transparent" VARIABLE feature

  Are you sure? yes | no

Thomas wrote 03/04/2017 at 11:07 point

I just tried your loadserial.py script - the handshake seems to work, and compiling code to NVM is very fast compared to the "worst case delay" method!

However, I had to interrupt the script with ctrl-c after the transfer was finished. The reason was that my Forth code ended with "HAND", after which loadserial.py waited in vain for the handshake signal.

I can imagine that an improved uploader does the following:

* handle FILE and HAND (no need to include those in source file), or

* terminate transfer when the response is anything but the handshake character

The next thing on a programmer's wish list is a way for including source files (nested, of course). I can also imagine testing if "base code" has already been transferred, e.g. using some query-response between the Forth system and the uploader.

  Are you sure? yes | no

Thomas wrote 02/27/2017 at 22:26 point

Hi RigTig, this is cool! Now the last reason not to learn Python (the haploid language, as I use to say) has gone. I'm going to need it in my job, anyway ;-)

PS: I just added the tag v2.2.8.1.snapshot, and this means that the binary size of CORE is below 4096 bytes, complete with the new "transparent" VARIABLE feature

  Are you sure? yes | no

RigTig wrote 02/23/2017 at 05:44 point

Thanks Thomas for a great environment in which to have lots of fun. I needed VARIABLE to be defined in NVM, but to keep its data in RAM. Some variables need to change for every data line processed (megabytes of GCODE), so using NVM is just not going to cut it for real use. Besides NVM access is slow. So, here is my replacement definition for my project:

: variable create here , 2 $6e +! does> @ ;

Now, this works only in NVM mode, because it makes no sense to use it in RAM mode anyway. Besides the DOES> part would be wiped every COLD or restart. The magic address of $006E is the address of next available RAM when in NVM mode.

If you want to test after a restart or COLD, you need to adjust the address of next available RAM to be after the last used address by a variable. In my case, the last used address was $009e. Note that in RAM  mode, the address of next available RAM is at $006A. So, I typed

$a0 $6a !

and then initialised all variables and they just work. Now this hack is not for every project (obviously), but does show what can be done when a need arises. Enjoy!

  Are you sure? yes | no

Thomas wrote 02/23/2017 at 21:35 point

Hi RigTig! That's indeed a nice hack, and it is much along the lines of what I had planned.

I'd like to propose the following solution: 

1. some memory below the user dictionary in RAM shall be set aside by adjusting the reset value of USRCP
2. the next variable address for NVM routines shall be stored in the (new) variable USRVAR, which shall be initialized from USRCP
3. when switching from NVM to RAM the reset value of USRCP shall be set to the value of USRVAR

I'd like to check if it's possible to make VARIABLE work transparently in NVM and RAM mode. Most likely writing a different word is easier.

  Are you sure? yes | no

RigTig wrote 02/24/2017 at 04:09 point

Thanks for compliment. I haven't really tried to make VARIABLE work in both RAM and NVM, but I am sure it'd work. The key is just understanding that there is one level of indirection (address of value instead of value), so RAM variables use an extra 2 bytes over the non-indirect version. Nice to avoid wasting ram, but not really a show-stopper. Coding in assembler should be far more memory efficient than the Forth version, but it's the joy of Forth to be able to do these kinds of things at all (and optimise later when you find that it is really a good idea!).

A hard reset or even COLD needs to preserve the ram space needed by variables, but I prefer not to lock in a pre-determined limit on the number of variables. I also hate wasting valuable resources by committing them for just-in-case scenarios. 

So let's consider the use cases. Is there a need to support programming to NVM, then RAM, and back to NVM? If we say that all NVM variables need to be defined before RAM gets any code, is that reasonable? At least all the ram needed is in one block in this case. Probably a bit hard to communicate to programmers, and practically impossible to enforce.

Even if there is some code compiled into ram before or after NVM variables are created, the only thing needed is to set the ram space used for parsing commands to be above the last used ram for any variable. This happens anyway until COLD or hard reset. Maybe all that is needed is a persistent vector stored in NVM to be used instead of the $0080 for start of ram space for code and variables. Now the incentive is for the programmer not to waste space, so it becomes 'obvious' that defining all NVM variables before using ram for anything else is just better management of the limited ram. VARIABLE needs to update the persistent vector each time, based on current ram pointer. Variables defined in ram waste space after a COLD, but that might just be a price to pay (and is quite ok during interactive development, methinks). Mmm... and RESET needs to reset the vector to first available ram for code and variables back to its compilation default ($0080).

I am sure to have missed something in this ramble, but hey, that's what hacking is about isn't it? If I knew what I was doing, then it is not real hacking! And what other language allows you to play around with how the language itself works, so Go Forth.

  Are you sure? yes | no

Thomas wrote 02/24/2017 at 06:41 point

RigTig, we're on the same page :-) 

If you read me previous comment carefully you'll find that the "machine" needed for implementing is mainly coded in the difference between "the reset value of USRCP" and "USRCP" (there is one error though: point 2. should be "in the new variable USRVAR which shall be initialized from the reset value of USRCP"). 

One could argue that this means waste of RAM, but actually it's just a buffer for certain use cases. You already mentioned some uses cases, and how much they would "surprise Joe Programmer".

My model for the programming workflow is this:

1. start a session with COLD, reset, or flashing the µC

2. write some test code in RAM (i.e. do the things you'd normally do with the original STM8EF)

3. run COLD and set the stage (e.g. define helper words like here: https://github.com/TG9541/stm8ef/wiki/STM8S-eForth-Programming#low-level-interrupts-in-forth)
4. run NVM, define words, variables etc as you like

5. run RAM, make pointers to the newly defined words, and also to USRVAR persistent

6. return to 4. (write more persistent code) or to 2. (test your code, preferably automated)

Of course, the casual user may miss the finer parts of the "Stage/NVM/RAM/Test/COLD" cycle, but they will notice quickly that words defined in RAM can't be compiled-in (only interpreted) in NVM, and that code compiled in NVM is lost if they forget to run RAM.

As you pointed out, a certain coding style, like defining variables first, isn't difficult to get used to. Setting aside a small buffer (e.g. 32 bytes) as a variable space wouldn't be a big deal, and it would enable the "setting the stage" use case without the risk of immediately overwriting words like IVEC. It's of course also possible to cycle through the steps 2..6 more often (also as a part of the source code) , but a buffer would add some flexibility. In the extreme case (use many variables, use a huge stack), writing test code in RAM would suffer. But hey, when testing words one tests the units, not the whole program where the stack reaches its maximum size.

  Are you sure? yes | no

Thomas wrote 02/26/2017 at 09:35 point

@RigTig

Please have a look at this: https://github.com/TG9541/stm8ef/tree/variable

The new code has the features discussed above. The behavior of VARIABLE and ALLOT is transparent in NVM mode, and in most cases there is no need to manage RAM allocation. Only if one allocates more than 32 byte RAM in a session it's necessary to cycle through COLD before using variables newly defined in NVM mode.

Edit: preliminary documentation of the new feature is here: https://github.com/TG9541/stm8ef/issues/16#issuecomment-282547170

  Are you sure? yes | no

RigTig wrote 02/27/2017 at 01:08 point

Thomas, I have to say that your approach is just brilliant. I love the idea of being able to just get more variable space if needed, and not wasting any ram either. 

P.S. We might be both on the same page, but I'm only partway down. I am still getting my head around the STM8EF code. I keep going back and changing the options for a new flash image and it is installed in a second or two. What fun to play with!

  Are you sure? yes | no

Thomas wrote 02/27/2017 at 07:17 point

@RigTig: thanks for your support! I just pushed a "size reduced" revision to the variable branch. Since I had to do some shuffling, some "review" and "testing" by "an independent person" would be great (in a hobby project that's what's known as "playing with the code" :-)

Currently some RAM gets wasted, but that could be bettered by giving the programmer control over the headroom for RAM allocation (which would be easy).

By the way, I ordered two of the radio modules you've been working on.

  Are you sure? yes | no

Elliot Williams wrote 01/23/2017 at 08:55 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 01/23/2017 at 19:14 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 01/23/2017 at 19:45 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
    HALT
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

Elliot Williams wrote 01/24/2017 at 11:52 point

Woot!  

re: clocks: I read something somewhere sometime about them needing a reset.  I can't find that anymore.  I may be crazy.  

I saw some other STM8 code (http://blog.mark-stevens.co.uk/2014/06/auto-wakeup-stm8s/) that runs the AWU without re-clocking, strongly suggesting that I'm crazy.

That code, though, makes it look like (if interrupts are enabled) the AWU reset lands in the AWU ISR, which is uninitialized ($0000) in the vector table at $800C.

I just ran your BG example above, and it halts, but never returns until hit with a hard reset. I wonder if your code is working b/c it NOPs off to the next ISR and you got lucky.  Or does it actually try to execute whatever's at $0000?

So: how do we set up ISRs in eForth?  (Or, how do you write bytes directly to flash?)

  Are you sure? yes | no

Thomas wrote 01/24/2017 at 19:23 point

TL;DR: the quick-fix: an AWU "driver" that does it all but I would prefer a Forth solution and this requires some design decisions.

Long version:

Due to limitations in the SDCC tool chain any interrupt must be declared in main.c. Writing ISR vectors to Flash might work, but it requires a good approach for registering (and unregistering) interrupts to be viable (I'm thinking of RESET). Also Forth VM context switching would have to be done before executing any Forth code.

Another approach would be a "catchall" interrupt handler for several interrupts that then redirects to Forth code. This has the advantage that the context switch can be handled in a uniform way, but the dispatching won't be very efficient (or again a lookup).

This brings us to the next problem: some interrupt sources require resetting some bit in some peripherals control register. Leaving that to user code is very error prone, and a "catchall" interrupt handler would have to do it for all possible sources or leave it to user code.

What do you feel about of a middle way?
* Interrupt handler declared in main.c
* basic handler code in assembler or c to do a context switch, and to clear the trigger source
* handler code in Forth registered through something like BG

A last point: how many concurrent "Forth code interrupts" can we allow?
* Level0 we have the console
* on Level1 is the BG interrupt
* on Level2 is TIM4 (for COM simulation)

I guess that some stuff like TIM4 shouldn't have to compete with other code (the current code is efficient as it gets). Most likely it's possible to drop the interrupt level in BG code to Level0, and use Level1 for Forth handlers without character-I/O. The latency would still be in the lower µs range.

  Are you sure? yes | no

Elliot Williams wrote 01/25/2017 at 12:43 point

How does the 'BOOT mechanism work?  If you could do placeholders for the various ISRs like that, the user could write their handler function and store its address in the right place?  That seems very Forthy to me.  <code>: awu-isr stuff ; ' awu-isr ISR_AWU ! </code> or something.  One of these functions / memory locations per IRQ and you'd be done?

On resetting the flags as you leave the ISR: I think that should be user code rather than bloating up the system with it.  Yeah, it's going to hang the system if you do it wrong.  If I could count the number of times I've pressed the reset button...

On context switching in ISRs:  I'm not sure I understand the full details.  Unlike C, there's not necessarily any context to switch?  If the ISR maintains stack balance then there's no need for any context?  Leave whatever's on the stack, and it'll still be there when the interrupt is done?

For me, personally, I'd just be stoked to have a pointer to an address that I could set to execute when the AWU IRQ fires.  The rest, I can handle in code, I hope. :)  (Assuming that the return from interrupt works right.)

  Are you sure? yes | no

Thomas wrote 01/25/2017 at 20:20 point

'BOOT is simple: it returns the address of the "Parameter" field (like DOVAR). To safe code I used it to get the address of the whole following table of initialization values for USR variables. After switching to "NVM" it's possible to simply overwrite all these values. There is a 2nd copy to restore these values, e.g. to "forget" user vocabulary in Flash memory with RESET.

Yes, the 'BOOT method can be used in for interrupts, too, but that would require one more level of indirection.

About context switching:

my first approach was to re-use the Data Stack, but I quickly learned that X isn't always a valid Data Stack Pointer: it does that at the start and the end of a word, but not always in between ("always" is a very important attribute when writing interrupt code). Before implementing the background task, I tried  to make sure that X always represents a valid stack pointer in all primitive words. However, I failed to get it working until I started using a 2nd Data Stack for the background task (which I didn't like since it appears wasteful). Later on, I applied coding techniques that use X for reducing code size. Of course, it's possible to re-factor the code. It would be interesting to compare other multi-tasking Forth implementations. 

I went in a different direction: In several refactoring rounds I removed the following variables entirely: TEMP, XTEMP, PROD1, PROD2, PROD3, CARRY, and I also made the I/O context leaner.

Now, for code without character I/O only YTEMP must be saved. Otherwise also BASE, PAD, and HLD must be taken into consideration. And, of course, we need a stack. One approach would be to have a floating "stack pad" to work around the "X!=TOS" problem.

I guess it will take some time to implement a full featured solution for Forth interrupt handlers.

A minimal solution might look like this:
* a word IVEC! to set an interrupt vector
* a word SAVEC to save the context
* a word RESTC to restore the context, ends with IRET

The application could then define a word in the following way:  

: handler SAVEC ( some stuff ) RESTC ;

 ' handler 1 IVEC! \ set the AWU interrupt handler

Now that I'm looking at it, this doesn't look too bad.

Edit: I made some corrections, added some details, and added one more option for a solution

  Are you sure? yes | no

Thomas wrote 01/25/2017 at 22:23 point

I added the solution above for testing to the develop branch. Due to the mentioned limitations it's currently necessary to initialize the interrupt to priority low (0:1) (it shares the data stack with the ticker).

I also changed TIM4 to prio "highest", which might allow to implement all user defined interrupts with priority "high" later on. This would then require 3 data stacks with the sizes normal (console), medium (background task) and small (interrupt handler).

  Are you sure? yes | no

Thomas wrote 01/26/2017 at 20:48 point

@Elliot Williams:

Here is a starting point for Forth code user interrupts and AWU usage:

  nvm

  : awuint savec awu_csr1 c@ drop restc ;

  ' awuint 1 ivec!

  : initawu 38 awu_apr c! 1 awu_tbr c! 16 awu_csr1 c! ;

  ram

When I run HALT with this code, it returns immediately. Since I didn't find the time to make sense of the AWU configuration, I simply took the AWU timing values from the page you mentioned before.

Please not that this currently only works when I run HALT from the console (I still need a solution for the Data Stack problem). Running HALT from the background task would change the contents of the first element on the stack (which would work if the stack were empty).

A quick fix here is to assume that X represents TOS when HALT is executed (which is the case), and skip initializing the stack. Please note that this only works for HALT, and not in the general case.

  Are you sure? yes | no

Thomas wrote 01/23/2017 at 21:51 point

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

  Are you sure? yes | no

Youlian Troyanov wrote 01/26/2017 at 04:51 point

please write your long story about esp-14 :)

  Are you sure? yes | no

Thomas wrote 01/27/2017 at 22:19 point

Elliot, in order to get a simple and practical solution, I now propose the following:

1) In RAM code IVEC! (its only used once for setting an interrupt handler

: IVEC! ( a n - -  ) 2* 2* $800A + ! ;

2) Implement HALT as a user word:

: HALT  ( -- ) [ $8E C, ] ;

3) Implement your interrupt handler using SAVEC and RESTC (make sure not to use more than 8 cells on stack)

This will work for any interrupt. Please make sure to change the interrupt down from highest to high.

  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