Teensy 4.0 CW Keyer: Ultra-Low Latency Iambic A/B + Straight Key

chaseology

New member
Teensy 4.0 CW Keyer: Ultra-Low Latency Iambic A/B + Straight Key over USB Serial to C++ CW KEYER JACK App on Ubuntu 24.04.
See this 49-second YouTube demo showing iambic paddles and straight key connected directly to Teensy GPIOs, sending precise key-down/up events over USB serial to a companion C++ JACK audio connection kit CW keyer app (also shown with remote rig keying demo):

Project Overview​

This is a complete CW keyer system using Teensy 4.0 as a raw serial sensor board for iambic paddles (modes A/B) and straight key simultaneously—no switches to choose iAMBICs or ST KEY are needed. Teensy debounces inputs with Bounce2, sends events like "DIT:D", "DAH:U", "S1:D", plus "KA" keepalives at 115200 baud. The host Qt/JACK C++ app processes events in real-time (48kHz, envelope LUTs for rise/fall), generates clean smooth Raised Cosine edged sinewave tones (WPM 5-100, pitch 300-1200Hz), and also is able to couple perfectly into a UDP Sockets over IP C++ Sender APP for remote rig CW keying on the PI/RIG udp sockets receiver, keying GPIO PIN 17 to key the rig's cw jack using a FET OPTO. Optimized even for QRQ with atomic RT params, event queue (4096 deep), and -O3 native tuning.
Latest improved code (12/20/25, by multiple AI-assisted refinements): https://u.pcloud.link/publink/show?code=XZDczx5ZLwHbdfYh85FA6rXk9ltNAuKb3QlV
(Contains: teensy_keyer.ino, main.cpp, cw_keyer.pro for qmake/make)

Hardware Setup​

  • Teensy 4.0 pins (all INPUT_PULLUP, counting from top-left USB side):
    • Straight key (S1): GPIO 2 (4th pin down from USB-top, left side)
    • DIT paddle: GPIO 4 (6th pin down from USB-top, left side)
    • DAH paddle: GPIO 5 (7th pin down from USB-top, left side)
    • Heartbeat LED: GPIO 13 (onboard, flickers on keepalives)
  • Wire paddles/straight key to pins + GND. Plug Teensy USB into Linux host with JACK server running (48kHz recommended). No extra hardware needed.

Key Software Features​

  • Teensy side (Arduino sketch): High-precision elapsedMillis timing, immediate Serial.send_now() flushes, adaptive 1s keepalives.

    cpp
    if (b_dit.fell()) { send_event("DIT:D"); } // Precise paddle capture
    if (idle_timer >= 1000) { Serial.println("KA"); Serial.send_now(); }
  • Host app (Qt/C++ JACK): RT-safe event queue, iambic state machine (IDLE/RISING/STEADY/FALLING/SPACE), GUI sliders for WPM/pitch/volume/rise(1-25ms)/fall/comp/iambic mode. Serial thread auto-detects Teensy (/dev/ttyACM*).
    • JACK process() callback: sine gen with LUT envelopes, denorm protection.
    • Build: qmake cw_keyer.pro && make (needs Qt Widgets, JACK, pthread, rt).

Usage & Builds​

  1. Flash teensy_keyer.ino to Teensy 4.0 (115200 baud).
  2. Build/run C++ app on Linux: using qmake.pro file (included in the link)
  3. Connect paddles/key to Teensy GPIO pins —start keying immediately with ultra-low latency. GUI updates RT params atomically.
  4. Remote rigs: a different C++ App sends UDP keying (see prior videos for Pi interface
    ).
 
Back
Top