import time from machine import Pin, RTC #from neopixel import NeoPixel # modifications to get sane adressing with meandering panels # (c) 2022 Joerg Reisenweber # NeoPixel driver for MicroPython # MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared from machine import bitstream class NeoPixel: # '''the panels have the neopixels data-in/out chain in meanders, here assuming first LED in that data daisychain # is upper-left of panel and 2nd LED below first. # map "table" is converting the typical rasterscan framebuffer pixel adresses, like # 8, 9, 10, 11 # 4, 5, 6, 7 # 0, 1, 2, 3 # to LED position in data daisychain # map[0] for framebuffer address (0,0) is pointing to bottom leftmost LED with position 15 in data daisychain # # python code generating the table, origin=1 means "1. quadrant" / origin:bottomleft # origin=1 # for y in range(16): # print('\n# y:', y) # for x in range(4): # i = (x*16 + y) if ((x)%2 == origin) else (x*16 + 15 - y) # print( str(i) + ', ', end='') # ''' map = (# y: 0 origin:left-bottom so this is 'upside down' 15, 16, 47, 48, 79, 80, 111, 112, 143, 144, 175, 176, 207, 208, 239, 240, 271, 272, 303, 304, 335, 336, 367, 368, 399, 400, 431, 432, 463, 464, 495, 496, 527, 528, 559, 560, 591, 592, 623, 624, 655, 656, 687, 688, 719, 720, 751, 752, # y: 1 14, 17, 46, 49, 78, 81, 110, 113, 142, 145, 174, 177, 206, 209, 238, 241, 270, 273, 302, 305, 334, 337, 366, 369, 398, 401, 430, 433, 462, 465, 494, 497, 526, 529, 558, 561, 590, 593, 622, 625, 654, 657, 686, 689, 718, 721, 750, 753, # y: 2 13, 18, 45, 50, 77, 82, 109, 114, 141, 146, 173, 178, 205, 210, 237, 242, 269, 274, 301, 306, 333, 338, 365, 370, 397, 402, 429, 434, 461, 466, 493, 498, 525, 530, 557, 562, 589, 594, 621, 626, 653, 658, 685, 690, 717, 722, 749, 754, # y: 3 12, 19, 44, 51, 76, 83, 108, 115, 140, 147, 172, 179, 204, 211, 236, 243, 268, 275, 300, 307, 332, 339, 364, 371, 396, 403, 428, 435, 460, 467, 492, 499, 524, 531, 556, 563, 588, 595, 620, 627, 652, 659, 684, 691, 716, 723, 748, 755, # y: 4 11, 20, 43, 52, 75, 84, 107, 116, 139, 148, 171, 180, 203, 212, 235, 244, 267, 276, 299, 308, 331, 340, 363, 372, 395, 404, 427, 436, 459, 468, 491, 500, 523, 532, 555, 564, 587, 596, 619, 628, 651, 660, 683, 692, 715, 724, 747, 756, # y: 5 10, 21, 42, 53, 74, 85, 106, 117, 138, 149, 170, 181, 202, 213, 234, 245, 266, 277, 298, 309, 330, 341, 362, 373, 394, 405, 426, 437, 458, 469, 490, 501, 522, 533, 554, 565, 586, 597, 618, 629, 650, 661, 682, 693, 714, 725, 746, 757, # y: 6 9, 22, 41, 54, 73, 86, 105, 118, 137, 150, 169, 182, 201, 214, 233, 246, 265, 278, 297, 310, 329, 342, 361, 374, 393, 406, 425, 438, 457, 470, 489, 502, 521, 534, 553, 566, 585, 598, 617, 630, 649, 662, 681, 694, 713, 726, 745, 758, # y: 7 8, 23, 40, 55, 72, 87, 104, 119, 136, 151, 168, 183, 200, 215, 232, 247, 264, 279, 296, 311, 328, 343, 360, 375, 392, 407, 424, 439, 456, 471, 488, 503, 520, 535, 552, 567, 584, 599, 616, 631, 648, 663, 680, 695, 712, 727, 744, 759, # y: 8 7, 24, 39, 56, 71, 88, 103, 120, 135, 152, 167, 184, 199, 216, 231, 248, 263, 280, 295, 312, 327, 344, 359, 376, 391, 408, 423, 440, 455, 472, 487, 504, 519, 536, 551, 568, 583, 600, 615, 632, 647, 664, 679, 696, 711, 728, 743, 760, # y: 9 6, 25, 38, 57, 70, 89, 102, 121, 134, 153, 166, 185, 198, 217, 230, 249, 262, 281, 294, 313, 326, 345, 358, 377, 390, 409, 422, 441, 454, 473, 486, 505, 518, 537, 550, 569, 582, 601, 614, 633, 646, 665, 678, 697, 710, 729, 742, 761, # y: 10 5, 26, 37, 58, 69, 90, 101, 122, 133, 154, 165, 186, 197, 218, 229, 250, 261, 282, 293, 314, 325, 346, 357, 378, 389, 410, 421, 442, 453, 474, 485, 506, 517, 538, 549, 570, 581, 602, 613, 634, 645, 666, 677, 698, 709, 730, 741, 762, # y: 11 4, 27, 36, 59, 68, 91, 100, 123, 132, 155, 164, 187, 196, 219, 228, 251, 260, 283, 292, 315, 324, 347, 356, 379, 388, 411, 420, 443, 452, 475, 484, 507, 516, 539, 548, 571, 580, 603, 612, 635, 644, 667, 676, 699, 708, 731, 740, 763, # y: 12 3, 28, 35, 60, 67, 92, 99, 124, 131, 156, 163, 188, 195, 220, 227, 252, 259, 284, 291, 316, 323, 348, 355, 380, 387, 412, 419, 444, 451, 476, 483, 508, 515, 540, 547, 572, 579, 604, 611, 636, 643, 668, 675, 700, 707, 732, 739, 764, # y: 13 2, 29, 34, 61, 66, 93, 98, 125, 130, 157, 162, 189, 194, 221, 226, 253, 258, 285, 290, 317, 322, 349, 354, 381, 386, 413, 418, 445, 450, 477, 482, 509, 514, 541, 546, 573, 578, 605, 610, 637, 642, 669, 674, 701, 706, 733, 738, 765, # y: 14 1, 30, 33, 62, 65, 94, 97, 126, 129, 158, 161, 190, 193, 222, 225, 254, 257, 286, 289, 318, 321, 350, 353, 382, 385, 414, 417, 446, 449, 478, 481, 510, 513, 542, 545, 574, 577, 606, 609, 638, 641, 670, 673, 702, 705, 734, 737, 766, # y: 15 0, 31, 32, 63, 64, 95, 96, 127, 128, 159, 160, 191, 192, 223, 224, 255, 256, 287, 288, 319, 320, 351, 352, 383, 384, 415, 416, 447, 448, 479, 480, 511, 512, 543, 544, 575, 576, 607, 608, 639, 640, 671, 672, 703, 704, 735, 736, 767) # origin=0 ##origin:left-top # map = (# y: 0 # 0, 31, 32, 63, 64, 95, 96, 127, 128, 159, 160, 191, 192, 223, 224, 255, 256, 287, 288, 319, 320, 351, 352, 383, 384, 415, 416, 447, 448, 479, 480, 511, 512, 543, 544, 575, 576, 607, 608, 639, 640, 671, 672, 703, 704, 735, 736, 767, # # y: 1 # 1, 30, 33, 62, 65, 94, 97, 126, 129, 158, 161, 190, 193, 222, 225, 254, 257, 286, 289, 318, 321, 350, 353, 382, 385, 414, 417, 446, 449, 478, 481, 510, 513, 542, 545, 574, 577, 606, 609, 638, 641, 670, 673, 702, 705, 734, 737, 766, # # y: 2 # 2, 29, 34, 61, 66, 93, 98, 125, 130, 157, 162, 189, 194, 221, 226, 253, 258, 285, 290, 317, 322, 349, 354, 381, 386, 413, 418, 445, 450, 477, 482, 509, 514, 541, 546, 573, 578, 605, 610, 637, 642, 669, 674, 701, 706, 733, 738, 765, # # y: 3 # 3, 28, 35, 60, 67, 92, 99, 124, 131, 156, 163, 188, 195, 220, 227, 252, 259, 284, 291, 316, 323, 348, 355, 380, 387, 412, 419, 444, 451, 476, 483, 508, 515, 540, 547, 572, 579, 604, 611, 636, 643, 668, 675, 700, 707, 732, 739, 764, # # y: 4 # 4, 27, 36, 59, 68, 91, 100, 123, 132, 155, 164, 187, 196, 219, 228, 251, 260, 283, 292, 315, 324, 347, 356, 379, 388, 411, 420, 443, 452, 475, 484, 507, 516, 539, 548, 571, 580, 603, 612, 635, 644, 667, 676, 699, 708, 731, 740, 763, # # y: 5 # 5, 26, 37, 58, 69, 90, 101, 122, 133, 154, 165, 186, 197, 218, 229, 250, 261, 282, 293, 314, 325, 346, 357, 378, 389, 410, 421, 442, 453, 474, 485, 506, 517, 538, 549, 570, 581, 602, 613, 634, 645, 666, 677, 698, 709, 730, 741, 762, # # y: 6 # 6, 25, 38, 57, 70, 89, 102, 121, 134, 153, 166, 185, 198, 217, 230, 249, 262, 281, 294, 313, 326, 345, 358, 377, 390, 409, 422, 441, 454, 473, 486, 505, 518, 537, 550, 569, 582, 601, 614, 633, 646, 665, 678, 697, 710, 729, 742, 761, # # y: 7 # 7, 24, 39, 56, 71, 88, 103, 120, 135, 152, 167, 184, 199, 216, 231, 248, 263, 280, 295, 312, 327, 344, 359, 376, 391, 408, 423, 440, 455, 472, 487, 504, 519, 536, 551, 568, 583, 600, 615, 632, 647, 664, 679, 696, 711, 728, 743, 760, # # y: 8 # 8, 23, 40, 55, 72, 87, 104, 119, 136, 151, 168, 183, 200, 215, 232, 247, 264, 279, 296, 311, 328, 343, 360, 375, 392, 407, 424, 439, 456, 471, 488, 503, 520, 535, 552, 567, 584, 599, 616, 631, 648, 663, 680, 695, 712, 727, 744, 759, # # y: 9 # 9, 22, 41, 54, 73, 86, 105, 118, 137, 150, 169, 182, 201, 214, 233, 246, 265, 278, 297, 310, 329, 342, 361, 374, 393, 406, 425, 438, 457, 470, 489, 502, 521, 534, 553, 566, 585, 598, 617, 630, 649, 662, 681, 694, 713, 726, 745, 758, # # y: 10 # 10, 21, 42, 53, 74, 85, 106, 117, 138, 149, 170, 181, 202, 213, 234, 245, 266, 277, 298, 309, 330, 341, 362, 373, 394, 405, 426, 437, 458, 469, 490, 501, 522, 533, 554, 565, 586, 597, 618, 629, 650, 661, 682, 693, 714, 725, 746, 757, # # y: 11 # 11, 20, 43, 52, 75, 84, 107, 116, 139, 148, 171, 180, 203, 212, 235, 244, 267, 276, 299, 308, 331, 340, 363, 372, 395, 404, 427, 436, 459, 468, 491, 500, 523, 532, 555, 564, 587, 596, 619, 628, 651, 660, 683, 692, 715, 724, 747, 756, # # y: 12 # 12, 19, 44, 51, 76, 83, 108, 115, 140, 147, 172, 179, 204, 211, 236, 243, 268, 275, 300, 307, 332, 339, 364, 371, 396, 403, 428, 435, 460, 467, 492, 499, 524, 531, 556, 563, 588, 595, 620, 627, 652, 659, 684, 691, 716, 723, 748, 755, # # y: 13 # 13, 18, 45, 50, 77, 82, 109, 114, 141, 146, 173, 178, 205, 210, 237, 242, 269, 274, 301, 306, 333, 338, 365, 370, 397, 402, 429, 434, 461, 466, 493, 498, 525, 530, 557, 562, 589, 594, 621, 626, 653, 658, 685, 690, 717, 722, 749, 754, # # y: 14 # 14, 17, 46, 49, 78, 81, 110, 113, 142, 145, 174, 177, 206, 209, 238, 241, 270, 273, 302, 305, 334, 337, 366, 369, 398, 401, 430, 433, 462, 465, 494, 497, 526, 529, 558, 561, 590, 593, 622, 625, 654, 657, 686, 689, 718, 721, 750, 753, # # y: 15 # 15, 16, 47, 48, 79, 80, 111, 112, 143, 144, 175, 176, 207, 208, 239, 240, 271, 272, 303, 304, 335, 336, 367, 368, 399, 400, 431, 432, 463, 464, 495, 496, 527, 528, 559, 560, 591, 592, 623, 624, 655, 656, 687, 688, 719, 720, 751, 752 ) # # G R B W ORDER = (1, 0, 2, 3) def __init__(self, pin, n, bpp=3, timing=1): self.pin = pin self.n = n self.bpp = bpp self.buf = bytearray(n * bpp) self.pin.init(pin.OUT) # Timing arg can either be 1 for 800kHz or 0 for 400kHz, # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). self.timing = ( ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing ) def __len__(self): return self.n def __setitem__(self, i, v): offset = self.map[i] * self.bpp for i in range(self.bpp): self.buf[offset + self.ORDER[i]] = v[i] def __getitem__(self, i): offset = self.map[i] * self.bpp return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) def fill(self, v): b = self.buf l = len(self.buf) bpp = self.bpp for i in range(bpp): c = v[i] j = self.ORDER[i] while j < l: b[j] = c j += bpp def write(self): # BITSTREAM_TYPE_HIGH_LOW = 0 bitstream(self.pin, 0, self.timing, self.buf) ################## end "neopixel_inline_import" ######################## ######################################################################## # main() # font 'bitmaps', tuples of (x, y) coords of pixels to set, relative to char's left-bottom (0, 0)foot ChrRct= ( (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (0, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (0, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (0, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10), (0, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (5, 10), (0, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (6, 10), (0, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (6, 10) ) Char0 = ( (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0,7), (0, 8), (1, 1), (1, 9), (2, 0), (2, 10), (3, 0), (3, 10), (4, 0), (4, 10), (5, 1), (5, 9), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8) ) Char1 = ( (0, 7), (1, 8), (2, 9), (3, 10), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10) ) Char2 = ( (0, 0), (0, 8), (1, 0), (1, 1), (1, 9), (2, 0), (2, 2), (2, 10), (3, 0), (3, 3), (3, 10), (4, 0), (4, 4), (4, 10), (5, 0), (5, 5), (5, 9), (6, 0), (6, 6), (6, 7), (6, 8) ) Char3 = ( (0, 1), (0, 2), (0, 8), (0, 9), (1, 0), (1, 10), (2, 0), (2, 10), (3, 0), (3, 10), (4, 0), (4, 5), (4, 10), (5, 0), (5, 4), (5, 6), (5, 9), (6, 1), (6, 2), (6, 3), (6, 7), (6, 8) ) Char4 = ( (0, 3), (0, 4), (1, 3), (1, 5), (2, 3), (2, 6), (3, 3), (3, 7), (4, 3), (4, 8), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 9), (6, 3), (6, 10) ) Char5 = ( (0, 2), (0, 3), (0, 8), (0, 9), (0, 10), (1, 1), (1, 7), (1, 10), (2, 0), (2, 6), (2, 10), (3, 0), (3, 6), (3, 10), (4, 0), (4, 6), (4, 10), (5, 1), (5, 5), (5, 10), (6, 2), (6, 3), (6, 4), (6, 10), ) Char6 = ( (0, 2), (0, 3), (0, 4), (0, 5), (1, 1), (1, 4), (1, 6), (2, 0), (2, 5), (2, 7), (3, 0), (3, 5), (3, 8), (4, 0), (4, 5), (4, 9), (5, 1), (5, 4), (5, 10), (6, 2), (6, 3) ) Char7 = ( (0, 10), (1, 0), (1, 10), (2, 1), (2, 2), (2, 10), (3, 3), (3, 4), (3, 10), (4, 5), (4, 6), (4, 10), (5, 7), (5, 8), (5, 10), (6, 9), (6, 10) ) Char8 = ( (0, 2), (0, 3), (0, 4), (1, 1), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 0), (2, 5), (2, 10), (3, 0), (3, 5), (3, 10), (4, 0), (4, 5), (4, 10), (5, 1), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 2), (6, 3), (6, 4) ) Char9 = ( (0, 2), (0, 7), (0, 8), (1, 1), (1, 6), (1, 9), (2, 0), (2, 5), (2, 10), (3, 0), (3, 5), (3, 10), (4, 0), (4, 5), (4, 10), (5, 1), (5, 6), (5, 9), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8) ) ChrCol= ( (0, 2), (0, 3), (0, 6), (0, 7), (1, 2), (1, 3), (1, 6), (1, 7) ) char = (Char0, Char1, Char2, Char3, Char4, Char5, Char6, Char7, Char8, Char9) # implementation const DX = 48; DY = 16 # dimensions of the display, here 3 panels of 16*16 left to right NUM_LEDS = DX * DY pin = Pin(22, Pin.OUT) # set GPIO0 to output to drive NeoPixels np = NeoPixel(pin, NUM_LEDS) # create NeoPixel driver rtc = RTC() def writechar(buf, charmap, color, footcoord): # ''' writes a charmap to buf at position footcoord, using color ''' for pixy in charmap: buf[footcoord[0]+pixy[0] + DX*(footcoord[1]+pixy[1])] = color bgcolor = (0, 0, 0) hhcolor = (2, 3, 1) delcolor= (1, 1, 1) mmcolor = hhcolor sscolor = (2, 0, 0) cy = 4 chlx = 0 chrx = 7 cdelx = 14 cmlx = 17 cmrx = 25 cslx = 33 csrx = 41 datetime = rtc.datetime() while True: while (datetime == rtc.datetime()): time.sleep_ms(10) datetime = rtc.datetime() print("{:02d}".format(datetime[4]) + ":" + "{:02d}".format(datetime[5]) + ":" + "{:02d}".format(datetime[6])) np.fill( (0b0000000, 0, 0) ) writechar(np, char[datetime[4]//10], hhcolor, (chlx, cy)) writechar(np, char[datetime[4]%10], hhcolor, (chrx, cy)) writechar(np, ChrCol, delcolor, (cdelx, cy)) writechar(np, char[datetime[5]//10], mmcolor, (cmlx, cy)) writechar(np, char[datetime[5]%10], mmcolor, (cmrx, cy)) writechar(np, char[datetime[6]//10], sscolor, (cslx, cy)) writechar(np, char[datetime[6]%10], sscolor, (csrx, cy)) np.write(); time.sleep_us(50) time.sleep_ms(900) '''testcode txt = input("Type something to continue!") np.fill( (0b0000000, 0, 0) ) writechar(np, Char6, (5, 3, 1), (0, 4)) writechar(np, Char7, (5, 3, 1), (7, 4)) writechar(np, Char8, (5, 3, 1), (16, 4)) writechar(np, Char9, (5, 3, 1), (32, 4)) np.write() # r, g, b = np[0] # get first pixel colour time.sleep_ms(13550) #np.fill( (0b00011111, 0b00011111, 0b00011111) ) start = time.ticks_ms(); numwrites = 0 for offy in range(1, 4): for offx in range(40): np.fill( (0b00000001, 0, 0) ) writechar(np, Char1, (1, 4, 3), (offx, offy) ) np.write() numwrites+=1 # write data to all pixels delta = time.ticks_diff(time.ticks_ms(), start) print(" loop painting sliding Char1 => ", delta / numwrites, "ms, ", numwrites * 1000 / delta, "fps") time.sleep_ms(13550) np.fill( (0b00000001, 0, 0) ) np.write() testcode'''