UPDATE: I’ve now started a GitHub repository, and uploaded the code there:
https://github.com/michaelbapst/CYD-ESP32-2432S028R/tree/main
I’ve also made more versions of Name Badge:
NameBadge2: Removed the enormous Switch/Case statement and replaced it with 2D String array.
NameBadge3: Added code to change the Random Number seed with the X * Y of where the screen has been touched, thereby changing how the list of names get’s displayed.

Cheap Yellow Display (CYD)

I recently stumbled across Brian Lough’s [witnessmenow] ESP32 Cheap Yellow Display git hub page, via Hackaday’s Article about the CYD. The Cheap Yellow Display is an ESP32 development board with the following features:

  • ESP32 (With Wifi and Bluetooth)
  • 320 x 240 LCD Display (2.8″)
  • Touch Screen (Resistive)
  • USB for powering and programming
  • SD Card Slot, LED and some additional pins broken out

I purchased mine through Ali Express for $6.94USD including shipping, and I got it in less than 2 weeks. There are a number of projects on a variety of git repositories. You can find a list here. One of my personal favorites is ESP32-Marauder, which turns the CYD into a neat little WIFI/Bluetooth hacking device.

Once you get your CYD, you’ll need to set it up, and here are detailed instructions. Make sure you follow them completely, setup your Arduino IDE with the correct libraries, and install User_Setup.h in <USERNAME>\Documents\Arduino\libraries\TFT_eSPI. Nothing using the TFT_eSPI Library will work with out the User_Setup.h installed.

Since I am playing Odin at my local renaissance faire this Autumn, I wanted to an electronic name badge that randomly shows 1 of 96 names of Odin both in English and Elder Futhark Runes. I started by using the code from “Hello World” for Cheap Yellow Display by Brian Lough, added code snippets from other examples, encoded a runic font file (FutharkAOE28 Is based on Futhark AOE Regular Brian J. Bonislawsky astigma@astigmatic.com), and some help from Microsoft’s Copilot AI. I haven’t written anything in C language since the ’90’s, and I haven’t done any real coding in over 15 years. Copilot was a huge help. Here is a video of the end product:

I’m quite happy with the end product. I’m sure the code could be further optimized. Like I said, I haven’t done this in a very long time. Instead of using a giant Switch/Case statement, I probably could have grabbed a name from a text file on an sdcard. But I didn’t want to fiddle with fileIO, and this code works without having an sdcard installed. You can download the code from GitHub, or follow along below:
(Updated to NameBadge3)

namebadge3.ino

/*******************************************************************
    Name Badge  
    Adapted by Michael Bapst (https://www.einherjar.org)

    Name Badge is based on "Hello World" for the ESP32 Cheap Yellow Display.
    https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display

    Written by Brian Lough
    YouTube: https://www.youtube.com/brianlough
    Twitter: https://twitter.com/witnessmenow
    
    Touch code was taken from Rui Santos & Sara Santos - Random Nerd Tutorials
    Additional code was supplied by Microsoft Copilot, who helped me remember
    a lot of C/C++, which I hadn't touched since the 90's
 *******************************************************************/

// Make sure to copy the UserSetup.h file into the library as
// per the Github Instructions. The pins are defined in there.
#include <string>
#include "NotoSansBold36.h"
#include "FutharkAOE.h"
#include "namelist.h"

// The font names are arrays references, thus must NOT be in quotes ""
#define AA_FONT_LARGE NotoSansBold36
#define AA_FONT_RUNIC FutharkAOE28 
#define Name_List cNameList

#include <SPI.h>

// A library for interfacing with LCD displays
// Can be installed from the library manager (Search for "TFT_eSPI")
//https://github.com/Bodmer/TFT_eSPI
#include <TFT_eSPI.h>       // Hardware-specific library

TFT_eSPI tft = TFT_eSPI();

// Install the "XPT2046_Touchscreen" library by Paul Stoffregen to use the Touchscreen - https://github.com/PaulStoffregen/XPT2046_Touchscreen
// Note: this library doesn't require further configuration
#include <XPT2046_Touchscreen.h>

