LilyGO T-Deck uLisp Machine
This article describes how to convert the LilyGO T-Deck into a self-contained handheld Lisp computer, based on the latest version of uLisp:
The uLisp T-Deck, a handheld Lisp computer with a self-contained keyboard and display.
It has an 320x240 colour TFT display that gives a scrolling display of 24 lines of 53 characters, an integrated 35-key Blackberry-type keyboard, and an SD card socket . It's available from AliExpress, or direct from LilyGO, for around $50/£50.
19th October 2023: This description has been updated to reflect changes to Release 4 of the uLisp T-Deck firmware.
The LilyGO T-Deck is based on an ESP32-S3 dual-core LX7 microprocessor, with 2.4 GHz Wi-Fi & Bluetooth 5 (LE). It has 16M bytes of flash and 8M bytes of PSRAM.
The display is a 2.8 inch ST7789 SPI Interface IPS LCD with a resolution of 320 x 240. The display uses the Arduino GFX library, and the firmware provides software scrolling.
The T-Deck includes a socket for a 3.7V lithium cell, and this can be charged from the USB port.
Here's the full specification:
uLisp T-Deck – Specification
Size: 68mm x 100mm (2.7" x 3.9").
Display: 53 characters x 24 lines (can be increased to 30 lines).
Keyboard: Integrated 35-key I2C keyboard providing upper and lower-case characters, digits, and most symbols required by uLisp. The '@' and '_' keys are translated into the characters '~' and '\' required by uLisp.
Memory available: 22000 Lisp cells (176000 bytes).
Flash: 1.5M bytes of flash are reserved for use to save the Lisp workspace using save-image if the SD card interface is not used.
Clock speed: 240 MHz.
Trackball: The trackball is used as an Escape key - press it in to escape from a running program.
uLisp, a subset of Common Lisp, with approximately 200 Lisp functions and special forms.
It also provides keywords, such as :input and :output, as a convenient way of entering Arduino constants.
For a full definition see uLisp Language Reference.
Types supported: list, symbol, integer, floating-point, character, string, stream, and array.
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.
The floating-point numbers have full 32-bit precision.
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.
uLisp includes a mark and sweep garbage collector. Garbage collection takes about 0.9 msec.
You can enter commands and programs by typing them at the keyboard, and pressing ↩. A keyboard buffer is provided that buffers a full screen of text, and you can use the ⌫ key to delete characters and correct typing mistakes. The editor includes parenthesis matching which automatically highlights matching brackets in green as you type in a program. This makes it much easier to enter a program correctly, and is especially helpful in telling you how many closing brackets to type at the end of defining a function.
To get upper-case letters hold down one of the two ⇧ keys while typing a letter key.
To get the symbols and digits on the top row of each key legend press the sym key followed by the appropriate key.
Hold down alt and press B to turn on/off the keyboard backlight.
Hold down alt and press C to clear the display
Connecting to a computer
You can also connect the T-Deck to a computer via a USB cable. You can then use the Serial Monitor in the Arduino IDE to enter and edit programs as described in Using uLisp.
You can play notes through the internal speaker using the uLisp note function. On the T-Deck you must supply the duration, in milliseconds, as a fourth argument. For example, the following function plays a scale of C:
(defun scale () (mapc (lambda (n) (note 3 n 4 500)) '(0 2 4 5 7 9 11 12)))
The beep character beeps the speaker:
The T-Deck SD card socket can be used to read from and write to SD cards from uLisp, and to save an image of the Lisp workspace. To return a list of the files on an SD card give the command directory:
21827> (directory) ("T1.bmp" "A1" "F2" "T2" "PIC.BMP" "ULISP.IMG" "Greeting.txt" "PIC2.BMP" "X1")
For details of using SD cards see SD card interface.
If you don't want to use the SD card, upload the firmware with the following line commented out with:
// #define sdcardsupport
The (save-image) command will then use the flash memory to save the workspace.
With a default 240MHz clock the uLisp T-deck firmware clears the screen in about 33ms:
21827> (time (write-byte 12)) nil Time: 33 ms
Scrolling the screen is optimised, depending on the content, and takes about 30ms:
21827> (time (terpri)) nil Time: 30 ms
As discussed on the page ESP32-S2, ESP-S3, and ESP-C3 boards, there is an outstanding issue with the ESP32-S3 built-in USB support that makes it hang up if you try to enter a program of more than a few lines from the Serial Monitor. Hopefully this will be fixed in a future release of the ESP32 core. Alternatively, it may be possible to work around this problem by using a USB-to-Serial adapter connected to the Rx and Tx serial pins on the T-Deck.
Installing the T-Deck uLisp firmware
The following instructions describe how to upload the uLisp firmware using the Arduino IDE. I used Arduino 1.8.19 on a Mac, but it should be possible to use other versions of the IDE, and other platforms.
In addition to the Arduino IDE you also need to install the following cores and libraries:
- Use the Boards Manager to install the ESP32 core. I used 2.0.14.
Note that version 3.0.0-alpha2 of the ESP32 core will not work.
Ensure that you are installing the version by Espressif Systems, not the Arduino version that only supports the Arduino Nano ESP32.
Install the TFT_eSPI library from the lib folder in the LilyGO T-Deck repository on GitHub at https://github.com/Xinyuan-LilyGO/T-Deck/tree/master/lib, by copying it into the libraries folder in your Arduino folder.
Note that this is a modified version of the Bodmer TFT_eSPI library, and it won't work if you install the one from Bodmer's GitHub repository, or from the Library Manager.
- Download the T-deck uLisp firmware from https://github.com/technoblogy/ulisp-tdeck.
- Choose the ESP32S3 Dev Module option under the ESP32 Arduino heading on the Board option on the Tools menu.
- Check that the subsequent options are set as follows (leave the other options at their defaults):
USB CDC On Boot: "Enabled"
Flash Size: "16MB (128Mb)"
Partition Scheme: "Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)"
- Connect the computer's USB port to the T-Deck and select the port from the Tools menu Port submenu.
- Check that Compiler warnings is set to Default in the Arduino IDE Preferences panel, otherwise the compilation may fail on warnings.
- Choose Upload from the Sketch menu to upload uLisp.
You should then see the uLisp prompt on the T-Deck display, and be able to enter Lisp programs at the keyboard. You should also be able to enter Lisp programs from the Arduino IDE Serial Monitor; you may have to select the USB port from the Port submenu again.
The uLisp T-deck firmware on GitHub: https://github.com/technoblogy/ulisp-tdeck
LilyGO's T-Deck repository on GitHub: T-Deck.
LilyGO's T-Deck information page: T-Deck.
This firmware builds on the work posted on the uLisp Forum by @hasn0life in porting uLisp to the T-Deck, and @nanomonkey in adding SD card support.