Hardware support is done with a two level approach.
Builtin Support
Firstly, the most basic capabilities have been added to the CircuitScheme runtime by way of builtin functions: the board module to give access to pins, digital and analog I/O, I2C bus creation, and sleep.
Let's look at the Hello, World of hardware: blink. It shows setting up a digital output on D13, setting its value, and sleeping. Note it uses recursion. The let
structure simply binds the symbol led
to the digital output for use in the code within the let
.
(define (blink) (let ((led (digital-pin (board "D13") **OUTPUT**))) (define (loop val) (pin-value! led val) (sleep 0.5) (loop (not val))) (loop #t)))
The functions below are supplied. They work as you would expect. Later in the guide, we'll see some examples.
board-pins
- get a list of the names of all pins on the boardboard
- given a pin name, return the corresponding pin objectdigital-pin
- create a DigitalInOut from a pin objectanalog-pin
- create an analog pin from a pin name and direction**INPUT**
- use to create a digital or analog input**OUTPUT**
- use to create a digital or analog output**PULLUP**
- set a pull up resistor on a digital input**PULLDOWN**
- set a pull down resistor on a digital inputpin-value
- get the value (digital or analog) of a pinpin-value!
- set the value (digital or analog) of a pini2c
- create an I2C bus object given SCL and SDA pins objectssleep
- delay some number of seconds
Wrapping CircuitPython Driver Libraries
The second approach provides a facility to dynamically load wrappers around Python device driver modules. This will generally just be a Python file, but can involve a file of CircuitScheme code as well. A .py
and .scm
file with the same basename can be loaded from the /devices subdirectory on CIRCUITPY
. If either file is not found, it is ignored. The code implementing this is:
def execfile(f):
exec(open(f).read())
def load_device(device_driver_name):
try:
execfile('./devices/{0}.py'.format(device_driver_name))
except OSError:
pass
try:
load('./devices/{0}.scm'.format(device_driver_name))
except OSError:
pass
The load_device function is bound to load-device in CircuitScheme, so to load support for a device (e.g. the Si7021 temperature and humidity sensor) you would use:
(load-device "si7021")
Then the functions provided can be used. Here is devices/si7021.py
(there is no si7021.scm
):
import adafruit_si7021 def make_si7021(i2c_bus): return adafruit_si7021.SI7021(i2c_bus) def si7021_relative_humidity(device): return device.relative_humidity def si7021_temperature(device): return device.temperature global_env.storage.update({ 'make-si7021':make_si7021, 'si7021-relative-humidity':si7021_relative_humidity, 'si7021-temperature':si7021_temperature })
This defines three functions that we want to make available: create an Si7021 interface object, read the humidity, and read the temperature. It then makes them available to CircuitScheme code by adding them to the global environment's dictionary: global_env.storage
Once loaded, it can be used:
(load-device "si7021") (define sensor (make-si7021 (i2c (board "SCL") (board "SDA")))) (display "Temperature: ") (display (si7021-temperature sensor)) (newline) (display " Humidity: ") (display (si7021-relative-humidity sensor)) (newline)
Which results in:
CircuitScheme version 1.0: 185280 free bytes
==> (load "si7021-sample")
Temperature: 24.3539
Humidity: 42.3818
==>
Text editor powered by tinymce.