MorseTrainer is a standalone Morse code practice device built on the Waveshare ESP32-S3-Touch-LCD-2.8. Connect your CW paddle or straight key and start practicing - no computer, no phone, no internet required.
Source code and releases: github.com/Hex4rts/Morsetrainer
Iambic A, Iambic B, and adaptive Straight Key that learns your personal timing
Falling Letters, Callsign Rush, Morse Trace with LEARN mode, QSO Simulator, and CW Essentials
5-tab interface on a 320x240 IPS display with dark theme
Drop a firmware file on the SD card, reboot, done
| Component | Detail |
|---|---|
| Board | Waveshare ESP32-S3-Touch-LCD-2.8 (16MB flash, OPI PSRAM) |
| Dit paddle | GPIO 15 - active LOW, internal pullup |
| Dah paddle | GPIO 18 - active LOW, internal pullup |
| NeoPixels | 20x WS2812 on GPIO 43 |
| Audio | I2S DAC (BCLK=48, LRC=38, DOUT=47) |
| SD card | 4-bit SDMMC - stores scores, progress, and settings backup |
The screen is divided into five tabs along the bottom: HOME, KEY, OPS, CFG, and NET. Tap any tab to switch screens.
This is your main operating screen. As you key, colored bars appear at the top showing each dit and dah in real time. In Iambic mode, dits are blue and dahs are amber. In Straight Key mode, all bars are green with their width matching exactly how long you held the key.
Below the bars, a large text area displays the decoded characters as you send them. A CLR button lets you clear the text.
At the bottom of the screen, three cards show your current WPM speed, keyer mode, and callsign at a glance.
This is where you choose your keyer mode and adjust your sending speed. The current WPM is shown in large text along with the dit duration in milliseconds. Use the + and - buttons to adjust speed from 5 to 60 WPM.
Three mode buttons let you switch between Iambic A, Iambic B, and Straight Key. The active mode is highlighted. A paddle swap button at the bottom lets you reverse which paddle is dit and which is dah.
The games menu. Five game cards show the name, a short description, and your best score. Tap a card to start playing.
A RESET SCORES button at the bottom clears all high scores and LEARN mode progress. It requires a confirmation tap to prevent accidents.
All device settings in a scrollable list. Each row has a label and a control - sliders, switches, dropdowns, or buttons.
| Setting | What it does |
|---|---|
| CALL | Your callsign. Tap to edit with on-screen keyboard. |
| VOLUME | Sidetone volume |
| TONE | Sidetone frequency (200-1200 Hz) |
| LIGHT | Screen backlight brightness |
| FLIP | Rotate the display 180 degrees for upside-down mounting |
| LED | Choose the LED effect mode (8 options) |
| LEDs | Number of NeoPixels in your strip (1-60). Use + and - to match your hardware. |
| KEY BRT | Brightness for key-press LED flashes |
| BG BRT | Brightness for background LED animations |
| COLOR | Pick the color used by LED modes (7 presets) |
| BACKUP | Save all settings to the SD card |
| RESTORE | Load settings from SD card backup |
| RESET | Factory reset - all settings back to defaults |
If flipping makes touch unusable, hold both paddles while powering on to force normal orientation.
WiFi settings for future features. Enter your network SSID and password. Credentials are stored on the SD card.
All games have an EXIT button to return to the menu at any time. Scores are saved to the SD card.
Letters fall from the top of the screen. Key the correct Morse code to destroy each letter before it hits the danger zone at the bottom. The speed increases with each level. The game uses the full A-Z alphabet. If two identical letters are on screen, keying always destroys the one closest to the bottom first.
Beginner: the letter and its Morse code hint are both shown. Expert: only the letter - you need to know the code.
A random callsign appears on screen. Send it back in Morse as fast as you can. Callsigns use realistic prefixes from around the world.
Beginner: callsign shown with visual and audio, no time limit - practice at your own pace. Intermediate: callsign shown with audio, 12-second timer. Expert: audio only, 12-second timer.
The device presents a letter (visually, audibly, or both depending on difficulty). You key it back. The device compares your timing to the correct pattern. Four difficulty levels: LEARN, Beginner, Intermediate, and Expert.
Practice realistic CW contacts. The device plays an incoming transmission and you respond with the appropriate reply. Three difficulty levels combined with three complexity levels (simple exchange, RST report, and full QSO) give you 9 combinations to master.
Three practice modes in one game:
MY CALLSIGN: Builds your callsign progressively, letter by letter. First you practice just the first letter. Get it right 3 times in a row and the second letter is added. Then 3 more correct to add the third, and so on until you can send your full callsign from muscle memory. Your full callsign is shown faintly as a reference so you always know where you're headed.
PHRASES - GUIDED: A random CW phrase appears with its meaning (for example "QSL" with "Acknowledged / Confirmed" underneath). The device plays it in Morse first so you can hear it, then you key it back. Great for learning what each abbreviation sounds like and what it means at the same time.
PHRASES - PRACTICE: Same phrases and meanings shown on screen, but no audio. You key them from memory.
The phrase pool covers Q-codes (QSL, QRT, QRS, QRZ, QTH, QRM, QRN, QSB), prosigns (AR, SK, BT, K), common exchanges (CQ, DE, 73, 88, TU, R, RST), and greetings (GM, GA, GE). Every phrase is shown with its meaning so you learn what you're sending, not just the pattern.
The LEARN option inside Morse Trace is designed to teach Morse code from scratch. It introduces one letter at a time and uses a drill-and-recall cycle to build your memory.
Learning order: E T I A N M S U R W D K G O H V F L P J B X C Z Y Q 0-9
First, you drill each new letter with full guidance - the letter is shown, the sound is played, and visual bars show the pattern. You copy what you see and hear. After you've learned your first 3 letters, the system starts testing you with recall rounds: the letter appears but there's no sound and no bars. You have to key it from memory.
You get 3 tries per recall. If you fail all 3, the letter goes back to the drill queue. After 3 correct recalls in a row, the next new letter is introduced. The system alternates between drilling new letters and testing learned ones, making sure you don't forget what you've already practiced.
Your progress saves automatically to the SD card. You can turn off the device and pick up exactly where you left off.
Hold both paddles and the keyer produces alternating dits and dahs. Release both paddles and it stops after the current element finishes. Dit and dah lengths are determined by your WPM setting.
Same as Iambic A, but if you release a paddle during an element, the opposite element still plays. This is the "squeeze and release" technique preferred by many experienced CW operators.
Either paddle works as a simple on/off key. The device listens to your timing and figures out your speed automatically - you don't need to set a WPM for input. It learns the difference between your dits and dahs, detects character boundaries, and inserts spaces, all based on how you actually key.
The WPM setting only controls playback speed in games when the device sends Morse to you.
The device has a strip of 20 NeoPixel LEDs with 8 selectable modes. Two separate brightness sliders let you control how bright the key-press flashes are versus how bright the background animation is.
| Mode | What it does |
|---|---|
| OFF | Completely dark. No response to key presses or game events. |
| KEY FLASH | Dark when idle. Flashes briefly each time you press a key. |
| WPM METER | Shows your current speed as a bar graph across the strip. |
| STEADY | Solid glow in your chosen color. |
| BREATHE | Your chosen color gently pulses up and down. |
| STARFIELD | Random pixels twinkle and fade independently, like stars. |
| CHASE | A bright tail of light runs continuously around the strip. |
| RAINBOW | A continuous rainbow cycles across all the LEDs. |
Every mode except OFF also flashes when you press a key. The flash briefly overrides the background animation, then the background resumes. You can pick your color from 7 presets in the CFG tab - it affects Steady, Breathe, Starfield, and Chase.
Four ways to get firmware onto your MorseTrainer, from easiest to most technical. All files live at github.com/Hex4rts/Morsetrainer.
Flash a brand-new ESP32-S3 directly from your browser. No Python, no Arduino IDE, no command line.
Works: Chrome, Edge, Opera (desktop). Won't work: Firefox, Safari, any mobile browser. The Web Serial API is only supported in Chromium-based desktop browsers.
Many USB-C cables are charge-only. Use one you know transmits data, or the board simply won't enumerate.
Auto-installed on most systems. On Windows, if no COM port shows up, install CP210x or CH340 depending on your board's USB-to-serial chip.
Click FLASH MORSETRAINER above.
Select your ESP32-S3's serial port in the browser popup.
Wait ~30 seconds. Don't unplug during flashing. The device reboots into MorseTrainer automatically when done.
Hold the BOOT button while plugging in USB, wait a second, then release and click Flash again. Most ESP32-S3 boards auto-enter download mode, but some need this manual step.
Already running MorseTrainer and want the latest version? Download the firmware, drop it on your SD card, reboot - no computer needed.
Click DOWNLOAD firmware.bin above. Keep the filename exactly firmware.bin - don't rename it.
Copy the file to the root of your SD card (not inside any folder).
Insert the SD card, power on the device. Every boot it checks for firmware.bin, flashes it, and renames it to firmware.done so it won't re-flash next time.
Device reboots into the new version. Total time ~20 seconds.
OTA updates only work if the device was initially installed with the custom partition scheme. Option A above uses it automatically. If your first install used "Huge APP", re-flash once via Option A before OTA will work.
For power users who prefer the command line, or for scripted/batch flashing.
Install esptool (requires Python):
With a merged binary (single file, simplest):
Replace COM3 with your actual port (on Linux, usually /dev/ttyACM0).
With separate files:
If the board isn't detected, hold the BOOT button while plugging in USB, then release.
For those who want to build from source or make modifications.
Install Arduino IDE and add ESP32 board support (esp32 by Espressif Systems from Board Manager).
Install libraries: LVGL 9.x and Adafruit NeoPixel via Library Manager.
Copy lv_conf.h from the project into your Arduino libraries folder. It must sit next to the lvgl folder, not inside it:
Extract all project files into a folder called MorseTrainer inside your Arduino sketch folder. The .ino file, all .h/.cpp files, and the partitions.csv file must all be in the same folder.
Configure board settings in the Tools menu:
Connect the board via USB and upload.
The included partitions.csv creates two app partitions, which is required for OTA updates to work. If you select "Huge APP", the firmware will compile and run, but you won't be able to update via SD card later. You'd have to re-flash via USB to fix it.
The device creates these files as needed. Deleting any of them just resets that data.
| File | Purpose |
|---|---|
/firmware.bin | Firmware update - consumed on boot, renamed to .done |
/mt_settings.txt | Settings backup (from the BACKUP button in CFG) |
/mt_wifi.txt | WiFi network name and password |
/trainer2.txt | LEARN mode progress |
/koch.txt | Koch lesson progress |
/scores/*.txt | High scores for each game (falling, callrush, trace, qso, phrases) |