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

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [lloled.v] - Blame information for rev 34

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    lloled.v
4
//
5
// Project:     OpenArty, an entirely open SoC based upon the Arty platform
6
//
7 34 dgisselq
// Purpose:     This is a low-level SPI output (not input) controller
8
//              designed to command interactions between an upper level
9
//      controller and a PModOLEDrgb.  As a result, this is a one-bit
10
//      (traditional, not quad) SPI controller, it has no MISO input bits,
11
//      and it also controls a DCN bits (output data at active high, vs
12
//      output control at active low).
13 3 dgisselq
//
14 34 dgisselq
//      This particular implementation was taken from a low-level QSPI
15
//      controller.  For those who wish to compare, the low-level QSPI
16
//      controller is very similar to the low-level EQSPI controller that is
17
//      also a part of the OpenArty project.
18
//
19
//      Interfacing with the controller works as follows: If the controller
20
//      is idle, set the values you wish to send and strobe the i_wr bit.
21
//      Once the last bit has been committed to the interface, but before it
22
//      closes the connection by setting CS_N high, it will check the i_wr bit
23
//      again.  If that bit is high, the busy bit will be dropped for one
24
//      cycle, new data will be accepted, and the controller will continue
25
//      with the new(er) data as though it was still part of the last 
26
//      transmission (without lowering cs_n).
27
//
28 3 dgisselq
// Creator:     Dan Gisselquist, Ph.D.
29
//              Gisselquist Technology, LLC
30
//
31
////////////////////////////////////////////////////////////////////////////////
32
//
33
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
34
//
35
// This program is free software (firmware): you can redistribute it and/or
36
// modify it under the terms of  the GNU General Public License as published
37
// by the Free Software Foundation, either version 3 of the License, or (at
38
// your option) any later version.
39
//
40
// This program is distributed in the hope that it will be useful, but WITHOUT
41
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
42
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
43
// for more details.
44
//
45
// You should have received a copy of the GNU General Public License along
46
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
47
// target there if the PDF file isn't present.)  If not, see
48
// <http://www.gnu.org/licenses/> for a copy.
49
//
50
// License:     GPL, v3, as defined and found on www.gnu.org,
51
//              http://www.gnu.org/licenses/gpl.html
52
//
53
//
54
////////////////////////////////////////////////////////////////////////////////
55
`define OLED_IDLE       3'h0
56
`define OLED_START      3'h1
57
`define OLED_BITS       3'h2
58
`define OLED_READY      3'h3
59
`define OLED_STOP       3'h4
60
`define OLED_STOP_B     3'h5
61 34 dgisselq
`define OLED_STOP_C     3'h6
62 3 dgisselq
 
63
// Modes
64
`define OLED_MOD_SPI    2'b00
65
`define OLED_MOD_QOUT   2'b10
66
`define OLED_MOD_QIN    2'b11
67
 
68
module  lloled(i_clk,
69
                // Module interface
70
                i_wr, i_dbit, i_word, i_len, o_busy,
71
                // OLED interface
72
                o_sck, o_cs_n, o_mosi, o_dbit);
73
        parameter       CTRBITS = 8;
74
        input                   i_clk;
75
        // Chip interface
76
        //      Can send info
77
        //              i_wr = 1,
78
        //                      i_word = { 1'b0, 32'info to send },
79
        //                      i_len = # of bytes in word-1
80
        input                   i_wr, i_dbit;
81
        input           [31:0]   i_word;
82
        input           [1:0]    i_len;  // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits
83
        output  reg             o_busy;
84
        // Interface with the OLED lines
85
        output  reg             o_sck, o_cs_n, o_mosi, o_dbit;
86
 
87
        // Timing:
88
        //
89
        //      Tick    Clk     BSY/WR  CS_n    BIT/MO  STATE
90
        //       0      1       0/0     1        -      
91
        //       1      1       0/1     1        -
92
        //       2      1       1/0     0         -      OLED_START
93
        //       3      0        1/0     0         -      OLED_START
94
        //       4      0        1/0     0         0      OLED_BITS
95
        //       5      1       1/0     0         0      OLED_BITS
96
        //       6      0        1/0     0         1      OLED_BITS
97
        //       7      1       1/0     0         1      OLED_BITS
98
        //       8      0        1/0     0         2      OLED_BITS
99
        //       9      1       1/0     0         2      OLED_BITS
100
        //      10      0        1/0     0         3      OLED_BITS
101
        //      11      1       1/0     0         3      OLED_BITS
102
        //      12      0        1/0     0         4      OLED_BITS
103
        //      13      1       1/0     0         4      OLED_BITS
104
        //      14      0        1/0     0         5      OLED_BITS
105
        //      15      1       1/0     0         5      OLED_BITS
106
        //      16      0        1/0     0         6      OLED_BITS
107
        //      17      1       1/1     0         6      OLED_BITS
108
        //      18      0        1/1     0         7      OLED_READY
109
        //      19      1       0/1     0         7      OLED_READY
110
        //      20      0        1/0/V   0         8      OLED_BITS
111
        //      21      1       1/0     0         8      OLED_BITS
112
        //      22      0        1/0     0         9      OLED_BITS
113
        //      23      1       1/0     0         9      OLED_BITS
114
        //      24      0        1/0     0        10      OLED_BITS
115
        //      25      1       1/0     0        10      OLED_BITS
116
        //      26      0        1/0     0        11      OLED_BITS
117
        //      27      1       1/0     0        11      OLED_BITS
118
        //      28      0        1/0     0        12      OLED_BITS
119
        //      29      1       1/0     0        12      OLED_BITS
120
        //      30      0        1/0     0        13      OLED_BITS
121
        //      31      1       1/0     0        13      OLED_BITS
122
        //      32      0        1/0     0        14      OLED_BITS
