reorganize in preparation for libifying

This commit is contained in:
Jeff Epler 2024-12-16 08:33:33 -06:00
parent b9ec9c2141
commit dc31807568
2 changed files with 151 additions and 142 deletions

View file

@ -9,6 +9,8 @@
#include "hardware/pio.h" #include "hardware/pio.h"
#include "protomatter.pio.h" #include "protomatter.pio.h"
#define countof(arr) (sizeof((arr)) / sizeof((arr)[0]))
#define PIN_R0 (5) #define PIN_R0 (5)
#define PIN_G0 (13) #define PIN_G0 (13)
#define PIN_B0 (6) #define PIN_B0 (6)
@ -24,105 +26,29 @@
#define PIN_CLK (17) // SRCLK: clocks on RISING edge #define PIN_CLK (17) // SRCLK: clocks on RISING edge
#define PIN_LAT (21) // RCLK: latches on RISING edge #define PIN_LAT (21) // RCLK: latches on RISING edge
const uint8_t all_pins[] = { typedef uint8_t pin_t;
const pin_t all_pins[] = {
PIN_R0, PIN_R0,
PIN_G0, PIN_G0,
PIN_B0, PIN_B0,
PIN_R1, PIN_R1,
PIN_G1, PIN_G1,
PIN_B1, PIN_B1,
PIN_ADDR_A,
PIN_ADDR_B,
PIN_ADDR_C,
// PIN_ADDR_D,
// PIN_ADDR_E,
PIN_OE, PIN_OE,
PIN_CLK, PIN_CLK,
PIN_LAT, PIN_LAT,
PIN_ADDR_A,
PIN_ADDR_B,
PIN_ADDR_C,
PIN_ADDR_D,
PIN_ADDR_E,
}; };
#define DATA_OVERHEAD (2) #define DATA_OVERHEAD (3)
#define DELAY_OVERHEAD (4) #define CLOCKS_PER_DATA (2)
#define DELAY_OVERHEAD (5) // including the y==0 loop iteration and "jmp top"
#define CLOCKS_PER_DELAY (1) #define CLOCKS_PER_DELAY (1)
// so for example a DATA word with a delay of 3 will take DATA_OVERHEAD+3*CLOCKS_PER_DELAY
static const struct pio_program protomatter_program = {
.instructions = protomatter,
.length = 32,
.origin = -1,
};
static inline pio_sm_config protomatter_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + protomatter_wrap_target, offset + protomatter_wrap);
return c;
}
static inline void protomatter_program_init(PIO pio, int sm, uint offset) {
for(int i=0; i<sizeof(all_pins); i++) {
int pin = all_pins[i];
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
}
pio_sm_config c = protomatter_program_get_default_config(offset);
sm_config_set_out_shift(&c, /* shift_right= */ false, /* auto_pull = */ true, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_clkdiv(&c, 1.0);
sm_config_set_out_pins(&c, 0, 28);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
uint16_t gamma_lut[256];
uint32_t rgb(unsigned r, unsigned g, unsigned b) {
assert(r < 256);
assert(g < 256);
assert(b < 256);
return (gamma_lut[r] << 20) | (gamma_lut[g] << 10) | gamma_lut[b];
}
#define ACROSS (32)
#define DOWN (16)
#define _ (0)
#define r (1023 << 20)
#define g (1023 << 10)
#define b (1023)
#define y (r|g)
#define c (g|b)
#define m (r|b)
#define w (r|g|b)
uint32_t pixels[][ACROSS] = {
{_,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
{w,_,w,_,r,_,r,_,g,_,g,_,b,_,_,_,c,_,c,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 3
{w,_,w,_,r,r,_,_,g,_,g,_,b,_,_,_,c,_,c,_,_,y,_,_,m,m,m,_,_,w,_,_}, // 4
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}, // 5
{_,c,_,_,y,y,_,_,_,m,_,_,r,r,r,_,g,g,_,_,b,_,b,_,w,w,w,_,c,c,c,_}, // 6
{c,_,c,_,y,_,y,_,m,_,m,_,r,_,_,_,g,_,g,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 7
{c,c,c,_,y,_,y,_,m,m,m,_,r,r,_,_,g,g,_,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 8
{c,_,c,_,y,_,y,_,m,_,m,_,r,_,_,_,g,_,g,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 9
{c,_,c,_,y,y,_,_,m,_,m,_,r,_,_,_,g,_,g,_,_,b,_,_,w,w,w,_,_,c,_,_}, // 10
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}, // 11
{r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g}, // 12
{y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,y}, // 13
{g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,c,b}, // 14
{c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,c,b,m}, // 15
};
#undef r
#undef g
#undef b
#undef c
#undef y
#undef w
#undef _
constexpr int data_delay_shift = 28;
constexpr uint32_t data_delay = 2;
constexpr uint32_t clock_delay = 2;
constexpr uint32_t command_data = 1u <<31; constexpr uint32_t command_data = 1u <<31;
constexpr uint32_t command_delay = 0; constexpr uint32_t command_delay = 0;
@ -136,39 +62,44 @@ constexpr uint32_t post_oe_delay = 0;
constexpr uint32_t post_latch_delay = 0; constexpr uint32_t post_latch_delay = 0;
constexpr uint32_t post_addr_delay = 50; constexpr uint32_t post_addr_delay = 50;
uint32_t colorwheel(int i) { // so for example sending 8 data words will take DATA_OVERHEAD + CLOCKS_PER_DATA*8 PIO cycles
i = i & 0xff; // and sending a delay of 5 will take DELAY_OVERHEAD + CLOCKS_PER_DELAY * 5
if(i < 85) {
return rgb(255 - i * 3, 0, i * 3); static const struct pio_program protomatter_program = {
} .instructions = protomatter,
if(i < 170) { .length = 32,
i -= 85; .origin = -1,
return rgb(0, i * 3, 255 - i * 3); };
}
i -= 170; static inline pio_sm_config protomatter_program_get_default_config(uint offset) {
return rgb(i * 3, 255 - i * 3, 0); pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + protomatter_wrap_target, offset + protomatter_wrap);
return c;
} }
std::vector<uint32_t> test_pattern(int offs) { static inline void protomatter_pin_init(PIO pio, int sm, int num_addr_pins) {
std::vector<uint32_t> result; for(int i=0; i<countof(all_pins) - 5 + num_addr_pins; i++) {
int pin = all_pins[i];
for(int i=0; i<ACROSS; i++) { pio_gpio_init(pio, pin);
pixels[11][i] = rgb(1+i*8, 1+i*8, 1+i*8); pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
//int j = 255 - i * 8;
//pixels[ 5][i] = rgb(j, j, j);
pixels[12][i] = colorwheel(2*i + offs);
pixels[13][i] = colorwheel(2*i+64 + offs);
pixels[14][i] = colorwheel(2*i+128 + offs);
pixels[15][i] = colorwheel(2*i+192 + offs);
} }
}
static inline void protomatter_program_init(PIO pio, int sm, uint offset) {
pio_sm_config c = protomatter_program_get_default_config(offset);
sm_config_set_out_shift(&c, /* shift_right= */ false, /* auto_pull = */ true, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_clkdiv(&c, 1.0);
sm_config_set_out_pins(&c, 0, 28);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
if(0) {
memset(pixels, 0, sizeof(pixels));
for(int i=0; i<DOWN; i++) {
pixels[i][2*i] = rgb(255,0,0);
}
} }
void protomatter_convert(std::vector<uint32_t> &result, uint32_t *pixels, int across, int down, int n_planes) {
result.clear();
int data_count = 0; int data_count = 0;
auto do_delay = [&](uint32_t delay) { auto do_delay = [&](uint32_t delay) {
@ -223,11 +154,10 @@ pixels[i][2*i] = rgb(255,0,0);
int last_bit = 0; int last_bit = 0;
int prev_addr = 7; int prev_addr = 7;
#define N_PLANES 10
#define N_BITS 10 #define N_BITS 10
#define OFFSET (N_BITS - N_PLANES) #define OFFSET (N_BITS - n_planes)
for(int addr = 0; addr < 8; addr++) { for(int addr = 0; addr < down / 2; addr++) {
for(int bit = N_PLANES - 1; bit >= 0; bit--) { for(int bit = n_planes - 1; bit >= 0; bit--) {
uint32_t r = 1 << (20 + OFFSET + bit); uint32_t r = 1 << (20 + OFFSET + bit);
uint32_t g = 1 << (10 + OFFSET + bit); uint32_t g = 1 << (10 + OFFSET + bit);
uint32_t b = 1 << (0 + OFFSET + bit); uint32_t b = 1 << (0 + OFFSET + bit);
@ -239,23 +169,24 @@ pixels[i][2*i] = rgb(255,0,0);
// illuminate the right row for data in the shift register (the previous address) // illuminate the right row for data in the shift register (the previous address)
uint32_t addr_bits = calc_addr_bits(prev_addr); uint32_t addr_bits = calc_addr_bits(prev_addr);
prep_data(2 * ACROSS); prep_data(2 * across);
for(int across = 0; across < ACROSS; across++) { for(int x = 0; x < across; x++) {
auto pixel0 = pixels[addr][across]; auto pixel0 = pixels[addr*across+x];
auto r0 = pixel0 & r; auto r0 = pixel0 & r;
auto g0 = pixel0 & g; auto g0 = pixel0 & g;
auto b0 = pixel0 & b; auto b0 = pixel0 & b;
auto pixel1 = pixels[addr+8][across]; auto pixel1 = pixels[(addr+down/2) * across + x];
auto r1 = pixel1 & r; auto r1 = pixel1 & r;
auto g1 = pixel1 & g; auto g1 = pixel1 & g;
auto b1 = pixel1 & b; auto b1 = pixel1 & b;
add_pixels(addr_bits, r0, g0, b0, r1, g1, b1, across < desired_duration); add_pixels(addr_bits, r0, g0, b0, r1, g1, b1, x < desired_duration);
} }
// hold /OE low until desired time has elapsed to illuminate the LAST line // hold /OE low until desired time has elapsed to illuminate the LAST line
if (desired_duration > ACROSS) { int remain = desired_duration - across;
do_delay((desired_duration - ACROSS) * DATA_OVERHEAD); if (remain > 0) {
do_delay(remain * CLOCKS_PER_DATA - DELAY_OVERHEAD);
} }
do_data_delay(addr_bits | oe_inactive, post_oe_delay); do_data_delay(addr_bits | oe_inactive, post_oe_delay);
@ -269,10 +200,10 @@ pixels[i][2*i] = rgb(255,0,0);
} }
} }
} }
return result;
} }
uint16_t gamma_lut[256];
void make_gamma_lut(double exponent) { void make_gamma_lut(double exponent) {
for(int i=0; i<256; i++) { for(int i=0; i<256; i++) {
auto v = std::max(i, int(round(1023 * pow(i / 255, exponent)))); auto v = std::max(i, int(round(1023 * pow(i / 255, exponent))));
@ -280,27 +211,103 @@ void make_gamma_lut(double exponent) {
} }
} }
uint64_t monotonicns64() { uint32_t rgb(unsigned r, unsigned g, unsigned b) {
assert(r < 256);
assert(g < 256);
assert(b < 256);
return (gamma_lut[r] << 20) | (gamma_lut[g] << 10) | gamma_lut[b];
}
#define ACROSS (32)
#define DOWN (16)
#define N_PLANES (10)
#define _ (0)
#define r (1023 << 20)
#define g (1023 << 10)
#define b (1023)
#define y (r|g)
#define c (g|b)
#define m (r|b)
#define w (r|g|b)
uint32_t pixels[][ACROSS] = {
{_,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
{w,_,w,_,r,_,r,_,g,_,g,_,b,_,_,_,c,_,c,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 3
{w,_,w,_,r,r,_,_,g,_,g,_,b,_,_,_,c,_,c,_,_,y,_,_,m,m,m,_,_,w,_,_}, // 4
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}, // 5
{_,c,_,_,y,y,_,_,_,m,_,_,r,r,r,_,g,g,_,_,b,_,b,_,w,w,w,_,c,c,c,_}, // 6
{c,_,c,_,y,_,y,_,m,_,m,_,r,_,_,_,g,_,g,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 7
{c,c,c,_,y,_,y,_,m,m,m,_,r,r,_,_,g,g,_,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 8
{c,_,c,_,y,_,y,_,m,_,m,_,r,_,_,_,g,_,g,_,b,_,b,_,_,w,_,_,_,c,_,_}, // 9
{c,_,c,_,y,y,_,_,m,_,m,_,r,_,_,_,g,_,g,_,_,b,_,_,w,w,w,_,_,c,_,_}, // 10
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}, // 11
{r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g}, // 12
{y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,y}, // 13
{g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,c,b}, // 14
{c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,y,g,c,b,m,r,g,c,b,m}, // 15
};
#undef r
#undef g
#undef b
#undef c
#undef y
#undef w
#undef _
uint32_t colorwheel(int i) {
i = i & 0xff;
if(i < 85) {
return rgb(255 - i * 3, 0, i * 3);
}
if(i < 170) {
i -= 85;
return rgb(0, i * 3, 255 - i * 3);
}
i -= 170;
return rgb(i * 3, 255 - i * 3, 0);
}
void test_pattern(std::vector<uint32_t> &result, int offs) {
for(int i=0; i<ACROSS; i++) {
pixels[11][i] = rgb(1+i*8, 1+i*8, 1+i*8);
pixels[12][i] = colorwheel(2*i + offs / 3);
pixels[13][i] = colorwheel(2*i+64 + offs / 5);
pixels[14][i] = colorwheel(2*i+128 + offs / 2);
pixels[15][i] = colorwheel(2*i+192 + offs / 7);
}
protomatter_convert(result, &pixels[0][0], ACROSS, DOWN, N_PLANES);
}
static uint64_t monotonicns64() {
struct timespec tp; struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp); clock_gettime(CLOCK_MONOTONIC, &tp);
return tp.tv_sec * UINT64_C(1000000000)+ tp.tv_nsec; return tp.tv_sec * UINT64_C(1000000000)+ tp.tv_nsec;
} }
int main(int argc, char **argv) { static void dump_test_pattern() {
{ FILE *f = fopen("pattern.txt", "w");
FILE *f = fopen("pattern.txt", "w"); std::vector<uint32_t> data;
std::vector<uint32_t> data = test_pattern(0); test_pattern(data, 0);
bool first = true; bool first = true;
fprintf(f, "[\n"); fprintf(f, "[\n");
for(auto i : data) { for(auto i : data) {
if (!first) { fprintf(f, ",\n"); } if (!first) { fprintf(f, ",\n"); }
first=false; first=false;
fprintf(f, "%u", i); } fprintf(f, "%u", i); }
fprintf(f, "]\n"); fprintf(f, "]\n");
fclose(f); fclose(f);
} }
int main(int argc, char **argv) {
if constexpr(0)
dump_test_pattern();
PIO pio = pio0; PIO pio = pio0;
int sm = pio_claim_unused_sm(pio, true); int sm = pio_claim_unused_sm(pio, true);
@ -315,13 +322,14 @@ printf("clock %fMHz\n", clock_get_hz(clk_sys)/1e6);
pio_sm_set_clkdiv(pio, sm, 1.0); pio_sm_set_clkdiv(pio, sm, 1.0);
protomatter_program_init(pio, sm, offset); protomatter_program_init(pio, sm, offset);
pio_sm_set_clkdiv(pio, sm, 1.0); protomatter_pin_init(pio, sm, 3);
std::vector<uint32_t> data;
int n = argc > 1 ? atoi(argv[1]) : 1000; int n = argc > 1 ? atoi(argv[1]) : 1000;
uint64_t start = monotonicns64(); uint64_t start = monotonicns64();
for(int i=0; i<n; i++) { for(int i=0; i<n; i++) {
std::vector<uint32_t> data = test_pattern(i); test_pattern(data, i);
uint32_t *databuf = &data[0]; uint32_t *databuf = &data[0];
size_t datasize = data.size() * sizeof(uint32_t); size_t datasize = data.size() * sizeof(uint32_t);

View file

@ -43,3 +43,4 @@ delay_loop:
nop nop
nop nop
nop nop
nop