litex-hub / litex-boards

LiteX boards files
BSD 2-Clause "Simplified" License
376 stars 287 forks source link

Sipeed Tang Nano 1k support #518

Open Podolyakofs opened 1 year ago

Podolyakofs commented 1 year ago

Good day, I have Sipeed Tang Nano 1K (which is replacement for Tang Nano already supported in Litex) with GW1NZ-LV1QN48C6/I5 and BL702 usb-jtag

Here's its documentation https://wiki.sipeed.com/hardware/en/tang/Tang-Nano-1K/Nano-1k.html

Looks like to run Litex on it previous sipeed_tang_nano board definitions need some changes:

sipeed_tang_nano_1k_platform.py ``` from migen import * from litex.build.generic_platform import * from litex.build.gowin.platform import GowinPlatform from litex.build.openfpgaloader import OpenFPGALoader from litex.build.gowin.programmer import GowinProgrammer # IOs ---------------------------------------------------------------------------------------------- _io = [ #All io changes # Clk / Rst ("clk27", 0, Pins("47"), IOStandard("LVCMOS33"),Misc("PULL_MODE=UP")), ("rst_n", 0, Pins("13"), IOStandard("LVCMOS33"),Misc("PULL_MODE=UP")), # Leds ("user_led", 0, Pins("9"), IOStandard("LVCMOS33"), Misc("PULL_MODE=UP")), ("user_led", 1, Pins("10"), IOStandard("LVCMOS33"),Misc("PULL_MODE=UP")), ("user_led", 2, Pins("11"), IOStandard("LVCMOS33"),Misc("PULL_MODE=UP")), # Buttons. ("user_btn", 0, Pins("44"), IOStandard("LVCMOS33")), ("user_btn", 1, Pins("13"), IOStandard("LVCMOS33")), # Serial # ("serial", 0, #Can use other pins, this on this board used for led, disabled for now # Subsignal("tx", Pins("8")), # Subsignal("rx", Pins("9")), # IOStandard("LVCMOS33") # ), ] # Connectors --------------------------------------------------------------------------------------- _connectors = [] # Platform ----------------------------------------------------------------------------------------- class Platform(GowinPlatform): default_clk_name = "clk27" #Change freq to 27 Mhz default_clk_period = 1e9/27e6 #Change freq def __init__(self, toolchain="gowin"): GowinPlatform.__init__(self, "GW1NZ-LV1QN48C6/I5", _io, _connectors, toolchain=toolchain, devicename="GW1NZ-1") #Change FPGA name self.toolchain.options["use_done_as_gpio"] = 1 self.toolchain.options["use_reconfign_as_gpio"] = 1 def create_programmer(self, kit="openfpgaloader"): if kit == "gowin": return GowinProgrammer(self.devicename) else: return OpenFPGALoader(cable="ft2232") #Change to BL702 support def do_finalize(self, fragment): GowinPlatform.do_finalize(self, fragment) self.add_period_constraint(self.lookup_request("clk27", loose=True), 1e9/27e6) #Change freq ```
sipeed_tang_nano_1k_platform.py ``` from migen import * from litex.gen import * import stn_1k_platform as sipeed_tang_nano from gowin_gw1n import GW1NPLL #We need some changes to "from litex.soc.cores.clock.gowin_gw1n import GW1NPLL" from litex.soc.integration.soc_core import * from litex.soc.integration.builder import * from litex.soc.cores.led import LedChaser # CRG ---------------------------------------------------------------------------------------------- class _CRG(LiteXModule): def __init__(self, platform, sys_clk_freq): self.rst = Signal() self.cd_sys = ClockDomain() # # # # Clk / Rst. clk27 = platform.request("clk27") #Freq change rst_n = platform.request("user_btn", 0) # PLL. self.pll = pll = GW1NPLL(devicename=platform.devicename, device=platform.device) self.comb += pll.reset.eq(~rst_n) pll.register_clkin(clk27, 27e6) #Freq change pll.create_clkout(self.cd_sys, sys_clk_freq) # BaseSoC ------------------------------------------------------------------------------------------ class BaseSoC(SoCMini): def __init__(self, sys_clk_freq=48e6, with_led_chaser=True, **kwargs): platform = sipeed_tang_nano.Platform() # CRG -------------------------------------------------------------------------------------- self.crg = _CRG(platform, sys_clk_freq) # SoCMini ---------------------------------------------------------------------------------- kwargs["uart_name"] = "crossover" SoCMini.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Tang Nano", **kwargs) # UARTBone --------------------------------------------------------------------------------- #disabled for now - need to select pins in previous # self.add_uartbone(name="serial", baudrate=115200) # Leds ------------------------------------------------------------------------------------- if with_led_chaser: self.leds = LedChaser( pads = platform.request_all("user_led"), sys_clk_freq = sys_clk_freq) # Build -------------------------------------------------------------------------------------------- def main(): from litex.build.parser import LiteXArgumentParser parser = LiteXArgumentParser(platform=sipeed_tang_nano.Platform, description="LiteX SoC on Tang Nano.") parser.add_target_argument("--flash", action="store_true", help="Flash Bitstream.") parser.add_target_argument("--sys-clk-freq",default=48e6, type=float, help="System clock frequency.") args = parser.parse_args() soc = BaseSoC( sys_clk_freq = args.sys_clk_freq, **parser.soc_argdict ) builder = Builder(soc, **parser.builder_argdict) if args.build: builder.build(**parser.toolchain_argdict) if args.load: prog = soc.platform.create_programmer() prog.load_bitstream(builder.get_bitstream_filename(mode="sram")) if args.flash: prog = soc.platform.create_programmer() prog.flash(0, builder.get_bitstream_filename(mode="flash", ext=".fs")) # FIXME #That's not my (= if __name__ == "__main__": main() ```
some changes to GW1NPLL class from litex.soc.cores.clock.gowin_gw1n ``` @staticmethod def get_vco_freq_range(device): vco_freq_range = None if device.startswith('GW1NS'): if 'C7/I6' in device or 'C6/I5' in device: vco_freq_range = (600e6, 1200e6) # datasheet says (400, 1200) but compiler enforces (600, 1200) elif 'C5/I4' in device: vco_freq_range = (320e6, 960e6) # datasheet values, not tested if device.startswith('GW1NZ'): #Add this FPGA and its VCO if 'C6/I5' in device: vco_freq_range = (400e6, 800e6) # datasheet says (400, 800) elif device.startswith('GW1N-1S'): vco_freq_range = (400e6, 1200e6) elif device.startswith('GW1N-') or device.startswith('GW1NR-'): vco_freq_range = (400e6, 900e6) if vco_freq_range is None: raise ValueError(f"Unsupported device {device}.") return vco_freq_range @staticmethod def get_pfd_freq_range(device): pfd_freq_range = None if device.startswith('GW1NS'): if 'C7/I6' in device or 'C6/I5' in device: pfd_freq_range = (3e6, 400e6) elif 'C5/I4' in device: pfd_freq_range = (3e6, 320e6) if device.startswith('GW1NZ'): #Add this FPGA and its PFD if 'C6/I5' in device: pfd_freq_range = (3e6, 400e6) # datasheet says (3, 400) elif device.startswith('GW1N-1S'): pfd_freq_range = (3e6, 400e6) # not verified: not found in the datasheet elif device.startswith('GW1N-') or device.startswith('GW1NR-'): pfd_freq_range = (3e6, 400e6) # not verified: not found in the datasheet if pfd_freq_range is None: raise ValueError(f"Unsupported device {device}.") return pfd_freq_range``` ```

run with

python ./sipeed_tang_nano_platform.py  --build  --load --cpu-type None --csr-csv "csr.csv" --no-uart

After that I got blink on board with litex.

Can anyone check this, also are there any other changes that need to be applied to GW1NPLL class?

trabucayre commented 1 year ago

My first idea was to introduce a variant arg to select between original and new. But both seems really different for pinout/LCD/etc. It make more sense to introduce a new platform/target called sipeed_tang_nano_1k.py. Could you explain a bit more changes required to GW1NPLL ?

Podolyakofs commented 1 year ago

From GW1NZ series of FPGA Products (look at LV - C6/I5) ( https://dl.sipeed.com/shareURL/TANG/Nano%201K/6_Chip_Manual/EN) image

@staticmethod
    def get_vco_freq_range(device):
           vco_freq_range = None
           if device.startswith('GW1NZ'):  #Add this FPGA and its VCO (or change to startwith"GW1NZ-1")
                   if 'C6/I5' in device:
                          vco_freq_range = (400e6, 800e6)  # datasheet says (400, 800)
@staticmethod
    def get_pfd_freq_range(device):
        pfd_freq_range = None
        if device.startswith('GW1NZ'):            #Add this FPGA and its PFD (or change to startwith"GW1NZ-1")
            if 'C6/I5' in device:
                pfd_freq_range = (3e6, 400e6)  # datasheet says (3, 400)

But I'm not sure that this is enough Device and part number is from https://github.com/sipeed/TangNano-1K-examples/blob/main/example_led/led_prj/src/led_prj.cst