added v2.0
This commit is contained in:
40
06_IO_Devices/03_SPI/Include.v
Normal file
40
06_IO_Devices/03_SPI/Include.v
Normal file
@@ -0,0 +1,40 @@
|
||||
`include "../../01_Boolean_Logic/Nand.v"
|
||||
`include "../../01_Boolean_Logic/Not.v"
|
||||
`include "../../01_Boolean_Logic/Buffer.v"
|
||||
`include "../../01_Boolean_Logic/And.v"
|
||||
`include "../../01_Boolean_Logic/Or.v"
|
||||
`include "../../01_Boolean_Logic/Xor.v"
|
||||
`include "../../01_Boolean_Logic/Mux.v"
|
||||
`include "../../01_Boolean_Logic/DMux.v"
|
||||
`include "../../01_Boolean_Logic/Not16.v"
|
||||
`include "../../01_Boolean_Logic/Buffer16.v"
|
||||
`include "../../01_Boolean_Logic/And16.v"
|
||||
`include "../../01_Boolean_Logic/Or16.v"
|
||||
`include "../../01_Boolean_Logic/Mux16.v"
|
||||
`include "../../01_Boolean_Logic/Or8Way.v"
|
||||
`include "../../01_Boolean_Logic/Mux4Way16.v"
|
||||
`include "../../01_Boolean_Logic/Mux8Way16.v"
|
||||
`include "../../01_Boolean_Logic/DMux4Way.v"
|
||||
`include "../../01_Boolean_Logic/DMux8Way.v"
|
||||
|
||||
`include "../../02_Boolean_Arithmetic/HalfAdder.v"
|
||||
`include "../../02_Boolean_Arithmetic/FullAdder.v"
|
||||
`include "../../02_Boolean_Arithmetic/Add16.v"
|
||||
`include "../../02_Boolean_Arithmetic/Inc16.v"
|
||||
`include "../../02_Boolean_Arithmetic/ALU.v"
|
||||
|
||||
`include "../../03_Sequential_Logic/DFF.v"
|
||||
`include "../../03_Sequential_Logic/Bit.v"
|
||||
`include "../../03_Sequential_Logic/Register.v"
|
||||
`include "../../03_Sequential_Logic/PC.v"
|
||||
`include "../../03_Sequential_Logic/BitShift9R.v"
|
||||
`include "../../03_Sequential_Logic/BitShift8L.v"
|
||||
|
||||
`include "../../06_IO_Devices/UartTX.v"
|
||||
`include "../../06_IO_Devices/UartRX.v"
|
||||
`include "../../06_IO_Devices/SPI.v"
|
||||
`include "../../06_IO_Devices/InOut.v"
|
||||
`include "../../06_IO_Devices/SRAM_D.v"
|
||||
`include "../../06_IO_Devices/GO.v"
|
||||
`include "../../06_IO_Devices/LCD.v"
|
||||
`include "../../06_IO_Devices/RTP.v"
|
12
06_IO_Devices/03_SPI/Makefile
Normal file
12
06_IO_Devices/03_SPI/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
NAME = cat
|
||||
|
||||
all: asm install
|
||||
|
||||
asm:
|
||||
../../tools/Assembler/assembler.pyc $(NAME).asm
|
||||
install:
|
||||
cp $(NAME).hack ../00_HACK/ROM.hack
|
||||
clean:
|
||||
rm -f *.hack *~
|
||||
|
||||
.PHONY: all clean
|
119
06_IO_Devices/03_SPI/Readme.md
Normal file
119
06_IO_Devices/03_SPI/Readme.md
Normal file
@@ -0,0 +1,119 @@
|
||||
## 03 SPI
|
||||
|
||||
The special function register `SPI` memory mapped to address 4100 enables HACK to read/write bytes from the spi flash memory chip W25Q16BV situated on iCE40HX1K-EVB. The timing diagramm for SPI communication looks like the following diagram (we use CPOL=0 and CPHA=0).
|
||||
|
||||

|
||||
|
||||
### Chip specification
|
||||
|
||||
| IN/OUT | wire | function |
|
||||
| ------ | -------- | ------------------------------------------- |
|
||||
| IN | in[7:0] | byte to be sent. |
|
||||
| IN | in[8] | =1 send byte and set CSX low |
|
||||
| IN | in[8] | =0 pull CSX high without sending byte |
|
||||
| IN | load | =1 initiates the transmission, when in[8]=1 |
|
||||
| OUT | out[15] | =0 chip is busy, =0 chip is ready |
|
||||
| OUT | out[7:0] | received byte (when out[15]=0) |
|
||||
| OUT | CSX | chip select not |
|
||||
| OUT | SDO | serial data out |
|
||||
| OUT | SCK | serial clock |
|
||||
| IN | SDI | serial data in |
|
||||
|
||||
When load=1 and in[8]=0 transmission of byte in[7:0] is initiated. CSX is goes low (and stays low even when transmission is completed). The byte is send to SDO bitwise together with 8 clock signals on SCK. At the same time the SPI receives a byte at SDI. During transmission out[15] is 1. After 16 clock cycles the transmission of one byte is completed. out[15] goes low and SPI outputs the received byte to out[7:0].
|
||||
|
||||
When load=1 and in[8]=1 CSX goes high without transmission of any bit.
|
||||
|
||||
**Attention:** Sampling of SDO is done at rising edge of SCK and shifting is done at falling edge of SCK.
|
||||
|
||||
### Proposed Implementation
|
||||
|
||||
Use a `Bit` to store the state (0 = ready, 1 = busy) which is output to out[15]. Use a counter `PC` to count from 0 to 15. Finally we need a `BitShift8L`. This will be loaded with the byte in[7:0] to be send. Another `Bit` will sample the SDI wire when SCK=0 and shift the stored bit into the `BitShift8L` when SCK=1. After 8 bits are transmitted the module cleares out[15] and outputs the received byte to out[7:0].
|
||||
|
||||

|
||||
|
||||
### Memory map
|
||||
|
||||
The special function register `SPI` is mapped to memory map of HACK according to:
|
||||
|
||||
| address | I/O device | R/W | function |
|
||||
| ------- | ---------- | --- | ----------------------------------------- |
|
||||
| 4100 | SPI | R | out[15]=1 if busy, out[7:0] received byte |
|
||||
| 4100 | SPI | W | start transmittion of byte in[7:0] |
|
||||
|
||||
### cat.asm
|
||||
|
||||
To test HACK with SPI we need a little machine language programm `cat.asm`, which reads 4 consecutive bytes of SPI flash memory chip W25Q16BV of iCE40HX1K-EVB, starting at address 0x040000 (256k) and sends them to UART_TX.
|
||||
|
||||
According to the datasheet of spi flash rom chip W25Q16BV the commands needed to read the flash rom chip are:
|
||||
|
||||
| command | function |
|
||||
| ------------------- | ---------------------------------------------------------------------- |
|
||||
| 0xAB | wake up from deep power down (wait 3us) before launching next command. |
|
||||
| 0x03 0x04 0x00 0x00 | read data (command 0x03) starting at address 0x040000 (256k) |
|
||||
| 0xB9 | go in power down |
|
||||
|
||||
### SPI in real hardware
|
||||
|
||||
The board iCE40HX1K-EVB comes with a SPI flash rom chip W25Q16BV. The chip is already connected to iCE40HX1K according `iCE40HX1K-EVB.pcf` (Compare with schematic [iCE40HX1K_EVB](../../doc/iCE40HX1K-EVB_Rev_B.pdf).
|
||||
|
||||
```
|
||||
set_io SPI_SDO 45 # iCE40-SDO
|
||||
set_io SPI_SDI 46 # iCE40-SDI
|
||||
set_io SPI_SCK 48 # iCE40-SCK
|
||||
set_io SPI_CSX 49 # iCE40-SS_B
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
### Project
|
||||
|
||||
* Implement `SPI.v` and test with testbench:
|
||||
|
||||
```
|
||||
$ cd 03_SPI
|
||||
$ apio clean
|
||||
$ apio sim
|
||||
```
|
||||
|
||||
* Compare output `OUT` of special function tregister `SPI` with `CMP`.
|
||||
|
||||

