{"id":4922,"date":"2025-07-28T08:00:30","date_gmt":"2025-07-28T15:00:30","guid":{"rendered":"https:\/\/www.cloudacm.com\/?p=4922"},"modified":"2025-07-27T21:31:21","modified_gmt":"2025-07-28T04:31:21","slug":"esp8266-cheap-heads-up-display-c-h-u-d-ii","status":"publish","type":"post","link":"https:\/\/www.cloudacm.com\/?p=4922","title":{"rendered":"ESP8266 Cheap Heads Up Display &#8211; C.H.U.D. II"},"content":{"rendered":"<p>This post is a branch from the earlier ESP32 based heads up display. Instead of using the frame buffer as a canvas to write text and variables or draw graphics, this post will use NTSC encoding.<\/p>\n<p><iframe loading=\"lazy\" title=\"ESP8266 Wemos NTSC HUD Demo\" src=\"https:\/\/player.vimeo.com\/video\/1099360468?dnt=1&amp;app_id=122963\" width=\"640\" height=\"480\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\"><\/iframe><\/p>\n<p>See this Wikipedia link for more details about NTSC, <a href=\"https:\/\/en.wikipedia.org\/wiki\/NTSC\">https:\/\/en.wikipedia.org\/wiki\/NTSC<\/a>. The code used in this post is a deviation from Matthias Goebl&#8217;s Github repo, <a href=\"https:\/\/github.com\/matgoebl\/esp8266-ntsc-c64-emulator\">https:\/\/github.com\/matgoebl\/esp8266-ntsc-c64-emulator<\/a> with credit given to Jan Ostman, <a href=\"https:\/\/www.hackster.io\/janost\">https:\/\/www.hackster.io\/janost<\/a>. I&#8217;m grateful to both of them for providing the foundation for what is presented here.<\/p>\n<p>Most all other examples of NTSC or PAL use the Arduino Uno or ESP32. The Uno required 2 pins whereas the ESP32 used a pin not available on the ESP8266. Yes, ChatGPT was used in the effort because most every other human has abandoned developing on the ESP8266. I have a few hundred of these devices, so it&#8217;s a viable effort for me at least.\u00a0 This video will provide some background for anyone curious about the topic of NTSC, the basis of Analog FPV.<\/p>\n<p><iframe loading=\"lazy\" title=\"How Analog Video works in FPV!\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/szJOUXineYw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>The specific hardware behind this project is the ESP8266 Wemos D1 mini clone. The module uses only one pin for the video out feed using the UART RX GPIO3 Pin. It is fed through a series of resisters with a tap that feeds a filtering capacitor out to the video input of the NTSC compatible device. There is an additional capacitor to filter high frequency noise to ground.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-4941\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit-1024x504.png\" alt=\"\" width=\"640\" height=\"315\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit-1024x504.png 1024w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit-300x148.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit-768x378.png 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit-549x270.png 549w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/Wemos-NTSC_Circuit.png 1122w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a>I also used the RunCam Mini FPV DVR to record the NTSC feed from the ESP8266, <a href=\"https:\/\/shop.runcam.com\/runcam-mini-fpv-dvr\/\">https:\/\/shop.runcam.com\/runcam-mini-fpv-dvr\/<\/a>.\u00a0 I used another RunCam for the background video.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/RunCam-Mini-FPV-DVR-Pinout.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-4934\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/RunCam-Mini-FPV-DVR-Pinout.jpg\" alt=\"\" width=\"506\" height=\"381\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/RunCam-Mini-FPV-DVR-Pinout.jpg 506w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/RunCam-Mini-FPV-DVR-Pinout-300x226.jpg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/RunCam-Mini-FPV-DVR-Pinout-359x270.jpg 359w\" sizes=\"auto, (max-width: 506px) 100vw, 506px\" \/><\/a><\/p>\n<p>The code was compiled using the Arduino IDE with these board settings, LOLIN(WEMOS) D1 mini (clone), 4MB (FS:none OTA:~1019KB). The bulk of the code uses native libraries from Jan&#8217;s code, which was available here <a href=\"https:\/\/hacksterio.s3.amazonaws.com\/uploads\/attachments\/650768\/ESP8266-NTSC-C64.zip\">https:\/\/hacksterio.s3.amazonaws.com\/uploads\/attachments\/650768\/ESP8266-NTSC-C64.zip<\/a>. This list indicates the code changes made.<\/p>\n<p>file &#8211; cpu.c<\/p>\n<p>I had to add change this line, <strong>prog_uchar BIOS[16384] PROGMEM = {<\/strong><br \/>\nto this, <strong>const unsigned char BIOS[16384] PROGMEM = {<\/strong><\/p>\n<p>These files remained unchanged.<\/p>\n<p>dmsstuff.h<br \/>\ngenerate_video.c<br \/>\npin_mux_register.h<br \/>\nslc_register.h<\/p>\n<p>Finding the character ROM was a real joy, not really.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/VID00001.AVI-00001.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-4929\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/VID00001.AVI-00001.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/VID00001.AVI-00001.png 640w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/VID00001.AVI-00001-300x225.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/VID00001.AVI-00001-360x270.png 360w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p>There was a lot of trial and error only to find that it was staring me in the face. All I had to do was count from the upper left corner to the right and down.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-4930\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08.png\" alt=\"\" width=\"864\" height=\"218\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08.png 864w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08-300x76.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08-768x194.png 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2025\/07\/901439-08-604x152.png 604w\" sizes=\"auto, (max-width: 864px) 100vw, 864px\" \/><\/a><\/p>\n<p>See this site <a href=\"https:\/\/cbmsteve.ca\/cbmchr\/index.html\">https:\/\/cbmsteve.ca\/cbmchr\/index.html<\/a>, much thanks to Steve J. Gray for bringing back memories of simpler times. Once I had the binary ROM file, I used this bash and python script to extract the array.<\/p>\n<p>Bash<\/p>\n<pre>#!\/bin\/sh\r\npython 2-generate_petscii.py 901439-08.bin &gt; 901439-08_petscii_font.h\r\nexit<\/pre>\n<p>Python<\/p>\n<pre>#!\/usr\/bin\/env python3\r\nimport sys\r\n\r\ndef main(rom_file):\r\ndata = open(rom_file, \"rb\").read(2048)\r\nprint(\"\/\/ Generated PETSCII font bitmap (256 chars \u00d7 8 bytes each)\")\r\nprint(\"static const uint8_t petscii_font[256][8] = {\")\r\nfor i in range(256):\r\nchunk = data[i*8:(i+1)*8]\r\nhexes = \",\".join(f\"0x{b:02X}\" for b in chunk)\r\nprint(f\" \/* 0x{i:02X} *\/ {{{hexes}}},\")\r\nprint(\"};\")\r\n\r\nif __name__ == \"__main__\":\r\nif len(sys.argv) != 2:\r\nprint(\"Usage: generate_petscii.py &lt;chargen.bin&gt;\")\r\nsys.exit(1)\r\nmain(sys.argv[1])<\/pre>\n<p>Creating the example video above was from some FFMpeg commands to take video from an action camera, crop it, and layer the NTSC video on top.<\/p>\n<p>Bash<\/p>\n<pre>#!\/bin\/sh\r\n\r\n# Crop the Runcam 1080p video to 480p\r\nffmpeg -i 20230205_133707_01.MP4 -filter:v \"crop=640:480\" 20230205_133707_01_cropped.MP4\r\n# Alpha channel the Runcam 480p video and layer both\r\nffmpeg -i 20230205_133707_01_cropped.MP4 -i HUD-Demo.AVI -filter_complex \\\r\n\"[1:v]colorkey=0x000000:0.3:0.1[ckout]; \\\r\n[0:v][ckout]overlay=(main_w-overlay_w)\/2:(main_h-overlay_h)\/2\" \\\r\n-t 60 ESP8266 Wemos NTSC HUD-Demo Overlay.mp4\r\n\r\nexit<\/pre>\n<p>Here is the Arduino code used in the H.U.D. example video above.\u00a0 It uses counters for the changing values.\u00a0 This is a demo of the NTSC feed, not interfacing sensors with the microcontroller and displaying those values.\u00a0 I&#8217;ll defer to the audience to move forward in that regard.<\/p>\n<pre>#include &lt;Arduino.h&gt;\r\n#define FREQUENCY 160\r\n\r\nextern \"C\" {\r\n#include \"user_interface.h\"\r\nvoid exec6502(int32_t tickcount);\r\nvoid reset6502();\r\n}\r\n\r\nstatic int z = 0;\r\nconst char* text;\r\nint i;\r\nint RunOnce = 0;\r\n\r\n\/\/ CBM Textset1 ROM - see https:\/\/cbmsteve.ca\/cbmchr\/index.html\r\nunsigned char charROM [256][8] = {\r\n\r\n\/* 0x00 *\/ {0x1C,0x22,0x4A,0x56,0x4C,0x20,0x1E,0x00},\r\n\/* 0x01 *\/ {0x18,0x24,0x42,0x7E,0x42,0x42,0x42,0x00},\r\n\/* 0x02 *\/ {0x7C,0x22,0x22,0x3C,0x22,0x22,0x7C,0x00},\r\n\/* 0x03 *\/ {0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00},\r\n\/* 0x04 *\/ {0x78,0x24,0x22,0x22,0x22,0x24,0x78,0x00},\r\n\/* 0x05 *\/ {0x7E,0x40,0x40,0x78,0x40,0x40,0x7E,0x00},\r\n\/* 0x06 *\/ {0x7E,0x40,0x40,0x78,0x40,0x40,0x40,0x00},\r\n\/* 0x07 *\/ {0x1C,0x22,0x40,0x4E,0x42,0x22,0x1C,0x00},\r\n\/* 0x08 *\/ {0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x00},\r\n\/* 0x09 *\/ {0x1C,0x08,0x08,0x08,0x08,0x08,0x1C,0x00},\r\n\/* 0x0A *\/ {0x0E,0x04,0x04,0x04,0x04,0x44,0x38,0x00},\r\n\/* 0x0B *\/ {0x42,0x44,0x48,0x70,0x48,0x44,0x42,0x00},\r\n\/* 0x0C *\/ {0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00},\r\n\/* 0x0D *\/ {0x42,0x66,0x5A,0x5A,0x42,0x42,0x42,0x00},\r\n\/* 0x0E *\/ {0x42,0x62,0x52,0x4A,0x46,0x42,0x42,0x00},\r\n\/* 0x0F *\/ {0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00},\r\n\/* 0x10 *\/ {0x7C,0x42,0x42,0x7C,0x40,0x40,0x40,0x00},\r\n\/* 0x11 *\/ {0x18,0x24,0x42,0x42,0x4A,0x24,0x1A,0x00},\r\n\/* 0x12 *\/ {0x7C,0x42,0x42,0x7C,0x48,0x44,0x42,0x00},\r\n\/* 0x13 *\/ {0x3C,0x42,0x40,0x3C,0x02,0x42,0x3C,0x00},\r\n\/* 0x14 *\/ {0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x00},\r\n\/* 0x15 *\/ {0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00},\r\n\/* 0x16 *\/ {0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00},\r\n\/* 0x17 *\/ {0x42,0x42,0x42,0x5A,0x5A,0x66,0x42,0x00},\r\n\/* 0x18 *\/ {0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00},\r\n\/* 0x19 *\/ {0x22,0x22,0x22,0x1C,0x08,0x08,0x08,0x00},\r\n\/* 0x1A *\/ {0x7E,0x02,0x04,0x18,0x20,0x40,0x7E,0x00},\r\n\/* 0x1B *\/ {0x3C,0x20,0x20,0x20,0x20,0x20,0x3C,0x00},\r\n\/* 0x1C *\/ {0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00},\r\n\/* 0x1D *\/ {0x3C,0x04,0x04,0x04,0x04,0x04,0x3C,0x00},\r\n\/* 0x1E *\/ {0x00,0x08,0x1C,0x2A,0x08,0x08,0x08,0x08},\r\n\/* 0x1F *\/ {0x00,0x00,0x10,0x20,0x7F,0x20,0x10,0x00},\r\n\/* 0x20 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x21 *\/ {0x08,0x08,0x08,0x08,0x00,0x00,0x08,0x00},\r\n\/* 0x22 *\/ {0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x23 *\/ {0x24,0x24,0x7E,0x24,0x7E,0x24,0x24,0x00},\r\n\/* 0x24 *\/ {0x08,0x1E,0x28,0x1C,0x0A,0x3C,0x08,0x00},\r\n\/* 0x25 *\/ {0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00},\r\n\/* 0x26 *\/ {0x30,0x48,0x48,0x30,0x4A,0x44,0x3A,0x00},\r\n\/* 0x27 *\/ {0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x28 *\/ {0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00},\r\n\/* 0x29 *\/ {0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00},\r\n\/* 0x2A *\/ {0x08,0x2A,0x1C,0x3E,0x1C,0x2A,0x08,0x00},\r\n\/* 0x2B *\/ {0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00},\r\n\/* 0x2C *\/ {0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10},\r\n\/* 0x2D *\/ {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00},\r\n\/* 0x2E *\/ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00},\r\n\/* 0x2F *\/ {0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00},\r\n\/* 0x30 *\/ {0x3C,0x42,0x46,0x5A,0x62,0x42,0x3C,0x00},\r\n\/* 0x31 *\/ {0x08,0x18,0x28,0x08,0x08,0x08,0x3E,0x00},\r\n\/* 0x32 *\/ {0x3C,0x42,0x02,0x0C,0x30,0x40,0x7E,0x00},\r\n\/* 0x33 *\/ {0x3C,0x42,0x02,0x1C,0x02,0x42,0x3C,0x00},\r\n\/* 0x34 *\/ {0x04,0x0C,0x14,0x24,0x7E,0x04,0x04,0x00},\r\n\/* 0x35 *\/ {0x7E,0x40,0x78,0x04,0x02,0x44,0x38,0x00},\r\n\/* 0x36 *\/ {0x1C,0x20,0x40,0x7C,0x42,0x42,0x3C,0x00},\r\n\/* 0x37 *\/ {0x7E,0x42,0x04,0x08,0x10,0x10,0x10,0x00},\r\n\/* 0x38 *\/ {0x3C,0x42,0x42,0x3C,0x42,0x42,0x3C,0x00},\r\n\/* 0x39 *\/ {0x3C,0x42,0x42,0x3E,0x02,0x04,0x38,0x00},\r\n\/* 0x3A *\/ {0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00},\r\n\/* 0x3B *\/ {0x00,0x00,0x08,0x00,0x00,0x08,0x08,0x10},\r\n\/* 0x3C *\/ {0x0E,0x18,0x30,0x60,0x30,0x18,0x0E,0x00},\r\n\/* 0x3D *\/ {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00},\r\n\/* 0x3E *\/ {0x70,0x18,0x0C,0x06,0x0C,0x18,0x70,0x00},\r\n\/* 0x3F *\/ {0x3C,0x42,0x02,0x0C,0x10,0x00,0x10,0x00},\r\n\/* 0x40 *\/ {0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},\r\n\/* 0x41 *\/ {0x08,0x1C,0x3E,0x7F,0x7F,0x1C,0x3E,0x00},\r\n\/* 0x42 *\/ {0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10},\r\n\/* 0x43 *\/ {0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00},\r\n\/* 0x44 *\/ {0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x45 *\/ {0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x46 *\/ {0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},\r\n\/* 0x47 *\/ {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},\r\n\/* 0x48 *\/ {0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04},\r\n\/* 0x49 *\/ {0x00,0x00,0x00,0x00,0xE0,0x10,0x08,0x08},\r\n\/* 0x4A *\/ {0x08,0x08,0x08,0x04,0x03,0x00,0x00,0x00},\r\n\/* 0x4B *\/ {0x08,0x08,0x08,0x10,0xE0,0x00,0x00,0x00},\r\n\/* 0x4C *\/ {0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF},\r\n\/* 0x4D *\/ {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01},\r\n\/* 0x4E *\/ {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80},\r\n\/* 0x4F *\/ {0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0x80},\r\n\/* 0x50 *\/ {0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x01},\r\n\/* 0x51 *\/ {0x00,0x3C,0x7E,0x7E,0x7E,0x7E,0x3C,0x00},\r\n\/* 0x52 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00},\r\n\/* 0x53 *\/ {0x36,0x7F,0x7F,0x7F,0x3E,0x1C,0x08,0x00},\r\n\/* 0x54 *\/ {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40},\r\n\/* 0x55 *\/ {0x00,0x00,0x00,0x00,0x03,0x04,0x08,0x08},\r\n\/* 0x56 *\/ {0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81},\r\n\/* 0x57 *\/ {0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00},\r\n\/* 0x58 *\/ {0x08,0x1C,0x2A,0x77,0x2A,0x08,0x08,0x00},\r\n\/* 0x59 *\/ {0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02},\r\n\/* 0x5A *\/ {0x08,0x1C,0x3E,0x7F,0x3E,0x1C,0x08,0x00},\r\n\/* 0x5B *\/ {0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08},\r\n\/* 0x5C *\/ {0xA0,0x50,0xA0,0x50,0xA0,0x50,0xA0,0x50},\r\n\/* 0x5D *\/ {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08},\r\n\/* 0x5E *\/ {0x00,0x00,0x01,0x3E,0x54,0x14,0x14,0x00},\r\n\/* 0x5F *\/ {0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0x03,0x01},\r\n\/* 0x60 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x61 *\/ {0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},\r\n\/* 0x62 *\/ {0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF},\r\n\/* 0x63 *\/ {0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x64 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF},\r\n\/* 0x65 *\/ {0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},\r\n\/* 0x66 *\/ {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55},\r\n\/* 0x67 *\/ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},\r\n\/* 0x68 *\/ {0x00,0x00,0x00,0x00,0xAA,0x55,0xAA,0x55},\r\n\/* 0x69 *\/ {0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80},\r\n\/* 0x6A *\/ {0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03},\r\n\/* 0x6B *\/ {0x08,0x08,0x08,0x08,0x0F,0x08,0x08,0x08},\r\n\/* 0x6C *\/ {0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F},\r\n\/* 0x6D *\/ {0x08,0x08,0x08,0x08,0x0F,0x00,0x00,0x00},\r\n\/* 0x6E *\/ {0x00,0x00,0x00,0x00,0xF8,0x08,0x08,0x08},\r\n\/* 0x6F *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF},\r\n\/* 0x70 *\/ {0x00,0x00,0x00,0x00,0x0F,0x08,0x08,0x08},\r\n\/* 0x71 *\/ {0x08,0x08,0x08,0x08,0xFF,0x00,0x00,0x00},\r\n\/* 0x72 *\/ {0x00,0x00,0x00,0x00,0xFF,0x08,0x08,0x08},\r\n\/* 0x73 *\/ {0x08,0x08,0x08,0x08,0xF8,0x08,0x08,0x08},\r\n\/* 0x74 *\/ {0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0},\r\n\/* 0x75 *\/ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},\r\n\/* 0x76 *\/ {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07},\r\n\/* 0x77 *\/ {0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x78 *\/ {0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0x79 *\/ {0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF},\r\n\/* 0x7A *\/ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF},\r\n\/* 0x7B *\/ {0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0},\r\n\/* 0x7C *\/ {0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00},\r\n\/* 0x7D *\/ {0x08,0x08,0x08,0x08,0xF8,0x00,0x00,0x00},\r\n\/* 0x7E *\/ {0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00},\r\n\/* 0x7F *\/ {0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F},\r\n\/* 0x80 *\/ {0x1C,0x22,0x4A,0x56,0x4C,0x20,0x1E,0x00},\r\n\/* 0x81 *\/ {0x18,0x24,0x42,0x7E,0x42,0x42,0x42,0x00},\r\n\/* 0x82 *\/ {0x7C,0x22,0x22,0x3C,0x22,0x22,0x7C,0x00},\r\n\/* 0x83 *\/ {0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00},\r\n\/* 0x84 *\/ {0x78,0x24,0x22,0x22,0x22,0x24,0x78,0x00},\r\n\/* 0x85 *\/ {0x7E,0x40,0x40,0x78,0x40,0x40,0x7E,0x00},\r\n\/* 0x86 *\/ {0x7E,0x40,0x40,0x78,0x40,0x40,0x40,0x00},\r\n\/* 0x87 *\/ {0x1C,0x22,0x40,0x4E,0x42,0x22,0x1C,0x00},\r\n\/* 0x88 *\/ {0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x00},\r\n\/* 0x89 *\/ {0x1C,0x08,0x08,0x08,0x08,0x08,0x1C,0x00},\r\n\/* 0x8A *\/ {0x0E,0x04,0x04,0x04,0x04,0x44,0x38,0x00},\r\n\/* 0x8B *\/ {0x42,0x44,0x48,0x70,0x48,0x44,0x42,0x00},\r\n\/* 0x8C *\/ {0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00},\r\n\/* 0x8D *\/ {0x42,0x66,0x5A,0x5A,0x42,0x42,0x42,0x00},\r\n\/* 0x8E *\/ {0x42,0x62,0x52,0x4A,0x46,0x42,0x42,0x00},\r\n\/* 0x8F *\/ {0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00},\r\n\/* 0x90 *\/ {0x7C,0x42,0x42,0x7C,0x40,0x40,0x40,0x00},\r\n\/* 0x91 *\/ {0x18,0x24,0x42,0x42,0x4A,0x24,0x1A,0x00},\r\n\/* 0x92 *\/ {0x7C,0x42,0x42,0x7C,0x48,0x44,0x42,0x00},\r\n\/* 0x93 *\/ {0x3C,0x42,0x40,0x3C,0x02,0x42,0x3C,0x00},\r\n\/* 0x94 *\/ {0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x00},\r\n\/* 0x95 *\/ {0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00},\r\n\/* 0x96 *\/ {0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00},\r\n\/* 0x97 *\/ {0x42,0x42,0x42,0x5A,0x5A,0x66,0x42,0x00},\r\n\/* 0x98 *\/ {0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00},\r\n\/* 0x99 *\/ {0x22,0x22,0x22,0x1C,0x08,0x08,0x08,0x00},\r\n\/* 0x9A *\/ {0x7E,0x02,0x04,0x18,0x20,0x40,0x7E,0x00},\r\n\/* 0x9B *\/ {0x3C,0x20,0x20,0x20,0x20,0x20,0x3C,0x00},\r\n\/* 0x9C *\/ {0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00},\r\n\/* 0x9D *\/ {0x3C,0x04,0x04,0x04,0x04,0x04,0x3C,0x00},\r\n\/* 0x9E *\/ {0x00,0x08,0x1C,0x2A,0x08,0x08,0x08,0x08},\r\n\/* 0x9F *\/ {0x00,0x00,0x10,0x20,0x7F,0x20,0x10,0x00},\r\n\/* 0xA0 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xA1 *\/ {0x08,0x08,0x08,0x08,0x00,0x00,0x08,0x00},\r\n\/* 0xA2 *\/ {0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xA3 *\/ {0x24,0x24,0x7E,0x24,0x7E,0x24,0x24,0x00},\r\n\/* 0xA4 *\/ {0x08,0x1E,0x28,0x1C,0x0A,0x3C,0x08,0x00},\r\n\/* 0xA5 *\/ {0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00},\r\n\/* 0xA6 *\/ {0x30,0x48,0x48,0x30,0x4A,0x44,0x3A,0x00},\r\n\/* 0xA7 *\/ {0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xA8 *\/ {0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00},\r\n\/* 0xA9 *\/ {0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00},\r\n\/* 0xAA *\/ {0x08,0x2A,0x1C,0x3E,0x1C,0x2A,0x08,0x00},\r\n\/* 0xAB *\/ {0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00},\r\n\/* 0xAC *\/ {0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10},\r\n\/* 0xAD *\/ {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00},\r\n\/* 0xAE *\/ {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00},\r\n\/* 0xAF *\/ {0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00},\r\n\/* 0xB0 *\/ {0x3C,0x42,0x46,0x5A,0x62,0x42,0x3C,0x00},\r\n\/* 0xB1 *\/ {0x08,0x18,0x28,0x08,0x08,0x08,0x3E,0x00},\r\n\/* 0xB2 *\/ {0x3C,0x42,0x02,0x0C,0x30,0x40,0x7E,0x00},\r\n\/* 0xB3 *\/ {0x3C,0x42,0x02,0x1C,0x02,0x42,0x3C,0x00},\r\n\/* 0xB4 *\/ {0x04,0x0C,0x14,0x24,0x7E,0x04,0x04,0x00},\r\n\/* 0xB5 *\/ {0x7E,0x40,0x78,0x04,0x02,0x44,0x38,0x00},\r\n\/* 0xB6 *\/ {0x1C,0x20,0x40,0x7C,0x42,0x42,0x3C,0x00},\r\n\/* 0xB7 *\/ {0x7E,0x42,0x04,0x08,0x10,0x10,0x10,0x00},\r\n\/* 0xB8 *\/ {0x3C,0x42,0x42,0x3C,0x42,0x42,0x3C,0x00},\r\n\/* 0xB9 *\/ {0x3C,0x42,0x42,0x3E,0x02,0x04,0x38,0x00},\r\n\/* 0xBA *\/ {0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00},\r\n\/* 0xBB *\/ {0x00,0x00,0x08,0x00,0x00,0x08,0x08,0x10},\r\n\/* 0xBC *\/ {0x0E,0x18,0x30,0x60,0x30,0x18,0x0E,0x00},\r\n\/* 0xBD *\/ {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00},\r\n\/* 0xBE *\/ {0x70,0x18,0x0C,0x06,0x0C,0x18,0x70,0x00},\r\n\/* 0xBF *\/ {0x3C,0x42,0x02,0x0C,0x10,0x00,0x10,0x00},\r\n\/* 0xC0 *\/ {0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},\r\n\/* 0xC1 *\/ {0x00,0x00,0x38,0x04,0x3C,0x44,0x3A,0x00},\r\n\/* 0xC2 *\/ {0x40,0x40,0x5C,0x62,0x42,0x62,0x5C,0x00},\r\n\/* 0xC3 *\/ {0x00,0x00,0x3C,0x42,0x40,0x42,0x3C,0x00},\r\n\/* 0xC4 *\/ {0x02,0x02,0x3A,0x46,0x42,0x46,0x3A,0x00},\r\n\/* 0xC5 *\/ {0x00,0x00,0x3C,0x42,0x7E,0x40,0x3C,0x00},\r\n\/* 0xC6 *\/ {0x0C,0x12,0x10,0x7C,0x10,0x10,0x10,0x00},\r\n\/* 0xC7 *\/ {0x00,0x00,0x3A,0x46,0x46,0x3A,0x02,0x3C},\r\n\/* 0xC8 *\/ {0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x00},\r\n\/* 0xC9 *\/ {0x08,0x00,0x18,0x08,0x08,0x08,0x1C,0x00},\r\n\/* 0xCA *\/ {0x04,0x00,0x0C,0x04,0x04,0x04,0x44,0x38},\r\n\/* 0xCB *\/ {0x40,0x40,0x44,0x48,0x50,0x68,0x44,0x00},\r\n\/* 0xCC *\/ {0x18,0x08,0x08,0x08,0x08,0x08,0x1C,0x00},\r\n\/* 0xCD *\/ {0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x00},\r\n\/* 0xCE *\/ {0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x00},\r\n\/* 0xCF *\/ {0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x00},\r\n\/* 0xD0 *\/ {0x00,0x00,0x5C,0x62,0x62,0x5C,0x40,0x40},\r\n\/* 0xD1 *\/ {0x00,0x00,0x3A,0x46,0x46,0x3A,0x02,0x02},\r\n\/* 0xD2 *\/ {0x00,0x00,0x5C,0x62,0x40,0x40,0x40,0x00},\r\n\/* 0xD3 *\/ {0x00,0x00,0x3E,0x40,0x3C,0x02,0x7C,0x00},\r\n\/* 0xD4 *\/ {0x10,0x10,0x7C,0x10,0x10,0x12,0x0C,0x00},\r\n\/* 0xD5 *\/ {0x00,0x00,0x42,0x42,0x42,0x46,0x3A,0x00},\r\n\/* 0xD6 *\/ {0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00},\r\n\/* 0xD7 *\/ {0x00,0x00,0x41,0x49,0x49,0x49,0x36,0x00},\r\n\/* 0xD8 *\/ {0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00},\r\n\/* 0xD9 *\/ {0x00,0x00,0x42,0x42,0x46,0x3A,0x02,0x3C},\r\n\/* 0xDA *\/ {0x00,0x00,0x7E,0x04,0x18,0x20,0x7E,0x00},\r\n\/* 0xDB *\/ {0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08},\r\n\/* 0xDC *\/ {0xA0,0x50,0xA0,0x50,0xA0,0x50,0xA0,0x50},\r\n\/* 0xDD *\/ {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08},\r\n\/* 0xDE *\/ {0xCC,0xCC,0x33,0x33,0xCC,0xCC,0x33,0x33},\r\n\/* 0xDF *\/ {0xCC,0x66,0x33,0x99,0xCC,0x66,0x33,0x99},\r\n\/* 0xE0 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xE1 *\/ {0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},\r\n\/* 0xE2 *\/ {0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF},\r\n\/* 0xE3 *\/ {0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xE4 *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF},\r\n\/* 0xE5 *\/ {0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},\r\n\/* 0xE6 *\/ {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55},\r\n\/* 0xE7 *\/ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},\r\n\/* 0xE8 *\/ {0x00,0x00,0x00,0x00,0xAA,0x55,0xAA,0x55},\r\n\/* 0xE9 *\/ {0x99,0x33,0x66,0xCC,0x99,0x33,0x66,0xCC},\r\n\/* 0xEA *\/ {0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03},\r\n\/* 0xEB *\/ {0x08,0x08,0x08,0x08,0x0F,0x08,0x08,0x08},\r\n\/* 0xEC *\/ {0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F},\r\n\/* 0xED *\/ {0x08,0x08,0x08,0x08,0x0F,0x00,0x00,0x00},\r\n\/* 0xEE *\/ {0x00,0x00,0x00,0x00,0xF8,0x08,0x08,0x08},\r\n\/* 0xEF *\/ {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF},\r\n\/* 0xF0 *\/ {0x00,0x00,0x00,0x00,0x0F,0x08,0x08,0x08},\r\n\/* 0xF1 *\/ {0x08,0x08,0x08,0x08,0xFF,0x00,0x00,0x00},\r\n\/* 0xF2 *\/ {0x00,0x00,0x00,0x00,0xFF,0x08,0x08,0x08},\r\n\/* 0xF3 *\/ {0x08,0x08,0x08,0x08,0xF8,0x08,0x08,0x08},\r\n\/* 0xF4 *\/ {0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0},\r\n\/* 0xF5 *\/ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},\r\n\/* 0xF6 *\/ {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07},\r\n\/* 0xF7 *\/ {0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xF8 *\/ {0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00},\r\n\/* 0xF9 *\/ {0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF},\r\n\/* 0xFA *\/ {0x01,0x02,0x44,0x48,0x50,0x60,0x40,0x00},\r\n\/* 0xFB *\/ {0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0},\r\n\/* 0xFC *\/ {0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00},\r\n\/* 0xFD *\/ {0x08,0x08,0x08,0x08,0xF8,0x00,0x00,0x00},\r\n\/* 0xFE *\/ {0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00},\r\n\/* 0xFF *\/ {0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F},\r\n\r\n};\r\n\r\nuint8_t asciiToCharROM(char c) {\r\nswitch (c) {\r\n\/\/ case '@': return 0;\r\ncase 'A': return 1;\r\ncase 'B': return 2;\r\ncase 'C': return 3;\r\ncase 'D': return 4;\r\ncase 'E': return 5;\r\ncase 'F': return 6;\r\ncase 'G': return 7;\r\ncase 'H': return 8;\r\ncase 'I': return 9;\r\ncase 'J': return 10;\r\ncase 'K': return 11;\r\ncase 'L': return 12;\r\ncase 'M': return 13;\r\ncase 'N': return 14;\r\ncase 'O': return 15;\r\ncase 'P': return 16;\r\ncase 'Q': return 17;\r\ncase 'R': return 18;\r\ncase 'S': return 19;\r\ncase 'T': return 20;\r\ncase 'U': return 21;\r\ncase 'V': return 22;\r\ncase 'W': return 23;\r\ncase 'X': return 24;\r\ncase 'Y': return 25;\r\ncase 'Z': return 26;\r\ncase '[': return 27;\r\ncase '\\\\': return 28;\r\ncase ']': return 29;\r\ncase '^': return 30;\r\ncase ' ': return 32;\r\ncase '!': return 33;\r\ncase '\u201c': return 34;\r\ncase '#': return 35;\r\n\/\/ case '$': return 36;\r\ncase '%': return 37;\r\ncase '&amp;': return 38;\r\ncase '\\'': return 39;\r\ncase '(': return 40;\r\ncase ')': return 41;\r\ncase '*': return 42;\r\ncase '+': return 43;\r\ncase ',': return 44;\r\ncase '-': return 45;\r\ncase '.': return 46;\r\ncase '\/': return 47;\r\ncase '0': return 48;\r\ncase '1': return 49;\r\ncase '2': return 50;\r\ncase '3': return 51;\r\ncase '4': return 52;\r\ncase '5': return 53;\r\ncase '6': return 54;\r\ncase '7': return 55;\r\ncase '8': return 56;\r\ncase '9': return 57;\r\ncase ':': return 58;\r\n\/\/ case ';': return 59;\r\ncase '&lt;': return 60;\r\ncase '=': return 61;\r\ncase '&gt;': return 62;\r\ncase '?': return 63;\r\ncase '|': return 66;\r\ncase ';': return 86; \/\/ Cross glyph\r\ncase '$': return 87; \/\/ Circle glyph\r\ncase '@': return 90; \/\/ Diamond glyph\r\ncase 'a': return 193;\r\ncase 'b': return 194;\r\ncase 'c': return 195;\r\ncase 'd': return 196;\r\ncase 'e': return 197;\r\ncase 'f': return 198;\r\ncase 'g': return 199;\r\ncase 'h': return 200;\r\ncase 'i': return 201;\r\ncase 'j': return 202;\r\ncase 'k': return 203;\r\ncase 'l': return 204;\r\ncase 'm': return 205;\r\ncase 'n': return 206;\r\ncase 'o': return 207;\r\ncase 'p': return 208;\r\ncase 'q': return 209;\r\ncase 'r': return 210;\r\ncase 's': return 211;\r\ncase 't': return 212;\r\ncase 'u': return 213;\r\ncase 'v': return 214;\r\ncase 'w': return 215;\r\ncase 'x': return 216;\r\ncase 'y': return 217;\r\ncase 'z': return 218;\r\ndefault: return 32; \/\/ fallback or space\r\n}\r\n}\r\n\r\n\/\/ Custom Glyphs - see, https:\/\/dotmatrixtool.com\/#\r\nconst uint_8 FriendGlyph[] =\r\n{\r\n0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00\r\n};\r\n\r\nconst uint_8 FoeGlyph[8] = {\r\n{\r\n0x08, 0x14, 0x22, 0x41, 0x22, 0x14, 0x08, 0x00\r\n};\r\n\r\nuint8_t screenmem[1000];\r\nuint8_t colormem[1000];\r\nuint8_t RAM[16384];\r\nuint8_t BOARDER;\r\nuint8_t BGCOLOR;\r\nuint8_t VIC_D020;\r\nuint8_t VIC_D021;\r\n\r\nextern \"C\" {\r\nvoid videoinit();\r\n}\r\n\r\n\r\n\r\n\r\nvoid Background() {\r\nRunOnce = 1; \/\/ Mark that it's been run\r\n\r\n\/\/ The formatting of the array is lost in this WordPress post, it is missing spaces.\r\n\/\/ You will need to ensure that there are 40 character slots for each line.\r\n\/\/ I suppose this is why Github is recommended.\r\nconst char* messages[] = {\r\n\" Lat 47.6795 Lon -122.3821 \",\r\n\" \",\r\n\" Alt XXX Spd YY \",\r\n\" \",\r\n\" - - \",\r\n\" 20 - - 20 \",\r\n\" - - \",\r\n\" 10 - - 10 \",\r\n\" - - \",\r\n\" 0 -- -- 0 \",\r\n\" - - \",\r\n\" - - \",\r\n\" - - \",\r\n\" - - \",\r\n\" - - \",\r\n\" N E S \",\r\n\" | | | | ^ | | | | \",\r\n\" $ @ \",\r\n\" \",\r\n\" @ Hom 00.00 - HH:MM:SS.S \",\r\n\" $ Way 10.51 N \",\r\n\" \",\r\n\" ESP8266-Wemos_NTSC-ChatGPT-Demo3 \",\r\n\" \",\r\n\" CloudACM July 28th 2025 \",\r\n};\r\n\r\nconst int numMessages = sizeof(messages) \/ sizeof(messages[0]);\r\nconst int screenWidth = 40;\r\n\r\n\/\/ Clear screen once\r\nmemset(screenmem, 32, 40 * 25);\r\n\r\nfor (int m = 0; m &lt; numMessages; m++) {\r\nconst char* text = messages[m];\r\nint len = strlen(text);\r\nint base = m * screenWidth;\r\n\r\nfor (int i = 0; i &lt; len &amp;&amp; i &lt; screenWidth; i++) {\r\nscreenmem[base + i] = asciiToCharROM(text[i]);\r\n}\r\n}\r\n}\r\n\r\n\r\n\r\n\r\n\r\nvoid updateAltSpd(int altValue, int spdValue) {\r\nint base = 2 * 40; \/\/ base = x * 40, where x is the line number (top line is 0) for a 40 char line width\r\n\r\n\/\/ Format values into 3-character strings\r\nchar altStr[4];\r\nchar spdStr[3];\r\n\r\nsnprintf(altStr, sizeof(altStr), \"%3d\", altValue); \/\/ Right-aligned\r\nsnprintf(spdStr, sizeof(spdStr), \"%2d\", spdValue);\r\n\r\n\/\/ Write to screenmem at fixed positions\r\nscreenmem[base + 6] = asciiToCharROM(altStr[0]);\r\nscreenmem[base + 7] = asciiToCharROM(altStr[1]);\r\nscreenmem[base + 8] = asciiToCharROM(altStr[2]);\r\n\r\nscreenmem[base + 33] = asciiToCharROM(spdStr[0]);\r\nscreenmem[base + 34] = asciiToCharROM(spdStr[1]);\r\n\r\n}\r\n\r\n\r\n\r\n\r\nvoid updateTime() {\r\nint base = 19 * 40; \/\/ Row 19 (zero-based), so actual 20th line\r\n\r\n\/\/ Get uptime in milliseconds\r\nunsigned long ms = millis();\r\n\r\nunsigned long total_seconds = ms \/ 1000;\r\nunsigned long hours = (total_seconds \/ 3600) % 100; \/\/ Keep within 2-digit range\r\nunsigned long minutes = (total_seconds \/ 60) % 60;\r\nunsigned long seconds = total_seconds % 60;\r\nunsigned long tenths = (ms % 1000) \/ 100; \/\/ 0\u20139 (1 digit)\r\n\r\n\/\/ Format time as HH:MM:SS.S\r\nchar timeStr[11]; \/\/ \"HH:MM:SS.S\"\r\nsnprintf(timeStr, sizeof(timeStr), \"%02lu:%02lu:%02lu.%1lu\",\r\nhours, minutes, seconds, tenths);\r\n\r\n\/\/ Write to screenmem at fixed position: starts at column 27\r\nfor (int i = 0; i &lt; 10; i++) {\r\nscreenmem[base + 28 + i] = asciiToCharROM(timeStr[i]);\r\n}\r\n}\r\n\r\n\r\n\r\n\r\nvoid setup() {\r\n\r\ndelay(1); \r\nsystem_update_cpu_freq(FREQUENCY);\r\nvideoinit();\r\nreset6502(); \r\nmemset(screenmem, 32, 40 * 25);\r\n\r\n}\r\n\r\n\r\n\r\n\r\nvoid loop() {\r\nstatic int counterX = 0;\r\nstatic int counterY = 0;\r\n\r\nif (RunOnce == 0) {\r\nBackground(); \/\/ Run only once at startup\r\n} else {\r\nupdateAltSpd(counterX, counterY); \r\nupdateTime();\r\ncounterX++;\r\ncounterY += 2;\r\nif (counterX &gt;= 1000) {\r\ncounterX = 0;\r\n}\r\nif (counterY &gt;= 100) {\r\ncounterY = 0;\r\n}\r\ndelay(50); \/\/ Control update rate\r\n}\r\n}\r\n\r\n<\/pre>\n<p>As always, be cautious of your surroundings when your head is in the C.H.U.D.<\/p>\n<p><iframe loading=\"lazy\" title=\"Mos Eisley spaceport.\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/GoRPVsN2SVM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is a branch from the earlier ESP32 based heads up display. Instead of using the frame buffer as a canvas to write text and variables or draw graphics, this post will use NTSC encoding. See this Wikipedia link for more details about NTSC, https:\/\/en.wikipedia.org\/wiki\/NTSC. The code used in this post is a deviation from Matthias Goebl&#8217;s Github repo, https:\/\/github.com\/matgoebl\/esp8266-ntsc-c64-emulator with credit given to Jan Ostman, https:\/\/www.hackster.io\/janost. I&#8217;m grateful to both of them for providing the foundation for what&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.cloudacm.com\/?p=4922\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4922","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4922","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4922"}],"version-history":[{"count":22,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4922\/revisions"}],"predecessor-version":[{"id":4942,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4922\/revisions\/4942"}],"wp:attachment":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4922"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4922"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4922"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}