enjoy-digital / litex

Build your hardware, easily!
Other
2.81k stars 542 forks source link

Way to separate Subsignals in a Platform? #1366

Open marrrk opened 2 years ago

marrrk commented 2 years ago

Hi, I'm working with litex for my current project and I've reached a stage that requires something that I'm not sure is supported or not. The board I'm working with has the CLK pin of an iCE40UP5K connected to two separate ICs, with one being the SPIFlash, see image below:

image

Following the examples written for the FOMU and the iCEbreaker I was able to setup the rom linker region in the SPIFlash and instructed the program to be read from there. I now wish to connect another SPI core to the second IC using the same clock pin but am running into issues coming from yosys not allowing the two pins used separately as shown in the code below:

    #SPIFlash
    ("spiflash", 0,
        Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
        Subsignal("clk",  Pins("D1"), IOStandard("LVCMOS33")),  # Source of Error
        Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")),
        Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")),
    ),

    #SPI
    ("spi_bus",0,                   
        Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")),    # Source of Error              
        Subsignal("cs_n", Pins("E3"), IOStandard("LVCMOS33")),                 
        Subsignal("mosi", Pins("B1"), IOStandard("LVCMOS33")),                 
        Subsignal("miso", Pins("A2"), IOStandard("LVCMOS33")),                 
    ),

Thinking of ways to avoid this error, I would think the best solution would be to set up a sort of generic signal for clk and then use it twice once for spiflash and again for spi_bus. However I am not sure if that is possible? Another option would be to include it once in say spiflash and when requesting for the other spi core include the subsignal, sort of like:

spi_pads = [platform.request("spiflash", 0, "clk")]
spi_pads.append(platform.request("spi_bus", 0, "cs_n") # etc for mosi and miso
self.submodules.SPI = SPIMaster(spi_pads,
data_width = 8,
sys_clk_freq = sys_clk_freq,
spi_clk_freq = 8e6)

Looking forward to a response!

enjoy-digital commented 2 years ago

Hello @marrrk,

something like this should work:

    # Platform.
    # ---------

    # Shared SPI Clk.
    ("spi_clk", 0, Pins("C1"), IOStandard("LVCMOS33")),

    # SPI Flash.
    ("spi_flash", 0,
        Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
        Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")),
        Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")),
    ),

    # SPI Bus.
    ("spi_bus",0,                   
        Subsignal("cs_n", Pins("E3"), IOStandard("LVCMOS33")),                 
        Subsignal("mosi", Pins("B1"), IOStandard("LVCMOS33")),                 
        Subsignal("miso", Pins("A2"), IOStandard("LVCMOS33")),                 
    ),

    # Target.
    # -------

    # SPI Flash.
    spi_flash_pads = platform.request("spi_flash")
    spi_flash_pads.clk = Signal()
    self.submodules.SPI = SPIMaster(spi_flash_pads,
        data_width = 8,
        sys_clk_freq = sys_clk_freq,
        spi_clk_freq = 8e6
    )

    # SPI Bus.
    spi_bus_pads = platform.request("spi_bus")
    spi_bus_pads.clk = Signal()
    # FIXME: Add SPI Bus Core.

    # SPI Clk.
    spi_clk = platform.request("spi_clk")

    # Simple OR:
    self.comb += spi_clk.eq(spi_flash_pads.clk | spi_bus.pads.clk) 

    # Or manual selection:
    spi_clk_sel = Signal() # FIXME: Assign when SPI Flash or SPI Bus are selected
    self.comb += [
        If(spi_clk_sel,
            spi_clk.eq(spi_flash_pads.clk)
        ).Else(
            spi_clk.eq(spi_bus_pads.clk)
        )
    ]
marrrk commented 2 years ago

Thanks for responding, my apologies though because I realize the code I gave in the question was misleading because the way I instantiated the spiflash was actually as:

        # SPI Flash --------------------------------------------------------------------------------
        from litespi.modules import N25Q032A
        from litespi.opcodes import SpiNorFlashOpCodes as Codes
        self.add_spi_flash(mode="1x", module=N25Q032A(Codes.READ_1_1_1), with_master=False)

And the snippet in the original question is actually used for spi_bus. However, I looked at the add_spi_flash function within litex and made some edits to the code which managed to build SoC without errors;

        # SPI Flash --------------------------------------------------------------------------------
        from litespi.modules import N25Q032A
        from litespi.opcodes import SpiNorFlashOpCodes as Codes
        from litespi.phy.generic import LiteSPIPHY
        spi_flash_pads = platform.request("spiflash")
        spi_flash_pads.clk = Signal()
        spiflash_phy = LiteSPIPHY(spi_flash_pads, N25Q032A(Codes.READ_1_1_1), device=self.platform.device, default_divisor=int(self.sys_clk_freq/self.sys_clk_freq), rate="1:1")
        self.add_spi_flash(phy=spiflash_phy,mode="1x", module=N25Q032A(Codes.READ_1_1_1), with_master=False)

I'm hoping this change along with your suggestion will work. Unfortunately though I am unable to test it on hardware as of yet, but should do so in the next day or so, so I'll let you know!

marrrk commented 2 years ago

Hi @enjoy-digital,

Unfortunately I am unable to achieve my goal so far. Despite being able to build and flash the board, it seems as though the SoC is unable to load the firmware from the spiflash as it could previously. I investigated and deduced that the edits made for spi_bus for the separate clock signal work well in that I am able to replicate the same behavior (with the original spiflash) so I believe that method works. It's just in the instantiation of the spiflash that I am struggling with. The error occurs even when I am not trying to use a shared clock but still isolating the clock pin.

I'm inclined to believe that my calling of LiteSPIPHY might be the issue and so tried different variants but none solved the issue, is there anything I could be missing?