tdraudio: implement ΔΣ-DAC and volume control

This commit is contained in:
slederer 2025-09-25 00:14:00 +02:00
parent d5888861d3
commit a73fad5786

View file

@ -10,23 +10,30 @@ module tdraudio #(DATA_WIDTH=32) (
input wire wr_en, input wire wr_en,
output wire pdm_out, output wire pdm_out,
output wire gain_en, output wire gain_sel,
output wire shutdown_n output wire shutdown_n
); );
localparam CLOCK_DIV_WIDTH = 22; localparam CLOCK_DIV_WIDTH = 22;
localparam AMP_WIDTH = 16;
localparam TDRAU_REG_CTL = 0; /* control register */ localparam TDRAU_REG_CTL = 0; /* control register */
localparam TDRAU_REG_CLK = 1; /* clock divider register */ localparam TDRAU_REG_CLK = 1; /* clock divider register */
localparam TDRAU_REG_AMP = 2; /* amplitude (volume) register */
reg audio_out; wire audio_out;
reg channel_enable; reg channel_enable;
reg [CLOCK_DIV_WIDTH-1:0] clock_div; reg [CLOCK_DIV_WIDTH-1:0] clock_div;
reg [CLOCK_DIV_WIDTH-1:0] div_count; reg [CLOCK_DIV_WIDTH-1:0] div_count;
reg amp_phase;
reg [AMP_WIDTH-1:0] amp_start;
reg [AMP_WIDTH-1:0] amp_out;
reg [AMP_WIDTH:0] deltasigma_acc;
assign pdm_out = audio_out; assign pdm_out = audio_out;
assign rd_data = {{DATA_WIDTH-8-CLOCK_DIV_WIDTH{1'b0}}, div_count, {7{1'b0}}, channel_enable}; assign rd_data = {{DATA_WIDTH-8-CLOCK_DIV_WIDTH{1'b0}}, div_count, {7{1'b0}}, channel_enable};
assign gain_en = 0; assign gain_sel = 1; // gain select: 0 -> 12dB, 1 -> 6dB
assign shutdown_n = channel_enable; assign shutdown_n = channel_enable;
/* channel enable flag */ /* channel enable flag */
@ -43,10 +50,21 @@ module tdraudio #(DATA_WIDTH=32) (
begin begin
if(reset) if(reset)
clock_div <= 0; clock_div <= 0;
else if (wr_en && (reg_sel == TDRAU_REG_CLK)) else
if (wr_en && (reg_sel == TDRAU_REG_CLK))
clock_div <= wr_data; clock_div <= wr_data;
end end
/* amplitude register */
always @(posedge clk)
begin
if(reset)
amp_start <= 0;
else
if (wr_en && (reg_sel == TDRAU_REG_AMP))
amp_start <= wr_data;
end
/* divider counter */ /* divider counter */
always @(posedge clk) always @(posedge clk)
begin begin
@ -59,16 +77,41 @@ module tdraudio #(DATA_WIDTH=32) (
end end
else else
if (wr_en && (reg_sel == TDRAU_REG_CLK)) if (wr_en && (reg_sel == TDRAU_REG_CLK))
div_count <= 0; // set counter to zero whenever the clock divider is set div_count <= 1; // start cycle in next clock tick
end end
/* 1-bit audio output */ /* amplitude out */
always @(posedge clk) always @(posedge clk)
begin begin
if (reset) if (reset)
audio_out <= 0; begin
amp_out <= 0;
amp_phase <= 1;
end
else else
if (channel_enable && (div_count == 0)) if (channel_enable && (div_count == 0)) // invert amplitude on clock tick
audio_out <= ~audio_out; begin
amp_out <= amp_phase ? amp_start : ~amp_start;
amp_phase <= ~amp_phase;
end
// reset phase bit when enabling the channel
if (wr_en && (reg_sel == TDRAU_REG_CTL) && wr_data[0])
// when channel is enabled, phase will be flipped on next tick
// because div_count will become zero
amp_phase <= 1;
end end
endmodule
/* delta-sigma DAC */
always @(posedge clk)
begin
if(reset)
deltasigma_acc <= 0;
else
if (channel_enable)
deltasigma_acc <= deltasigma_acc[AMP_WIDTH-1:0] + amp_out;
end
/* 1-bit audio output */
assign audio_out = deltasigma_acc[AMP_WIDTH];
endmodule