I'm trying to get MIPI CSI working on the Crosslinknx evaluation board. Unfortunately, I don't see anything on the byte clock - 'freq' returns 0 Hz and the data / packets are all empty. I had a similar setup (I2C + CSI, no soft core) written in Verilog and built on Radiant with the same issue. Here are the changes I've made to your original project:
Other than this I also made some changes to the Makefile and C source to make it compatible with the new litex setup. I can push it to a new branch if that's useful. Unfortunately, I don't have a VIP board to test it, so I didn't make a PR.
As shown below I tried different combinations of constraints, but no success. Also for some reason, the project doesn't work when built with radiant (led chaser stuck with all LEDs on, no BIOS on UART), but that's probably a separate issue. I would appreciate any ideas or inputs about how I can go forward with this. Was it working at the time of publishing this? If yes, could you send me the versions so I can try to replicate it?
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2020 David Corrigan <[email protected]>
# Copyright (c) 2020 Alan Green <[email protected]>
# Copyright (c) 2020-21 gatecat <[email protected]>
#
# SPDX-License-Identifier: BSD-2-Clause
from migen import *
from litex_boards.platforms import lattice_crosslink_nx_evn
from litex_boards.targets.lattice_crosslink_nx_evn import _CRG
from litex.build.io import CRG
from litex.soc.cores.ram import NXLRAM
from litex.build.generic_platform import *
from litex.soc.interconnect import wishbone
from litex.soc.cores.clock import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.integration.soc import SoCRegion
from litex.soc.cores.led import LedChaser
from litex.soc.cores.bitbang import I2CMaster
from litex.soc.cores.freqmeter import FreqMeter
from litex.soc.cores.gpio import GPIOIn
from litex.build.lattice.oxide import oxide_args, oxide_argdict
from dphy_wrapper import DPHY_CSIRX_CIL
from mipi_csi import *
kB = 1024
mB = 1024*kB
camera = [
("camera", 0,
# Subsignal("clkp", Pins("X")),
# Subsignal("clkn", Pins("X")),
# Subsignal("dp", Pins("X X X X")),
# Subsignal("dn", Pins("X X X X"))
Subsignal("clkp", Pins("DPHY0")),
Subsignal("clkn", Pins("DPHY0")),
# Subsignal("dp", Pins("B2 A3 C2 A4"), IOStandard("MIPI_DPHY")),
# Subsignal("dn", Pins("C1 B3 D1 B4"), IOStandard("LVCMOS12H"))
Subsignal("dp", Pins("DPHY0 DPHY0 DPHY0 DPHY0")),
Subsignal("dn", Pins("DPHY0 DPHY0 DPHY0 DPHY0"))
),
("camera_i2c", 0,
Subsignal("scl", Pins("Y5")),
Subsignal("sda", Pins("W5")),
IOStandard("LVCMOS18H")
),
("camera_reset", 0, Pins("W18"), IOStandard("LVCMOS18H")),
]
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
SoCCore.mem_map = {
"rom": 0x00000000,
"sram": 0x40000000,
"main_ram": 0x50000000,
"csr": 0xf0000000,
}
def __init__(self, sys_clk_freq=int(75e6), hyperram="none", toolchain="radiant", **kwargs):
platform = lattice_crosslink_nx_evn.Platform(device="LIFCL-40-9BG400C", toolchain=toolchain)
# CRG --------------------------------------------------------------------------------------
self.crg = _CRG(platform, sys_clk_freq)
# SoCCore -----------------------------------------_----------------------------------------
# Disable Integrated SRAM since we want to instantiate LRAM specifically for it
kwargs["integrated_sram_size"] = 0
# Make serial_pmods available
platform.add_extension(lattice_crosslink_nx_evn.serial_pmods)
# Set uart output to pmod0
kwargs["uart_name"] = "serial_pmod0"
platform.add_extension(camera)
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Crosslink-NX Evaluation Board", **kwargs)
# 128KB LRAM (used as SRAM and main RAM) ---------------------------------------------
self.spram = NXLRAM(32, 64*kB)
self.bus.add_slave("sram", self.spram.bus, SoCRegion(origin=self.mem_map["sram"], size=64*kB))
self.main_ram = NXLRAM(32, 64*kB)
self.bus.add_slave("main_ram", self.main_ram.bus, SoCRegion(origin=self.mem_map["main_ram"], size=64*kB))
# Leds -------------------------------------------------------------------------------------
self.leds = LedChaser(
pads = Cat(*[platform.request("user_led", i) for i in range(14)]),
sys_clk_freq = sys_clk_freq)
self.submodules.i2c = I2CMaster(platform.request("camera_i2c", 0))
self.add_csr("i2c")
self.submodules.dphy = DPHY_CSIRX_CIL(
pads = platform.request("camera", 0),
num_lanes = 4,
clk_mode = "ENABLED",
deskew = "DISABLED",
gearing = 8,
loc = "TDPHY_CORE2",
)
cam_rst = platform.request("camera_reset", 0)
self.comb += cam_rst.eq(ResetSignal())
self.comb += [
self.dphy.sync_clk.eq(ClockSignal()),
self.dphy.sync_rst.eq(ResetSignal()),
self.dphy.pd_dphy.eq(0),
self.dphy.hs_rx_en.eq(1),
]
self.submodules.clk_byte_freq = FreqMeter(period=int(sys_clk_freq), clk=self.dphy.clk_byte)
self.add_csr("clk_byte_freq")
self.submodules.hs_rx_data = GPIOIn(pads=self.dphy.hs_rx_data)
self.add_csr("hs_rx_data")
self.submodules.hs_rx_sync = GPIOIn(pads=self.dphy.hs_rx_sync)
self.add_csr("hs_rx_sync")
self.clock_domains.cd_mipi = ClockDomain()
self.comb += self.cd_mipi.clk.eq(self.dphy.clk_byte)
dphy_header = Signal(32)
for i in range(0, 4):
prev_sync = Signal()
self.sync.mipi += prev_sync.eq(self.dphy.hs_rx_sync[i])
self.sync.mipi += If(prev_sync, dphy_header[(8*i):(8*(i+1))].eq(self.dphy.hs_rx_data[(8*i):(8*(i+1))]))
self.submodules.dphy_header = GPIOIn(pads=dphy_header)
self.add_csr("dphy_header")
wa = WordAligner(lane_width=8, num_lanes=4, depth=3)
swapped_data = Cat(self.dphy.hs_rx_data[24:32], self.dphy.hs_rx_data[8:16], self.dphy.hs_rx_data[16:24], self.dphy.hs_rx_data[0:8])
self.sync.mipi += [
wa.data_in.eq(swapped_data),
wa.sync_in.eq(self.dphy.hs_rx_sync)
]
self.submodules.wa = wa
packet_cap = PacketCapture(data=wa.data_out, data_sync=wa.sync_out, depth=128)
self.submodules.packet_cap = packet_cap
packet_io = wishbone.SRAM(self.packet_cap.mem, read_only=True)
self.submodules.packet_io = packet_io
self.bus.add_slave("packet_io", packet_io.bus, SoCRegion(origin=0xb0000000, size=0x4000, cached=False, mode="r"))
# ----------------------------------------------------------------
image_cap = ImageCapture(data=wa.data_out, data_sync=wa.sync_out, subsample_x=10, subsample_y=32, out_width=60, out_height=33)
self.submodules.image_cap = image_cap
image_io = wishbone.SRAM(self.image_cap.mem, read_only=True)
self.submodules.image_io = image_io
self.bus.add_slave("image_io", image_io.bus, SoCRegion(origin=0xb0010000, size=0x4000, cached=False, mode="r"))
# self.add_uartbone(uart_name="serial")
# Build --------------------------------------------------------------------------------------------
def main():
from litex.build.parser import LiteXArgumentParser
parser = LiteXArgumentParser(platform=lattice_crosslink_nx_evn.Platform, description="LiteX SoC on Crosslink-NX Eval Board.")
parser.add_target_argument("--device", default="LIFCL-40-9BG400C", help="FPGA device (LIFCL-40-9BG400C, LIFCL-40-8BG400CES, or LIFCL-40-8BG400CES2).")
parser.add_target_argument("--sys-clk-freq", default=75e6, type=float, help="System clock frequency.")
parser.add_target_argument("--serial", default="serial", help="UART Pins (serial (requires R15 and R17 to be soldered) or serial_pmod[0-2]).")
parser.add_target_argument("--programmer", default="radiant", help="Programmer (radiant or ecpprog or openocd).")
parser.add_target_argument("--address", default=0x0, help="Flash address to program bitstream at.")
parser.add_target_argument("--prog-target", default="direct", help="Programming Target (direct or flash).")
parser.add_target_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).")
parser.add_target_argument("--with-uartbone", action="store_true", help="Add UartBone on 1st serial.")
args = parser.parse_args()
soc = BaseSoC(
sys_clk_freq = `args.sys_clk_freq,`
device = args.device,
toolchain = args.toolchain,
with_spi_flash = args.with_spi_flash,
with_uartbone = args.with_uartbone,
**parser.soc_argdict
)
builder = Builder(soc, **parser.builder_argdict)
if args.build:
builder.build(**parser.toolchain_argdict)
if __name__ == "__main__":
main()