Difference between revisions of "Forth"

From eLinux.org
Jump to: navigation, search
m (Adding new words)
Line 128: Line 128:
  
 
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
 
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:
 +
<code><pre>
 +
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;
 +
}
 +
</pre></code>
 +
 +
Add #include <time.h> at line 20 in atlast.c
 +
 +
Test the command
 +
<code><pre>
 +
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.
 +
</pre></code>
 
[[Category: RaspberryPi]]
 
[[Category: RaspberryPi]]

Revision as of 02:00, 9 July 2013

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.