source: PlatformSupport/CustomPeripherals/pcores/warp_spi_io_v1_00_a/hdl/verilog/warp_spi_io.v

Last change on this file was 1873, checked in by murphpo, 11 years ago

Attempting fix to SPI timing

File size: 4.6 KB
Line 
1
2module warp_spi_io (
3    input sys_clk,
4    input reset,
5    input go,
6    input [0:2]  clkDiv,
7
8    input [0:31] txData,
9
10    output reg [0:31] rxData1,
11    output reg [0:31] rxData2,
12    output reg [0:31] rxData3,
13    output reg [0:31] rxData4,
14
15    output done,
16
17    //Current bit index, in case user code needs to switch output enable mid-xfer
18    output [0:4] currBitNum,
19   
20    //SPI signals
21    output spi_mosi, //Master-out-slave-in serial data
22    output spi_cs,   //Active-high chip select
23    output spi_sclk, //Serial clock (masked by spi_cs)
24
25    input spi_miso1, //Dev 1 master-in-slave-out
26    input spi_miso2, //Dev 2 master-in-slave-out
27    input spi_miso3, //Dev 3 master-in-slave-out
28    input spi_miso4  //Dev 4 master-in-slave-out
29);
30
31parameter SPI_XFER_LEN = 5'd24;
32
33//Counter to generate SPI clock
34// Big enough that clkDiv can index any bit
35reg [0:7] spi_clk_counter;
36
37wire spi_clk;
38reg spi_clk_d1;
39wire spi_clk_pos, spi_clk_neg;
40
41reg go_d1;
42wire go_pos;
43
44reg [0:4] spi_xfer_counter;
45reg spi_xfer_running, spi_xfer_done;
46
47assign go_pos = go & ~go_d1;
48
49assign spi_cs = spi_xfer_running;
50assign currBitNum = spi_xfer_counter;
51assign done = spi_xfer_done;
52
53always @(posedge sys_clk)
54begin
55    if(reset == 1)
56        go_d1 <= 1'b0;
57    else if(spi_clk_neg)
58        go_d1 <= go;
59end
60
61//Free-running counter to generate SPI clock
62// 1 bit of this counter will be selected as the clock source
63always @(posedge sys_clk)
64begin
65    if(reset == 1)
66    begin
67        spi_clk_counter <= 6'b0;
68        spi_clk_d1 <= 1'b0;
69    end
70    else
71    begin
72        spi_clk_counter <= spi_clk_counter + 6'b000001;
73        spi_clk_d1 <= spi_clk;
74    end
75end
76
77//Select a bit of the counter to create the free-running clock
78// masked by an active SPI transfer
79//User code will mask again by per-device CS
80assign spi_clk = spi_clk_counter[clkDiv];
81assign spi_sclk = spi_clk & spi_xfer_running;
82
83//Rising/falling edges of spi clk for internal clk enables
84assign spi_clk_pos = (spi_clk & ~spi_clk_d1);
85assign spi_clk_neg = (~spi_clk & spi_clk_d1);
86
87
88//SPI transfer status signals
89// spi_xfer_running:
90//  Asserts when the user signals go
91//  De-asserts when the last SPI character bit is processed
92// spi_xfer_done
93//  Asserts after the last SPI character bit is processed
94//  De-asserts when a new SPI transaction starts
95always @(posedge sys_clk)
96begin
97    if(reset == 1)
98    begin
99        spi_xfer_running <= 1'b0;
100        spi_xfer_done <= 1'b0;
101    end
102    else if( go & (spi_xfer_counter < SPI_XFER_LEN) & spi_clk_neg)
103    begin       
104        spi_xfer_running <= 1'b1;
105        spi_xfer_done <= 1'b0;
106    end
107    else if(spi_xfer_counter >= SPI_XFER_LEN)
108    begin
109        spi_xfer_running <= 1'b0;
110        spi_xfer_done <= 1'b1;
111    end
112    else
113    begin
114        spi_xfer_running <= spi_xfer_running;
115        spi_xfer_done <= 1'b0;
116    end
117end
118
119//Bit-counter for SPI transactions
120// Counts from 0 to SPI_XFER_LEN, used to select the current Tx/Rx bit for serial I/O
121// Increments on the neg edge of the output SPI clock, so that output data is valid
122//  on the arriving rising edge of sclk at SPI slave devices
123always @(posedge sys_clk)
124begin
125    if((reset == 1) || spi_xfer_done)
126        spi_xfer_counter <= 5'b0;
127    else if (spi_xfer_counter >= (SPI_XFER_LEN))
128        spi_xfer_counter <= SPI_XFER_LEN;
129    else if (spi_xfer_running & spi_clk_neg)
130        spi_xfer_counter <= spi_xfer_counter + 1;
131    else
132        spi_xfer_counter <= spi_xfer_counter;
133end
134
135//Add 1 extra bit to txData, so the bit select below can safely select bit[32]
136wire [0:32] txData_safe;
137wire [4:0] data_bitSel;
138assign data_bitSel = spi_xfer_counter + (32-SPI_XFER_LEN);
139assign txData_safe = {txData, 1'b0};
140
141//SPI data out is one bit from txData
142// The least significant SPI_XFER_LEN bits of txData are used
143// Data is transmitted MSB first
144//Example: for SPI_XFER_LEN=24, txData[8:31] is used, with txData[8] sent first, txData[31] last
145assign spi_mosi = spi_xfer_running ? txData_safe[data_bitSel] : 1'b0;
146
147//Second condition used to be:
148// else if(spi_xfer_running & spi_rnw & (spi_xfer_counter >= SPI_FIRST_RXBIT) & spi_clk_freerun_neg)
149// Don't care about rnw at this level anymore (right?)
150//data capture used to be:
151//      if(~ad1_spi_cs_n)
152//          rxByte1[spi_xfer_counter - SPI_FIRST_RXBIT] <= ad1_spi_miso;
153           
154always @(posedge sys_clk)
155begin
156    if(reset == 1)
157    begin
158        rxData1 <= 32'b0;
159        rxData2 <= 32'b0;
160        rxData3 <= 32'b0;
161        rxData4 <= 32'b0;
162    end
163//  else if(spi_xfer_running & spi_clk_neg)
164    else if(spi_xfer_running & spi_clk_pos)
165    begin
166        rxData1[data_bitSel] <= spi_miso1;
167        rxData2[data_bitSel] <= spi_miso2;
168        rxData3[data_bitSel] <= spi_miso3;
169        rxData4[data_bitSel] <= spi_miso4;
170    end
171    else
172    begin
173        rxData1 <= rxData1;
174        rxData2 <= rxData2;
175        rxData3 <= rxData3;
176        rxData4 <= rxData4;
177    end
178end
179
180endmodule
Note: See TracBrowser for help on using the repository browser.