Hello,
I've been experimenting with one bit DAC recently to get a very easy way to output sound from the Basys3.
So, here it is.
It uses a 100MHz clock (even if the output one bit modulation is 12.5MHz).
The input is 20 bit.
The output bit is meant to be sent directly to a physical port.
Before going Verilog I experimented it in a Java benchmark to check stability
- the first integrator u is leaky ( hence the - (u>>>3) ) to limit chaotic behavior for low level sounds.
This is not an intent to replace a genuine converter.
But I think it can be handy if you don't have one at hand and want to experiment with sound generation.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Thierry Rochebois
//
// Create Date: 22.12.2021 10:31:45
// Module Name: DAC
// Description: A second order one bit audio DAC.
// inputs: clk 100 MHz clock
// in 20 bit signed input
// (can be refreshed at a rate up to 200kHz)
// output: out 1 bit out modulated at 12.5MHz
//
// Dependencies: NONE
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DAC(
input clk, // 100MHz clock
input signed [19:0] in, // input (update rate up to 200kHz)
output reg out // one bit out modulated at 12.5MHz
);
reg signed [2:-21] x = 24'b0; // input cast to q3.21
reg signed [2:-21] u = 24'b0; // first integrator
reg signed [2:-21] v = 24'b0; // second integrator
wire signed [2:0] y; // output for feedback q3.0 -1 or +1
always @(posedge clk) begin
x <= {{4{in[19]}}, in}; // 20 bit input -> q3.21 [-0.5 0.5[
end
// 1/8 counter -> 12.5MHz
reg [2:0] cpt8;
always @(posedge clk) begin
cpt8 <= cpt8 - 1;
end
// for feedback -1 q3.0 +1 q3.0
assign y = (v > 0) ? 3'b111 : 3'b001;
wire signed [2:-20] s1;
wire signed [2:-21] s1h;
assign s1 = {x[2:0] + y, x[-1:-20]};
assign s1h = {s1[2], s1[2:-20]};
wire signed [2:-20] s2;
wire signed [2:-21] s2h;
assign s2 = {u[2:0] + y, u[-1:-20]};
assign s2h = {s2[2], s2[2:-20]};
// 100MHz / 8 = 12.5MHz for the 1 bit DAC
always @(posedge clk && (cpt8 == 0)) begin
u <= u + s1h - (u>>>3); // first integrator with feedback
v <= v + s2h; // second integrator with feedback
out <= v[2]; // output
end
endmodule
Here is an example with some triangle waves :