// Touchscreen pins
#define XPT2046_IRQ 36   // T_IRQ
#define XPT2046_MOSI 32  // T_DIN
#define XPT2046_MISO 39  // T_OUT
#define XPT2046_CLK 25   // T_CLK
#define XPT2046_CS 33    // T_CS

// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;

SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

void RNDSeedTouch(int touchX, int touchY, int touchZ) {
  srand(touchX * touchY);
}

void setup() {
  //Initial Random seed value. The random seed will change when you touch the screen
  srand(69); //Nice...
  
  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  touchscreen.begin(touchscreenSPI);
  // Set the Touchscreen rotation in landscape mode
  // Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 3: touchscreen.setRotation(3);
  touchscreen.setRotation(1);

  // Start the tft display and set it to black
  tft.init();
  tft.setRotation(1); //This is the display in landscape
  
  // Clear the screen before writing to it
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);
  tft.drawString("HELLO, MY NAME IS...", 5, 10, 4); // Left Aligned
  tft.drawCentreString("(ODIN)", 160, 200, 2); 
  tft.loadFont(AA_FONT_LARGE); // Must load the font first
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
  tft.drawCentreString("Michael", 160, 90, 4); //Center Aligned
  tft.unloadFont(); // Remove the font to recover memory used
  delay(3000);
}


void loop() {
  
  //Checks to see if the screen has been touched, and if it has
  //Seed the random number with X * Y of where the screen has been touched.
  if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, 320);
    y = map(p.y, 240, 3800, 1, 240);
    z = p.z;
    
    RNDSeedTouch(x, y, x);

    // Uncomment the next two lines to print the new random seed to the screen.
    //tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
    //tft.drawCentreString(String(x * y), 160, 220, 2);

    delay(100);
  }

  int rndNumber = rand() % 96; //Pick a number between 0 and 96
  //Randomly selected name so it doesn't look like your going down an alphabetical list

  //Print Name in Roman Characters
  tft.loadFont(AA_FONT_LARGE);    // Must load the font first]
  //Blank out old text instead of clearing the screen. This prevents screen flashing 
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
  tft.drawCentreString("                                  ", 160, 90, 4);
  tft.drawCentreString(Name_List[rndNumber][0], 160, 90, 4);              //Write new text
  tft.unloadFont(); // Remove the font to recover memory used
  
  //Print Name is Runic Characters
  tft.loadFont(AA_FONT_RUNIC);    // Must load the font first
  tft.setTextColor(TFT_RED, TFT_BLACK, true);
  tft.drawCentreString("                                  ", 160, 140, 4); //Clear old text
  tft.drawCentreString(Name_List[rndNumber][1], 160, 140, 4);              //Write new text
  tft.unloadFont(); // Remove the font to recover memory used

  delay(2000); //wait 2 seconds and start over
}

namelist.h

/* *****************************************************************************************
                              A list of Odhinn's names
Odin has 170 different names. More if you count the different spellings of the same name:
ODIN -> ODHINN -> OTHEN -> WODEN -> WOTAN
Here I have selected 96 of them.
The first name is Old Norse ---> English spelling 
The Second Name is the Rune friendly Spelling (Y=I, C=K, V=W, etc.)
*******************************************************************************************/

