Skip to content

Commit

Permalink
Vertical scroll wrap, 8 scroll groups instead of 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelBell committed Sep 27, 2023
1 parent bfea726 commit cb2602f
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 28 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"cmath": "cpp",
"vreg.h": "c",
"tuple": "cpp",
"cstdlib": "c"
"cstdlib": "c",
"unordered_map": "cpp",
"numeric": "cpp"
},
"cortex-debug.variableUseNaturalFormat": false
}
4 changes: 2 additions & 2 deletions FrameFormat.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ Frame table header:
Frame tables:
Number of frames times:
Frame table length times:
2 bits: Scroll offset index - Which scroll offset from the I2C register to apply to the line address, or 0 for none.
3 bits: Scroll offset index - Which scroll offset from the I2C register to apply to the line address, or 0 for none.
2 bits: Line mode (ARGB1555, RGB888, 8-bit palette)
4 bits: Horizontal repeat, must be 1 or 2 (currently assumed to be 1)
3 bits: Horizontal repeat, must be 1 or 2 (currently assumed to be 1)
3 bytes: Line address

Palette tables:
Expand Down
2 changes: 1 addition & 1 deletion constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#endif

constexpr int PALETTE_SIZE = 32;
constexpr int NUM_SCROLL_GROUPS = 4;
constexpr int NUM_SCROLL_GROUPS = 8;

#if !SUPPORT_WIDE_MODES
// Support for normal modes, require <300MHz overclock,
Expand Down
5 changes: 5 additions & 0 deletions display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,12 @@ void DisplayDriver::read_two_lines(uint idx) {
for (int i = 0; i < 2; ++i) {
const FrameTableEntry& entry = frame_table[line_counter + i];
const ScrollConfig& scroll_config = frame_scroll[entry.frame_offset_idx()];

uint32_t addr = entry.line_address() + scroll_config.start_address_offset;
if (scroll_config.max_start_address > 0 && addr >= scroll_config.max_start_address) {
addr = entry.line_address() + scroll_config.start_address_offset2;
}

addresses[address_idx] = addr;
pixel_ptr[idx * 2 + i] = ptr;

Expand Down
6 changes: 5 additions & 1 deletion display.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class DisplayDriver
// Disbale a sprite
void clear_sprite(int8_t i);

void set_frame_data_address_offset(int idx, int offset) {
void set_frame_data_address_offset(int idx, int offset, uint32_t max_addr, int offset2) {
next_frame_scroll[idx].start_address_offset = offset;
next_frame_scroll[idx].max_start_address = max_addr;
next_frame_scroll[idx].start_address_offset2 = offset2;
}

void set_scroll_wrap(int idx, int16_t position, int16_t offset) {
Expand Down Expand Up @@ -122,6 +124,8 @@ class DisplayDriver
struct ScrollConfig {
// Everything here is in bytes
int start_address_offset = 0;
uint32_t max_start_address = 0; // If non-zero, use start_address_offset2 if addr + start_address_offset >= max_start_address_offset
int start_address_offset2 = 0;
int16_t wrap_position = 0;
int16_t wrap_offset = 0; // This is the offset from the start of the line.
};
Expand Down
28 changes: 23 additions & 5 deletions i2c_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ namespace {
constexpr uint I2C_SPRITE_REG_BASE = 0;
constexpr uint I2C_SPRITE_DATA_LEN = 7;

constexpr uint I2C_SCROLL_GROUP_REG_BASE = 0xE0;
constexpr uint I2C_SCROLL_GROUP_DATA_LEN = 13;

constexpr uint I2C_HIGH_REG_BASE = 0xC0;
constexpr uint I2C_NUM_HIGH_REGS = 0x40;
constexpr uint I2C_GPIO_INPUT_REG = 0xC0;
constexpr uint I2C_GPIO_HI_INPUT_REG = 0xC8;
constexpr uint I2C_EDID_REGISTER = 0xFB;

// Callback made after an I2C write to high registers is complete. It gives the first register written,
// The last register written, and a pointer to the memory representing all high registers (from 0xC0).
void (*i2c_reg_written_callback)(uint8_t, uint8_t, uint8_t*) = nullptr;
// The last register written, a pointer to the memory representing all high registers (from 0xC0), and a pointer to the scroll group memory
void (*i2c_reg_written_callback)(uint8_t, uint8_t, uint8_t*, uint8_t*) = nullptr;

// Calback made after an I2C write to sprite memory. It gives the index of the first sprite written,
// number of bytes written (this may go on to further sprites), and a pointer to the memory
Expand All @@ -41,6 +44,7 @@ namespace {
struct I2CContext
{
uint8_t sprite_mem[MAX_SPRITES * I2C_SPRITE_DATA_LEN];
uint8_t scroll_group_mem[(NUM_SCROLL_GROUPS - 1) * I2C_SCROLL_GROUP_DATA_LEN];
alignas(4) uint8_t high_regs[I2C_NUM_HIGH_REGS];
uint16_t cur_register;
uint8_t first_register;
Expand Down Expand Up @@ -70,6 +74,14 @@ namespace {
++cxt->cur_register;
}
cxt->data_written = true;
} else if (cxt->cur_register >= I2C_SCROLL_GROUP_REG_BASE + 1 && cxt->cur_register < I2C_SCROLL_GROUP_REG_BASE + NUM_SCROLL_GROUPS) {
// save into memory
cxt->scroll_group_mem[(cxt->cur_register - I2C_SCROLL_GROUP_REG_BASE - 1) * I2C_SCROLL_GROUP_DATA_LEN + cxt->access_idx] = i2c_read_byte(i2c);
if (++cxt->access_idx == I2C_SCROLL_GROUP_DATA_LEN) {
cxt->access_idx = 0;
++cxt->cur_register;
}
cxt->data_written = true;
} else if (cxt->cur_register >= I2C_HIGH_REG_BASE && cxt->cur_register < I2C_HIGH_REG_BASE + I2C_NUM_HIGH_REGS) {
cxt->high_regs[cxt->cur_register - I2C_HIGH_REG_BASE] = i2c_read_byte(i2c);
++cxt->cur_register;
Expand All @@ -83,11 +95,17 @@ namespace {
case I2C_SLAVE_REQUEST: // master is requesting data
// load from memory
if (cxt->cur_register >= I2C_SPRITE_REG_BASE && cxt->cur_register < I2C_SPRITE_REG_BASE + MAX_SPRITES) {
i2c_write_byte(i2c, cxt->sprite_mem[cxt->cur_register + cxt->access_idx]);
i2c_write_byte(i2c, cxt->sprite_mem[cxt->cur_register * I2C_SPRITE_DATA_LEN + cxt->access_idx]);
if (++cxt->access_idx == I2C_SPRITE_DATA_LEN) {
cxt->access_idx = 0;
++cxt->cur_register;
}
} else if (cxt->cur_register >= I2C_SCROLL_GROUP_REG_BASE + 1 && cxt->cur_register < I2C_SCROLL_GROUP_REG_BASE + NUM_SCROLL_GROUPS) {
i2c_write_byte(i2c, cxt->scroll_group_mem[(cxt->cur_register - I2C_SCROLL_GROUP_REG_BASE - 1) * I2C_SCROLL_GROUP_DATA_LEN + cxt->access_idx]);
if (++cxt->access_idx == I2C_SCROLL_GROUP_DATA_LEN) {
cxt->access_idx = 0;
++cxt->cur_register;
}
} else if (cxt->cur_register == I2C_EDID_REGISTER) {
i2c_write_byte(i2c, get_edid_data()[cxt->access_idx]);
if (++cxt->access_idx == 128) cxt->access_idx = 0;
Expand All @@ -114,7 +132,7 @@ namespace {
}
} else if (cxt->first_register >= I2C_HIGH_REG_BASE && cxt->first_register < I2C_HIGH_REG_BASE + I2C_NUM_HIGH_REGS) {
if (i2c_reg_written_callback) {
i2c_reg_written_callback(cxt->first_register, std::min(cxt->cur_register-1, int(I2C_HIGH_REG_BASE + I2C_NUM_HIGH_REGS - 1)), cxt->high_regs);
i2c_reg_written_callback(cxt->first_register, std::min(cxt->cur_register-1, int(I2C_HIGH_REG_BASE + I2C_NUM_HIGH_REGS - 1)), cxt->high_regs, cxt->scroll_group_mem);
}
}
}
Expand All @@ -130,7 +148,7 @@ namespace {
}

namespace i2c_slave_if {
uint8_t* init(void (*sprite_callback)(uint8_t, uint8_t, uint8_t*), void (*reg_callback)(uint8_t, uint8_t, uint8_t*)) {
uint8_t* init(void (*sprite_callback)(uint8_t, uint8_t, uint8_t*), void (*reg_callback)(uint8_t, uint8_t, uint8_t*, uint8_t*)) {
i2c_reg_written_callback = reg_callback;
i2c_sprite_written_callback = sprite_callback;

Expand Down
2 changes: 1 addition & 1 deletion i2c_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace i2c_slave_if {
// - Last register written (same as first if only one byte written)
// - Pointer start of high register memory (for all registers, the pointer points at register 0xC0)
// The init call returns the pointer to high register memory, so that it can be properly initialized.
uint8_t* init(void (*sprite_callback)(uint8_t, uint8_t, uint8_t*), void (*reg_callback)(uint8_t, uint8_t, uint8_t*));
uint8_t* init(void (*sprite_callback)(uint8_t, uint8_t, uint8_t*), void (*reg_callback)(uint8_t, uint8_t, uint8_t*, uint8_t*));

// Deinitialize before adjusting clocks, then init again.
void deinit();
Expand Down
33 changes: 19 additions & 14 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static uint8_t get_vreg_select_for_voltage(uint8_t voltage_50mv) {

void setup_i2c_reg_data(uint8_t* regs);

void handle_i2c_reg_write(uint8_t reg, uint8_t end_reg, uint8_t* regs) {
void handle_i2c_reg_write(uint8_t reg, uint8_t end_reg, uint8_t* regs, uint8_t* scroll_group_mem) {
// Subtract 0xC0 from regs so that register numbers match addresses
regs -= 0xC0;

Expand Down Expand Up @@ -128,20 +128,25 @@ void handle_i2c_reg_write(uint8_t reg, uint8_t end_reg, uint8_t* regs) {
display.clear_late_scanlines();
}

for (int i = 0; i < 3; ++i) {
if (REG_WRITTEN2(0xE0 + 8*i, 0xE7 + 8*i)) {
uint8_t* reg_base = &regs[0xE0 + 8*i];
int16_t wrap_position = (reg_base[1] << 8) |
for (int i = 1; i < NUM_SCROLL_GROUPS; ++i) {
if (REG_WRITTEN(0xE0 + i)) {
uint8_t* reg_base = &scroll_group_mem[(i-1) * 13];
int offset = (reg_base[2] << 16) |
(reg_base[1] << 8) |
(reg_base[0]);
int16_t wrap_offset = (reg_base[3] << 8) |
(reg_base[2]);
display.set_scroll_wrap(i+1, wrap_position, wrap_offset);

int offset = (reg_base[7] << 24) |
(reg_base[6] << 16) |
(reg_base[5] << 8) |
(reg_base[4]);
display.set_frame_data_address_offset(i+1, offset);
uint32_t max_addr = (reg_base[5] << 16) |
(reg_base[4] << 8) |
(reg_base[3]);
int offset2 = (reg_base[8] << 16) |
(reg_base[7] << 8) |
(reg_base[6]);
int16_t wrap_position = (reg_base[10] << 8) |
(reg_base[9]);
int16_t wrap_offset = (reg_base[12] << 8) |
(reg_base[11]);

display.set_scroll_wrap(i, wrap_position, wrap_offset);
display.set_frame_data_address_offset(i, offset, max_addr, offset2);
}
}

Expand Down
6 changes: 3 additions & 3 deletions pico_stick_frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ namespace pico_stick {
struct FrameTableEntry {
uint32_t entry;

uint32_t frame_offset_idx() const { return (entry >> 30); }
LineMode line_mode() const { return LineMode((entry >> 28) & 0x3); }
uint32_t h_repeat() const { return (entry >> 24) & 0xF; }
uint32_t frame_offset_idx() const { return (entry >> 29); }
LineMode line_mode() const { return LineMode((entry >> 27) & 0x3); }
uint32_t h_repeat() const { return (entry >> 24) & 0x7; }
uint32_t line_address() const { return entry & 0xFFFFFF; }
};

Expand Down

0 comments on commit cb2602f

Please sign in to comment.