|
||||
|
||||
* Add special function register`SPI` to `HACK.v` at memory address 4100.
|
||||
|
||||
* Implement `cat.asm` and test in simulation:
|
||||
|
||||
```
|
||||
$ cd 03_SPI
|
||||
$ make
|
||||
$ cd ../00_HACK
|
||||
$ apio clean
|
||||
$ apio sim
|
||||
```
|
||||
|
||||
* Check the wake up command 0xAB:
|
||||
|
||||

|
||||
|
||||
* Check command 0x03040000 (read from address 0x040000)
|
||||
|
||||

|
||||
|
||||
* Check reading of string "SPI!" output to UartTX.
|
||||
|
||||

|
||||
|
||||
* preload the SPI memory chip with some text file at address 0x040000.
|
||||
|
||||
* build and upload HACK with `cat.asm` in ROM.BIN to iCE40HX1K-EVB.
|
||||
|
||||
```
|
||||
$ echo SPI! > spi.txt
|
||||
$ iceprogduino -o 256k -w spi.txt
|
||||
$ cd 00_HACK
|
||||
$ apio clean
|
||||
$ apio upload
|
||||
$ tio /dev/ttyACM0
|
||||
```
|
||||
|
||||
* Check if you see "SPI!" in your terminal.
|
BIN
06_IO_Devices/03_SPI/SPI.dia
Normal file
BIN
06_IO_Devices/03_SPI/SPI.dia
Normal file
Binary file not shown.
BIN
06_IO_Devices/03_SPI/SPI.png
Normal file
BIN
06_IO_Devices/03_SPI/SPI.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
48
06_IO_Devices/03_SPI/SPI_tb.gtkw
Normal file
48
06_IO_Devices/03_SPI/SPI_tb.gtkw
Normal file
@@ -0,0 +1,48 @@
|
||||
[*]
|
||||
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
|
||||
[*] Fri Dec 30 13:39:55 2022
|
||||
[*]
|
||||
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/03_SPI/SPI_tb.vcd"
|
||||
[dumpfile_mtime] "Fri Dec 30 13:39:20 2022"
|
||||
[dumpfile_size] 238580
|
||||
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/03_SPI/SPI_tb.gtkw"
|
||||
[timestart] 0
|
||||
[size] 1606 597
|
||||
[pos] 88 59
|
||||
*-19.000000 107000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||
[sst_width] 281
|
||||
[signals_width] 160
|
||||
[sst_expanded] 1
|
||||
[sst_vpaned_height] 132
|
||||
@28
|
||||
SPI_tb.clk
|
||||
@200
|
||||
-IN
|
||||
@28
|
||||
SPI_tb.load
|
||||
@22
|
||||
SPI_tb.in[15:0]
|
||||
@28
|
||||
SPI_tb.SDI
|
||||
@200
|
||||
-OUT
|
||||
@28
|
||||
SPI_tb.CSX
|
||||
SPI_tb.SDO
|
||||
SPI_tb.SCK
|
||||
@22
|
||||
SPI_tb.out[15:0]
|
||||
@200
|
||||
-CMP
|
||||
@28
|
||||
SPI_tb.CSX_cmp
|
||||
SPI_tb.SDO_cmp
|
||||
SPI_tb.SCK_cmp
|
||||
@22
|
||||
SPI_tb.out_cmp[15:0]
|
||||
@200
|
||||
-Test
|
||||
@29
|
||||
SPI_tb.fail
|
||||
[pattern_trace] 1
|
||||
[pattern_trace] 0
|
81
06_IO_Devices/03_SPI/SPI_tb.v
Normal file
81
06_IO_Devices/03_SPI/SPI_tb.v
Normal file
@@ -0,0 +1,81 @@
|
||||
`timescale 10ns/1ns
|
||||
`default_nettype none
|
||||
|
||||
module SPI_tb();
|
||||
|
||||
// IN,OUT
|
||||
reg clk = 0;
|
||||
reg load = 0;
|
||||
reg [15:0] in = 0;
|
||||
wire [15:0] out;
|
||||
wire CSX;
|
||||
wire SDO;
|
||||
reg SDI=0;
|
||||
wire SCK;
|
||||
|
||||
// Part
|
||||
SPI SPI(
|
||||
.clk(clk),
|
||||
.load(load),
|
||||
.in(in),
|
||||
.out(out),
|
||||
.CSX(CSX),
|
||||
.SDO(SDO),
|
||||
.SDI(SDI),
|
||||
.SCK(SCK)
|
||||
);
|
||||
|
||||
// Simulate
|
||||
always #2 clk=~clk;
|
||||
wire trigger;
|
||||
assign trigger = (n==20) || (n==40) || (n==60) || (n==80) || (n==100);
|
||||
always @(posedge clk) begin
|
||||
in <= $random;
|
||||
load <= trigger;
|
||||
SDI <= $random;
|
||||
end
|
||||
|
||||
// Compare
|
||||
reg[4:0] bits=0;
|
||||
always @(posedge clk)
|
||||
bits <= (load&~in[8])?1:((bits==16)?0:(busy?bits+1:0));
|
||||
wire busy=|bits;
|
||||
wire [15:0] out_cmp = {busy,7'd0,shift};
|
||||
reg [7:0] shift=0;
|
||||
reg miso_s;
|
||||
always @(posedge clk)
|
||||
miso_s <= SDI;
|
||||
always @(posedge clk)
|
||||
shift <= load?in[7:0]:(~SCK_cmp?shift:{shift[6:0],miso_s});
|
||||
wire SCK_cmp=busy&~bits[0];
|
||||
reg CSX_cmp=1;
|
||||
always @(posedge clk)
|
||||
CSX_cmp<=load?in[8]:CSX_cmp;
|
||||
wire SDO_cmp=shift[7];
|
||||
reg fail = 0;
|
||||
reg [31:0] n = 0;
|
||||
task check;
|
||||
#4
|
||||
if ((out!=out_cmp)||(SCK!=SCK_cmp)||(SDO!=SDO_cmp)||(CSX!=CSX_cmp))
|
||||
begin
|
||||
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, CSX=%1b, SDO=%1b, SDI=%1b, SCK=%1b",clk,load,in,out,CSX,SDO,SDI,SCK);
|
||||
fail=1;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
$dumpfile("SPI_tb.vcd");
|
||||
$dumpvars(0, SPI_tb);
|
||||
|
||||
$display("------------------------");
|
||||
$display("Testbench: SPI");
|
||||
|
||||
for (n=0; n<400;n=n+1)
|
||||
check();
|
||||
|
||||
if (fail==0) $display("passed");
|
||||
$display("------------------------");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
3
06_IO_Devices/03_SPI/apio.ini
Normal file
3
06_IO_Devices/03_SPI/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
6
06_IO_Devices/03_SPI/cat.asm
Normal file
6
06_IO_Devices/03_SPI/cat.asm
Normal file
@@ -0,0 +1,6 @@
|
||||
// cat.asm
|
||||
//
|
||||
// load spi flash rom starting at address 0x040000 and write the
|
||||
// data to UART_TX
|
||||
//
|
||||
// Put your code here:
|
BIN
06_IO_Devices/03_SPI/echo.png
Normal file
BIN
06_IO_Devices/03_SPI/echo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
BIN
06_IO_Devices/03_SPI/spi-timing.png
Normal file
BIN
06_IO_Devices/03_SPI/spi-timing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 206 KiB |
BIN
06_IO_Devices/03_SPI/spi_read040000.png
Normal file
BIN
06_IO_Devices/03_SPI/spi_read040000.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
BIN
06_IO_Devices/03_SPI/spi_tb.png
Normal file
BIN
06_IO_Devices/03_SPI/spi_tb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
BIN
06_IO_Devices/03_SPI/spi_wakeup.png
Normal file
BIN
06_IO_Devices/03_SPI/spi_wakeup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
Reference in New Issue
Block a user