diff --git a/C0135/IN@ b/C0135/IN@ new file mode 100644 index 0000000..5d56dec --- /dev/null +++ b/C0135/IN@ @@ -0,0 +1,34 @@ +\ C0135 4-Relay board: read low side inputs - License MIT refer to STM8 eForth + +\ This is close to the iron +\res MCU: STM8S105 +\res export PC_IDR PC_CR1 PD_IDR PD_CR1 + +\ copy bit to C flag, set/res bit +#require ]BC +#require ]B! +#require WIPE + +\ opcode: rotate C left through TOS lsb +: RLC(1,X) $6901 , ; IMMEDIATE + +NVM + \ read C0135 inputs - connect INx to GND to get a "1" + : IN@ ( -- n ) + -1 \ inputs are "NPN" (in PLC speak), start with all bits 1 + [ ( IN4 ) PC_IDR 6 ]BC RLC(1,X) \ some simple STM8 assembly + [ ( IN3 ) PC_IDR 7 ]BC RLC(1,X) \ to load bits to C + [ ( IN2 ) PD_IDR 2 ]BC RLC(1,X) \ and rotate them into the + [ ( IN1 ) PD_IDR 3 ]BC RLC(1,X) \ Top Of Stack low-byte + NOT + ; + + \ init C0135 inputs + : IN@INIT ( -- ) + \ let's assume that Px_DDR are still in reset state + [ ( IN1 ) 1 PD_CR1 3 ]B! \ set pull-up for NPN (low side) switches + [ ( IN2 ) 1 PD_CR1 2 ]B! + [ ( IN3 ) 1 PC_CR1 7 ]B! + [ ( IN4 ) 1 PC_CR1 6 ]B! + ; +WIPE RAM diff --git a/C0135/board.fs b/C0135/board.fs index dd5562e..1024346 100644 --- a/C0135/board.fs +++ b/C0135/board.fs @@ -1,8 +1,17 @@ \ C0135 STM8 eForth MODBUS board code +( Hint for non-Forthers ) +\ - this and the above are comments +\ - @ means "read" and ! means "write" +\ - : means "compile", [ switches to "interpret", ] back and ; "end compile" +\ - #require, \res, etc are e4thcom or codeload.py keywords + \ compile MODBUS server and protocol words #require MBSERVER +\ We need the C0135 "read inputs" word +#require C0135/IN@ + \ we're in RAM mode: load "scaffolding words" #require :NVM #require WIPE @@ -10,23 +19,27 @@ #require ULOCK #require 'IDLE -\ temporary symbols +\ define temporary constants $4000 CONSTANT EE_NODE $4002 CONSTANT EE_BAUD +\ now compile to Flash ROM NVM -\ from here on compile to Flash ROM -#require OUT! + \ headerless code Preparation Handler + :NVM + IN@ inputs ! + ;NVM ( xt-pre ) \ compile time: keep this eXecution Token on the stack \ headerless code Action Handler :NVM coils @ OUT! - ;NVM ( xt-act ) \ compile time: keep this eXecution Token on the stack + ;NVM ( xt-act ) \ and also this \ --- MODBUS server startup : init ( -- ) \ register the xt (see above) as the MODBUS Action Handler ( xt-act ) LITERAL mbact ! + ( xt-pre ) LITERAL mbpre ! \ Holding C0135 key "S2" while start-up resets Node-ID and baud rate BKEY IF @@ -41,6 +54,9 @@ NVM UNTIL THEN + \ initialize C0135 inputs + IN@INIT + \ initialize MODBUS "coils" and outputs 0 coils ! 0 OUT! diff --git a/MBSERVER b/MBSERVER index 0b75855..6bf2383 100644 --- a/MBSERVER +++ b/MBSERVER @@ -38,7 +38,7 @@ NVM \ compile to Flash memory from here on \ FC01 handler :NVM ( -- ) - [ ( xt xth ) SWAP ] LITERAL 1 ( xth xt bpu ) mbread + [ ( xt xth ) SWAP ] LITERAL 1 ( xt bpu ) mbread ;NVM ( xth ) 1 FC>XT ! @@ -53,7 +53,7 @@ NVM \ compile to Flash memory from here on \ FC02 handler :NVM ( -- ) - [ ( xt xth ) SWAP ] LITERAL 1 ( xth xt bpu ) mbread + [ ( xt xth ) SWAP ] LITERAL 1 ( xt bpu ) mbread ;NVM ( xth ) 2 FC>XT ! @@ -77,7 +77,7 @@ NVM \ compile to Flash memory from here on \ FC03 handler :NVM ( -- ) - [ ( xt xth ) SWAP ] LITERAL 16 ( xth xt bpu ) mbread + [ ( xt xth ) SWAP ] LITERAL 16 ( xt bpu ) mbread ;NVM ( xth ) 3 FC>XT ! @@ -90,7 +90,7 @@ NVM \ compile to Flash memory from here on \ FC04 handler :NVM ( -- ) - [ ( xt xth ) SWAP ] LITERAL 16 ( xth xt bpu ) mbread + [ ( xt xth ) SWAP ] LITERAL 16 ( xt bpu ) mbread ;NVM ( xth ) 4 FC>XT ! diff --git a/README.md b/README.md index f2455fb..31efd05 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # stm8ef-modbus [![Travis-CI](https://travis-ci.org/TG9541/stm8ef-modbus.svg)](https://travis-ci.org/TG9541/stm8ef-modbus) -This repository provides a lightweight MODBUS RTU implementation with [STM8 eForth](https://github.com/TG9541/stm8ef/wiki) for "wired" control nodes, e.g. for home automation. The is intended for low-cost STM8S 8bit µCs like the STM8S003F3P6 with 8K Flash and 1K RAM. +This repository provides a lightweight MODBUS RTU implementation with [STM8 eForth](https://github.com/TG9541/stm8ef/wiki) for "wired" control nodes, e.g. for home automation. The main target is low-cost STM8S 8bit µCs like the STM8S003F3P6 with 8K Flash and 1K RAM. The MODBUS I/O Node implementation for the low-cost [C0135 4-Relay RTU module][C0135] serves as a demonstrator, and in [GitHub Releases](https://github.com/TG9541/stm8ef-modbus/releases) you'll find a ready-to-use binary. -Using STM8 Forth for MODBUS has many advantages: while the implementation is very compact it gives applications access to many advanced architectural features like independent I/O-locic execution in the background, a CLI (command line interface). The Forth compiler is included and you can literally change the code through the built-in console while your board is communicating with the MODBUS host! +Using STM8 Forth for MODBUS has some advantages: the implementation is very compact and it gives applications access to many advanced architecture features like "I/O-locic execution in the background" or a CLI (command line interface). -The C0135 MODBUS implementation covers basic FCs: it's a subset of [MODBUS V1.1b](http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf) common in simple I/O nodes. It's easy to write code for other FCs. It's also simple to turn the board in something like an independent controller for window blinds: the MODBUS host only commands "open" or "closed", not "up" and "down". Local control code can help to make home automation much more robust and reactive. +The Forth compiler/interpreter is part of the binary you can literally change the code while your board is communicating with the MODBUS host! -Right now there is no MODBUS master implementation but the code in this repository can be re-used to write one. +The MODBUS RTU implementation covers basic FCs: it's a subset of [MODBUS V1.1b](http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf) common in simple I/O nodes. It's easy to write code for other FCs. It's also simple to turn the board in something like an independent controller for window blinds: the MODBUS host only commands "open" or "closed", not "up" and "down". Local control code can help to make home automation much more robust and reactive. ## Supported Boards @@ -22,7 +22,7 @@ The [C0135 board][C0135] is the default target. You can simply transfer the ready-made binary to your board with a cheap "ST-LINK V2" dongle, or run `make` to flash the STM8 eForth C0135 code. -Using a diode and a cheap USB-TTL dongle you can [get a console][TWOWIRE]. +Using a diode and a cheap USB-TTL dongle you can [get a console][TWOWIRE] (this means the MODBUS node *is* a computer, a bit like the console of a VIC20 in the old days ;-) ). [TWOWIRE]: https://github.com/TG9541/stm8ef/wiki/STM8-eForth-Programming-Tools#using-a-serial-interface-for-2-wire-communication @@ -39,7 +39,7 @@ It's easy to build custom targets, e.g. using the $0.80 [MINDEV board](https://g ![MINDEV](https://camo.githubusercontent.com/82bd480f176951de9a469e134f543a6570f48597/68747470733a2f2f616530312e616c6963646e2e636f6d2f6b662f485442314e6642615056585858586263587058587136785846585858362f357063732d6c6f742d53544d3853313033463350362d73797374656d2d626f6172642d53544d38532d53544d382d646576656c6f706d656e742d626f6172642d6d696e696d756d2d636f72652d626f6172642e6a70675f323230783232302e6a7067) -When using PB5 for RS485 direction control (-> `BUSCTRL`) the C0135 code can be used. +When using PB5 for RS485 direction control (-> `BUSCTRL`) the C0135 code can be used unchanged. ## Supported MODBUS Function Codes @@ -47,20 +47,22 @@ When using PB5 for RS485 direction control (-> `BUSCTRL`) the C0135 code can be FC | Description | Support -|-|- -**1**| **Read Coils** | implemented -**2** | **Read Discrete Inputs** | implemented (limit to "8bit aligned") -**3** | **Read Holding Registers** | implemented (variables in RAM) +**1**| **Read Coils** | implemented ++ +**2** | **Read Discrete Inputs** | implemented ++ +**3** | **Read Holding Registers** | implemented (variables or EEPROM) **4** | **Read Input Registers** | implemented **5** | **Write Single Coil** | implemented **6** | **Write Single (Holding) Register** | implemented -**15** | **Write Multiple Coils** | implemented +15 | Write Multiple Coils | see [issue #19](https://github.com/TG9541/stm8ef-modbus/issues/19) 16 | Write Multiple Registers | partial -An example for diagnostic functions is in `main.fs` and a way to load communication properties from the EEPROM is implemented in `C0135/board.fs`. +++: *currently limited to "8bit aligned start address", e.g. 0, 8, 16* + +A working example with Node-ID and Baud Rate stored in EEPROM is implemented in `C0135/board.fs`. An example that shows how to develop minimal servers with FC handlers from scratch using the Forth console is in `main.fs`. ## Installation -This project uses the STM8 eForth "Modular Build" feature: `make depend` fetches a STM8 eForth release. +This project uses the STM8 eForth "Modular Build" feature: `make depend` fetches the STM8 eForth release defined in the `Makefile`. On a Linux system common dependencies are e.g. GAWK, MAKE and Python. SDCC needs to be installed. It's also possible to use `tg9541/docker-sdcc` in a Docker container (refer to `.travis.yml` for details). @@ -70,7 +72,7 @@ Please refer to the [Installation Instructions](https://github.com/TG9541/stm8ef ## Console -While MODBUS communication uses the STM8S UART, the Forth console communicates through a half-duplex simulated RS232 interface through the `PD1/SWIM` GPIO pin (and a diode). This is made possible by the SWIMCOM STM8 eForth "stock binary" which the makefile pulls from the STM8 eForth Releases. Other CLI communication options, e.g. using simulated full-duplex RxD-TxD lines, require building a custom STM8 eForth binary. +While MODBUS communication uses the STM8S UART, the Forth console communicates through a half-duplex simulated RS232 interface through the `PD1/SWIM` GPIO pin (and a diode). This is made possible by the SWIMCOM STM8 eForth "stock binary" which the makefile pulls from the STM8 eForth Releases. Other CLI communication options, e.g. using simulated full-duplex RxD-TxD lines, require building a custom STM8 eForth binary. It's also possible to use an STM8S High Density device with two UARTs like the STM8S207RBT6. Please refer to the [STM8 eForth Wiki](https://github.com/TG9541/stm8ef/wiki/STM8S-Value-Line-Gadgets#other-target-boards) to learn more about half-duplex CLI communication options and preferred terminal programs. @@ -81,12 +83,14 @@ The software architecture separates hardware abstraction and application in simp Layer|Source file|Description -|-|- 5|`main.fs` or `{BOARD}/board.fs`|configuration and application layer -4|`MBSERVER`|MODBUS FC plug-ins +4|`MBSERVER`|MODBUS FC plug-ins (optional) 3|`MBPROTO`|MODBUS protocol layer 2|`UARTISR`|buffered UART communication 1|`BUSCTRL`|bus access (i.e. RS485 direction control) 0|STM8 eForth|lightweight interactive multi-tasking OS +The different concerns are separeted in the code and FC handlers can be changed through the CLI without restarting the application! + The code is organized in the following execution domains: * interrupt service routines for buffered MODBUS communication * fixed-rate background task for I/O logic (asynchronous to MODBUS) @@ -94,6 +98,4 @@ The code is organized in the following execution domains: * foreground command line interface (CLI) through independent COM port provided by STM8 eForth * handlers for MODBUS I/O: `mbpre` for input, `mbact` for output actions -The different concerns are separeted in the code - FC handlers can be changed through the CLI without restarting the application! - Please refer to the [how-to in the wiki](https://github.com/TG9541/stm8ef-modbus/wiki/HowTo) and don't hesitate to open an [issue](https://github.com/TG9541/stm8ef-modbus/issues) if you have questions!