TG9541 / stm8ef

STM8 eForth - a user friendly Forth for simple µCs with docs
https://github.com/TG9541/stm8ef/wiki
Other
308 stars 66 forks source link

[Q] Modbus and push button on C0135 #238

Closed bademux closed 5 years ago

bademux commented 5 years ago

Hello, I'm looking for easy way control relay (220V load) with modbus and input pins (push buttons) on C0135 board. As far as I understand I need to implement modbus and handling push buttons with GPIO? Is it possible\worth with stm8ef?

Thanks for great project.

TG9541 commented 5 years ago

Hi :-)

There are plans to implement the MODBUS RTU protocol. My problem has been creating a test setup.

Is my understanding right that you're talking about a MODBUS endpoint based on the C0135 board and not a MODBUS master?

Otherwise, what's the role of Forth (e.g. local logic, fallback-behavior)?

bademux commented 5 years ago

Thanks for your response!

Lets me describe the problem I want to solve:

Got: 
- Openhab Server  with USB-to-RS485 dobgle  (Modebus master plugin).
- 6x bunch of push buttons and twisted pair cables nearby.
- 6x 220V loads to be on\off
Goal:
- to be able to change the state of relay with Openhab Server and push button simultaiously, 
so the server can track curret state.

From what I know INT1-4 are read only by default on C0135 (I don't have C0135 yet). My question is how much should be done to solve my problem using C0135. From my understanding the list for tasks to be done:

  1. Modebus slave
  2. Handling INT1-4
TG9541 commented 5 years ago

I browsed the openHAB MODBUS docs: what surprised me is that there doesn't seem to be the notion of a bus, just that of a MODBUS device connected to an RS485 interface with specific parameters (otherwise it looks like a nice piece of software!).

If that's the case (please check!) two C0135 devices would have to be connected to two independent RS485 buses.

Otherwise a solution might be to build something using cheap Chinese modules (e.g. 8 relay board, RS485 converter, STM8S103F3P6 module), a couple of resistors and diodes for the inputs, some perfboard, and wires.

Now we come to the software: I've not yet done it but I guess that the implementation of the MODBUS RTU protocol isn't too hard if one has an example and a cheap protocol analyzer (the latter I have). I wanted to implement a UART interrupt handler anyway. What I don't know is if the MODBUS implementation on the openHAB side tolerates some delay when sending RTU replies.

bademux commented 5 years ago

wow, thanks for such great analisis! It is not a problem to update Openhab binding implementation, but hardware\firmware here is a great unknown for me :)

TG9541 commented 5 years ago

Ok then - give me some time - maybe I can hack a MODBUS RTU implementation during the Christmas break :-)

TG9541 commented 5 years ago

Ok, the Modicon Modbus Protocol Reference Guide PI–MBUS–300 Rev. J contains the most useless description of a binary encoding I've ever seen:

When controllers are setup to communicate on a Modbus network using RTU
(Remote Terminal Unit) mode, each 8–bit byte in a message contains two 4–bit
hexadecimal characters.

I double checked: no, the MODBUS RTU protocol doesn't use "two hexadecimal characters" for "each 8-bit byte in a message":

MODBUS RTU trace

This information about timing constraints is relevant:

Each message must be transmitted in a continuous stream.

Regarding endianness I found more information about magic of hexadecimal numbers. However, I infer that RTU is big-endian:

The CRC field is appended to the message as the last field in the message.
When this is done, the low–order byte of the field is appended first, followed by the
high–order byte.  The CRC high–order byte is the last byte to be sent in the
message.
sbridger commented 5 years ago

FYI, Realterm can encode messages with modbus16 crc, on the "send" tab This might help you verify.

TG9541 commented 5 years ago

Thanks, that's cool

I'll have to "steal" my wife's laptop computer, though - maybe I should somehow get a Windows10 machine for such tests.

sbridger commented 5 years ago

Here is the module source, for what its worth (I always find a specific numeric example useful):

