Skip to content

Commit

Permalink
ak4619: fix timing bug in synchronizing clk_fs and internal clkdiv
Browse files Browse the repository at this point in the history
  • Loading branch information
vk2seb committed Oct 6, 2023
1 parent 955c455 commit e7bcafa
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 35 deletions.
78 changes: 54 additions & 24 deletions gateware/drivers/ak4619.sv
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// Driver for AK4619 ADC/DAC
// Driver for AK4619 CODEC.
//
// Currently assumes the device is configured in the audio
// interface mode specified in ak4619-cfg.hex.
// Usage:
// - `clk_256fs` and `clk_fs` determine the hardware sample rate.
// - Once CODEC is initialized over I2C, samples can be streamed.
// - `sample_in` is latched on falling `clk_fs`.
// - `sample_out` transitions on falling `clk_fs`.
// - As a result, users of this core should latch sample_out (and transition
// sample_in) on rising `clk_fs`.
//
// The following registers are most important:
// This core assumes the device is configured in the audio
// interface mode specified in ak4619-cfg.hex. This happens
// over I2C inside the state machine `pmod_i2c_master.sv`.
//
// The following registers specify the interface format:
// - FS == 0b000, which means:
// - MCLK = 256*Fs,
// - BICK = 128*Fs,
Expand All @@ -17,32 +26,37 @@
module ak4619 #(
parameter W = 16 // sample width, bits
)(
input rst,
input clk_256fs,
input clk_fs,

input rst,
// Route these straight out to the CODEC pins.
output pdn,
output mclk,
output bick,
output lrck,
output reg sdin1,
input sdout1,

// Transitions on falling `clk_fs`.
output reg signed [W-1:0] sample_out0,
output reg signed [W-1:0] sample_out1,
output reg signed [W-1:0] sample_out2,
output reg signed [W-1:0] sample_out3,
input signed [W-1:0] sample_in0,
input signed [W-1:0] sample_in1,
input signed [W-1:0] sample_in2,
input signed [W-1:0] sample_in3

// Latches on falling `clk_fs`.
input signed [W-1:0] sample_in0,
input signed [W-1:0] sample_in1,
input signed [W-1:0] sample_in2,
input signed [W-1:0] sample_in3
);

localparam int N_CHANNELS = 4;

logic signed [(W*N_CHANNELS)-1:0] dac_words;
logic signed [W-1:0] adc_words [N_CHANNELS];

logic last_fs;
logic [7:0] clkdiv;

logic [1:0] channel;
Expand All @@ -53,32 +67,46 @@ assign bick = clkdiv[0];
assign mclk = clk_256fs;
assign lrck = clkdiv[7];

assign channel = clkdiv[7:6]; // 0, 1, 2, 3 == L, R, L, R
// 0, 1, 2, 3 == L, R, L, R
assign channel = clkdiv[7:6];
// 0..31 for each channel, regardless of W.
assign bit_counter = clkdiv[5:1];

always_ff @(negedge clk_fs) begin
dac_words = {sample_in3, sample_in2,
sample_in1, sample_in0};
sample_out0 <= adc_words[0];
sample_out1 <= adc_words[1];
sample_out2 <= adc_words[2];
sample_out3 <= adc_words[3];
end

always_ff @(posedge clk_256fs) begin
clkdiv <= clkdiv + 1;
if (rst) begin
last_fs <= 0;
clkdiv <= 0;
dac_words = 0;
sample_out0 <= 0;
sample_out1 <= 0;
sample_out2 <= 0;
sample_out3 <= 0;
end else if (last_fs && ~clk_fs) begin
// Synchronize clkdiv to the incoming sample clock, latching
// our inputs and outputs at the falling edge of clk_fs.
clkdiv <= 8'h0;
end else if (bick) begin // HI -> LO
// Clock in W bits
dac_words = {sample_in3, sample_in2,
sample_in1, sample_in0};
sample_out0 <= adc_words[0];
sample_out1 <= adc_words[1];
sample_out2 <= adc_words[2];
sample_out3 <= adc_words[3];
last_fs <= clk_fs;
end else if (bick) begin
// BICK transition HI -> LO: Clock in W bits
// On HI -> LO both SDIN and SDOUT do not transition.
// (determined by AK4619 transition polarity register BCKP)
if (bit_counter == 0) begin
adc_words[channel] <= 0;
end
if (bit_counter < W) begin
adc_words[channel][W - bit_counter - 1] <= sdout1;
end
end else begin
// Clock out W bits
clkdiv <= clkdiv + 1;
last_fs <= clk_fs;
end else begin // BICK: LO -> HI
// BICK transition LO -> HI: Clock out W bits
// On LO -> HI both SDIN and SDOUT transition.
if (bit_counter <= (W-1)) begin
case (channel)
0: sdin1 <= dac_words[(1*W)-1-bit_counter];
Expand All @@ -89,6 +117,8 @@ always_ff @(posedge clk_256fs) begin
end else begin
sdin1 <= 0;
end
clkdiv <= clkdiv + 1;
last_fs <= clk_fs;
end
end

Expand Down
22 changes: 12 additions & 10 deletions gateware/eurorack_pmod.sv
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,19 @@ cal #(
.out7 (sample_dac3)
);

// CODEC ser-/deserialiser. Also derives sample clock.
// CODEC ser-/deserialiser. Sample rate derived from these clocks.
ak4619 ak4619_instance (
.clk_256fs (clk_256fs),
.clk_fs (clk_fs),
.rst (rst),
.pdn (pdn),
.mclk (mclk),
.bick (bick),
.lrck (lrck),
.sdin1 (sdin1),
.sdout1 (sdout1),
.rst (rst),
.clk_256fs (clk_256fs),
.clk_fs (clk_fs),

.pdn (pdn),
.mclk (mclk),
.bick (bick),
.lrck (lrck),
.sdin1 (sdin1),
.sdout1 (sdout1),

.sample_out0 (sample_adc0),
.sample_out1 (sample_adc1),
.sample_out2 (sample_adc2),
Expand Down
1 change: 0 additions & 1 deletion gateware/sim/ak4619/tb_ak4619.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@


async def clock_out_word(dut, word):
await FallingEdge(dut.bick)
for i in range(32):
await RisingEdge(dut.bick)
dut.sdout1.value = (word >> (0x1F-i)) & 1
Expand Down

0 comments on commit e7bcafa

Please sign in to comment.