ADC DMA complete, not working for obscure reason

This commit is contained in:
Sebastien Bourdeauducq 2020-10-25 18:58:33 +08:00
parent 461c722975
commit bf13e9f7c3
3 changed files with 123 additions and 25 deletions

View File

@ -93,7 +93,8 @@ pub fn main_core0() {
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());
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]);

View File

@ -1,32 +1,34 @@
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):
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.base_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
self.length = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
self.start = Signal()
self.busy = Signal()
current_address = Signal(aligned_address_width)
remaining = Signal(aligned_address_width)
current_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
remaining = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
self.comb += [
membus_stream.addr.eq(Cat(C(0, alignment_bits), current_address)),
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(data_width//8)), # Width of burst: 3 = 8 bytes = 64 bits.
membus_stream.size.eq(log2_int(AXI_DATA_WIDTH//8)), # Width of burst: 3 = 8 bytes = 64 bits.
membus_stream.cache.eq(0xf),
]
@ -52,16 +54,80 @@ class BlockAddressGenerator(Module):
)
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, data_width, pads):
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(1),
#self.sink.ack.eq(membus.w.ready),
membus_stream.data.eq(0x12345678deadbeef),
membus_stream.strb.eq(2**(data_width//8)-1),
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 += [
@ -76,20 +142,25 @@ class ADCWriter(Module):
)
]
# 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):
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.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, data_width)
address_generator = BlockAddressGenerator(membus.aw, AXI_DATA_WIDTH)
self.submodules += address_generator
self.comb += [
address_generator.base_address.eq(self.base_address.storage),
@ -97,8 +168,16 @@ class ADC(Module, AutoCSR):
address_generator.start.eq(self.start.re)
]
adc_writer = ADCWriter(membus.w, data_width, pads)
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)

View File

@ -5,6 +5,7 @@ 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
@ -24,8 +25,25 @@ 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")