OpenCores
URL https://opencores.org/ocsvn/asynchronous_master_spi/asynchronous_master_spi/trunk

Subversion Repositories asynchronous_master_spi

[/] [asynchronous_master_spi/] [trunk/] [rtl/] [spi_master.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 morgothcre
`timescale 1ns / 1ps
2
////////////////////////////////////////////////////////////////////////////////
3
////                                                                        ////
4
//// Project Name: ASYNCHRONOUS SPI MASTER (Verilog)                        ////
5
////                                                                        ////
6
//// Module Name: spi_master                                                ////
7
////                                                                        ////
8
////                                                                        ////
9
////  Author(s):                                                            ////
10
////      Iulian Gheorghiu                                                  ////
11
////                                                                        ////
12
////  Create Date: 01/17/2017 11:21:57 AM                                   ////
13
////  Refer to simulate.v for more information                              ////
14
////  Revision 0.01 - File Created                                          ////
15
////                                                                        ////
16
////////////////////////////////////////////////////////////////////////////////
17
 
18
module spi_master(
19
        clk,/* Peripheral clock/not necessary to be core clock, the core clock can be different (input) */
20
        rst,/* Asynchronus reset, is mandatory to provide this signal, active on posedge (input) */
21
        data,/* In/Out data(bidirectional) */
22
        wr,/* Send data, asynchronus with 'clk' , active on posedge or negedge(input) */
23
        rd,/* Read data, , asynchronus with 'clk' , active on posedge or negedge (input) */
24
        buffempty,/* '1' if transmit buffer is empty (output) */
25
        prescaller,/* The prescaller divider is = (1 << prescaller) value between 0 and 7 for dividers by:1,2,4,8,16,32,64,128 and 256 (input)*/
26
        sck,/* SPI 'sck' signal (output) */
27
        mosi,/* SPI 'mosi' signal (output) */
28
        miso,/* SPI 'miso' signal (input) */
29
        ss,/* SPI 'ss' signal (if send buffer is maintained full the ss signal will not go high between between transmit chars)(output) */
30
        lsbfirst,/* If '0' msb is send first, if '1' lsb is send first (input) */
31
        mode,/* All four modes is supported (input) */
32
        senderr,/* If you try to send a character if send buffer is full this bit is set to '1', this can be ignored and if is '1' does not affect the interface (output) */
33
        res_senderr,/* To reset 'senderr' signal write '1' wait minimum half core clock and and after '0' to this bit, is asynchronous with 'clk' (input)*/
34
        charreceived/* Is set to '1' if a character is received, if you read the receive buffe this bit will go '0', if you ignore it and continue to send data this bit will remain '1' until you read the read register (output) */
35
    );
36
 
37
parameter WORD_LEN = 8;
38
parameter PRESCALLER_SIZE = 8;
39
 
40
input clk;
41
input rst;
42
inout [WORD_LEN - 1:0]data;
43
input wr;
44
input rd;
45
output buffempty;
46
input [2:0]prescaller;
47
output sck;
48
output mosi;
49
reg _mosi;
50
input miso;
51
output reg ss;
52
input lsbfirst;
53
input [1:0]mode;
54
output reg senderr;
55
input res_senderr;
56
output charreceived;
57
 
58
reg charreceivedp;
59
reg charreceivedn;
60
 
61
reg inbufffullp = 1'b0;
62
reg inbufffulln = 1'b0;
63
 
64
reg [WORD_LEN - 1:0]input_buffer;
65
reg [WORD_LEN - 1:0]output_buffer;
66
 
67
assign buffempty = ~(inbufffullp ^ inbufffulln);
68
reg [2:0]prescallerbuff;
69
/***********************************************/
70
/************* Asynchronus send ****************/
71
/***********************************************/
72
/*
73
 *  You need to put the data on the bus and wait a half of core clock to assert the wr signal(see simulation).
74
 */
75
`ifdef WRITE_ON_NEG_EDGE == 1
76
always @ (negedge wr)
77
`else
78
always @ (posedge wr)
79
`endif
80
begin
81
    if(wr && inbufffullp == inbufffulln && buffempty)
82
    begin
83
            input_buffer <= data;
84
    end
85
end
86
 
87
`ifdef WRITE_ON_NEG_EDGE == 1
88
always @ (negedge wr or posedge res_senderr or posedge rst)
89
`else
90
always @ (posedge wr or posedge res_senderr or posedge rst)
91
`endif
92
begin
93
    if(rst)
94
    begin
95
        inbufffullp <= 1'b0;
96
        senderr <= 1'b0;
97
        prescallerbuff <= 3'b000;
98
    end
99
    else
100
    if(res_senderr)
101
        senderr <= 1'b0;
102
    else
103
    if(wr && inbufffullp == inbufffulln && buffempty)
104
    begin
105
            inbufffullp <= ~inbufffullp;
106
            prescallerbuff = prescaller;
107
    end
108
    else
109
    if(!buffempty)
110
        senderr <= 1'b1;
111
end
112
/***********************************************/
113
/************ !Asynchronus send ****************/
114
/***********************************************/
115
parameter state_idle = 1'b0;
116
parameter state_busy = 1'b1;
117
reg state;
118
 
119
 
120
reg [PRESCALLER_SIZE - 1:0]prescaller_cnt;
121
reg [WORD_LEN - 1:0]shift_reg_out;
122
reg [WORD_LEN - 1:0]shift_reg_in;
123
reg [4:0]sckint;
124
//reg sckintn;
125
reg [2:0]prescallerint;
126
reg [7:0]prescdemux;
127
 
128
 
129
always @ (*)
130
begin
131
    if(prescallerint < PRESCALLER_SIZE)
132
    begin
133
        case(prescallerint)
134
        3'b000: prescdemux <= 8'b00000001;
135
        3'b001: prescdemux <= 8'b00000011;
136
        3'b010: prescdemux <= 8'b00000111;
137
        3'b011: prescdemux <= 8'b00001111;
138
        3'b100: prescdemux <= 8'b00011111;
139
        3'b101: prescdemux <= 8'b00111111;
140
        3'b110: prescdemux <= 8'b01111111;
141
        3'b111: prescdemux <= 8'b11111111;
142
        endcase
143
    end
144
    else
145
        prescdemux <= 8'b00000001;
146
end
147
 
148
reg lsbfirstint;
149
reg [1:0]modeint;
150
 
151
always @ (posedge clk or posedge rst)
152
begin
153
    if(rst)
154
    begin
155
        inbufffulln <= 1'b0;
156
        ss <= 1'b1;
157
        state <= state_idle;
158
        prescaller_cnt <= {PRESCALLER_SIZE{1'b0}};
159
        prescallerint <= {PRESCALLER_SIZE{3'b0}};
160
        shift_reg_out <= {WORD_LEN{1'b0}};
161
        shift_reg_in <= {WORD_LEN{1'b0}};
162
        sckint <=  {5{1'b0}};
163
        _mosi <= 1'b1;
164
        output_buffer <= {WORD_LEN{1'b0}};
165
        charreceivedp <= 1'b0;
166
        lsbfirstint <= 1'b0;
167
        modeint <= 2'b00;
168
    end
169
    else
170
    begin
171
        case(state)
172
        state_idle:
173
            begin
174
                if(inbufffullp != inbufffulln)
175
                begin
176
                    inbufffulln <= ~inbufffulln;
177
                    ss <= 1'b0;
178
                    prescaller_cnt <= {PRESCALLER_SIZE{1'b0}};
179
                    prescallerint <= prescallerbuff;
180
                    lsbfirstint <= lsbfirst;
181
                    modeint <= mode;
182
                    shift_reg_out <= input_buffer;
183
                    state <= state_busy;
184
                    if(!mode[0])
185
                    begin
186
                        if(!lsbfirst)
187
                            _mosi <= input_buffer[WORD_LEN - 1];
188
                        else
189
                            _mosi <= input_buffer[0];
190
                    end
191
                end
192
            end
193
        state_busy:
194
            begin
195
                if(prescaller_cnt != prescdemux)
196
                begin
197
                    prescaller_cnt <= prescaller_cnt + 1;
198
                end
199
                else
200
                begin
201
                    prescaller_cnt <= {PRESCALLER_SIZE{1'b0}};
202
                    sckint <= sckint + 1;
203
                    if(sckint[0] == modeint[0])
204
                    begin
205
                        if(!lsbfirstint)
206
                        begin
207
                            shift_reg_in <= {miso, shift_reg_in[7:1]};
208
                            shift_reg_out <= {shift_reg_out[6:0], 1'b1};
209
                        end
210
                        else
211
                        begin
212
                            shift_reg_in <= {shift_reg_in[6:0], miso};
213
                            shift_reg_out <= {1'b1, shift_reg_out[7:1]};
214
                        end
215
                    end
216
                    else
217
                    begin
218
                        if(!lsbfirstint)
219
                            _mosi <= shift_reg_out[WORD_LEN - 1];
220
                        else
221
                            _mosi <= shift_reg_out[0];
222
 
223
                        if(sckint[4:1] == WORD_LEN)
224
                        begin
225
                            sckint <= {5{1'b0}};
226
                            if(inbufffullp == inbufffulln)
227
                            begin
228
                                ss <= 1'b1;
229
                            end
230
                            output_buffer <= shift_reg_in;
231
                            if(charreceivedp == charreceivedn)
232
                                charreceivedp <= ~charreceivedp;
233
                            state <= state_idle;
234
                        end
235
                    end
236
                end
237
            end
238
        endcase
239
    end
240
end
241
/*
242
 *  You need to assert rd signal, wait a half core clock and after read the data(see simulation).
243
 */
244
`ifdef READ_ON_NEG_EDGE == 1
245
always @ (negedge rd or posedge rst)
246
`else
247
always @ (posedge rd or posedge rst)
248
`endif
249
begin
250
    if(rst)
251
        charreceivedn <= 1'b0;
252
    else
253
    if(charreceivedp != charreceivedn)
254
        charreceivedn <= ~charreceivedn;
255
end
256
 
257
assign data = (rd) ? output_buffer : {WORD_LEN{1'bz}};
258
 
259
assign sck = (modeint[1])? ~sckint : sckint;
260
assign mosi = (ss) ? 1'b1:_mosi;
261
assign charreceived = (charreceivedp ^ charreceivedn);
262
 
263
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.