# Lisp Badge: A single-board computer that you can program in uLisp

3 min read## Lisp Badge

The Lisp Badge is a self-contained computer with its own display and keyboard, based on an ATmega1284, that you can program in uLisp:

You can use it to run programs that interface to components such as LEDs and push-buttons via the I/O pins, read the analogue inputs, and operate external devices via the I2C and SPI interfaces. It has a greyscale OLED display that gives 8 lines of 42 characters, and an integrated 45-key keyboard optimised for Lisp.

For details of how to build one see Lisp Badge on Technoblogy.

### Specification

**Size:** 107mm x 61mm (4.2″ x 2.4″).

**Display**: 42 characters x 8 lines.

**Keyboard:** Integrated 45-key keyboard providing upper and lower-case characters, digits, and the symbols required by uLisp.

**Memory available**: 2816 Lisp cells (11264 bytes).

**EEPROM**: 1024 Lisp cells (4096 bytes), allows you to save the Lisp workspace using **save-image**.

**Processor:** ATmega1284P

**Clock speed:** 16 MHz.

**Current consumption:** Approx. 20 mA.

**Language**

uLisp, a subset of Common Lisp, with 122 Lisp functions and special forms. For a full definition see uLisp Language Reference.

The language includes two extensions, **plot** and **plot3d**, for plotting graphs and 3d functions.

**Types supported**: list, symbol, integer, character, string, and stream.

An integer is a sequence of digits, optionally prefixed with “+” or “-“. Integers can be between -32768 and 32767. You can enter numbers in hexadecimal, octal, or binary with the notations #x2A, #o52, or #b101010, all of which represent 42.

User-defined symbol names can have arbitrary names. Any sequence that isn’t an integer can be used as a symbol; so, for example, 12a is a valid symbol.

There is one namespace for functions and variables; in other words, you cannot use the same name for a function and a variable.

Includes a mark and sweep garbage collector. Garbage collection takes 5 msec.

**Interfaces**

These interfaces are brought to headers at the edge of the Lisp Badge board. The numbers in brackets refer to Arduino pin numbers:

- Four analogue input pins using
**analogread**: A0 to A3 (24 to 27) plus VCC and GND. - Two analogue outputs using
**analogwrite**: MISO (6), and SCK (7). - Digital input and output using
**pinmode**,**digitalread**, and**digitalwrite**: MOSI (5), MISO (6), SCK (7), RX0 (8), TX0 (9), SCL (16), SDA (17), and A0 to A3 (24 to 27) - I2C interface using
**with-i2c**and**restart-i2c**: SCL (16) and SDA (17). - SPI interface using
**with-spi**: MOSI (5), MISO (6), and SCK (7). - Serial interface (FTDI) using
**with-serial**: RX0 (8) and TX0 (9).

The shift key can be used as a digital input: SHIFT (23).

SCK (7) is connected to an LED on the front panel. This is an analogue output pin, so you can vary the brightness of the LED.

### Plotting extensions

The Lisp Badge contains two plotting extensions, plot and plot3d, designed to allow plotting to the greyscale graphics display.

After generating a plot both functions wait for the ESC key to be pressed before displaying the uLisp prompt.

### plot function

**Syntax:** `(plot [`

*x-intercept y-intercept*] [*function*]...)

Plots up to four functions on the same graph, optionally with axes.

Each function should be a function of one parameter, the x coordinate, and it will be called with each value of x from 0 to 255. The function should return the y value, from 0 to 63.

If *x-intercept* and *y-intercept* are specified, **plot3d** draws axes through those intercepts.

For example, defining:

(defun sine () (let ((x 0) (y 2045)) (lambda (n) n (incf x (/ (* y 16) 163)) (decf y (/ (* x 16) 163)) (+ 32 (ash x -6)))))

the following command:

(plot 0 32 (sine))

will plot:

#### Plotting multiple functions

The following example plots the voltages on the analogue inputs 0 to 3 once a second on a single plot. First define:

(defun adc (n) (lambda (x) (delay 250) (/ (analogread n) 8)))

Then give the command:

(plot 0 0 (adc 0) (adc 1) (adc 2) (adc 3))

### plot3d function

**Syntax:** `(plot3d [`

*x-intercept y-intercept*] [*function*])

The function should be a function of two parameters, the x and y coordinates, and it will be called with each value of x from 0 to 255 and y from 0 to 63. The function should return the greyscale value to be plotted, from 0 to 15.

If *x-intercept* and *y-intercept* are specified, **plot3d** draws axes through those intercepts.

For example, defining:

(defun p (x y) (let ((a (/ (- x 128) 2)) (b (- y 32))) (min (abs (- (logand (/ (+ (* a a) (* b b) (* a b)) 16) 31) 15)) 15)))

the following command:

(plot3d 128 32 p)

will plot: