Skip to content

Commit

Permalink
ecpix nice audio but last 2 channels duplicate to output 4 channels??
Browse files Browse the repository at this point in the history
  • Loading branch information
vk2seb committed Sep 24, 2023
1 parent 385dddb commit 2521af8
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 21 deletions.
2 changes: 1 addition & 1 deletion deps/eurorack-pmod
202 changes: 187 additions & 15 deletions example-ecpix-5.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,160 @@
),
]

class DMARouter(LiteXModule):

def __init__(self, soc):

self.sink = stream.Endpoint([("in0", 16),
("in1", 16),
("in2", 16),
("in3", 16)])

self.source = stream.Endpoint([("out0", 16),
("out1", 16),
("out2", 16),
("out3", 16)])

self.writer_bus0 = wishbone.Interface()
self.reader_bus0 = wishbone.Interface()
self.submodules.dma_writer0 = WishboneDMAWriter(self.writer_bus0, endianness="big")
self.submodules.dma_reader0 = WishboneDMAReader(self.reader_bus0, endianness="big", fifo_depth=1)

def add_csr(self):
# CSR
self._base_writer = CSRStorage(32)
self._base_reader = CSRStorage(32)
self._length_words = CSRStorage(32, reset=0)
self._offset_words = CSRStatus(32)
self._enable = CSRStorage(reset=0)

# Local signals
shift = log2_int(self.writer_bus0.data_width//8)
base_writer = Signal(self.writer_bus0.adr_width)
base_reader = Signal(self.writer_bus0.adr_width)
offset_words = Signal(self.writer_bus0.adr_width)
length_words = Signal(self.writer_bus0.adr_width)
offset_words_r= Signal(self.writer_bus0.adr_width)

self.comb += [
base_writer.eq(self._base_writer.storage[shift:]),
base_reader.eq(self._base_reader.storage[shift:]),
length_words.eq(self._length_words.storage),
self._offset_words.status.eq(offset_words),
]

# IRQ logic
self.ev = EventManager()
self.ev.half = EventSourceProcess(edge="rising")
self.comb += [
self.ev.half.trigger.eq(
(offset_words == (length_words >> 1)) |
(offset_words == (length_words - 2))),
]
self.ev.finalize()

# DMA FSM (write side)

fsm_write = FSM(reset_state="IDLE")
fsm_write = ResetInserter()(fsm_write)
self.submodules += fsm_write
self.comb += fsm_write.reset.eq(~self._enable.storage)

fsm_write.act("IDLE",
NextValue(offset_words, 0),
NextState("EVEN"),
)

fsm_write.act("EVEN",
self.dma_writer0.sink.valid.eq(self.sink.valid),
self.dma_writer0.sink.address.eq(base_writer + offset_words),
self.dma_writer0.sink.data.eq((self.sink.in3 << 16) | self.sink.in2),
self.sink.ready.eq(self.dma_writer0.sink.ready),
If(self.sink.valid & self.sink.ready,
NextValue(offset_words, offset_words + 1),
NextState("ODD"),
)
)

fsm_write.act("ODD",
self.dma_writer0.sink.valid.eq(self.sink.valid),
self.dma_writer0.sink.address.eq(base_writer + offset_words),
self.dma_writer0.sink.data.eq((self.sink.in1 << 16) | self.sink.in0),
self.sink.ready.eq(0),
If(self.sink.valid & self.dma_writer0.sink.ready,
NextValue(offset_words, offset_words + 1),
If((offset_words + 1) == length_words,
NextValue(offset_words, 0)
),
NextState("EVEN"),
)
)

# DMA FSM (read side)

fsm_read = FSM(reset_state="IDLE")
fsm_read = ResetInserter()(fsm_read)
self.submodules += fsm_read
self.comb += fsm_read.reset.eq(~self._enable.storage)

fsm_read.act("IDLE",
NextValue(offset_words_r, 0),
NextState("EVEN"),
)

fsm_read.act("EVEN",
self.dma_reader0.sink.valid.eq(1),
NextValue(self.dma_reader0.sink.address, base_reader + offset_words_r),
If(self.dma_reader0.sink.ready,
NextValue(self.dma_reader0.source.ready, 1),
NextValue(offset_words_r, offset_words_r + 1),
NextState("WAIT1"),
),
)

fsm_read.act("WAIT1",
# Not sure about this...
If(self.dma_reader0.source.valid,
NextValue(self.dma_reader0.source.ready, 0),
NextValue(self.source.out0, self.dma_reader0.source.data[:16]),
NextValue(self.source.out1, self.dma_reader0.source.data[16:32]),
NextState("ODD"),
)
)

fsm_read.act("ODD",
self.dma_reader0.sink.valid.eq(1),
NextValue(self.dma_reader0.sink.address, base_reader + offset_words_r),
If(self.dma_reader0.sink.ready,
NextValue(self.dma_reader0.source.ready, 1),
NextValue(offset_words_r, offset_words_r + 1),
NextState("WAIT2"),
),
)


fsm_read.act("WAIT2",
# Not sure about this...
If(self.dma_reader0.source.valid,
NextValue(self.source.valid, 1),
NextValue(self.dma_reader0.source.ready, 0),
NextValue(self.source.out2, self.dma_reader0.source.data[:16]),
NextValue(self.source.out3, self.dma_reader0.source.data[16:32]),
NextState("WAIT3"),
)
)

fsm_read.act("WAIT3",
# Not sure about this...
If(self.source.ready,
NextValue(self.source.valid, 0),
If(offset_words_r == length_words,
NextValue(offset_words_r, 0)
),
NextState("EVEN"),
)
)

def add_eurorack_pmod(soc, sample_rate=48000):
soc.platform.add_extension(_io_eurorack_pmod)

Expand All @@ -53,30 +207,48 @@ def add_eurorack_pmod(soc, sample_rate=48000):
eurorack_pmod = EurorackPmod(soc.platform, eurorack_pmod_pads)

# CDC
cdc_in0 = ClockDomainCrossing(layout=[("data", 32)], cd_from="clk_fs", cd_to="sys")
cdc_out0 = ClockDomainCrossing(layout=[("data", 32)], cd_from="sys", cd_to="clk_fs")
cdc_in0 = ClockDomainCrossing(
layout=[("in0", 16),
("in1", 16),
("in2", 16),
("in3", 16)],
cd_from="clk_fs",
cd_to="sys"
)
cdc_out0 = ClockDomainCrossing(
layout=[("out0", 16),
("out1", 16),
("out2", 16),
("out3", 16)],
cd_from="sys",
cd_to="clk_fs"
)

# CDC <-> I2S (clk_fs domain)
soc.comb += [
# ADC -> CDC
cdc_in0.sink.valid.eq(1),
cdc_in0.sink.payload.data.eq(eurorack_pmod.cal_in0),
cdc_in0.sink.in0.eq(eurorack_pmod.cal_in0),
cdc_in0.sink.in1.eq(eurorack_pmod.cal_in1),
cdc_in0.sink.in2.eq(eurorack_pmod.cal_in2),
cdc_in0.sink.in3.eq(eurorack_pmod.cal_in3),
# CDC -> DAC
cdc_out0.source.ready.eq(1),
eurorack_pmod.cal_out0.eq(cdc_out0.source.payload.data)
eurorack_pmod.cal_out0.eq(cdc_out0.source.out0),
eurorack_pmod.cal_out1.eq(cdc_out0.source.out1),
eurorack_pmod.cal_out2.eq(cdc_out0.source.out2),
eurorack_pmod.cal_out3.eq(cdc_out0.source.out3),
]

# DMA master (ADC -> CDC -> Wishbone)
soc.submodules.dma_writer0 = WishboneDMAWriter(wishbone.Interface(), endianness="big", with_csr=True)
soc.bus.add_master(master=soc.dma_writer0.bus)
soc.comb += cdc_in0.source.connect(soc.dma_writer0.sink)
soc.irq.add("dma_writer0", use_loc_if_exists=True)

# DMA master (Wishbone -> CDC -> DAC)
soc.submodules.dma_reader0 = WishboneDMAReader(wishbone.Interface(), endianness="big", with_csr=True)
soc.bus.add_master(master=soc.dma_reader0.bus)
soc.comb += soc.dma_reader0.source.connect(cdc_out0.sink)
soc.irq.add("dma_reader0", use_loc_if_exists=True)
soc.submodules.dma_router0 = DMARouter(soc)
soc.dma_router0.add_csr()
soc.comb += [
soc.dma_router0.source.connect(cdc_out0.sink),
cdc_in0.source.connect(soc.dma_router0.sink),
]
soc.bus.add_master(master=soc.dma_router0.dma_writer0.bus)
soc.bus.add_master(master=soc.dma_router0.dma_reader0.bus)
soc.irq.add("dma_router0", use_loc_if_exists=True)

soc.add_module("eurorack_pmod0", eurorack_pmod)
soc.add_module("cdc_in0", cdc_in0)
Expand Down
4 changes: 2 additions & 2 deletions firmware/litex-fw/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ fn default_handler() {
if offset as usize == ((BUF_SZ_WORDS/2)+1) {
for i in 0..(BUF_SZ_SAMPLES/2) {
unsafe {
//BUF_OUT[i] = BUF_IN[i];
BUF_OUT[i] = BUF_IN[i];
}
}
}

if offset as usize == (BUF_SZ_WORDS-1) {
for i in (BUF_SZ_SAMPLES/2)..(BUF_SZ_SAMPLES) {
unsafe {
//BUF_OUT[i] = BUF_IN[i];
BUF_OUT[i] = BUF_IN[i];
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions firmware/litex-fw/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ litex_hal::timer! {
}

const N_CHANNELS: usize = 4;
const BUF_SZ_WORDS: usize = 16;
const BUF_SZ_WORDS: usize = 64;
const BUF_SZ_SAMPLES: usize = BUF_SZ_WORDS * 2;

// MUST be aligned to 4-byte (word) boundary for RV32. These buffers are directly
Expand All @@ -48,7 +48,7 @@ fn main() -> ! {
for i in 0..BUF_SZ_SAMPLES {
unsafe {
//BUF_OUT_CP[i] = (16000.0f32*f32::sin(2.0f32*3.141f32*i as f32 / BUF_SZ_WORDS as f32)) as i16;
BUF_OUT[i] = (256 + (i*256)) as i16;
BUF_OUT[i] = (i*256) as i16;
}
}

Expand Down Expand Up @@ -105,6 +105,7 @@ fn main() -> ! {
}
}
*/
/*
log::info!("READ");
unsafe {
asm!("fence iorw, iorw");
Expand All @@ -114,6 +115,7 @@ fn main() -> ! {
}
}
timer.delay_ms(10u32);
*/
/*
log::info!("jack_detect {:x}", peripherals.EURORACK_PMOD0.csr_jack.read().bits() as u8);
log::info!("input0 {}", peripherals.EURORACK_PMOD0.csr_cal_in0.read().bits() as i16);
Expand Down
2 changes: 1 addition & 1 deletion sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def add_eurorack_pmod(soc):
eurorack_pmod = EurorackPmod(soc.platform, eurorack_pmod_pads, sim=True)

# Simulate all outputs looped back to inputs on the PMOD I2S
soc.comb += eurorack_pmod_pads.sdout1.eq(eurorack_pmod_pads.sdin1)
#soc.comb += eurorack_pmod_pads.sdout1.eq(eurorack_pmod_pads.sdin1)

# CDC
cdc_in0 = ClockDomainCrossing(
Expand Down

0 comments on commit 2521af8

Please sign in to comment.