1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
34
35
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
62
63
69
70
78
79
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
107
108
109
110
114
115
116
117
118
119
120
121
122
123
124
125
129
130
131
147
148
153
154
155
156
171
172
177
178
179
180
181
182
183
184
185
186
187
188
193
194
199
200
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
228
229
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* ... */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/sem.h"
#include "hardware/pio.h"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "ws2812.pio.h"
9 includes
#define FRAC_BITS 4
#define NUM_PIXELS 64
#define WS2812_PIN_BASE 2
static uint8_t *current_strip_out;
static bool current_strip_4color;
static inline void put_pixel(uint32_t pixel_grb) {
*current_strip_out++ = pixel_grb & 0xffu;
*current_strip_out++ = (pixel_grb >> 8u) & 0xffu;
*current_strip_out++ = (pixel_grb >> 16u) & 0xffu;
if (current_strip_4color) {
*current_strip_out++ = 0;
}if (current_strip_4color) { ... }
}{ ... }
static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
return
((uint32_t) (r) << 8) |
((uint32_t) (g) << 16) |
(uint32_t) (b);
}{ ... }
void pattern_snakes(uint len, uint t) {
for (uint i = 0; i < len; ++i) {
uint x = (i + (t >> 1)) % 64;
if (x < 10)
put_pixel(urgb_u32(0xff, 0, 0));
else if (x >= 15 && x < 25)
put_pixel(urgb_u32(0, 0xff, 0));
else if (x >= 30 && x < 40)
put_pixel(urgb_u32(0, 0, 0xff));
else
put_pixel(0);
}for (uint i = 0; i < len; ++i) { ... }
}{ ... }
void pattern_random(uint len, uint t) {
if (t % 8)
return;
for (uint i = 0; i < len; ++i)
put_pixel(rand());
}{ ... }
void pattern_sparkle(uint len, uint t) {
if (t % 8)
return;
for (uint i = 0; i < len; ++i)
put_pixel(rand() % 16 ? 0 : 0xffffffff);
}{ ... }
void pattern_greys(uint len, uint t) {
uint max = 100;
t %= max;
for (uint i = 0; i < len; ++i) {
put_pixel(t * 0x10101);
if (++t >= max) t = 0;
}for (uint i = 0; i < len; ++i) { ... }
}{ ... }
void pattern_solid(uint len, uint t) {
t = 1;
for (uint i = 0; i < len; ++i) {
put_pixel(t * 0x10101);
}for (uint i = 0; i < len; ++i) { ... }
}{ ... }
int level = 8;
void pattern_fade(uint len, uint t) {
uint shift = 4;
uint max = 16;
max <<= shift;
uint slow_t = t / 32;
slow_t = level;
slow_t %= max;
static int error = 0;
slow_t += error;
error = slow_t & ((1u << shift) - 1);
slow_t >>= shift;
slow_t *= 0x010101;
for (uint i = 0; i < len; ++i) {
put_pixel(slow_t);
}for (uint i = 0; i < len; ++i) { ... }
}{ ... }
typedef void (*pattern)(uint len, uint t);
const struct {
pattern pat;
const char *name;
...} pattern_table[] = {
{pattern_snakes, "Snakes!"},
{pattern_random, "Random data"},
{pattern_sparkle, "Sparkles"},
{pattern_greys, "Greys"},
...};
#define VALUE_PLANE_COUNT (8 + FRAC_BITS)
typedef struct {
uint32_t planes[VALUE_PLANE_COUNT];
...} value_bits_t;
void add_error(value_bits_t *d, const value_bits_t *s, const value_bits_t *e) {
uint32_t carry_plane = 0;
for (int p = VALUE_PLANE_COUNT - 1; p >= 8; p--) {
uint32_t e_plane = e->planes[p];
uint32_t s_plane = s->planes[p];
d->planes[p] = (e_plane ^ s_plane) ^ carry_plane;
carry_plane = (e_plane & s_plane) | (carry_plane & (s_plane ^ e_plane));
}for (int p = VALUE_PLANE_COUNT - 1; p >= 8; p--) { ... }
for (int p = 7; p >= 0; p--) {
uint32_t s_plane = s->planes[p];
d->planes[p] = s_plane ^ carry_plane;
carry_plane &= s_plane;
}for (int p = 7; p >= 0; p--) { ... }
}{ ... }
typedef struct {
uint8_t *data;
uint data_len;
uint frac_brightness;
...} strip_t;
void transform_strips(strip_t **strips, uint num_strips, value_bits_t *values, uint value_length,
uint frac_brightness) {
for (uint v = 0; v < value_length; v++) {
memset(&values[v], 0, sizeof(values[v]));
for (uint i = 0; i < num_strips; i++) {
if (v < strips[i]->data_len) {
uint32_t value = (strips[i]->data[v] * strips[i]->frac_brightness) >> 8u;
value = (value * frac_brightness) >> 8u;
for (int j = 0; j < VALUE_PLANE_COUNT && value; j++, value >>= 1u) {
if (value & 1u) values[v].planes[VALUE_PLANE_COUNT - 1 - j] |= 1u << i;
}for (int j = 0; j < VALUE_PLANE_COUNT && value; j++, value >>= 1u) { ... }
}if (v < strips[i]->data_len) { ... }
}for (uint i = 0; i < num_strips; i++) { ... }
}for (uint v = 0; v < value_length; v++) { ... }
}{ ... }
void dither_values(const value_bits_t *colors, value_bits_t *state, const value_bits_t *old_state, uint value_length) {
for (uint i = 0; i < value_length; i++) {
add_error(state + i, colors + i, old_state + i);
}for (uint i = 0; i < value_length; i++) { ... }
}{ ... }
static value_bits_t colors[NUM_PIXELS * 4];
static value_bits_t states[2][NUM_PIXELS * 4];
static uint8_t strip0_data[NUM_PIXELS * 3];
static uint8_t strip1_data[NUM_PIXELS * 4];
strip_t strip0 = {
.data = strip0_data,
.data_len = sizeof(strip0_data),
.frac_brightness = 0x40,
...};
strip_t strip1 = {
.data = strip1_data,
.data_len = sizeof(strip1_data),
.frac_brightness = 0x100,
...};
strip_t *strips[] = {
&strip0,
&strip1,
...};
#define DMA_CHANNEL 0
#define DMA_CB_CHANNEL 1
#define DMA_CHANNEL_MASK (1u << DMA_CHANNEL)
#define DMA_CB_CHANNEL_MASK (1u << DMA_CB_CHANNEL)
#define DMA_CHANNELS_MASK (DMA_CHANNEL_MASK | DMA_CB_CHANNEL_MASK)
5 defines
static uintptr_t fragment_start[NUM_PIXELS * 4 + 1];
static struct semaphore reset_delay_complete_sem;
alarm_id_t reset_delay_alarm_id;
int64_t reset_delay_complete(__unused alarm_id_t id, __unused void *user_data) {
reset_delay_alarm_id = 0;
sem_release(&reset_delay_complete_sem);
return 0;
}{ ... }
void __isr dma_complete_handler() {
if (dma_hw->ints0 & DMA_CHANNEL_MASK) {
dma_hw->ints0 = DMA_CHANNEL_MASK;
if (reset_delay_alarm_id) cancel_alarm(reset_delay_alarm_id);
reset_delay_alarm_id = add_alarm_in_us(400, reset_delay_complete, NULL, true);
}if (dma_hw->ints0 & DMA_CHANNEL_MASK) { ... }
}{ ... }
void dma_init(PIO pio, uint sm) {
dma_claim_mask(DMA_CHANNELS_MASK);
dma_channel_config channel_config = dma_channel_get_default_config(DMA_CHANNEL);
channel_config_set_dreq(&channel_config, pio_get_dreq(pio, sm, true));
channel_config_set_chain_to(&channel_config, DMA_CB_CHANNEL);
channel_config_set_irq_quiet(&channel_config, true);
dma_channel_configure(DMA_CHANNEL,
&channel_config,
&pio->txf[sm],
NULL,
8,
false);
dma_channel_config chain_config = dma_channel_get_default_config(DMA_CB_CHANNEL);
dma_channel_configure(DMA_CB_CHANNEL,
&chain_config,
&dma_channel_hw_addr(
DMA_CHANNEL)->al3_read_addr_trig,
NULL,
1,
false);
irq_set_exclusive_handler(DMA_IRQ_0, dma_complete_handler);
dma_channel_set_irq0_enabled(DMA_CHANNEL, true);
irq_set_enabled(DMA_IRQ_0, true);
}{ ... }
void output_strips_dma(value_bits_t *bits, uint value_length) {
for (uint i = 0; i < value_length; i++) {
fragment_start[i] = (uintptr_t) bits[i].planes;
}for (uint i = 0; i < value_length; i++) { ... }
fragment_start[value_length] = 0;
dma_channel_hw_addr(DMA_CB_CHANNEL)->al3_read_addr_trig = (uintptr_t) fragment_start;
}{ ... }
int main() {
stdio_init_all();
puts("WS2812 parallel");
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_parallel_program);
ws2812_parallel_program_init(pio, sm, offset, WS2812_PIN_BASE, count_of(strips), 800000);
sem_init(&reset_delay_complete_sem, 1, 1);
dma_init(pio, sm);
int t = 0;
while (1) {
int pat = rand() % count_of(pattern_table);
int dir = (rand() >> 30) & 1 ? 1 : -1;
if (rand() & 1) dir = 0;
puts(pattern_table[pat].name);
puts(dir == 1 ? "(forward)" : dir ? "(backward)" : "(still)");
int brightness = 0;
uint current = 0;
for (int i = 0; i < 1000; ++i) {
current_strip_out = strip0.data;
current_strip_4color = false;
pattern_table[pat].pat(NUM_PIXELS, t);
current_strip_out = strip1.data;
current_strip_4color = true;
pattern_table[pat].pat(NUM_PIXELS, t);
transform_strips(strips, count_of(strips), colors, NUM_PIXELS * 4, brightness);
dither_values(colors, states[current], states[current ^ 1], NUM_PIXELS * 4);
sem_acquire_blocking(&reset_delay_complete_sem);
output_strips_dma(states[current], NUM_PIXELS * 4);
current ^= 1;
t += dir;
brightness++;
if (brightness == (0x20 << FRAC_BITS)) brightness = 0;
}for (int i = 0; i < 1000; ++i) { ... }
memset(&states, 0, sizeof(states));
}while (1) { ... }
}{ ... }