\documentclass[11pt,a4paper]{article}

% 2006-07-04 EW Adventures-1.tex

% needs to be first for some reason
\usepackage{epsfig}
%\psfigurepath{./images}

% language support
\usepackage[german]{babel}

%\usepackage[latin1]{inputenc} % can use Umlauts now ü instead of ü
\usepackage{pslatex} % use native PostScript fonts

\usepackage{url} % \url{} \path{} with correct "hyphenation"
\usepackage{fancyvrb} % for code examples

% \voffset-10mm
% \pagestyle{empty}
% \pagestyle{plain}
% \pagestyle{headings}
% \renewcommand{\baselinestretch}{1.08}
\usepackage{xspace}
\parindent=0pt
%\newcommand{Forth}{\textsc{forth}\xspace}
\begin{document}


\title{Adventures in Forth}

\author{Erich Wälde}

\maketitle

\begin{multicols}{2}

Bevor ich vergesse, wie es am Anfang war, schreib ich mal ein bisschen auf, wie
es mir ergangen ist, seit ich meine Nase in Forth gesteckt habe.

Am Linuxtag 2006 in Wiesbaden hatte ich den Renesas r8c/13--Mikrokontroller
in Forth--Aktion gesehen. Den Kontroller auf dem Elektor--Platinchen hatte
ich noch zu Hause, und so hatte ich endlich eine sinnvolle Verwendung
dafür. Allerdings habe ich das Entwicklungsboard (von Elektor, \ref{elektor}) und ein 
16x2--LCDisplay dazugekauft.


\section{Installation}

Das Wiki von Bernd Paysan (\ref{wiki}) führte mich zu den nötigen Zutaten
\begin{enumerate}
\item \texttt{gforth}
\item \texttt{libffcall}
\item \texttt{m16c\_flasher} von Thomas Fischl
\end{enumerate}

Eine etwas ältere Version von gforth war auf meinem Rechner schon
installiert:

\begin{verbatim}
$ dpkg -l gforth
ii  gforth         0.6.2-6        GNU Forth
Language Environment
\end{verbatim}

% $ der Dollar ist nur um fontlock-mode zufriedenzustellen

Die Installation der libffcall war zwar einfach, aber wie gforth
beim Installieren davon Wind bekommt, das war nicht ganz
offensichtlich, weil ich diese Dinge in meinem HOME--Verzeichnis
installiert hatte. Mit ein paar zusätzlichen Umgebungsvariablen
lässt sich das aber lösen ('\$' ist der shell prompt):


\begin{verbatim}
$ wget ftp://ftp.ilog.fr/pub/Users/haible/gnu/
ffcall-1.8.tar.gz
$ tar xvf ffcall-1.8.tar.gz
$ export CC=gcc-3.4
$ cd ffcall-1.8
$ ./configure --prefix=$HOME
$ make
$ make install
$ cd ..
\end{verbatim}

\begin{verbatim}
$ cvs -d :pserver:anonymous@c1.complang.tuwien.
ac.at:/nfs/unsafe/cvs-repository/src-master co
gforth
$ export CFLAGS=-I$HOME/include
$ export LDFLAGS=-L$HOME/lib
$ cd gforth
$ export GFORTH=/usr/bin/gforth
$ export GFORTHPATH=$PWD:/usr/lib/gforth/0.6.2
$ ./BUILD-FROM-SCRATCH --prefix=$HOME
$ ./build-ec r8c
$ cd ..
\end{verbatim}

\begin{verbatim}
$ wget http://www.fischl.de/thomas/elektronik/
r8c/m16c_r8c_flash.2005-11-20.tar.gz
$ tar xzvf  ~/Forth/m16c_r8c_flash.2005-11-20.
tar.gz
$ cd m16c_flash
$ make clean
$ make
$ cd ..
\end{verbatim}
% $

\texttt{BUILD-FROM-SCRATCH} blieb bei mir irgendwann hängen, aber \texttt{gforth}
wurde davor erzeugt, so dass \texttt{./build-ec r8c}
erfolgreich läuft.


Das frisch gebackene \texttt{rom-r8c.mot} muss jetzt auf den
Kontroller. Dazu verbindet man den Kontroller entweder direkt mit
der seriellen Schnittstelle (s. Elektor 01/2006) oder über das
dazugehörige Entwicklungsboard. Eine Stromversorgung und das
Ansteuern des MODE--Pins zum Programmieren gehört dazu, Details
finden sich in den erwähnten Artikeln. Angenommen, die serielle
Schnittstelle des Entwicklungsrechner wäre
\texttt{/dev/ttyUSB0}, dann geht das Programmieren des
Kontrollers so:

