Compare commits
3 Commits
e6bad44e83
...
bf13e9f7c3
Author | SHA1 | Date |
---|---|---|
Sebastien Bourdeauducq | bf13e9f7c3 | |
Sebastien Bourdeauducq | 461c722975 | |
Sebastien Bourdeauducq | 2c588992c5 |
|
@ -33,7 +33,7 @@ checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"
|
|||
[[package]]
|
||||
name = "core_io"
|
||||
version = "0.1.20200410"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -75,7 +75,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libboard_zynq"
|
||||
version = "0.0.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"embedded-hal",
|
||||
|
@ -91,7 +91,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libconfig"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"core_io",
|
||||
"fatfs",
|
||||
|
@ -102,7 +102,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libcortex_a9"
|
||||
version = "0.0.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"libregister",
|
||||
|
@ -112,7 +112,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libregister"
|
||||
version = "0.0.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"vcell",
|
||||
|
@ -122,7 +122,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libsupport_zynq"
|
||||
version = "0.0.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#80d12d57802b9b78aa45b821a147f71444d401f0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#22833ef0c6ff705130c9c7e39c83103b5b6a1c12"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libboard_zynq",
|
||||
|
|
|
@ -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,25 @@ 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={}, overflow={}",
|
||||
pl::csr::adc::bus_error_read(), pl::csr::adc::overflow_read());
|
||||
cache::dcci_slice(&BUFFER.data);
|
||||
for i in 0..BUFFER_SIZE {
|
||||
info!("{:02x}", BUFFER.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
asm::wfe();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
from migen import *
|
||||
from migen.genlib.fsm import FSM
|
||||
from migen.genlib.fifo import AsyncFIFOBuffered
|
||||
from migen.genlib.cdc import MultiReg, PulseSynchronizer
|
||||
from migen_axi.interconnect import axi
|
||||
from misoc.interconnect.csr import *
|
||||
|
||||
|
||||
AXI_ADDRESS_WIDTH = 32
|
||||
AXI_DATA_WIDTH = 64
|
||||
AXI_BURST_LEN = 16
|
||||
AXI_ALIGNMENT_BITS = log2_int(AXI_BURST_LEN*AXI_DATA_WIDTH//8)
|
||||
AXI_ALIGNED_ADDRESS_WIDTH = AXI_ADDRESS_WIDTH - AXI_ALIGNMENT_BITS
|
||||
|
||||
|
||||
class BlockAddressGenerator(Module):
|
||||
def __init__(self, membus_stream, data_width):
|
||||
self.base_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
||||
self.length = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
||||
self.start = Signal()
|
||||
self.busy = Signal()
|
||||
|
||||
current_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
||||
remaining = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
||||
|
||||
self.comb += [
|
||||
membus_stream.addr.eq(Cat(C(0, AXI_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(AXI_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")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def convert_signal_endianness(signal):
|
||||
assert len(signal) % 8 == 0
|
||||
nbytes = len(signal)//8
|
||||
signal_bytes = []
|
||||
for i in range(nbytes):
|
||||
signal_bytes.append(signal[8*i:8*(i+1)])
|
||||
return Cat(*reversed(signal_bytes))
|
||||
|
||||
|
||||
class ADCWriter(Module):
|
||||
def __init__(self, membus_stream, pads):
|
||||
self.length = Signal(AXI_ALIGNED_ADDRESS_WIDTH) # in AXI bursts
|
||||
self.start = Signal()
|
||||
self.overflow = Signal()
|
||||
self.busy = Signal()
|
||||
|
||||
fifo = ClockDomainsRenamer({"write": "adc", "read": "sys"})(AsyncFIFOBuffered(64, 512))
|
||||
self.submodules += fifo
|
||||
|
||||
# FIFO write
|
||||
adc_a = Signal(16)
|
||||
adc_b = Signal(16)
|
||||
self.sync.adc += [
|
||||
#adc_a.eq(pads.data_a),
|
||||
#adc_b.eq(pads.data_b),
|
||||
adc_a.eq(0x7842),
|
||||
adc_b.eq(0xdf86),
|
||||
]
|
||||
|
||||
fifo_inbuf = Signal(64)
|
||||
fifo_inbuf_sel = Signal()
|
||||
self.sync.adc += [
|
||||
fifo_inbuf_sel.eq(~fifo_inbuf_sel),
|
||||
If(fifo_inbuf_sel,
|
||||
fifo_inbuf[32:].eq(Cat(adc_a, adc_b)),
|
||||
).Else(
|
||||
fifo_inbuf[:32].eq(Cat(adc_a, adc_b)),
|
||||
)
|
||||
]
|
||||
self.comb += fifo.din.eq(fifo_inbuf),
|
||||
|
||||
length = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
||||
start = Signal()
|
||||
|
||||
assert AXI_DATA_WIDTH == len(fifo_inbuf)
|
||||
remaining = Signal(AXI_ADDRESS_WIDTH - log2_int(AXI_DATA_WIDTH//8)) # in AXI_DATA_WIDTH words
|
||||
self.sync.adc += [
|
||||
If(remaining != 0, remaining.eq(remaining - 1)),
|
||||
If(start, remaining.eq(length << log2_int(AXI_BURST_LEN))),
|
||||
]
|
||||
self.comb += fifo.we.eq((remaining != 0) & ~fifo_inbuf_sel)
|
||||
|
||||
overflow = Signal()
|
||||
self.comb += overflow.eq(fifo.we & ~fifo.writable)
|
||||
|
||||
# control CDC
|
||||
self.specials += MultiReg(self.length, length, "adc")
|
||||
ps_start = PulseSynchronizer("sys", "adc")
|
||||
ps_overflow = PulseSynchronizer("adc", "sys")
|
||||
self.submodules += ps_start, ps_overflow
|
||||
self.comb += [
|
||||
ps_start.i.eq(self.start),
|
||||
start.eq(ps_start.o),
|
||||
ps_overflow.i.eq(overflow),
|
||||
self.overflow.eq(ps_overflow.o)
|
||||
]
|
||||
|
||||
# FIFO read
|
||||
self.comb += [
|
||||
membus_stream.id.eq(0),
|
||||
membus_stream.valid.eq(fifo.readable),
|
||||
fifo.re.eq(membus_stream.ready),
|
||||
membus_stream.data.eq(convert_signal_endianness(fifo.dout)),
|
||||
membus_stream.strb.eq(2**(AXI_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)
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
# Busy generation
|
||||
remaining_sys = Signal(AXI_ADDRESS_WIDTH - log2_int(AXI_DATA_WIDTH//8))
|
||||
self.sync += [
|
||||
If(self.start, remaining_sys.eq(self.length << log2_int(AXI_BURST_LEN))),
|
||||
If(fifo.readable & fifo.re, remaining_sys.eq(remaining_sys - 1))
|
||||
]
|
||||
self.comb += self.busy.eq(remaining_sys != 0)
|
||||
|
||||
|
||||
class ADC(Module, AutoCSR):
|
||||
def __init__(self, membus, pads):
|
||||
self.base_address = CSRStorage(AXI_ADDRESS_WIDTH, alignment_bits=AXI_ALIGNMENT_BITS)
|
||||
self.length = CSRStorage(AXI_ADDRESS_WIDTH, alignment_bits=AXI_ALIGNMENT_BITS)
|
||||
self.start = CSR()
|
||||
self.busy = CSRStatus()
|
||||
self.bus_error = CSRStatus()
|
||||
self.overflow = CSRStatus()
|
||||
|
||||
address_generator = BlockAddressGenerator(membus.aw, AXI_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, pads)
|
||||
self.submodules += adc_writer
|
||||
self.comb += [
|
||||
adc_writer.length.eq(self.length.storage),
|
||||
adc_writer.start.eq(self.start.re)
|
||||
]
|
||||
self.sync += [
|
||||
If(self.start.re, self.overflow.status.eq(0)),
|
||||
If(adc_writer.overflow, self.overflow.status.eq(1))
|
||||
]
|
||||
|
||||
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))
|
||||
]
|
|
@ -5,10 +5,13 @@ from operator import itemgetter
|
|||
|
||||
from migen import *
|
||||
from migen.build.generic_platform import *
|
||||
from migen.genlib.cdc import AsyncResetSynchronizer
|
||||
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 +25,28 @@ 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 clocking
|
||||
clk125_pads = platform.request("clk125")
|
||||
platform.add_platform_command("create_clock -name clk_adc -period 8 [get_ports {port}]", port=clk125_pads.p)
|
||||
self.clock_domains.cd_adc = ClockDomain()
|
||||
self.specials += [
|
||||
Instance("IBUFGDS", i_I=clk125_pads.p, i_IB=clk125_pads.n,
|
||||
o_O=self.cd_adc.clk),
|
||||
AsyncResetSynchronizer(self.cd_adc, ResetSignal()),
|
||||
]
|
||||
adc_pads = platform.request("adc")
|
||||
self.specials += [
|
||||
Instance("ODDR", o_Q=adc_pads.clk[0], i_D1=1, i_D2=0, i_CE=1, i_C=self.cd_adc.clk),
|
||||
Instance("ODDR", o_Q=adc_pads.clk[1], i_D1=0, i_D2=1, i_CE=1, i_C=self.cd_adc.clk),
|
||||
]
|
||||
self.comb += adc_pads.cdcs.eq(1)
|
||||
for port in adc_pads.data_a, adc_pads.data_b:
|
||||
platform.add_platform_command("set_input_delay -max 3.400 -clock clk_adc [get_ports {port}[*]]", port=port)
|
||||
|
||||
# ADC DMA
|
||||
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:
|
||||
|
|
|
@ -3,6 +3,6 @@ let
|
|||
in
|
||||
pkgs.fetchgit {
|
||||
url = "https://git.m-labs.hk/M-Labs/zynq-rs.git";
|
||||
rev = "80d12d57802b9b78aa45b821a147f71444d401f0";
|
||||
sha256 = "0q91x3kvhaikgzcz1ki24y6vgx5w5w2dwjikx67z2hx5wzrp6jw0";
|
||||
rev = "22833ef0c6ff705130c9c7e39c83103b5b6a1c12";
|
||||
sha256 = "095dk8jmsqmj5822zwn34i9x08f0arqy8rhif0dxqsn1zpb4mk1l";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue