Skip to content

Instantly share code, notes, and snippets.

@TG9541
Last active December 5, 2021 15:15
Show Gist options
  • Save TG9541/fe63109242bf18a37853691197c2dd0b to your computer and use it in GitHub Desktop.
Save TG9541/fe63109242bf18a37853691197c2dd0b to your computer and use it in GitHub Desktop.
1-Wire Primitives for STM8 eForth

Devices and chips that use the Dallas/Maxim 1-Wire protocol, e.g. iButton have been around since the 1990s. The DS18B20 temperature sensor is still very popular (although it's more likely that you get one of its clones).

This page contains 1-Wire primitives for STM8 eForth. Higher level words, e.g. ROM scanning or the DOW-CRC8 will be added when required.

\ STM8 eForth "1-Wire" communication primitives

\res MCU: STM8S103
\res export PB_DDR PB_IDR
#require ]B!
#require ]B?
#require ]CB
#require ]BC
#require :NVM
#require ALIAS

: gpio.d ( -- a c ) PB_DDR 4 ;  \ literals for DDR GPIO
: gpio.i ( -- a c ) PB_IDR 4 ;  \ literals IDR GPIO

:NVM ( -- )    \ GPIO low / dominant
  [ 1 gpio.d ]B!
;RAM ALIAS 1w.l

:NVM ( -- )    \ GPIO floating / input
  [ 0 gpio.d ]B!
;RAM ALIAS 1w.f

:NVM ( n -- )  \ wait n x 2us @16MHz
  FOR [ $9d9d , $9d9d , $9d9d , $9d C, ] NEXT
;RAM ALIAS x2us

NVM
  : 1w.res ( -- f ) \ 1-wire reset with presence check
    1w.l 240 x2us  1w.f 30 x2us  [ gpio.i ]B? NOT 210 x2us
  ;

  : 1w.t ( c -- c ) \ 1-wire transfer c -> c
    7 FOR
      1w.l  1 x2us
      [ $6401 ,       \   SRL (1,X)
        $8C  C,       \   CCF
        gpio.d ]CB  3 x2us  [ gpio.i ]BC
      [ $76  C, ]     \   RRC (X)
      12 x2us
      1w.f  1 x2us
    NEXT EXG
  ;
RAM

Using these primitives the data can be exchanged with a 1-Wire node quite easily:

VARIABLE RomID 14 ALLOT

RomID 16 ERASE

: 1w.readrom
  1w.res
  $33 1w.t drop
  7 for
    $ff 1w.t
    [ RomID 7 + ] LITERAL I - C!
  next
  RomID 10 DUMP
;

The 1-Wire Search Algorithm in Maxim app-note 187 requires factoring 1w.t. There should be an implementation in "1wire.frt" by Brad Rodriguez but that appears to have dropped out of the web.

The following implementation of the well known CRC8 for 1-Wire is going to be added to the STM8 lib folder:

\ STM8 eForth: CRC8, polynomial x8 + x5 + x4 + 1
\ refer to github.com/TG9541/stm8ef/blob/master/LICENSE.md

\ implementation for 1-wire protocol

: CRC8 ( crc c -- crc ) [   \  DOW-CRC8
  $A608 ,    \     LD	  A,#8     ; loop through 8 bits
  $F7  C,    \     LD	  (X),A    ; use MSB as bit counter 
  $E601 ,    \     LD	  A,(1,X)  ; 
  $E803 ,    \ 1$: XOR 	A,(3,X)  ; crc XOR c.bit0
  $46  C,    \     RRC	A        ; to carry
  $E603 ,    \     LD	  A,(3,X)  ; crc -> A
  $2402 ,    \     JRNC	0$
  $A818 ,    \     XOR	A,#0x18  ; apply x5 + x4
  $46  C,    \ 0$: RRC	A        ; apply x8 + 1
  $E703 ,    \     LD	  (3,X),A  ; update crc value
  $6401 ,    \     SRL  (1,X)    ; next c.bit0
  $E601 ,    \     LD	  A,(1,X)
  $7A  C,    \     DEC	(X)      ; bit counter until 0
  $26ED ,    \     JRNE	1$       ; loop?
  $5C  C,    \     INCW X        ; DROP
  $5C  C,    \     INCW X
] ;

\\ Test

\ DALLAS MAXIM AN937 Figure 3 Example Calculation for DOW CRC
HEX 0 2 CRC8 1C CRC8 B8 CRC8 1 CRC8 0 CRC8 0 CRC8 0 CRC8 . DECIMAL \ -> A2
\ STM8 eForth 1-Wire DS18B20, simple implementation without ROM search
\res MCU: STM8S103
\res export PB_DDR PB_IDR
#require ]B!
#require ]B?
#require ]CB
#require ]BC
#require :NVM
#require ALIAS
: gpio.d ( -- a c ) PB_DDR 4 ; \ literals for DDR GPIO
: gpio.i ( -- a c ) PB_IDR 4 ; \ literals IDR GPIO
:NVM ( -- ) \ GPIO low / dominant
[ 1 gpio.d ]B!
;RAM ALIAS 1w.l
:NVM ( -- ) \ GPIO floating / input
[ 0 gpio.d ]B!
;RAM ALIAS 1w.f
:NVM ( n -- ) \ wait n x 2us @16MHz
FOR [ $9d9d , $9d9d , $9d9d , $9d C, ] NEXT
;RAM ALIAS x2us
NVM
: 1w.res ( -- f ) \ 1-wire reset with presence check
1w.l 250 x2us 1w.f 30 x2us [ gpio.i ]B? NOT 250 x2us
;
: 1w.t ( c -- c ) \ 1-wire transfer c -> c
7 FOR
1w.l 2 x2us
[ $6401 , \ SRL (1,X)
$8C C, \ CCF
gpio.d ]CB 3 x2us [ gpio.i ]BC
[ $76 C, ] \ RRC (X)
11 x2us
1w.f 1 x2us
NEXT EXG
;
: 1w.w ( c -- ) \ 1w-write-byte
( c ) 1w.t drop
;
: 1w.com ( c -- ) \ command with 1w-reset
1w.res DROP 1w.w
;
: 1w.r ( -- c ) \ 1w-read
$FF 1w.t
;
VARIABLE RomID 6 ALLOT
: 1w.readrom ( -- ) \ 1w-read-rom from single-sensor to var RomID
$33 1w.com
7 FOR
1w.r
[ RomID 7 + ] LITERAL I - C!
NEXT
;
: 1w.match ( a_id -- ) \ 1w-match ROM-id at a_id
$55 1w.com
( a ) 7 + 7 FOR
DUP I - ( ai ) C@ 1w.w
NEXT
DROP
;
: 1w.skip ( -- ) \ 1w-skip, can replace 1w.match for single sensor
$CC 1w.com
;
: 1w.conv ( -- ) \ 1w-convert matched sensor
$44 1w.w
;
VARIABLE Scratch 7 ALLOT
: 1w.scratch ( -- ) \ read scratchpad from matched sensor
$BE 1w.w 8 FOR
1w.r
[ Scratch 8 + ] LITERAL I - C!
NEXT
;
: 1w.sens ( -- c c ) \ read sensor value from matched sensor
$BE 1w.w
1w.r 1w.r ( l h ) EXG OR
;
RAM
\\ Example
1w.readrom \ read ROM of single sensor to RomID
RomID 8 DUMP \ show ROM Id, should start with $28
\ example for fixed/known sensor ID
CREATE MYSENSOR $28 C, $88 C, $16 C, $76 C, $E0 C, $01 C, $3C C, $0A C,
: testid ( a_id -- )
DUP 1w.match 1w.conv
1w.match 1w.scratch
scratch 9 DUMP
;
RomID testid \ read the full scratchpad
: testsingle ( -- n )
1w.skip 1w.conv
1w.skip 1w.sens
;
testsingle . \ conversion takes 750ms, so better repeat this
@TG9541
Copy link
Author

TG9541 commented Mar 4, 2021

Also check out the 1-Wire-Advanced Gist that uses the CamelForth "onewire.f" solution.

@TG9541
Copy link
Author

TG9541 commented Dec 5, 2021

I added an improved implementation 1W-DS18B20.fs with the essential commands for getting temperature readings out of a DS18B20 sensor. The timing has also been improved since PulseView (but not sensors) complained that the "low time" was too short. It's now been increased from 2µs to 4µs.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment