Forth
Forth on RPi
sudo apt-get install wget
wget http://www.fourmilab.ch/atlast/download/1.2/atlast-1.2.tar.gz
tar -xzvf atlast-1.2.tar.gz
cd atlast-1.2/
make
Start the Forth interpreter with ./atlast and exit with Ctrl-D
atlast.html and atlast.pdf is included and an is an extensive atlast-forth manual. Read it online [1] and read about Forth itself here [2] and here [3] (Beware that the Forth dialect in the book Starting Forth is a bit outdated compared to Atlast Forth). Leo Brodie wrote another book, Thinking Forth, read it here [4]
Adding new words
Most of the power of Atlast Forth derives from the ease with which C coded primitives can be added to the language. In my case I will add some words for controlling my Gertboard. There is a detailed description on how to do this in the atlast-forth manual. And you can copy much of the word implementations from the gertboard_sw directory if you have downloaded the gertboard demo files. It is easy to add your own words, just add a "define GERTBOARD" to atlast.c around line 56.
#define EVALUATE /* The EVALUATE primitive */
#define FILEIO /* File I/O primitives */
#define GERTBOARD /* Gertboard functions */
Include the gb_common.h right after include <math.h>
#ifdef MATH
#include <math.h>
#endif
#ifdef GERTBOARD
#include "gb_common.h"
#endif
Then add your own word definitions at the end of the section with word definitions, around line 2704, right after #endif /* COMPILERW */ in atlast.c
#ifdef GERTBOARD
prim P_gert_io() // state ---
{ // Setup and restore io
Sl(1);
if(S0 == 1)
setup_io(); // Map the I/O sections
else
restore_io(); // Unmap and free memory
Pop;
}
prim P_gert_setport() // channel state ---
{ // Set a digital io port to a specified state
int rev;
Sl(2);
if (S1 == 21)
{ // find out which rev of RPi we have
rev = pi_revision();
if (rev != 1)
S1 = 27; // GP21 on Gertboard is controlled by GPIO27
}
INP_GPIO(S1);
OUT_GPIO(S1);
if (S0 == 1)
GPIO_SET0 = (1<<S1);
else
GPIO_CLR0 = (1<<S1);
Pop2;
}
prim P_gert_getport() // channel ---
{ // Get a digital io port
int rev;
Sl(1);
if (S0 == 21)
{ // find out which rev of RPi we have
rev = pi_revision();
if (rev != 1)
S0 = 27; // GP21 on Gertboard is controlled by GPIO27
}
INP_GPIO(S0);
S0 = !!(GPIO_IN0 & (1 << S0));
}
#endif /* GERTBOARD */
And finally, add the actual words to the Table of primitive words, right after #endif /* EVALUATE */ at line 2960 or so.
#ifdef EVALUATE
{"0EVALUATE", P_evaluate},
#endif /* EVALUATE */
#ifdef GERTBOARD
{"0GERTBOARD", P_gert_io},
{"0SETIO", P_gert_setport},
{"0GETIO", P_gert_getport},
#endif /* GERTBOARD */
As we are using code from the Gertboard demos, copy the files gb_common.o and gb_common.h from the gertboard_sw directory to atlast-1.2 directory (it's there if you have run make in this directory as well).
Add gb_common.o to the file Makefile in atlast-1.2.
ATLOBJ = atlast.o gb_common.o atlmain.o
Now, save and run "make" again to recompile atlast.c.
Test the new words
Wire up the Gertboard according to the information you get when you run the command sudo ./leds in the Gertboard demo directory.
Run sudo ./atlast in the atlast-1.2 directory.
Type 1 gertboard
Type 22 1 setio and press enter, the corresponding LED will go on.
Type 22 0 setio and the LED will go off.
Type 0 gertboard
Play with it
Define your own LED demo, start the interpreter with sudo ./atlast. Define these words:
: use 1 ;
: free 0 ;
: leds 25 24 23 22 21 18 17 11 10 9 8 7 ;
: on 12 0 do 1 setio loop ;
: off 12 0 do 0 setio loop ;
Now type use gertboard leds on and press enter and all leds should go on. Type leds off and they should go off again. And finally type free gertboard
A real Use Case
I have a kWh meter that I would like to read with the RPi. On the meter there is a small light that blinks once per second at 1 kWh. So I need a way to detect time between pulses. I tape up a simple LDR over the blinking light and connects it to Gertboard Buf1 and ground. Make B1 an input with a jumper on the board. Connect GP25 to B1.
Now that you know how to add a primitive word to atlast I just list the code for the word:
prim P_gert_getkwh() // channel --- clocks clocks_per_sec
{ // Get a digital io port negative edge
unsigned int i;
clock_t start, end;
start = clock();
Sl(1);
if (S0 == 21)
{ // find out which rev of RPi we have
rev = pi_revision();
if (rev != 1)
S0 = 27; // GP21 on Gertboard is controlled by GPIO27
}
INP_GPIO(S0);
i = 0;
while(GPIO_IN0 & (1 << S0))
{
i++;
if(i > 100000000) break;
}
long_wait(1);
end = clock();
S0 = (double) (end - start);
So(1);
Push = (stackitem) CLOCKS_PER_SEC;
}
Add #include <time.h> at line 20 in atlast.c
Test the command
1 gertboard
25 getkwh . .
: time_kwh 25 getkwh 2drop 25 getkwh float 2 roll float 2swap f/ ;
time_kwh f.
: hz_kwh 25 getkwh 2drop 25 getkwh float 2 roll float 2swap f/ 1.0 2swap f/ ;
hz_kwh f.
0 gertboard