const String cNameList[96][2] = {
  { "Alfadhr", "alfadhr" }, 
  { "Aldagautr", "aldagautr" },
  { "Atridhr", "atridhr" },
  { "Asagrim", "asagrim" },
  { "Audhun", "audhun" },
  { "Baleygr Baleyg", "baleigr baleig" },
  { "Biflindi", "biflindi" },
  { "Blindr", "blindr" },
  { "Bolverkr", "bolwerkr" },
  { "Draugadrottinn", "draugadrottinn" },
  { "Dresvarpr", "dreswarpr" },
  { "Drottinn", "drottinn" },
  { "Farmagnudhr", "farmagnudhr" },
  { "Farmatyr", "farmatir" },
  { "Fimbultyr", "fimbultir" },
  { "Fimbulthulr", "fimbulthulr" },
  { "Fjolnir", "fjolnir" },
  { "Fjolsvidhr", "fjolswidhr" },
  { "Foldardrottinn", "foldardrottinn" },
  { "Forni", "forni" },
  { "Gagnradhr", "gagnradhr" },
  { "Galdrafodhr", "galdrafodhr" },
  { "Fadhir galdrs", "fadhir galdrs" },
  { "Ganglari", "ganglari" },
  { "Gautr", "gautr" },
  { "Geirtyr", "geirtir" },
  { "Geirvaldr", "geirwaldr" },
  { "Glapsvidhr", "glapswidhr" },
  { "Gondlir", "gondlir" },
  { "Grimnir", "grimnir" },
  { "Gunnblindi", "gunnblindi" },
  { "Hagvirkr", "hagwirkr" },
  { "Hangadrottinn", "hangadrottinn" },
  { "Hangatyr", "hangatir" },
  { "Hangi", "hangi" },
  { "Haptagudh", "haptagudh" },
  { "Harbardhr", "harbardhr" },
  { "Harr", "harr" },
  { "Havi", "hawi" },
  { "Helblindi", "helblindi" },
  { "Herjafodhr", "herjafodhr" },
  { "Herjan", "herjan" },
  { "Herteitr", "herteitr" },
  { "Hildolfr", "hildolfr" },
  { "Hjaldrgegnir", "hjaldrgegnir" },
  { "Hjalmberi", "hjalmberi" },
  { "Hnikarr", "hnikarr" },
  { "Hoarr", "hoarr" },
  { "Hrafnagudh", "hrafnagudh" },
  { "Hroptatyr", "hroptatir" },
  { "Jafnharr", "jafnharr" },
  { "Odhinn", "odhinn" },
  { "Ofnir", "ofnir" },
  { "Reidhartyr", "reidhartir" },
  { "Rognir", "rognir" },
  { "Runatyr", "runatir" },
  { "Sadhr", "sadhr" },
  { "Sanngetall", "sanngetall" },
  { "Sidhgrani", "sidhgrani" },
  { "Sidhhottr", "sidhhottr" },
  { "Sidhskeggr", "sidhskeggr" },
  { "Sigfodhr", "sigfodhr" },
  { "Sigrunnr", "sigrunnr" },
  { "Sigtryggr", "sigtriggr" },
  { "Sigtyr", "sigtir" },
  { "Sigthror", "sigthror" },
  { "Skilfingr", "skilfingr" },
  { "Skollvaldr", "skollwaldr" },
  { "Svafnir", "swafnir" },
  { "Sveigdhir", "sweigdhir" },
  { "Svidhrir", "swidhrir" },
  { "Svipall", "swipall" },
  { "Svolnir", "swolnir" },
  { "Tviblindi", "twiblindi" },
  { "Thekkr", "thekkr" },
  { "Thrasarr", "thrasarr" },
  { "Thridhi", "thridhi" },
  { "Thriggi", "thriggi" },
  { "Throttr", "throttr" },
  { "Udhr", "udhr" },
  { "Vafudhr", "wafudhr" },
  { "Valfodhr", "walfodhr" },
  { "Valgautr", "walgautr" },
  { "Valkjosandi", "walkjosandi" },
  { "Valtamr", "waltamr" },
  { "Valtyr", "waltir" },
  { "Valthognir", "walthognir" },
  { "Vegtam", "wegtam" },
  { "Veratyr", "weratir" },
  { "Vidhfrager", "widhfrager" },
  { "Vidhrir", "widhrir" },
  { "Vidhrimnir", "widhrimnir" },
  { "Vidhurr", "widhurr" },
  { "Vingnir", "wingnir" },
  { "Woden", "woden" },
  { "Wotan", "wotan" },
};

NotoSansBold36.h – Too large to display.
FutharkAOE.h – Too large to display

(Listing the above files is giving WordPress a complete fit. Removed for now. Download the project from GitHub.)

By Lynx

Born in the 70's. Grew up in Western NY. Happily married, and has 2 children. Lives in Connecticut.