\begin{verbatim}
<Mode-Pin-erden>
<Reset-Taste-drücken>
$ ./m16c_flash/flash /dev/ttyUSB0 R8C ./gforth/
rom-r8c.mot ff:ff:ff:ff:ff:ff:ff
<Mode-Pin-befreien>
<Reset-Taste-drücken>
\end{verbatim}
%$


über die gerade eben schon verwendete serielle Schnittstelle kann
man sich jetzt mit dem Kontroller verbinden, z.B. mit minicom.
Die Einstellungen sind dann \texttt{/dev/ttyUSB0},
 38400 baud, 8 Datenbits, kein Paritätsbit, 1 Stopbit (8N1).
Wenn alles funktioniert, erhält man auf Drücken der Return--Taste
\verb+<RET>+ die Antwort "`\texttt{ok.}"'

\begin{verbatim}
minicom
... start message ...
<RET>
ok.
\end{verbatim}
%$


Siehe auch den Diskussionsthread unter \ref{thread_install} für Hinweise.

% ----------------------------------------------------------------------
\section{Erste Versuche}

Für die ersten Versuche (blinken mit den LEDs, etwas auf das Display
schreiben) finden sich Beispiele im Wiki (\ref{wiki}).

Über Forth selbst sind die Dokumentation von gforth sowie die Bücher
``Starting Forth'' und ``Thinking Forth'' (Leo Brodie) sehr gute Quellen.
Zu beiden Büchern gibt es Webseiten (\ref{startingforth}, \ref{thinkingforth}).
Auch der Wikipedia--Artikel zu Forth (\ref{wikipediaforth}) 
ist meiner Meinung nach recht gut.

% ----------------------------------------------------------------------

\section{\texttt{rom} und \texttt{ram}}

aus dem Wiki:

\begin{quote}
Das Forth  \ldots legt selbstdefinierte Programme per
Default im (sehr knappen) RAM ab. Umschalten zwischen RAM und ROM mit den
Wörtern ram und rom.
\end{quote}

ROM ist das Flashrom des Kontrollers, es ist größer als das RAM. Daher
kann man Forth--Programme ins ROM speichern:

\begin{verbatim}
rom
... hier kommt das programm hin
ram
savesystem
\end{verbatim}


\texttt{savesystem} speichert eine Kopie des RAM--Inhalts ins ROM.
Wenn das Programm im ROM überschrieben werden soll, dann muss
man das ROM erst mit dem Wort \texttt{empty} löschen. Wenn man das
versäumt, oder wenn es nicht richtig funktioniert hat, dann
erhält man beim nächsten Befehl etwas irreführende
Fehlermeldungen, etwa so:

\begin{verbatim}
: foo <<< Undefined word
\end{verbatim}
%>>>

\texttt{empty} und evtl. ein RESET hilft dann normalerweise.
Den Erfolg kann man auch überprüfen mit dem Wort \texttt{dump}, welches
den Speicher\-inhalt ausliest:

\begin{verbatim}
rom
... ein paar Befehle hier
ram
savesystem

$2000 $800 dump
...
empty
$2000 $800 dump
...
\end{verbatim}


Nach dem \texttt{empty} stehen lauter \texttt{FF} im Speicher,
vorher kann man mit etwas Phantasie das Programm wiederfinden.

Das Dollarzeichen `\$' sagt Forth, dass die Zahl dahinter auf
jeden Fall eine Hexadezimalzahl ist, egal welche Basis zur
Eingabe gerade benutzt wird, z.B.\ \$10 = 16. Entsprechend sagt
das Prozentzeichen `\%', dass die Zahl dahinter eine Binärzahl
ist, z.B. \%10001010 = \$8a = 138. Auch für Dezimalzahlen gibt
es ein Zeichen: `\&', welches in den Beispielen im Wiki benutzt
wird.

%----------------------------------------------------------------------

\section{Ein i2c--Device ansteuern}

Als erstes Bastelprojekt, bei dem sich richtig was tut, wollte
ich einen i2c--Baustein ansteuern, welcher 8 digitale IO--Pins
besitzt (PCF8574). Der Bus benutzt 2 Drähte, SDA und SCL
genannt. Die Details stehen im Datenblatt zum PCF8574 oder
beispielsweise in dem Buch ``I2C Bus angewandt''
(\ref{i2cbus_angewandt}) Der R8C--Kontroller soll als ``i2c
master'' funktionieren, d.h., nur er darf den Bus ungefragt
belegen und er gibt bei der Datenübertragung den Takt vor.


Als Erstes werden ein paar Konstanten definiert. Deren Namen sind
aussagekräftiger als die blanken Werte. Sie machen das Programm
besser lesbar. Pin 15 alias P1.0 des Kontrollers gehört zum
ersten Bit von Port 1 und soll die SCL Leitung treiben:

\begin{verbatim}
0 Constant PinSCL
\end{verbatim}

Pin 14 alias P1.1, also das zweite Bit von Port 1 soll die SDA
Leitung treiben:

\begin{verbatim}
1 Constant PinSDA
\end{verbatim}

Für den Port 1 gibt es schon ein Wort (\texttt{port1}), ansonsten hört
der auch auf das Register mit der Adresse \$E1

\begin{verbatim}
port1 Constant PortI2C
\end{verbatim}

Da ich nicht nur auf den Bus schreiben will, sondern auch davon
lesen, muss ich gelegentlich das "`Data Direction Register"' von
Port 1 beschreiben. Deshalb bekommt es ebenfalls einen Namen
statt seiner Registeradresse (\$E3)

\begin{verbatim}
$E3 Constant PddrI2C
\end{verbatim}
%$

Die 7--Bit--Adresse des Portexpanders ist \%010\_0000 oder \$20
hexadezimal. Das Schreiben/Lesen--Bit--w wird hintendran gehängt:
\%010\_0000\_w. Das ist \$20 um eins nach links verschoben + w,
also \$40 + w. Zum Lesen vom Baustein wird diese Adresse um 1
erhöht (\$41).

\begin{verbatim}
$40 Constant i2c_addr_portexpander
\end{verbatim}
%$

Die einfachsten Funktionen (Worte) setzen je einen der beiden
Pins auf 0 oder 1:

\begin{verbatim}
: sda0 PinSDA PortI2C bclr ;
: sda1 PinSDA PortI2C bset ;
: scl0 PinSCL PortI2C bclr ;
: scl1 PinSCL PortI2C bset ;
\end{verbatim}

Diese Worte kann man jetzt schon ausprobieren. Da an diesen
beiden Pins auf der Ergänzungsplatine schon LEDs angeschlossen
sind, kann man sofort sehen, ob es funktioniert. Nach
\texttt{scl0} geht die rechte der 4 LEDs aus, nach \texttt{sda0}
die links daneben.


Um ein Bit zu versenden, müssen wir das Datenbit setzen, ein
bisschen warten, dann SCL auf 1 setzen, wieder ein bisschen warten
und dann SCL zurück auf 0. Ich habe beschlossen, jeden
Clock--Zyklus in 4 Teile zu zerlegen, Die kleinste Wartezeit nenne
ich \texttt{tick} und sie soll eine Mikrosekunde betragen. Damit
dauert ein Clock--Zyklus 4 Mikrosekunden, was lange genug sein
sollte.

\begin{verbatim}
: tick 1 us ;
: 2tick tick tick ;
\end{verbatim}

Man kann tick anfangs auch sehr viel länger wählen, z.B.\
\texttt{250 ms} (Millisekunden), dann kann man den Datenaustausch
an den LEDs \textit{sehen}.
Um ein Bit zu verschicken, erwarten wir das Bit (0 oder 1) auf
dem Stack, IF nimmt es vom Stapel und inspiziert es. Ist es 1
(true), dann wird die Datenleitung ebenfalls auf 1 gesetzt,
andernfalls wird die Datenleitung auf 0 gesetzt.

\begin{verbatim}
IF sda1 ELSE sda0 ENDIF
\end{verbatim}

Danach muss ich den Clock--Impuls erzeugen, und das vollständige
Wort soll \verb+bit>i2c+ heißen:

\begin{verbatim}
\ sende 1 Bit per Clock-Zyklus
: bit>i2c ( bit -- )
    IF sda1 ELSE sda0 ENDIF
    tick scl1 2tick scl0 tick ;
\end{verbatim}

Um ein bestimmtes Bit aus einem gegebenen Byte zu verschicken,
muss ich dieses Bit aus dem Byte extrahieren. Um das Bit Nr.\ i
aus dem Byte x zu erhalten, muss ich das Byte um i Stellen nach
rechts verschieben (\texttt{x i rshift}) und evtl. vorhandene
höherwertige Bits löschen (\texttt{\$01 and}).

\begin{verbatim}
: getBit ( x i -- bit ) rshift $01 and ;
\end{verbatim}
%$

Damit kann ich jedes Bit aus dem Byte einzeln gewinnen. Das lässt
sich schön überprüfen mit