{MODBUS CRC-16 ObjectPascal (Delphi) Routine by Panu-Kristian Poiksalo 2003
This function calculates a checksum STRING for a message STRING for maximum
usability for me... example call for this function would be something like...
Examples
$47 03 00 01 00 08 CRC= 1B6A
1 3 0 1 0 1  CRC=D5CA

var message:string;
begin
message:=#1#5#0#0#255#0;
ModbusSerialPort.Output:= message + crc16string (message);
end;

happy coding! send me a greeting at bancho@microdim.net when you get it to
work and share this code freely with everyone at any web site!}
//sjb 12/5/15 change CHR() at end to fix errors.
// 1 3 0 $7E 0 10 = A5 D5 -good (old and new)
// 1 3 0 $81 0 10 = 95 E5 - good ; 3F E5 - bad

unit ModbusCRC;

interface
function ModbusCrc16String(msg:string):string;

implementation

function ModbusCrc16String(msg: string): string;
var
  crc: word;
  n, i: integer;
  b: byte;
begin
  crc := $FFFF;
  for i := 1 to length(msg) do
  begin
    b := ord(msg[i]);
    crc := crc xor b;
    for n := 1 to 8 do
    begin
      if (crc and 1) <> 0 then
        crc := (crc shr 1) xor $A001
      else
        crc := crc shr 1;
    end;
  end;
  result := ansichar(lo(crc)) + ansichar(hi(crc));
end;
end.
TG9541 commented 5 years ago

I'm using lib/CRC16 and the following simple test.

HEX
\ All light: 01 06 00 01 ff ff d9 ba (vendor's MODBUS RTU docs )
-1 $01 CRC16 $06 CRC16 $00 CRC16 $01 CRC16 $FF CRC16 $FF CRC16 . BAD9 ok
\ 1 3 0 $7E 0 10 = A5 D5 -good (old and new)
-1 $01 CRC16 $03 CRC16 $00 CRC16 $7E CRC16 $00 CRC16 $0A CRC16 . D5A5 ok
\ 1 3 0 $81 0 10 = 95 E5 - good ; 3F E5 - bad
-1 $01 CRC16 $03 CRC16 $00 CRC16 $81 CRC16 $00 CRC16 $0A CRC16 . E595 ok

Looks good :-)

Oh, it's been a while since I coded in Turbo Pascal 6 or Borland Pascal 7 - I used to earn my salary with that :-D

My humble routine looks like this:

  : CRC16 ( n c -- n )
  \ CRC-16-ANSI (seed with -1 for Modbus CRC)
    XOR DOXCODE [
      $A608 ,  \         LD      A,#8
      $54 C,   \ 1$:     SRLW    X
      $2407 ,  \         JRNC    2$
      $01 C,   \         RRWA    X   ; XOR X,#0xA001
      $A801 ,  \         XOR     A,#0x01  
      $01 C,   \         RRWA    X
      $A8A0 ,  \         XOR     A,#0xA0
      $01 C,   \         RRWA    X
      $4A C,   \ 2$:     DEC     A
      $26F3 ,  \         JRNE    1$
   ] ;

43 bytes including header, no variables :-)

TG9541 commented 5 years ago

Interrupt driven RxD was easy. I also have the "3.5 character time" trigger for processing in the slave working. The processing runs in the idle task - not sure if that's the right place to put it but it's very convenient for debugging.

Let's see how the next steps will look like.

TG9541 commented 5 years ago

I ran into a problem: the CRC16 test with various examples was successful (see above).

Now I tested processing of received messages with the command line tools mbpoll and modbus-cli. Both programs send a different CRC value than I expected:

 A 10 64 1 2 2A 3D0F 5C9B

  80   A 10 64  1  2 2A 5C 9B  0  0  0  0  0  0  0  0  __d__*\_________ ok

A 10 64 1 2 2A is the data, 5C 9B is the CRC (big endien). 3D0F is what CRC16 gives me if I seed with -1:

DECIMAL -1 HEX A CRC16 10 CRC16 64 CRC16 1 CRC16 2 CRC16 2A CRC16 . 3D0F ok

Something isn't quite right.

TG9541 commented 5 years ago

The current code is here: https://gist.github.com/TG9541/25a0d8e2e68e42d08ecec13c7e9a9981

I'm using a STM8S103F3P6 breakout board and the DOUBLECOM binary.

TG9541 commented 5 years ago

The examples here are correct: CRC high and low bytes have to be swapped (little endian):

DECIMAL -1 HEX 11 r 05 r 04 r  31 r FF r 00 r . 55DE ok

This is the example:

Request

This command is writing the contents of boolean variable  # 1073 to ON
to the slave device with address 17.

11 05 0431 FF00 DE55

11: The Slave Address (11 hex = address17 )
05: The Function Code (Force Single Boolean)
0431: The Data Address of the boolean variable. (0431 hex = 1073 )
FF00: The status to write ( FF00 = ON,  0000 = OFF ) 
DE55: The CRC (cyclic redundancy check) for error checking.

This leaves us with two types of MODBUS masters... What am I missing here?

TG9541 commented 5 years ago

This thread warrants social studies. It appears to me that MODBUS is all about figuring out where programmers confused protocol with memory access. The rest is fruitless discussions about The Right Way to mess things up. It's so entrenched that libmodbus is hardly an exception. Accessing 32 bit values in "registers" (confused with memory) makes "feature requests" like this necessary.

@bademux I'll need your input here. Please provide logs from openHAB MODBUS :-)

bademux commented 5 years ago

@TG9541 thanks for research. From what I understand Openhab modebus plugin can do swap on his side (int64_swap). Looks like it is indeed 2 versions of protocol ASCII and RTU, jamod supports both: "There exist two transmission modes, which differ in encoding, framing and checksum". Threre is "encoding" configuration parameter per slave device in openhab modbus plugin. upd: From what I see RTU is more popular, but ASCII can be more handy for debug\manual input

TG9541 commented 5 years ago

@bademux : I've assumed that we use MODBUS RTU as it appears to be much more popular than MODBUS ASCII. The jamod link you provided describes what kind of problems are to be expected when using that implementation (the 1.5 Character Time upper bound for serial transmission inter character delay is maybe problematic for anything that's JAVA based).

The best way to proceed, I guess, is to actually use openHAB to produce MODBUS RTU requests.

TG9541 commented 5 years ago

@bademux helped me to locate the problem: there is nothing wrong with openHAB/JAMOD or Python libmodbus (mbpoll and modbus-cli): the problem was that ?RX uses the STM8 eForth atokey which doen't take 0x00 for an input... my bad.

The MODBUS reveive Gist has been updated!

TG9541 commented 5 years ago

I've got bidirectional communication with ISR chains and RS485 access control working. STM8 UART TX handlers are a bit peculiar. The gist is here.

TG9541 commented 5 years ago

I tested the timing of the UARTISR code at 115200 baud by transmitting the 4 char sequence ABBB with start-tx and looping UART_TX back to UART_RX with a patch wire:

uart-isr

The diagram shows nicely how the TX ISR chain works (double load at spin-up 30µs, spin-down and end-of-transmission 20µs). The RX ISR also takes about 30µs for copying a char to the receive buffer and writing the receive time stamp including buffer bounds checking.

My conclusion is that buffered communication with ISRs in STM8 eForth is good up to 115200 baud in full-duplex mode and up to 230400 baud in half duplex mode (e.g. MODBUS). Higher baud rates require optimizations, e.g. assembly instead of the Forth VM for control structures and data flow.

bademux commented 5 years ago

for simle usecases like on\off switches it is more than enough. Thanks!

TG9541 commented 5 years ago

@bademux: that's good progress but we're not there yet :-)

Which MODBUS features will we need (e.g. supported MODBUS function codes, MODBUS registers in EEPROM)?

I can see that for the on/off-switches we'll need some kind of "fail-safe properties" (e.g. how to detect when the MODBUS master is down, how manipulate states locally).

When there are local states we also need to establish a protocol for state information synchronization by the MODBUS master when the connection is active again.

bademux commented 5 years ago

Yes it is good progress. From Modbus it will be register (Discrete Output Coil?). From Manual Switch (a User) I see the scenario: when our uC "listens" Input port for a state change (puch button clicked) then the state of the Relay and state of the Register changed accordingly.

In case of faliure Modbus master reread register one again. The only state in our system is "an variable" inside the uC, so I hope that modbus poll process will keep the state of our device in sync with master. If for some reason our device will be rebooted, then "OFF" state is good default one.

TG9541 commented 5 years ago

This sounds good! Users will observe an immediate reaction, and automation use cases can be handled by the MODBUS master nevertheless. States can even be stored in local EEPROM.

bademux commented 5 years ago

Maybe it is better to store states in RAM? Full turn off smiply resets all and device will start in OFF state.

TG9541 commented 5 years ago

First light with MBTEST:

thomas@w500:~/source/stm8s/stm8ef$ mbpoll -a10 -b 9600 -t4:int /dev/ttyUSB1 -- -1
mbpoll 1.4-8 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright © 2015-2018 Pascal JEAN, https://github.com/epsilonrt/mbpoll
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'mbpoll -w' for details.

Protocol configuration: Modbus RTU
Slave configuration...: address = [10]
                        start reference = 1, count = 1
Communication.........: /dev/ttyUSB1,       9600-8E1 
                        t/o 1.00 s, poll rate 1000 ms
Data type.............: 32-bit integer (little endian), output (holding) register table

Written 1 references.

My test code MBTEST outputs the following:

CRC: -1
SLAVE:  10
FC:  16
R0:  0
R#:  2

 rxbuf: 13
  80   A 10  0  0  0  2  4 FF FF FF FF D7 1F  0  0  0  ________________
 txbuf: 8
  98   A 10  0  0  0  2 40 B3  0  0  0  0  0  0  0  0  ______@_________

This only works for FC 16 but at least it works :-)

The test code runs in an 'IDLE task, which means that it processes stuff when the user doesn't enter commands with the Forth REPL.

I also updated UARTISR.

TG9541 commented 5 years ago

Now it also works with the JAMOD SerialDITest:

thomas@w500:~/source/jamod$ java -cp "target/jamod-1.2.3.OH-SNAPSHOT.jar:target/dependency/*" net.wimpi.modbus.cmd.SerialDITest /dev/ttyUSB1 43 13 11
net.wimpi.modbus.debug set to: null
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2b 02 00 0d 00 0b af c4 
Response: 2b 02 02 0c 14 
Bit 0 = false
Bit 1 = false
Bit 2 = true
Bit 3 = true
Bit 4 = false
Bit 5 = false
Bit 6 = false
Bit 7 = false
Bit 8 = false
Bit 9 = false
Bit 10 = true

The STM8 eForth console output is this:

SLAVE:  43
FC:  2
R0:  13
R#:  11

 rxbuf: 8
  80  2B  2  0  D  0  B AF C4  0  0  0  0  0  0  0  0  +_______________
 txbuf: 7
  98  2B  2  2  C 14 A5 71 4E  0  0  0  0  0  0  0  0  +_____qN________

I updated MBTEST.

MODBUS has a way to keep a programmers busy by using 1 and 0 as index for the first element in a seemingly random way.

Edit: I guess that an implementation for an 8bit µC with 8K Flash will be allowed certain implementation gaps (e.g. reject input indices that are not multiples of 8, and always serve 8 inputs per byte). It's not like we're building a generic standard compliant product, and something will go terribly wrong because we don't know how to use it, right?

TG9541 commented 5 years ago

modbus-fc

FC Description Input Output Support?
1 Read Coils A (2 x 16bit) 1a (packed bits as bytes) planned
2 Read Discrete Inputs A (2 x 16bit) 1b (bytes) prototype implemented (limit to 8bit aligned?)
3 Read Holding Registers A (2 x 16bit) 3a (16bit values) planned - define mapping to variables, constants, RAM and EEPROM
4 Read Input Registers A (2 x 16bit) 3b (16bit values) planned (simpler than FC-2)
5 Write Single Coil A (2 x 16bit) 5 (echo A) prototype implemented
6 Write Single (Holding) Register A (2 x 16bit) 5 (echo A) planned (see FC-3)
7 Read Exception Status B (none) 7 (single byte) maybe (looks simple enough to be useful)
8 Diagnostics C (1 x 16bit) P (single 16 bit value) rather not (who will need it?)
11 Get Comm Event Counter A (2 x 16bit) P (single 16 bit value) rather not (who will need it?)
12 Get Comm Event Log B (none) M (16bit values) maybe (looks simple enough to be useful)
15 Write Multiple Coils D1 (2x16bit + n bytes) Q (mirror 16bit inputs) planned (limit inputs to 8bit aligned?)
16 Write Multiple Registers D2 (2x16bit + nx2 bytes ) Q (mirror 16bit inputs) prototype implemented (see FC-3)
17 Report Slave ID B (none) R (n + bytes) maybe (looks simple enough to be useful)
20 Read File Record E (list of list references) S (list of list contents) no
21 Write File Record E (list of list references) T (loop back input D) no
22 Mask Write Register F (3 x 16bit) U (loop back input E) maybe (see FC-3)
23 Read/Write Multiple registers A + D1 M (16bit values) this looks like a catch-all (simple enough but who will need it?)
24 Read FIFO Queue C (1 x 16bit) V (complex data structure) no (our device will be fast enough not to require a FIFO)
43 Encapsulated Interface Transport G (very complex) W (very complex) CANopen over MODBUS? Not unless I get a device with at least 20 times the memory of STM8S003F3P6 and I get payed very well for the pain I'd be bound to suffer in a full-time job.
TG9541 commented 5 years ago

