Skip to content

Commit

Permalink
Restarting in another mode seems to work
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelBell committed Sep 21, 2023
1 parent 5ffc475 commit cebb9d6
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 57 deletions.
54 changes: 33 additions & 21 deletions display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,38 +103,43 @@ void DisplayDriver::run_core1() {
prepare_scanline_core1(line_counter, colourbuf, tmdsbuf, lmode);
multicore_fifo_push_blocking(0);
}

// dvi_stop() - needs implementing
}
__builtin_unreachable();
}

void DisplayDriver::init() {
//ram.init();

gpio_init(PIN_VSYNC);
gpio_put(PIN_VSYNC, 0);
gpio_set_dir(PIN_VSYNC, GPIO_OUT);
if (!ever_inited) {
gpio_init(PIN_VSYNC);
gpio_put(PIN_VSYNC, 0);
gpio_set_dir(PIN_VSYNC, GPIO_OUT);

// Setup TMDS symbol LUTs
tmds_double_encode_setup_default_lut(tmds_15bpp_lut);
memcpy(tmds_palette_luts + (PALETTE_SIZE * PALETTE_SIZE * 6), tmds_15bpp_lut, PALETTE_SIZE * PALETTE_SIZE * 2);
memcpy(tmds_palette_luts + (PALETTE_SIZE * PALETTE_SIZE * 10), tmds_15bpp_lut, PALETTE_SIZE * PALETTE_SIZE * 2);
// Setup TMDS symbol LUTs
tmds_double_encode_setup_default_lut(tmds_15bpp_lut);
memcpy(tmds_palette_luts + (PALETTE_SIZE * PALETTE_SIZE * 6), tmds_15bpp_lut, PALETTE_SIZE * PALETTE_SIZE * 2);
memcpy(tmds_palette_luts + (PALETTE_SIZE * PALETTE_SIZE * 10), tmds_15bpp_lut, PALETTE_SIZE * PALETTE_SIZE * 2);

dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
for (int i = 0; i < NUM_TMDS_BUFFERS; ++i) {
void* bufptr = (void*)&tmds_buffers[i * 3 * MAX_FRAME_WIDTH / DVI_SYMBOLS_PER_WORD];
queue_add_blocking_u32(&dvi0.q_tmds_free, &bufptr);
}
sem_init(&dvi_start_sem, 0, 1);
hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
for (int i = 0; i < NUM_TMDS_BUFFERS; ++i) {
void* bufptr = (void*)&tmds_buffers[i * 3 * MAX_FRAME_WIDTH / DVI_SYMBOLS_PER_WORD];
queue_add_blocking_u32(&dvi0.q_tmds_free, &bufptr);
}
sem_init(&dvi_start_sem, 0, 1);
hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);

Sprite::init();
Sprite::init();

for (int i = 0; i < MAX_FRAME_HEIGHT; ++i) {
for (int j = 0; j < MAX_PATCHES_PER_LINE; ++j) {
patches[i][j].data = nullptr;
for (int i = 0; i < MAX_FRAME_HEIGHT; ++i) {
for (int j = 0; j < MAX_PATCHES_PER_LINE; ++j) {
patches[i][j].data = nullptr;
}
}

ever_inited = true;
}
else {
dvi_setup(&dvi0);
}

// This calculation shouldn't overflow for any resolution we could plausibly support.
Expand Down Expand Up @@ -182,7 +187,7 @@ void DisplayDriver::run() {
bool first_frame = true;
uint heartbeat = 9;
//int frame_address_dir = 4;
while (true) {
while (!stop_display) {
if (heartbet_led) {
uint val;
if (heartbeat < 32) val = heartbeat << 3;
Expand Down Expand Up @@ -340,6 +345,13 @@ void DisplayDriver::run() {
first_frame = false;
}
}

dvi_stop(&dvi0);
sleep_ms(1);

multicore_reset_core1();

stop_display = false;
}

void DisplayDriver::main_loop() {
Expand Down
8 changes: 8 additions & 0 deletions display.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class DisplayDriver

void enable_heartbeat(bool enable) { heartbet_led = enable; }

void stop() { stop_display = true; }

private:
friend class Sprite;

Expand Down Expand Up @@ -146,4 +148,10 @@ class DisplayDriver

// Whether to output heartbeat LED
bool heartbet_led = true;

// Whether to stop
volatile bool stop_display = false;

// Whether we have been initialized
bool ever_inited = false;
};
10 changes: 10 additions & 0 deletions i2c_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "i2c_fifo.h"
#include "i2c_slave.h"
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/structs/usb.h"

#include "constants.hpp"
#include "pins.hpp"
Expand All @@ -19,6 +21,8 @@ namespace {

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 = 0xED;

// Callback made after an I2C write to high registers is complete. It gives the first register written,
Expand Down Expand Up @@ -87,6 +91,12 @@ namespace {
} 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;
} else if (cxt->cur_register == I2C_GPIO_INPUT_REG) {
i2c_write_byte(i2c, gpio_get_all() >> 23);
++cxt->cur_register;
} else if (cxt->cur_register == I2C_GPIO_HI_INPUT_REG) {
i2c_write_byte(i2c, sio_hw->gpio_hi_in | ((usb_hw->phy_direct & 0x60000) >> 11));
++cxt->cur_register;
} else if (cxt->cur_register >= I2C_HIGH_REG_BASE && cxt->cur_register < I2C_HIGH_REG_BASE + I2C_NUM_HIGH_REGS) {
i2c_write_byte(i2c, cxt->high_regs[cxt->cur_register - I2C_HIGH_REG_BASE]);
++cxt->cur_register;
Expand Down
89 changes: 55 additions & 34 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,34 @@ void handle_i2c_reg_write(uint8_t reg, uint8_t end_reg, uint8_t* regs) {
}
}

if (REG_WRITTEN(0xC2)) {
if (regs[0xC2] < 4) {
gpio_set_dir(PIN_ADC, GPIO_IN);
gpio_set_pulls(PIN_ADC, regs[0xC2] & 0x1, regs[0xC2] & 0x2);
gpio_set_input_enabled(PIN_ADC, true);
gpio_set_function(PIN_LED, GPIO_FUNC_SIO);
} else if (regs[0xC2] == 4) {
gpio_put(PIN_ADC, regs[0xC3]);
gpio_set_dir(PIN_ADC, GPIO_OUT);
gpio_set_input_enabled(PIN_ADC, true);
gpio_set_function(PIN_LED, GPIO_FUNC_SIO);
} else if (regs[0xC2] == 5) {
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, 4.f);
pwm_config_set_wrap(&config, 254);
pwm_init(PIN_ADC_PWM_SLICE_NUM, &config, true);
pwm_set_gpio_level(PIN_ADC, regs[0xC3]);
gpio_set_input_enabled(PIN_ADC, true);
gpio_set_function(PIN_ADC, GPIO_FUNC_PWM);
} else if (regs[0xC2] == 6) {
adc_gpio_init(PIN_ADC);
}
}
if (REG_WRITTEN(0xC3)) {
if (regs[0xC2] == 4) gpio_put(PIN_ADC, regs[0xC3]);
else if (regs[0xC2] == 5) pwm_set_gpio_level(PIN_ADC, regs[0xC3]);
}

if (REG_WRITTEN(0xC9)) {
sio_hw->gpio_hi_out = regs[0xC9] & 0x3F;
hw_write_masked(&usb_hw->phy_direct, (regs[0xC9] & 0xC0) << 4, 0xC00);
Expand Down Expand Up @@ -130,12 +158,8 @@ void handle_i2c_reg_write(uint8_t reg, uint8_t end_reg, uint8_t* regs) {
}
if (REG_WRITTEN(0xFF)) {
if (regs[0xFF] == 0x01) {
printf("Resetting\n");
watchdog_reboot(0x20000001, 0x15004000, 0);
}
if (regs[0xFF] == 0x02) {
printf("Resetting to DFU mode\n");
reset_usb_boot(0, 0);
//printf("Stopping\n");
display.stop();
}
}

Expand All @@ -157,8 +181,9 @@ void handle_i2c_sprite_write(uint8_t sprite, uint8_t end_sprite, uint8_t* sprite
void set_i2c_reg_data_for_frame(uint8_t* regs, const DisplayDriver::Diags& diags) {
regs -= 0xC0;

regs[0xC0] = gpio_get_all() >> 23;
regs[0xC8] = sio_hw->gpio_hi_in | ((usb_hw->phy_direct & 0x60000) >> 11);
// To reduce latency these are now handled directly in the I2C interface
//regs[0xC0] = gpio_get_all() >> 23;
//regs[0xC8] = sio_hw->gpio_hi_in | ((usb_hw->phy_direct & 0x60000) >> 11);

regs[0xD0] = (diags.vsync_time * 200) / diags.available_vsync_time;
regs[0xD1] = ((diags.scanline_total_prep_time[0] + diags.scanline_total_prep_time[1]) * 100) / diags.available_total_scanline_time;
Expand Down Expand Up @@ -279,38 +304,34 @@ int main() {

read_edid();

// Wait for I2C to indicate we should start
while (regs[0xFD] == 0) __wfe();
display.init();
display.diags_callback = handle_display_diags_callback;
printf("DV Display Driver Initialised\n");
while(true) {
// Wait for I2C to indicate we should start
while (regs[0xFD] == 0) __wfe();
display.init();
display.diags_callback = handle_display_diags_callback;
printf("DV Display Driver Initialised\n");

// Deinit I2C before adjusting clock
i2c_slave_if::deinit();
// Deinit I2C before adjusting clock
i2c_slave_if::deinit();

// Set voltage to value from I2C register - in future this might have been altered since boot.
uint vreg_select = get_vreg_select_for_voltage(i2c_slave_if::get_high_reg_table()[0xDE - 0xC0]);
hw_write_masked(&vreg_and_chip_reset_hw->vreg, vreg_select << VREG_AND_CHIP_RESET_VREG_VSEL_LSB, VREG_AND_CHIP_RESET_VREG_VSEL_BITS);
sleep_ms(10);
// Set voltage to value from I2C register - in future this might have been altered since boot.
uint vreg_select = get_vreg_select_for_voltage(i2c_slave_if::get_high_reg_table()[0xDE - 0xC0]);
hw_write_masked(&vreg_and_chip_reset_hw->vreg, vreg_select << VREG_AND_CHIP_RESET_VREG_VSEL_LSB, VREG_AND_CHIP_RESET_VREG_VSEL_BITS);
sleep_ms(10);

set_sys_clock_khz(display.get_clock_khz(), true);
set_sys_clock_khz(display.get_clock_khz(), true);

stdio_init_all();
display.get_ram().adjust_clock();

// Reinit I2C now clock is set.
i2c_slave_if::init(handle_i2c_sprite_write, handle_i2c_reg_write);
stdio_init_all();
display.get_ram().adjust_clock();

printf("DV Driver: Clock configured\n");
// Reinit I2C now clock is set.
i2c_slave_if::init(handle_i2c_sprite_write, handle_i2c_reg_write);

display.run();
printf("DV Driver: Clock configured\n");

// If run ever exits, the magic number in the RAM was wrong.
// For now we reboot if that happens
printf("DV Driver: Display failed\n");
display.run();

printf("DV Driver: Resetting\n");
watchdog_reboot(0x20000001, 0x15004000, 0);

while (true);
printf("DV Driver: Display stopped\n");
regs[0xFD] = 0;
}
}
3 changes: 2 additions & 1 deletion pins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ constexpr int PIN_LED_PWM_SLICE_NUM = 4;
constexpr int PIN_I2S_DATA = 26;
constexpr int PIN_I2S_BCLK = 27;
constexpr int PIN_I2S_LRCLK = 28;
constexpr int PIN_ADC = 29;
constexpr int PIN_ADC = 29;
constexpr int PIN_ADC_PWM_SLICE_NUM = 6;

0 comments on commit cebb9d6

Please sign in to comment.