Created
December 9, 2021 15:57
-
-
Save benevpi/e00afd0016953b3c2ada41f88764919d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rp2 | |
import time | |
from machine import Pin | |
import array | |
import math | |
import _thread | |
import random | |
import time | |
import rp2040_pio_dma | |
import uctypes | |
import machine | |
machine.freq(200000000) | |
#TODO | |
#* Sped up to about 5 bits per pixel. Maybe make it 4 to be safe. (this will still require overclocking) | |
#* weird flashing on updating the draw frame. No idea why? | |
bit_depth = 5 | |
clock_pin = 16 | |
data_pin_start = 0 | |
latch_pin_start = 12 | |
row_pin_start = 6 | |
row_bits = 3 | |
data_bits = 192 # note must be divisible by 32 | |
row_ar_len = 50 | |
@rp2.asm_pio(out_shiftdir=1, autopull=True, pull_thresh=24, out_init=(rp2.PIO.OUT_HIGH, rp2.PIO.OUT_LOW, | |
rp2.PIO.OUT_HIGH,rp2.PIO.OUT_HIGH, rp2.PIO.OUT_HIGH, rp2.PIO.OUT_HIGH), | |
sideset_init=(rp2.PIO.OUT_LOW), fifo_join = rp2.PIO.JOIN_TX) | |
def data_hub75(): | |
#pull # actually, can I use autopull? | |
#is this a bit weird? better to use nops with side set? | |
#really simple clocking out of pins? | |
#not 100% sure how this will work as pulling in 32 bits at a time, but out won't line up with this? | |
#do I need some dummy bits? | |
#wrap_target() | |
#nop() .side(0) | |
out(pins, 6) | |
nop() .side(1) | |
nop() .side(0) | |
out(pins, 6) | |
nop() .side(1) | |
nop() .side(0) | |
out(pins, 6) | |
nop() .side(1) | |
nop() .side(0) | |
out(pins, 6) | |
nop() .side(1) | |
nop() .side(0) | |
#wrap() | |
@rp2.asm_pio(out_shiftdir=1, autopull=False,out_init=(rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW, | |
rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW), sideset_init=(rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW), | |
fifo_join=rp2.PIO.JOIN_TX) | |
def row_hub75(): | |
wrap_target() | |
pull() | |
nop() .side(2) | |
out(pins, 5) [2]#note 3 as only three pins needed for 32x32 screen. This might be wrong. Might needs all five still | |
nop() .side(3) #this triggers the latch | |
nop() .side(2) #this disables the latch | |
nop() .side(0) | |
#setup state machines | |
#can I run them at full tilt, or do they need slowing down? | |
#Seem to run at max 100MHz. Any faster and they start to splutter | |
sm_data = rp2.StateMachine(0,data_hub75, out_base=Pin(data_pin_start), sideset_base=Pin(clock_pin), | |
freq=100000000) | |
sm_row = rp2.StateMachine(1, row_hub75, out_base=Pin(row_pin_start),sideset_base=Pin(latch_pin_start), | |
freq=100000000) | |
sm_row.active(1) | |
sm_data.active(1) | |
counter = 0 | |
toggle = False | |
rows = [] | |
blocks_per_row = const(8) #each block has 24 bits, so 4 pixels x 2 scanlines | |
num_rows = const(16) | |
fast_buffer1 = array.array("L", (0 for x in range(blocks_per_row * num_rows * (1<<bit_depth)))) | |
#fast_buffer3 = array.array("L", (0 for x in range(blocks_per_row * num_rows * (1<<bit_depth)))) | |
fast_buffer2 = array.array("L", (0 for x in range(blocks_per_row * num_rows * (1<<bit_depth)))) | |
''' | |
#This isn't always contiguous | |
for i in range(blocks_per_row * num_rows): | |
fast_buffer1.append(0) | |
fast_buffer2.append(0) | |
''' | |
drawBuffer = fast_buffer1 | |
frameBuffer = fast_buffer2 | |
#fill with white | |
for j in range(num_rows): | |
rows.append([]) | |
for i in range(blocks_per_row): | |
rows[j].append(0xffffffff) | |
#fill with black | |
for j in range(num_rows): | |
rows.append([]) | |
for i in range(blocks_per_row): | |
rows[j].append(0x00000000) | |
# There are 32x32 3-bit values for each panel. | |
# Pins r1g1b1 control scanlines 0-15 while pins r2g2b2 control scanlines 16-31 | |
# We want to write 24-bits at a time so we can write out 4 pixels per scanline at a time | |
# 1st pixel 0th scanline would be the lowest bits (0-2) | |
# 1st pixel 16th scanline would be the next bits (3-5) | |
# 2nd pixel 0th scanline would be the next lowest bits (6-8) | |
# 2nd pixel 16th scanline would be the next lowest bits (9-11) | |
# continue this pattern to fill our 24-bits | |
@micropython.viper | |
def set_pixel(x:int, y:int, rgb:uint, depth:int): | |
bit_posn = ((x % 4) * 6) | |
if y > 15: | |
y = y - 17 | |
bit_posn += 3 | |
else: | |
y = y - 1 | |
# a mystery but rows 0/16 need to use y = 15 to be drawn correctly | |
if y == -1: | |
y = 15 | |
index = (y * blocks_per_row + int(x >> 2)) + (blocks_per_row * num_rows * depth) | |
val = uint(drawBuffer[index]) | |
drawBuffer[index] = val | uint(rgb << (bit_posn)) | |
@micropython.native | |
def light_xy(x:int,y:int, r:int, g:int, b:int): | |
for i in range((1<<(bit_depth))): | |
r1 = 1 if r>i else 0 | |
g1 = 1 if g>i else 0 | |
b1 = 1 if b>i else 0 | |
rgb = (r1 << 0) | (g1 << 1) | (b1 << 2); | |
set_pixel(x, y, rgb, i) | |
#p-shape | |
#should these really be stored as datapoints? | |
def p_draw(init_x, init_y, r, g, b): | |
#line 10 pixels high | |
for i in range(10): | |
light_xy(init_x, init_y+i, r, g, b) | |
#line 4 pixesl across | |
for i in range(4): | |
light_xy(init_x+i, init_y, r, g, b) | |
for i in range(4): | |
light_xy(init_x+i, init_y+4, r, g, b) | |
for i in range(3): | |
light_xy(init_x+4, init_y+i+1, r, g, b) | |
def i_draw(init_x, init_y, r, g, b): | |
for i in range(4): | |
light_xy(init_x, init_y+i+2, r, g, b) | |
light_xy(init_x, init_y, r, g, b) | |
def c_draw(init_x, init_y, r, g, b): | |
for i in range(4): | |
light_xy(init_x, init_y+i+1, r, g, b) | |
for i in range(3): | |
light_xy(init_x+1+i, init_y, r, g, b) | |
light_xy(init_x+1+i, init_y+5, r, g, b) | |
def o_draw(init_x, init_y, r, g, b): | |
for i in range(4): | |
light_xy(init_x, init_y+i+1, r, g, b) | |
light_xy(init_x+4, init_y+i+1, r, g, b) | |
for i in range(3): | |
light_xy(init_x+1+i, init_y, r, g, b) | |
light_xy(init_x+1+i, init_y+5, r, g, b) | |
@micropython.native | |
def clearBuffer(): | |
# reusing should be same or faster than reallocations | |
#for j in range(num_rows): | |
# for i in range(blocks_per_row): | |
# rows[j][i] = 0 | |
for i in range(blocks_per_row * num_rows * (1<<bit_depth)): | |
drawBuffer[i] = 0 | |
text_y = 14 | |
direction = 1 | |
def draw_text(): | |
global text_y | |
global direction | |
global writing | |
global current_rows | |
global rows | |
writing = True | |
text_y = text_y + direction | |
if text_y > 20: direction = -1 | |
if text_y < 5: direction = 1 | |
clearBuffer() | |
p_draw(3, text_y-4, 8, 1, 1) | |
i_draw(9, text_y, 4, 1, 1) | |
c_draw(11, text_y, 1, 1, 1) | |
o_draw(16, text_y, 1, 8, 1) | |
writing = False | |
#@micropython.native | |
def draw_colours(i:int): | |
clearBuffer() | |
#draw_text() | |
for x in range(32): | |
for y in range(32): | |
light_xy(x, y, (x+i)%8, (y+i)%8, (x+y+i)%8) | |
#draw_text() | |
draw_counter = 0 | |
writing = False | |
out_rows = rows | |
def draw_performance(): | |
global writing | |
global rows | |
writing = True | |
start = time.ticks_us() | |
counter = random.randint(1, 7); | |
clearBuffer() | |
for j in range(32): | |
for i in range(32): | |
set_pixel(i, j, 1 + counter % 6) | |
counter += 1 | |
end = time.ticks_us() | |
usecs = time.ticks_diff(end, start) | |
print(usecs / 1000.0) | |
writing = False | |
def draw_test_pattern(): | |
global writing | |
global rows | |
writing = True | |
clearBuffer() | |
for i in range(0,32): | |
# draw random selection of rows/colums using all colors | |
light_xy(i, 31, 0, 0, 1) | |
light_xy(i, 0, 0, 1, 0) | |
light_xy(i, 16, 0, 1, 1) | |
light_xy(0, i, 1, 0, 0) | |
light_xy(5, i, 1, 0, 1) | |
light_xy(15, i, 1, 1, 0) | |
light_xy(25, i, 1, 1, 1) | |
light_xy(30, i, 1, 0, 0) | |
writing = False | |
#draw_text() | |
draw_colours(0) | |
#tempBuffer = frameBuffer | |
#frameBuffer = drawBuffer | |
#drawBuffer = tempBuffer | |
#let's try DMA output | |
@micropython.native | |
def update(): | |
counter = 0 | |
dma_class = rp2040_pio_dma.PIO_DMA_Transfer(0, 0, 32, 8) | |
bit_depth=4 | |
loops = 16 * (1<<bit_depth) | |
transfers = 0 | |
loopc = 0 | |
frame_buff_address = int(uctypes.addressof(frameBuffer)) | |
while(True): | |
#print(loopc) | |
#loopc = loopc+1 | |
for counter in range(loops): | |
sm_row.put(counter) | |
#print(counter) | |
# Write out 8 integers that hold 8 pixels worth of 3-bit RGB (two scanlines x four pixels) | |
baseIndex = counter <<4 #* 8 | |
#dma_class.set_transfer_count(8) | |
dma_class.start_transfer_address(frame_buff_address+baseIndex) | |
#transfers = transfers+1 | |
#print(transfers) | |
''' | |
this_count=1 | |
while (this_count>0): | |
this_count = int(dma_class.transfer_count()) | |
#print(this_count) | |
''' | |
#for i in range(8): | |
# sm_data.put(frameBuffer[baseIndex + i]) | |
#sm_data.put(out_rows[counter][i]) | |
''' | |
else: | |
for i in range(8): | |
sm_data.put(0) | |
counter = counter +1 | |
if (counter > loops): | |
counter = 0 | |
''' | |
#@micropython.native | |
def change_colours(): | |
global tempBuffer | |
global frameBuffer | |
global drawBuffer | |
while True: | |
for thing in range(8): | |
#pass | |
draw_colours(thing) | |
#print(i) | |
#tempBuffer = frameBuffer | |
#frameBuffer = drawBuffer | |
#drawBuffer = tempBuffer | |
#time.sleep(1) | |
draw_colours(1) | |
tempBuffer = frameBuffer | |
frameBuffer = drawBuffer | |
drawBuffer = frameBuffer | |
#_thread.start_new_thread(change_colours, ()) | |
while(True): | |
update() | |
time.sleep(10) | |
#change_colours() | |
#tempBuffer = frameBuffer | |
#frameBuffer = drawBuffer | |
#drawBuffer = tempBuffer | |
''' | |
sm_row.put(counter) | |
# Write out 8 integers that hold 8 pixels worth of 3-bit RGB (two scanlines x four pixels) | |
baseIndex = counter * 8 | |
if (counter < 16): | |
for i in range(8): | |
val = frameBuffer[baseIndex + i] | |
sm_data.put(val) | |
#sm_data.put(out_rows[counter][i]) | |
else: | |
for i in range(8): | |
sm_data.put(0) | |
counter = counter +1 | |
if (counter > 150): | |
counter = 0 | |
''' | |
''' | |
if writing == False: | |
# perform our double buffering | |
tempBuffer = frameBuffer | |
frameBuffer = drawBuffer | |
drawBuffer = tempBuffer | |
_thread.start_new_thread(draw_text, ()) | |
''' | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment