TinyCard Game Maker
25th March 2025
TinyCard is a simple text game maker to allow children to create short adventure games, interactive stories, surveys, or quizzes:
The TinyCard text game maker based on a 160x128 colour TFT display
and an ATtiny3224.
It's based on a low-cost TFT display controlled by an ATtiny3224 microprocessor. It includes four coloured buttons for interacting with the games, and there's an interface to a keyboard for entering and editing text. An optional SD card socket lets you save and load games, or give them to friends to play. The whole circuit is powered by two AAA batteries, and they act as a convenient angled stand for the PCB.
Introduction
TinyCard was inspired by my earlier project Scrolling Text Display. I originally designed that to allow children to create the types of displays seen in buses and trains, but soon realised that it was being used in a wider range of play activities, including storytelling, and as a component in larger games.
This led me to thinking about how the Scrolling Text Display could be extended to allow more interaction with the text it displays, and the result was this TinyCard project. The concept is that it allows you to create a series of 'Cards', each of which can contain up to a screenful of text. For example, each card could present a question in a quiz, or the description of a location in an interactive story.
Each card can also contain hidden codes that determine which card you go to when one of four buttons is pressed, allowing you to create a network of questions and responses. You can create up to 12 cards, and all the content is retained when TinyCard is powered down. And it's free from the threat of advertising, in-app purchases, or unwanted updates to the content!
Also, one type of play I observed with the Scrolling Text Display was that it was made part of a larger game, such as a vending machine made from a cardboard box, and it's hard to do this with a mobile phone. I designed the TinyCard with this possibility in mind, so you can play the game with the keyboard disconnected, using just the four buttons below the display.
Using TinyCard
TinyCard provides you with 12 cards, numbered 1 to 12, which can contain text, describing your game, and prompts, which will jump to another card when the player presses one of the four coloured buttons.
The set of 12 cards is referred to as a "pack".
Edit mode
In Edit mode you can type or edit the text on a card. Each card can contain up to a screenful of text.
Press F1 to F12 to display card 1 to card 12. The number of the current card is shown in the top right corner of the card.
You can then type text on the current card with the keyboard. Words wrap automatically to the next line, but you can type a Return to force a new line. You can delete characters with the Backspace key to correct mistakes, or clear the text with Ctrl-X.
You can also include up to four prompts on the card. Each prompt gives a choice in the game which allows the player to jump to another card.
To make a prompt press Alt-F1 to Alt-F12 to insert a code ,
,
, etc, where the number is the number of the card you want to jump to. Follow the code by a prompt to the player. In Play mode the codes won't appear, and the prompt words will be displayed in colour.
For example, on a card you could write:
Note: don't leave a space between the code and the prompt word.
The prompts will be assigned to the buttons in sequence: red, yellow, green, and blue. So the above example specifies that if the player presses the red button the game will jump to card 4, the yellow button will jump to card 3, the green button to card 6, and the blue button to card 5.
If you want a prompt of more than one word you can put an underscore (Shift -) between each word. The underscores will be shown as spaces in Play mode.
Play mode
In Play mode you can display the cards and use the four coloured buttons to respond to the prompts on each card.
To see what a card will look like in Play mode press Esc.
In Play mode the previous example will be displayed as:
To switch back to Edit mode press Esc again. The only keyboard key that works in Play mode is Esc.
To play a game
Usually each game will start on card 1, so to play a game press F1 to select this card, and then press Esc to go into Play mode.
You can use TinyCard in Play mode without the keyboard. Put TinyCard to sleep before plugging it back in.
Saving a pack to SD card
Although TinyCard can be used without an SD card interface, the addition of SD cards adds the ability to save packs to an SD card so you can play them again at a later time, or give them to a friend to play.
To save the current pack type Ctrl-S. A screen shows the contents of the SD card:
The letters shown in white are packs you've saved previously. The letters shown in grey are unused names.
Press a letter key, from A to Z, to save the pack. If you choose one of the packs already on the SD card it will be replaced.
Alternatively press any other key to cancel saving.
Loading a pack from SD card
To load a pack from SD card press Ctrl-L. A screen shows the contents of the SD card:
The letters shown in white are the packs available to load.
Press a letter key, from A to Z, to load the pack. Note that this will replace any pack you currently have loaded in TinyCard.
Alternatively press any other key to cancel loading.
Key summary
Here's a summary of the special key functions:
Key | Description |
Esc | Switches between Edit mode and Play mode. |
F1 to F12 | In Edit mode, shows the corresponding card 1 to 12. * |
Alt-F1 to Alt-F12 | Enters a code to jump to card 1 to 12 respectively. |
Ctrl-X | Cuts the text from the current card and saves it on the clipboard. |
Ctrl-C | Copies the text from the current card and saves it on the clipboard. |
Ctrl-V | Pastes the text from the clipboard replacing the current card. |
Ctrl-L | Loads a saved pack from SD card, A to Z. |
Ctrl-S | Saves the current pack to SD card, A to Z. |
Ctrl-B | Loads a built-in game, 1 to 4. |
Scroll Lock | Saves a screenshot as a BMP file to the SD card. * |
* To get F11, F12, and Scroll Lock on some keyboards you have to hold down the Fn key.
Switching on and off
To switch off TinyCard press the ON/OFF button. The display will show Sleeping… and then fade off. Alternatively, TinyCard automatically goes to sleep if you haven't pressed any keys for five minutes. In sleep mode TinyCard retains everything you've created, provided you don't remove the batteries.
To switch on again when TinyCard is asleep press the ON/OFF button.
Saving screenshots
Pressing ScrollLock saves the current screen as a BMP format image file on the SD card. This allows you to make printed materials, such as game instructions, showing screenshots.
After pressing ScrollLock the screen dims while screenshot is being saved.
Built-in games
TinyCard includes the following built-in games:
Game | Title | Description |
1 | Number Game | Think of a number and see what result you get |
2 | The Island | Can you survive on treasure island? |
3 | Animal Quiz | Test your knowledge of animals |
4 | Colour Game | Can the game guess your favourite colour? |
5 | Twisty Maze | Escape from the maze |
You can load these even if you don't have an SD card.
Playing a built-in game
To load a built-in pack from the TinyCard flash memory press Ctrl-B. A screen shows how many packs are available:
Press a number key, from 1 to 4, to load the pack. Note that this will replace any pack you currently have loaded in TinyCard.
Alternatively press any other key to cancel loading.
1 - Number Game
In Number Game you follow the instructions, and the game predicts what result you'll get:
2 - The Island
This is a simple adventure game on a treasure island:
3 - Animal Quiz
This asks you four questions about animals, and tells if you got them all correct:
4 - Colour Game
Think of a colour; the game will try and guess it:
5 - Twisty Maze
Escape from the maze of twisty little passages:
The circuit
Here's the circuit of TinyCard:
The circuit of the TinyCard simple text game maker.
The circuit consists of four components:
- The ATtiny3224 processor, a 14-pin chip that's one of my favourite microcontrollers because of its unusually large amount of RAM and flash memory for its size; see On Bytes and Pins.
- A 1.8" 160x128 colour TFT display. Sockets are provided to allow you to use one of two alternative displays.
- An interface to a PS/2 keyboard for entering and editing text.
- An optional SD card interface, for saving and reloading packs.
Power supply
The aspect of the design that went through most revisions was the power supply. The ATtiny3224 can operate from 1.8V to 5.5V; the display and SD card interface require 3.3V; and the PS/2 keyboard requires 4.5V to 5V.
After several experiments with different configurations the final version uses two AAA cells to provide the 3V power supply, and a MAX619 DC-to-DC converter chip to provide the 5V keyboard supply from this [1]. During power-down the ATtiny3224 is put in low-power sleep mode, the 3V supply to the TFT display is switched off using a P-MOSFET, and the 5V supply to the keyboard is switched off using the SHUTDOWN pin on the MAX619.
Buttons
The four coloured Play buttons and the ON/OFF button are detected by a single analogue input, using a resistor ladder to generate a different input voltage identifying each button. This technique is explained in my earlier article Getting Extra Pins on ATtiny.
Build options
In the process of designing the PCB for TinyCard I tested several component options, and the PCB allows you to choose between them depending on your preferences:
Display
TinyCard is based on a 1.8" 160x128 colour TFT display with an ST7735R driver. The PCB is designed for a low-cost display module from AliExpress [2] or Amazon [3].
Use the 8-way row of pins on the left for the AliExpress/Amazon display. To ensure that your display is compatible, check that it has the following 8-way pin header:
GND | VCC | SCL | SDA | RES | DC | CS | BL |
The AliExpress displays I've used successfully have a blue PCB. They sell other 160x128 TFT displays with a red PCB that have a different pin layout; these won't be suitable for use with the TinyCard PCB.
Tthe 10-way row of pins on the right were to allow for the possibility of using an equivalent Adafruit display, but this isn't yet supported.
The display header pin holes are staggered, with each hole shifted 8 mil (~0.2 mm) off-centre. This allows you to push the display's pin headers in place, and they will stay firmly connected without soldering. To remove them press evenly with a suitable flat object. Of course you also have the option of soldering them if you prefer, for a permanent solution.
SD card socket
The optional SD card interface allows you to save and reload packs. The PCB will accommodate either of two different designs of full-size SD card sockets:
- This slimline push-push socket is available on Mouser.co.uk [4].
- This slightly thicker push-pull socket is available on Farnell [5] or AliExpress [6].
SD cards
TinyCard packs take up very little space on the SD card, so there's no advantage in having a card larger than 8GB or 16GB, which seem to be the smallest sizes currently available. I've had good results with Extreme PRO cards from King USB Store on AliExpress [7], or Microdrive cards from Memory Backup Store on AliExpress [8].
Note that the Arduino SD Card library used in this project only supports FAT16 or FAT32; FAT12 and ExFAT are not supported. All the cards I've bought come already formatted in FAT32 format.
Power
Power is provided by two AAA batteries in series, with the batteries mounted onto the back of the PCB. You can either use two separate PCB-mounting battery holders [9], or a double battery holder [10].
Note that if you're using a double battery holder make sure it has the correct polarity; I've seen similar battery holders for sale which have the orientation of the two cells reversed, and these won't be compatible with the PCB.
The active current consumption is about 38mA, so with alkaline AAA batteries that have a capacity of 1200mAh this will give about 32 hours of usage. TinyCard goes to sleep if not used for 5 minutes, and the consumption in sleep is negligible.
Fit the 100µF capacitor if you plan to power TinyCard from an external power supply. It will absorb the power surge when TinyCard comes out of sleep; otherwise the processor may reset. You can omit it if you are only powering TinyCard from batteries.
Keyboard
The keyboard should be terminated in a USB-A plug, but include support for the older PS/2 interface. I've tested the project with two different keyboards:
- The low-cost 284 x 122mm Slim Chiclet Keyboard [11] is a good full-sized keyboard, which works well.
- The 220 x 118mm MC Saite MC-8017 Miniature PS/2 and USB keyboard is a more compact keyboard, available from Adafruit [12]:
MC Saite MC-8017 Miniature PS/2 and USB keyboard.
Here's the full parts list (click to expand):
► Parts list
Construction
I designed a PCB in Eagle and sent it to JLCPCB for production. There's a link at the end of the article if you want to make yourself some boards.
Solder the surface-mount components first. The ICs are in SOIC packages and the other other surface-mount components are 0805, so they should be reasonably easy to solder by hand using a fine-tipped soldering iron. Alternatively you can use a hot air gun; I used a Youyue 858D+ hot air gun set to 275°C.
Solder the push buttons, USB-A socket, and battery holders using a conventional soldering iron:
The back of the TinyCard PCB showing the battery holders mounted above the SD card socket.
After soldering the battery-holder terminals, clip the leads as close to the PCB as possible so they won't touch the back of the display. Note that the battery holders use steel leads rather than copper wire, so don't use your best wire cutters as they will make dents in the jaws. Ideally use special steel wire cutters hardened to HRC 64.
Finally insert the display by gently pressing the header pins into the PCB holes. I held the display in place with a double-sided sticky pad.
The program
The TinyCard firmware has ended up quite a bit larger than most of my projects, so the following is just an overview of the code. It consists of the following modules:
Graphics library
The program uses my Compact TFT Graphics Library to drive the display. This uses standard SPI calls to interface with the ST7735R display driver, and supports plotting points and drawing lines, drawing filled and open rectangles, and plotting characters and text in 16-bit colour. It uses the extension described in Smooth Big Text with Hints to generate smooth double-sized characters from a standard 5x7 pixel character set, allowing 13 characters x 8 lines on the 160x128 pixel TFT display.
It also supports reading pixels back from the display using the routine described in Reading from a TFT Display. This is used to allow you to save screenshots from TinyCard to an SD card, by calling the routine bmpSave().
Keyboard interface
TinyCard includes an interface for the older PS/2 protocol. This is a much simpler protocol than USB that can be decoded by a processor such as the ATtiny3224. Fortunately many USB keyboards include legacy support for PS/2; some suitable keyboards are described above.
The keyboard interface decodes key presses under interrupt, and stores each key in the global variable KeyBuf; it also stores the state of the Ctrl and Alt keys in the global variables KeyBufCtrl and KeyBufAlt. The interface is based on the one I used in the Scrolling Text Display project.
SD card interface
The SD card interface consists of the functions SDSave() and SDLoad() to save the pack to an SD card, and load a pack from SD card. Packs are named with a single letter filename, from A to Z, and a .PAK extension (for pack). The routines ChooseFile() and ChooseBuiltin() display a dialog showing the available filenames to load/save, and wait for the user to press a letter or digit to choose the file to load/save.
Comment out the directive #define SDCARD at the start of the program if the SD card socket isn't fitted.
TinyCard memory structure
The TinyCard content in stored in a struct named Pack:
struct { union { struct { uint8_t PackName; // Currently selected pack uint8_t Card; // Currently selected card uint16_t EndPtr; // Points after last character uint16_t StartPtr[Cards+1]; uint8_t Buffer[MaxMessage]; }; uint8_t Copybuf[PackSize]; }; } Pack;
The maximum total amount of text that can be stored on the 12 cards is 13x8x12 or 1248 characters. This text is stored in a single text buffer, Buffer[1248], with pointers StartPtr[0] to StartPtr[11] to the start of the text on each card, and StartPtr[12] to the end of the text on the last card.
In Play mode the buffer is packed, so that the start of each card immediately follows the end of the previous card, and there is blank space from the end of the last card to the end of the buffer.
Entering Edit mode calls SplitBuf() to expand the currently selected card, Pack.Card, with spaces by shuffling all subsequent cards to the end of the buffer. Text entry then simply writes in the current card at the cursor position given by Pack.EndPtr.
Switching to Play mode calls JoinBuf() to compact all the cards so they're contiguous, and the blank space is moved to the end of the buffer. JoinBuf() is also called before saving the pack to SD card to minimise the data that needs to be saved.
Displaying cards
The routine ShowCard(false) displays a card in Edit mode, and ShowCard(true) displays a card in Play mode.
The main difference is that in Edit mode the card number is displayed in the top right corner of the card, and the cursor is shown after the last character in the card.
In Play mode the control codes are hidden, but these change the Foreground colour of the prompts to ButtonColour[], and the destination card for each prompt is recorded in the array Button[].
Processing key and button presses
The main program loop, in loop(), checks the global variable KeyBuf, and if a key has been typed it calls ProcessKey() with the key and the state of the Ctrl and Alt keys.
ProcessKey() then handles the action of each key press, depending on whether TinyCard is in Play mode or Edit mode.
In Play mode the only keys that have an effect are Esc, to go to Edit mode, and Scroll Lock, to save a screenshot.
In Edit mode the keys are interpreted as follows:
- Esc goes to Play mode.
- F1 to F12 display the corresponding card 1 to 12.
- Ctrl-S followed by A to Z saves the current pack to SD card as A.PAK to Z.PAK.
- Ctrl-L followed by A to Z loads a pack A.PAK to Z.PAK from SD card.
- Ctrl-B followed by 1 to 4 loads a built-in game from the TinyCard flash memory.
- Scroll Lock saves a screenshot. Successive screenshots are named IMAGEA.BMP, IMAGEB.BMP, etc.
- Ctrl-C copies the text on the current card to the clipboard.
- Ctrl-X cuts the text from the current card to the clipboard.
- Ctrl-V pastes the text from the clipboard to the current card if the clipboard isn't empty.
- Backspace deletes the character before the cursor.
- Return inserts a return character, to move to the start of the next line.
- Alt-F1 to Alt-F12 insert the corresponding control code 1 to 12.
Characters other than these are inserted at the cursor position. Where possible, words are automatically wrapped onto the next line if they won't fit on the end of the current line.
Sleep
The main loop in loop() times how long TinyCard has been awake for, and when Timeout has been exceeded (by default, five minutes) calls GoToSleep() to enter a low power mode. Alternatively, pressing the ON/OFF button calls GoToSleep() immediately.
Finding the best configuration of the I/O pins for minimum power consumption in sleep involved a bit of experimentation. The GoToSleep() routine performs the following actions:
- Displays sleeping… and slowly dims the backlight.
- Takes Enable high to switch off power to the display and keyboard.
- Configures the TFT display and SD card signals as inputs to minimise power consumption.
- Turns off the DATA and CLOCK pullups and CLOCK interrupt from the keyboard.
- Turns on a pin change interrupt to the Buttons pin, to allow the ON/OFF switch to wake from sleep.
- Puts the ATtiny3224 to sleep by calling sleep_cpu();
The typical current consumption in sleep is 0.2µA. When the processor is woken up by the Buttons pin interrupt, execution continues and the ports are set back into their usual states.
Compiling and uploading
Compile the program using Spence Konde's MegaTiny Core [13]. Choose the ATtiny3224 (No bootloader) option under the ATTinyCore heading on the Board menu. Then check that the subsequent options are set as follows (ignore any other options):
Chip: "ATtiny3224"
Clock Speed: "20 MHz internal"
The recommended option is to use a 5V Serial board, such as the SparkFun FTDI Basic board [14], or a USB to Serial cable [15], connected with a Schottky diode as follows. You can substitute a 4.7kΩ resistor for the Schottky diode:
- Set Programmer to the first of the "SerialUPDI - 230400 baud" options.
- Select the USB port corresponding to the USB to Serial board in the Port menu.
- Choose Burn Bootloader to set the fuses.
- Then choose Upload from the Arduino IDE Tools menu to upload the program.
Adding your own built-in packs
The TinyCard program is provided with five built-in packs already defined, but you can add your own, up to the limit of available program memory. To do it proceed as follows:
- Save the pack to SD card in the usual way.
- Insert the SD card into a computer, and access the SD card from a terminal program.
- Give the Unix command:
xxd -i H.PAK
where H.PAK is the name of the pack you saved. This will print the data on the card in a C compatible format.
For example, here is a pack just containing "Hello World" on the first card:
unsigned char H_PAK[] = { 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 }; unsigned int H_PAK_len = 41;
- Copy the lines of hexadecimal data and paste them after the existing data in the definition of BuiltinPack[] in the TinyCard source, adding curly brackets as necessary to maintain the structure.
- Finally, increase the value of:
const int Packs = 5;
to reflect the pack definition you have added.
Resources
Here's the TinyCard program: TinyCard Program.
Get the Eagle or Gerber files for the PCB on GitHub here: https://github.com/technoblogy/tinycard.
Or order boards from OSH Park here: TinyCard.
- ^ MAX619 datasheet on analog.com.
- ^ 1.8" 128x160 SPI TFT display on AliExpress.
- ^ LCD Display Module 1.8" 160x128 on Amazon.co.uk.
- ^ Same Sky SD-1-a on Mouser.co.uk.
- ^ Memory Card Connector SD Push-Pull on Farnell.com.
- ^ SD Card Holder Non Self Popping on AliExpress.
- ^ Extreme PRO 16GB SD Card on AliExpress.
- ^ Microdrive 16GB SD Card on AliExpress.
- ^ AAA Battery Holder PCB Mount on Switch Electronics.
- ^ Keystone 2468 2xAAA Battery Holder on Rapid Online.
- ^ Slim Chiclet Keyboard on Pimoroni.
- ^ Miniature PS/2 and USB keyboard on Adafruit.
- ^ MegaTinyCore on GitHub.
- ^ SparkFun FTDI Basic Breakout - 5V on Sparkfun.
- ^ FTDI Serial TTL-232 USB Cable on Adafruit.
blog comments powered by Disqus