\begin{verbatim}
%00001010 dup . 0 getBit . 10 0  ok
%00001010 dup . 1 getBit . 10 1  ok
%00001010 dup . 2 getBit . 10 0  ok
%00001010 dup . 3 getBit . 10 1  ok
%00001010 dup . 4 getBit . 10 0  ok
\end{verbatim}



Um ein ganzes Byte zu verschicken, muss ich eine Schleife
schreiben, die 8 mal durchlaufen wird.

\begin{verbatim}
8 0 DO ... LOOP
\end{verbatim}

Dabei ist 8 der Grenzwert, 0 der Startwert, und das Wort
\texttt{I} legt den aktuellen Zählerstand auf den Stapel.
\texttt{I} produziert nacheinander die Werte 0 bis 7:

\begin{verbatim}
: 8mal 8 0 DO I . LOOP ;  ok
8mal <RET> 0 1 2 3 4 5 6 7  ok
\end{verbatim}

Allerdings muss das höchstwertige Bit zuerst verschickt werden.
Ich muß also statt $I$ den Wert $8 - (I + 1)$
benutzen:

\begin{verbatim}
: 8mal 8 0 DO 8 I 1+ - . LOOP ; redefined 8mal
   ok
8mal <RET> 7 6 5 4 3 2 1 0  ok
\end{verbatim}

Damit hätte ich alles beisammen, um ein ganzes Byte mit dem
höchstwertigen Bit zuerst zu versenden. Beachte, dass das zu
versendende Byte immer erst dupliziert werden muss, weil es sonst
nach dem ersten Schleifendurchgang verloren ist. Am Ende der
Schleife muss man dann das übriggebliebene Byte mit
\texttt{drop} vom Stapel nehmen.

\begin{verbatim}
\ sende 1 Byte (8 Bit) MSB zuerst
: >i2c ( x -- )
    8 0 DO
        dup 8 I 1+ - getBit
        bit>i2c
    LOOP
    drop ;
\end{verbatim}

Wenn man statt \verb+bit>i2c+ das Bit lediglich ausgibt mit \texttt{.}, dann
erhält man folgende Ausgaben:

\begin{verbatim}
10 >i2c <RET> 0 0 0 0 1 0 1 0  ok
11 >i2c <RET> 0 0 0 0 1 0 1 1  ok
12 >i2c <RET> 0 0 0 0 1 1 0 0  ok
64 >i2c <RET> 0 1 0 0 0 0 0 0  ok
\end{verbatim}


Mit diesen Worten kann ich 1 Byte auf dem Bus verschicken. Soweit
so gut. Davor brauchen wir noch eine Startbedingung, und am Ende
eine Stopbedingung.

\begin{verbatim}
\ sende START, STOP
: i2c_start ( -- ) tick sda0 2tick scl0 tick ;
: i2c_stop  ( -- ) tick scl1 2tick sda1 tick ;
\end{verbatim}

Jetzt fehlt lediglich noch eine Kleinigkeit, nämlich, nach dem
Versenden der Adresse zu überprüfen, ob sich der adressierte
Baustein auch angesprochen fühlt. Dies tut er kund, indem er
beim 9.\ Clock--Impuls die Datenleitung auf low zieht. Ich muss
also die Datenrichtung an SDA umkehren, einen Clock--Impuls
erzeugen und die Leitung lesen, während SCL high ist: \textit{
  (Bei manchen Kontrollern muss man vorher SDA auf 1 setzen, bei
  diesem anscheinend nicht.)}

\begin{verbatim}
\ setze Pin SDA als Eingang / Ausgang
: sdaInput  ( -- ) PinSDA PddrI2C bclr ;
: sdaOutput ( -- ) PinSDA PddrI2C bset ;

\ lies SDA
: readSDA   ( -- bit )
    PinSDA PortI2C btst IF 1 ELSE 0 ENDIF ;

\ lies ACK oder NACK vom Empfänger
: ack<i2c ( -- bit )
    sdaInput
    tick scl1 tick readSDA tick scl0 tick
    sdaOutput ;
\end{verbatim}

