-
Notifications
You must be signed in to change notification settings - Fork 1
/
led_ctrl.sv
202 lines (181 loc) · 5.75 KB
/
led_ctrl.sv
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
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Mike Evans
//
// Create Date: 01/15/2017 09:34:59 PM
// Design Name: Arty LED Test Control Module
// Module Name: led_ctrl
// Project Name: Arty LED Test
// Target Devices: Digilient Arty Dev Board
// Tool Versions: Vivado 2016.4
// Description: This module controls the LED's colors and brightness levels.
//
// Dependencies: led_top.sv, debounce.sv, Arty_sw_btn_led.xdc (constraints file, 1/1)
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module led_ctrl(
input resetn,
input sclk,
input [3:0] sw,
input [3:0] btn,
output logic [3:0] led,
output logic led0_r,
output logic led0_g,
output logic led0_b,
output logic led1_r,
output logic led1_g,
output logic led1_b,
output logic led2_r,
output logic led2_g,
output logic led2_b,
output logic led3_r,
output logic led3_g,
output logic led3_b
);
/*
wire [3:0] led_temp = sw | btn;
always_ff @(posedge sclk) begin
led <= led_temp;
end
*/
typedef struct packed{
logic r;
logic g;
logic b;
} color_led__st;
color_led__st color_led__s[4];
color_led__st color_led_duty_cycled__s[4];
color_led__st red__s;
color_led__st green__s;
color_led__st blue__s;
color_led__st purple__s;
color_led__st yellow__s;
color_led__st cyan__s;
assign red__s = color_led__st'{1'b1, 1'b0, 1'b0};
assign green__s = color_led__st'{1'b0, 1'b1, 1'b0};
assign blue__s = color_led__st'{1'b0, 1'b0, 1'b1};
assign purple__s = color_led__st'{1'b1, 1'b0, 1'b1};
assign yellow__s = color_led__st'{1'b1, 1'b1, 1'b0};
assign cyan__s = color_led__st'{1'b0, 1'b1, 1'b1};
assign {led0_r, led0_g, led0_b} = {color_led_duty_cycled__s[0].r, color_led_duty_cycled__s[0].g, color_led_duty_cycled__s[0].b};
assign {led1_r, led1_g, led1_b} = {color_led_duty_cycled__s[1].r, color_led_duty_cycled__s[1].g, color_led_duty_cycled__s[1].b};
assign {led2_r, led2_g, led2_b} = {color_led_duty_cycled__s[2].r, color_led_duty_cycled__s[2].g, color_led_duty_cycled__s[2].b};
assign {led3_r, led3_g, led3_b} = {color_led_duty_cycled__s[3].r, color_led_duty_cycled__s[3].g, color_led_duty_cycled__s[3].b};
logic button_status[4];
logic button_toggled[4];
always_ff @(posedge sclk) begin
for(int i = 0; i < 4; i++) begin
if(button_toggled[i]) begin
button_status[i] <= 1'b0;
button_toggled[i] <= 1'b0;
end
else if(btn[i]) begin //Initial push
button_status[i] <= 1'b1;
button_toggled[i] <= 1'b0;
end
else if(!btn[i] && button_status[i]) begin
button_status[i] <= 1'b0;
button_toggled[i] <= 1'b1;
end
end
end
parameter RED = 3'd0;
parameter GREEN = 3'd1;
parameter BLUE = 3'd2;
parameter PURPLE = 3'd3;
parameter YELLOW = 3'd4;
parameter CYAN = 3'd5;
logic [2:0] color_state[4];
logic [2:0] next_color_state[4];
always_comb begin
for(int i = 0; i < 4; i++) begin
unique case (color_state[i])
RED: begin
color_led__s[i] = red__s;
next_color_state[i] = GREEN;
end
GREEN: begin
color_led__s[i] = green__s;
next_color_state[i] = BLUE;
end
BLUE: begin
color_led__s[i] = blue__s;
next_color_state[i] = PURPLE;
end
PURPLE: begin
color_led__s[i] = purple__s;
next_color_state[i] = YELLOW;
end
YELLOW: begin
color_led__s[i] = yellow__s;
next_color_state[i] = CYAN;
end
CYAN: begin
color_led__s[i] = cyan__s;
next_color_state[i] = RED;
end
default: begin
color_led__s[i] = 'dx;
next_color_state[i] = 'dx;
end
endcase
end
end
always_ff @(posedge sclk) begin
for(int i = 0; i < 4; i++) begin
if(!resetn) begin
color_state[i] <= 3'd0;
end
else if (button_toggled[i]) begin
color_state[i] <= next_color_state[i];
end
end
end
logic [3:0] clk_counter;
always_ff @(posedge sclk) begin
if(!resetn) clk_counter <= 'd0;
else clk_counter <= clk_counter + 1'b1; //Counts 0-15. Intentional roll-over.
end
//We need an exponential curve on our output to make the brightness controls more effective.
//The curve we want is approx 1.2^x.
//Cheapest way to do this is with a table, below
logic [3:0] sw_exp;
always_comb begin
unique case (sw)
'd15: sw_exp = 'd15;
'd14: sw_exp = 'd12;
'd13: sw_exp = 'd10;
'd12: sw_exp = 'd8;
'd11: sw_exp = 'd6;
'd10: sw_exp = 'd5;
'd9: sw_exp = 'd4;
'd8, 'd7: sw_exp = 'd3;
'd6, 'd5: sw_exp = 'd2;
'd4, 'd3, 'd2, 'd1: sw_exp = 'd1;
'd0: sw_exp = 'd0;
endcase
end
always_ff @(posedge sclk) begin
for(int i = 0; i < 4; i++) begin
if(!resetn) begin
color_led_duty_cycled__s[i].r <= 1'b1;
color_led_duty_cycled__s[i].g <= 1'b0;
color_led_duty_cycled__s[i].b <= 1'b1;
end
else if(clk_counter < sw_exp) begin
color_led_duty_cycled__s[i].r <= color_led__s[i].r | btn[i];
color_led_duty_cycled__s[i].g <= color_led__s[i].g | btn[i];
color_led_duty_cycled__s[i].b <= color_led__s[i].b | btn[i];
end
else begin
color_led_duty_cycled__s[i].r <= 1'b0;
color_led_duty_cycled__s[i].g <= 1'b0;
color_led_duty_cycled__s[i].b <= 1'b0;
end
end
end
endmodule