549 Morse Tree LED Decoder

549 : Morse Tree LED Decoder

Design render

How it works

The design listens to a Morse key on ui[0] and walks the Morse code binary tree: every dot goes to the left child, every dash to the right child. The current tree node is shown on an 8x8 LED matrix, one LED at a time. If you glue the LEDs onto a poster of the Morse tree (with the letter written next to each LED), the light wanders down the tree while you key a character and stops on the decoded letter.

Tree nodes are numbered like a binary heap: the root is 1 and each symbol appends one bit (node = node * 2 + symbol, dot = 0, dash = 1). The 6-bit node number selects the LED: node[5:3] is the row (uo_out, one-hot, active high) and node[2:0] is the column (uio_out, one-hot, active low). Node 1 (root) is the "ready" LED, node 0 is an error LED (more than five symbols).

Timing is measured in units of the dot length. The dot length is 2^SPEED base ticks, one base tick being 2^15 clock cycles (3.3 ms at 10 MHz):

SPEED (ui[3:1]) 0 1 2 3 4 5 6 7
dot length @ 10 MHz 3.3 ms 6.5 ms 13 ms 26 ms 52 ms 105 ms 210 ms 420 ms
  • key pressed shorter than 2 units = dot, 2 units or longer = dash
  • key released for 2 units = character complete (the LED stays on the letter)
  • key released for 8 units = back to the root (unless HOLD = 1, then the letter stays until the next key press)

Hand keying works well with SPEED 5 or 6. SPEED 0 and 1 are only meant for machine keying, because the ~3 ms debounce filter would swallow such short dots. Other clock frequencies scale all times accordingly (e.g. 20 MHz halves every value).

The key input is synchronised and debounced (stable for about 3 ms). KEY_INV (ui[7]) inverts the key, so a button to GND with a pull-up resistor can be used directly.

RAW (ui[5]) switches uo_out from the row one-hot code to the plain node number: uo[5:0] = node, uo[6] = character complete, uo[7] = debounced key. This is handy for testing from the demo board or for driving an external decoder instead of the matrix.

LED positions

Node Char Code Row (uo) Col (uio)
0 (error) more than 5 symbols 0 0
1 (root) idle / keying 0 1
2 E . 0 2
3 T - 0 3
4 I .. 0 4
5 A .- 0 5
6 N -. 0 6
7 M -- 0 7
8 S ... 1 0
9 U ..- 1 1
10 R .-. 1 2
11 W .-- 1 3
12 D -.. 1 4
13 K -.- 1 5
14 G --. 1 6
15 O --- 1 7
16 H .... 2 0
17 V ...- 2 1
18 F ..-. 2 2
19 Ü ..-- 2 3
20 L .-.. 2 4
21 Ä .-.- 2 5
22 P .--. 2 6
23 J .--- 2 7
24 B -... 3 0
25 X -..- 3 1
26 C -.-. 3 2
27 Y -.-- 3 3
28 Z --.. 3 4
29 Q --.- 3 5
30 Ö ---. 3 6
31 CH ---- 3 7
32 5 ..... 4 0
33 4 ....- 4 1
35 3 ...-- 4 3
39 2 ..--- 4 7
47 1 .---- 5 7
48 6 -.... 6 0
56 7 --... 7 0
60 8 ---.. 7 4
62 9 ----. 7 6
63 0 ----- 7 7

All other nodes 32..63 are the remaining five-symbol codes (punctuation, prosigns, accented letters); their node number is simply 1 followed by the five symbol bits.

How to test

  1. Apply a 10 MHz clock and release reset. With ui_in = 0 the root LED (row 0, column 1) is lit: uo_out = 0x01, uio_out = 0xFD.
  2. Set the speed, e.g. ui[3:1] = 5 (dot = 105 ms), and connect a push button to ui[0] (or set ui[7] = 1 for an active-low button).
  3. Key .- (short, long): after the dot the E LED lights (row 0, column 2), after the dash the A LED (row 0, column 5). Pause for two units and the A stays lit; after eight units the root LED comes back.
  4. For an automated check set ui[5] = 1 (RAW mode) and read the node number on uo[5:0]; uo[6] tells you that a character is complete.

The cocotb test in test/test.py keys several characters (S, O, A, H, 5, 1, ...), checks the node after every symbol, the character-complete flag, the word gap, the HOLD mode, the error node, the matrix outputs and the inverted key input.

External hardware

  • A push button or Morse key on ui[0].
  • Up to 64 LEDs wired as an 8x8 matrix: LED anodes to the row lines uo[0..7], cathodes to the column lines uio[0..7], one series resistor (about 470 Ω) per column line. Because only one LED is on at any time, no multiplexing or driver ICs are needed; the chip pins can only supply a few mA, so use efficient (low-current) LEDs or add transistor drivers for brighter ones.
  • Instead of a matrix you can use RAW mode and feed the node number into external decoders.

