519 Sine Wave Synthesizer

519 : Sine Wave Synthesizer

Design render

How it works

tt_um_abeccari_swsynth is a CORDIC sine-wave synthesizer: it plays an equal-tempered musical note as an audio tone. You choose the pitch on the input pins, and the tone comes out three ways — a parallel digital sample bus and two 1-bit pulse-density-modulated (PDM) streams.

GDS layout assembled with IHP PDK.

Signal chain:

  1. Note selectui[3:0] picks a semitone (see the table below) and ui[7:4] an octave above A0 = 27.5 Hz. The output frequency is f = 27.5 · 2^(note/12) · 2^octave Hz, with the octave clamped to ≤ 8 so the tone stays below the Nyquist rate.
  2. NCO — a frequency map turns the note into a phase increment that drives a 20-bit phase accumulator, stepped at the 48 kHz sample rate (clk / 256).
  3. CORDIC — a rotation-mode CORDIC converts the phase into signed sine and cosine samples (~8-bit accurate).
  4. Outputs
    • uo[6:0]7-bit parallel sine, offset-binary (0x40 = zero crossing), refreshed once per 48 kHz sample. uio[0] (SAMPLE_EN) pulses high for one clock at each new sample.
    • uo[7]PDM_I, a 1-bit sigma-delta stream of the sine at the full clock rate; low-pass filtered, it reconstructs the analog sine.
    • uio[7]PDM_Q, the same for the cosine (90° out of phase with PDM_I) — an I/Q pair.
    • uio[6]SQR, a 1-bit square wave at the tone frequency (the sign of the sine); a clean digital output that needs no filter.
    • uio[5]SAW, a 1-bit sigma-delta sawtooth at the tone frequency (the raw phase ramp); low-pass filter to reconstruct.
    • uio[4]NOISE, a 1-bit pseudo-random bitstream from a maximal-length 20-bit LFSR, advanced one step per 48 kHz sample. Unlike the PDM outputs this is a baseband signal, not a density-coded one — its 0–24 kHz band already is audio-band white noise, so no demodulation is needed. Being a zero-order-hold at 48 kHz it carries spectral images above f_s/2; a gentle low-pass at ≈ 20–24 kHz rejects those ultrasonic images (anti-imaging / reconstruction) for clean band-limited noise and to spare the amplifier ultrasonic switching energy. The sequence is deterministic and repeats every 2²⁰−1 samples (≈ 21.8 s).

Semitone codes on ui[3:0] (codes 12–15 have no distinct note and fold back to A):

ui[3:0] 0 1 2 3 4 5 6 7 8 9 10 11 12–15
Note A A# B C C# D D# E F F# G G# A

The clock is 12.288 MHz = 256 × 48 kHz.

<img src="note4_oct8.png" width="360" alt="Parallel 7-bit sine output (top) and its spectrum (bottom), note C#, octave 8 ≈ 8.87 kHz">

How to test

  1. Clock — drive clk at the 12.288 MHz design point; the pitch and 48 kHz sample rate scale with it (f_s = clk / 256), and being fully synchronous it also runs correctly at lower rates. Clocks up to ~60 MHz are within the process corners (worst-case Fmax ≈ 66 MHz at the slow corner, from signoff STA); the demo board's on-board clock tops out at 50 MHz, which the design meets with margin, so drive clk externally to go higher.
  2. Reset — hold rst_n low for a few clock cycles, then release it high.
  3. Pick a note — set ui[7:4] = octave and ui[3:0] = semitone. For example ui_in = 0x40 → octave 4, note 0 (A) → 440 Hz (concert A); ui_in = 0x80 → note A, octave 8 → 7040 Hz.
  4. Monitor
    • Put a logic analyzer on uo[6:0] (the 7-bit sine) and use uio[0] (SAMPLE_EN, 48 kHz) as the sample clock / scope trigger. The value traces a sine centered on 0x40.
    • Scope uo[7] (PDM_I) and uio[7] (PDM_Q): fast 1-bit streams whose pulse density follows the sine and cosine.
  5. Change the note on ui_in at any time; the tone follows on the next samples.

External hardware

On the TinyTapeout demo board the on-board RP2040 selects the design, supplies the clock, drives ui_in, and reads the outputs — so you can set the note from the on-board DIP switches or a MicroPython script and capture the 48 kHz parallel-sine samples in software, with no extra parts. All I/O is also broken out on the Pmod and SIL headers for the analog add-ons below.

  • Hear it: low-pass filter uo[7] (PDM_I) with a simple RC and drive a powered speaker or amplifier. The Audio Pmod does exactly this (RC reconstruction filter + amplifier + jack) and takes its input on uo[7], so it plugs straight into the output Pmod.
  • Quadrature (I/Q): filter uio[7] (PDM_Q) the same way for a second channel 90° out of phase — useful for demodulation experiments.
  • Parallel DAC: feed uo[6:0] (offset-binary, midscale 0x40) into a 7-bit R-2R resistor-ladder DAC on the output Pmod or a SIL header, latched by SAMPLE_EN (uio[0]), for an analog staircase sine; add a gentle RC afterward to smooth the sampling images.

PDM I and Q streams low-pass filtered back to sine and cosine (top), their spectra before/after filtering (middle), and the I/Q cross-correlation confirming 90° quadrature (bottom), note A, octave 8 = 7040 Hz

IO

#InputOutputBidirectional
0NOTE0 (semitone LSB)SINE0 (sine LSB, offset-binary)SAMPLE_EN (48 kHz sample strobe)
1NOTE1SINE1unused
2NOTE2SINE2unused
3NOTE3 (semitone MSB; 0=A..11=G#)SINE3unused
4OCT0 (octave LSB)SINE4NOISE (1-bit white noise, maximal-length LFSR PRBS)
5OCT1SINE5SAW (1-bit sigma-delta sawtooth at the tone frequency)
6OCT2SINE6 (sine MSB)SQR (1-bit square wave at the tone frequency)
7OCT3 (octave MSB; above A0=27.5Hz)PDM_I (1-bit sigma-delta audio out)PDM_Q (1-bit sigma-delta audio out - 90 degrees out of phase from PDM_I)

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)