-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdostring_wave.v
369 lines (318 loc) · 11.2 KB
/
dostring_wave.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
// This is the workhorse for creating the colorful sine waves.
// I am attempting to do everything on the fly, which would
// eliminate the need for multiple buffers.
// Each iteration of the wand will be created on the fly using
// an artistic sine wave approach. Colors will be based on sinasuidal
// rotation of values of the primary colors. Each of red, green, and blue
// will rotate based on ascend, then descend, then flat, then ascend and so on.
// As wand moves by, you would see via persistance of vision a sine wave. Above
// of sine wave would be one set of changing colors; sine wave itself would be
// white. Then below the sine wave would be another set of changing colors.
module dostring_wave (
output wire led1,
output wire led2,
output wire mosi,
output wire sck,
input wire dostring_reset,
input wire dostring_clk
);
// Each string needs special data at the beginning and the end, otherwise
// data is tri-color data for each led in the string
localparam
STRING_START = 0,
STRING_INSIDE = 1,
STRING_END = 2;
// Overall state of string operation. We have to wait for the SPI data processing
// out to the wand itself. This is slower than the main clock of 100 mhz.
// All operations are governed by this state table. This is the 'outer' state table
// and all others are nested inside this one.
localparam
STR_WAIT_FOR_LED = 0,
STR_LOAD_COLORS = 1,
STR_SEND_COLORS = 2,
STR_CHECK_COUNTERS = 3,
STR_CLEAR_START = 4,
STR_INCREMENT_WAND_COUNTERS = 5,
STR_SET_THE_SEGMENT_TO_START_SEGMENT = 6;
// Which color segment are we on?
// Goes from 0 for purple to COLOR_SEGMENT_NUMBER for red
reg[7:0] color_segment_count;
// Where in color segment are we?
// Goes from 0 to COLOR_SEGMENT_SIZE
reg[7:0] color_segment_position;
// Where in the segment shall we start this string
reg[7:0] start_in_segment;
// Which segment to start in
reg[7:0] which_segment_to_start;
// Begin and end are special data; inside is normal tri color data
reg[1:0] string_state;
// LED SPI data rate is low, we need to wait, then load data, then start send
reg[2:0] led_send_state;
// This is for the led output module. There are three data types:
// First of string is a special start string data set,
// Then each LED is a tri-color data set, then
// End of string is a special data set.
localparam
INPUT_TYPE_START = 0,
INPUT_TYPE_LED = 1,
INPUT_TYPE_END = 2;
localparam STRING_SIZE = 47;
// localparam STRING_SIZE = 20; //DEBUG
localparam
COLOR_FULL_BRITE = 8'hf0,
COLOR_QUARTER_BRITE = 8'h40,
COLOR_HALF_BRITE = 8'h80,
COLOR_MIN_BRITE = 9'h02,
COLOR_THREE_QUARTER_BRITE = 8'hc0,
COLOR_SEGMENT_SIZE = 15,
COLOR_SEGMENT_NUMBER = 7;
localparam MAX_COLOR_VALUE = 200;
wire[7:0] blue_seg[COLOR_SEGMENT_NUMBER-1:0];
wire[7:0] green_seg[COLOR_SEGMENT_NUMBER-1:0];
wire[7:0] red_seg[COLOR_SEGMENT_NUMBER-1:0];
// Where in the string are we? This will repeat for each scan of the
// wand. Zero is at the joint between the wand and the handle.
// This is important because we need to send special data at the
// start of the wand and at the end of the wand, while sending normal
// led data for inside the wand
// This value is also checked to determine whether we are above, on, or
// below the sine wave on the wand
reg[7:0] create_string_count = 0;
// These three out values are the color elements that are fed to the
// wand's SPI output driver module
reg[7:0] blue_out = 0;
reg[7:0] green_out = 0;
reg[7:0] red_out = 0;
// This register is connected to the wand's SPI driver module. It tells
// the SPI driver to start sending the values to the wand.
reg led_start = 0;
// This tells the wand SPI driver what type of data, start, end, or LED
reg[1:0] input_type = INPUT_TYPE_START;
// This comes from the wand SPI driver. It indicates that the SPI driver
// is busy and that no data going to it should be changed, especially the
// red, blue, or green out registers.
wire doled_busy;
assign led1 = mosi;
assign led2 = sck;
// Rainbow color values for color arrays
// purple
assign blue_seg[0] = COLOR_HALF_BRITE;
assign green_seg[0] = COLOR_MIN_BRITE;
assign red_seg[0] = COLOR_HALF_BRITE;
// blue
assign blue_seg[1] = COLOR_FULL_BRITE;
assign green_seg[1] = COLOR_MIN_BRITE;
assign red_seg[1] = COLOR_MIN_BRITE;
// cyan
assign blue_seg[2] = COLOR_HALF_BRITE;
assign green_seg[2] = COLOR_HALF_BRITE;
assign red_seg[2] = COLOR_MIN_BRITE;
// green
assign blue_seg[3] = COLOR_MIN_BRITE;
assign green_seg[3] = COLOR_FULL_BRITE;
assign red_seg[3] = COLOR_MIN_BRITE;
// yellow
assign blue_seg[4] = COLOR_MIN_BRITE;
assign green_seg[4] = COLOR_HALF_BRITE;
assign red_seg[4] = COLOR_FULL_BRITE;
// orange
assign blue_seg[5] = COLOR_MIN_BRITE;
assign green_seg[5] = COLOR_QUARTER_BRITE;
assign red_seg[5] = COLOR_THREE_QUARTER_BRITE;
// red
assign blue_seg[6] = COLOR_MIN_BRITE;
assign green_seg[6] = COLOR_MIN_BRITE;
assign red_seg[6] = COLOR_FULL_BRITE;
// Instantiation of the doled module
doled doled_1 (
.blue_input(blue_out),
.green_input(green_out),
.red_input(red_out),
.type_input(input_type),
.doled_busy(doled_busy),
.doled_start(led_start),
.mosi(mosi),
.sck(sck),
.doled_reset(dostring_reset),
.doled_clk(dostring_clk)
);
always @ (posedge dostring_clk or posedge dostring_reset)
begin
if (dostring_reset)
begin
input_type <= INPUT_TYPE_START;
blue_out <= 0;
red_out <= 0;
green_out <= 0;
led_start <= 0;
string_state <= STRING_START;
led_send_state <= STR_WAIT_FOR_LED;
color_segment_count <= 0;
color_segment_position <= 0;
start_in_segment <= 0;
which_segment_to_start <= 0;
end
else
begin
// Outermost state machine; one that handles the SPI to the wand.
// All others must nest on this as this one is driven by the SPI
// signaling which is slower than the main system clock.
case (led_send_state)
STR_WAIT_FOR_LED:
// We cannot do much but sit and wait for the SPI to the wand
begin
if (~doled_busy)
begin
led_send_state <= STR_LOAD_COLORS;
end
end
STR_LOAD_COLORS:
begin
// SPI is done with previous LED. We are now free to load the color values
// This is the 2nd level nesting of state machine. This state machine is driven
// by whether we are at the start, end, or anywhere in the middle of the string
// sent to the wand. Beginning and ending data sets are special. Those in between
// are RGB LED values
case (string_state)
// Are we at begin, end, or middle of string?
STRING_START:
begin
input_type <= INPUT_TYPE_START;
blue_out <= 0;
green_out <= 0;
red_out <= 0;
end
STRING_END:
begin
input_type <= INPUT_TYPE_END;
blue_out <= 8'hff;
green_out <= 8'hff;
red_out <= 8'hff;
end
STRING_INSIDE:
begin
// This is the workhorse. Individual LED colors are set here
// The 3rd level nesting of state machine. This is driven by where
// we are on the wand; ie; how far are we from the beginning of the wand
// Where the handle is glued to the wand itself.
// Where we are in a segment and which segment we are in determine the
// color values
// set the color values
blue_out <= blue_seg[color_segment_count];
green_out <= green_seg[color_segment_count];
red_out <= red_seg[color_segment_count];
// Bump up color_segment_position
color_segment_position <= color_segment_position + 1;
// This is the input type
input_type <= INPUT_TYPE_LED;
end
default:
begin
input_type <= INPUT_TYPE_END;
blue_out <= 8'hff;
green_out <= 8'hff;
red_out <= 8'hff;
end
endcase // string_state
led_send_state <= STR_SEND_COLORS;
end // Done with loading the colors to the SPI
STR_SEND_COLORS:
begin
led_start <= 1; // Tell SPI to do it's thing
led_send_state <= STR_CHECK_COUNTERS;
end
STR_CHECK_COUNTERS:
begin
// First check the state of the string (begin, inside for LED, end)
if (create_string_count == 0)
begin
string_state <= STRING_START;
end
else if (create_string_count < STRING_SIZE)
begin
string_state <= STRING_INSIDE;
// and while we are still inside the string, check the segment position
// and bump up segment if we are at the end of the segment
if (color_segment_position >= COLOR_SEGMENT_SIZE)
begin
// Are we at the last segment? If so, go back to the start of the rainbow
if (color_segment_count >= COLOR_SEGMENT_NUMBER-1)
begin
color_segment_count <= 0;
end
else
begin
color_segment_count <= color_segment_count + 1;
end
color_segment_position <= 0;
end
else
begin
color_segment_position <= color_segment_position + 1;
end
end
else
begin
string_state <= STRING_END;
end
// Now bump up create_string_count now that we used it in this cycle
if (create_string_count < STRING_SIZE)
begin
create_string_count <= create_string_count + 1;
end
else
begin
create_string_count <= 0;
end
led_send_state <= STR_CLEAR_START;
end
STR_CLEAR_START:
// Now that we are two clock from starting the SPI, let's clear the
// led_start signal so that it won't repeat this LED when it is done
// with it
begin
led_start <= 0;
if (string_state == STRING_END)
// At end of string, set the next string start segment and position
// otherwise wait for SPI to finish and then output the next LED
begin
led_send_state <= STR_INCREMENT_WAND_COUNTERS;
end
else
begin
led_send_state <= STR_WAIT_FOR_LED;
end
end
STR_INCREMENT_WAND_COUNTERS:
begin
// Now determine the new segment start position and which segment
if (start_in_segment >= COLOR_SEGMENT_SIZE)
begin
// Switch segment to start in
if (which_segment_to_start >= COLOR_SEGMENT_NUMBER)
begin
// Go back to beginning of rainbow
which_segment_to_start <= 0;
end
else
begin
which_segment_to_start <= which_segment_to_start + 1;
end
start_in_segment <= 0;
end
else
begin
start_in_segment <= start_in_segment + 1;
end
led_send_state <= STR_SET_THE_SEGMENT_TO_START_SEGMENT;
end
STR_SET_THE_SEGMENT_TO_START_SEGMENT:
begin
color_segment_position <= start_in_segment;
color_segment_count <= which_segment_to_start;
led_send_state <= STR_WAIT_FOR_LED;
end
endcase // led_send_state
end
end
endmodule