|
| 1 | +NUM_PIXELS = 4 |
| 2 | +NEO_PIXELS_IN_PIN = 22 |
| 3 | + |
| 4 | +try: |
| 5 | + |
| 6 | + import time |
| 7 | + import rp2 |
| 8 | + from machine import Pin |
| 9 | + |
| 10 | + # bits shifting |
| 11 | + # ============= |
| 12 | + # - for the pixels: 1st pixel then 2nd pixel ... |
| 13 | + # - for a pixel (24 bits): G then R then B |
| 14 | + # - for R/G/B (8 bits): most significant bit first |
| 15 | + # timing for a bit: |
| 16 | + # - 0: .4us high + .85us low |
| 17 | + # - 1: .8us high + .45us low |
| 18 | + # if frequency is 20MHz ... i.e. each cycle takes 0.05us |
| 19 | + # - 0: 8 cycles high + 17 cycles low |
| 20 | + # - 1: 16 cycles high + 9 cycles low |
| 21 | + # afterward, delay for 300us |
| 22 | + |
| 23 | + @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT) # SHIFT_LEFT: i.e. most significant bit first |
| 24 | + def neo_prog(): |
| 25 | + pull() # osr <= number of pixels - 1 |
| 26 | + mov(y, osr) # y <= number of pixels - 1 |
| 27 | + label("loop_pixel") |
| 28 | + mov(isr, y) # isr (pixel counter) <= y |
| 29 | + pull() # sor <= 24 bits GRB |
| 30 | + set(x, 23) # x (bit counter) <= 23 |
| 31 | + label("loop_pixel_bit") |
| 32 | + out(y, 1) # y <= left-most 1 bit of sor |
| 33 | + jmp(not_y, "bit_0") |
| 34 | + set(pins, 1).delay(15) # 1: high (16 cycles) |
| 35 | + set(pins, 0).delay(8) # 1: low (9 cycles) |
| 36 | + jmp("bit_end") |
| 37 | + label("bit_0") |
| 38 | + set(pins, 1).delay(7) # 0: high (8 cycles) |
| 39 | + set(pins, 0).delay(16) # 0: low (17 cycles) |
| 40 | + label("bit_end") |
| 41 | + jmp(x_dec, "loop_pixel_bit") # x is bit counter |
| 42 | + mov(y, isr) # y <= isr (pixel counter) |
| 43 | + jmp(y_dec, "loop_pixel") # y is pixel counter |
| 44 | + |
| 45 | + sm = rp2.StateMachine(0, neo_prog, freq=20_000_000, set_base=Pin(NEO_PIXELS_IN_PIN)) |
| 46 | + sm.active(1) |
| 47 | + |
| 48 | + def ShowNeoPixels(*pixels): |
| 49 | + ''' |
| 50 | + each pixel is the tuple (r, g, b) |
| 51 | + ''' |
| 52 | + pixel_count = len(pixels) |
| 53 | + sm.put(pixel_count - 1) |
| 54 | + for i in range(pixel_count): |
| 55 | + pixel = pixels[i] |
| 56 | + if pixel: |
| 57 | + (r, g, b) = pixel |
| 58 | + else: |
| 59 | + (r, g, b) = (0, 0, 0) |
| 60 | + grb = (g << 16) + (r << 8) + b # the order is G R B |
| 61 | + sm.put(grb, 8) # a word is 32 bits, so, pre-shift out (discard) 8 bits, leaving 24 bits of the GRB |
| 62 | + time.sleep_us(300) # make sure the NeoPixels is reset for the next round |
| 63 | + |
| 64 | + Pixels = [] |
| 65 | + for i in range(NUM_PIXELS): |
| 66 | + Pixels.append(None) |
| 67 | + |
| 68 | +except: |
| 69 | + print("Cannot initialize NeoPixels!") |
| 70 | + Pixels = None |
| 71 | + |
| 72 | + |
1 | 73 | from dumbdisplay.core import * |
2 | 74 | from dumbdisplay.layer_graphical import * |
3 | 75 | from dumbdisplay.layer_joystick import * |
|
16 | 88 | from dumbdisplay.io_inet import * |
17 | 89 | dd = DumbDisplay(io4Inet()) |
18 | 90 |
|
| 91 | + |
19 | 92 | import time |
20 | 93 |
|
21 | 94 |
|
| 95 | +# create a graphical layer (LayerGraphical) to show the color set using the following sliders |
22 | 96 | color_layer = LayerGraphical(dd, 150, 101) |
23 | 97 | color_layer.border(5, "black", "round", 2) |
24 | 98 |
|
| 99 | +# create R slider (LayerJoystick) for controlling R (0-255) |
25 | 100 | r_slider_layer = LayerJoystick(dd, 255, "hori", 0.5) |
26 | 101 | r_slider_layer.border(3, "darkred", "round", 1) |
27 | 102 | r_slider_layer.colors("red", RGB_COLOR(0xff, 0x44, 0x44), "black", "darkgray") |
28 | 103 |
|
| 104 | +# create G slider (LayerJoystick) for controlling G (0-255) |
29 | 105 | g_slider_layer = LayerJoystick(dd, 255, "hori", 0.5) |
30 | 106 | g_slider_layer.border(3, "darkgreen", "round", 1) |
31 | 107 | g_slider_layer.colors("green", RGB_COLOR(0x44, 0xff, 0x44), "black", "darkgray") |
32 | 108 |
|
| 109 | +# create B slider (LayerJoystick) for controlling B (0-255) |
33 | 110 | b_slider_layer = LayerJoystick(dd, 255, "hori", 0.5) |
34 | 111 | b_slider_layer.border(3, "darkblue", "round", 1) |
35 | 112 | b_slider_layer.colors("blue", RGB_COLOR(0x44, 0x44, 0xff), "black", "darkgray") |
36 | 113 |
|
| 114 | +# auto "pin" the above layers vertically |
37 | 115 | AutoPin('V').pin(dd) |
38 | 116 |
|
39 | 117 | r = 0 |
40 | 118 | g = 0 |
41 | 119 | b = 0 |
42 | 120 | color_layer.backgroundColor(RGB_COLOR(r, g, b)) |
| 121 | +last_ms = time.ticks_ms() |
| 122 | + |
43 | 123 | while True: |
| 124 | + diff_ms = time.ticks_diff(time.ticks_ms(), last_ms) |
| 125 | + if diff_ms >= 200: |
| 126 | + # shift pixels colors ... the 1st one will then be set to the color of (r, g, b) |
| 127 | + for i in range(NUM_PIXELS - 1, 0, -1): |
| 128 | + Pixels[i] = Pixels[i - 1] |
| 129 | + Pixels[0] = (r, g, b) |
| 130 | + ShowNeoPixels(*Pixels) |
| 131 | + last_ms = time.ticks_ms() |
| 132 | + |
44 | 133 | old_r = r |
45 | 134 | old_g = g |
46 | 135 | old_b = b |
47 | 136 | fb: Feedback = r_slider_layer.getFeedback() |
48 | 137 | if fb: |
| 138 | + # if there is "feedback" from the R slider, its x position will be the new value for r |
49 | 139 | r = fb.x |
50 | 140 | fb: Feedback = g_slider_layer.getFeedback() |
51 | 141 | if fb: |
| 142 | + # if there is "feedback" from the G slider, its x position will be the new value for g |
52 | 143 | g = fb.x |
53 | 144 | fb: Feedback = b_slider_layer.getFeedback() |
54 | 145 | if fb: |
| 146 | + # if there is "feedback" from the B slider, its x position will be the new value for b |
55 | 147 | b = fb.x |
56 | 148 | if r != old_r or g != old_g or b != old_b: |
| 149 | + # set the background color of the color layer to the new (r, g, b) color |
57 | 150 | color_layer.backgroundColor(RGB_COLOR(r, g, b)) |
0 commit comments