
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.

Signal chain:
ui[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.clk / 256).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">
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.rst_n low for a few clock cycles, then release it high.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.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.uo[7] (PDM_I) and uio[7] (PDM_Q): fast 1-bit streams whose pulse density follows the sine and cosine.ui_in at any time; the tone follows on the next samples.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.
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.uio[7] (PDM_Q) the same way for a second channel 90° out of phase — useful for demodulation experiments.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.
| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | NOTE0 (semitone LSB) | SINE0 (sine LSB, offset-binary) | SAMPLE_EN (48 kHz sample strobe) |
| 1 | NOTE1 | SINE1 | unused |
| 2 | NOTE2 | SINE2 | unused |
| 3 | NOTE3 (semitone MSB; 0=A..11=G#) | SINE3 | unused |
| 4 | OCT0 (octave LSB) | SINE4 | NOISE (1-bit white noise, maximal-length LFSR PRBS) |
| 5 | OCT1 | SINE5 | SAW (1-bit sigma-delta sawtooth at the tone frequency) |
| 6 | OCT2 | SINE6 (sine MSB) | SQR (1-bit square wave at the tone frequency) |
| 7 | OCT3 (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) |