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