Skip to content

Commit 77c2951

Browse files
committed
Added pwm generator with a gamma correction table.
This example fades two LEDs on the iCEBreaker board but uses a gamma correction lookup table. This makes the LEDs fade more evenly. Our eyesight is not linear but exponential, this means that if we fade the LEDs linearelly they will go from off to on very quickly and seem to be at a high brightness level for a very long time. The gamma correction makes it seem that we fade the led value more linearelly. :)
1 parent 2a5932a commit 77c2951

File tree

6 files changed

+184
-3
lines changed

6 files changed

+184
-3
lines changed

main.mk

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

22
all: $(PROJ).rpt $(PROJ).bin
33

4-
%.blif: %.v
4+
%.blif: %.v $(ADD_SRC) $(ADD_DEPS)
55
yosys -p 'synth_ice40 -top top -blif $@' $<
66

7-
%.json: %.v
7+
%.json: %.v $(ADD_SRC) $(ADD_DEPS)
88
yosys -p 'synth_ice40 -top top -json $@' $<
99

1010
ifeq ($(USE_NEXTPNR),)
@@ -45,7 +45,7 @@ sudo-prog: $(PROJ).bin
4545
sudo iceprog $<
4646

4747
clean:
48-
rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin $(PROJ).json
48+
rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin $(PROJ).json $(ADD_CLEAN)
4949

5050
.SECONDARY:
5151
.PHONY: all prog clean

pwm_fade_gamma/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
gen_gamma_table*
2+
gamma_table.hex

pwm_fade_gamma/COPYING

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright (C) 2018 Piotr Esden-Tempski <[email protected]>
2+
3+
Permission to use, copy, modify, and/or distribute this software for any
4+
purpose with or without fee is hereby granted, provided that the above
5+
copyright notice and this permission notice appear in all copies.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

pwm_fade_gamma/Makefile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
PROJ = gamma_pwm
2+
ADD_DEPS = gamma_table.hex
3+
ADD_CLEAN = *.o gen_gamma_table *.hex
4+
5+
PIN_DEF = ../icebreaker.pcf
6+
DEVICE = up5k
7+
8+
include ../main.mk
9+
10+
gen_gamma_table: gen_gamma_table.o
11+
gcc $< -o $@ -lm
12+
13+
gamma_table.hex: gen_gamma_table
14+
./gen_gamma_table > gamma_table.hex

pwm_fade_gamma/gamma_pwm.v

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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

pwm_fade_gamma/gen_gamma_table.c

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 program generates a gamma correction table. This table is then loaded
21+
// into bram of the FPGA to provide a lookup table.
22+
23+
#include <stdio.h>
24+
#include <math.h>
25+
26+
#define GAMMA 2.2
27+
28+
int main()
29+
{
30+
fprintf(stderr, "Generating the gamma lookup table.\n");
31+
32+
for (int i = 0; i < 256; i++) {
33+
double dvalue = pow((1.0 / 256.0) * i, GAMMA);
34+
long lvalue = 0xFFFFl * dvalue;
35+
36+
fprintf(stderr, ".");
37+
38+
if ((i % 8) == 0) {
39+
printf("%s@%08x ", (i != 0) ? "\n" : "", i);
40+
}
41+
printf("%04lX ", lvalue);
42+
//printf("%f\n", value);
43+
//printf("%5i | %f\n", i, value);
44+
}
45+
46+
fprintf(stderr, "\ndone\n");
47+
48+
return 0;
49+
}

0 commit comments

Comments
 (0)