Here is something I'd like to come back to:

If that's the case (please check!) two C0135 devices would have to be connected to two independent RS485 buses.

I think it's possible to create a distributed MODBUS slave, that is a number of nodes on the same bus that interpret the register address as an extended node identification. These would only answer to input, coil and holding r/w which they are responsible for. The shared bus would allow for a distributed error reaction when none of the nodes that share a MODBUS ID sends a regular response.

bademux commented 5 years ago

It's not like we're building a generic standard compliant product, and something will go terribly wrong because we don't know how to use it, right?

Absolutely right - minimal working implementation is one we need.

I think it's possible to create a distributed MODBUS slave, that is a number of nodes on the same bus that interpret the register address as an extended node identification.

I know that modbus allows to have several slave devices identified by their addresses. Msg format: SlaveID|FCode|Data|Crc. That way we will be compatible with other modbus devices.

TG9541 commented 5 years ago

JAMOD didn't provide a CLI test for MODBUS RTU FC01 "Read Coils" and FC05 "Write Single Coils" so I did some copy-and-paste programming:

I updated MBTEST and implemented FC01 (Read Coils) and FC05 (Write Single Coil).

Here is the test result:

thomas@w500:~/source/jamod$ java -cp "target/jamod-1.2.3.OH-SNAPSHOT.jar:target/dependency/*" net.wimpi.modbus.cmd.SerialCoilsTest /dev/ttyUSB1 43 0 8
net.wimpi.modbus.debug set to: null
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2b 01 00 00 00 08 3a 06 
Response: 2b 01 01 00 
Bit 0 = false
Bit 1 = false
Bit 2 = false
Bit 3 = false
Bit 4 = false
Bit 5 = false
Bit 6 = false
Bit 7 = false
thomas@w500:~/source/jamod$ java -cp "target/jamod-1.2.3.OH-SNAPSHOT.jar:target/dependency/*" net.wimpi.modbus.cmd.SerialDOTest /dev/ttyUSB1 43 1 true
net.wimpi.modbus.debug set to: null
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2b 05 00 01 ff 00 da 30 
Response: 2b 05 00 01 ff 00 
thomas@w500:~/source/jamod$ java -cp "target/jamod-1.2.3.OH-SNAPSHOT.jar:target/dependency/*" net.wimpi.modbus.cmd.SerialCoilsTest /dev/ttyUSB1 43 0 8
net.wimpi.modbus.debug set to: null
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2b 01 00 00 00 08 3a 06 
Response: 2b 01 01 01 
Bit 0 = true
Bit 1 = false
Bit 2 = false
Bit 3 = false
Bit 4 = false
Bit 5 = false
Bit 6 = false
Bit 7 = false
TG9541 commented 5 years ago

I did a test with the original relay board firmware. The programmer didn't care about the timing requirements, or didn't bother reading the protocol specification:
c0135-mb-origfw To use the board with that firmware a MODBUS client must switch from TX to RX in about 150µs - that's sporty: even at 115.2kbaud the "3.5 char times" requirement equals 300µs. In any case, cheap RS485-serial adapters that require a quiet phase for switching from TX to RX won't work.

Another observation: the FC02 "Read Discrete Inputs" implementation is quirky:

thomas@w500:~/source/jamod$ java -cp "target/jamod-1.2.3.OH-SNAPSHOT.jar:target/dependency/*" net.wimpi.modbus.cmd.SerialDITest /dev/ttyUSB0 1 0 8
01 02 00 00 00 07 39 c8 
Response: 01 02 02 02 02 
Bit 0 = false
Bit 1 = true
Bit 2 = false
Bit 3 = false
Bit 4 = false
Bit 5 = false
Bit 6 = false
Bit 7 = false