IO

#InputOutputBidirectional
0KEY (Morse key, 1 = pressed)ROW0 / NODE0COL0 (active low)
1SPEED[0]ROW1 / NODE1COL1 (active low)
2SPEED[1]ROW2 / NODE2COL2 (active low)
3SPEED[2]ROW3 / NODE3COL3 (active low)
4HOLD (keep last character until next key press)ROW4 / NODE4COL4 (active low)
5RAW (uo_out = {KEY, DONE, NODE[5:0]})ROW5 / NODE5COL5 (active low)
6ROW6 / DONECOL6 (active low)
7KEY_INV (1 = key is active low)ROW7 / KEYCOL7 (active low)

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_ieee_LDO (LDO) tt_um_chip_ieee_analog (IEEE Bandgap Reference) tt_um_snn_voice_calculator_mauro_ciccone (snn-voice-calculator) tt_um_hx2003_delay (4 Channel - 32 Tap Programmable Delay with Delay Locked Loop Calibration) tt_um_adxl362_test (tt_um_adxl362_test) tt_um_larsnit_cfar (1D CA/GO/SO CFAR radar detector) tt_um_abeccari_swsynth (Sine Wave Synthesizer) tt_um_dpi_adexp (AdExp DPI Neuron ) tt_um_140oo041_fpu130 (FPU-130) tt_um_blonghi_uart (uart) tt_um_directsgg_mini_proceo_8bit (Mini 8-bit Processor) tt_um_umaece1982_lfsr (Low-Power LFSR-Based Test Pattern Generator) tt_um_deploy_timer (launch deployment timer) tt_um_urish_simon (Simon Says memory game) tt_um_nimelli_kinematic_wave_engine (Kinematic Wave Engine) tt_um_multi_seg_monitor (Multi Segment Monitor) tt_um_UART_TX (project) tt_um_crc8_lfsr (CRC-8 Serial LFSR) tt_um_tinynpu4 (TinyNPU4) tt_um_alu_bns (6-bit multi function ALU ( eldawly_V2) ) tt_um_echoworld424_tpv (Timing-Prediction Test Vehicle) tt_um_gyro_lockin (Laser Gyro Lock-in Readout Core) tt_um_josue_olivos_sar_adc (4-Bit Charge-Redistribution SAR ADC Controller) tt_um_flower (VGA Flower) tt_um_vperumal_l1_fabric (Scalable Banked L1 Memory Fabric for Edge AI) tt_um_preinception_top (Preinception: Simple Compute Accelerator) tt_um_italu (iTALU: Interactive Testable Arithmetic Logic Unit) tt_um_neuron (4-Input Signed Neuron / Perceptron) tt_um_4tap_mac (4-Tap Signed MAC Unit) tt_um_mac_engine (DSP MAC Engine) tt_um_crypto_led_demo (QAMER CryptoUART: Encrypted UART with LED Status) tt_um_layernorm (LayerNorm) tt_um_ez130_8t_mystery (EZ130 8T Mystery Circuit) tt_um_sent2spi (SENT Receiver with SPI Interface) tt_um_llr_hepiarisc (Hepiarisc with SPI flash) tt_um_rebeccargb_vga_pride (VGA Pride) tt_um_hasi_ising (Oscillator Ising Machine) tt_um_c061618g2 (Circuitli C061618G2) tt_um_tiny_dram_pim (Tiny Dual-Channel DRAM-PIM Controller + PU) tt_um_Tbilisi_CORDIC_Engine (Tbilisi CORDIC Engine) tt_um_rahulmascarenhas_folded_nn (Frozen ternary backbone + loadable head) tt_um_miniMAC (miniMAC_IHP26b) tt_um_rumcajs (IEEE DOORSH) tt_um_sg13g2_mystery (SG13G2 Mystery Circuit) tt_um_ULSR88 (ULSR demo) tt_um_ez130_7t_mystery (EZ130 7T Mystery Circuit) tt_um_tinyopt4 (ieee_tt_tinyopt4) tt_um_vga_example (IEEE VGA Animated Beach) tt_um_hyphen133_drone_detection (IEEE Acoustic Drone Detector) tt_um_nuatlabs_fifo_pwm (Async FIFO with CDC + PWM Peripheral) tt_um_nuatlabs_uart (8N1 UART Transceiver) tt_um_eeg_threshold_detector (IEEE Digital EEG Threshold Event Detector) tt_um_smart_traffic (Smart Traffic Light Controller) tt_um_94442024_mini_cpu (Mini 8-bit Accumulator CPU) tt_um_wokwi_475369131246576641 (IEEE_UPB_TT_1) tt_um_aion (AION) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_flappy_bird (IEEE Flappy Bird VGA Game) tt_um_oryan01_alu (ALU CASS PUCV) tt_um_S4xU4 (S4xU4) tt_um_vga_ca (Space CA) tt_um_llr_simplenpu (simple SPI flash streaming NPU) tt_um_pucv_pspwm (3LFCC PS-PWM Modulator) tt_um_yuri_fpga (Tiny FPGA) tt_um_mikailgedik_inverted_inverters (Inverted inverters) tt_um_esauqch_hamming74 (Hamming(7,4) encoder/decoder (IEEE)) tt_um_hackin7_analog_experiments (TinyAnalogExperiments) tt_um_snake (snake game) tt_um_mini_kraken (Kraken IO Subprocessor) tt_um_fabien_pio (AstraPIO) tt_um_chiplab (ChipLab) tt_um_wokwi_475490677474407425 (Tiny_Divider) tt_um_c061618g2tr (Circuitli C061618G2TR) tt_um_catalinlazar_nanopio (nanoPIO) tt_um_catalinlazar_uart_spi_i2c_bridge (UART-SPI-I2C Bridge) tt_um_enzonappi_sent_i2c (SENT to I2C bridge) tt_um_kush1434_proof (Proof) tt_um_schwallsunk_signal_discriminator (Highspeed voltage discriminator) tt_um_tiarinix_ttihp_verilog_template (8-bit educational SAP-style CPU) tt_um_vga_glyph_mode (BOOTCAMP) tt_um_GiulioGirelli_packet_processor (Configurable Low-Latency Match-Action Packet Processor) tt_um_vga_tictactoe (Tic Tac Toe) tt_um_vga_dvd_player (DVD player) tt_um_clea_katseye_rain (KATSEYE) tt_um_romd_uart_hello (UART Hello World) tt_um_vga_snake (CDM PYTHON GAME) tt_um_vga_slot_machine (tt_um_vga_slot_machine) tt_um_jet_seq8b (SEQ8 Programmable Sequencer) tt_um_kibo_leak_inspect (KIBO Leak-Inspection Target Controller (VGA)) tt_um_endless_runner (Endless Runner) tt_um_omega_infinity_kaoru (OMEGA INFINITY KAORU 3D Metal Grid Processor) tt_um_nikleberg_mixer (Mixer) tt_um_lahnb_sgdma (TinyDMA: A Descriptor-Based Dual-PSRAM Memory Mover) tt_um_gstj_lockin (Digital IQ Lock-in (IEEE)) tt_um_benpayne_ps2_decoder (PS/2 Keyboard Decoder for 68k) tt_um_cass_s_ui_neuron_lif (Neurona LIF con Aprendizaje STDP Dinamico (IEEE)) tt_um_vga_glyph_mode_CDM_Matrix (CDM Matrix) tt_um_qd39l_xor_stream (Fixed-ROM XOR Stream Engine) tt_um_conv3x3 (3x3 Clock Rate Streaming Input Convolution Engine) tt_um_mc14500b_soc_extended (MC14500B Extended 1-bit Microcontroller SoC) tt_um_vga_hypno_spiral (tt_um_vga_hypno_spiral) tt_um_mattizen_morse_tree (Morse Tree LED Decoder) tt_um_CDM (Colegio de Muntinlupa DVD-like Display) tt_um_romd_uart_loader (UART SPI RAM Loader) tt_um_TscherterJunior_stapel_geraet (stapel gerät) tt_um_das2225_dna_accel (DNA_Accel) tt_um_tinysoc (TinySoC) tt_um_barrel_shifter (Barrel Shifter) tt_um_approx_mac_coprocessor (Approximate DSP: Time-Multiplexed MAC Coprocessor) tt_um_joesagents_market_split_oracle (Market-split oracle) tt_um_mgpauly1458_ringmeter (Ring oscillator frequency meter) tt_um_pettit_prism_lite (PRISM with Risc-V (TinyQV) SoC) tt_um_workshop_cpu (IEEE Workshop Simple CPU) tt_um_algofoogle_analog_junk (Simple comparator + 2 DACs analog layout in a 1x1 tile) tt_um_lkhanh_cordic (TinyQV SoC (Dual Memory Backend)) tt_um_4x4npu (4x4NPU: Dual-Lane INT4 Neural Accelerator) tt_um_abiaselli_izh_bridge_3x2 (Izhikevich event bridge (4 contexts)) tt_um_fabulous_ihp_26b (Tiny FABulous FPGA) tt_um_zanderivo_voronoi (Four-Metric VGA Nearest-Prototype Visualizer)