forked from osresearch/LEDscape
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatrix.p
473 lines (393 loc) · 11.8 KB
/
matrix.p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
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
270
271
272
273
274
275
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
// \file
/* PRU based 16x32 LED Matrix driver.
*
* Drives up to sixteen 16x32 matrices using the PRU hardware.
*
* Uses sixteen data pins in GPIO0 (one for each data line on each
* matrix) and six control pins in GPIO1 shared between all the matrices.
*
* The ARM writes a 24-bit color 512x16 into the shared RAM, sets the
* frame buffer pointer in the command structure and the PRU clocks it out
* to the sixteen matrices. Since there is no PWM in the matrix hardware,
* the PRU will cycle through various brightness levels. After each PWM
* cycle it rechecks the frame buffer pointer, allowing a glitch-free
* transition to a new frame.
*
* To pause the redraw loop, write a NULL to the buffer pointer.
* To shut down the PRU, write -1 to the buffer pointer.
*/
#define r11_gpio 2
#define r11_pin 2
#define g11_gpio 2
#define g11_pin 3
#define b11_gpio 2
#define b11_pin 5
#define r12_gpio 0
#define r12_pin 23
#define g12_gpio 2
#define g12_pin 4
#define b12_gpio 0
#define b12_pin 26
#define r21_gpio 0
#define r21_pin 27
#define g21_gpio 2
#define g21_pin 1
#define b21_gpio 0
#define b21_pin 22
#define r22_gpio 2
#define r22_pin 22
#define g22_gpio 2
#define g22_pin 23
#define b22_gpio 2
#define b22_pin 24
#define r31_gpio 0
#define r31_pin 30
#define g31_gpio 1
#define g31_pin 18
#define b31_gpio 0
#define b31_pin 31
#define r32_gpio 1
#define r32_pin 16
#define g32_gpio 0
#define g32_pin 3
#define b32_gpio 0 // not working?
#define b32_pin 5
#define r41_gpio 0
#define r41_pin 2
#define g41_gpio 0
#define g41_pin 15
#define b41_gpio 1
#define b41_pin 17
#define r42_gpio 3
#define r42_pin 21
#define g42_gpio 3
#define g42_pin 19
#define b42_gpio 0
#define b42_pin 4
#define r51_gpio 2
#define r51_pin 25
#define g51_gpio 0
#define g51_pin 11
#define b51_gpio 0
#define b51_pin 10
#define r52_gpio 0
#define r52_pin 9
#define g52_gpio 0
#define g52_pin 8
#define b52_gpio 2
#define b52_pin 17
#define r61_gpio 2
#define r61_pin 16
#define g61_gpio 2
#define g61_pin 15
#define b61_gpio 2
#define b61_pin 14
#define r62_gpio 2
#define r62_pin 13
#define g62_gpio 2
#define g62_pin 10
#define b62_gpio 2
#define b62_pin 12
#define r71_gpio 2
#define r71_pin 11
#define g71_gpio 2
#define g71_pin 9
#define b71_gpio 2
#define b71_pin 8
#define r72_gpio 2
#define r72_pin 6
#define g72_gpio 0
#define g72_pin 7
#define b72_gpio 2
#define b72_pin 7
#define r81_gpio 3
#define r81_pin 17
#define g81_gpio 3
#define g81_pin 16
#define b81_gpio 3
#define b81_pin 15
#define r82_gpio 3
#define r82_pin 14
#define g82_gpio 0
#define g82_pin 14
#define b82_gpio 0
#define b82_pin 20
#define CAT3(X,Y,Z) X##Y##Z
// Control pins are all in GPIO1
#define gpio1_sel0 12 /* must be sequential with sel1 and sel2 */
#define gpio1_sel1 13
#define gpio1_sel2 14
#define gpio1_sel3 15
#define gpio1_latch 28
#define gpio1_oe 29
#define gpio1_clock 19
/** Generate a bitmask of which pins in GPIO0-3 are used.
*
* \todo wtf "parameter too long": only 128 chars allowed?
*/
#define GPIO1_SEL_MASK (0\
|(1<<gpio1_sel0)\
|(1<<gpio1_sel1)\
|(1<<gpio1_sel2)\
|(1<<gpio1_sel3)\
)
.origin 0
.entrypoint START
#include "ws281x.hp"
/** Mappings of the GPIO devices */
#define GPIO0 (0x44E07000 + 0x100)
#define GPIO1 (0x4804c000 + 0x100)
#define GPIO2 (0x481AC000 + 0x100)
#define GPIO3 (0x481AE000 + 0x100)
/** Offsets for the clear and set registers in the devices.
* Since the offsets can only be 0xFF, we deliberately add offsets
*/
#define GPIO_CLRDATAOUT (0x190 - 0x100)
#define GPIO_SETDATAOUT (0x194 - 0x100)
/** Register map */
#define data_addr r0
#define width r1
#define row r2
#define bright r3
#define offset r4
#define out_clr r5 // must be one less than out_set
#define out_set r6
#define gpio0_set r6 // overloaded with out_set
#define gpio1_set r7
#define gpio2_set r8
#define gpio3_set r9
#define gpio0_led_mask r10
#define gpio1_led_mask r11
#define gpio2_led_mask r13
#define gpio3_led_mask r14
#define clock_pin r15
#define gpio0_base r16
#define gpio1_base r17
#define gpio2_base r18
#define gpio3_base r19
#define pixel_data r20 // the next 12 registers, too
#define BRIGHT_STEP 16
#define CLOCK_LO \
SBBO clock_pin, gpio1_base, GPIO_SETDATAOUT, 4; \
#define CLOCK_HI \
SBBO clock_pin, gpio1_base, GPIO_CLRDATAOUT, 4; \
#define LATCH_HI \
MOV out_set, 1 << gpio1_latch; \
SBBO out_set, gpio1_base, GPIO_SETDATAOUT, 4; \
#define LATCH_LO \
MOV out_clr, 1 << gpio1_latch; \
SBBO out_clr, gpio1_base, GPIO_CLRDATAOUT, 4; \
#define DISPLAY_OFF \
MOV out_set, 1 << gpio1_oe; \
SBBO out_set, gpio1_base, GPIO_SETDATAOUT, 4; \
#define DISPLAY_ON \
MOV out_set, 1 << gpio1_oe; \
SBBO out_set, gpio1_base, GPIO_CLRDATAOUT, 4; \
START:
// Enable OCP master port
// clear the STANDBY_INIT bit in the SYSCFG register,
// otherwise the PRU will not be able to write outside the
// PRU memory space and to the BeagleBon's pins.
LBCO r0, C4, 4, 4
CLR r0, r0, 4
SBCO r0, C4, 4, 4
// Configure the programmable pointer register for PRU0 by setting
// c28_pointer[15:0] field to 0x0120. This will make C28 point to
// 0x00012000 (PRU shared RAM).
MOV r0, 0x00000120
MOV r1, CTPPR_0
ST32 r0, r1
// Configure the programmable pointer register for PRU0 by setting
// c31_pointer[15:0] field to 0x0010. This will make C31 point to
// 0x80001000 (DDR memory).
MOV r0, 0x00100000
MOV r1, CTPPR_1
ST32 r0, r1
// Write a 0x1 into the response field so that they know we have started
MOV r2, #0x1
SBCO r2, CONST_PRUDRAM, 12, 4
// Wait for the start condition from the main program to indicate
// that we have a rendered frame ready to clock out. This also
// handles the exit case if an invalid value is written to the start
// start position.
MOV gpio0_base, GPIO0
MOV gpio1_base, GPIO1
MOV gpio2_base, GPIO2
MOV gpio3_base, GPIO3
MOV gpio0_led_mask, 0
MOV gpio1_led_mask, 0
MOV gpio2_led_mask, 0
MOV gpio3_led_mask, 0
#define GPIO_MASK(X) CAT3(gpio,X,_led_mask)
SET GPIO_MASK(r11_gpio), r11_pin
SET GPIO_MASK(g11_gpio), g11_pin
SET GPIO_MASK(b11_gpio), b11_pin
SET GPIO_MASK(r12_gpio), r12_pin
SET GPIO_MASK(g12_gpio), g12_pin
SET GPIO_MASK(b12_gpio), b12_pin
SET GPIO_MASK(r21_gpio), r21_pin
SET GPIO_MASK(g21_gpio), g21_pin
SET GPIO_MASK(b21_gpio), b21_pin
SET GPIO_MASK(r22_gpio), r22_pin
SET GPIO_MASK(g22_gpio), g22_pin
SET GPIO_MASK(b22_gpio), b22_pin
SET GPIO_MASK(r31_gpio), r31_pin
SET GPIO_MASK(g31_gpio), g31_pin
SET GPIO_MASK(b31_gpio), b31_pin
SET GPIO_MASK(r32_gpio), r32_pin
SET GPIO_MASK(g32_gpio), g32_pin
SET GPIO_MASK(b32_gpio), b32_pin
SET GPIO_MASK(r41_gpio), r41_pin
SET GPIO_MASK(g41_gpio), g41_pin
SET GPIO_MASK(b41_gpio), b41_pin
SET GPIO_MASK(r42_gpio), r42_pin
SET GPIO_MASK(g42_gpio), g42_pin
SET GPIO_MASK(b42_gpio), b42_pin
SET GPIO_MASK(r51_gpio), r51_pin
SET GPIO_MASK(g51_gpio), g51_pin
SET GPIO_MASK(b51_gpio), b51_pin
SET GPIO_MASK(r52_gpio), r52_pin
SET GPIO_MASK(g52_gpio), g52_pin
SET GPIO_MASK(b52_gpio), b52_pin
SET GPIO_MASK(r61_gpio), r61_pin
SET GPIO_MASK(g61_gpio), g61_pin
SET GPIO_MASK(b61_gpio), b61_pin
SET GPIO_MASK(r62_gpio), r62_pin
SET GPIO_MASK(g62_gpio), g62_pin
SET GPIO_MASK(b62_gpio), b62_pin
SET GPIO_MASK(r71_gpio), r71_pin
SET GPIO_MASK(g71_gpio), g71_pin
SET GPIO_MASK(b71_gpio), b71_pin
SET GPIO_MASK(r72_gpio), r72_pin
SET GPIO_MASK(g72_gpio), g72_pin
SET GPIO_MASK(b72_gpio), b72_pin
SET GPIO_MASK(r81_gpio), r81_pin
SET GPIO_MASK(g81_gpio), g81_pin
SET GPIO_MASK(b81_gpio), b81_pin
SET GPIO_MASK(r82_gpio), r82_pin
SET GPIO_MASK(g82_gpio), g82_pin
SET GPIO_MASK(b82_gpio), b82_pin
MOV clock_pin, 1 << gpio1_clock
READ_LOOP:
// Load the pointer to the buffer from PRU DRAM into r0 and the
// length (in pixels) into r1.
LBCO data_addr, CONST_PRUDRAM, 0, 8
// Wait for a non-zero command
QBEQ READ_LOOP, data_addr, #0
// Command of 0xFF is the signal to exit
QBEQ EXIT, data_addr, #0xFF
// scale the width into number of bytes that we will read
// 16 outputs * 3 bytes per output
/********
ADD offset, width, width
ADD offset, offset, width
LSL width, offset, 4
*/
MOV row, 0
NEW_ROW_LOOP:
// Disable output while we set the address
DISPLAY_OFF
// set address; select pins in gpio1 are sequential
// xor with the select bit mask to set which ones should
LSL out_set, row, gpio1_sel0
MOV out_clr, GPIO1_SEL_MASK
AND out_set, out_set, out_clr // ensure no extra bits
XOR out_clr, out_clr, out_set // complement the bits into clr
SBBO out_clr, gpio1_base, GPIO_CLRDATAOUT, 8 // set both
MOV bright, 0x100
ROW_LOOP:
// Re-start reading at the same row
MOV offset, 0
// Reset the latch pin; will be toggled at the end of the row
LATCH_LO
// compute where we are in the image
PIXEL_LOOP:
// Load the sixteen RGB outputs into
// consecutive registers, starting at pixel_data.
// This takes about 250 ns
LBBO pixel_data, data_addr, offset, 3*16
CLOCK_HI
MOV gpio0_set, 0
MOV gpio1_set, 0
MOV gpio2_set, 0
MOV gpio3_set, 0
#define GPIO(R) CAT3(gpio,R,_set)
#define OUTPUT_ROW(N,reg_r,reg_g,reg_b) \
QBGE skip_r##N, reg_r, bright; \
SET GPIO(r##N##_gpio), r##N##_pin; \
skip_r##N: \
QBGE skip_g##N, reg_g, bright; \
SET GPIO(g##N##_gpio), g##N##_pin; \
skip_g##N: \
QBGE skip_b##N, reg_b, bright; \
SET GPIO(b##N##_gpio), b##N##_pin; \
skip_b##N: \
OUTPUT_ROW(11, r20.b0, r20.b1, r20.b2)
OUTPUT_ROW(12, r20.b3, r21.b0, r21.b1)
OUTPUT_ROW(21, r21.b2, r21.b3, r22.b0)
OUTPUT_ROW(22, r22.b1, r22.b2, r22.b3)
OUTPUT_ROW(31, r23.b0, r23.b1, r23.b2)
OUTPUT_ROW(32, r23.b3, r24.b0, r24.b1)
OUTPUT_ROW(41, r24.b2, r24.b3, r25.b0)
OUTPUT_ROW(42, r25.b1, r25.b2, r25.b3)
OUTPUT_ROW(51, r26.b0, r26.b1, r26.b2)
OUTPUT_ROW(52, r26.b3, r27.b0, r27.b1)
OUTPUT_ROW(61, r27.b2, r27.b3, r28.b0)
OUTPUT_ROW(62, r28.b1, r28.b2, r28.b3)
OUTPUT_ROW(71, r29.b0, r29.b1, r29.b2)
OUTPUT_ROW(72, r29.b3, r30.b0, r30.b1)
OUTPUT_ROW(81, r30.b2, r30.b3, r31.b0)
OUTPUT_ROW(82, r31.b1, r31.b2, r31.b3)
// All bits are configured;
// the non-set ones will be cleared
// We write 8 bytes since CLR and DATA are contiguous,
// which will write both the 0 and 1 bits in the
// same instruction. gpio0 and out_set are the same
// register, so they must be done first.
AND out_set, gpio0_set, gpio0_led_mask
XOR out_clr, out_set, gpio0_led_mask
SBBO out_clr, gpio0_base, GPIO_CLRDATAOUT, 8
AND out_set, gpio1_set, gpio1_led_mask
XOR out_clr, out_set, gpio1_led_mask
SBBO out_clr, gpio1_base, GPIO_CLRDATAOUT, 8
AND out_set, gpio2_set, gpio2_led_mask
XOR out_clr, out_set, gpio2_led_mask
SBBO out_clr, gpio2_base, GPIO_CLRDATAOUT, 8
AND out_set, gpio3_set, gpio3_led_mask
XOR out_clr, out_set, gpio3_led_mask
SBBO out_clr, gpio3_base, GPIO_CLRDATAOUT, 8
CLOCK_LO
#if 1
// If the brightness is less than the pixel, turn off
// but keep in mind that this is the brightness of
// the previous row, not this one.
LSR out_set, offset, 0
ADD out_clr, bright, 10
LSL out_clr, out_clr, 4
QBLT no_blank, out_clr, out_set
DISPLAY_OFF
no_blank:
#endif
ADD offset, offset, 3*16
QBNE PIXEL_LOOP, offset, width
// Full data has been clocked out; latch it
LATCH_HI
DISPLAY_ON
// Update the brightness, and then give the row another scan
SUB bright, bright, BRIGHT_STEP
QBLT ROW_LOOP, bright, 0
// We have just done all eight brightness levels for this
// row. Time to move to the new row
// Increment our data_offset to point to the next row
ADD data_addr, data_addr, offset
ADD row, row, 1
QBEQ READ_LOOP, row, 8
QBA NEW_ROW_LOOP
EXIT:
#ifdef AM33XX
// Send notification to Host for program completion
MOV R31.b0, PRU0_ARM_INTERRUPT+16
#else
MOV R31.b0, PRU0_ARM_INTERRUPT
#endif
HALT