mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2024-10-01 01:45:38 -04:00
A construction of a minimal SPI master.
- NOTE: This is an optional feature, not built by default. Not included in the tk1 for sale at Tillitis shop. - This makes it possible to interface the SPI flash onboard TKey. - To include the SPI master in the build, use `make application_fpga.bin YOSYS_FLAG=-DINCLUDE_SPI_MASTER`. Signed-off-by: Joachim Strömbergson <joachim@assured.se>
This commit is contained in:
parent
eade3e11c5
commit
3bc2453287
@ -33,6 +33,11 @@ run-make:
|
|||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make clean application_fpga.bin
|
$(IMAGE) make clean application_fpga.bin
|
||||||
|
|
||||||
|
run-make-spi:
|
||||||
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
|
$(IMAGE) make clean application_fpga.bin YOSYS_FLAG=-DINCLUDE_SPI_MASTER
|
||||||
|
|
||||||
|
|
||||||
run-tb:
|
run-tb:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make tb
|
$(IMAGE) make tb
|
||||||
|
@ -68,6 +68,7 @@ VERILOG_SRCS = \
|
|||||||
$(P)/core/uds/rtl/uds_rom.v \
|
$(P)/core/uds/rtl/uds_rom.v \
|
||||||
$(P)/core/touch_sense/rtl/touch_sense.v \
|
$(P)/core/touch_sense/rtl/touch_sense.v \
|
||||||
$(P)/core/tk1/rtl/tk1.v \
|
$(P)/core/tk1/rtl/tk1.v \
|
||||||
|
$(P)/core/tk1/rtl/tk1_spi_master.v \
|
||||||
$(P)/core/tk1/rtl/udi_rom.v \
|
$(P)/core/tk1/rtl/udi_rom.v \
|
||||||
$(P)/core/uart/rtl/uart_core.v \
|
$(P)/core/uart/rtl/uart_core.v \
|
||||||
$(P)/core/uart/rtl/uart_fifo.v \
|
$(P)/core/uart/rtl/uart_fifo.v \
|
||||||
@ -236,9 +237,19 @@ tb:
|
|||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# Main FPGA build flow.
|
# Main FPGA build flow.
|
||||||
# Synthesis. Place & Route. Bitstream generation.
|
# Synthesis. Place & Route. Bitstream generation.
|
||||||
|
#
|
||||||
|
# To include the SPI-master, add the flag -DINCLUDE_SPI_MASTER to Yosys cmd.
|
||||||
|
# This can, for example, be done using
|
||||||
|
# 'make application_fpga.bin YOSYS_FLAG=-DINCLUDE_SPI_MASTER'.
|
||||||
|
# Important: do a make clean between builds with and wihtout the SPI master.
|
||||||
|
# Otherwise, there is a risk of unintended components persisting between
|
||||||
|
# builds.
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex
|
|
||||||
$(YOSYS_PATH)yosys -v3 -l synth.log -DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
|
YOSYS_FLAG ?=
|
||||||
|
|
||||||
|
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex $(P)/data/uds.hex $(P)/data/udi.hex
|
||||||
|
$(YOSYS_PATH)yosys -v3 -l synth.log $(YOSYS_FLAG) -DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
|
||||||
-DFIRMWARE_HEX=\"$(P)/bram_fw.hex\" \
|
-DFIRMWARE_HEX=\"$(P)/bram_fw.hex\" \
|
||||||
-p 'synth_ice40 -dsp -top application_fpga -json $@; write_verilog -attr2comment synth.v' \
|
-p 'synth_ice40 -dsp -top application_fpga -json $@; write_verilog -attr2comment synth.v' \
|
||||||
$(filter %.v, $^)
|
$(filter %.v, $^)
|
||||||
|
@ -190,6 +190,60 @@ core will detect that and start flashing the status LED with a red
|
|||||||
light indicating that the CPU is in a trapped state and no further
|
light indicating that the CPU is in a trapped state and no further
|
||||||
execution is possible.
|
execution is possible.
|
||||||
|
|
||||||
|
## SPI-master
|
||||||
|
|
||||||
|
The TK1 includes a minimal SPI-master that provides access to the
|
||||||
|
Winbond Flash memory mounted on the board. The SPI-master is byte
|
||||||
|
oriented and very minimalistic.
|
||||||
|
|
||||||
|
In order to transfer more than a single byte, SW must read status and
|
||||||
|
write commands needed to send a sequence of bytes. In order to read
|
||||||
|
out a sequence of bytes from the memory, SW must send as many dummy
|
||||||
|
bytes as the data being read from the memory.
|
||||||
|
|
||||||
|
The SPI-master is controlled using a few API
|
||||||
|
addresses:
|
||||||
|
|
||||||
|
```
|
||||||
|
localparam ADDR_SPI_EN = 8'h80;
|
||||||
|
localparam ADDR_SPI_XFER = 8'h81;
|
||||||
|
localparam ADDR_SPI_DATA = 8'h82;
|
||||||
|
```
|
||||||
|
|
||||||
|
**ADDR_SPI_EN** enables and disabled the SPI-master. Writing a 0x01 will
|
||||||
|
lower the SPI chip select to the memory. Writing a 0x00 will raise the
|
||||||
|
chip select.
|
||||||
|
|
||||||
|
Writing to the **ADDR_SPI_XFER** starts a byte transfer. Reading from
|
||||||
|
the address returns the status for the SPI-master. If the return value
|
||||||
|
is not zero, the SPI-master is ready to send a byte.
|
||||||
|
|
||||||
|
**ADDR_SPI_DATA** is the address used to send and receive a byte.
|
||||||
|
data. The least significant byte will be sent to the memory during a
|
||||||
|
transfer. The byte returned from the memory will be presented to SW if
|
||||||
|
the address is read after a transfer has completed.
|
||||||
|
|
||||||
|
The sequence of operations needed to perform is thus:
|
||||||
|
|
||||||
|
1. Activate the SPI-master by writing a 0x00000001 to ADDR_SPI_EN
|
||||||
|
2. Write a byte to ADDR_SPI_DATA
|
||||||
|
3. Read ADDR_SPI_XFER to check status. Repeat until the read
|
||||||
|
operation returns non-zero value
|
||||||
|
4. Write to ADDR_SPI_XFER
|
||||||
|
5. Read ADDR_SPI_XFER to check status. Repeat until the read operation
|
||||||
|
returns a non-zero value
|
||||||
|
6. Read out the received byte from ADDR_SPI_DATA
|
||||||
|
7. Repeat 2..6 as many times as needed to send a command and data to
|
||||||
|
the memory and getting the expected status, data back.
|
||||||
|
8. Deactivate the SPI-master by writing 0x00000000 to ADDR_SPI_EN
|
||||||
|
|
||||||
|
The SPI connected memory on the board is the Winbond W25Q80. For
|
||||||
|
information about the memory including support commands and protocol,
|
||||||
|
see the datasheet:
|
||||||
|
|
||||||
|
https://www.mouser.se/datasheet/2/949/w25q80dv_dl_revh_10022015-1489677.pdf
|
||||||
|
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
The core is implemented as a single module. Future versions will
|
The core is implemented as a single module. Future versions will
|
||||||
|
@ -28,6 +28,13 @@ module tk1(
|
|||||||
output wire [14 : 0] ram_aslr,
|
output wire [14 : 0] ram_aslr,
|
||||||
output wire [31 : 0] ram_scramble,
|
output wire [31 : 0] ram_scramble,
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
output wire spi_ss,
|
||||||
|
output wire spi_sck,
|
||||||
|
output wire spi_mosi,
|
||||||
|
input wire spi_miso,
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
output wire led_r,
|
output wire led_r,
|
||||||
output wire led_g,
|
output wire led_g,
|
||||||
output wire led_b,
|
output wire led_b,
|
||||||
@ -86,6 +93,11 @@ module tk1(
|
|||||||
localparam ADDR_CPU_MON_FIRST = 8'h61;
|
localparam ADDR_CPU_MON_FIRST = 8'h61;
|
||||||
localparam ADDR_CPU_MON_LAST = 8'h62;
|
localparam ADDR_CPU_MON_LAST = 8'h62;
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
localparam ADDR_SPI_EN = 8'h80;
|
||||||
|
localparam ADDR_SPI_XFER = 8'h81;
|
||||||
|
localparam ADDR_SPI_DATA = 8'h82;
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
localparam TK1_NAME0 = 32'h746B3120; // "tk1 "
|
localparam TK1_NAME0 = 32'h746B3120; // "tk1 "
|
||||||
localparam TK1_NAME1 = 32'h6d6b6466; // "mkdf"
|
localparam TK1_NAME1 = 32'h6d6b6466; // "mkdf"
|
||||||
@ -157,6 +169,17 @@ module tk1(
|
|||||||
|
|
||||||
wire [31:0] udi_rdata;
|
wire [31:0] udi_rdata;
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
reg spi_enable;
|
||||||
|
reg spi_enable_vld;
|
||||||
|
reg spi_start;
|
||||||
|
reg [7 : 0] spi_tx_data;
|
||||||
|
reg spi_tx_data_vld;
|
||||||
|
wire spi_ready;
|
||||||
|
wire [7 : 0] spi_rx_data;
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Concurrent connectivity for ports etc.
|
// Concurrent connectivity for ports etc.
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@ -195,6 +218,26 @@ module tk1(
|
|||||||
);
|
);
|
||||||
/* verilator lint_on PINMISSING */
|
/* verilator lint_on PINMISSING */
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
tk1_spi_master spi_master(
|
||||||
|
.clk(clk),
|
||||||
|
.reset_n(reset_n),
|
||||||
|
|
||||||
|
.spi_ss(spi_ss),
|
||||||
|
.spi_sck(spi_sck),
|
||||||
|
.spi_mosi(spi_mosi),
|
||||||
|
.spi_miso(spi_miso),
|
||||||
|
|
||||||
|
.spi_enable(spi_enable),
|
||||||
|
.spi_enable_vld(spi_enable_vld),
|
||||||
|
.spi_start(spi_start),
|
||||||
|
.spi_tx_data(spi_tx_data),
|
||||||
|
.spi_tx_data_vld(spi_tx_data_vld),
|
||||||
|
.spi_rx_data(spi_rx_data),
|
||||||
|
.spi_ready(spi_ready)
|
||||||
|
);
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
|
|
||||||
udi_rom rom_i(
|
udi_rom rom_i(
|
||||||
.addr(address[0]),
|
.addr(address[0]),
|
||||||
@ -393,6 +436,15 @@ module tk1(
|
|||||||
tmp_read_data = 32'h0;
|
tmp_read_data = 32'h0;
|
||||||
tmp_ready = 1'h0;
|
tmp_ready = 1'h0;
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
spi_enable_vld = 1'h0;
|
||||||
|
spi_start = 1'h0;
|
||||||
|
spi_tx_data_vld = 1'h0;
|
||||||
|
|
||||||
|
spi_enable = write_data[0];
|
||||||
|
spi_tx_data = write_data[7 : 0];
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
if (cs) begin
|
if (cs) begin
|
||||||
tmp_ready = 1'h1;
|
tmp_ready = 1'h1;
|
||||||
if (we) begin
|
if (we) begin
|
||||||
@ -460,8 +512,22 @@ module tk1(
|
|||||||
cpu_mon_last_we = 1'h1;
|
cpu_mon_last_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
if (address == ADDR_SPI_EN) begin
|
||||||
|
spi_enable_vld = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (address == ADDR_SPI_XFER) begin
|
||||||
|
spi_start = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (address == ADDR_SPI_DATA) begin
|
||||||
|
spi_tx_data_vld = 1'h1;
|
||||||
|
end
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
|
end
|
||||||
else begin
|
else begin
|
||||||
if (address == ADDR_NAME0) begin
|
if (address == ADDR_NAME0) begin
|
||||||
tmp_read_data = TK1_NAME0;
|
tmp_read_data = TK1_NAME0;
|
||||||
@ -509,6 +575,17 @@ module tk1(
|
|||||||
tmp_read_data = udi_rdata;
|
tmp_read_data = udi_rdata;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
if (address == ADDR_SPI_XFER) begin
|
||||||
|
tmp_read_data[0] = spi_ready;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (address == ADDR_SPI_DATA) begin
|
||||||
|
tmp_read_data[7 : 0] = spi_rx_data;
|
||||||
|
end
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end // api
|
end // api
|
||||||
|
327
hw/application_fpga/core/tk1/rtl/tk1_spi_master.v
Normal file
327
hw/application_fpga/core/tk1/rtl/tk1_spi_master.v
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
//======================================================================
|
||||||
|
//
|
||||||
|
// tk1_spi_master.v
|
||||||
|
// ----------------
|
||||||
|
// Minimal SPI master to be integrated into the tk1 module.
|
||||||
|
// The SPI master is able to generate a clock, and transfer,
|
||||||
|
// exchange a single byte with the slave.
|
||||||
|
//
|
||||||
|
// This master is compatible with the Winbond W25Q80DV memory.
|
||||||
|
// This means that MSB of a response from the memory is provided
|
||||||
|
// on the falling clock edge on the LSB of the command byte, not
|
||||||
|
// on a dummy byte. This means that the response spans the boundary
|
||||||
|
// of the bytes, The core handles this by sampling the MISO
|
||||||
|
// just prior to settint the positive clock flank at the start
|
||||||
|
// of a byte transfer.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Author: Joachim Strombergson
|
||||||
|
// Copyright (C) 2023 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
//
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
|
||||||
|
module tk1_spi_master(
|
||||||
|
input wire clk,
|
||||||
|
input wire reset_n,
|
||||||
|
|
||||||
|
output wire spi_ss,
|
||||||
|
output wire spi_sck,
|
||||||
|
output wire spi_mosi,
|
||||||
|
input wire spi_miso,
|
||||||
|
|
||||||
|
input wire spi_enable,
|
||||||
|
input wire spi_enable_vld,
|
||||||
|
input wire spi_start,
|
||||||
|
input wire [7 : 0] spi_tx_data,
|
||||||
|
input wire spi_tx_data_vld,
|
||||||
|
output wire [7 : 0] spi_rx_data,
|
||||||
|
output wire spi_ready
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Internal constant and parameter definitions.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
parameter CTRL_IDLE = 3'h0;
|
||||||
|
parameter CTRL_POS_FLANK = 3'h1;
|
||||||
|
parameter CTRL_WAIT_POS = 3'h2;
|
||||||
|
parameter CTRL_NEG_FLANK = 3'h3;
|
||||||
|
parameter CTRL_WAIT_NEG = 3'h4;
|
||||||
|
parameter CTRL_NEXT = 3'h5;
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Registers including update variables and write enable.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
reg spi_ss_reg;
|
||||||
|
|
||||||
|
reg spi_csk_reg;
|
||||||
|
reg spi_csk_new;
|
||||||
|
reg spi_csk_we;
|
||||||
|
|
||||||
|
reg [7 : 0] spi_tx_data_reg;
|
||||||
|
reg [7 : 0] spi_tx_data_new;
|
||||||
|
reg spi_tx_data_nxt;
|
||||||
|
reg spi_tx_data_we;
|
||||||
|
|
||||||
|
reg [7 : 0] spi_rx_data_reg;
|
||||||
|
reg [7 : 0] spi_rx_data_new;
|
||||||
|
reg spi_rx_data_nxt;
|
||||||
|
reg spi_rx_data_we;
|
||||||
|
|
||||||
|
reg spi_miso_sample_reg;
|
||||||
|
|
||||||
|
reg [3 : 0] spi_clk_ctr_reg;
|
||||||
|
reg [3 : 0] spi_clk_ctr_new;
|
||||||
|
reg spi_clk_ctr_rst;
|
||||||
|
|
||||||
|
reg [2 : 0] spi_bit_ctr_reg;
|
||||||
|
reg [2 : 0] spi_bit_ctr_new;
|
||||||
|
reg spi_bit_ctr_rst;
|
||||||
|
reg spi_bit_ctr_inc;
|
||||||
|
reg spi_bit_ctr_we;
|
||||||
|
|
||||||
|
reg spi_ready_reg;
|
||||||
|
reg spi_ready_new;
|
||||||
|
reg spi_ready_we;
|
||||||
|
|
||||||
|
reg [2 : 0] spi_ctrl_reg;
|
||||||
|
reg [2 : 0] spi_ctrl_new;
|
||||||
|
reg spi_ctrl_we;
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Concurrent connectivity for ports etc.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
assign spi_ss = spi_ss_reg;
|
||||||
|
assign spi_sck = spi_csk_reg;
|
||||||
|
assign spi_mosi = spi_tx_data_reg[7];
|
||||||
|
assign spi_rx_data = spi_rx_data_reg;
|
||||||
|
assign spi_ready = spi_ready_reg;
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// reg_update
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @ (posedge clk)
|
||||||
|
begin : reg_update
|
||||||
|
if (!reset_n) begin
|
||||||
|
spi_ss_reg <= 1'h1;
|
||||||
|
spi_csk_reg <= 1'h0;
|
||||||
|
spi_miso_sample_reg <= 1'h0;
|
||||||
|
spi_tx_data_reg <= 8'h0;
|
||||||
|
spi_rx_data_reg <= 8'h0;
|
||||||
|
spi_clk_ctr_reg <= 4'h0;
|
||||||
|
spi_bit_ctr_reg <= 3'h0;
|
||||||
|
spi_ready_reg <= 1'h1;
|
||||||
|
spi_ctrl_reg <= CTRL_IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
else begin
|
||||||
|
spi_miso_sample_reg <= spi_miso;
|
||||||
|
spi_clk_ctr_reg <= spi_clk_ctr_new;
|
||||||
|
|
||||||
|
if (spi_enable_vld) begin
|
||||||
|
spi_ss_reg <= ~spi_enable;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_csk_we) begin
|
||||||
|
spi_csk_reg <= spi_csk_new;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_tx_data_we) begin
|
||||||
|
spi_tx_data_reg <= spi_tx_data_new;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_rx_data_we) begin
|
||||||
|
spi_rx_data_reg <= spi_rx_data_new;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_ready_we) begin
|
||||||
|
spi_ready_reg <= spi_ready_new;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_bit_ctr_we) begin
|
||||||
|
spi_bit_ctr_reg <= spi_bit_ctr_new;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_ctrl_we) begin
|
||||||
|
spi_ctrl_reg <= spi_ctrl_new;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end // reg_update
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// clk_ctr
|
||||||
|
//
|
||||||
|
// Continuously running clock cycle counter that can be
|
||||||
|
// reset to zero.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @*
|
||||||
|
begin : clk_ctr
|
||||||
|
if (spi_clk_ctr_rst) begin
|
||||||
|
spi_clk_ctr_new = 4'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
else begin
|
||||||
|
spi_clk_ctr_new = spi_clk_ctr_reg + 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// bit_ctr
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @*
|
||||||
|
begin : bit_ctr
|
||||||
|
spi_bit_ctr_new = 3'h0;
|
||||||
|
spi_bit_ctr_we = 1'h0;
|
||||||
|
|
||||||
|
if (spi_bit_ctr_rst) begin
|
||||||
|
spi_bit_ctr_new = 3'h0;
|
||||||
|
spi_bit_ctr_we = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
else if (spi_bit_ctr_inc) begin
|
||||||
|
spi_bit_ctr_new = spi_bit_ctr_reg + 1'h1;
|
||||||
|
spi_bit_ctr_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// spi_tx_data_logic
|
||||||
|
// Logic for the tx_data shift register.
|
||||||
|
// Either load or shift the data register.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @*
|
||||||
|
begin : spi_tx_data_logic
|
||||||
|
spi_tx_data_new = 8'h0;
|
||||||
|
spi_tx_data_we = 1'h0;
|
||||||
|
|
||||||
|
if (spi_tx_data_vld) begin
|
||||||
|
if (spi_ready_reg) begin
|
||||||
|
spi_tx_data_new = spi_tx_data;
|
||||||
|
spi_tx_data_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (spi_tx_data_nxt) begin
|
||||||
|
spi_tx_data_new = {spi_tx_data_reg[6 : 0], 1'h0};
|
||||||
|
spi_tx_data_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// spi_rx_data_logic
|
||||||
|
// Logic for the rx_data shift register.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @*
|
||||||
|
begin : spi_rx_data_logic
|
||||||
|
spi_rx_data_new = 8'h0;
|
||||||
|
spi_rx_data_we = 1'h0;
|
||||||
|
|
||||||
|
if (spi_ss) begin
|
||||||
|
spi_rx_data_new = 8'h0;
|
||||||
|
spi_rx_data_we = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
else if (spi_rx_data_nxt) begin
|
||||||
|
spi_rx_data_new = {spi_rx_data_reg[6 : 0], spi_miso_sample_reg};
|
||||||
|
spi_rx_data_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// spi_master_ctrl
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @*
|
||||||
|
begin : spi_master_ctrl
|
||||||
|
spi_rx_data_nxt = 1'h0;
|
||||||
|
spi_tx_data_nxt = 1'h0;
|
||||||
|
spi_clk_ctr_rst = 1'h0;
|
||||||
|
spi_csk_new = 1'h0;
|
||||||
|
spi_csk_we = 1'h0;
|
||||||
|
spi_bit_ctr_rst = 1'h0;
|
||||||
|
spi_bit_ctr_inc = 1'h0;
|
||||||
|
spi_ready_new = 1'h0;
|
||||||
|
spi_ready_we = 1'h0;
|
||||||
|
spi_ctrl_new = CTRL_IDLE;
|
||||||
|
spi_ctrl_we = 1'h0;
|
||||||
|
|
||||||
|
|
||||||
|
case (spi_ctrl_reg)
|
||||||
|
CTRL_IDLE: begin
|
||||||
|
if (spi_start) begin
|
||||||
|
spi_csk_new = 1'h0;
|
||||||
|
spi_csk_we = 1'h1;
|
||||||
|
spi_bit_ctr_rst = 1'h1;
|
||||||
|
spi_ready_new = 1'h0;
|
||||||
|
spi_ready_we = 1'h1;
|
||||||
|
spi_ctrl_new = CTRL_POS_FLANK;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL_POS_FLANK: begin
|
||||||
|
spi_rx_data_nxt = 1'h1;
|
||||||
|
spi_csk_new = 1'h1;
|
||||||
|
spi_csk_we = 1'h1;
|
||||||
|
spi_clk_ctr_rst = 1'h1;
|
||||||
|
spi_ctrl_new = CTRL_WAIT_POS;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL_WAIT_POS: begin
|
||||||
|
if (spi_clk_ctr_reg == 4'hf) begin
|
||||||
|
spi_ctrl_new = CTRL_NEG_FLANK;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL_NEG_FLANK: begin
|
||||||
|
spi_csk_new = 1'h0;
|
||||||
|
spi_csk_we = 1'h1;
|
||||||
|
spi_clk_ctr_rst = 1'h1;
|
||||||
|
spi_ctrl_new = CTRL_WAIT_NEG;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL_WAIT_NEG: begin
|
||||||
|
if (spi_clk_ctr_reg == 4'hf) begin
|
||||||
|
spi_ctrl_new = CTRL_NEXT;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL_NEXT: begin
|
||||||
|
if (spi_bit_ctr_reg == 3'h7) begin
|
||||||
|
spi_ready_new = 1'h1;
|
||||||
|
spi_ready_we = 1'h1;
|
||||||
|
spi_ctrl_new = CTRL_IDLE;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
spi_tx_data_nxt = 1'h1;
|
||||||
|
spi_bit_ctr_inc = 1'h1;
|
||||||
|
spi_ctrl_new = CTRL_POS_FLANK;
|
||||||
|
spi_ctrl_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
end
|
||||||
|
endcase // case (spi_ctrl_reg)
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule // tk1_spi_master
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// EOF tk1_spi_master.v
|
||||||
|
//======================================================================
|
@ -37,6 +37,10 @@ lint-top: $(LINT_SRC)
|
|||||||
$(LINT) $(LINT_FLAGS) $(LINT_SRC)
|
$(LINT) $(LINT_FLAGS) $(LINT_SRC)
|
||||||
|
|
||||||
|
|
||||||
|
lint-spi: $(SPI_SRC)
|
||||||
|
$(LINT) $(LINT_FLAGS) $^
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f top.sim
|
rm -f top.sim
|
||||||
|
|
||||||
|
@ -18,6 +18,13 @@ set_io interface_tx 25
|
|||||||
# set_io interface_rts 28
|
# set_io interface_rts 28
|
||||||
|
|
||||||
|
|
||||||
|
# SPI master to flash memory.
|
||||||
|
set_io spi_miso 17
|
||||||
|
set_io spi_sck 15
|
||||||
|
set_io spi_ss 16
|
||||||
|
set_io spi_mosi 14
|
||||||
|
|
||||||
|
|
||||||
# Touch sense.
|
# Touch sense.
|
||||||
set_io touch_event 6
|
set_io touch_event 6
|
||||||
|
|
||||||
|
@ -141,4 +141,8 @@
|
|||||||
#define TK1_MMIO_TK1_CPU_MON_CTRL 0xff000180
|
#define TK1_MMIO_TK1_CPU_MON_CTRL 0xff000180
|
||||||
#define TK1_MMIO_TK1_CPU_MON_FIRST 0xff000184
|
#define TK1_MMIO_TK1_CPU_MON_FIRST 0xff000184
|
||||||
#define TK1_MMIO_TK1_CPU_MON_LAST 0xff000188
|
#define TK1_MMIO_TK1_CPU_MON_LAST 0xff000188
|
||||||
|
|
||||||
|
#define TK1_MMIO_TK1_SPI_EN 0xff000200
|
||||||
|
#define TK1_MMIO_TK1_SPI_XFER 0xff000204
|
||||||
|
#define TK1_MMIO_TK1_SPI_DATA 0xff000208
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,13 @@ module application_fpga(
|
|||||||
output wire interface_rx,
|
output wire interface_rx,
|
||||||
input wire interface_tx,
|
input wire interface_tx,
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
output wire spi_ss,
|
||||||
|
output wire spi_sck,
|
||||||
|
output wire spi_mosi,
|
||||||
|
input wire spi_miso,
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
input wire touch_event,
|
input wire touch_event,
|
||||||
|
|
||||||
input wire app_gpio1,
|
input wire app_gpio1,
|
||||||
@ -317,6 +324,13 @@ module application_fpga(
|
|||||||
.ram_aslr(ram_aslr),
|
.ram_aslr(ram_aslr),
|
||||||
.ram_scramble(ram_scramble),
|
.ram_scramble(ram_scramble),
|
||||||
|
|
||||||
|
`ifdef INCLUDE_SPI_MASTER
|
||||||
|
.spi_ss(spi_ss),
|
||||||
|
.spi_sck(spi_sck),
|
||||||
|
.spi_mosi(spi_mosi),
|
||||||
|
.spi_miso(spi_miso),
|
||||||
|
`endif // INCLUDE_SPI_MASTER
|
||||||
|
|
||||||
.led_r(led_r),
|
.led_r(led_r),
|
||||||
.led_g(led_g),
|
.led_g(led_g),
|
||||||
.led_b(led_b),
|
.led_b(led_b),
|
||||||
|
Loading…
Reference in New Issue
Block a user