Mit diesen Worten kann ich dem Baustein ein Byte `x' schicken.

\begin{verbatim}
 : >portexpander ( x -- )
    i2c_start     \ START
    i2c_addr_portexander >i2c
                  \ Adresse schreiben
    ack<i2c drop  \ ACK lesen und verwerfen
    >i2c          \ Datenbyte schreiben
    ack<i2c drop  \ ACK lesen und verwerfen
    i2c_stop ;    \ STOP
\end{verbatim}

Selbstverständlich kann ich das sofort testen:

\begin{verbatim}
15 >portexpander <RET> ok
\end{verbatim}

Jetzt sollten 4 von den 8 LEDs am PCF8574 leuchten. Wenn man
genau hinschaut, dann stellt man fest, dass die LEDs der 4
höherwertigen Bits leuchten. Das ist richtig, weil die LEDs gegen
+5V geschaltet sind, und ein Pin mit einer Null den Strom durch
die LEDs einschaltet. Oft will man das aber anders sehen, dafür
muss man die Bits des zu verschickenden Bytes invertieren. Dafür
gibt es auch ein Forth--Wort:

\begin{verbatim}
15 invert >portexpander <RET> ok
\end{verbatim}

Jetzt ist alles so, wie's sein soll. Um länger in den Genuss
blinkender LEDs zu kommen, hilft eine Schleife, in der eine
Variable (\texttt{N}) jede Sekunde um 1 erhöht und dann
invertiert auf dem i2c--Portexpander ausgegeben wird. Die
Schleife soll unterbrochen werden, wenn ich eine beliebige Taste
drücke. Die Forth--Worte \texttt{Variable}, \texttt{!} (store),
\texttt{@} (fetch), \texttt{BEGIN \dots{} UNTIL} (Schleife) und
\texttt{key?} (ist eine Taste gedrückt worden?) kommen mir zu
Hilfe:

\begin{verbatim}
Variable N
0 N !
: run
    0 >portexpander
    1000 ms
    BEGIN
        N @
        dup invert >portexpander
        1+ N !
        1000 ms
    key? UNTIL ;
\end{verbatim}

Nach der Eingabe von \texttt{run} sollten auf den LEDs alle
Sekunde ein neuer Wert erscheinen! Das Programm beendet sich,
wenn man eine Taste drückt.

Natürlich kann man das alles von Hand eintippen, aber nach einem
Reset ist erst mal alles verloren. Deshalb schreibe ich eine
Datei \texttt{adv\_01.fs}, in der alle Anweisungen stehen,
eingeklammert mit den Worten \texttt{rom} und \texttt{ram}. Die
Datei kann ich im terminal--Programm mit \texttt{include} an den
Kontroller übertragen und danach die darin definierten Worte
benutzen:


\begin{verbatim}
$ gforth terminal.fs
include adv_01.fs
run
\end{verbatim}
%$

and watch the show!

Das Programm zu diesem Teil befindet sich in der Datei \texttt{adv\_01.fs}.

%----------------------------------------------------------------------
\section{Verbesserungen}

Einen i2c--Baustein in etwa 60 kurzen Zeilen Code anzusprechen,
das finde ich schon bemerkenswert --- auch wenn es bislang ganz
ohne Fehlerbehandlung ist.

\subsection{Adressierung}

Der erste Schritt ist gemacht, ein i2c--Baustein lässt sich zum
Schreiben ansprechen. Ein anderer Baustein lässt sich durch
Auswechseln der Adresse ebenfalls addressieren. Allerdings würde
ich dazu eine Kopie von \texttt{>portexpander} anlegen, in der
nur die Adresse anders ist. Schön ist das nicht. Daher soll das
Wort \texttt{>portexpander} so geändert werden, dass sich die
Adresse auf dem Stapel befindet.

\begin{verbatim}
: send1byte>i2c ( x addr -- )
    i2c_start    \ START
    >i2c         \ Adresse 'addr' senden
    ack<i2c drop \ ACK lesen und verwerfen
    >i2c         \ DatenByte 'x' senden
    ack<i2c drop \ ACK lesen und verwerfen
    i2c_stop ;   \ STOP

15 i2c_addr_portexpander send1byte>i2c
\end{verbatim}

\subsection{Schreiben/Lesen}

Bislang schreibe ich Daten an den i2c--Baustein. Um zu lesen,
brauchen wir analog zu \verb+>i2c+ ein Wort \verb+<i2c+, welches
ein Byte vom Bus liest:

\begin{verbatim}
: <i2c ( -- x )
    sdaInput  \ SDA auf Input schalten
    0         \ Datenbyte auf 0 gesetzt
    8 0 DO    \ Schleife über 8 Bit
        1 lshift
              \ das bisherige Datenbyte um 1
              \ Stelle nach links verschieben
              \ einen Clock-Impuls erzeugen und
              \ das Bit lesen
        tick scl1 tick readSDA tick scl0 tick
        +     \ das Bit zum Datenbyte addieren
    LOOP      \ Ende der Schleife
    sdaOutput ;  \ SDA auf Output
\end{verbatim}




Wenn ich vom Bus Lesen will, dann muss ich den Baustein
adressieren und dabei das Read--Bit setzen. Die Adresse ändert
sich von \verb,($20 << 1) | 0 == $40, auf \verb,($20 << 1) | 1 == $41,.

Wenn man den Baustein direkt lesen kann, dann ist das schon
alles, und einmal lesen sieht etwa so aus:

\begin{verbatim}
: get1byte<i2c ( addr -- x )
    i2c_start    \ START
    >i2c         \ ADRESSE
    ack<i2c drop \ ACK lesen und verwerfen
    <i2c         \ DatenByte _lesen_
    1 bit>i2c    \ NACK _senden_
    i2c_stop ;   \ STOP
\end{verbatim}

Allerdings muss man fast immer nach der Adresse erst einmal ein
Byte schreiben: Das kann ein \textit{Controlbyte} sein, oder die
Adresse im Speicher des Bausteins, von der man die Daten will,
oder die Kanalnummer bei einem AD--Wandler etc. Sogar bei dem
simplen Portexpander muss ich erst mal eine \texttt{1} auf alle
Pins schreiben und dann lesen, damit das Ergebnis zuverlässig
ist.

Die Folge ist dann eben Start, Adresse senden, ACK lesen, das
Controlbyte senden, ACK lesen, danach wird eine repeated--start--Bedingung 
gesendet, dann ein oder mehrere Datenbytes gelesen und
nach jedem gelesenen Byte ein ACK \textit{gesendet}. Nach dem
letzten gelesenen Byte verschickt der i2c--Master ein NACK, also
eine 1 statt einer 0. Damit wird dem adressierten Baustein
mitgeteilt, dass keine weiteren Bytes gelesen werden. Und zum
Abschluss wie immer eine Stopp--Bedingung.

\begin{verbatim}
\ Sende "repeated start"
: i2c_rstart ( -- )
    sda1 tick scl1 tick sda0 tick scl0 tick ;
\end{verbatim}


\subsection{Variable Anzahl von Bytes lesen/schreiben}

Ein Lesevorgang auf dem i2c--Bus besteht also normalerweise aus
dem Verschicken von mindestens einem Controlbyte an die Adresse,
dem Lesen von einem oder mehreren Datenbytes, jeweils gefolgt von ACK
oder NACK. Um das besser programmieren zu können, ändere ich
die Worte \verb+>i2c+ und \verb+<i2c+ so ab, dass sie eine
variable Anzahl von Bytes verschicken können.


\begin{verbatim}
\ verschicke N Bytes nach Adresse addr
\ das "most significant Byte" liegt oben
\ auf dem Stapel
: NB>i2c ( x1 .. xN.msB N addr -- )
    i2c_start \ START
    >i2c ack<i2c drop
              \ ADRESSE senden, ACK lesen
    0 DO      \ Schleife, nimmt N vom Stapel
        >i2c ack<i2c drop
              \   DATA_BYTE verschicken
    LOOP      \ Ende Schleife
    i2c_stop  \ STOP
;

\ Lies N Bytes von Adresse addr
\ das "least significant Byte" liegt
\ danach oben auf dem Stapel
\ Adresse und ControlByte sind schon verschickt
: NB<i2c ( N addr -- xN.msB .. x1 )
  i2c_rstart  \ REPEATED_START
  1+ >i2c ack<i2c drop
             \ ADRESSE | READ senden, ACK lesen
  1- dup 0 > IF
             \ Schleife über N-1 Byte
    0 DO     \   Datenbyte = 0 (initialisieren)
      <i2c 0 bit>i2c
             \   DATA_BYTE lesen, ACK schicken
    LOOP     \ Ende Schleife
  ENDIF
  <i2c 1 bit>i2c
             \ letztes Byte lesen, NACK schicken
  i2c_stop   \ STOP
;
\end{verbatim}

Die Schleife geht hier über $n-1$ Byte, nicht $n$ Byte, weil nur $n-1$
ACK verschickt werden. Man hätte das auch anders lösen können,
aber mir gefällt es so. Ich hätte auch das Versenden von ACK
und NACK getrennt definieren können:

\begin{verbatim}
: ack>i2c  ( -- ) 0 bit>i2c ;
: nack>i2c ( -- ) 1 bit>i2c ;
\end{verbatim}

Aber da diese Stelle nur in \texttt{NB<i2c} vorkommt, erschien es
mir nicht lohnend. Das Lesen vom Portexpander geht dann so:

\begin{verbatim}
: <portexpander ( -- x )
    $ff                     \ ControlByte
    1 i2c_addr_portexpander NB>i2c
    1 i2c_addr_portexpander NB<i2c
;

<portexpander cr . <RET>
255 ok
\end{verbatim}
%$

Jetzt ist es nett und übersichtlich. Zwar muss ich die LEDs
durch eine Schalterleiste auswechseln, sonst kommt immer das
gleiche Ergebnis (255), aber das ist kein Programmierproblem. Das
Programm zu diesem Teil befindet sich in der Datei
\texttt{adv\_02.fs}.

%----------------------------------------------------------------------

\section{Thermometer}

In diesem Teil kommt ein Thermometer mit i2c--Schnittstelle an den
i2c--Bus, welches vom R8C--Kontroller gelesen wird. Das Ergebnis
wird auf dem LCDisplay ausgegeben. Etwa 4 Messungen pro Sekunde
sollen es werden. Der Temperatursensor ist ein LM75, die
Auflösung beträgt 0.5$^{\circ}$C, die Genauigkeit etwa $\pm
2^{\circ}$C. Der Baustein hat die 7--Bit--Adresse \$48, wenn alle
Adressbits auf low sind, und \$4f, wenn alle Adressbits gesetzt
sind. \verb,$4f << 1 == $9e,.

\begin{verbatim}
$9e Constant i2c_addr_lm75
\end{verbatim}
%$

Der LM75 liefert das Ergebnis in 2 Bytes, das höherwertige Byte
(xh) wird zuerst übertragen. Im niederwertigen Byte (xl) ist nur
noch ein Bit gültig, nämlich das höchste. (Beim LM75\textbf{A}
sind es die \textit{drei} höchsten Bits, was einer Auflösung
von 0.125$^{\circ}$C entspricht) Um die Temperatur zu lesen, ist
eine \$00 zu verschicken (pointer register, s.\ Datenblatt), das
entspricht unserem Controlbyte. Mit den oben erarbeiteten Worten
ist das Auslesen des LM75 ein Kinderspiel:

\begin{verbatim}
: get.T ( -- xh xl )
   $00                      \ ControlByte
   1 i2c_addr_lm75 NB>i2c   \ verschicken
   2 i2c_addr_lm75 NB<i2c   \ 2 Byte lesen
;
\end{verbatim}
%$

Um die beiden Bytes in eine Temperatur umzuwandeln, konsultiert
man das Datenblatt. Die 9 Bits bilden eine Zahl mit Vorzeichen,
die von $-55.0$ bis $+128.0$ reicht, in Schritten von $0.5$.

xl liegt oben auf dem Stapel, die 7 ungültigen Bits lösche ich
mit
\begin{verbatim}
$80 and
\end{verbatim}
%$
dann bringe ich xh nach oben
\begin{verbatim}
swap
\end{verbatim}
und rücke das Byte um 8 Stellen nach links
\begin{verbatim}
8 lshift
\end{verbatim}
dann werden die beiden Teile einfach addiert
\begin{verbatim}
+
\end{verbatim}


Das Resultat ist die Temperatur, allerdings um den Faktor 256 zu
groß. Wenn ich das Resultat einfach durch 256 teile, dann
verliere ich die Nachkommastelle. In Forth skaliert man solche
Zahlen mit einem geeigneten Wert. Um eine Nachkommastelle zu
behalten, skaliere ich die Temperatur mit 10. Wenn ich jetzt aber
einfach
\begin{verbatim}
10 * 256 /
\end{verbatim}
hinschreibe, dann ist das Ergebnis dennoch unbefriedigend, weil
das Ergebnis der Operation
\begin{verbatim}
10 *
\end{verbatim}
nur die Größe einer Zelle hat. Ist das Zwischenergebnis größer,
dann verliere ich die höchsten Bits. Zu Hilfe kommt das Forth--Wort 
\texttt{*/} (star--slash), welches ein Zwischenergebnis doppelter
Breite benutzt. Also
\begin{verbatim}
10 256 */
\end{verbatim}
oder
\begin{verbatim}
5 128 */
\end{verbatim}
erzeugen die Temperatur in Einheiten von 1/10 $^{\circ}$C.

\begin{verbatim}
: decode.T ( xh xl -- T*10 )
    $80 and     \ die ungültigen Bits löschen
    swap        \ xh nach oben holen
    8 lshift    \ xh << 8
    +           \ == (xh << 8) + ( xl & 0x80)
    5 128 */ ;  \ == T*10
\end{verbatim}
%$

Versuch macht kluch:

\begin{verbatim}
get.T cr .s decode.T cr . <RET>
<2> 24 255
245  ok
\end{verbatim}

Das sind $24.5^{\circ}$C, soweit so schön. Um die Zahl mit
Nachkommastelle auf das LCDisplay zu schreiben, muss man im
Forth--Buch oder in der Dokumentation von gforth nachlesen. Hier
das Ergebnis ohne große Erklärungen:

\begin{verbatim}
\ _immer_ das Vorzeichen anzeigen, '+' or '-'
: sign! 0 < IF 45 ELSE 43 ENDIF hold ;

\ formatiere T zur Ausgabe mit type or lcdtype
: format.T ( T*10 -- )
    dup >R  \ Kopie fuer das Vorzeichen aufheben
    abs s>d \ Betrag, single in double umwandeln
    \ 1 Ziffer, "." Dezimalpunkt, 2 Ziffern,
    \ Vorzeichen
    \ Zahlen >= 1000 werden VORNE abgeschnitten!
    <# # 46 hold # # R> sign! #> \ == "%+5.1f"
;
\end{verbatim}

Ausprobieren mit
\begin{verbatim}
lcdpage
get.T decode.T format.T lcdtype
\end{verbatim}

Das Thermometer soll ständig laufen, braucht also wieder
eine Schleife. Eine Messung soll 4-mal pro Sekunde sein:

\begin{verbatim}
: thermometer
    BEGIN
        lcdpage
        get.T decode.T format.T lcdtype
    250 ms
    key? UNTIL
;

thermometer
\end{verbatim}

\begin{figure}
\includegraphics[width=1\hsize]{2006-03/img_thermometer1}
\caption{Thermometer--Aufbau}
\end{figure}

Auffällig ist, dass das LCDisplay recht unruhig
{\em flimmert}. Das kommt durch die häufigen Aufrufe von
\texttt{lcdpage}. Besser ist es, ein Wort \texttt{lcdpos} zu schreiben,
welches den Cursor an eine bestimmte Stelle setzt.

\begin{verbatim}
: lcdpos ( row col -- )
    swap $40 * + $80 + lcdctrl! &1 ms ;
\end{verbatim}

Damit kann man \texttt{thermometer} aufbessern:

\begin{verbatim}
: thermometer
    lcdpage
    BEGIN
        0 5 lcdpos
        get.T decode.T format.T lcdtype
        250 ms
    key? UNTIL
;
thermometer
\end{verbatim}

Den Finger auf den LM75 \dots{}

\includegraphics[width=1\hsize]{2006-03/img_thermometer2}

\dots{} and watch the show!

Das Programm zu diesem Teil befindet sich in der Datei \texttt{adv\_03.fs}.

%----------------------------------------------------------------------

\section{Referenzen}


\begin{enumerate}
\item \label{elektor} Elektor--Hefte 12/2005, 01/2006, 02/2006
  \url{http://www.elektor.de}
\item \label{wiki} \href{http://www.forth-ev.de/wiki/doku.php/projects:r8c:r8c_forth}{\tt http://www.forth-ev.de/wiki/doku.php/pro jects:r8c:r8c\_forth}
\item \label{thread_install}
\href{http://groups.google.com/group/de.comp.lang.forth/browse_thread/thread/038d092aab9c558c/80aa79ab4b8624cd#80aa79ab4b8624cd}{\tt http://groups.google.com/group/de.comp.lang. forth/browse\_thread/thread/038d092aab9c558c/ 80aa79ab4b8624cd\#80aa79ab4b8624cd}  (thread zur Installation)
%
\item \label{startingforth}
\url{http://home.iae.nl/users/mhx/sf.html} Starting Forth Online Transkript
\item \label{thinkingforth}
\url{http://thinking-forth.sourceforge.net/} Thinking Forth
Online
\item \label{i2cbus_angewandt}
 I2C--Bus angewandt (Elektor--Verlag, ISBN \mbox{3928051717})
\item \label{wikipediaforth} \href{http://en.wikipedia.org/wiki/Forth_programming_language}{\tt http://en.wikipedia.org/wiki/Forth\_program ming\_language}
\end{enumerate}

\end{multicols}

\section{Listings}
\begin{quote}
\begin{small}
\listinginput[1]{1}{2006-03/SMBus.fs}
\listinginput[1]{1}{2006-03/adv_01.fs}
\listinginput[1]{1}{2006-03/adv_02.fs}
\listinginput[1]{1}{2006-03/adv_03.fs}
\end{small}
\end{quote}

\end{document}
