Some computers exist to push limits. I built Daisy to push back!
This is a homebrew personal computer built from three Arduino boards, some resistors, and a lot of love. It isn't trying to be powerful. It's trying to be fun: portable, limited, and deliberately cute. The kind of machine you could spend a night with, writing a little art, a little music, a small game. The kind of machine that used to exist everywhere and mostly doesn't anymore. The Timex Sinclair 1000, Commodore PET, TRS-80 MC-10.
But Pinecone Daisy is also something else: an artifact from an alternative history. It has a name, a manufacturer, a model number, and a printed BASIC programmer's reference guide. The guide is styled after the Abacus Software books for the Amiga, inspired by a magazine ad for the DASH-80, and credited to a company called Pinecone Computer. None of that is real, exactly. All of it is real enough. The machine works. The manual documents it accurately. Bear (the capybara on the cover, and on the desk) was present for most of the build as a rubber duck debug partner.
The name comes from two places: the fictional computer company from the 1985 film Electric Dreams, and my dog, Daisy. The model is the DAISY-1.
The creative, adventurous spirit of home computing in the 1970s and 80s was inseparable from constraint. You had 40 columns, a couple of colors if you were lucky, a handful of voices, and BASIC. That wasn't a limitation to overcome. It was the medium. And you know what Marshall McLuhan said: 80s computing is a rare medium that's well-done. (Or maybe I imagined that!)
Hardware Overview
Pinecone Daisy is built from three Arduino boards, each running dedicated firmware:
- Video processorArduino Mega
- Audio processorArduino Uno
- OS / BASIC interpreterArduino Due
The master controller (Due) communicates with both the video and audio boards over UART using a lightweight packetized message protocol. I²C and SPI aren't available for interboard comms because the NTSC interrupt timing on the video board is tight enough to make both unreliable. Packets include a checksum. If a packet is lost, it's lost. There's no retry logic. For a single-user machine with short cable runs between boards, that's the right tradeoff.
The Due also handles keyboard matrix scanning for the Lazer 50's built-in keyboard. The original keyboard lacks dedicated cursor keys and backspace, so control key combinations fill the gap. Shift+Space is backspace. It sounds like it shouldn't work, but in practice it's quick and cozy. Your hands find it fast.
Video
The display processor runs on a dedicated Arduino Mega, generating 40x25 monochrome NTSC composite video at 8x8 character resolution, bit-banged out of an abused SPI pin. Black and white, character-based, period-appropriate. The foundation is Dave Schmenk's work improving on the TVout library, adapted and extended for Daisy's needs. (Hi, Dave! You rock!)
There are two character sets, each 256 characters. The first, charram, ships populated with ASCII plus a set of drawing glyphs. The second, gfxram, is blank: a clean canvas for tile graphics, custom bitmaps, whatever you need. Both are fully redefinable. Each row of the display can be independently assigned to draw from either set, which means you can run UI chrome in one charset and a graphics playfield in another within the same frame. It's not a bitmap mode, but it doesn't need to be.
The character-based approach isn't a stylistic choice. A full bitmap framebuffer at this resolution is simply out of reach on the Mega: not enough RAM to hold it, and not enough timing budget in the NTSC interrupt to push it. Characters are how you get a display at all. Two charsets are how you make the most of that: one always-populated with text and drawing glyphs, one blank and free for tile sets and bitmaps.
Both charsets live in RAM only, but they can be saved and loaded from storage over the network.
The display also supports a semigraphics layer, in the tradition of the Sinclair ZX81 and TRS-80. Each 8x8 character cell is subdivided into a 2x2 pixel grid, giving an effective resolution of 80x50 pixels. Pixels can be solid on, solid off, or dithered (a checkerboard pattern). That last option is more useful than it sounds: on a small CRT at normal viewing distance, dithered pixels blend optically and produce something close to a grey value. It's the same principle as halftone printing, and on a monochrome composite signal it looks genuinely good. Three tonal values out of a black and white display.
The pixel graphics command set is complete for the resolution:
PPLOT sets individual pixels.PLINE draws Bresenham lines and filled or unfilled rectangles.PCIRCLE handles full ellipses, arcs, and filled variants with optional start and end angles.PFILL does a 4-connectivity flood fill.PPOLY draws connected polygons from a 2D coordinate array and accepts two arrays at once to erase and redraw in a single video message for flicker-free animation.The signal has been tested on a small black-and-white baby monitor, a Commodore 1084, and a composite-to-HDMI converter. It holds up on all three.
Audio
Listen to a sample of Daisy playing music in this video.
The audio processor runs on an Arduino Uno, generating three voices at 31.25 kHz via a Timer1 ISR: two pulse waves and one noise channel. The three digital outputs are mixed through a resistor ladder DAC, the same approach you'd have used in 1982.
The pulse waves support variable pulse width and an LFO-driven PWM sweep, which animates and thickens the sound beyond what a static square wave offers. Both voices also support portamento, with pitch glides between notes updated roughly 244 times per second. The noise channel is not generic white noise. It implements the SID 6581's 23-bit LFSR with the original tap pattern, giving it that specific textured quality that Commodore users will recognize immediately.
DaisyBASIC
The heart of the machine is DaisyBASIC, running on the Arduino Due. It draws from multiple lineages: Commodore/Microsoft BASIC, Applesoft, GW-BASIC, TI BASIC. It adds original extensions designed around actually writing programs on this machine. The goal wasn't to pick one ancestor. It was to let different programmers work the way they remember working.
READMAT bulk-loads an entire array directly from DATA statements in one command. Anyone who has written a FOR loop to populate a lookup table in Commodore BASIC knows exactly why this exists.SWAPARR swaps two arrays element-by-element, or performs a three-way rotation. Swap your draw buffer and display buffer without copying. CLEARARR zeroes an entire array, or a tail slice of one, in a single statement.RETURN can pass values back to the caller, giving subroutines a clean result mechanism without global variable side effects. TRAP and RESUME provide structured error handling.TIMER fires a GOSUB at a specified interval, useful for game loops and animation without blocking on a polling loop.CHUNK splits a string into an array on a specified delimiter. RENUMBER renumbers lines and updates all GOTO and GOSUB references automatically.For sound, there are two paradigms by design. PLAY accepts MML strings in the tradition of Commodore 128 BASIC 7 and GW-BASIC, for music composition. SOUNDPGM offloads frequency/duration pairs to the audio processor directly, freeing the main loop and better suited for sound effects. Both coexist because different machines solved sound differently, and different programmers think differently.
There is also a built-in Space Invaders clone, because why not? :-)
Networking
WiFi is provided by an ESP8266 running Bo Zimmer's ZiModem firmware, a Hayes-compatible modem over WiFi. Pinecone Daisy can hit a BBS! The built-in VT52 terminal emulator is a complete implementation, with cursor movement, clear screen, graphics mode, ANSI arrow key support, and a status bar with date and time.
Beyond terminal use, DaisyBASIC exposes the network connection directly to programs. NETPRINT, NETGET, and NETINPUT let a running BASIC program send and receive data over a TCP connection, byte by byte or line by line, blocking or non-blocking. That's enough to remote-control another machine, exchange game state between two Daisies, or talk to anything on the network that speaks plain TCP. Networked games are an obvious use. So is using a more powerful machine as a back-end while Daisy handles the UI.
Storage
Storage is handled by a small Python server (daisyfile.py) running on any networked computer. A laptop, a Raspberry Pi, whatever you have. Programs, character set definitions, and sequential files can be saved, loaded, deleted, renamed, and organized into directories. The file I/O commands (FOPEN, FCLOSE, FPRINT, FINPUT, FGET, FPUT, FSEEK) give BASIC programs direct access to files on the host as sequential streams.
Using It
The line editor behaves exactly like a Commodore 8-bit. Cursor up to a previous line, make your edit, hit Return, and the change is committed. That's it. No EDIT command, no cryptic cursor key sequences like on the Apple II. Just the natural, direct editing experience that Commodore BASIC users took for granted and everyone else should have had.
Key clicks are on by default, Atari 400/800 style: every keypress gets a short percussive beep. It sounds right on a machine like this. One command turns it off if you prefer silence.
There is also a MORE command for reading text files, inspired by the same command on AmigaDOS. Load a file from the server and page through it on screen. Small thing, but it rounds out the machine as something you can actually use, not just program.
It's about fun and heart
Pinecone Daisy is a toy, in the best sense of the word. It lives in a Lazer 50 personal computer case, using its original keyboard. It boots to BASIC. It has a name from a movie and a dog.
It's a machine for the kind of focused, solitary, creative computing that used to be ordinary and is now rare. Plug it in, fire up BASIC, and make something small and weird and yours.
The full project, all three firmware images and the Python file server, will be released soon!
By the way: there's a reason I called it Daisy ONE...
