Skip to content

iitzex/pcm56

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PCM56 FPGA Audio DAC Controller

License: MIT Build Status

Digital audio frontend for the classic Burr-Brown PCM56 R-2R DAC, implemented in SystemVerilog on Lattice ECP5. Provides a complete clock-domain-isolated DSP pipeline with async FIFO jitter isolation, 2x FIR oversampling with inverse sinc compensation, TPDF dither, and 1st-order noise shaping.

Features

  • I2S / Left-Justified input with input synchronizers
  • Async BRAM FIFO (1024 depth) for clock domain crossing — decouples jittery I2S BCK from clean local master clock
    • Write domain: incoming BCK (jittery)
    • Read domain: local MCK (clean, via Amanero)
    • Automatic fill-level recentering: inserts/drops samples at zero-crossing when FIFO approaches full/empty, preventing long-term drift with asynchronous clock sources
  • 31-tap FIR 2x oversampler with embedded inverse sinc compensation, running on a gated clock shifted away from BCK edges
  • Audio DSP pipeline: 24-bit → 16-bit with TPDF dither + 1st-order error-feedback noise shaping
  • PCM56 serial transmitter with synchronous clock-enable architecture
  • Output reclocking: BCK outputs driven via ODDRX1F + DCCA global clock buffer for low-jitter DAC interface
  • Dual-mode: Oversampling (OS) / Non-Oversampling (NOS) via compile-time defines

Architecture

 ┌─────────────────────────────────────────────────────────────────────────────┐
 │ I2S Source (Amanero)                                                        │
 │  BCK (jittery) ──────┬──────────┐                                          │
 │  LRCK ───── Sync ────┤ I2S      │                                          │
 │  DATA ───── Sync ────┤ Receiver │                                          │
 └───────────────────────┴────┬─────┘                                          │
                              │ 24-bit L/R                                     │
                              ▼                                                │
 ┌──────────────────────────────────────────────────────────────────────────┐ │
 │  Dirty Domain (BCK)              Async FIFO (1024×48bit, dual-clock BRAM)│ │
 │  wr_clk = bck_i    ──────────►   ┌──────────────────────────────┐        │ │
 │                                   │  Gray-code pointers         │        │ │
 │                                   │  Dual 2-flop CDC sync      │        │ │
 │                                   │  Registered almost_full/    │        │ │
 │                                   │  almost_empty watermarks    │        │ │
 │                                   └──────────┬───────────────────┘        │ │
 └──────────────────────────────────────────────┼────────────────────────────┘ │
                                                │ 48-bit dout                  │
                                                ▼                              │
 ┌──────────────────────────────────────────────────────────────────────────┐ │
 │  Clean Domain (MCK)          MCK via DCCA (global clock buffer)         │ │
 │                                                                          │ │
 │  Timing Generator ──► clean BCK (MCK/4)                                  │ │
 │                   ──► clean LRCK                                         │ │
 │                   ──► bit counter (64-step frame)                        │ │
 │                                                                          │ │
 │  FIFO Recentering:                                                       │ │
 │    almost_full  ──► drop one FIFO read (decrease fill)                   │ │
 │    almost_empty ──► repeat one FIFO word (increase fill)                 │ │
 │                                                                          │ │
 │  FIR Filter (2x OS, 31-tap polyphase HBF + inv-sinc)                    │ │
 │    on gated fir_clk (DCCA CE, shifted off BCK edges)                    │ │
 │                                                                          │ │
 │  Audio DSP: TPDF dither + 1st-order error-feedback noise shaper          │ │
 │                                                                          │ │
 │  PCM56 Transmitter (posedge MCK with CE, serializer)                    │ │
 │                                                                          │ │
 │  Output IO: BCK via ODDRX1F + DCCA                                       │ │
 │             SDO/LE via IOBUF (SLEWRATE=FAST)                             │ │
 └───────────────────────────────────┬──────────────────────────────────────┘ │
                                     │                                        │
                                     ▼                                        │
                              PCM56 DAC (CH2/CH3)                             │
 └─────────────────────────────────────────────────────────────────────────────┘

File Structure

  • rtl/i2s_top.sv — Top-level: clock management, FIFO, module integration
  • rtl/async_fifo.sv — Dual-clock async FIFO with registered watermarks
  • rtl/i2s_receiver.sv — I2S / Left-Justified serial audio capture
  • rtl/input_sync.sv — Double-flop input synchronizers
  • rtl/timing_gen.sv — Clean BCK/LRCK generation from MCK
  • rtl/oversampler_fir.sv — 31-tap polyphase FIR with inverse sinc
  • rtl/audio_dsp.sv — TPDF dither + 1st-order noise shaper
  • rtl/pcm56_transmitter.sv — PCM56 serial interface driver
  • rtl/reset_sync.sv — Power-on reset with domain-specific deassertion
  • pinmap.lpf — ECP5 pin mapping and timing constraints
  • sim/i2s_tb.sv — Testbench for behavioral simulation
  • docs/pcm56.pdf — Hardware schematic (10 pages)

Jitter Architecture

The design separates the I2S source domain from the DAC output domain at the async FIFO boundary:

Domain Clock Role Jitter handling
Dirty incoming BCK I2S receiver, FIFO write Jitter present on BCK, but only affects capture flops; CDC isolation prevents propagation
Clean local MCK (Amanero) timing gen, FIR, DSP, transmitter, output BCK MCK is a clean dedicated clock; jitter-free output to DAC

Amanero provides both the I2S signal and the local MCK, ensuring clean clock quality without additional PLL cleanup.

The FIFO bridges the two domains via Gray-code pointer CDC. Registered watermarks (almost_full/almost_empty) drive automatic recentering: when fill approaches overflow/underflow, a single sample is dropped or repeated, preventing audio dropout with asynchronous source clocks.

Toolchain Requirements

  • Synthesis: Yosys
  • Place & Route: nextpnr-ecp5
  • Bitstream: Project Trellis (ecppack)
  • Simulation: Icarus Verilog
  • Programming: openFPGALoader

Target device: Lattice ECP5-25K (CABGA256, speed grade 6)

Usage

Build (2x Oversampling, default)

make

Build (Non-Oversampling)

make nos

Run Simulation

make sim

Program FPGA

make flash        # flash (non-volatile), OS mode
make load         # SRAM (volatile), OS mode
make flash_nos    # flash, NOS mode
make load_nos     # SRAM, NOS mode

Clean

make clean

License

MIT. See LICENSE file.

About

High-performance SystemVerilog audio frontend for dual PCM56 DACs.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors