diff --git a/src/firmware/src/main.rs b/src/firmware/src/main.rs index bfdb8cf..d8bb24d 100644 --- a/src/firmware/src/main.rs +++ b/src/firmware/src/main.rs @@ -6,7 +6,7 @@ extern crate alloc; use core::{cmp, str}; use log::{info, warn}; -use libcortex_a9::asm; +use libcortex_a9::{asm, cache}; use libboard_zynq::{timer::GlobalTimer, logger, slcr}; use libsupport_zynq::ram; use libconfig::Config; @@ -52,9 +52,18 @@ fn identifier_read(buf: &mut [u8]) -> &str { } +const BUFFER_SIZE: usize = 128; + +#[repr(C, align(128))] +struct DmaBuffer { + data: [u8; BUFFER_SIZE], +} + +static mut BUFFER: DmaBuffer = DmaBuffer { data: [0; BUFFER_SIZE] }; + #[no_mangle] pub fn main_core0() { - let mut timer = GlobalTimer::start(); + GlobalTimer::start(); logger::init().unwrap(); log::set_max_level(log::LevelFilter::Info); @@ -73,6 +82,24 @@ pub fn main_core0() { } }; + unsafe { + let base_addr = &mut BUFFER.data[0] as *mut _ as usize; + pl::csr::adc::base_address_write(base_addr as u32); + pl::csr::adc::length_write(BUFFER_SIZE as u32); + + cache::dcci_slice(&BUFFER.data); + pl::csr::adc::start_write(1); + + let busy = pl::csr::adc::busy_read(); + info!("started {}", busy); + while pl::csr::adc::busy_read() != 0 {} + info!("done, bus_error={}", pl::csr::adc::bus_error_read()); + cache::dcci_slice(&BUFFER.data); + for i in 0..BUFFER_SIZE { + info!("{:02x}", BUFFER.data[i]); + } + } + loop { asm::wfe(); } diff --git a/src/gateware/dma.py b/src/gateware/dma.py new file mode 100644 index 0000000..8142ad7 --- /dev/null +++ b/src/gateware/dma.py @@ -0,0 +1,110 @@ +from migen import * +from migen.genlib.fsm import FSM +from migen_axi.interconnect import axi +from misoc.interconnect.csr import * + + +AXI_BURST_LEN = 16 + + +class BlockAddressGenerator(Module): + def __init__(self, membus_stream, data_width): + address_width = len(membus_stream.addr) + alignment_bits = log2_int(AXI_BURST_LEN*data_width//8) + aligned_address_width = address_width - alignment_bits + + self.base_address = Signal(aligned_address_width) + self.length = Signal(aligned_address_width) + self.start = Signal() + self.busy = Signal() + + current_address = Signal(aligned_address_width) + remaining = Signal(aligned_address_width) + + self.comb += [ + membus_stream.addr.eq(Cat(C(0, alignment_bits), current_address)), + membus_stream.id.eq(0), # Same ID for all transactions to forbid reordering. + membus_stream.burst.eq(axi.Burst.incr.value), + membus_stream.len.eq(AXI_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...). + membus_stream.size.eq(log2_int(data_width//8)), # Width of burst: 3 = 8 bytes = 64 bits. + membus_stream.cache.eq(0xf), + ] + + fsm = FSM() + self.submodules += fsm + fsm.act("IDLE", + If(self.start, + NextValue(current_address, self.base_address), + NextValue(remaining, self.length), + NextState("RUNNING") + ) + ) + fsm.act("RUNNING", + self.busy.eq(1), + membus_stream.valid.eq(1), + If(membus_stream.ready, + NextValue(current_address, current_address + 1), + NextValue(remaining, remaining - 1), + If(remaining == 1, + NextState("IDLE") + ) + ) + ) + + +class ADCWriter(Module): + def __init__(self, membus_stream, data_width, pads): + self.busy = Signal() + + self.comb += [ + membus_stream.id.eq(0), + membus_stream.valid.eq(1), + #self.sink.ack.eq(membus.w.ready), + membus_stream.data.eq(0x12345678deadbeef), + membus_stream.strb.eq(2**(data_width//8)-1), + ] + beat_count = Signal(max=AXI_BURST_LEN) + self.sync += [ + If(membus_stream.valid & membus_stream.ready, + membus_stream.last.eq(0), + If(membus_stream.last, + beat_count.eq(0) + ).Else( + If(beat_count == AXI_BURST_LEN-2, membus_stream.last.eq(1)), + beat_count.eq(beat_count + 1) + ) + ) + ] + + +class ADC(Module, AutoCSR): + def __init__(self, membus, pads): + data_width = len(membus.w.data) + address_width = len(membus.aw.addr) + alignment_bits = log2_int(AXI_BURST_LEN*data_width//8) + + self.base_address = CSRStorage(address_width, alignment_bits=alignment_bits) + self.length = CSRStorage(address_width, alignment_bits=alignment_bits) + self.start = CSR() + self.busy = CSRStatus() + self.bus_error = CSRStatus() + + address_generator = BlockAddressGenerator(membus.aw, data_width) + self.submodules += address_generator + self.comb += [ + address_generator.base_address.eq(self.base_address.storage), + address_generator.length.eq(self.length.storage), + address_generator.start.eq(self.start.re) + ] + + adc_writer = ADCWriter(membus.w, data_width, pads) + self.submodules += adc_writer + + self.comb += self.busy.status.eq(address_generator.busy | adc_writer.busy) + + self.comb += membus.b.ready.eq(1) + self.sync += [ + If(self.start.re, self.bus_error.status.eq(0)), + If(membus.b.valid & membus.b.ready & (membus.b.resp != axi.Response.okay), + self.bus_error.status.eq(1)) + ] diff --git a/src/gateware/rust-pitaya.py b/src/gateware/rust-pitaya.py index ccf8651..4d0bb4c 100755 --- a/src/gateware/rust-pitaya.py +++ b/src/gateware/rust-pitaya.py @@ -9,6 +9,8 @@ from migen_axi.integration.soc_core import SoCCore from migen_axi.platforms import redpitaya from misoc.integration import cpu_interface +import dma + class RustPitaya(SoCCore): def __init__(self): @@ -22,6 +24,11 @@ class RustPitaya(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") + adc_pads = platform.request("adc") + + self.submodules.adc = dma.ADC(self.ps7.s_axi_hp0, adc_pads) + self.csr_devices.append("adc") + def write_csr_file(soc, filename): with open(filename, "w") as f: