Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created June 4, 2022 21:40
Show Gist options
  • Save samneggs/61488861a53efc19c4400e954908fb1b to your computer and use it in GitHub Desktop.
Save samneggs/61488861a53efc19c4400e954908fb1b to your computer and use it in GitHub Desktop.
RGB 64x32 Matrix Clock
from machine import Pin, Timer
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep, localtime
from usys import exit
import framebuf, array
from uctypes import addressof
from micropython import const
import _thread
from random import randint
import gc
R1 = Pin(2, Pin.OUT)
G1 = Pin(3, Pin.OUT)
B1 = Pin(4, Pin.OUT)
R2 = Pin(5, Pin.OUT)
G2 = Pin(8, Pin.OUT)
B2 = Pin(9, Pin.OUT)
CLK = Pin(11, Pin.OUT)
STB = Pin(12, Pin.OUT)
OE = Pin(13, Pin.OUT)
LINE_A = Pin(10,Pin.OUT)
LINE_B = Pin(16,Pin.OUT)
LINE_C = Pin(18,Pin.OUT)
LINE_D = Pin(20,Pin.OUT)
LINE_E = Pin(22,Pin.OUT)
LED = Pin(25,Pin.OUT)
IR = Pin(28, Pin.IN)
EMPTY = const(0)
WATER_COLOR = const(0x001f)
SAND_COLOR = const(0xff00)
FIXED_COLOR = const(0xffff)
RANDOM_ADR = const(0x4006001c)
BLUE = const(0x001f)
BLACK = const(0)
WHITE = const(0xffff)
GREEN = const(0x03e0)#e00A)
BROWN = const(0xe091)
RED = const(0b11111_000000_00000)
YELLOW=const(0xff00)
MAGENTA=const(0x1FF8)
ORANGE = const(0xfc06)
MAXSCREEN_X = const(64)
MAXSCREEN_Y = const(32)
MaxLed = 64
c12 = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
c13 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
color_l2 = array.array('H', [])
matrix_buffer=bytearray(64*32*2)
matrix = framebuf.FrameBuffer(matrix_buffer, 64, 32, framebuf.RGB565)
text_buffer = bytearray(64*32*2)
big_text = framebuf.FrameBuffer(text_buffer, 64, 32, framebuf.RGB565)
control_asm=array.array('I',(addressof(matrix_buffer),0xD0000000,0x40014000,0,99,0,32,0,0b00000_111111_11111,200,0))
T = array.array('h',(2022, 5, 26, 17, 44, 6, 3, 146))
sandctl_asm=array.array('I',(addressof(matrix_buffer),0,64,SAND_COLOR,WATER_COLOR,FIXED_COLOR,RANDOM_ADR,0,0,0))
MATRIX_CTL = const(0) #0
SIO_START_CTL = const(4) #1
GPIO_START_CTL = const(8) #2
LINE_CTL = const(12) #3
DEBUG_CTL = const(16) #4
COUNT_CTL = const(20) #5
SHADES_CTL = const(24) #6
EXIT_CTL = const(28) #7
TEST_CTL = const(32) #8
BRIGHT_CTL = const(36) #9
@micropython.asm_thumb
def rgb_asm(r0):
label(NEW_SCREEN)
ldr(r1,[r0,EXIT_CTL])
cmp(r1,0)
beq(DONT_EXIT)
b(EXIT) # exit from upy
label(DONT_EXIT)
ldr(r4,[r0,LINE_CTL])
ldr(r1,[r0,SIO_START_CTL]) # r1=SIO_START_CTL
mov(r6,1)
lsl(r2,r6,13) # pin 13 (OE)
str(r2,[r1,0x14]) # GPIO_SET Register
mov(r7,r4)
label(CHECK_A)
ror(r7,r6)
bpl(CLEAR_A)
lsl(r2,r6,10) # pin 10 (LINE_A)
str(r2,[r1,0x14]) # GPIO_SET Register
b(CHECK_B)
label(CLEAR_A)
lsl(r2,r6,10) # pin 10 (LINE_A)
str(r2,[r1,0x18]) # GPIO_CLR Register
label(CHECK_B)
ror(r7,r6)
bpl(CLEAR_B)
lsl(r2,r6,16) # pin 16 (LINE_B)
str(r2,[r1,0x14]) # GPIO_SET Register
b(CHECK_C)
label(CLEAR_B)
lsl(r2,r6,16) # pin 16 (LINE_B)
str(r2,[r1,0x18]) # GPIO_CLR Register
label(CHECK_C)
ror(r7,r6)
bpl(CLEAR_C)
lsl(r2,r6,18) # pin 18 (LINE_C)
str(r2,[r1,0x14]) # GPIO_SET Register
b(CHECK_D)
label(CLEAR_C)
lsl(r2,r6,18) # pin 18 (LINE_C)
str(r2,[r1,0x18]) # GPIO_CLR Register
label(CHECK_D)
ror(r7,r6)
bpl(CLEAR_D)
lsl(r2,r6,20) # pin 20 (LINE_D)
str(r2,[r1,0x14]) # GPIO_SET Register
b(CHECK_E)
label(CLEAR_D)
lsl(r2,r6,20) # pin 20 (LINE_D)
str(r2,[r1,0x18]) # GPIO_CLR Register
label(CHECK_E)
ror(r7,r6)
bpl(CLEAR_E)
lsl(r2,r6,22) # pin 22 (LINE_E)
str(r2,[r1,0x14]) # GPIO_SET Register
b(DONE_LINES)
label(CLEAR_E)
lsl(r2,r6,22) # pin 22 (LINE_E)
str(r2,[r1,0x18]) # GPIO_CLR Register
label(DONE_LINES)
mov(r5,1)
lsl(r5,r5,12) # pin 12 (STB)
str(r5,[r1,0x14]) # GPIO_OE_CLR Register
mov(r5,1)
lsl(r5,r5,12) # pin 12 (STB)
str(r5,[r1,0x18]) # GPIO_OUT_SET Register
ldr(r4,[r0,LINE_CTL])
add(r4,1)
cmp(r4,16)
blt(STR_LINE_CTL)
mov(r4,0)
ldr(r1,[r0,SHADES_CTL])
add(r1,1)
cmp(r1,16)
blt(NO_RESET)
mov(r1,0)
label(NO_RESET)
str(r1,[r0,SHADES_CTL]) # 0-16 bright level
label(STR_LINE_CTL)
str(r4,[r0,LINE_CTL]) # 0-63 for line
ldr(r1,[r0,SIO_START_CTL]) # r1=SIO_START_CTL
mov(r2,0) # r2 = 0-64 (x)
label(LOOP)
ldr(r3,[r0,LINE_CTL]) # r3=line (y)
lsl(r3,r3,6) # =line*64
add(r3,r3,r2) # =(line*64)+r2
add(r3,r3,r3) # double ldrh
ldr(r4,[r0,MATRIX_CTL]) # r4=matrix address
add(r3,r3,r4) # r3=pixel address
ldrh(r4,[r3,0]) # r4=pixel data
bl(SETPIXEL1)
mov(r7,1)
lsl(r7,r7,11) # 2048 = 64*16*2
#str(r7,[r0,DEBUG_CTL])
add(r7,r3,r7) # RGB2 part of matrix
ldrh(r4,[r7,0]) # r7=RGB2 matrix pixel
bl(SETPIXEL2)
bl(DO_CLK)
bl(OFF_DELAY)
label(NEXT)
add(r2,1)
cmp(r2,64)#64
blt(LOOP)
mov(r5,1)
lsl(r5,r5,13) # pin 13 (OE)
str(r5,[r1,0x18]) # GPIO_CLR Register
bl(ON_DELAY)
b(NEW_SCREEN)
# -------------------------SUBS---------------------------------
label(DO_CLK)
mov(r5,1)
lsl(r6,r5,11) # pin 11 (CLK)
str(r6,[r1,0x14]) # GPIO_OUT_SET Register
str(r6,[r1,0x18]) # GPIO_OE_CLR Register
bx(lr)
label(ON_DELAY)
#mov(r7,200)#32
ldr(r7,[r0,BRIGHT_CTL])
label(LOOP2)
sub(r7,1)
cmp(r7,0)
bgt(LOOP2)
bx(lr)
label(OFF_DELAY)
mov(r7,100)#32
label(LOOP3)
sub(r7,1)
cmp(r7,0)
bgt(LOOP3)
bx(lr)
label(SETPIXEL1)
ldr(r7,[r0,SHADES_CTL])
lsr(r6,r4,11)#11
cmp(r6,r7)
ble(CLEAR_RED)
mov(r5,1<<2) # pin 2 (R1)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(CHECK_GREEN)
label(CLEAR_RED)
mov(r5,1<<2) # pin 2 (R1)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(CHECK_GREEN)
lsl(r6,r4,21) # clear out red
lsr(r6,r6,27)#26? # clear out blue
cmp(r6,r7)
ble(CLEAR_GREEN)
mov(r5,1<<3) # pin 3 (G1)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(CHECK_BLUE)
label(CLEAR_GREEN)
mov(r5,1<<3) # pin 3 (G1)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(CHECK_BLUE)
lsl(r6,r4,27) # clear red/green
lsr(r6,r6,27)
cmp(r6,r7)
ble(CLEAR_BLUE)
mov(r5,1<<4) # pin 4 (B1)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(PIXEL_DONE)
label(CLEAR_BLUE)
mov(r5,1<<4) # pin 4 (B1)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(PIXEL_DONE)
bx(lr)
label(SETPIXEL2)
ldr(r7,[r0,SHADES_CTL])
lsr(r6,r4,11)#11
cmp(r6,r7)
ble(CLEAR_RED2)
mov(r5,1<<5) # pin 5 (R1)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(CHECK_GREEN2)
label(CLEAR_RED2)
mov(r5,1<<5)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(CHECK_GREEN2)
lsl(r6,r4,21) # clear out red
lsr(r6,r6,27)#26? # clear out blue
cmp(r6,r7)
ble(CLEAR_GREEN2)
mov(r5,1)
lsl(r5,r5,8) # pin 8 (B2)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(CHECK_BLUE2)
label(CLEAR_GREEN2)
mov(r5,1)
lsl(r5,r5,8) # pin 8 (B2)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(CHECK_BLUE2)
lsl(r6,r4,27) # clear red/green
lsr(r6,r6,27)
cmp(r6,r7)
ble(CLEAR_BLUE2)
mov(r5,1)
lsl(r5,r5,9) # pin 9 (G2)
str(r5,[r1,0x14]) # GPIO_OUT_SET Register
b(PIXEL_DONE2)
label(CLEAR_BLUE2)
mov(r5,1)
lsl(r5,r5,9) # pin 9 (g2)
str(r5,[r1,0x18]) # GPIO_OE_CLR Register
label(PIXEL_DONE2)
bx(lr)
label(EXIT)
ldr(r0,[r0,DEBUG_CTL])
def matrix_reset():
MaxLed=64
OE.value(1)
STB.value(0)
CLK.value(0)
for l in range(0, MaxLed):
y = l % 16
R1.value(0)# = False
G1.value(0)# = False
B1.value(0)# = False
R2.value(0)# = False
G2.value(0)# = False
B2.value(0)# = False
if c12[y] == 1:
R1.value(1)# = True
G1.value(1)# = True
B1.value(1)# = True
R2.value(1)# = True
G2.value(1)# = True
B2.value(1)# = True
if l > (MaxLed - 12):
STB.value(1)# = True
else:
STB.value(0)# = False
CLK.value(1)# = True
for delay in range(1000):
pass
#time.sleep(0.001) #(0.000002)
CLK.value(0)# = False
STB.value(0)# = False
CLK.value(0)# = False
for l in range(0, MaxLed):
y = l % 16
R1.value(0)# = False
G1.value(0)# = False
B1.value(0)# = False
R2.value(0)# = False
G2.value(0)# = False
B2.value(0)# = False
if c13[y] == 1:
R1.value(1)# = True
G1.value(1)# = True
B1.value(1)# = True
R2.value(1)# = True
G2.value(1)# = True
B2.value(1)# = True
if l > (MaxLed - 13):
STB.value(1)# = True
else:
STB.value(0)# = False
CLK.value(1)# = True
for delay in range(1000):
pass
#time.sleep(0.000002)
CLK.value(0)# = False
STB.value(0)# = False
CLK.value(0)# = False
@micropython.viper
def water_rgb16(): # 16 bit water/sand sim
screen_addr=ptr16(matrix_buffer)
offset = 0
odd = 1
for y in range(31,0,-1):
for x in range(61,0,-1):
source = screen_addr[(y-1)*MAXSCREEN_X+x]
if source == 0:
continue
dest = screen_addr[y*MAXSCREEN_X+x]
dest_m = screen_addr[y*MAXSCREEN_X+x-1]
dest_p = screen_addr[y*MAXSCREEN_X+x+1]
source_m = screen_addr[((y-1)*MAXSCREEN_X)+x-1]
source_p = screen_addr[((y-1)*MAXSCREEN_X)+x+1]
source_sand = source == SAND_COLOR
dest_water = dest == WATER_COLOR
destp_water = dest_p == WATER_COLOR
destm_water = dest_m == WATER_COLOR
rand_water = int(randint(0,3))
if source < FIXED_COLOR:
if y==31: # clear out at bottom
source=EMPTY
elif dest == EMPTY or (source_sand and dest_water) : # check down
dest = source
source = EMPTY
elif dest_p == EMPTY or (source_sand and destp_water) : # check down/right
dest_p = source
source = EMPTY
elif dest_m == EMPTY or (source_sand and destm_water): # check down/left
dest_m = source
source = EMPTY
elif rand_water == 0:
if source == WATER_COLOR and source_p == EMPTY: # water right
source_p = source
source = EMPTY
elif source == WATER_COLOR and source_m == EMPTY: # water left
source_m = source
source = EMPTY
else:
if source == WATER_COLOR and source_m == EMPTY: # water left
source_m = source
source = EMPTY
elif source == WATER_COLOR and source_p == EMPTY: # water right
source_p = source
source = EMPTY
screen_addr[(y-1)*MAXSCREEN_X+x] = source
screen_addr[y*MAXSCREEN_X+x] = dest
screen_addr[y*MAXSCREEN_X+x-1] = dest_m
screen_addr[y*MAXSCREEN_X+x+1] = dest_p
screen_addr[(y-1)*MAXSCREEN_X+x-1] = source_m
screen_addr[(y-1)*MAXSCREEN_X+x+1] = source_p
def core1():
global DONE,ALIVE
rgb_asm(control_asm)
OE.value(1)
DONE=True
def platform(start,erase):
if erase:
color1=WHITE
color2=BLACK
else:
color1=BLACK
color2=WHITE
matrix.line(start,25,start+6,31,color1) # \
matrix.line(start,26,start+5,31,color1) # \
matrix.line(start+20,25,start+15,31,color1) # /
matrix.line(start+20,26,start+14,31,color1) # /
matrix.line(start,25,start+20,25,color2) # ----
def init_pile(t,pos):
if t==0:
return
c1=24 % t
c2=24 % (t-c1)
c3=(t-(c1+c2))
if c1>0:
matrix.line(pos, 1,pos ,c1,SAND_COLOR)
if c2>0:
matrix.line(pos+1,1,pos+1,c2,SAND_COLOR)
if c3>0:
matrix.line(pos+2,1,pos+2,c3,SAND_COLOR)
def init_time():
global T
T=localtime()
h=T[3]
if h>12:
h-=12
init_pile(h,12)
m=T[4]
init_pile(m,32)
s=T[5]
init_pile(s,52)
matrix.text(':',19,5,0xffff)
matrix.text(':',39,5,0xffff)
def num2str(n,hour):
if n<10:
if hour==True:
return ' '+str(n)
else:
return '0'+str(n)
else:
return str(n)
def get_time(x):
global T,FIRST
T=localtime()
hr=T[3]
if hr>12:
hr-=12
matrix.pixel(52,0,SAND_COLOR) # seconds
matrix.fill_rect(44,5,16,7,BLUE)
matrix.text(num2str(T[5],False),44,5,WHITE)
if T[5]==0 or FIRST:
matrix.fill_rect(25,5,16,7,BLACK)
matrix.text(num2str(T[4],False),25,5,WHITE)
if T[4]==0 or FIRST:
matrix.fill_rect(5,5,16,7,BLACK)
matrix.text(num2str(hr,True),5,5,WHITE)
if T[5]==59:
platform(42,True)
if T[4]<59:
matrix.pixel(31,0,SAND_COLOR) # minutes
if T[4]==59:
platform(21,True)
matrix.pixel(13,0,SAND_COLOR) # hours
if T[3]==23:
platform(0,True)
else:
platform(42,False)
platform(21,False)
platform(0,False)
FIRST=False
def fade(input_color1, input_color2):
color1=input_color1
red1 =color1>>11& 0b11111 # extract red #13
green1=color1>>6 & 0b11111 # extract green
blue1 =color1 & 0b11111 # extract blue
color2 = input_color2
red2 =color2>>11& 0b11111 # extract red
green2=color2>>6 & 0b11111 # extract green
blue2 =color2 & 0b11111 # extract blue
inc_red =(red2- red1)/31# 31 # find increment step
inc_green=(green2-green1)/31#31
inc_blue =(blue2- blue1)/31#31
for i in range(0,32):#32
red3 =red1 +int(i*inc_red) # build colors by steps
green3=green1+int(i*inc_green)
blue3 =blue1 +int(i*inc_blue)
color3=red3<<11 | green3<<6 | blue3 # combine RGB
color_l2.append(color3) # byte swap to LCD RGB565
DONE=False
FIRST=True
ALIVE=0
fade(BLACK,GREEN)
fade(GREEN,BLUE)
fade(BLUE,RED)
fade(RED,GREEN)
matrix_reset()
matrix.fill(0)
get_time(1)
control_asm[9]=255 #100 LED brightness
init_time()
_thread.start_new_thread(core1, ())
tim = Timer(period=1000, mode=Timer.PERIODIC, callback=get_time)
while not DONE:
for pause in range(10000): #10000 fire, 15000 rain
pass
water_rgb16()
matrix.pixel(randint(2,5),0,BLUE)
ALIVE+=1
if ALIVE>100:
ALIVE=0
tim.deinit()
OE.value(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment