Let’s make the JeeNode Zero do some simple things. Like blinking LEDs in a continuous loop:
The code for this was actually written step by step, and later saved in a file called e-leds.fs:
forgetram
\ configure one pin as push-pull output
: out ( pin -- ) OMODE-PP swap io-mode! ;
\ configure all the LED pins as outputs
: setup PA0 out PA1 out PA2 out PA3 out PA4 out PA5 out ;
\ turn one pin on for 100 milliseconds
: blip ( pin -- ) dup ios! 100 ms ioc! ;
\ blink LEDs in a loop, until new input is received from Folie
: go
begin
PA0 blip PA1 blip PA2 blip PA3 blip PA4 blip PA5 blip
key? until ;
setup go \ press <enter> to quit
Let’s go through these lines of code in some more detail:
forgetram
– Clear all previously defined words from RAM. It’s not strictly needed, but avoids generating a bunch of “Redefine …” warnings.: out ... ;
– Define a new word “out” which sets up a pin supplied as argument on the stack to be an output (OMODE) in push-pull mode (PP), using a utility word (io-mode!) which takes two arguments - the “swap” is needed to get these arguments in the proper order.( pin -- )
– This is a stack comment - everything between “(” and “)” is ignored by Mecrisp Forth, this example documents the stack use of “out
”.: setup ... ;
– Uses the “out” word to set up all 6 pins with a LED attached. There are 6 LEDs in the above setup (using a little eBay module with current limit resistors).: blip ... ;
– Set a specified pin to “1”, wait 0.1 seconds, and clear it to “0” again.: go ... ;
– This is the main loop, it sequences through each of the six LED pins, and repeats. At the end of each cycle, it checks for new incoming commands from Folie and quits the loop when that happens.setup go
– Start the ball rolling, i.e. initialise everything and loop. Note that you don’t have to include the actual calls here, you can also enter them manually after the above definitions have been loaded.
Speaking of loading, there are two ways to develop with Folie: either enter code
interactively and try it out until working as intended, or save definitions in a
file and use Folie’s “send”, by entering “!s <file>
”. Interactive mode is
best when you’re not yet sure about the code and need to try things out, but
it’s volatile since everything typed in will be gone after a reset. When saved
on file, you can edit and extend as needed, then resend. The forgetram
at the
start and the setup go
at the end help streamline this approach. A mix of both
is often used: define the more stable words in a file and resend when changed,
then call them interactively.
The above demo code illustrates how to use the essential words defined in
flib/stm32l0/io.fs.
Here is a summary of all the pin modes you can set with io-mode!
, taken from that same file:
IMODE-FLOAT \ input, floating
IMODE-HIGH \ input, pull up
IMODE-LOW \ input, pull down
IMODE-ADC \ input, analog
OMODE-AF-PP \ alternate function, push-pull
OMODE-AF-OD \ alternate function, open drain
OMODE-PP \ output, push-pull
OMODE-OD \ output, open drain
OMODE-WEAK \ add to OMODE-* for 400 KHz iso 10 MHz drive
OMODE-SLOW \ add to OMODE-* for 2 MHz iso 10 MHz drive
OMODE-FAST \ add to OMODE-* for 35 MHz iso 10 MHz drive
Now let’s try something a bit more advanced. We’ll attach a BME280 sensor, load a Forth driver for it, and use that to initialise the sensor and get readings twice a second:
The code for this is small, because the driver in flib/i2c/bme280.fs does all the hard work:
forgetram
\ include ../flib/i2c/bme280.fs
\ use PA13 and PA14 to supply power to the BME280 sensor
: bme-power
OMODE-PP PA14 io-mode! PA14 ioc! \ set PA14 to "0", acting as ground
OMODE-PP PA13 io-mode! PA13 ios! \ set PA13 to "1", acting as +3.3V
;
\ configure I2C and the BME280 sensor attached to it
: setup i2c-init bme-power bme-init . bme-calib ;
\ print BME readings every 500 ms, until new input is received from Folie
: go
begin
bme-data bme-calc
cr . . .
500 ms
key? until ;
\ the delay is a hack to force a timeout in Folie before the loop starts
1234 ms setup go
Some notes:
- this demo is available on GitHub at
e-sensor.fs,
so if you’re in the “1608/jz3/” directory, you can upload it using “
!s e-sensor.fs
” in Folie - the driver
include
has been commented out, because it’s already included bycore.fs
, which is stored permanently into flash - given the way the breakout board pins are laid out, we can avoid using wire
jumpers - instead, the “GND” and “VIN” pins are connected to to I/O pins,
which we then set up as fixed outputs set to “0” and “1” respectively - see
the definition of
bme-power
above - “
: setup ... ;
” does 3 things: 1) enable the BME power pins (bme-power
), 2) init the BME sensor (bme-init
) – the return value is non-zero if there was an error, we simply print it out using “.
” – and 3) set up the BME280’s calibration data (bme-calib
) - “
: go ... ;
” is again the main loop for this demo, but now it requests a sensor reading (bme-data) and calculates actual temperature / humidity / pressure values, returned as three values on the Forth data stack - the “
cr . . .
” code pops these three values in reverse order, and prints them on a line - the final “
1234 ms setup go
” is a bit of a hack: the delay (which has to be slightly over 1 second to trigger Folie’s timeout) generates an error in Folie, causing it to abort the send, but since it’s the last line of the file anyway, we don’t care: thego
loop will already have started, and will terminate when we hit <enter>
Here is some sample output, with a new reading printed out every 500 milliseconds:
ok.
!s e-sensor.fs
1> e-sensor.fs 23: 1234 ms setup go (timeout)
0
2176 102972 4635
2176 102975 4634
2176 102975 4634
2175 102964 4634
2175 102964 4634
As you can see, it’s currently 21.76°C here at JeeLabs, the barometric pressure is 1029.72 hPa, and the relative humidity is 46.35%. Due to the excellent factory calibration of the BME280, we are getting realistic and reliable measurements!