DMA demo
This commit is contained in:
parent
e6bad44e83
commit
2c588992c5
|
@ -6,7 +6,7 @@ extern crate alloc;
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use libcortex_a9::asm;
|
use libcortex_a9::{asm, cache};
|
||||||
use libboard_zynq::{timer::GlobalTimer, logger, slcr};
|
use libboard_zynq::{timer::GlobalTimer, logger, slcr};
|
||||||
use libsupport_zynq::ram;
|
use libsupport_zynq::ram;
|
||||||
use libconfig::Config;
|
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]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
let mut timer = GlobalTimer::start();
|
GlobalTimer::start();
|
||||||
logger::init().unwrap();
|
logger::init().unwrap();
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
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 {
|
loop {
|
||||||
asm::wfe();
|
asm::wfe();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
]
|
|
@ -9,6 +9,8 @@ from migen_axi.integration.soc_core import SoCCore
|
||||||
from migen_axi.platforms import redpitaya
|
from migen_axi.platforms import redpitaya
|
||||||
from misoc.integration import cpu_interface
|
from misoc.integration import cpu_interface
|
||||||
|
|
||||||
|
import dma
|
||||||
|
|
||||||
|
|
||||||
class RustPitaya(SoCCore):
|
class RustPitaya(SoCCore):
|
||||||
def __init__(self):
|
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("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")
|
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):
|
def write_csr_file(soc, filename):
|
||||||
with open(filename, "w") as f:
|
with open(filename, "w") as f:
|
||||||
|
|
Loading…
Reference in New Issue