Double the pixel clock rate

.. by moving the "assert CLK after each data" into the PIO program,
cutting the amount of PIO data in half.
This commit is contained in:
Jeff Epler 2025-01-24 11:17:44 -06:00
parent a532a9105e
commit 3d6b58f74d
5 changed files with 44 additions and 51 deletions

View file

@ -1,29 +1,26 @@
import sys import io
from contextlib import contextmanager import pathlib
from contextlib import redirect_stdout
import adafruit_pioasm import adafruit_pioasm
import click import click
@contextmanager
def temporary_stdout(filename):
old_stdout = sys.stdout
try:
with open(filename, "w", encoding="utf-8") as sys.stdout:
yield sys.stdout
finally:
sys.stdout = old_stdout
@click.command @click.command
@click.argument("infile") @click.argument("infile")
@click.argument("outfile") @click.argument("outfile")
def main(infile, outfile): def main(infile, outfile):
program_name = infile.rpartition("/")[2].partition(".")[0] program_name = pathlib.Path(infile).stem
print(program_name)
program = adafruit_pioasm.Program.from_file(infile, build_debuginfo=True) program = adafruit_pioasm.Program.from_file(infile, build_debuginfo=True)
with temporary_stdout(outfile): c_program = io.StringIO()
with redirect_stdout(c_program):
program.print_c_program(program_name) program.print_c_program(program_name)
with open(outfile, "w", encoding="utf-8") as out:
print("#pragma once", file=out)
print("", file=out)
print(c_program.getvalue().rstrip().replace("True", "true"), file=out)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -111,6 +111,8 @@ struct piomatter : piomatter_base {
pio_sm_config c = pio_get_default_sm_config(); pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + protomatter_wrap_target, sm_config_set_wrap(&c, offset + protomatter_wrap_target,
offset + protomatter_wrap); offset + protomatter_wrap);
// 1 side-set pin
sm_config_set_sideset(&c, 2, true, false);
sm_config_set_out_shift(&c, /* shift_right= */ false, sm_config_set_out_shift(&c, /* shift_right= */ false,
/* auto_pull = */ true, 32); /* auto_pull = */ true, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
@ -119,10 +121,11 @@ struct piomatter : piomatter_base {
// frequency is approximately the best sustainable clock with current // frequency is approximately the best sustainable clock with current
// FW & kernel. // FW & kernel.
constexpr double target_freq = constexpr double target_freq =
2700000; // 2.7MHz PIO clock -> 1.35MHz pixel clock 2700000 * 2; // 2.7MHz pixel clock, 2 PIO cycles per pixel
double div = clock_get_hz(clk_sys) / target_freq; double div = clock_get_hz(clk_sys) / target_freq;
sm_config_set_clkdiv(&c, div); sm_config_set_clkdiv(&c, div);
sm_config_set_out_pins(&c, 0, 28); sm_config_set_out_pins(&c, 0, 28);
sm_config_set_sideset_pins(&c, pinout::PIN_CLK);
pio_sm_init(pio, sm, offset, &c); pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true); pio_sm_set_enabled(pio, sm, true);

View file

@ -2,24 +2,27 @@
const int protomatter_wrap = 4; const int protomatter_wrap = 4;
const int protomatter_wrap_target = 0; const int protomatter_wrap_target = 0;
const int protomatter_sideset_pin_count = 0; const int protomatter_sideset_pin_count = 1;
const bool protomatter_sideset_enable = 0; const bool protomatter_sideset_enable = true;
const uint16_t protomatter[] = { const uint16_t protomatter[] = {
// ; data format (out-shift-right): // ; data format (out-shift-right):
// ; MSB ... LSB // ; MSB ... LSB
// ; 0 ddd......ddd: 31-bit delay // ; 0 ddd......ddd: 31-bit delay
// ; 1 ccc......ccc: 31 bit data count // ; 1 ccc......ccc: 31 bit data count
// .side_set 1 opt
// .wrap_target // .wrap_target
// top: // top:
0x6021, // out x, 1 0x6021, // out x, 1
0x605f, // out y, 31 0x605f, // out y, 31
0x0025, // jmp !x delay_loop 0x0025, // jmp !x do_delay
// data_loop: // data_loop:
0x6000, // out pins, 32 0x6000, // out pins, 32
0x0083, // jmp y--, data_loop 0x1883, // jmp y--, data_loop side 1 ; assert clk bit
// .wrap // .wrap
// do_delay:
0x6000, // out pins, 32
// delay_loop: // delay_loop:
0x0085, // jmp y--, delay_loop 0x0086, // jmp y--, delay_loop
0x0000, // jmp top 0x0000, // jmp top
// ;; fill program out to 32 instructions so nothing else can load // ;; fill program out to 32 instructions so nothing else can load
0xa042, // nop 0xa042, // nop

View file

@ -7,10 +7,10 @@
namespace piomatter { namespace piomatter {
constexpr unsigned DATA_OVERHEAD = 3; constexpr int DATA_OVERHEAD = 3;
constexpr unsigned CLOCKS_PER_DATA = 2; constexpr int CLOCKS_PER_DATA = 2;
constexpr unsigned DELAY_OVERHEAD = 5; constexpr int DELAY_OVERHEAD = 5;
constexpr unsigned CLOCKS_PER_DELAY = 1; constexpr int CLOCKS_PER_DELAY = 1;
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;
@ -137,12 +137,12 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
int data_count = 0; int data_count = 0;
auto do_delay = [&](uint32_t delay) { auto do_data_delay = [&](uint32_t data, int32_t delay) {
if (delay == 0) delay = std::max((delay / CLOCKS_PER_DELAY) - DELAY_OVERHEAD, 1);
return;
assert(delay < 1000000); assert(delay < 1000000);
assert(!data_count); assert(!data_count);
result.push_back(command_delay | (delay ? delay - 1 : 0)); result.push_back(command_delay | (delay ? delay - 1 : 0));
result.push_back(data);
}; };
auto prep_data = [&data_count, &result](uint32_t n) { auto prep_data = [&data_count, &result](uint32_t n) {
@ -153,27 +153,15 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
data_count = n; data_count = n;
}; };
auto do_data = [&](uint32_t d) {
assert(data_count);
data_count--;
result.push_back(d);
};
int32_t active_time; int32_t active_time;
auto do_data_active = [&active_time, &do_data](uint32_t d) { auto do_data_clk_active = [&active_time, &data_count, &result](uint32_t d) {
bool active = active_time > 0; bool active = active_time > 0;
active_time--; active_time--;
d |= active ? pinout::oe_active : pinout::oe_inactive; d |= active ? pinout::oe_active : pinout::oe_inactive;
do_data(d); assert(data_count);
}; data_count--;
result.push_back(d);
auto do_data_delay = [&prep_data, &do_data, &do_delay](uint32_t d,
int32_t delay) {
prep_data(1);
do_data(d);
if (delay > 0)
do_delay(delay);
}; };
auto calc_addr_bits = [](int addr) { auto calc_addr_bits = [](int addr) {
@ -195,9 +183,9 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
return data; return data;
}; };
auto add_pixels = [&do_data_active, &result](uint32_t addr_bits, bool r0, auto add_pixels = [&do_data_clk_active,
bool g0, bool b0, bool r1, &result](uint32_t addr_bits, bool r0, bool g0, bool b0,
bool g1, bool b1) { bool r1, bool g1, bool b1) {
uint32_t data = addr_bits; uint32_t data = addr_bits;
if (r0) if (r0)
data |= (1 << pinout::PIN_RGB[0]); data |= (1 << pinout::PIN_RGB[0]);
@ -212,8 +200,7 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
if (b1) if (b1)
data |= (1 << pinout::PIN_RGB[5]); data |= (1 << pinout::PIN_RGB[5]);
do_data_active(data); do_data_clk_active(data);
do_data_active(data | pinout::clk_bit);
}; };
int last_bit = 0; int last_bit = 0;
@ -243,7 +230,7 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
active_time = 1 << last_bit; active_time = 1 << last_bit;
last_bit = bit; last_bit = bit;
prep_data(2 * pixels_across); prep_data(pixels_across);
auto mapiter = matrixmap.map.begin() + 2 * addr * pixels_across; auto mapiter = matrixmap.map.begin() + 2 * addr * pixels_across;
for (size_t x = 0; x < pixels_across; x++) { for (size_t x = 0; x < pixels_across; x++) {
assert(mapiter != matrixmap.map.end()); assert(mapiter != matrixmap.map.end());

View file

@ -3,17 +3,20 @@
; 0 ddd......ddd: 31-bit delay ; 0 ddd......ddd: 31-bit delay
; 1 ccc......ccc: 31 bit data count ; 1 ccc......ccc: 31 bit data count
.side_set 1 opt
.wrap_target .wrap_target
top: top:
out x, 1 out x, 1
out y, 31 out y, 31
jmp !x delay_loop jmp !x do_delay
data_loop: data_loop:
out pins, 32 out pins, 32
jmp y--, data_loop jmp y--, data_loop side 1 ; assert clk bit
.wrap .wrap
do_delay:
out pins, 32
delay_loop: delay_loop:
jmp y--, delay_loop jmp y--, delay_loop
jmp top jmp top