Working SPI
authorNicolas 'Pixel' Noble <nicolas@nobis-crew.org>
Sun, 14 Oct 2018 04:14:09 +0000 (21:14 -0700)
committerNicolas 'Pixel' Noble <nicolas@nobis-crew.org>
Sun, 14 Oct 2018 05:23:50 +0000 (22:23 -0700)
spi.v

diff --git a/spi.v b/spi.v
index 1027efdd42b9219a795c473f3e92ef49c9a96c3c..2c7b9bee5bf841397ef65dd3bae6bc218618a601 100644 (file)
--- a/spi.v
+++ b/spi.v
@@ -1,10 +1,13 @@
 module master_spi
 #(
-  parameter WIDTH = 8
+  parameter WIDTH = 8,
+  parameter CPOL = 0,
+  parameter CPHA = 0,
+  parameter LITTLE_ENDIAN = 0
 )
-
 (
   clk,
+  sclk,
   mosi,
   miso,
   ssel,
@@ -16,16 +19,17 @@ module master_spi
 );
 
 function integer log2;
-  input integer value;
+  input integer n;
   begin
-    value = value - 1;
-    for (log2 = 0; value > 0; log2 = log2 + 1) value = value >> 1;
+    n = n - 1;
+    for (log2 = 0; n > 0; log2 = log2 + 1) n = n >> 1;
   end
 endfunction
 
 input clk;
+output reg sclk = CPOL;
+output mosi;
 input miso;
-output reg mosi = 0;
 output reg ssel = 1;
 input [WIDTH-1:0] din;
 output [WIDTH-1:0] dout;
@@ -34,32 +38,45 @@ input r;
 input s;
 
 reg started = 0;
-reg [log2(WIDTH)-1:0] counter;
+reg [log2(WIDTH):0] counter;
 reg [WIDTH-1:0] sp_in = 0;
 reg [WIDTH-1:0] sp_out = 0;
+reg [1:0] cooldown = CPHA;
 
 assign dout = sp_out;
+assign mosi = sp_in[LITTLE_ENDIAN ? 0 : WIDTH-1];
 
 always @(posedge clk) begin
   if (r) begin
+    cooldown <= CPHA;
     started <= 0;
     done <= 0;
+    sclk <= CPOL;
     ssel <= 1;
   end else if (started) begin
     if (counter == 0) begin
-      ssel <= 1;
-      done <= 1;
-    end else begin
-      ssel <= 0;
-      mosi <= sp_in[WIDTH-1];
-      sp_in <= sp_in << 1;
-      sp_out <= (sp_out << 1) | miso;
+      if (sclk != CPOL) sclk <= ~sclk;
+      if (cooldown == 3) begin
+        done <= 1;
+      end else begin
+        cooldown <= cooldown + 1;
+        if (cooldown == 2) ssel <= 1;
+      end
+    end else if (sclk == (CPOL ^ CPHA)) begin // read cycle
+      if (LITTLE_ENDIAN) sp_out <= { miso, sp_out[WIDTH-1:1] };
+      else sp_out <= (sp_out << 1) | miso;
       counter <= counter - 1;
+      sclk <= ~sclk;
+    end else begin // write cycle
+      if (LITTLE_ENDIAN) sp_in <= sp_in >> 1;
+      else sp_in <= sp_in << 1;
+      sclk <= ~sclk;
     end
   end else if (s) begin
     sp_in <= din;
     sp_out <= 0;
     started <= 1;
+    ssel <= 0;
     counter <= WIDTH;
   end
 end