The talk in the Forth2020 User-Group Zoom meeting 2022 #24 about using STM8 eForth for MODBUS nodes is here on YouTube.
If you wish to replicate the demo you should clone the STM8 eForth MODBUS code on GitHub and follow the instructions there. The code below should be placed in the root folder of this cloned repository with the indicated names.
If you have questions, please either join the Forth2020 group or open a GitHub Issue in the stm8ef-modbus repository.
This the base code with the MODBUS protocol handler loaded first (save as base):
\ STM8EF-MODBUS base protocol code
\ Show free memory for STM8 devices with 8K Flash memory
NVM
: FREE ( -- )
CR ." Free NVM:" $a000 last 2+ @ - . ;
RAM
#require MBPROTO
#require PERSIST
#require WIPE
PERSIST
WIPE
FREE
The MODBUS FC6 (Write Holding Register) demo handler is below. It uses the STM8 eForth console for debug messages (that's possible because the handler runs in the 'IDLE
task and I either operate QModMaster or use the Forth console (save as fc6demo):
\ Minimal MODBUS server with a FC06 "Write Single Register" handler
#require MBPROTO
RAM
#require WIPE
#require MBRESET
MBRESET \ Reset the MODBUS Function Code table
#require :NVM
#require 'IDLE
NVM
#require MBDUMP
VARIABLE myreg
\ --- FC06 handler "Write Single Register"
:NVM ( -- )
\ set myreg as FC6 "HOLDING 0", write address and value to the console
mbp1 0= IF \ mbp1 contains the "holding register" address
mbp2 myreg ! \ mbp2 contains the value
." myreg "
ELSE
." register " mbp1 .
THEN
." =" mbp2 . CR
MBWR \ acknowledge FC06
;NVM ( xt ) 6 FC>XT ! \ register the FC handler
: showfc ( -- )
rtbuf 1+ C@ ." FC:" . CR
1 MBEC \ set error code
;
: init ( -- )
0 myreg !
0 UARTISR \ init UART handler w/ default baud rate
1 mbnode ! \ set node address
[ ' showfc ] LITERAL mbdef ! \ FC default action (optional feature)
[ ' MBDUMP ] LITERAL mbact ! \ show buffers (debug demo)
[ ' MBPROTO ] LITERAL 'IDLE ! \ run MB protocol handler as idle task
CR ." STM8EF-MODBUS FC6 handler demo"
hi
;
' init 'BOOT !
WIPE RAM
The last demo, an IR LED lamp control] through MODBUS uses a version of the STM8 eForth IR-NEC LED lamp control demo slightly modified for the GPIOs available on the terminals of the C0135 relay board (save as irctrl):
\ "W28" IR remote control with NEC protocol for a Chinese "RGBW" LED lamp
\ using an STM8S Low Density device (e.g. STM8S103)
\ IR LED cathode connected to PC6 (TIM1_CH1)
\ C0135 terminal IN4 is PC6, [TIM1_CH1] is an "alternate function
#require WIPE
\res MCU: STM8S103
\res export OPT2
#require OPT!
OPT2 C@ 1 ( ) OR OPT2 OPT!
WIPE
\res export TIM1_CR1 TIM1_IER TIM1_SR1 TIM1_BKR TIM1_CCER1
\res export TIM1_ARRH TIM1_CCMR1 TIM1_CCR1H INT_TIM1 OPT2
\ TIM1 bit constants
0 CONSTANT UIE
0 CONSTANT CC1E
7 CONSTANT MOE
#require WIPE
#require :NVM
#require ALIAS
#require ]B!
#require >REL
\ ( carry-flag ) IF with relative addressing
: ]CFIF ( -- ) $24 C, ] >REL ; \ JRNC rel
NVM
VARIABLE mrk \ mark duration in 1/38kHz pulses
VARIABLE spc \ spc duration in 1/38kHz pulses
VARIABLE bcnt \ bit counter
VARIABLE sreg 2 ALLOT \ IR send register for ISR
\ IR-NEC pattern ISR triggered by TIM1 Update Event
:NVM
SAVEC
[ 0 TIM1_SR1 UIE ]B! \ clear interrupt
mrk @ ?DUP IF
[ 1 TIM1_CCER1 CC1E ]B! \ mark: enable 38 kHz PWM
1- mrk !
ELSE
[ 0 TIM1_CCER1 CC1E ]B! \ space: disable 38 kHz PWM
spc @ ?DUP IF
1- spc !
ELSE
bcnt @ ?DUP IF
1- bcnt !
24 mrk ! [ \ 0.65 ms mark
\ rotate right bit pattern - NEC protocol is LSB first
$36 C, sreg 3 + C, \ RRC sreg+3 ; (zero page addressing)
$36 C, sreg 2 + C, \ RRC sreg+2
$36 C, sreg 1 + C, \ RRC sreg+1)
$36 C, sreg C, \ RRC sreg
]CFIF
60 spc ! \ carry flag set: spc 1.6ms
ELSE
19 spc ! \ carry flag clr: spc 0.5ms
THEN
THEN
THEN
THEN
IRET
[ OVERT ( xt ) INT_TIM1 !
\ Init TIM1 for 38kHz ticker interrupt and 50 duty PWM output
: IRINIT ( -- )
$60 TIM1_CCMR1 C! \ PWM mode 1
421 TIM1_ARRH 2C! \ 38kHz @ 16MHz HSI
210 TIM1_CCR1H 2C! \ 50% duty cycle
[ 1 TIM1_BKR MOE ]B! \ main output enable
[ 1 TIM1_CCER1 CC1E ]B! \ Capture Compare output enable (CC1E)
[ 1 TIM1_CR1 UIE ]B! \ enable timer
[ 1 TIM1_IER UIE ]B! \ enable timer update interupt
;
\ turn c into MSB, complement LSB
:NVM ( c - n ) [
\ 256 OVER * SWAP NOT 255 AND OR
$E601 , \ LD A,(1,X)
$6301 , \ CPL (1,X)
$F7 C, \ LD (X),A
;NVM ( xt ) ALIAS NECinv
\ send NEC-IR code with W28 remote control timing
: IR ( c -- )
[ 0 TIM1_CR1 UIE ]B! \ disable timer interrupt
0 NECinv sreg ! \ the W28 remote control uses address 0
( c ) NECinv sreg 2+ !
342 mrk ! \ 9ms AGC pulse (first mark)
171 spc ! \ 4.5ms leader pause (first space)
33 bcnt ! \ NEC: 33 mark/space events
[ 1 TIM1_CR1 UIE ]B! \ enable timer interrupt
;
\ wait until the IR code transmission has ended
: IRW ( -- )
BEGIN bcnt @ 0= UNTIL
;
RAM
\\ Example:
\ -----------|----------|---------|----------
\ 5 bright | 4 dim | 6 off | 7 on
\ -----------|----------|---------|----------
\ 9 red | 8 green |10 blue |11 white
\ -----------|----------|---------|----------
\ 13 red1 |12 green1 |14 blue1 |15 cf-col
\ -----------|----------|---------|----------
\ 21 red2 |20 green2 |22 blue2 |23 cr-col
\ -----------|----------|---------|----------
\ 25 red3 |24 green3 |26 blue3 |27 flash
\ -----------|----------|---------|----------
\ 17 red4 |16 green4 |18 blue4 |19 cs-col
\ -----------|----------|---------|----------
IRCTRL
7 IR \ lamp on
10 IR IRW 11 IR \ flash blue, then white
6 IR \ lamp off