Migen

Environment

Activate the prepared environment every time you use Migen.

source ~/.venv/bin/activate

Creating project

Create your own directory in a home directory i. e. labs. Create a new subdirectory and name it lab2, then create a file lab2.py in the subdirectory, after that copy a below text to the file.

#!/usr/bin/env python3

from migen import *

from litex.build.generic_platform import *
from litex.build.altera import AlteraPlatform
from litex.build.altera.programmer import USBBlaster

# IOs ----------------------------------------------------------------------------------------------

_io = [
    # Clk / Rst
    ("clk10", 0, Pins("N5"),  IOStandard("3.3-V LVTTL")),
    ("clk50", 0, Pins("P11"), IOStandard("3.3-V LVTTL")),
    ("clk50", 1, Pins("N14"), IOStandard("3.3-V LVTTL")),

    # Seven Segment
    ("seven_seg", 0, Pins("C14 E15 C15 C16 E16 D17 C17 D15"), IOStandard("3.3-V LVTTL")),
    ("seven_seg", 1, Pins("C18 D18 E18 B16 A17 A18 B17 A16"), IOStandard("3.3-V LVTTL"))
]

# Platform -----------------------------------------------------------------------------------------

class Platform(AlteraPlatform):
    default_clk_name   = "clk50"
    default_clk_period = 1e9/50e6
    create_rbf         = False

    def __init__(self, toolchain="quartus"):
        AlteraPlatform.__init__(self, "10M50DAF484C7G", _io, toolchain=toolchain)
        self.add_platform_command("set_global_assignment -name FAMILY \"MAX 10\"")
        self.add_platform_command("set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF")
        self.add_platform_command("set_global_assignment -name INTERNAL_FLASH_UPDATE_MODE \"SINGLE IMAGE WITH ERAM\"")

    def create_programmer(self):
        return USBBlaster()

    def do_finalize(self, fragment):
        AlteraPlatform.do_finalize(self, fragment)
        self.add_period_constraint(self.lookup_request("clk10",    loose=True), 1e9/10e6)
        self.add_period_constraint(self.lookup_request("clk50", 0, loose=True), 1e9/50e6)
        self.add_period_constraint(self.lookup_request("clk50", 1, loose=True), 1e9/50e6)

# Design -------------------------------------------------------------------------------------------
class HexDisp(Module):
      def __init__(self, output_hex0, output_hex1):
        hex0 = Signal(8)
        hex1 = Signal(8)

        self.output_hex0 = output_hex0
        self.output_hex1 = output_hex1

        self.comb += hex0[0].eq(1)
        self.comb += hex0[1].eq(0)
        self.comb += hex0[2].eq(0)
        self.comb += hex0[3].eq(1)
        self.comb += hex0[4].eq(1)
        self.comb += hex0[5].eq(0)
        self.comb += hex0[6].eq(0)
        self.comb += hex0[7].eq(1)

        self.comb += hex1[0].eq(0)
        self.comb += hex1[1].eq(0)
        self.comb += hex1[2].eq(1)
        self.comb += hex1[3].eq(0)
        self.comb += hex1[4].eq(0)
        self.comb += hex1[5].eq(1)
        self.comb += hex1[6].eq(0)
        self.comb += hex1[7].eq(1)

        self.comb += self.output_hex0.eq(hex0)
        self.comb += self.output_hex1.eq(hex1)

# Build --------------------------------------------------------------------------------------------
if __name__ == "__main__":
# Create our platform (fpga interface)
    platform = Platform()
    hex0 = platform.request("seven_seg",0)
    hex1 = platform.request("seven_seg",1)

# Create our module (fpga description)
    module=HexDisp(hex0, hex1)
# Build --------------------------------------------------------------------------------------------
    platform.build(module)
    prog = platform.create_programmer()
    prog.load_bitstream(os.path.join("build", "top.sof"))

Running projects

Running project is quite simple. To run project add project name as paramter to python3 command, like it is written below. Remember to set directory with project as current directory in console using cd command.

python3 lab2.py

A result should look like below.

image info

Comments

The presented source code requires some comments, to understand the way how it works.

Packages

Listed packages are necessary for writing in Migen, synhtesizing project(AlteraPlatform) and programming a board(USBBlaster).

#!/usr/bin/env python3

from migen import *

from litex.build.generic_platform import *
from litex.build.altera import AlteraPlatform
from litex.build.altera.programmer import USBBlaster

IOs

IOs are used by project to connect design with physical componnents of the board. Pins and theirs connections are described in a board manual. For examples pins C14 E15 C15 C16 E16 D17 C17 D15 are connected with 7-seg LED display, C18 D18 E18 B16 A17 A18 B17 A16 are connected with another 7-seg LED display.

# IOs ----------------------------------------------------------------------------------------------

_io = [
    # Clk / Rst
    ("clk10", 0, Pins("N5"),  IOStandard("3.3-V LVTTL")),
    ("clk50", 0, Pins("P11"), IOStandard("3.3-V LVTTL")),
    ("clk50", 1, Pins("N14"), IOStandard("3.3-V LVTTL")),

    # Seven Segment
    ("seven_seg", 0, Pins("C14 E15 C15 C16 E16 D17 C17 D15"), IOStandard("3.3-V LVTTL")),
    ("seven_seg", 1, Pins("C18 D18 E18 B16 A17 A18 B17 A16"), IOStandard("3.3-V LVTTL"))
]

Platform

Platform class defines basic informations about platform which will run the project. The project will be running on DE10 lite board, so 10M50DAF484C7G is chosen, which is the id of the chip installed on the board. USBBlaster informs about the way the board will be programmed. In the source you can find also information about the clocks.

# Platform -----------------------------------------------------------------------------------------

class Platform(AlteraPlatform):
    default_clk_name   = "clk50"
    default_clk_period = 1e9/50e6
    create_rbf         = False

    def __init__(self, toolchain="quartus"):
        AlteraPlatform.__init__(self, "10M50DAF484C7G", _io, toolchain=toolchain)
        self.add_platform_command("set_global_assignment -name FAMILY \"MAX 10\"")
        self.add_platform_command("set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF")
        self.add_platform_command("set_global_assignment -name INTERNAL_FLASH_UPDATE_MODE \"SINGLE IMAGE WITH ERAM\"")

    def create_programmer(self):
        return USBBlaster()

    def do_finalize(self, fragment):
        AlteraPlatform.do_finalize(self, fragment)
        self.add_period_constraint(self.lookup_request("clk10",    loose=True), 1e9/10e6)
        self.add_period_constraint(self.lookup_request("clk50", 0, loose=True), 1e9/50e6)
        self.add_period_constraint(self.lookup_request("clk50", 1, loose=True), 1e9/50e6)

Design

This part is an independed part of the code. Describes how your project should work. Because this code will be connected with external devices the outpus are defined. Output_hex0 and output_hex are bridge between FPGA nad 7-seg LED displays. Hex0 and hex1 are internal signals of the class. Rest of code assigns values to variables. [] defines which bit of the signal should be changed.

# Design -------------------------------------------------------------------------------------------
class HexDisp(Module):
      def __init__(self, output_hex0, output_hex1):
        hex0 = Signal(8)
        hex1 = Signal(8)

        self.output_hex0 = output_hex0
        self.output_hex1 = output_hex1

        self.comb += hex0[0].eq(1)
        self.comb += hex0[1].eq(0)
        self.comb += hex0[2].eq(0)
        self.comb += hex0[3].eq(1)
        self.comb += hex0[4].eq(1)
        self.comb += hex0[5].eq(0)
        self.comb += hex0[6].eq(0)
        self.comb += hex0[7].eq(1)

        self.comb += hex1[0].eq(0)
        self.comb += hex1[1].eq(0)
        self.comb += hex1[2].eq(1)
        self.comb += hex1[3].eq(0)
        self.comb += hex1[4].eq(0)
        self.comb += hex1[5].eq(1)
        self.comb += hex1[6].eq(0)
        self.comb += hex1[7].eq(1)

        self.comb += self.output_hex0.eq(hex0)
        self.comb += self.output_hex1.eq(hex1)

Build

This part describes connections between design and an “outside world”.

# Build --------------------------------------------------------------------------------------------
if __name__ == "__main__":
# Create our platform (fpga interface)
    platform = Platform()
    hex0 = platform.request("seven_seg",0)
    hex1 = platform.request("seven_seg",1)

# Create our module (fpga description)
    module=HexDisp(hex0, hex1)
# Build --------------------------------------------------------------------------------------------
    platform.build(module)
    prog = platform.create_programmer()
    prog.load_bitstream(os.path.join("build", "top.sof"))

Tasks

Connect rest of the 7-seg LED displays with the code. To do this add rest of the IOs to IO part, you can find information about connections in user manual. Add additional variables and signals in the design part, add hex3, add hex4…, add output_hex3, add output_hex4…. Extend the Build part, add hex3, add hex4… Set an actual date on the displays. A results should look like an example below.

image info