Merge pull request #874 from 32blit/pico-picovision-board
Make building for boards that don't have headers in the SDK easier
diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt
index 64938fd..6168e30 100644
--- a/32blit-pico/CMakeLists.txt
+++ b/32blit-pico/CMakeLists.txt
@@ -39,7 +39,6 @@
${CMAKE_CURRENT_LIST_DIR}/led.cpp
${CMAKE_CURRENT_LIST_DIR}/main.cpp
${CMAKE_CURRENT_LIST_DIR}/multiplayer.cpp
- ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
)
@@ -73,11 +72,8 @@
set(BOARD_ID ${PICO_BOARD})
endif()
-if(EXISTS ${CONFIG_PATH}/config.cmake)
- include(${CONFIG_PATH}/config.cmake)
- message("Using board config \"${BLIT_BOARD_NAME}\"")
-else()
- include(${CMAKE_CURRENT_LIST_DIR}/board/pico/config.cmake)
+if(NOT EXISTS ${CONFIG_PATH}/config.cmake)
+ set(CONFIG_PATH ${CMAKE_CURRENT_LIST_DIR}/board/pico)
if(DEFINED PICO_ADDON)
message(WARNING "Using default config for \"${PICO_BOARD}\", add-on \"${PICO_ADDON}\"...")
else()
@@ -85,6 +81,9 @@
endif()
endif()
+include(${CONFIG_PATH}/config.cmake)
+message("Using board config \"${BLIT_BOARD_NAME}\"")
+
if(EXISTS ${CONFIG_PATH}/config.h)
list(APPEND BLIT_BOARD_DEFINITIONS "BLIT_BOARD_CONFIG=\"${CONFIG_PATH}/config.h\"")
endif()
@@ -149,8 +148,8 @@
pico_sdk_init()
# generate PIO headers (has to be after SDK init)
-pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789-spi.pio)
-pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789-8bit.pio)
+pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/dbi-spi.pio)
+pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/dbi-8bit.pio)
pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/spi.pio)
# include picovision drivers
@@ -180,8 +179,8 @@
blit_executable_args(${ARGN})
add_executable(${NAME} ${SOURCES})
+ target_compile_definitions(${NAME} PRIVATE PICO_EMBED_XIP_SETUP=1)
target_link_libraries(${NAME} BlitHalPico BlitEngine)
- target_link_options(${NAME} PUBLIC -specs=nano.specs -u _printf_float)
pico_enable_stdio_uart(${NAME} 1)
pico_enable_stdio_usb(${NAME} 0)
diff --git a/32blit-pico/board/display_pack/config.cmake b/32blit-pico/board/display_pack/config.cmake
index f62e455..d982cc4 100644
--- a/32blit-pico/board/display_pack/config.cmake
+++ b/32blit-pico/board/display_pack/config.cmake
@@ -1,4 +1,4 @@
set(BLIT_BOARD_NAME "Display Pack")
-blit_driver(display st7789)
+blit_driver(display dbi)
blit_driver(input gpio)
diff --git a/32blit-pico/board/display_pack_2/config.cmake b/32blit-pico/board/display_pack_2/config.cmake
index 0edcbf4..bb59ac1 100644
--- a/32blit-pico/board/display_pack_2/config.cmake
+++ b/32blit-pico/board/display_pack_2/config.cmake
@@ -1,4 +1,4 @@
set(BLIT_BOARD_NAME "Display Pack 2.0")
-blit_driver(display st7789)
+blit_driver(display dbi)
blit_driver(input gpio)
diff --git a/32blit-pico/board/display_pack_2_8/config.cmake b/32blit-pico/board/display_pack_2_8/config.cmake
new file mode 100644
index 0000000..a7a210e
--- /dev/null
+++ b/32blit-pico/board/display_pack_2_8/config.cmake
@@ -0,0 +1,4 @@
+set(BLIT_BOARD_NAME "Display Pack 2.8")
+
+blit_driver(display dbi)
+blit_driver(input gpio)
diff --git a/32blit-pico/board/display_pack_2_8/config.h b/32blit-pico/board/display_pack_2_8/config.h
new file mode 100644
index 0000000..df59db0
--- /dev/null
+++ b/32blit-pico/board/display_pack_2_8/config.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#define BUTTON_A_PIN 12
+#define BUTTON_B_PIN 13
+#define BUTTON_X_PIN 14
+#define BUTTON_Y_PIN 15
+
+// these are the defaults on a pico, but may not be on other boards
+#define LCD_CS_PIN 17
+#define LCD_SCK_PIN 18
+#define LCD_MOSI_PIN 19
+//#define LCD_VSYNC_PIN 21 // not so useful if rotated, also can't keep up with 50Hz in lores mode
+
+#define LCD_ROTATION 90
+
+#define LED_INVERTED
+#define LED_R_PIN 26
+#define LED_G_PIN 27
+#define LED_B_PIN 28
\ No newline at end of file
diff --git a/32blit-pico/board/explorer_base/config.cmake b/32blit-pico/board/explorer_base/config.cmake
index d53176a..b9bdbe7 100644
--- a/32blit-pico/board/explorer_base/config.cmake
+++ b/32blit-pico/board/explorer_base/config.cmake
@@ -7,5 +7,5 @@
)
blit_driver(audio beep)
-blit_driver(display st7789)
+blit_driver(display dbi)
blit_driver(input gpio)
diff --git a/32blit-pico/board/pimoroni_picosystem/config.cmake b/32blit-pico/board/pimoroni_picosystem/config.cmake
index f7e65a1..ac66d9c 100644
--- a/32blit-pico/board/pimoroni_picosystem/config.cmake
+++ b/32blit-pico/board/pimoroni_picosystem/config.cmake
@@ -10,5 +10,5 @@
)
blit_driver(audio beep)
-blit_driver(display st7789)
+blit_driver(display dbi)
blit_driver(input gpio)
diff --git a/32blit-pico/board/tufty2040/config.cmake b/32blit-pico/board/tufty2040/config.cmake
index b4da25b..80a52a6 100644
--- a/32blit-pico/board/tufty2040/config.cmake
+++ b/32blit-pico/board/tufty2040/config.cmake
@@ -4,5 +4,5 @@
PICO_FLASH_SIZE_BYTES=8388608
)
-blit_driver(display st7789)
+blit_driver(display dbi)
blit_driver(input gpio)
diff --git a/32blit-pico/board/tufty2040/config.h b/32blit-pico/board/tufty2040/config.h
index c43305b..7cbda62 100644
--- a/32blit-pico/board/tufty2040/config.h
+++ b/32blit-pico/board/tufty2040/config.h
@@ -15,7 +15,7 @@
#define DISPLAY_ST7789
-#define ST7789_8BIT
+#define DBI_8BIT
#define LCD_ROTATION 270
#define LCD_CS_PIN 10
#define LCD_DC_PIN 11
diff --git a/32blit-pico/st7789-8bit.pio b/32blit-pico/dbi-8bit.pio
similarity index 95%
rename from 32blit-pico/st7789-8bit.pio
rename to 32blit-pico/dbi-8bit.pio
index b4ed2e3..ac46576 100644
--- a/32blit-pico/st7789-8bit.pio
+++ b/32blit-pico/dbi-8bit.pio
@@ -1,4 +1,4 @@
-.program st7789_raw
+.program dbi_raw
.side_set 1 opt
; raw serial, nothing special
@@ -8,7 +8,7 @@
.wrap
; pixel doubling, "borrowed" from PicoSystem
-.program st7789_pixel_double
+.program dbi_pixel_double
.side_set 1 opt
.wrap_target
diff --git a/32blit-pico/st7789-spi.pio b/32blit-pico/dbi-spi.pio
similarity index 96%
rename from 32blit-pico/st7789-spi.pio
rename to 32blit-pico/dbi-spi.pio
index d754618..1040ef0 100644
--- a/32blit-pico/st7789-spi.pio
+++ b/32blit-pico/dbi-spi.pio
@@ -1,4 +1,4 @@
-.program st7789_raw
+.program dbi_raw
.side_set 1 opt
; raw serial, nothing special
@@ -8,7 +8,7 @@
.wrap
; pixel doubling, "borrowed" from PicoSystem
-.program st7789_pixel_double
+.program dbi_pixel_double
.side_set 1 opt
.wrap_target
diff --git a/32blit-pico/display/dbi.cpp b/32blit-pico/display/dbi.cpp
new file mode 100644
index 0000000..4b6d3be
--- /dev/null
+++ b/32blit-pico/display/dbi.cpp
@@ -0,0 +1,534 @@
+#include <cstdlib>
+#include <math.h>
+
+#include "display.hpp"
+
+#include "hardware/clocks.h"
+#include "hardware/dma.h"
+#include "hardware/irq.h"
+#include "hardware/pwm.h"
+#include "pico/binary_info.h"
+#include "pico/time.h"
+
+#include "config.h"
+
+#ifdef DBI_8BIT
+#include "dbi-8bit.pio.h"
+#else
+#include "dbi-spi.pio.h"
+#endif
+
+using namespace blit;
+
+// double buffering for lores
+static volatile int buf_index = 0;
+
+static volatile bool do_render = true;
+
+static bool have_vsync = false;
+static bool backlight_enabled = false;
+static uint32_t last_render = 0;
+
+enum MADCTL : uint8_t {
+ // writing to internal memory
+ ROW_ORDER = 0b10000000, // MY / y flip
+ COL_ORDER = 0b01000000, // MX / x flip
+ SWAP_XY = 0b00100000, // AKA "MV"
+
+ // scanning out from internal memory
+ SCAN_ORDER = 0b00010000,
+ RGB = 0b00001000,
+ HORIZ_ORDER = 0b00000100
+};
+
+static const uint8_t rotations[]{
+ 0, // 0
+ MADCTL::HORIZ_ORDER | MADCTL::SWAP_XY | MADCTL::COL_ORDER, // 90
+ MADCTL::HORIZ_ORDER | MADCTL::SCAN_ORDER | MADCTL::COL_ORDER | MADCTL::ROW_ORDER, // 180
+ MADCTL::SCAN_ORDER | MADCTL::SWAP_XY | MADCTL::ROW_ORDER // 270
+};
+
+// standard commands
+enum MIPIDCS
+{
+ Nop = 0x00,
+ SoftReset = 0x01,
+ GetAddressMode = 0x0B,
+ GetPixelFormat = 0x0C,
+ EnterSleepMode = 0x10,
+ ExitSleepMode = 0x11,
+ ExitInvertMode = 0x20,
+ EnterInvertMode = 0x21,
+ DisplayOff = 0x28,
+ DisplayOn = 0x29,
+ SetColumnAddress = 0x2A,
+ SetRowAddress = 0x2B,
+ WriteMemoryStart = 0x2C,
+ SetTearOff = 0x34,
+ SetTearOn = 0x35,
+ SetAddressMode = 0x36,
+ SetPixelFormat = 0x3A,
+ SetTearScanline = 0x44,
+};
+
+enum ST7789Reg
+{
+ RAMCTRL = 0xB0,
+ PORCTRL = 0xB2,
+ GCTRL = 0xB7,
+ VCOMS = 0xBB,
+ LCMCTRL = 0xC0,
+ VDVVRHEN = 0xC2,
+ VRHS = 0xC3,
+ VDVS = 0xC4,
+ FRCTRL2 = 0xC6,
+ PWCTRL1 = 0xD0,
+ PVGAMCTRL = 0xE0,
+ NVGAMCTRL = 0xE1,
+};
+
+static PIO pio = pio0;
+static uint pio_sm = 0;
+static uint pio_offset = 0, pio_double_offset = 0;
+
+static uint32_t dma_channel = 0;
+
+static uint16_t win_w, win_h; // window size
+
+static bool write_mode = false; // in RAMWR
+static bool pixel_double = false;
+static uint16_t *upd_frame_buffer = nullptr;
+
+// frame buffer where pixel data is stored
+static uint16_t *frame_buffer = nullptr;
+
+// pixel double scanline counter
+static volatile int cur_scanline = DISPLAY_HEIGHT;
+
+// PIO helpers
+static void pio_put_byte(PIO pio, uint sm, uint8_t b) {
+ while (pio_sm_is_tx_fifo_full(pio, sm));
+ *(volatile uint8_t*)&pio->txf[sm] = b;
+}
+
+static void pio_wait(PIO pio, uint sm) {
+ uint32_t stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + sm);
+ pio->fdebug |= stall_mask;
+ while(!(pio->fdebug & stall_mask));
+}
+
+// used for pixel doubling
+static void __isr dbi_dma_irq_handler() {
+ if(dma_channel_get_irq0_status(dma_channel)) {
+ dma_channel_acknowledge_irq0(dma_channel);
+
+ if(++cur_scanline > win_h / 2)
+ return;
+
+ auto count = cur_scanline == (win_h + 1) / 2 ? win_w / 4 : win_w / 2;
+
+ dma_channel_set_trans_count(dma_channel, count, false);
+ dma_channel_set_read_addr(dma_channel, upd_frame_buffer + (cur_scanline - 1) * (win_w / 2), true);
+ }
+}
+
+static void command(uint8_t command, size_t len = 0, const char *data = nullptr) {
+ pio_wait(pio, pio_sm);
+
+ if(write_mode) {
+ // reconfigure to 8 bits
+ pio_sm_set_enabled(pio, pio_sm, false);
+ pio->sm[pio_sm].shiftctrl &= ~PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS;
+ pio->sm[pio_sm].shiftctrl |= (8 << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB) | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS;
+
+ // switch back to raw
+ pio_sm_restart(pio, pio_sm);
+ pio_sm_set_wrap(pio, pio_sm, pio_offset + dbi_raw_wrap_target, pio_offset + dbi_raw_wrap);
+ pio_sm_exec(pio, pio_sm, pio_encode_jmp(pio_offset));
+
+ pio_sm_set_enabled(pio, pio_sm, true);
+ write_mode = false;
+ }
+
+ gpio_put(LCD_CS_PIN, 0);
+
+ gpio_put(LCD_DC_PIN, 0); // command mode
+ pio_put_byte(pio, pio_sm, command);
+
+ if(data) {
+ pio_wait(pio, pio_sm);
+ gpio_put(LCD_DC_PIN, 1); // data mode
+
+ for(size_t i = 0; i < len; i++)
+ pio_put_byte(pio, pio_sm, data[i]);
+ }
+
+ pio_wait(pio, pio_sm);
+ gpio_put(LCD_CS_PIN, 1);
+}
+
+static void set_window(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ uint32_t cols = __builtin_bswap32((x << 16) | (x + w - 1));
+ uint32_t rows = __builtin_bswap32((y << 16) | (y + h - 1));
+
+ command(MIPIDCS::SetColumnAddress, 4, (const char *)&cols);
+ command(MIPIDCS::SetRowAddress, 4, (const char *)&rows);
+
+ win_w = w;
+ win_h = h;
+}
+
+static void send_init_sequence() {
+ command(MIPIDCS::SoftReset);
+
+ sleep_ms(150);
+
+#ifdef LCD_VSYNC_PIN
+ command(MIPIDCS::SetTearOn, 1, "\x00"); // enable frame sync signal if used
+#endif
+
+ command(MIPIDCS::SetPixelFormat, 1, "\x05"); // 16 bits per pixel
+
+ int window_x = 0, window_y = 0;
+
+ if(DISPLAY_WIDTH == 240 && DISPLAY_HEIGHT == 240) {
+ command(ST7789Reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
+ command(ST7789Reg::GCTRL, 1, "\x14");
+ command(ST7789Reg::VCOMS, 1, "\x37");
+ command(ST7789Reg::LCMCTRL, 1, "\x2c");
+ command(ST7789Reg::VDVVRHEN, 1, "\x01");
+ command(ST7789Reg::VRHS, 1, "\x12");
+ command(ST7789Reg::VDVS, 1, "\x20");
+ command(ST7789Reg::PWCTRL1, 2, "\xa4\xa1");
+
+ command(ST7789Reg::PVGAMCTRL, 14, "\xD0\x08\x11\x08\x0c\x15\x39\x33\x50\x36\x13\x14\x29\x2d");
+ command(ST7789Reg::NVGAMCTRL, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0b\x16\x14\x2f\x31");
+
+
+ // trigger "vsync" slightly earlier to avoid tearing while pixel-doubling
+ // (this is still outside of the visible part of the screen)
+ command(MIPIDCS::SetTearScanline, 2, "\x01\x2C");
+ }
+
+ if(DISPLAY_WIDTH == 320 && DISPLAY_HEIGHT == 240) {
+ command(ST7789Reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
+ command(ST7789Reg::GCTRL, 1, "\x35");
+ command(ST7789Reg::VCOMS, 1, "\x1f");
+ command(ST7789Reg::LCMCTRL, 1, "\x2c");
+ command(ST7789Reg::VDVVRHEN, 1, "\x01");
+ command(ST7789Reg::VRHS, 1, "\x12");
+ command(ST7789Reg::VDVS, 1, "\x20");
+ command(ST7789Reg::PWCTRL1, 2, "\xa4\xa1");
+ command(0xd6, 1, "\xa1"); // ???
+ command(ST7789Reg::PVGAMCTRL, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D");
+ command(ST7789Reg::NVGAMCTRL, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31");
+ }
+
+ command(ST7789Reg::FRCTRL2, 1, "\x15"); // 50Hz
+
+ command(MIPIDCS::EnterInvertMode); // set inversion mode
+ command(MIPIDCS::ExitSleepMode); // leave sleep mode
+ command(MIPIDCS::DisplayOn); // turn display on
+
+ sleep_ms(100);
+
+ uint8_t madctl = MADCTL::RGB | rotations[LCD_ROTATION / 90];
+ command(MIPIDCS::SetAddressMode, 1, (char *)&madctl);
+
+ // setup correct addressing window
+ if(DISPLAY_WIDTH == 240 && DISPLAY_HEIGHT == 135) {
+ window_x = 40;
+ window_y = 53;
+ }
+
+ set_window(window_x, window_y, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+}
+
+static void prepare_write() {
+ pio_wait(pio, pio_sm);
+
+ // setup for writing
+ uint8_t r = MIPIDCS::WriteMemoryStart;
+ gpio_put(LCD_CS_PIN, 0);
+
+ gpio_put(LCD_DC_PIN, 0); // command mode
+ pio_put_byte(pio, pio_sm, r);
+ pio_wait(pio, pio_sm);
+
+ gpio_put(LCD_DC_PIN, 1); // data mode
+
+ pio_sm_set_enabled(pio, pio_sm, false);
+ pio_sm_restart(pio, pio_sm);
+
+ if(pixel_double) {
+ // switch program
+ pio_sm_set_wrap(pio, pio_sm, pio_double_offset + dbi_pixel_double_wrap_target, pio_double_offset + dbi_pixel_double_wrap);
+
+ // 32 bits, no autopull
+ pio->sm[pio_sm].shiftctrl &= ~(PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
+
+ pio_sm_exec(pio, pio_sm, pio_encode_jmp(pio_double_offset));
+
+ // reconfigure dma size
+ dma_channel_hw_addr(dma_channel)->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS;
+ dma_channel_hw_addr(dma_channel)->al1_ctrl |= DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB;
+ } else {
+ // 16 bits, autopull
+ pio->sm[pio_sm].shiftctrl &= ~PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS;
+ pio->sm[pio_sm].shiftctrl |= (16 << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB) | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS;
+
+ dma_channel_hw_addr(dma_channel)->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS;
+ dma_channel_hw_addr(dma_channel)->al1_ctrl |= DMA_SIZE_16 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB;
+ }
+
+ pio_sm_set_enabled(pio, pio_sm, true);
+
+ write_mode = true;
+}
+
+static void update() {
+ dma_channel_wait_for_finish_blocking(dma_channel);
+
+ if(!write_mode)
+ prepare_write();
+
+ if(pixel_double) {
+ cur_scanline = 0;
+ upd_frame_buffer = frame_buffer;
+ dma_channel_set_trans_count(dma_channel, win_w / 4, false);
+ } else
+ dma_channel_set_trans_count(dma_channel, win_w * win_h, false);
+
+ dma_channel_set_read_addr(dma_channel, frame_buffer, true);
+}
+
+static void set_backlight(uint8_t brightness) {
+#ifdef LCD_BACKLIGHT_PIN
+ // gamma correct the provided 0-255 brightness value onto a
+ // 0-65535 range for the pwm counter
+ float gamma = 2.8;
+ uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f);
+ pwm_set_gpio_level(LCD_BACKLIGHT_PIN, value);
+#endif
+}
+
+static bool vsync_callback(gpio_irq_callback_t callback) {
+#ifdef LCD_VSYNC_PIN
+ gpio_set_irq_enabled_with_callback(LCD_VSYNC_PIN, GPIO_IRQ_EDGE_RISE, true, callback);
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void set_pixel_double(bool pd) {
+ pixel_double = pd;
+
+ // nop to reconfigure PIO
+ if(write_mode)
+ command(0);
+
+ if(pixel_double) {
+ dma_channel_acknowledge_irq0(dma_channel);
+ dma_channel_set_irq0_enabled(dma_channel, true);
+ } else
+ dma_channel_set_irq0_enabled(dma_channel, false);
+}
+
+static void clear() {
+ if(!write_mode)
+ prepare_write();
+
+ for(int i = 0; i < win_w * win_h; i++)
+ pio_sm_put_blocking(pio, pio_sm, 0);
+}
+
+static bool dma_is_busy() {
+ if(pixel_double && cur_scanline <= win_h / 2)
+ return true;
+
+ return dma_channel_is_busy(dma_channel);
+}
+
+static void vsync_callback(uint gpio, uint32_t events) {
+ if(!do_render && !dma_is_busy()) {
+ ::update();
+ do_render = true;
+ }
+}
+
+void init_display() {
+ frame_buffer = screen_fb;
+
+ // configure pins
+ gpio_set_function(LCD_DC_PIN, GPIO_FUNC_SIO);
+ gpio_set_dir(LCD_DC_PIN, GPIO_OUT);
+
+ gpio_set_function(LCD_CS_PIN, GPIO_FUNC_SIO);
+ gpio_set_dir(LCD_CS_PIN, GPIO_OUT);
+ gpio_put(LCD_CS_PIN, 1);
+
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_DC_PIN, "Display D/C"));
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_CS_PIN, "Display CS"));
+
+ // if supported by the display then the vsync pin is
+ // toggled high during vertical blanking period
+#ifdef LCD_VSYNC_PIN
+ gpio_set_function(LCD_VSYNC_PIN, GPIO_FUNC_SIO);
+ gpio_set_dir(LCD_VSYNC_PIN, GPIO_IN);
+ gpio_set_pulls(LCD_VSYNC_PIN, false, true);
+
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_VSYNC_PIN, "Display TE/VSync"));
+#endif
+
+ // if a backlight pin is provided then set it up for
+ // pwm control
+#ifdef LCD_BACKLIGHT_PIN
+ pwm_config pwm_cfg = pwm_get_default_config();
+ pwm_set_wrap(pwm_gpio_to_slice_num(LCD_BACKLIGHT_PIN), 65535);
+ pwm_init(pwm_gpio_to_slice_num(LCD_BACKLIGHT_PIN), &pwm_cfg, true);
+ gpio_set_function(LCD_BACKLIGHT_PIN, GPIO_FUNC_PWM);
+
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_BACKLIGHT_PIN, "Display Backlight"));
+#endif
+
+#ifdef DBI_8BIT
+ // init RD
+ gpio_init(LCD_RD_PIN);
+ gpio_set_dir(LCD_RD_PIN, GPIO_OUT);
+ gpio_put(LCD_RD_PIN, 1);
+
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_RD_PIN, "Display RD"));
+#endif
+
+#ifdef LCD_RESET_PIN
+ gpio_set_function(LCD_RESET_PIN, GPIO_FUNC_SIO);
+ gpio_set_dir(LCD_RESET_PIN, GPIO_OUT);
+ gpio_put(LCD_RESET_PIN, 0);
+ sleep_ms(100);
+ gpio_put(LCD_RESET_PIN, 1);
+
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_RESET_PIN, "Display Reset"));
+#endif
+
+ // setup PIO
+ pio_offset = pio_add_program(pio, &dbi_raw_program);
+ pio_double_offset = pio_add_program(pio, &dbi_pixel_double_program);
+
+ pio_sm = pio_claim_unused_sm(pio, true);
+
+ pio_sm_config cfg = dbi_raw_program_get_default_config(pio_offset);
+
+#ifdef DBI_8BIT
+ const int out_width = 8;
+#else // SPI
+ const int out_width = 1;
+#endif
+
+ const int clkdiv = std::ceil(clock_get_hz(clk_sys) / float(LCD_MAX_CLOCK * 2));
+ sm_config_set_clkdiv(&cfg, clkdiv);
+
+ sm_config_set_out_shift(&cfg, false, true, 8);
+ sm_config_set_out_pins(&cfg, LCD_MOSI_PIN, out_width);
+ sm_config_set_fifo_join(&cfg, PIO_FIFO_JOIN_TX);
+ sm_config_set_sideset_pins(&cfg, LCD_SCK_PIN);
+
+ // init pins
+ for(int i = 0; i < out_width; i++)
+ pio_gpio_init(pio, LCD_MOSI_PIN + i);
+
+ pio_gpio_init(pio, LCD_SCK_PIN);
+
+ pio_sm_set_consecutive_pindirs(pio, pio_sm, LCD_MOSI_PIN, out_width, true);
+ pio_sm_set_consecutive_pindirs(pio, pio_sm, LCD_SCK_PIN, 1, true);
+
+ pio_sm_init(pio, pio_sm, pio_offset, &cfg);
+ pio_sm_set_enabled(pio, pio_sm, true);
+
+#ifdef DBI_8BIT
+ // these are really D0/WR
+ bi_decl_if_func_used(bi_pin_mask_with_name(0xFF << LCD_MOSI_PIN, "Display Data"));
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_SCK_PIN, "Display WR"));
+#else
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_MOSI_PIN, "Display TX"));
+ bi_decl_if_func_used(bi_1pin_with_name(LCD_SCK_PIN, "Display SCK"));
+#endif
+
+ // send initialisation sequence for our standard displays based on the width and height
+ send_init_sequence();
+
+ // initialise dma channel for transmitting pixel data to screen
+ dma_channel = dma_claim_unused_channel(true);
+ dma_channel_config config = dma_channel_get_default_config(dma_channel);
+ channel_config_set_transfer_data_size(&config, DMA_SIZE_16);
+ channel_config_set_dreq(&config, pio_get_dreq(pio, pio_sm, true));
+ dma_channel_configure(
+ dma_channel, &config, &pio->txf[pio_sm], frame_buffer, DISPLAY_WIDTH * DISPLAY_HEIGHT, false);
+
+ irq_add_shared_handler(DMA_IRQ_0, dbi_dma_irq_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
+ irq_set_enabled(DMA_IRQ_0, true);
+
+ clear();
+
+ have_vsync = vsync_callback(vsync_callback);
+}
+
+void update_display(uint32_t time) {
+ if((do_render || (!have_vsync && time - last_render >= 20)) && (fb_double_buffer || !dma_is_busy())) {
+ if(fb_double_buffer) {
+ buf_index ^= 1;
+
+ screen.data = (uint8_t *)screen_fb + (buf_index) * get_display_page_size();
+ frame_buffer = (uint16_t *)screen.data;
+ }
+
+ ::render(time);
+
+ if(!have_vsync) {
+ while(dma_is_busy()) {} // may need to wait for lores.
+ ::update();
+ }
+
+ if(last_render && !backlight_enabled) {
+ // the first render should have made it to the screen at this point
+ set_backlight(255);
+ backlight_enabled = true;
+ }
+
+ last_render = time;
+ do_render = false;
+ }
+}
+
+void init_display_core1() {
+}
+
+void update_display_core1() {
+}
+
+bool display_render_needed() {
+ return do_render;
+}
+
+bool display_mode_supported(blit::ScreenMode new_mode, const blit::SurfaceTemplate &new_surf_template) {
+ if(new_surf_template.format != blit::PixelFormat::RGB565)
+ return false;
+
+ // TODO: could allow smaller sizes with window
+ blit::Size expected_bounds(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+
+ if(new_surf_template.bounds == expected_bounds || new_surf_template.bounds == expected_bounds / 2)
+ return true;
+
+ return false;
+}
+
+void display_mode_changed(blit::ScreenMode new_mode, blit::SurfaceTemplate &new_surf_template) {
+ if(have_vsync)
+ do_render = true; // prevent starting an update during switch
+
+ set_pixel_double(new_mode == ScreenMode::lores);
+
+ if(new_mode == ScreenMode::hires)
+ frame_buffer = screen_fb;
+}
diff --git a/32blit-pico/display/st7789.cpp b/32blit-pico/display/st7789.cpp
deleted file mode 100644
index 7cf74f9..0000000
--- a/32blit-pico/display/st7789.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "display.hpp"
-
-#include "config.h"
-
-#include "st7789.hpp"
-
-using namespace blit;
-
-// double buffering for lores
-static volatile int buf_index = 0;
-
-static volatile bool do_render = true;
-
-static bool have_vsync = false;
-static bool backlight_enabled = false;
-static uint32_t last_render = 0;
-
-static void vsync_callback(uint gpio, uint32_t events) {
- if(!do_render && !st7789::dma_is_busy()) {
- st7789::update();
- do_render = true;
- }
-}
-
-void init_display() {
- st7789::frame_buffer = screen_fb;
- st7789::init();
- st7789::clear();
-
- have_vsync = st7789::vsync_callback(vsync_callback);
-}
-
-void update_display(uint32_t time) {
- if((do_render || (!have_vsync && time - last_render >= 20)) && (fb_double_buffer || !st7789::dma_is_busy())) {
- if(fb_double_buffer) {
- buf_index ^= 1;
-
- screen.data = (uint8_t *)screen_fb + (buf_index) * get_display_page_size();
- st7789::frame_buffer = (uint16_t *)screen.data;
- }
-
- ::render(time);
-
- if(!have_vsync) {
- while(st7789::dma_is_busy()) {} // may need to wait for lores.
- st7789::update();
- }
-
- if(last_render && !backlight_enabled) {
- // the first render should have made it to the screen at this point
- st7789::set_backlight(255);
- backlight_enabled = true;
- }
-
- last_render = time;
- do_render = false;
- }
-}
-
-void init_display_core1() {
-}
-
-void update_display_core1() {
-}
-
-bool display_render_needed() {
- return do_render;
-}
-
-bool display_mode_supported(blit::ScreenMode new_mode, const blit::SurfaceTemplate &new_surf_template) {
- if(new_surf_template.format != blit::PixelFormat::RGB565)
- return false;
-
- // TODO: could allow smaller sizes with window
- blit::Size expected_bounds(DISPLAY_WIDTH, DISPLAY_HEIGHT);
-
- if(new_surf_template.bounds == expected_bounds || new_surf_template.bounds == expected_bounds / 2)
- return true;
-
- return false;
-}
-
-void display_mode_changed(blit::ScreenMode new_mode, blit::SurfaceTemplate &new_surf_template) {
- if(have_vsync)
- do_render = true; // prevent starting an update during switch
-
- st7789::set_pixel_double(new_mode == ScreenMode::lores);
-
- if(new_mode == ScreenMode::hires)
- st7789::frame_buffer = screen_fb;
-}
diff --git a/32blit-pico/main.cpp b/32blit-pico/main.cpp
index 4ff8457..2f33434 100644
--- a/32blit-pico/main.cpp
+++ b/32blit-pico/main.cpp
@@ -17,6 +17,7 @@
#include "input.hpp"
#include "led.hpp"
#include "multiplayer.hpp"
+#include "storage.hpp"
#include "usb.hpp"
#include "engine/api_private.hpp"
@@ -25,6 +26,11 @@
static blit::AudioChannel channels[CHANNEL_COUNT];
+// override terminate handler to save ~20-30k
+namespace __cxxabiv1 {
+ std::terminate_handler __terminate_handler = std::abort;
+}
+
static uint32_t now() {
return to_ms_since_boot(get_absolute_time());
}
@@ -198,10 +204,13 @@
int main() {
#if OVERCLOCK_250
+#ifndef PICO_RP2350
// Apply a modest overvolt, default is 1.10v.
// this is required for a stable 250MHz on some RP2040s
vreg_set_voltage(VREG_VOLTAGE_1_20);
sleep_ms(10);
+#endif
+
set_sys_clock_khz(250000, false);
#endif
diff --git a/32blit-pico/st7789.cpp b/32blit-pico/st7789.cpp
deleted file mode 100644
index 5687b32..0000000
--- a/32blit-pico/st7789.cpp
+++ /dev/null
@@ -1,452 +0,0 @@
-#include "st7789.hpp"
-
-#include <cstdlib>
-#include <math.h>
-
-#include "hardware/clocks.h"
-#include "hardware/dma.h"
-#include "hardware/irq.h"
-#include "hardware/pwm.h"
-#include "pico/binary_info.h"
-#include "pico/time.h"
-
-#include "config.h"
-
-#ifdef ST7789_8BIT
-#include "st7789-8bit.pio.h"
-#else
-#include "st7789-spi.pio.h"
-#endif
-
-namespace st7789 {
-
- enum MADCTL : uint8_t {
- // writing to internal memory
- ROW_ORDER = 0b10000000, // MY / y flip
- COL_ORDER = 0b01000000, // MX / x flip
- SWAP_XY = 0b00100000, // AKA "MV"
-
- // scanning out from internal memory
- SCAN_ORDER = 0b00010000,
- RGB = 0b00001000,
- HORIZ_ORDER = 0b00000100
- };
-
- static const uint8_t rotations[]{
- 0, // 0
- MADCTL::HORIZ_ORDER | MADCTL::SWAP_XY | MADCTL::COL_ORDER, // 90
- MADCTL::HORIZ_ORDER | MADCTL::SCAN_ORDER | MADCTL::COL_ORDER | MADCTL::ROW_ORDER, // 180
- MADCTL::SCAN_ORDER | MADCTL::SWAP_XY | MADCTL::ROW_ORDER // 270
- };
-
- enum reg {
- SWRESET = 0x01,
- TEOFF = 0x34,
- TEON = 0x35,
- MADCTL = 0x36,
- COLMOD = 0x3A,
- GCTRL = 0xB7,
- VCOMS = 0xBB,
- LCMCTRL = 0xC0,
- VDVVRHEN = 0xC2,
- VRHS = 0xC3,
- VDVS = 0xC4,
- FRCTRL2 = 0xC6,
- PWCTRL1 = 0xD0,
- PORCTRL = 0xB2,
- PVGAMCTRL = 0xE0,
- NVGAMCTRL = 0xE1,
- INVOFF = 0x20,
- SLPOUT = 0x11,
- DISPON = 0x29,
- GAMSET = 0x26,
- DISPOFF = 0x28,
- RAMWR = 0x2C,
- INVON = 0x21,
- CASET = 0x2A,
- RASET = 0x2B,
- STE = 0x44
- };
-
- static PIO pio = pio0;
- static uint pio_sm = 0;
- static uint pio_offset = 0, pio_double_offset = 0;
-
- static uint32_t dma_channel = 0;
-
- // screen properties
- static const uint16_t width = DISPLAY_WIDTH;
- static const uint16_t height = DISPLAY_HEIGHT;
-
- static uint16_t win_w, win_h; // window size
-
- static bool write_mode = false; // in RAMWR
- static bool pixel_double = false;
- static uint16_t *upd_frame_buffer = nullptr;
-
- // frame buffer where pixel data is stored
- uint16_t *frame_buffer = nullptr;
-
- // pixel double scanline counter
- static volatile int cur_scanline = 240;
-
- void prepare_write();
-
- // PIO helpers
- static void pio_put_byte(PIO pio, uint sm, uint8_t b) {
- while (pio_sm_is_tx_fifo_full(pio, sm));
- *(volatile uint8_t*)&pio->txf[sm] = b;
- }
-
- static void pio_wait(PIO pio, uint sm) {
- uint32_t stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + sm);
- pio->fdebug |= stall_mask;
- while(!(pio->fdebug & stall_mask));
- }
-
- // used for pixel doubling
- static void __isr st7789_dma_irq_handler() {
- if(dma_channel_get_irq0_status(dma_channel)) {
- dma_channel_acknowledge_irq0(dma_channel);
-
- if(++cur_scanline > win_h / 2)
- return;
-
- auto count = cur_scanline == (win_h + 1) / 2 ? win_w / 4 : win_w / 2;
-
- dma_channel_set_trans_count(dma_channel, count, false);
- dma_channel_set_read_addr(dma_channel, upd_frame_buffer + (cur_scanline - 1) * (win_w / 2), true);
- }
- }
-
- void init(bool auto_init_sequence) {
- // configure pins
- gpio_set_function(LCD_DC_PIN, GPIO_FUNC_SIO);
- gpio_set_dir(LCD_DC_PIN, GPIO_OUT);
-
- gpio_set_function(LCD_CS_PIN, GPIO_FUNC_SIO);
- gpio_set_dir(LCD_CS_PIN, GPIO_OUT);
- gpio_put(LCD_CS_PIN, 1);
-
- bi_decl_if_func_used(bi_1pin_with_name(LCD_DC_PIN, "Display D/C"));
- bi_decl_if_func_used(bi_1pin_with_name(LCD_CS_PIN, "Display CS"));
-
- // if supported by the display then the vsync pin is
- // toggled high during vertical blanking period
-#ifdef LCD_VSYNC_PIN
- gpio_set_function(LCD_VSYNC_PIN, GPIO_FUNC_SIO);
- gpio_set_dir(LCD_VSYNC_PIN, GPIO_IN);
- gpio_set_pulls(LCD_VSYNC_PIN, false, true);
-
- bi_decl_if_func_used(bi_1pin_with_name(LCD_VSYNC_PIN, "Display TE/VSync"));
-#endif
-
- // if a backlight pin is provided then set it up for
- // pwm control
-#ifdef LCD_BACKLIGHT_PIN
- pwm_config pwm_cfg = pwm_get_default_config();
- pwm_set_wrap(pwm_gpio_to_slice_num(LCD_BACKLIGHT_PIN), 65535);
- pwm_init(pwm_gpio_to_slice_num(LCD_BACKLIGHT_PIN), &pwm_cfg, true);
- gpio_set_function(LCD_BACKLIGHT_PIN, GPIO_FUNC_PWM);
-
- bi_decl_if_func_used(bi_1pin_with_name(LCD_BACKLIGHT_PIN, "Display Backlight"));
-#endif
-
-#ifdef ST7789_8BIT
- // init RD
- gpio_init(LCD_RD_PIN);
- gpio_set_dir(LCD_RD_PIN, GPIO_OUT);
- gpio_put(LCD_RD_PIN, 1);
-
- bi_decl_if_func_used(bi_1pin_with_name(LCD_RD_PIN, "Display RD"));
-#endif
-
-#ifdef LCD_RESET_PIN
- gpio_set_function(LCD_RESET_PIN, GPIO_FUNC_SIO);
- gpio_set_dir(LCD_RESET_PIN, GPIO_OUT);
- gpio_put(LCD_RESET_PIN, 0);
- sleep_ms(100);
- gpio_put(LCD_RESET_PIN, 1);
-
- bi_decl_if_func_used(bi_1pin_with_name(LCD_RESET_PIN, "Display Reset"));
-#endif
-
- // setup PIO
- pio_offset = pio_add_program(pio, &st7789_raw_program);
- pio_double_offset = pio_add_program(pio, &st7789_pixel_double_program);
-
- pio_sm = pio_claim_unused_sm(pio, true);
-
- pio_sm_config cfg = st7789_raw_program_get_default_config(pio_offset);
-
-#ifdef ST7789_8BIT
- const int out_width = 8;
-#else // SPI
- const int out_width = 1;
-#endif
-
- const int clkdiv = std::ceil(clock_get_hz(clk_sys) / float(LCD_MAX_CLOCK * 2));
- sm_config_set_clkdiv(&cfg, clkdiv);
-
- sm_config_set_out_shift(&cfg, false, true, 8);
- sm_config_set_out_pins(&cfg, LCD_MOSI_PIN, out_width);
- sm_config_set_fifo_join(&cfg, PIO_FIFO_JOIN_TX);
- sm_config_set_sideset_pins(&cfg, LCD_SCK_PIN);
-
- // init pins
- for(int i = 0; i < out_width; i++)
- pio_gpio_init(pio, LCD_MOSI_PIN + i);
-
- pio_gpio_init(pio, LCD_SCK_PIN);
-
- pio_sm_set_consecutive_pindirs(pio, pio_sm, LCD_MOSI_PIN, out_width, true);
- pio_sm_set_consecutive_pindirs(pio, pio_sm, LCD_SCK_PIN, 1, true);
-
- pio_sm_init(pio, pio_sm, pio_offset, &cfg);
- pio_sm_set_enabled(pio, pio_sm, true);
-
-#ifdef ST7789_8BIT
- // these are really D0/WR
- bi_decl_if_func_used(bi_pin_mask_with_name(0xFF << LCD_MOSI_PIN, "Display Data"));
- bi_decl_if_func_used(bi_1pin_with_name(LCD_SCK_PIN, "Display WR"));
-#else
- bi_decl_if_func_used(bi_1pin_with_name(LCD_MOSI_PIN, "Display TX"));
- bi_decl_if_func_used(bi_1pin_with_name(LCD_SCK_PIN, "Display SCK"));
-#endif
-
- // if auto_init_sequence then send initialisation sequence
- // for our standard displays based on the width and height
- if(auto_init_sequence) {
- command(reg::SWRESET);
-
- sleep_ms(150);
-
- command(reg::TEON, 1, "\x00"); // enable frame sync signal if used
- command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel
-
- if(width == 240 && height == 240) {
- command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
- command(reg::GCTRL, 1, "\x14");
- command(reg::VCOMS, 1, "\x37");
- command(reg::LCMCTRL, 1, "\x2c");
- command(reg::VDVVRHEN, 1, "\x01");
- command(reg::VRHS, 1, "\x12");
- command(reg::VDVS, 1, "\x20");
- command(reg::PWCTRL1, 2, "\xa4\xa1");
-
- command(reg::PVGAMCTRL, 14, "\xD0\x08\x11\x08\x0c\x15\x39\x33\x50\x36\x13\x14\x29\x2d");
- command(reg::NVGAMCTRL, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0b\x16\x14\x2f\x31");
-
-
- // trigger "vsync" slightly earlier to avoid tearing while pixel-doubling
- // (this is still outside of the visible part of the screen)
- command(reg::STE, 2, "\x01\x2C");
- }
-
- if(width == 320 && height == 240) {
- command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
- command(reg::GCTRL, 1, "\x35");
- command(reg::VCOMS, 1, "\x1f");
- command(reg::LCMCTRL, 1, "\x2c");
- command(reg::VDVVRHEN, 1, "\x01");
- command(reg::VRHS, 1, "\x12");
- command(reg::VDVS, 1, "\x20");
- command(reg::PWCTRL1, 2, "\xa4\xa1");
- command(0xd6, 1, "\xa1"); // ???
- command(reg::PVGAMCTRL, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D");
- command(reg::NVGAMCTRL, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31");
- }
-
- command(reg::FRCTRL2, 1, "\x15"); // 50Hz
-
- command(reg::INVON); // set inversion mode
- command(reg::SLPOUT); // leave sleep mode
- command(reg::DISPON); // turn display on
-
- sleep_ms(100);
-
- // setup correct addressing window
- uint8_t madctl = MADCTL::RGB | rotations[LCD_ROTATION / 90];
- if(width == 240 && height == 240) {
- set_window(0, 0, 240, 240);
- }
-
- if(width == 240 && height == 135) {
- set_window(40, 53, 240, 135);
- }
-
- if(width == 320 && height == 240) {
- set_window(0, 0, 320, 240);
- }
-
- command(reg::MADCTL, 1, (char *)&madctl);
- }
-
- // initialise dma channel for transmitting pixel data to screen
- dma_channel = dma_claim_unused_channel(true);
- dma_channel_config config = dma_channel_get_default_config(dma_channel);
- channel_config_set_transfer_data_size(&config, DMA_SIZE_16);
- channel_config_set_dreq(&config, pio_get_dreq(pio, pio_sm, true));
- dma_channel_configure(
- dma_channel, &config, &pio->txf[pio_sm], frame_buffer, width * height, false);
-
- irq_add_shared_handler(DMA_IRQ_0, st7789_dma_irq_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
- irq_set_enabled(DMA_IRQ_0, true);
- }
-
- void command(uint8_t command, size_t len, const char *data) {
- pio_wait(pio, pio_sm);
-
- if(write_mode) {
- // reconfigure to 8 bits
- pio_sm_set_enabled(pio, pio_sm, false);
- pio->sm[pio_sm].shiftctrl &= ~PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS;
- pio->sm[pio_sm].shiftctrl |= (8 << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB) | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS;
-
- // switch back to raw
- pio_sm_restart(pio, pio_sm);
- pio_sm_set_wrap(pio, pio_sm, pio_offset + st7789_raw_wrap_target, pio_offset + st7789_raw_wrap);
- pio_sm_exec(pio, pio_sm, pio_encode_jmp(pio_offset));
-
- pio_sm_set_enabled(pio, pio_sm, true);
- write_mode = false;
- }
-
- gpio_put(LCD_CS_PIN, 0);
-
- gpio_put(LCD_DC_PIN, 0); // command mode
- pio_put_byte(pio, pio_sm, command);
-
- if(data) {
- pio_wait(pio, pio_sm);
- gpio_put(LCD_DC_PIN, 1); // data mode
-
- for(size_t i = 0; i < len; i++)
- pio_put_byte(pio, pio_sm, data[i]);
- }
-
- pio_wait(pio, pio_sm);
- gpio_put(LCD_CS_PIN, 1);
- }
-
- void update(bool dont_block) {
- if(dma_channel_is_busy(dma_channel) && dont_block) {
- return;
- }
-
- dma_channel_wait_for_finish_blocking(dma_channel);
-
- if(!write_mode)
- prepare_write();
-
- if(pixel_double) {
- cur_scanline = 0;
- upd_frame_buffer = frame_buffer;
- dma_channel_set_trans_count(dma_channel, win_w / 4, false);
- } else
- dma_channel_set_trans_count(dma_channel, win_w * win_h, false);
-
- dma_channel_set_read_addr(dma_channel, frame_buffer, true);
- }
-
- void set_backlight(uint8_t brightness) {
-#ifdef LCD_BACKLIGHT_PIN
- // gamma correct the provided 0-255 brightness value onto a
- // 0-65535 range for the pwm counter
- float gamma = 2.8;
- uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f);
- pwm_set_gpio_level(LCD_BACKLIGHT_PIN, value);
-#endif
- }
-
- bool vsync_callback(gpio_irq_callback_t callback) {
-#ifdef LCD_VSYNC_PIN
- gpio_set_irq_enabled_with_callback(LCD_VSYNC_PIN, GPIO_IRQ_EDGE_RISE, true, callback);
- return true;
-#else
- return false;
-#endif
- }
-
- void set_window(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
- uint32_t cols = __builtin_bswap32((x << 16) | (x + w - 1));
- uint32_t rows = __builtin_bswap32((y << 16) | (y + h - 1));
-
- command(reg::CASET, 4, (const char *)&cols);
- command(reg::RASET, 4, (const char *)&rows);
-
- win_w = w;
- win_h = h;
- }
-
- void set_pixel_double(bool pd) {
- pixel_double = pd;
-
- // nop to reconfigure PIO
- if(write_mode)
- command(0);
-
- if(pixel_double) {
- dma_channel_acknowledge_irq0(dma_channel);
- dma_channel_set_irq0_enabled(dma_channel, true);
- } else
- dma_channel_set_irq0_enabled(dma_channel, false);
- }
-
- void clear() {
- if(!write_mode)
- prepare_write();
-
- for(int i = 0; i < win_w * win_h; i++)
- pio_sm_put_blocking(pio, pio_sm, 0);
- }
-
- bool dma_is_busy() {
- if(pixel_double && cur_scanline <= win_h / 2)
- return true;
-
- return dma_channel_is_busy(dma_channel);
- }
-
- void prepare_write() {
- pio_wait(pio, pio_sm);
-
- // setup for writing
- uint8_t r = reg::RAMWR;
- gpio_put(LCD_CS_PIN, 0);
-
- gpio_put(LCD_DC_PIN, 0); // command mode
- pio_put_byte(pio, pio_sm, r);
- pio_wait(pio, pio_sm);
-
- gpio_put(LCD_DC_PIN, 1); // data mode
-
- pio_sm_set_enabled(pio, pio_sm, false);
- pio_sm_restart(pio, pio_sm);
-
- if(pixel_double) {
- // switch program
- pio_sm_set_wrap(pio, pio_sm, pio_double_offset + st7789_pixel_double_wrap_target, pio_double_offset + st7789_pixel_double_wrap);
-
- // 32 bits, no autopull
- pio->sm[pio_sm].shiftctrl &= ~(PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
-
- pio_sm_exec(pio, pio_sm, pio_encode_jmp(pio_double_offset));
-
- // reconfigure dma size
- dma_channel_hw_addr(dma_channel)->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS;
- dma_channel_hw_addr(dma_channel)->al1_ctrl |= DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB;
- } else {
- // 16 bits, autopull
- pio->sm[pio_sm].shiftctrl &= ~PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS;
- pio->sm[pio_sm].shiftctrl |= (16 << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB) | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS;
-
- dma_channel_hw_addr(dma_channel)->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS;
- dma_channel_hw_addr(dma_channel)->al1_ctrl |= DMA_SIZE_16 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB;
- }
-
- pio_sm_set_enabled(pio, pio_sm, true);
-
- write_mode = true;
- }
-}
diff --git a/32blit-pico/st7789.hpp b/32blit-pico/st7789.hpp
deleted file mode 100644
index a756bee..0000000
--- a/32blit-pico/st7789.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include "hardware/pio.h"
-#include "hardware/gpio.h"
-
-namespace st7789 {
-
- extern uint16_t *frame_buffer;
-
- void init(bool auto_init_sequence = true);
-
- void command(uint8_t command, size_t len = 0, const char *data = NULL);
- bool vsync_callback(gpio_irq_callback_t callback);
- void update(bool dont_block = false);
- void set_backlight(uint8_t brightness);
-
- void set_window(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
- void set_pixel_double(bool pd);
-
- void clear();
-
- bool dma_is_busy();
-}
diff --git a/32blit-sdl/CMakeLists.txt b/32blit-sdl/CMakeLists.txt
index 510694a..546af03 100644
--- a/32blit-sdl/CMakeLists.txt
+++ b/32blit-sdl/CMakeLists.txt
@@ -193,7 +193,7 @@
endif()
if(APPLE)
- set(SEARCH_DIRS /usr/local/lib)
+ set(SEARCH_DIRS /usr/local/lib /opt/homebrew/lib)
# assuming all frameworks installed in the same place
if(SDL2_FRAMEWORK_PATH)
diff --git a/32blit/engine/engine.cpp b/32blit/engine/engine.cpp
index ba34c1e..e262f28 100644
--- a/32blit/engine/engine.cpp
+++ b/32blit/engine/engine.cpp
@@ -33,7 +33,7 @@
if(new_screen.pen_blend)
screen.pbf = new_screen.pen_blend;
-
+
if(new_screen.blit_blend)
screen.bbf = new_screen.blit_blend;
@@ -89,8 +89,7 @@
return ret;
}
- Surface null_surface(nullptr, PixelFormat::M, Size(0, 0));
- Surface &screen = null_surface;
+ Surface screen(nullptr, PixelFormat::M, Size(0, 0));
static const uint32_t update_rate_ms = 10;
static uint32_t pending_update_time = 0;
diff --git a/32blit/engine/engine.hpp b/32blit/engine/engine.hpp
index 4351aeb..8b8ff1f 100644
--- a/32blit/engine/engine.hpp
+++ b/32blit/engine/engine.hpp
@@ -8,7 +8,7 @@
namespace blit {
enum ScreenMode { lores, hires, hires_palette };
- extern Surface &screen;
+ extern Surface screen;
extern void (*init) ();
diff --git a/pico.toolchain b/pico.toolchain
index 2db04e0..423b2c6 100644
--- a/pico.toolchain
+++ b/pico.toolchain
@@ -5,6 +5,6 @@
include(${CMAKE_CURRENT_LIST_DIR}/pico-common.toolchain)
-if (NOT PICO_BOARD)
+if (NOT PICO_BOARD AND NOT PICO_ADDON)
set(PICO_BOARD pimoroni_picosystem)
-endif()
\ No newline at end of file
+endif()
diff --git a/pico2.toolchain b/pico2.toolchain
index 88fb00e..27eb879 100644
--- a/pico2.toolchain
+++ b/pico2.toolchain
@@ -7,4 +7,8 @@
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mcmse")
endif()
-include(${CMAKE_CURRENT_LIST_DIR}/pico-common.toolchain)
\ No newline at end of file
+include(${CMAKE_CURRENT_LIST_DIR}/pico-common.toolchain)
+
+if (NOT PICO_BOARD)
+ set(PICO_BOARD pico2)
+endif()