1 /*
2  * Copyright (c) 2021, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 #include <zephyr/drivers/display.h>
10 #include <string.h>
11 
12 #define PIXEL_BIT(idx, val)  (val ? BIT(idx) : 0)
13 #define PIXEL_MASK(...)      (FOR_EACH_IDX(PIXEL_BIT, (|), __VA_ARGS__))
14 
15 static struct display_capabilities caps;
16 static uint8_t buf[5];
17 static const struct display_buffer_descriptor buf_desc = {
18 	.buf_size = sizeof(buf),
19 	.width    = 5,
20 	.height   = 5,
21 	.pitch    = 8,
22 };
23 
update_block_3x3(const struct device * dev)24 static void update_block_3x3(const struct device *dev)
25 {
26 	int ret;
27 	static const uint8_t small_bufs[][2] = {
28 		{ PIXEL_MASK(0, 1, 0) |
29 		  PIXEL_MASK(0, 1, 0) << 4,
30 		  PIXEL_MASK(0, 1, 0) },
31 		{ PIXEL_MASK(0, 0, 1) |
32 		  PIXEL_MASK(0, 1, 0) << 4,
33 		  PIXEL_MASK(1, 0, 0) },
34 		{ PIXEL_MASK(0, 0, 0) |
35 		  PIXEL_MASK(1, 1, 1) << 4,
36 		  PIXEL_MASK(0, 0, 0) },
37 		{ PIXEL_MASK(1, 0, 0) |
38 		  PIXEL_MASK(0, 1, 0) << 4,
39 		  PIXEL_MASK(0, 0, 1) },
40 	};
41 	static const struct display_buffer_descriptor small_buf_desc = {
42 		.buf_size = sizeof(small_bufs[0]),
43 		.width    = 3,
44 		.height   = 3,
45 		.pitch    = 4,
46 	};
47 
48 	for (int i = 0; i < 4 * ARRAY_SIZE(small_bufs); ++i) {
49 		k_sleep(K_MSEC(100));
50 
51 		ret = display_write(dev, 1, 1,
52 				    &small_buf_desc, small_bufs[i % 4]);
53 		if (ret < 0) {
54 			printk("display_write failed: %u/%d\n",
55 				__LINE__, ret);
56 		}
57 	}
58 }
59 
update_block_5x5(const struct device * dev)60 static void update_block_5x5(const struct device *dev)
61 {
62 	int ret;
63 
64 	buf[0] = PIXEL_MASK(0, 0, 0, 0, 1);
65 	buf[1] = PIXEL_MASK(0, 0, 0, 1, 1);
66 	buf[2] = PIXEL_MASK(0, 0, 1, 1, 1);
67 	buf[3] = PIXEL_MASK(0, 1, 1, 1, 1);
68 	buf[4] = PIXEL_MASK(1, 1, 1, 1, 1);
69 	ret = display_write(dev, 0, 0, &buf_desc, buf);
70 	if (ret < 0) {
71 		printk("display_write failed: %u/%d\n",
72 			__LINE__, ret);
73 	}
74 
75 	for (int i = 0; i < 4 * 5; ++i) {
76 		uint8_t tmp;
77 
78 		k_sleep(K_MSEC(100));
79 
80 		tmp = buf[0];
81 		buf[0] = buf[1];
82 		buf[1] = buf[2];
83 		buf[2] = buf[3];
84 		buf[3] = buf[4];
85 		buf[4] = tmp;
86 		ret = display_write(dev, 0, 0, &buf_desc, buf);
87 		if (ret < 0) {
88 			printk("display_write failed: %u/%d\n",
89 				__LINE__, ret);
90 		}
91 	}
92 }
93 
show_all_brightness_levels(const struct device * dev)94 static void show_all_brightness_levels(const struct device *dev)
95 {
96 	int ret;
97 	uint8_t brightness = 0;
98 
99 	do {
100 		--brightness;
101 		ret = display_set_brightness(dev, brightness);
102 		if (ret < 0) {
103 			printk("display_set_brightness failed: %u/%d\n",
104 				__LINE__, ret);
105 		}
106 
107 		k_sleep(K_MSEC(5));
108 	} while (brightness);
109 }
110 
update_through_framebuffer(const struct device * dev)111 static void update_through_framebuffer(const struct device *dev)
112 {
113 	uint8_t *framebuf = display_get_framebuffer(dev);
114 	uint8_t dimmed = 0;
115 	bool inc = false;
116 	enum {
117 		MIN_BRIGHTNESS = 0x0F,
118 		BLOCK_SIZE     = 5,
119 		STEPS          = BLOCK_SIZE - 1,
120 		RUNS           = 4
121 	};
122 
123 	if (!framebuf) {
124 		printk("frame buffer not available\n");
125 		return;
126 	}
127 
128 	/* Clear screen. */
129 	memset(framebuf, 0, caps.x_resolution * caps.y_resolution);
130 
131 	for (int i = 0; i < 1 + 3 * RUNS * STEPS; ++i) {
132 		k_sleep(K_MSEC(100));
133 
134 		for (uint8_t column = 0; column < BLOCK_SIZE; ++column) {
135 			for (uint8_t row = 0; row < BLOCK_SIZE; ++row) {
136 				uint8_t diff;
137 				uint8_t step = (0xFF - MIN_BRIGHTNESS) / STEPS;
138 
139 				/*
140 				 * Depending on the iteration, use different
141 				 * pixel values for:
142 				 * - vertical lines
143 				 */
144 				if (i < 1 * RUNS * STEPS) {
145 					diff = dimmed > column
146 					     ? dimmed - column
147 					     : column - dimmed;
148 				/*
149 				 * - horizontal lines
150 				 */
151 				} else if (i < 2 * RUNS * STEPS) {
152 					diff = dimmed > row
153 					     ? dimmed - row
154 					     : row - dimmed;
155 				/*
156 				 * - diagonal lines
157 				 */
158 				} else {
159 					uint8_t dist = column + row;
160 
161 					diff = 2 * dimmed > dist
162 					     ? 2 * dimmed - dist
163 					     : dist - 2 * dimmed;
164 					step /= 2;
165 				}
166 
167 				framebuf[column + row * caps.x_resolution] =
168 					MIN_BRIGHTNESS + diff * step;
169 			}
170 		}
171 
172 		if (dimmed == 0 || dimmed == STEPS) {
173 			inc = !inc;
174 		}
175 		if (inc) {
176 			++dimmed;
177 		} else {
178 			--dimmed;
179 		}
180 	}
181 }
182 
main(void)183 int main(void)
184 {
185 	printk("nRF LED matrix sample on %s\n", CONFIG_BOARD);
186 
187 	int ret;
188 	const struct device *const dev = DEVICE_DT_GET_ONE(nordic_nrf_led_matrix);
189 
190 	if (!dev) {
191 		printk("Display device not ready\n");
192 		return 0;
193 	}
194 
195 	display_get_capabilities(dev, &caps);
196 	if (!(caps.supported_pixel_formats & PIXEL_FORMAT_MONO01)) {
197 		printk("Expected pixel format not supported\n");
198 		return 0;
199 	}
200 
201 	ret = display_set_pixel_format(dev, PIXEL_FORMAT_MONO01);
202 	if (ret < 0) {
203 		printk("display_set_pixel_format failed: %u/%d\n",
204 			__LINE__, ret);
205 	}
206 
207 	printk("Started\n");
208 
209 	for (;;) {
210 		ret = display_set_brightness(dev, 0x7F);
211 		if (ret < 0) {
212 			printk("display_set_brightness failed: %u/%d\n",
213 				__LINE__, ret);
214 		}
215 
216 		buf[0] = PIXEL_MASK(1, 0, 1, 0, 1);
217 		buf[1] = PIXEL_MASK(1, 1, 0, 0, 1);
218 		buf[2] = PIXEL_MASK(1, 0, 1, 0, 1);
219 		buf[3] = PIXEL_MASK(1, 0, 0, 1, 1);
220 		buf[4] = PIXEL_MASK(1, 0, 1, 0, 1);
221 		ret = display_write(dev, 0, 0, &buf_desc, buf);
222 		if (ret < 0) {
223 			printk("display_write failed: %u/%d\n",
224 				__LINE__, ret);
225 		}
226 
227 		ret = display_blanking_off(dev);
228 		if (ret < 0) {
229 			printk("display_blanking_off failed: %u/%d\n",
230 				__LINE__, ret);
231 		}
232 
233 		k_sleep(K_MSEC(500));
234 
235 		update_block_3x3(dev);
236 
237 		k_sleep(K_MSEC(500));
238 
239 		update_block_5x5(dev);
240 
241 		k_sleep(K_MSEC(200));
242 
243 		ret = display_blanking_on(dev);
244 		if (ret < 0) {
245 			printk("display_blanking_on failed: %u/%d\n",
246 				__LINE__, ret);
247 		}
248 
249 		k_sleep(K_MSEC(500));
250 
251 		ret = display_blanking_off(dev);
252 		if (ret < 0) {
253 			printk("display_blanking_off failed: %u/%d\n",
254 				__LINE__, ret);
255 		}
256 
257 		k_sleep(K_MSEC(500));
258 
259 		show_all_brightness_levels(dev);
260 
261 		update_through_framebuffer(dev);
262 
263 		k_sleep(K_MSEC(500));
264 	}
265 	return 0;
266 }
267