forked from M-Labs/artiq-zynq
Compare commits
4 Commits
63112919a3
...
ef5b06b187
Author | SHA1 | Date |
---|---|---|
morgan | ef5b06b187 | |
morgan | cbd3058c83 | |
morgan | 0969a62aee | |
morgan | b370ec00ea |
|
@ -165,11 +165,6 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
]
|
||||
|
||||
|
||||
# DEBUG: tx loopback fifo control
|
||||
self.tx_stb = CSRStorage()
|
||||
self.sync += phy.tx_stb_sys.eq(self.tx_stb.storage)
|
||||
|
||||
|
||||
# DEBUG: Transmission Pipeline
|
||||
#
|
||||
# rtio pak ----+
|
||||
|
@ -183,20 +178,14 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
|
||||
# DEBUG: TX pipeline
|
||||
self.submodules.bootstrap_loopback = bootstrap_loopback = TX_Bootstrap()
|
||||
self.submodules.mux = mux = stream.Multiplexer(word_layout, 2)
|
||||
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper()
|
||||
self.submodules.trig_ack = trig_ack = Trigger_ACK_Inserter()
|
||||
|
||||
self.ack = CSR()
|
||||
self.mux_sel = CSRStorage()
|
||||
|
||||
self.sync += trig_ack.stb.eq(self.ack.re),
|
||||
self.comb += [
|
||||
bootstrap_loopback.source.connect(mux.sink0),
|
||||
mux.sel.eq(self.mux_sel.storage),
|
||||
]
|
||||
|
||||
tx_pipeline = [mux , pak_wrp, trig_ack, phy]
|
||||
tx_pipeline = [bootstrap_loopback, pak_wrp, trig_ack, phy]
|
||||
for s, d in zip(tx_pipeline, tx_pipeline[1:]):
|
||||
self.comb += s.source.connect(d.sink)
|
||||
|
||||
|
@ -205,17 +194,20 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
|
||||
# Receiver Pipeline WIP
|
||||
#
|
||||
# 32 32
|
||||
# PHY ---/---> CDC FIFO ---/---> trigger ack ------> packet ------> debug buffer
|
||||
# checker decoder
|
||||
# 32 32+8(dchar)
|
||||
# PHY ---/---> dchar -----/-----> trigger ack ------> packet ------> CDC FIFO ------> debug buffer
|
||||
# decoder checker decoder
|
||||
#
|
||||
cdr = ClockDomainsRenamer("cxp_gtx_rx")
|
||||
|
||||
# decode all incoming data as duplicate char and inject the result into the bus for downstream modules
|
||||
self.submodules.dchar_decoder = dchar_decoder = cdr(Duplicated_Char_Decoder())
|
||||
|
||||
# Priority level 1 packet - Trigger ack packet
|
||||
self.submodules.trig_ack_checker = trig_ack_checker = cdr(CXP_Trig_Ack_Checker())
|
||||
self.submodules.trig_ack_checker = trig_ack_checker = cdr(Trigger_Ack_Checker())
|
||||
|
||||
self.submodules.trig_ack_ps = trig_ack_ps = PulseSynchronizer("cxp_gtx_rx", "sys")
|
||||
self.comb += trig_ack_ps.i.eq(trig_ack_checker.ack)
|
||||
self.sync.cxp_gtx_rx += trig_ack_ps.i.eq(trig_ack_checker.ack)
|
||||
|
||||
self.trig_ack = Signal()
|
||||
self.trig_clr = Signal()
|
||||
|
@ -239,7 +231,7 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
test_err_ps = PulseSynchronizer("cxp_gtx_rx", "sys")
|
||||
buffer_err_ps = PulseSynchronizer("cxp_gtx_rx", "sys")
|
||||
self.submodules += decode_err_ps, test_err_ps, buffer_err_ps
|
||||
self.comb += [
|
||||
self.sync.cxp_gtx_rx += [
|
||||
decode_err_ps.i.eq(bootstrap.decode_err),
|
||||
test_err_ps.i.eq(bootstrap.test_err),
|
||||
buffer_err_ps.i.eq(bootstrap.buffer_err),
|
||||
|
@ -282,23 +274,11 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
]
|
||||
|
||||
|
||||
# DEBUG: remove this cdc fifo
|
||||
cdc_fifo = stream.AsyncFIFO(word_layout, 512)
|
||||
cdc_fifo = stream.AsyncFIFO(word_layout_dchar, 512)
|
||||
self.submodules += ClockDomainsRenamer({"write": "cxp_gtx_rx", "read": "sys"})(cdc_fifo)
|
||||
self.submodules.debug_out = debug_out = RX_Debug_Buffer()
|
||||
|
||||
self.dmux_sel = CSRStorage()
|
||||
self.submodules.dmux = dmux = stream.Demultiplexer(word_layout, 2)
|
||||
|
||||
|
||||
self.comb += [
|
||||
dmux.source0.connect(bootstrap.sink),
|
||||
dmux.source1.connect(cdc_fifo.sink),
|
||||
cdc_fifo.source.connect(debug_out.sink),
|
||||
dmux.sel.eq(self.dmux_sel.storage),
|
||||
]
|
||||
|
||||
rx_pipeline = [phy, trig_ack_checker, dmux]
|
||||
rx_pipeline = [phy, dchar_decoder, trig_ack_checker, bootstrap, cdc_fifo, debug_out]
|
||||
for s, d in zip(rx_pipeline, rx_pipeline[1:]):
|
||||
self.comb += s.source.connect(d.sink)
|
||||
|
||||
|
@ -319,8 +299,8 @@ class DownConn_Interface(Module, AutoCSR):
|
|||
# Instance("OBUF", i_I=phy.gtx.cd_cxp_gtx_rx.clk, o_O=debug_sma.p_tx),
|
||||
# Instance("OBUF", i_I=, o_O=debug_sma.p_rx),
|
||||
# # pmod 0-7 pin
|
||||
Instance("OBUF", i_I=bootstrap.test_err, o_O=pmod_pads[0]),
|
||||
Instance("OBUF", i_I=pak_start, o_O=pmod_pads[1]),
|
||||
# Instance("OBUF", i_I=bootstrap.test_err, o_O=pmod_pads[0]),
|
||||
# Instance("OBUF", i_I=pak_start, o_O=pmod_pads[1]),
|
||||
# Instance("OBUF", i_I=fifo_in.source.ack, o_O=pmod_pads[2]),
|
||||
# Instance("OBUF", i_I=gtx.comma_checker.aligner_en, o_O=pmod_pads[3]),
|
||||
# Instance("OBUF", i_I=gtx.comma_checker.check_reset, o_O=pmod_pads[4]),
|
||||
|
|
|
@ -56,9 +56,12 @@ class Receiver(Module):
|
|||
|
||||
self.source = stream.Endpoint(word_layout)
|
||||
|
||||
data_valid = Signal()
|
||||
self.sync.cxp_gtx_rx += [
|
||||
data_valid.eq(gtx.comma_checker.rxfsm.ongoing("READY")),
|
||||
|
||||
self.source.stb.eq(0),
|
||||
If(gtx.rx_ready & self.source.ack & ~((gtx.decoders[0].d == 0xBC) & (gtx.decoders[0].k == 1)),
|
||||
If(data_valid & self.source.ack & ~((gtx.decoders[0].d == 0xBC) & (gtx.decoders[0].k == 1)),
|
||||
self.source.stb.eq(1),
|
||||
self.source.data.eq(Cat(gtx.decoders[i].d for i in range(4))),
|
||||
self.source.k.eq(Cat(gtx.decoders[i].k for i in range(4))),
|
||||
|
@ -66,17 +69,22 @@ class Receiver(Module):
|
|||
]
|
||||
|
||||
# DEBUG: tx fifos for loopback
|
||||
# fw -> fifo (sys) -> cdc fifo -> gtx tx
|
||||
# fw -> -> cdc fifo -> buffered fifo -> gtx tx
|
||||
|
||||
tx_fifo = stream.AsyncFIFO(word_layout, 512)
|
||||
self.submodules += ClockDomainsRenamer({"write": "sys", "read": "cxp_gtx_tx"})(tx_fifo)
|
||||
self.sink = tx_fifo.sink
|
||||
cdc_fifo = stream.AsyncFIFO(word_layout, 512)
|
||||
self.submodules += ClockDomainsRenamer({"write": "sys", "read": "cxp_gtx_tx"})(cdc_fifo)
|
||||
self.sink = cdc_fifo.sink
|
||||
|
||||
self.tx_stb_sys = Signal()
|
||||
txstb = Signal()
|
||||
self.specials += MultiReg(self.tx_stb_sys, txstb, odomain="cxp_gtx_tx")
|
||||
# fix timing violation
|
||||
cdr = ClockDomainsRenamer("cxp_gtx_tx")
|
||||
self.submodules.buf = tx_fifo = cdr(stream.SyncFIFO(word_layout, 2, buffered=True))
|
||||
|
||||
word_count = Signal(max=100)
|
||||
self.comb += [
|
||||
cdc_fifo.source.connect(tx_fifo.sink),
|
||||
]
|
||||
|
||||
idle_period = 50 # press in word
|
||||
word_count = Signal(max=idle_period)
|
||||
|
||||
# JANK: fix the every 98th word got eaten
|
||||
# cnt 97 98 99 0
|
||||
|
@ -85,11 +93,11 @@ class Receiver(Module):
|
|||
self.sync.cxp_gtx_tx += [
|
||||
tx_fifo.source.ack.eq(0),
|
||||
|
||||
If(word_count == 99,
|
||||
If(word_count == idle_period-1,
|
||||
word_count.eq(word_count.reset),
|
||||
).Else(
|
||||
If(tx_fifo.source.stb & txstb,
|
||||
If(word_count != 98, tx_fifo.source.ack.eq(1)),
|
||||
If(tx_fifo.source.stb,
|
||||
If(word_count != idle_period-2, tx_fifo.source.ack.eq(1)),
|
||||
word_count.eq(word_count + 1),
|
||||
)
|
||||
)
|
||||
|
@ -97,7 +105,7 @@ class Receiver(Module):
|
|||
|
||||
# NOTE: prevent the first word send twice due to stream stb delay
|
||||
self.comb += [
|
||||
If((tx_fifo.source.stb & tx_fifo.source.ack & (word_count != 99)),
|
||||
If((tx_fifo.source.stb & tx_fifo.source.ack & (word_count != idle_period-1)),
|
||||
gtx.encoder.d[0].eq(tx_fifo.source.data[:8]),
|
||||
gtx.encoder.d[1].eq(tx_fifo.source.data[8:16]),
|
||||
gtx.encoder.d[2].eq(tx_fifo.source.data[16:24]),
|
||||
|
|
|
@ -4,12 +4,23 @@ from misoc.interconnect.csr import *
|
|||
from misoc.interconnect import stream
|
||||
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCChecker
|
||||
|
||||
from functools import reduce
|
||||
from itertools import combinations
|
||||
from operator import or_, and_
|
||||
|
||||
char_width = 8
|
||||
char_layout = [("data", char_width), ("k", char_width//8)]
|
||||
|
||||
word_dw = 32
|
||||
word_layout = [("data", word_dw), ("k", word_dw//8)]
|
||||
|
||||
word_layout_dchar = [
|
||||
("data", word_dw),
|
||||
("k", word_dw//8),
|
||||
("dchar", char_width),
|
||||
("dchar_k", char_width//8)
|
||||
]
|
||||
|
||||
buffer_count = 4
|
||||
buffer_depth = 512
|
||||
|
||||
|
@ -261,7 +272,7 @@ class TX_Bootstrap(Module, AutoCSR):
|
|||
|
||||
class RX_Debug_Buffer(Module,AutoCSR):
|
||||
def __init__(self):
|
||||
self.submodules.buf_out = buf_out = stream.SyncFIFO(word_layout, 128)
|
||||
self.submodules.buf_out = buf_out = stream.SyncFIFO(word_layout_dchar, 128)
|
||||
self.sink = buf_out.sink
|
||||
|
||||
self.inc = CSR()
|
||||
|
@ -277,21 +288,64 @@ class RX_Debug_Buffer(Module,AutoCSR):
|
|||
self.dout_valid.status.eq(buf_out.source.stb),
|
||||
]
|
||||
|
||||
class Duplicate_Majority_Voter(Module):
|
||||
def __init__(self, char_4x, k_4x):
|
||||
assert char_4x.nbits == 32
|
||||
assert k_4x.nbits == 4
|
||||
class Duplicated_Char_Decoder(Module):
|
||||
def __init__(self):
|
||||
self.sink = stream.Endpoint(word_layout)
|
||||
self.buffer = stream.Endpoint(word_layout)
|
||||
self.source = stream.Endpoint(word_layout_dchar)
|
||||
|
||||
# Section 9.2.2.1 (CXP-001-2021)
|
||||
# decoder should immune to single bit errors when handling duplicated characters
|
||||
self.char = Signal(char_width)
|
||||
self.k = Signal()
|
||||
# # #
|
||||
|
||||
a, b, c, d = [char_4x[i*8:(i+1)*8] for i in range(4)]
|
||||
a_k, b_k, c_k, d_k = [k_4x[i:(i+1)] for i in range(4)]
|
||||
self.comb += [
|
||||
self.char.eq(a&b&c | a&b&d | a&c&d | b&c&d),
|
||||
self.k.eq(a_k&b_k&c_k | a_k&b_k&d_k | a_k&c_k&d_k | b_k&c_k&d_k),
|
||||
|
||||
# For duplicated characters, an error correction method (e.g. majority voting) is required to meet the CXP spec:
|
||||
# RX decoder should immune to single bit errors when handling duplicated characters - Section 9.2.2.1 (CXP-001-2021)
|
||||
#
|
||||
#
|
||||
# 32
|
||||
# +---> buffer -----/-----+
|
||||
# 32 | | 32+8(dchar)
|
||||
# sink ---/---+ ---> source -----/-----> downstream
|
||||
# | 8(dchar) | decoders
|
||||
# +---> majority -----/-----+
|
||||
# voting
|
||||
#
|
||||
#
|
||||
# Due to the tight setup/hold time requiremnt for 12.5Gbps CXP, the voting logic cannot be implemented as combinational logic
|
||||
# Hence, a pipeline approach is needed to avoid any s/h violation, where the majority voting result are pre-calculate and injected into the bus immediate after the PHY.
|
||||
# And any downstream modules can access the voting result without implementing the voting logic inside the decoder
|
||||
|
||||
self.sync += [
|
||||
self.sink.ack.eq(self.buffer.ack),
|
||||
self.buffer.stb.eq(self.sink.stb),
|
||||
If(self.sink.stb,
|
||||
self.buffer.data.eq(self.sink.data),
|
||||
self.buffer.k.eq(self.sink.k),
|
||||
),
|
||||
]
|
||||
|
||||
# cycle 1 - calculate ABC, ABD, ACD & BCD
|
||||
char = [[self.sink.data[i*8:(i+1)*8], self.sink.k[i]] for i in range(4)]
|
||||
voters = [Record([("data", 8), ("k", 1)]) for _ in range(4)]
|
||||
|
||||
for i, comb in enumerate(combinations(char, 3)):
|
||||
self.sync += [
|
||||
If(self.sink.stb,
|
||||
voters[i].data.eq(reduce(and_, [code[0] for code in comb])),
|
||||
voters[i].k.eq(reduce(and_, [code[1] for code in comb])),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
# cycle 2 - inject the voting result
|
||||
self.sync += [
|
||||
self.buffer.ack.eq(self.source.ack),
|
||||
self.source.stb.eq(self.buffer.stb),
|
||||
If(self.buffer.stb,
|
||||
self.source.data.eq(self.buffer.data),
|
||||
self.source.k.eq(self.buffer.k),
|
||||
self.source.dchar.eq(Replicate(reduce(or_, [v.data for v in voters]), 4)),
|
||||
self.source.dchar_k.eq(Replicate(reduce(or_, [v.k for v in voters]), 4)),
|
||||
),
|
||||
]
|
||||
|
||||
@FullMemoryWE()
|
||||
|
@ -314,15 +368,14 @@ class RX_Bootstrap(Module):
|
|||
"heartbeat": 0x09,
|
||||
}
|
||||
|
||||
self.sink = stream.Endpoint(word_layout)
|
||||
self.source = stream.Endpoint(word_layout)
|
||||
self.sink = stream.Endpoint(word_layout_dchar)
|
||||
self.source = stream.Endpoint(word_layout_dchar)
|
||||
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
self.submodules.voter = voter = Duplicate_Majority_Voter(self.sink.data, self.sink.k)
|
||||
|
||||
fsm.act("IDLE",
|
||||
self.sink.ack.eq(1),
|
||||
If((self.sink.stb & (voter.char == KCode["pak_start"]) & (voter.k == 1)),
|
||||
If((self.sink.stb & (self.sink.dchar == KCode["pak_start"]) & (self.sink.dchar_k == 1)),
|
||||
NextState("DECODE"),
|
||||
)
|
||||
)
|
||||
|
@ -333,9 +386,9 @@ class RX_Bootstrap(Module):
|
|||
fsm.act("DECODE",
|
||||
self.sink.ack.eq(1),
|
||||
If(self.sink.stb,
|
||||
NextValue(self.packet_type, voter.char),
|
||||
NextValue(self.packet_type, self.sink.dchar),
|
||||
|
||||
Case(voter.char, {
|
||||
Case(self.sink.dchar, {
|
||||
type["data_stream"]: NextState("STREAMING"),
|
||||
type["test_packet"]: [
|
||||
NextValue(cnt, cnt.reset),
|
||||
|
@ -363,7 +416,7 @@ class RX_Bootstrap(Module):
|
|||
)
|
||||
# For stream data packet
|
||||
fsm.act("STREAMING",
|
||||
If((self.sink.stb & (voter.char == KCode["pak_end"]) & (voter.k == 1)),
|
||||
If((self.sink.stb & (self.sink.dchar == KCode["pak_end"]) & (self.sink.dchar_k == 1)),
|
||||
# discard K29,7
|
||||
self.sink.ack.eq(1),
|
||||
NextState("IDLE")
|
||||
|
@ -378,7 +431,7 @@ class RX_Bootstrap(Module):
|
|||
fsm.act("VERIFY_TEST_PATTERN",
|
||||
self.sink.ack.eq(1),
|
||||
If(self.sink.stb,
|
||||
If(((voter.char == KCode["pak_end"]) & (voter.k == 1)),
|
||||
If(((self.sink.dchar == KCode["pak_end"]) & (self.sink.dchar_k == 1)),
|
||||
NextState("IDLE"),
|
||||
).Else(
|
||||
If(((self.sink.data != Cat(cnt, cnt+1, cnt+2, cnt+3))),
|
||||
|
@ -405,7 +458,6 @@ class RX_Bootstrap(Module):
|
|||
self.comb += [
|
||||
mem_port.adr[:addr_nbits].eq(addr),
|
||||
mem_port.adr[addr_nbits:].eq(write_ptr),
|
||||
mem_port.dat_w.eq(self.sink.data),
|
||||
]
|
||||
|
||||
# For control ack, event packet
|
||||
|
@ -413,10 +465,11 @@ class RX_Bootstrap(Module):
|
|||
mem_port.we.eq(0),
|
||||
self.sink.ack.eq(1),
|
||||
If(self.sink.stb,
|
||||
If(((voter.char == KCode["pak_end"]) & (voter.k == 1)),
|
||||
If(((self.sink.dchar == KCode["pak_end"]) & (self.sink.dchar_k == 1)),
|
||||
NextState("MOVE_BUFFER_PTR"),
|
||||
).Else(
|
||||
mem_port.we.eq(1),
|
||||
mem_port.dat_w.eq(self.sink.data),
|
||||
NextValue(addr, addr + 1),
|
||||
If(addr == buffer_depth - 1,
|
||||
# discard the packet
|
||||
|
@ -439,10 +492,10 @@ class RX_Bootstrap(Module):
|
|||
NextState("IDLE"),
|
||||
)
|
||||
|
||||
class CXP_Trig_Ack_Checker(Module, AutoCSR):
|
||||
class Trigger_Ack_Checker(Module, AutoCSR):
|
||||
def __init__(self):
|
||||
self.sink = stream.Endpoint(word_layout)
|
||||
self.source = stream.Endpoint(word_layout)
|
||||
self.sink = stream.Endpoint(word_layout_dchar)
|
||||
self.source = stream.Endpoint(word_layout_dchar)
|
||||
|
||||
self.ack = Signal()
|
||||
|
||||
|
@ -450,10 +503,8 @@ class CXP_Trig_Ack_Checker(Module, AutoCSR):
|
|||
|
||||
self.submodules.fsm = fsm = FSM(reset_state="COPY")
|
||||
|
||||
self.submodules.voter = voter = Duplicate_Majority_Voter(self.sink.data, self.sink.k)
|
||||
|
||||
fsm.act("COPY",
|
||||
If((self.sink.stb & (voter.char == KCode["io_ack"]) & (voter.k == 1)),
|
||||
If((self.sink.stb & (self.sink.dchar == KCode["io_ack"]) & (self.sink.dchar_k == 1)),
|
||||
# discard K28,6
|
||||
self.sink.ack.eq(1),
|
||||
NextState("CHECK_ACK")
|
||||
|
@ -467,7 +518,7 @@ class CXP_Trig_Ack_Checker(Module, AutoCSR):
|
|||
NextState("COPY"),
|
||||
# discard the word after K28,6
|
||||
self.sink.ack.eq(1),
|
||||
If((voter.char == 0x01) & (voter.k == 0),
|
||||
If((self.sink.dchar == 0x01) & (self.sink.dchar_k == 0),
|
||||
self.ack.eq(1),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -24,9 +24,9 @@ pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: cxp_phys
|
|||
while (CXP[channel].downconn_rx_ready_read)() != 1 {}
|
||||
info!("rx ready!");
|
||||
|
||||
(CXP[channel].downconn_tx_stb_write)(1);
|
||||
cxp_proto::downconn_send_test_packet(channel);
|
||||
|
||||
// FIXME: why test + trig ack doesn't work well for rx??
|
||||
cxp_proto::downconn_debug_send_trig_ack(channel);
|
||||
|
||||
const DATA_MAXSIZE: usize = 253;
|
||||
|
@ -51,17 +51,22 @@ pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: cxp_phys
|
|||
.expect("loopback gtx tx error");
|
||||
|
||||
timer.delay_us(1000); // wait packet has arrive at RX async fifo
|
||||
(CXP[channel].downconn_tx_stb_write)(0);
|
||||
|
||||
info!("trig ack = {}", (CXP[channel].downconn_trigger_ack_read)());
|
||||
if (CXP[channel].downconn_trigger_ack_read)() == 1 {
|
||||
(CXP[channel].downconn_trigger_ack_write)(1);
|
||||
info!("after clr trig ack = {}", (CXP[channel].downconn_trigger_ack_read)());
|
||||
info!("trig ack and cleared");
|
||||
}
|
||||
|
||||
if (CXP[channel].downconn_bootstrap_decoder_err_read)() == 1 {
|
||||
info!("!!!!!!!DECODER ERROR!!!!!!! and cleared");
|
||||
(CXP[channel].downconn_bootstrap_decoder_err_write)(1);
|
||||
}
|
||||
|
||||
if (CXP[channel].downconn_bootstrap_test_err_read)() == 1 {
|
||||
info!("!!!!!!!TEST ERROR!!!!!!! and cleared");
|
||||
(CXP[channel].downconn_bootstrap_test_err_write)(1);
|
||||
}
|
||||
|
||||
info!(
|
||||
"decoder error = {}",
|
||||
(CXP[channel].downconn_bootstrap_decoder_err_read)()
|
||||
);
|
||||
info!("test error = {}", (CXP[channel].downconn_bootstrap_test_err_read)());
|
||||
info!("packet type = {:#06X}", (CXP[channel].downconn_packet_type_read)());
|
||||
|
||||
cxp_proto::receive(channel).expect("loopback gtx rx error");
|
||||
|
@ -82,6 +87,8 @@ pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: cxp_phys
|
|||
break;
|
||||
}
|
||||
}
|
||||
cxp_proto::print_packetu32(&pak_arr, &k_arr);
|
||||
|
||||
info!("rx ready = {}", (CXP[channel].downconn_rx_ready_read)());
|
||||
// cxp_proto::print_packetu32(&pak_arr, &k_arr);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue