BrunoLevy / learn-fpga

Learning FPGA, yosys, nextpnr, and RISC-V
BSD 3-Clause "New" or "Revised" License
2.58k stars 245 forks source link

FOMU: UART over USB #21

Open BrunoLevy opened 3 years ago

BrunoLevy commented 3 years ago

Add a UART to the FOMU (needs a USB core + UART over USB)

Mecrisp commented 3 years ago

Hi Bruno,

I have an USB-Serial core adapted from a mix of USB logic by Luke Valenty, Lawrie Griffiths and David Williams in Mecrisp-Ice.

https://github.com/tinyfpga/TinyFPGA-Bootloader https://github.com/lawrie/tiny_usb_examples https://github.com/davidthings/tinyfpga_bx_usbserial

See mecrisp-ice-1.9/common-verilog/usb. It's a drop-in UART core with the usual interface:

module usb_uart (
  input clk_48mhz,
  input resetq,
  output host_presence,

  // USB pins
  inout  pin_usb_p,
  inout  pin_usb_n,

  // UART interface
  input  uart_wr,
  input  uart_rd,
  input  [7:0] uart_tx_data,
  output [7:0] uart_rx_data,
  output uart_busy,
  output uart_valid
);

Matthias

BrunoLevy commented 3 years ago

Hi Matthias, Awesome ! I'll try it asap !

Mecrisp commented 3 years ago

We are working on it: https://github.com/ulixxe/usb_cdc/issues/1

Mecrisp commented 3 years ago

Hi Bruno, this one works perfectly now: https://github.com/ulixxe/usb_cdc I already have ported Mecrisp-Ice (my Swapforth/J1a descendant) to the FOMU using the @ulixxe code for terminal, and I can recommend it. Matthias

Mecrisp commented 3 years ago

Bonus points for allowing different clocks for USB and for the rest of the logic. Furthermore, it is very compact and it does not need any BRAM blocks.

Mecrisp commented 2 years ago

See https://github.com/ulixxe/usb_cdc, included here for a complete example:

https://sourceforge.net/projects/mecrisp/files/mecrisp-ice-2.2.tar.gz/download

mecrisp-ice-2.2/fomu/icestorm/j1a.v mecrisp-ice-2.2/common-verilog/usb_cdc/

Done :-)

Mecrisp commented 2 years ago
  // ######   USB-CDC terminal   ##############################

  assign usb_dp_pu = resetq;

  wire usb_p_tx;
  wire usb_n_tx;
  wire usb_p_rx;
  wire usb_n_rx;
  wire usb_tx_en;

   SB_IO #(
       .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
       .PULLUP(1'b 0)
   ) iobuf_usbp (
       .PACKAGE_PIN(usb_dp),
       .OUTPUT_ENABLE(usb_tx_en),
       .D_OUT_0(usb_p_tx),
       .D_IN_0(usb_p_rx)
   );

   SB_IO #(
       .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
       .PULLUP(1'b 0)
   ) iobuf_usbn (
       .PACKAGE_PIN(usb_dn),
       .OUTPUT_ENABLE(usb_tx_en),
       .D_OUT_0(usb_n_tx),
       .D_IN_0(usb_n_rx)
   );

  usb_cdc #(.VENDORID(16'h0483), .PRODUCTID(16'h5740), .BIT_SAMPLES(4), .USE_APP_CLK(1), .APP_CLK_RATIO(4)) _terminal
  (
    // Part running on 48 MHz:

    .clk_i(clk_usb),
    .tx_en_o(usb_tx_en),
    .tx_dp_o(usb_p_tx),
    .tx_dn_o(usb_n_tx),
    .rx_dp_i(usb_p_rx),
    .rx_dn_i(usb_n_rx),

    // Part running on 12 MHz:

    .app_clk_i(clk),
    .rstn_i(resetq),

    .out_data_o(terminal_data),
    .out_valid_o(terminal_valid),
    .out_ready_i(terminal_rd),

    .in_data_i(io_dout[7:0]),
    .in_ready_o(terminal_ready),
    .in_valid_i(terminal_wr)
  );

  wire terminal_valid, terminal_ready;
  wire [7:0] terminal_data;
  wire terminal_wr = io_wr & io_addr[12];
  wire terminal_rd = io_rd & io_addr[12];