diff --git a/dacVolume.py b/dacVolume.py new file mode 100644 index 0000000..01167fb --- /dev/null +++ b/dacVolume.py @@ -0,0 +1,38 @@ +from migen import * + +from litex.soc.interconnect.csr import * +from litex.soc.integration.doc import ModuleDoc + +# Test RGB Module ---------------------------------------------------------------------------------- + +class DacVolume(Module, AutoCSR, ModuleDoc): + """ + DAC Volume Control Module + + Set the Attenuation of the PCM1780 DAC + """ + def __init__(self, platform, pads): + platform.add_source("rtl/dacVolume.sv") + + self.pads = pads + self.volume = CSRStorage(size = 8, reset = 128, description = "PCM1780: Attenuation Control") + + self.m_sel_n = Signal() + self.m_clock = Signal() + self.m_data = Signal() + + # # # + + self.specials += Instance("dacVolume", + i_i_clk48 = ClockSignal(), + i_i_rst48_n = ~ResetSignal(), + i_i_valid = self.volume.re, + i_i_volume = self.volume.storage, + o_o_sel_n = self.m_sel_n, + o_o_clock = self.m_clock, + o_o_data = self.m_data, + ) + + self.comb += self.pads.ms.eq(self.m_sel_n) # Mode Bus: Select (Active Low) + self.comb += self.pads.mc.eq(self.m_clock) # Mode Bus: Clock + self.comb += self.pads.md.eq(self.m_data) # Mode Bus: Data diff --git a/make.py b/make.py index 6620e73..429cc56 100755 --- a/make.py +++ b/make.py @@ -26,6 +26,7 @@ from litex.soc.cores.led import LedChaser from litedram.modules import MT41K64M16, MT41K128M16, MT41K256M16, MT41K512M16 from litedram.phy import ECP5DDRPHY +from dacVolume import DacVolume from testLED import TestLed from testRGB import TestRgb from testSaw import TestSaw @@ -237,10 +238,20 @@ class BaseSoC(SoCCore): pads = platform.request("dac_pcm") ) + self.dac_vol = DacVolume( + platform = platform, + pads = platform.request("dac_ctrl") + ) + # LiteScope Analyzer ----------------------------------------------------------------------- self.add_uartbone(name="debug_uart", baudrate=921600) from litescope import LiteScopeAnalyzer analyzer_signals = [ + self.dac_vol.volume.re, + self.dac_vol.volume.storage, + self.dac_vol.m_sel_n, + self.dac_vol.m_clock, + self.dac_vol.m_data, self.audio.targ0.re, # self.audio.targ0.storage, self.audio.wave0.re, @@ -260,8 +271,10 @@ class BaseSoC(SoCCore): self.submodules.analyzer = LiteScopeAnalyzer( analyzer_signals, depth = analyzer_depth, - clock_domain = "dac", - samplerate = 36.92e6, # Actual clock frequency of DAC clock domain + # clock_domain = "dac", + clock_domain = "sys", + # samplerate = 36.92e6, # Actual clock frequency of DAC clock domain + samplerate = sys_clk_freq, csr_csv = "analyzer.csv", ) diff --git a/rtl/dacVolume.sv b/rtl/dacVolume.sv new file mode 100644 index 0000000..b2ced8f --- /dev/null +++ b/rtl/dacVolume.sv @@ -0,0 +1,48 @@ +`default_nettype none + +module dacVolume +( input var i_clk48 // Runs at 48MHz +, input var i_rst48_n // Active low reset for sys_clk +, input var i_valid // Only update DAC volume when CSRStorage is written to +, input var [7:0] i_volume // 8-bit volume control (0x00 = min, 0xFF = max) +, output var o_sel_n // DAC Control bus select (active low) +, output var o_clock // DAC Control bus clock +, output var o_data // DAC Control bus data (serial) +); + +logic [7:0] valid; +always_ff @(posedge i_clk48) // Capture when CSTStorage is written to + if (!i_rst48_n) valid <= 8'h00; + else if (i_valid) valid <= 8'hFF; + else valid <= {valid[6:0], 1'b0}; + +logic [7:0] volume; +always_ff @(posedge i_clk48) // Update volume setting when CSRStorage is written to + if (!i_rst48_n) volume <= 8'h00; + else if (i_valid) volume <= i_volume; + +logic [2:0] div_6m; +always_ff @(posedge i_clk48) // Count 6MHz cycle + if (!i_rst48_n) div_6m <= 3'b000; + else div_6m <= div_6m + 1; + +always_comb o_clock = div_6m[2]; // Drive DAC Control bus clock at 6MHz + +logic _sel_n; +logic _data; +// always_comb o_sel_n = _sel_n; // Design fails to boot unless _sel_n optimised out +// always_comb o_data = _data; // Design fails to boot unless _data optimised out + +logic [34:0] sel_n; +always_ff @(negedge o_clock) // Update SEL_n on falling edge of CLOCK (As in PCM1780 Datasheet) + if (!i_rst48_n) {_sel_n, sel_n} <= 36'hFFFFFFFFF; + else if (valid[7]) {_sel_n, sel_n} <= 36'h0000C0003; + else {_sel_n, sel_n} <= {sel_n, 1'b1}; + +logic [34:0] data; +always_ff @(negedge o_clock) // Update DATA on falling edge of CLOCK (As in PCM1780 Datasheet) + if (!i_rst48_n) {_data, data} <= 36'h000000000; + else if (valid[7]) {_data, data} <= {8'd16, volume, 2'd0, 8'd17, volume, 2'd0}; + else {_data, data} <= {data, 1'b0}; + +endmodule