Skip to content

USB example, submodules.car, and no direct platform support #281

@YusufCelik

Description

@YusufCelik

Tang primer 20k has a working example of the usb3317 being used (https://github.com/sipeed/TangPrimer-20K-example/tree/main/USB).
This example has been generated via https://luna.readthedocs.io/en/latest/. Unfortunately the author did not include the original .py files that generated the verilog.
I have been trying to reconstruct for two weeks what the original file might have been, but no luck (since I do not want a serial device but a simple custom device for bulk transfers).
I generated a file that fails at the descriptor stage as far as I can tell from Windows (although the connection sound does play. In other words, the device does appear in the device manager.

I suspect there might be an issue with my customization (i.e., disabling submodules.car and platform.request and using a Record instead):

#!/usr/bin/env python3
#
# This file is part of LUNA.
#
# Copyright (c) 2020 Great Scott Gadgets <[email protected]>
# SPDX-License-Identifier: BSD-3-Clause

import os

from amaranth import Elaboratable, Module
from usb_protocol.emitters import DeviceDescriptorCollection

from luna import top_level_cli
from luna.gateware.platform import NullPin
from luna.gateware.usb.usb2.device import USBDevice

from amaranth import Elaboratable, Module
from amaranth.hdl.rec import Record, DIR_FANIN, DIR_FANOUT, DIR_NONE
from amaranth.back import verilog

from luna import top_level_cli


class USBDeviceExample(Elaboratable):
    """ Simple example of a USB device using the LUNA framework. """

    def __init__(self):
        self.ulpi = Record([
            ('data', [('i', 8, DIR_FANIN),
                      ('o', 8, DIR_FANOUT), ('oe', 1, DIR_FANOUT)]),
            ('clk', [('i', 8, DIR_FANIN)]),
            ('nxt', [('i', 8, DIR_FANIN)]),
            ('stp', [('o', 8, DIR_FANOUT)]),
            ('dir', [('i', 1, DIR_FANIN)]),
            ('rst', [('o', 8, DIR_FANOUT)])
        ])

    def create_descriptors(self):
        """ Create the descriptors we want to use for our device. """

        descriptors = DeviceDescriptorCollection()

        #
        # We'll add the major components of the descriptors we we want.
        # The collection we build here will be necessary to create a standard endpoint.
        #

        # We'll need a device descriptor...
        with descriptors.DeviceDescriptor() as d:
            d.idVendor = 0x16d0
            d.idProduct = 0xf3b

            d.iManufacturer = "LUNA"
            d.iProduct = "Test Device"
            d.iSerialNumber = "1234"

            d.bNumConfigurations = 1

        # ... and a description of the USB configuration we'll provide.
        with descriptors.ConfigurationDescriptor() as c:

            with c.InterfaceDescriptor() as i:
                i.bInterfaceNumber = 0

                with i.EndpointDescriptor() as e:
                    e.bEndpointAddress = 0x01
                    e.wMaxPacketSize = 64

                with i.EndpointDescriptor() as e:
                    e.bEndpointAddress = 0x81
                    e.wMaxPacketSize = 64

        return descriptors

    def elaborate(self, platform):
        m = Module()

        # Generate our domain clocks/resets.
        # m.submodules.car = platform.clock_domain_generator()

        # Create our USB device interface...
        # bus = platform.request(platform.default_usb_connection)
        m.submodules.usb = usb = USBDevice(bus=bus)

        # Add our standard control endpoint to the device.
        descriptors = self.create_descriptors()
        usb.add_standard_control_endpoint(descriptors)

        # Connect our device as a high speed device by default.
        m.d.comb += [
            usb.connect          .eq(1),
            usb.full_speed_only  .eq(1 if os.getenv('LUNA_FULL_ONLY') else 0),
        ]

        # ... and for now, attach our LEDs to our most recent control request.
        m.d.comb += [
            platform.request_optional(
                'led', 0, default=NullPin()).o  .eq(usb.tx_activity_led),
            platform.request_optional(
                'led', 1, default=NullPin()).o  .eq(usb.rx_activity_led),
            platform.request_optional(
                'led', 2, default=NullPin()).o  .eq(usb.suspended),
        ]

        return m

    def ports(self):
        return [
            self.ulpi.data.o,
            self.ulpi.data.oe,
            self.ulpi.data.i,
            self.ulpi.clk.i,
            self.ulpi.nxt.i,
            self.ulpi.stp.o,
            self.ulpi.dir.i,
            self.ulpi.rst.o
        ]


if __name__ == "__main__":
    top_level_cli(USBDeviceExample)

The .car submodule seems to be addressed(?) in the Gowin project as follows (I assume):

assign ulpi_rst  = 1'b1;
assign ulpi_data = ulpi_data_oe ? ulpi_data_o : 8'hz;

wire int_clk = ~ulpi_clk;

reg [4:0] rst_cnt;

always @(posedge int_clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        rst_cnt <=5'd0;
    end else begin
        if (rst_cnt[4] == 1'b0) rst_cnt <= rst_cnt + 5'd1;
    end
end

What am I overlooking here? Did I do something counter to the Luna framework?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions