website logo

FPGA Capacitive Keyboard Synthesizer

An FPGA-Based Musical Instrument With Custom Capacitive Sensing and Digital Audio Synthesis

FPGA Synthesizer

WHY — Motivation, Problem, and Constraints

Project Constraints

  • Built on a Spartan-7 FPGA (limited BRAM + DSP slices)
  • Real-time requirements: touch → audio latency must feel instantaneous
  • Polyphony requires careful BRAM access arbitration and mixing
  • Capacitive sensing is noisy and timing-sensitive
  • No off-the-shelf IP cores; all RTL was hand-written
  • 24–36 capacitive pads (depending on iteration)
  • Clear division of labor required autonomy in subsystem design

WHAT — System Overview

A high-level architecture view:

System Block Diagram

Hardware System Components

Capacitive Interface

Capacitive Interface
  • 24 copper pads milled on a custom PCB
  • 3× MPR121 ICs
  • Address-configured to scale to 36+ pads
  • Routed via PMOD cables to FPGA board

Custom I²C Controller (My Work)

A hand-written Finite State Machine implementing:

  • Start / Stop conditions
  • Clock stretching
  • SDA bidirectional timing
  • Addressing and register access
  • ACK/NACK logic
  • Read/write sequencing
  • Bus arbitration
I2C Read Format I2C Write Format

MPR121 Driver Module

Implements:

  • Runtime configuration of thresholds
  • Continuous electrode polling
  • Combined 24-bit touch vector output
  • Integration with interrupt-based updates

Digital Audio Path

Two sound-generation pipelines were implemented:

A. Procedural Synthesis (My lead)

  • LUTs stored in BRAM
  • DDS phase accumulator
  • Sine / sawtooth / square waves

B. Oud Sample Playback (Adan's lead)

  • Recorded and pitch-processed in Python (librosa)
  • Resampled to 16 kHz
  • Converted into BRAM .mem files
  • Up to ~8k samples per note
  • 16-bit output resolution

ADSR (Adan's Module)

  • FSMD structure
  • Attack → Decay → Sustain → Release
  • Smooth multiplier applied to waveform sample
  • One ADSR per voice → enables polyphony

Polyphony Engine(Shared)

Supports 8 voices, each with:

  • Independent phase accumulator
  • Independent ADSR
  • BRAM reading logic
  • Normalized summation

PDM Output Encoder (My Work)

  • Selected PDM over PWM for better audio quality
  • Drives headphones or speakers with a simple RC filter

HOW — Engineering Decisions, Challenges, and Deep Technical Work


1. Custom I²C Implementation (My work)

Challenges

  • Bidirectional SDA line requires careful enable/disable timing
  • MPR121 requires specific reset timing and threshold registers
  • Received values needed stable synchronizers to avoid metastability
  • Correcting false positives due to noisy pads
  • Handling multi-byte sequential reads

Key Engineering Work

  • Designed a 9-state I²C FSM (“START”, “ADDR”, “ACK”, “WRITE”, “READ”, “STOP”, etc.)
  • Implemented sampling of SDA on the rising edge of SCL and driving on the falling edge
  • Added timeout behavior for bus lock-up
  • Used Saleae logic analyzer to validate waveform timing
  • Polled MPR121 electrode-status registers (0x00–0x01) and exposed a clean 24-bit vector

2. Note Decoder Logic (My Work)

Challenges

  • Mapping 24 touch channels to musical notes
  • Handling multi-pad activation gracefully
  • Interfacing with voice allocator

Design Approach

Decision

I separated gesture detection (touch) from voice triggering (synthesis) so polyphony infrastructure remained modular.


3. DDS + Sample Playback Pipeline

Phase Accumulator

  • 32-bit accumulator running at FPGA’s master clock
  • Computed: phase_increment = (frequency * 2^32) / Fs
  • High resolution → smooth pitch transitions

Waveform Address Generator

  • Top bits of accumulator used as BRAM address
  • Supported both LUT-based and sample-based paths

4. BRAM-Efficient Sample Storage

Challenge

  • Spartan-7 BRAM is tight
  • Realistic Oud notes require thousands of samples

Approach

  • Preprocessing in Python:
    • Trim silence
    • Normalize
    • Downsample to 16 kSps
    • Convert to .mem files
  • Designed BRAM layout: 4 BRAMs per note for ~8k samples
  • Enabled instrument to sound authentic despite memory constraints

5. Polyphony Architecture & Mixing

Challenge

  • Multiple voices → BRAM contention
  • Summation → overflow risk
  • Need per-voice ADSR channels

Design Choices

  • Use parallel channels for primary voices
  • Use TDM-like behavior for secondary voices
  • Normalization via shift-based scaling avoids costly division

6. PDM Output

Why PDM

  • Higher perceived audio fidelity than PWM on the same clock
  • Easier analog filtering
  • Produces clean signal for speakers/headphones

7. Physical Fabrication (My Work)

Enclosure
  • Designed and milled the capacitive PCB
  • Laser-cut enclosure inspired by Arabic geometries
  • Integrated PCB pad shape into ergonomic layout
  • Ensured low-noise grounding paths

Relevant Engineering Skills Demonstrated (Mapped to Formlabs Rubric)

✔ Autonomy

  • Designed full capacitive subsystem alone
  • Implemented I²C protocol from scratch
  • Built ADSR, PDM, and major parts of DDS
  • Performed full system integration & timing closure

✔ Challenge

  • Real-time constraints
  • BRAM budgeting
  • Timing-sensitive I²C HDL implementation
  • Polyphonic mixing without DSP overflow
  • Debugging noisy capacitive signals

✔ Technical Depth

  • FSM design for communication protocols
  • Direct Digital Synthesis
  • Audio sample processing and memory layout
  • HDL for DACs (PWM/PDM)
  • Multi-channel ADC-like sensing integration
  • Polyphony architecture and scheduling

✔ Decision-Making

  • Chose FPGA over MCU for deterministic timing & parallelism
  • Chose PDM over PWM for fidelity
  • Used sample playback where wavetable synthesis lacked richness
  • Designed I²C FSM instead of vendor IP for transparency
  • Mixed dedicated and TDM-based approaches for scalable polyphony

```