NB: This article has been written and developed over a significant period of time, with a number of errors and incorrect assumptions corrected when discovered, and new content added. If you haven't looked at it for a while, but aim to try these things out, it would be as well to review the latest version.
Last significant update (not minor corrections or adjustments of presentation): 02/02/2020
02/02/2020: Added information for booting straight to headless using WiFi instead of Ethernet (model 3A+ and others don't have an Ethernet socket); added information relevant to Raspbian Buster (latest version at time of update).
. . . . .
Introduction
This article is for people familiar with the Forth programming language but unfamiliar with using a Raspberry Pi, or people familiar with using the RPi but who might like to explore Forth for the first time. It is probably not for people unfamiliar with either the RPi or Forth, who may be better off with another introduction to the RPi and programming, but nonetheless, by following the instructions exactly, even a complete novice should (hopefully) succeed.
Forth as a programming language is closely coupled to the computer hardware it runs on, and is therefore very useful for "physical computing" (the control of hardware mechanisms such as lights, motors, switches etc). Forth is interpreted rather than compiled, so anything you can do in a program file can also be done directly on the command line - and program development provides instant gratification because you test in small steps as you develop the program. But beware: Forth makes you think for yourself instead of relying on sophisticated compilers to do all the heavy lifting.
The Raspberry Pi (RPi) is a small, cheap, single-board computer highly suited to (and originally designed for) experimenting with physical computing. As well as providing sufficient processor power and system resources to run complete personal-computer desktop operating systems and office suites, it has connections that can be used for operating external circuits under program control.
The following provides step-by-step instructions for installing an operating system on a Raspberry Pi, accessing a text command line, installing a version of the Forth programming language, and (as a demonstration) using Forth to turn a LED connected to the RPi's input-output header (known as the GPIO - General Purpose Input/Output) on and off. The hobbyist can then extend that to controlling motors, getting sensor input, building robots...
Tips for simple hardware interfacing to the GPIO are included at the end of the article under "Hardware Interfacing", for those unfamiliar with hooking up external circuits to their RPi.
A video demonstrating the instructions in this article has been posted on YouTube here (credit Peter Forth): https://youtube.com/watch?v=UBJegHVCPQQ
I'm sure this is not the only way of getting a Forth environment, it may not be the best way, and there are definitely other languages and programming environments that can flash a LED - but it works as a proof of concept if you are interested in using Forth, particularly if this is your first experience of using a Raspberry Pi.
. . . . .
Preface
As a novice rpi-er but (in a past life) a dabbler in Forth on Win3.1/98 (Win98 was the last version that actually lets you get at the hardware so I could use the printer port pins for I/O), the sorts of things I want to do with an RPi are hardware related, and Forth is great for instant-gratification lighting LEDs and moving motors.
As a novice, though, I was dismayed how little information there was on-line about how to set up a Forth environment and get it controlling the GPIO. What there was seemed to assume a level of knowledge I didn't have, so here are detailed instructions, explained simply, for anyone who wants to follow my footsteps. Comments from more experienced users (or followers who could or couldn't make it work) welcome and if there's anything I could have done better let me know. I have developed the article over the passage of some time, and incorporated comments where appropriate - thanks to all who have contributed.
The RPi I am using is "Model B+ V1.2"* with an 8GB micro-SD card (only 2GB required for Raspbian Lite).
* These instructions have been verified to work on Raspberry Pi models: A+, B+, 2B+, 3A+, 3B
Step 1 - Operating System
I wanted this to be headless* (ie no screen & keyboard required). It's not great to have an RPi controlling some hardware on a workbench but needing extra stuff in support! And neither did I want to be forced to connect a keyboard/monitor at any stage in the process. So, from raspberrypi.org I downloaded Raspbian Stretch** Lite to my Windows PC:
https://downloads.raspberrypi.org/raspbian_lite_latest ***
The product is a .zip containing a disk image that needs to be burned to the SD card. This does not just mean unzipping to the SD, a proper image writer is needed. My existing ISO burner wouldn't hack writing to an SD, so the solution was to download Etcher (available as both an installer and a no-install exe for Windows - I prefer the no-install, but run it with administrator privileges):
https://www.raspberrypi-spy.co.uk/2016/ ... linux-mac/
This is capable of reading the image source without unzipping the file first (excellent!). If your PC has an SD card slot you will need a micro-SD adapter, or if not you will need a USB-SD adapter.
The product is the micro-SD card with the necessary boot image to start up the RPi. However, by default this will not start headless, so it needs to be configured to enable a network terminal session.
The SD now has a 40MB FAT32 section and the remainder an Ext3/4 section, the (Windows) PC will not "see" the Ext3/4 section at all. However, in the section you can see on the PC, create an empty file called "ssh" (at the top directory level). This is a flag which tells the RPi boot process to configure for SSH login over the network (and once actioned the flag file is deleted, so don't be surprised if you can't find the ssh file afterwards).
***NEW*** When I tried to do the same thing for an RPi model 3A+, I realised it has no Ethernet port but built-in Wi-Fi instead. How to go headless? It is straightforward enough to configure the Wi-Fi with a screen and keyboard connected, but how to do it without ever connecting a screen and keyboard? It turns out that the Raspbian people have thought of that in a similar way to enabling SSH from first boot - all I had to do was place a configuration file in the FAT32 section of the SD card while still connected to the PC, according to instructions here:
https://www.raspberrypi.org/documentati ... eadless.md
I used Notepad++ to create the config file (which can write Linux line endings [LF] instead of Windows line endings [CR LF], in case that matters). If you are doing this with a Linux system or a Mac the line endings won't be a problem. The most difficult part was deciding what the country code should be (used to configure the correct frequency bands for the Wi-Fi) - for the UK it is "GB" (without the quotes).
Install the micro-SD in the RPi, connect power, and it should boot. Connect by Ethernet or Wi-Fi to your home network for headless access to the command line and for Internet access to continue the setting up.
As there is nothing to see and therefore give confidence that the RPi has booted properly for the first time, it is probably worth hooking up a TV by HDMI just to see the boot happening. Note that Raspbian Lite does not boot to a desktop, only a command prompt.
* There's no reason the below won't work if you choose to use a screen and keyboard instead of a remote terminal session.
** "Stretch" was simply the designation of the latest version of Raspbian available at the time of writing, and the version used to develop these instructions. The current latest is "Buster".
*** Alternatively, install the full-fat Raspbian (which boots to a full home-computer environment with on-screen desktop icons for word processing etc etc) instead of Raspbian Lite (which doesn't), but is a much larger download (2.5GB v 435MB) and much larger image on the SD card. For options see https://www.raspberrypi.org/downloads/raspbian/
Step 2 - Headless* Access to a Command Prompt
* You do not need to do this if you are using the keyboard+screen command line or a command terminal on the full-fat Raspbian desktop. "Headless Access" means accessing the command line using a remote terminal via a network connection.
For a Windows PC download the portable version of PuTTY:
Windows: https://portableapps.com/apps/internet/putty_portable
...or for iPad:
iOS: As the app I have used - vSSH - seems not to be available any more (and is now crippled by iOS updates), type "ssh terminal" in the App Store search and take your pick. Many of the free ones seem to be inundated with advertising, so you may want to just sample the free version and then upgrade to the paid one. If you find a good one, let me know!
I am currently trying out "Get Console" - it's a bit clunky and has a poor write-up, but at least it's free and supports Telnet, SSH, serial over Bluetooth, and various other things. I think the bad reviews might be due to people not putting in the time to get used to it.
Access your router settings to find out what IP address has been allocated to the RPi (most likely 192.168.?.?). Use that address as the address in your SSH client to connect to the RPi on your home network, and it should ask for a login. The default login is:
User ID: pi
Password: raspberry
(You will be pestered to change the password, as the default user name and password is well known and therefore insecure! Change the password to suit yourself. Buster introduces a new complication: running "passwd" as user "pi" rejects any new password it considers not sufficiently secure. To make it accept any password you want, adopt root privilege using "sudo passwd pi".)
At this point you should have a command prompt.
(I realise that SSH is more secure, but for this kind of mucking about normal Telnet is perfectly OK and more accessible, with a built-in client in Windows etc. However, the above instructions set things up for SSH not Telnet, so one trades the inconvenience of downloading an SSH client to use on a PC or iPad (or whatever) for the convenience of not having to set up a Telnet server on the RPi.)
Step 3 - Installing gForth
These instructions are adapted from Kris Johnson's Blog.
If you are running from a Raspbian desktop: open a command terminal - probably Ctrl+Alt+T or Alt+F2, otherwise select Terminal from the menus.
Make sure the repositories are up-to-date:
Code: Select all
sudo apt-get update
Code: Select all
sudo apt-get install gforth
https://www.forth.com/starting-forth/ (I bought the printed book decades ago - no Internet freebies in those days!)
However, just as a test: push two numbers onto the stack, add them (replacing the input values on the stack with the result), and output the value at the top of the stack. Note there is no Forth command line prompt - rather disconcertingly you will be presented with a blank line after the "gforth" command, and the response to a Forth command is on the same line:
Code: Select all
gforth
3 4 + .
Code: Select all
7 ok
Step 4 - Configuring gForth for GPIO Access
Install libraries:
Code: Select all
sudo apt-get install libtool-bin
sudo apt-get install wiringpi
...and fetch Kris Johnson's Forth definitions:
Code: Select all
sudo apt-get install git-core
git clone https://github.com/kristopherjohnson/wiringPi_gforth.git
cp wiringPi_gforth/wiringPi.fs .
Steps 3 & 4 - installing and configuring gForth - can be streamlined as follows (compressing the instructions above into three lines), courtesy scruss:
Code: Select all
sudo apt-get update
sudo apt-get install gforth libtool-bin wiringpi git-core
git clone https://github.com/kristopherjohnson/wiringPi_gforth.git
cp wiringPi_gforth/wiringPi.fs .
Step 5 - Testing
For my test, I wired a light emitting diode (LED) with a series resistor, positive lead to GPIO17 (connector pin 11) and negative lead to 0V (eg pin 6 or pin 9).
Getting the wiring wrong is the only way you might damage your RPi, so make sure you either know exactly what you are doing, or follow these instructions to the letter. It's not hard though, and even something as simple as making a LED flash from your own program for the first time is very satisfying! The ins and outs of wiring circuits to the GPIO are too long to discuss here, so for more information see the Hardware Interfacing section at the end of this article.
To initiate a Forth session with the GPIO control definitions pre-loaded:
Code: Select all
gforth wiringPi.fs
Code: Select all
wiringPiSetupGpio drop
Code: Select all
17 constant ledPin
ledPin OUTPUT pinMode
Code: Select all
: ledOn ledPin HIGH digitalWrite ;
: ledOff ledPin LOW digitalWrite ;
It is also possible to read back the state of the GPIO pin:
Code: Select all
: ledRead ledPin digitalRead ;
Code: Select all
ledOn ok
ledRead . 1 ok
ledRead . 1 ok
ledOff ok
ledRead . 0 ok
Code: Select all
: pause 500 delay ;
: blink begin ledOn pause ledOff pause again ;
And that is the essence of Forth coding! Create a verb, test it, build it into the next verb, etc. Note that if you leave the Forth session and come back another time, your definitions will have been lost - but I'll talk about that shortly.
Try this (flash the international distress signal "SOS" in Morse Code on the LED):
Code: Select all
: dit ledOn 200 delay ledOff 200 delay ;
: dah ledOn 600 delay ledOff 200 delay ;
: SOS dit dit dit dah dah dah dit dit dit ;
SOS
As an exercise to get to grips with Forth, you might like to write a verb "morse" to take a string as input, and output it in Morse Code to the LED (which could equally be a piezo buzzer). You will need to read up about string handling to fetch one character at a time, and array handling to be able to look up the Morse Code for any character in a predefined table. As above, the timings should be predefined constants rather than hard-coded. It would be elegant to have the look-up table convert (for example) "e" to "·" and "o" to "–––", which is then passed on to be interpreted into short and long LED flashes.
The specifications for International Morse Code are available on Wikipedia. Note that the international distress signal "SOS" is defined as ···–––··· and not the three individual letters S O S (which would have longer breaks separating the letters).
Writing something to read Morse on an input pin and convert it to on-screen text is do-able, but a much tougher programming challenge!
Saving
When you exit gForth, everything you did in Step 5 is forgotten and you will have to start again next time from "gforth...".
Well, that's not entirely true. gForth maintains a command history just like the normal Raspbian command prompt, and the history is preserved between sessions (in fact, the relevant history file just grows and grows). You can replay your previous sessions, or selected parts of them, simply by using the up-arrow and down-arrow keys (or Ctrl+P and Ctrl+N for "previous" and "next") to bring up the line you want, alter it if necessary, and press return to execute it.
The command history is also accessible outside the gForth session, in a hidden file ".gforth-history" (files starting with a dot don't show up in directory listings unless you specifically specify "ls .*"). This means that one can, for example, copy the history file to another file (thus saving it), and edit the new file into a definition file for gForth - which can then be loaded next time to reinstate your work. Of course, one can also create a definition file from scratch.
The following prepares to create a file "sos" containing the code used to define the Forth verb "SOS", as above:
Code: Select all
cp .gforth-history sos
nano sos
The command history file just gets longer and longer as sessions accumulate. To erase it and start again:
Code: Select all
rm .gforth-history
Code: Select all
include wiringPi.fs
wiringPiSetupGpio drop
17 constant ledPin
ledPin OUTPUT pinMode
: ledOn ledPin HIGH digitalWrite ;
: ledOff ledPin LOW digitalWrite ;
: dit ledOn 200 delay ledOff 200 delay ;
: dah ledOn 600 delay ledOff 200 delay ;
: SOS dit dit dit dah dah dah dit dit dit ;
It is much more convenient to do the text editing on the PC you are using to run the terminal session than in the terminal session itself. Files can be copied between the RPi and the PC using SFTP, which was enabled at the same time as SSH. To access the RPi file system from Windows via SFTP: use Filezilla and put in the same credentials as you use to log in to the SSH terminal session. FileZilla provides a dual-pane file manager you can use to copy files between systems.
Beware of differences in text file formats between Windows and Linux (in this case Raspbian). Windows won't show the Forth code file correctly in Notepad, because it doesn't have the expected end-of-line markers (for MS-DOS/Windows). Similarly, the markers used by Windows may confuse Linux. To ensure you can edit files and not make them incompatible: always start with a file originated on the RPi; and use Notepad++ to do the editing.
User Input
A program which just does the same thing every time is okay in some cases, but it is often useful to include some user control. Assuming the existing definitions etc listed previously are already loaded into gForth, add the following (or add it into the file "sos"):
Code: Select all
: oneBlink ledOn 200 delay ledOff 200 delay ;
: Blinks
CR
." How many blinks (1-9)? " KEY DUP EMIT SPACE
DUP DUP 48 > OVER 58 < AND
IF 48 DO oneBlink LOOP THEN
;
Using Root Privilege
Everything done above is from a normal user perspective, in this case the user login being "pi". Raspbian (in its default configuration) restricts the access that a normal user has so as to protect critical operating system files and the hardware. The alternative is "root" privilege, also known as "super-user", which allows access to everything (at your own risk). wiringPi, in general, provides direct access to the GPIO functions without requiring root privilege, and the ability to control the LED from gForth via the wiringPi libraries has been demonstrated not to need root privilege.
However, there may be occasions when it is necessary to over-ride the user level restrictions and ensure nothing blocks access to the hardware, in which case the gforth command can be prefixed by the command "sudo", which elevates everything done within the gForth session to root privilege:
Code: Select all
sudo gforth wiringPi.fs
"sudo" is a powerful but potentially dangerous command because it overrides protections that prevent accidental or deliberate attempts to corrupt the computer system - it elevates permissions to "Super User" for the duration of what the following command is DOing (in this case: gforth). It is not good practice to use "sudo" just anywhere, but as we are trying to interact with the RPi's hardware it may be needed on occasions.
Bear in mind however that this is your computer to do what you like with, even mess it up if you want - you are the super-user. Nothing's going to come to any harm if you do mess it up, so it doesn't matter. The worst that might happen is you have to start again from Step 1.
However, in super-user mode, gForth records its command history in a separate file, in a place inaccessible without root privilege. To append the "root" command history to the existing "user" command history (where the history lines can be easily accessed):
Code: Select all
sudo cat /root/.gforth-history >> ~/.gforth-history
Code: Select all
sudo rm /root/.gforth-history
Running a Forth Program from the Raspbian Command Line
Taking the SOS code above as our example, if we add two lines to the end of the file "sos":
Code: Select all
SOS
bye
Code: Select all
gforth sos
There are several ducks to be put in a row for this to happen:
- "sos" needs to invoke gForth so that the code it contains can be interpreted;
- "sos" needs to be marked as executable;
- "sos" needs to be on the command search path;
- Any files "sos" refers to need to be located when executed.
Code: Select all
#! /usr/bin/gforth
include wiringPi.fs
wiringPiSetupGpio drop
17 constant ledPin
ledPin OUTPUT pinMode
: ledOn ledPin HIGH digitalWrite ;
: ledOff ledPin LOW digitalWrite ;
: dit ledOn 200 delay ledOff 200 delay ;
: dah ledOn 600 delay ledOff 200 delay ;
: SOS dit dit dit dah dah dah dit dit dit ;
SOS
bye
Code: Select all
chmod 755 sos
Code: Select all
mkdir ~/bin
mv sos ~/bin
Finally, sos expects to find wiringPi.fs in the same directory. If we were to simply copy wiringPi.fs into ~/bin, that would mean there were several versions of wiringPi.fs floating around and all needing to be updated if one was updated. If we were to move it into ~/bin, that would make it unavailable for instant use on the Forth command line (without also specifying where to look for it). A solution is to move wiringPi.fs and create a symbolic link to it from the home directory:
Code: Select all
mv wiringPi.fs ~/bin
ln -s ~/bin/wiringPi.fs wiringPi.fs
Still to come...
Fetching parameters from the Raspbian command line;
More info about the GPIO commands provided by wiringPi.fs;
Calling Forth programs from other scripts.
Hardware Interfacing
I have now split this out to a separate post. See here: viewtopic.php?p=1330183#p1330183