The response should, of course, have been 01 02 01 02, not 01 02 02 02 02.

Another observation: the inputs are low-side (or "NPN" as the automation people say). That makes sense since switches can be connected directly. One should, however, be careful with of-the-shelf inductive sensors for automation: a disconnect of the sensor ground may destroy the µC on the board.

Some more observations:

TG9541 commented 5 years ago

Here is a general MODBUS protocol handler with the following features:

By the way: there must be a bug in JAMOD: it doesn't take "no" for an answer. MBPOLL handles exception codes correctly, so I don't think that the problem is at my side.

TG9541 commented 5 years ago

Next step, here is a (very simple) MODBUS server implementation that handles FC01 and FC05 (and that has dummies for FC02 and FC16).

The implementation works but some more factoring would be beneficial, and exception codes, e.g. for out-of-range parameters, should be implemented.

That shouldn't be a big problem, though: the complete MODBUS server (including protocol and buffered UART) currently fits in 1341 bytes Flash memory: in SWIMCOM there is still 2007 bytes free.

TG9541 commented 5 years ago

I updated UARTISR: the baud rate is now selectable from 2400 to 230400 baud. An update of the STM8 eForth core will follow since it's advantageous to export some more constants that describe a target architecture (a.k.a. BOARD).

TG9541 commented 5 years ago

I factored out the basic processing of the core FCs functional programming style:

  \ process MB in (xt) steps with bpu bit per increment
  : mbreply ( xt bpu -- )
    mbp2 * 1- 8 / 1+ txc+
    mbp1 mbp2 OVER + SWAP  DO 
      ( xt ) I OVER EXECUTE ( inc )
    +LOOP
    DROP
  ;

The reply loop "mbp2 units starting from mbp1 with bpu bits per unit" gets loop increments inc from the access function that's passed in as xt (execution token, in STC Forth a code address).

This way at least FC01, FC02, FC03 and FC04 can be implemented with just describing core functionality:

 :NVM  ( i -- 1 )  \  FC03 holding register transfer 
    2* holding + @ tx+
    1 ( inc )
  ;RAM ( xt ) NVM

  \ FC03 handler "Read Holding Registers"
  : FC03 ( -- )
    ( xt ) LITERAL 16 ( xt bpu ) mbreply
  ; 

For now I only allow bit addressed FCs with byte-aligned start addresses. Changing that shouldn't be too difficult.

  :NVM  ( i -- 8 )   \  FC01 coils register transfer
    8 / coils + 1 XOR ( BE -> LE ) @ txc+
    8 ( inc )
  ;RAM ( xt ) NVM

  \ FC01 handler "Read Coils"
  : FC01 ( -- )
    ( xt ) LITERAL 1 ( xt bpu ) mbreply
  ;

Mapping functionality to FCs is now reduced to assigning a "bit per unit" value and a "loop action" execution token for the copy function. The handler can then take care of plausibility tests.

I think that with minor modifications the method can also be used to implement write operations like FC15, FC16 and to read-write FC23.

TG9541 commented 5 years ago

The main functionality is now implemented with working handlers for FC01, FC02, FC03, FC04, FC05, FC15 and FC16.

The code is really dense but, as I think, very maintainable. The MODBUS server (including buffered UART ISR routines) requires less than 400 lines of code and 1365 bytes of Flash memory (with 1983 bytes free). I used SWIMCOM, which is a "full featured" STM8 eForth binary - a custom binary for MODBUS could be smaller by at least 600 bytes.

What's still missing is range checks (and the evaluating the MODBUS server ID ;-) ). Not a biggie, maybe 20 lines of code and less than 200 bytes of Flash memory.

In any case, there is plenty of space for any kind of application software software, and maybe also for a console with a MODBUS compatible transport. I should better open a repository for that :-)

bademux commented 5 years ago

MODBUS is work in proress feature as for now. The tiket can be closed.

TG9541 commented 5 years ago

There is now a GitHub repository for MODBUS with STM8 eForth! https://github.com/TG9541/stm8ef-modbus