forked from M-Labs/humpback-dds
nmigen: migrated
This commit is contained in:
parent
7351a9d58a
commit
8f1237a0a6
Binary file not shown.
|
@ -0,0 +1,24 @@
|
|||
|
||||
# If the design does not create a "sync" clock domain, it is created by the nMigen build system
|
||||
# using the platform default clock (and default reset, if any).
|
||||
|
||||
from nmigen import *
|
||||
from humpback import *
|
||||
|
||||
|
||||
class SimpleBlink(Elaboratable):
|
||||
def elaborate(self, platform):
|
||||
led = platform.request("user_led", 0)
|
||||
counter = Signal(24)
|
||||
pin = platform.request("gpioa", 0)
|
||||
|
||||
m = Module()
|
||||
m.d.sync += counter.eq(counter + 1)
|
||||
m.d.comb += led.o.eq(counter[23])
|
||||
m.d.comb += pin.o.eq(led)
|
||||
return m
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
platform = HumpbackPlatform()
|
||||
platform.build(SimpleBlink(), do_program=False)
|
|
@ -0,0 +1,112 @@
|
|||
# Strongly inspired by the migen build of humpback
|
||||
# Using STM32 Nucleo-H743ZI2 board
|
||||
# Note to self: Pin assignment differs from Nucleo-H743ZI
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from nmigen.build import *
|
||||
from nmigen.vendor.lattice_ice40 import *
|
||||
from nmigen_boards.resources import *
|
||||
from resources import *
|
||||
from pin_mapper import *
|
||||
|
||||
|
||||
__all__ = ["HumpbackPlatform"]
|
||||
|
||||
|
||||
class HumpbackPlatform(LatticeICE40Platform):
|
||||
device = "iCE40HX8K" # Using ICE40HX8K-CT256
|
||||
package = "CT256"
|
||||
default_clk = "clk25" # Point of deviation: Clock speed for humpback is fixed at 25MHz
|
||||
|
||||
# Acquire GPIO mappings from gpio_mapper
|
||||
gpio_dict, global_gpio_dict = GPIOMapping()
|
||||
resources = [
|
||||
|
||||
# Define clock
|
||||
Resource("clk25", 0, Pins("K9", dir="i"),
|
||||
Clock(25e6), Attrs(GLOBAL=True, IO_STANDARD="SB_LVCMOS")
|
||||
),
|
||||
|
||||
# Define user LED
|
||||
Resource("user_led", 0, Pins("H3", dir="o"),
|
||||
Attrs(IO_STANDARD="SB_LVCMOS")
|
||||
),
|
||||
|
||||
# Serial interfaces: Only including pins usable to STM32
|
||||
|
||||
# Define UART interfaces
|
||||
# UART interface: There are no pull ups from humpback.
|
||||
# Need to configure STM32 pins to pull up.
|
||||
# Note: Use USART in asynchronous mode
|
||||
UARTResource(0,
|
||||
rx="T11", tx="M13", rts="M15", cts="T10",
|
||||
attrs=Attrs(IO_STANDARD="SB_LVCMOS", PULLUP=1)
|
||||
),
|
||||
|
||||
# UART1 interface: Read note for UART interface above
|
||||
# UART1 interface is broken due to pin rearrangement introduced for Nucleo-H743ZI2
|
||||
# Uncomment if fixed, or found an alternative (e.g. bit banging UART)
|
||||
# *UARTResource(1,
|
||||
# tx="M11", rx="T13", rts="A6", cts="B16",
|
||||
# attrs=Attrs(IO_STANDARD="SB_LVCMOS", PULLUP=1)
|
||||
# ),
|
||||
|
||||
# Define SPI interfaces
|
||||
# Note: Use "role=device" to make humpback a SPI slave
|
||||
# The ~CS pin is a global pin, but not being configured global.
|
||||
SPIResource(0,
|
||||
cs="R2", clk="C8", mosi="N5", miso="T2",
|
||||
attrs=Attrs(IO_STANDARD="SB_LVCMOS")
|
||||
),
|
||||
|
||||
# Define I2C interface
|
||||
# Note: Need to program pull up in stm32
|
||||
# Use "role=device" to make humpback a I2C slave
|
||||
I2CResource(0,
|
||||
sda="T16", scl="M12",
|
||||
attrs=Attrs(IO_STANDARD="SB_LVCMOS", PULLUP=1)
|
||||
),
|
||||
|
||||
|
||||
# TODO:STM32 GPIO pins, ignore other unusable pins as well
|
||||
*GPIOResources(
|
||||
pins_dict = gpio_dict, dir = "o",
|
||||
attrs=Attrs(IO_STANDARD="SB_LVCMOS"),
|
||||
),
|
||||
*GPIOResources(
|
||||
pins_dict = global_gpio_dict, dir = "o",
|
||||
attrs=Attrs(GLOBAL=True, IO_STANDARD="SB_LVCMOS"),
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
connectors = []
|
||||
|
||||
# tool chain setup, using default ICE40 HX8K evaluation code
|
||||
def toolchain_program(self, products, name):
|
||||
iceprog = os.environ.get("ICEPROG", "iceprog")
|
||||
with products.extract("{}.bin".format(name)) as bitstream_filename:
|
||||
# TODO: this should be factored out and made customizable
|
||||
subprocess.check_call([iceprog, "-S", bitstream_filename])
|
||||
|
||||
if __name__ == "__main__":
|
||||
from nmigen_boards.test.blinky import *
|
||||
HumpbackPlatform().build(Blinky(), do_program=False)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
import pandas as pd
|
||||
|
||||
|
||||
# Get dictionaries of:
|
||||
# - Non-global GPIO to FPGA mapping
|
||||
# - Global GPIO to FPGA mapping
|
||||
# (Ordered)
|
||||
def GPIOMapping():
|
||||
|
||||
# Standard extraction of data from excel file
|
||||
data = pd.read_excel("nmigen/FPGA_pins.xlsx", skiprows = range(1,2))
|
||||
df = pd.DataFrame(data, columns=["Designator", "Pin Name", "Net"])
|
||||
|
||||
stm32 = df[df.Net.str.startswith("STM32")]
|
||||
|
||||
# Change some GPIO mapping for Nucleo-H743ZI2
|
||||
# Created a mapping from old pins to new pins
|
||||
old_to_new_dict = {
|
||||
# Old : New
|
||||
"PC1" :"PB1" ,
|
||||
"PC4" :"PC2" ,
|
||||
"PC5" :"PF10" ,
|
||||
"PA1" :"PB2" ,
|
||||
"PA7" :"PE9" ,
|
||||
"PA8" :"PF2" ,
|
||||
"PA9" :"PF1" ,
|
||||
"PA10" :"PF0" ,
|
||||
"PB1" :"PF4" ,
|
||||
"PC2" :"PF5" ,
|
||||
"PA2" :"PF6" ,
|
||||
"PB6" :"PG6" ,
|
||||
"PE13" :"PG12" ,
|
||||
"PF14" :"PE14" ,
|
||||
"PE14" :"PE6" ,
|
||||
}
|
||||
|
||||
# Extract data from stm32 dataframe to a dictionary
|
||||
gpio_dict = {}
|
||||
global_gpio_dict = {}
|
||||
|
||||
for index, row in stm32.iterrows():
|
||||
|
||||
# Replace old pins with new pins
|
||||
# Note: There are 2 PE6 pins on Nucleo-H743ZI2
|
||||
# This will remove 1 mapping of PE6, keys cannot be duplicated
|
||||
key = row["Net"].split("_")[1]
|
||||
if key in old_to_new_dict:
|
||||
key = old_to_new_dict.pop(key)
|
||||
|
||||
dict_entry = {key: row["Designator"]}
|
||||
|
||||
# Insert mappings into dictionary
|
||||
if "BIN" in row["Pin Name"]:
|
||||
global_gpio_dict.update(dict_entry)
|
||||
else:
|
||||
gpio_dict.update(dict_entry)
|
||||
|
||||
|
||||
return gpio_dict, global_gpio_dict
|
||||
|
||||
|
||||
# Function to provide mapping EEM pins to differential pins
|
||||
# Usage:
|
||||
# Positive pin: <returned>[<eem_port_val>][<eem_port_ldvs_num>][0]
|
||||
# Negative pin: <returned>[<eem_port_val>][<eem_port_ldvs_num>][1]
|
||||
def diffMapping():
|
||||
|
||||
eem0 = [
|
||||
# P+ve , N-ve
|
||||
[ "J3" , "H1" ],
|
||||
[ "F5" , "B1" ],
|
||||
[ "C1" , "C2" ],
|
||||
[ "F4" , "D2" ],
|
||||
[ "G5" , "D1" ],
|
||||
[ "G4" , "E3" ],
|
||||
[ "H5" , "E2" ],
|
||||
[ "G3" , "F3" ],
|
||||
]
|
||||
|
||||
eem1 = [
|
||||
# P+ve , N-ve
|
||||
[ "L6" , "L3" ],
|
||||
[ "H6" , "F1" ],
|
||||
[ "H4" , "G2" ],
|
||||
[ "J4" , "H2" ],
|
||||
[ "J2" , "J1" ],
|
||||
[ "K1" , "K3" ],
|
||||
[ "L4" , "L1" ],
|
||||
[ "K4" , "M1" ],
|
||||
]
|
||||
|
||||
eem2 = [
|
||||
# P+ve , N-ve
|
||||
[ "J5" , "G1" ],
|
||||
[ "K5" , "M2" ],
|
||||
[ "L7" , "N2" ],
|
||||
[ "M6" , "M3" ],
|
||||
[ "L5" , "N3" ],
|
||||
[ "P1" , "M4" ],
|
||||
[ "P2" , "M5" ],
|
||||
[ "R1" , "N4" ],
|
||||
]
|
||||
|
||||
return [eem0, eem1, eem2]
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
from nmigen.build import *
|
||||
|
||||
|
||||
__all__ = ["I2CResource", "GPIOResources", "DiffResources"]
|
||||
|
||||
|
||||
def I2CResource(*args, sda, scl, conn=None, attrs=None, role="host"):
|
||||
assert role in ("host", "device")
|
||||
|
||||
io = []
|
||||
|
||||
# sda line: I/O port for the data line
|
||||
io.append(Subsignal("sda", Pins(sda, dir="io", conn=conn, assert_width=1)))
|
||||
|
||||
# sck line: I2C clock signal outputs from master to slave
|
||||
if role == "host":
|
||||
io.append(Subsignal("scl", Pins(scl, dir="o", conn=conn, assert_width=1)))
|
||||
else: #device
|
||||
io.append(Subsignal("scl", Pins(scl, dir="i", conn=conn, assert_width=1)))
|
||||
|
||||
if attrs is not None:
|
||||
io.append(attrs)
|
||||
return Resource.family(*args, default_name="i2c", ios=io)
|
||||
|
||||
# Auto create a resource list given a set of iCE40 pins and STM32 pin names (pins_dict)
|
||||
def GPIOResources(*args, pins_dict, dir = "o", invert=False, conn=None, attrs=None):
|
||||
|
||||
# Check data integrity: pins_dict must be a dict AND port must be from a to k
|
||||
assert isinstance(pins_dict, dict)
|
||||
|
||||
# Debug: dir == "o"
|
||||
assert dir == "o"
|
||||
|
||||
# List of resources to be returned
|
||||
resources = []
|
||||
for STM32_pin, iCE40_pin in pins_dict.items():
|
||||
|
||||
# Set all gpio pins to be output only for the time being
|
||||
|
||||
# TODO: Allow dir argument.
|
||||
ios = [Pins(iCE40_pin, dir=dir, invert=invert, conn=conn)]
|
||||
if attrs is not None:
|
||||
ios.append(attrs)
|
||||
|
||||
# Extract GPIO port and port number from STM32_pin
|
||||
# Strip "P" from P<port><port_num>
|
||||
if STM32_pin.startswith('P'):
|
||||
STM32_pin = STM32_pin[1:]
|
||||
|
||||
# Acquire port from <port><port_num>
|
||||
port = STM32_pin[0].lower()
|
||||
port_num = int(STM32_pin[1:])
|
||||
|
||||
# Insert gpio<port>.<portNum> into resources list
|
||||
resources.append(Resource.family(*args, port_num, default_name=("gpio"+port), ios=ios))
|
||||
return resources
|
||||
|
||||
# Auto create a resource list for differential I/O
|
||||
def DiffResources(*args, eem_pins, invert=False, conn=None, attrs=None, dir):
|
||||
# TODO: Everything
|
||||
|
||||
# assert dimensionality
|
||||
assert isinstance(eem_pins, list)
|
||||
assert isinstance(eem_pins[0], list)
|
||||
assert isinstance(eem_pins[0][0], list)
|
||||
assert isinstance(eem_pins[0][0][0], str)
|
||||
|
||||
# assert direction to be either input or output
|
||||
# reject tristate or bidirectional pin
|
||||
assert dir in ("i", "o")
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
from pin_mapper import *
|
||||
eem = diffMapping()
|
||||
DiffResources(eem_pins = eem, dir = "o",
|
||||
attrs=Attrs(IO_STANDARD="SB_LVCMOS")
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue