simple case of pixelmap works (one panel, normal & r180)

This commit is contained in:
Jeff Epler 2024-12-17 14:07:24 -06:00
parent 734cd51cab
commit 56c0cc0cb2
2 changed files with 123 additions and 20 deletions

86
matrixmap.h Normal file
View file

@ -0,0 +1,86 @@
#pragma once
#include <vector>
#include <stdexcept>
using MatrixMap = std::vector<int>;
int orientation_normal(int width, int height, int x, int y) {
return x + width * y;
}
int orientation_r180(int width, int height, int x, int y) {
x = width - x - 1;
y = height - y - 1;
return orientation_normal(width, height, x, y);
}
int orientation_ccw(int width, int height, int x, int y) {
return orientation_normal(height, width, y, width - x - 1);
}
int orientation_cw(int width, int height, int x, int y) {
return orientation_normal(height, width, y - height - 1, x);
}
namespace {
template<typename Cb>
void submap(std::vector<int> &result,
int width, int height,
int start_x, int dx, int count_x_in,
int start_y, int dy, int count_y,
int half_panel_height,
const Cb &cb) {
for(int y = start_y; count_y; count_y -= 2, y += dy ) {
for(int x = start_x, count_x = count_x_in; count_x--; x += dx )
{
result.push_back(cb(width, height, x,y));
result.push_back(cb(width, height, x,y+dy*half_panel_height));
}
}
}
}
template<typename Cb>
MatrixMap make_matrixmap(
int width,
int height,
int n_addr_lines,
bool serpentine,
const Cb &cb) {
int panel_height = 2 << n_addr_lines;
if (height % panel_height != 0) {
throw std::range_error("Height does not evenly divide panel height");
}
int half_panel_height = 1 << n_addr_lines;
int v_panels = height / panel_height;
int across = width * v_panels;
MatrixMap result;
result.reserve(width*height);
printf("width=%d across=%d panel_height=%d v_panels=%d\n", width, across, panel_height, v_panels);
for(int i=0; i<half_panel_height; i++) {
for(int j=0; j<across; j++) {
int panel_no = j / width;
int panel_idx = j % width;
int x, y0, y1;
if (serpentine && panel_no % 2) {
x = width - panel_idx - 1;
y0 = (panel_no + 1) * panel_height - i - 1;
y1 = (panel_no + 1) * panel_height - i - half_panel_height - 1;
} else {
x = panel_idx;
y0 = panel_no * panel_height + i;
y1 = panel_no * panel_height + i + half_panel_height;
}
result.push_back(cb(width, height, x, y0));
result.push_back(cb(width, height, x, y1));
}
}
return result;
}

View file

@ -9,6 +9,8 @@
#include "hardware/pio.h"
#include "protomatter.pio.h"
#include "matrixmap.h"
#define countof(arr) (sizeof((arr)) / sizeof((arr)[0]))
#define PIN_R0 (5)
@ -97,7 +99,7 @@ static inline void protomatter_program_init(PIO pio, int sm, uint offset) {
}
void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int across, int down, int n_planes) {
void protomatter_convert(std::vector<uint32_t> &result, const MatrixMap &matrixmap, uint32_t *pixels, int across, int down, int n_planes) {
result.clear();
int data_count = 0;
@ -109,7 +111,7 @@ void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int ac
result.push_back(command_delay | (delay ? delay - 1 : 0));
};
auto prep_data = [&](uint32_t n) {
auto prep_data = [&data_count, &result](uint32_t n) {
assert(!data_count);
assert(n < 60000);
result.push_back(command_data | (n - 1));
@ -138,7 +140,7 @@ void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int ac
return data;
};
auto add_pixels = [&](uint32_t addr_bits, bool r0, bool g0, bool b0, bool r1, bool g1, bool b1, bool active) {
auto add_pixels = [&do_data, &result](uint32_t addr_bits, bool r0, bool g0, bool b0, bool r1, bool g1, bool b1, bool active) {
uint32_t data = (active ? oe_active : oe_inactive) | addr_bits;
if(r0) data |= (1 << PIN_R0);
if(g0) data |= (1 << PIN_G0);
@ -154,6 +156,10 @@ void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int ac
int last_bit = 0;
int prev_addr = 7;
// illuminate the right row for data in the shift register (the previous address)
uint32_t addr_bits = calc_addr_bits(prev_addr);
assert(matrixmap.size() == down * across);
#define N_BITS 10
#define OFFSET (N_BITS - n_planes)
for(int addr = 0; addr < down / 2; addr++) {
@ -163,19 +169,21 @@ void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int ac
uint32_t b = 1 << (0 + OFFSET + bit);
// the shortest /OE we can do is one DATA_OVERHEAD...
// TODO: should make sure desired duration of MSB is at least `across`
uint32_t desired_duration = 1 << last_bit;
last_bit = bit;
// illuminate the right row for data in the shift register (the previous address)
uint32_t addr_bits = calc_addr_bits(prev_addr);
prep_data(2 * across);
auto mapiter = matrixmap.begin() + 2 * addr * across;
for(int x = 0; x < across; x++) {
auto pixel0 = pixels[addr*across+x];
assert(mapiter != matrixmap.end());
auto pixel0 = pixels[*mapiter++];
auto r0 = pixel0 & r;
auto g0 = pixel0 & g;
auto b0 = pixel0 & b;
auto pixel1 = pixels[(addr+down/2) * across + x];
assert(mapiter != matrixmap.end());
auto pixel1 = pixels[*mapiter++];
auto r1 = pixel1 & r;
auto g1 = pixel1 & g;
auto b1 = pixel1 & b;
@ -186,7 +194,7 @@ void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int ac
// hold /OE low until desired time has elapsed to illuminate the LAST line
int remain = desired_duration - across;
if (remain > 0) {
do_delay(remain * CLOCKS_PER_DATA - DELAY_OVERHEAD);
do_data_delay(addr_bits | oe_active, remain * CLOCKS_PER_DATA - DELAY_OVERHEAD);
}
do_data_delay(addr_bits | oe_inactive, post_oe_delay);
@ -219,8 +227,8 @@ uint32_t rgb(unsigned r, unsigned g, unsigned b) {
}
#define ACROSS (64)
#define DOWN (32)
#define ACROSS (32)
#define DOWN (16)
#define N_PLANES (10)
#define _ (0)
#define r (1023 << 20)
@ -231,7 +239,9 @@ uint32_t rgb(unsigned r, unsigned g, unsigned b) {
#define m (r|b)
#define w (r|g|b)
uint32_t pixels[DOWN][ACROSS] = {
constexpr int width = 32, height = 16;
uint32_t pixels[height][width] = {
{_,w,_,_,r,r,_,_,_,g,_,_,b,b,b,_,c,c,_,_,y,_,y,_,m,m,m,_,w,w,w,_}, // 0
{w,_,w,_,r,_,r,_,g,_,g,_,b,_,_,_,c,_,c,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 1
{w,w,w,_,r,_,r,_,g,g,g,_,b,b,_,_,c,c,_,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 2
@ -270,16 +280,18 @@ uint32_t colorwheel(int i) {
return rgb(i * 3, 255 - i * 3, 0);
}
MatrixMap matrixmap;
void test_pattern(std::vector<uint32_t> &result, int offs) {
for(int i=0; i<ACROSS; i++) {
pixels[DOWN-5][i] = rgb(1+i*4, 1+i*4, 1+i*4);
pixels[DOWN-4][i] = colorwheel(2*i + offs / 3);
pixels[DOWN-3][i] = colorwheel(2*i+64 + offs / 5);
pixels[DOWN-2][i] = colorwheel(2*i+128 + offs / 2);
pixels[DOWN-1][i] = colorwheel(2*i+192 + offs / 7);
for(int i=0; i<width; i++) {
pixels[height-5][i] = rgb(1+i*4, 1+i*4, 1+i*4);
pixels[height-4][i] = colorwheel(2*i + offs / 3);
pixels[height-3][i] = colorwheel(2*i+64 + offs / 5);
pixels[height-2][i] = colorwheel(2*i+128 + offs / 2);
pixels[height-1][i] = colorwheel(2*i+192 + offs / 7);
}
protomatter_convert(result, &pixels[0][0], ACROSS, DOWN, N_PLANES);
protomatter_convert(result, matrixmap, &pixels[0][0], ACROSS, DOWN, N_PLANES);
}
static uint64_t monotonicns64() {
@ -319,8 +331,13 @@ void pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size, uint32_
}
}
static_assert(!(DOWN & (DOWN-1))); // is a power of two
int main(int argc, char **argv) {
int n = argc > 1 ? atoi(argv[1]) : 0;
matrixmap = make_matrixmap(width, height, 3, false, orientation_r180);
if(n == 0) {
dump_test_pattern();
exit(0);
@ -328,7 +345,7 @@ int main(int argc, char **argv) {
PIO pio = pio0;
int sm = pio_claim_unused_sm(pio, true);
int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 1);
int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 2);
if (r) {
perror("pio_sm_config_xfer");
abort();
@ -345,7 +362,7 @@ printf("clock %fMHz\n", clock_get_hz(clk_sys)/1e6);
pio_sm_set_clkdiv(pio, sm, 1.0);
protomatter_program_init(pio, sm, offset);
protomatter_pin_init(pio, sm, 4);
protomatter_pin_init(pio, sm, __builtin_ffs(DOWN)-2);
std::vector<uint32_t> data;