123
        //      33      1       1/0     0        14      OLED_BITS
124
        //      34      0        1/0     0        15      OLED_READY
125
        //      35      1       1/0     0        15      OLED_READY
126
        //      36      1       1/0/V   0         -      OLED_STOP
127
        //      37      1       1/0     0         -      OLED_STOPB
128
        //      38      1       1/0     1        -      OLED_IDLE
129
        //      39      1       0/0     1        -
130
 
131
        reg     [5:0]    spi_len;
132
        reg     [31:0]   r_word;
133
        reg     [2:0]    state;
134
        initial state = `OLED_IDLE;
135
        initial o_sck   = 1'b1;
136
        initial o_cs_n  = 1'b1;
137
        initial o_mosi  = 1'b0;
138
        initial o_busy  = 1'b0;
139
 
140
        reg     [(CTRBITS-1):0]  counter;
141
        reg     last_counter, pre_last_counter;
142
        always @(posedge i_clk) // Clock cycle time > 150 ns > 300 ticks
143
                last_counter <= (counter == {{(CTRBITS-1){1'b0}},1'b1});
144
        always @(posedge i_clk)
145
                pre_last_counter <= (counter == {{(CTRBITS-2){1'b0}},2'b10});
146
        always @(posedge i_clk)
147
                if (state == `OLED_IDLE)
148
                        counter <= {(CTRBITS){1'b1}};
149
                else
150
                        counter <= counter + {(CTRBITS){1'b1}};
151
        always @(posedge i_clk)
152
                if ((state == `OLED_IDLE)&&(o_sck))
153
                begin
154
                        o_cs_n <= 1'b1;
155
                        o_busy  <= 1'b0;
156
                        r_word <= i_word;
157
                        spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
158
                        o_sck <= 1'b1;
159
                        o_dbit <= i_dbit;
160
                        if (i_wr)
161
                        begin
162
                                state <= `OLED_START;
163
                                o_cs_n <= 1'b0;
164
                                o_busy <= 1'b1;
165
                        end
166
                end else if (state == `OLED_START)
167
                begin // We come in here with sck high, stay here 'til sck is low
168
                        o_sck <= 1'b0;
169
                        if (o_sck == 1'b0)
170
                        begin
171
                                state <= `OLED_BITS;
172
                                spi_len<= spi_len - 6'h1;
173
                                r_word <= { r_word[30:0], 1'b0 };
174
                        end
175
                        o_cs_n <= 1'b0;
176
                        o_busy <= 1'b1;
177
                        o_mosi <= r_word[31];
178
                end else if (~last_counter)
179
                begin
180 34 dgisselq
                        o_busy <= (!pre_last_counter)||(!o_sck)
181
                                ||(state != `OLED_READY)||(~i_wr);
182 3 dgisselq
                end else if (~o_sck)
183
                begin
184
                        o_sck <= 1'b1;
185
                        o_busy <= 1'b1;
186
                end else if (state == `OLED_BITS)
187
                begin
188
                        // Should enter into here with at least a spi_len
189
                        // of one, perhaps more
190
                        o_sck <= 1'b0;
191
                        o_busy <= 1'b1;
192
                        o_mosi <= r_word[31];
193
                        r_word <= { r_word[30:0], 1'b0 };
194
                        spi_len <= spi_len - 6'h1;
195
                        if (spi_len == 6'h1)
196
                                state <= `OLED_READY;
197
                end else if (state == `OLED_READY)
198
                begin
199
                        o_cs_n <= 1'b0;
200
                        o_busy <= 1'b1;
201
                        // This is the state on the last clock (both low and
202
                        // high clocks) of the data.  Data is valid during
203
                        // this state.  Here we chose to either STOP or
204
                        // continue and transmit more.
205
                        o_sck <= 1'b0;
206
                        if((~o_busy)&&(i_wr))// Acknowledge a new request
207
                        begin
208
                                state <= `OLED_BITS;
209
                                o_busy <= 1'b1;
210
                                o_sck <= 1'b0;
211
 
212
                                // Set up the first bits on the bus
213
                                o_mosi <= i_word[31];
214
                                r_word <= { i_word[30:0], 1'b0 };
215
                                spi_len<= { 1'b0, i_len, 3'b111 };
216
 
217
                                // Read a bit upon any transition
218
                        end else begin
219
                                o_sck <= 1'b1;
220
                                state <= `OLED_STOP;
221
                                o_busy <= 1'b1;
222
                        end
223
                end else if (state == `OLED_STOP)
224
                begin
225
                        o_sck   <= 1'b1; // Stop the clock
226
                        o_busy  <= 1'b1; // Still busy till port is clear
227
                        state <= `OLED_STOP_B;
228 34 dgisselq
                end else if (state == `OLED_STOP_B)
229 3 dgisselq
                begin
230
                        o_cs_n <= 1'b1; // Deselect CS
231
                        o_sck <= 1'b1;
232
                        // Do I need this????
233
                        // spi_len <= 3; // Minimum CS high time before next cmd
234 34 dgisselq
                        state <= `OLED_STOP_C;
235
                        o_mosi <= 1'b1;
236
                        o_busy <= 1'b1;
237
                end else // if (state == `OLED_STOP_C)
238
                begin
239
                        // Keep us in idle for at least a full clock period.
240
                        o_cs_n <= 1'b1; // Deselect CS
241
                        o_sck <= 1'b1;
242
                        // Do I need this????
243
                        // spi_len <= 3; // Minimum CS high time before next cmd
244 3 dgisselq
                        state <= `OLED_IDLE;
245
                        o_mosi <= 1'b1;
246
                        o_busy <= 1'b1;
247
                end
248
                /*
249
                */
250
 
251
endmodule
252
 

powered by: WebSVN 2.1.0

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