1
+ /*
2
+ * icebreaker examples - gamma pwm demo
3
+ *
4
+ * Copyright (C) 2018 Piotr Esden-Tempski <[email protected] >
5
+ *
6
+ * Permission to use, copy, modify, and/or distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ *
18
+ */
19
+
20
+ // This example generates PWM with gamma correction
21
+ // The intended result is opposite pulsating Red and Green LEDs
22
+ // on the iCEBreaker. The intended effect is that the two LED "breathe" evenly
23
+ // and don't stay at a perceptable brightness level longer than others.
24
+ //
25
+ // For more information about gamma correction:
26
+ // https://en.wikipedia.org/wiki/Gamma_correction
27
+
28
+ module top (
29
+ input CLK,
30
+ output LEDR_N,
31
+ output LEDG_N,
32
+ output P1A7,
33
+ output P1A8,
34
+ output P1A9
35
+ );
36
+
37
+ // Gamma value lookup table parameters
38
+ parameter G_PW = 8 ; // Number of input bits
39
+ parameter G_OW = 16 ; // Number of output bits
40
+
41
+ // Load the gamma value lookup table
42
+ reg [(G_OW- 1 ):0 ] gamma_lut [0 :((1 << (G_PW))- 1 )];
43
+ initial $readmemh ("gamma_table.hex" , gamma_lut);
44
+
45
+ // Very simple dual output PWM generator
46
+ // We need two outputs as we can't just invert the gamma corrected PWM output,
47
+ // as this would also invert the gamma curve.
48
+ reg [15 :0 ] pwm_counter = 0 ;
49
+ reg [15 :0 ] pwm_compare_0 = (1 << 15 ) / 2 ;
50
+ reg [15 :0 ] pwm_compare_1 = (1 << 15 ) / 2 ;
51
+ reg pwm_out_0;
52
+ reg pwm_out_1;
53
+ always @(posedge CLK) begin
54
+ pwm_counter <= pwm_counter + 1 ;
55
+
56
+ if (pwm_counter < pwm_compare_0) begin
57
+ pwm_out_0 <= 1 ;
58
+ end else begin
59
+ pwm_out_0 <= 0 ;
60
+ end
61
+
62
+ if (pwm_counter < pwm_compare_1) begin
63
+ pwm_out_1 <= 1 ;
64
+ end else begin
65
+ pwm_out_1 <= 0 ;
66
+ end
67
+ end
68
+
69
+ // PWM compare value generator
70
+ // Fade through the values using the gamma correction
71
+ reg [16 :0 ] pwm_inc_counter = 0 ;
72
+ reg [G_PW- 1 :0 ] pwm_value = 0 ;
73
+ reg pwm_dir = 1 ;
74
+ always @(posedge CLK) begin
75
+ // Divide clock by 131071
76
+ pwm_inc_counter <= pwm_inc_counter + 1 ;
77
+
78
+ // increment/decrement the index
79
+ if (pwm_inc_counter == 0 )
80
+ if (pwm_dir)
81
+ pwm_value <= pwm_value + 1 ;
82
+ else
83
+ pwm_value <= pwm_value - 1 ;
84
+
85
+ // Reverse directions when reaching the index extremes
86
+ if (pwm_value == ((1 << G_PW) - 1 ))
87
+ pwm_dir <= 0 ;
88
+ if (pwm_value == 0 )
89
+ pwm_dir <= 1 ;
90
+
91
+ if (pwm_inc_counter == 1 ) begin
92
+ pwm_compare_0 <= gamma_lut[pwm_value];
93
+ pwm_compare_1 <= gamma_lut[((1 << G_PW) - 1 ) - pwm_value];
94
+ end
95
+ end
96
+
97
+ assign LEDG_N = ~ pwm_out_0;
98
+ assign LEDR_N = ~ pwm_out_1;
99
+ assign P1A7 = pwm_counter[15 ];
100
+ assign P1A8 = pwm_out_0;
101
+ assign P1A9 = pwm_out_1;
102
+
103
+ endmodule
0 commit comments