diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index 497904651..da94def58 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -146,7 +146,8 @@ endif() pico_sdk_init() # generate PIO headers (has to be after SDK init) -pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789.pio) +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}/spi.pio) # include picovision drivers diff --git a/32blit-pico/board/tufty2040/config.cmake b/32blit-pico/board/tufty2040/config.cmake new file mode 100644 index 000000000..ded4850c6 --- /dev/null +++ b/32blit-pico/board/tufty2040/config.cmake @@ -0,0 +1,8 @@ +set(BLIT_BOARD_NAME "Tufty 2040") + +set(BLIT_BOARD_DEFINITIONS + PICO_FLASH_SIZE_BYTES=8388608 +) + +blit_driver(display st7789) +blit_driver(input tufty) diff --git a/32blit-pico/board/tufty2040/config.h b/32blit-pico/board/tufty2040/config.h new file mode 100644 index 000000000..5c46d6b70 --- /dev/null +++ b/32blit-pico/board/tufty2040/config.h @@ -0,0 +1,17 @@ +#pragma once + +#define DISPLAY_WIDTH 320 + + + +#define ST7789_8BIT +#define ST7789_ROTATE_180 +#define LCD_CS_PIN 10 +#define LCD_DC_PIN 11 +#define LCD_SCK_PIN 12 // WR +#define LCD_RD_PIN 13 +#define LCD_MOSI_PIN 14 // DB0 +#define LCD_BACKLIGHT_PIN 2 +// #define LCD_VSYNC_PIN 11 // shared + +// there is a white LED \ No newline at end of file diff --git a/32blit-pico/config.h b/32blit-pico/config.h index 2b514ac90..c81dce16f 100644 --- a/32blit-pico/config.h +++ b/32blit-pico/config.h @@ -1,6 +1,8 @@ #pragma once +#ifdef BLIT_BOARD_CONFIG #include BLIT_BOARD_CONFIG +#endif // these are the defaults diff --git a/32blit-pico/input_tufty.cpp b/32blit-pico/input_tufty.cpp new file mode 100644 index 000000000..1117f1df0 --- /dev/null +++ b/32blit-pico/input_tufty.cpp @@ -0,0 +1,63 @@ +#include "input.hpp" + +#include "hardware/gpio.h" + +#include "pico/binary_info.h" + +#include "engine/api_private.hpp" +#include "engine/input.hpp" + +enum class ButtonIO { + UP = 22, + DOWN = 6, + + A = 7, + B = 8, + C = 9, + USER = 23, // USER_SW +}; + +static void init_button(ButtonIO b) { + int gpio = static_cast(b); + gpio_set_function(gpio, GPIO_FUNC_SIO); + gpio_set_dir(gpio, GPIO_IN); + gpio_pull_down(gpio); +} + +inline bool get_button(ButtonIO b) { + auto gpio = static_cast(b); + + if(b == ButtonIO::USER) // USER_SW goes the other way + return !gpio_get(gpio); + + return gpio_get(gpio); +} + +void init_input() { + init_button(ButtonIO::UP); + init_button(ButtonIO::DOWN); + init_button(ButtonIO::A); + init_button(ButtonIO::B); + init_button(ButtonIO::C); + init_button(ButtonIO::USER); + + #define BUTTON_DECL(btn) bi_decl(bi_1pin_with_name(static_cast(ButtonIO::btn), #btn" Button")); + BUTTON_DECL(UP) + BUTTON_DECL(DOWN) + BUTTON_DECL(A) + BUTTON_DECL(B) + BUTTON_DECL(C) + BUTTON_DECL(USER) + #undef BUTTON_DECL +} + +void update_input() { + using namespace blit; + + api.buttons = (get_button(ButtonIO::UP) ? uint32_t(Button::DPAD_UP) : 0) + | (get_button(ButtonIO::DOWN) ? uint32_t(Button::DPAD_DOWN) : 0) + | (get_button(ButtonIO::A) ? uint32_t(Button::A) : 0) + | (get_button(ButtonIO::B) ? uint32_t(Button::B) : 0) + | (get_button(ButtonIO::C) ? uint32_t(Button::X) : 0) + | (get_button(ButtonIO::USER) ? uint32_t(Button::Y) : 0); +} diff --git a/32blit-pico/st7789-8bit.pio b/32blit-pico/st7789-8bit.pio new file mode 100644 index 000000000..b4ed2e3fd --- /dev/null +++ b/32blit-pico/st7789-8bit.pio @@ -0,0 +1,52 @@ +.program st7789_raw +.side_set 1 opt + +; raw serial, nothing special +.wrap_target + out x, 8 side 1 + mov pins, x side 0 +.wrap + +; pixel doubling, "borrowed" from PicoSystem +.program st7789_pixel_double +.side_set 1 opt + +.wrap_target + + pull side 1 ; fetch two pixels + mov x, osr ; both pixels in x register + out y, 16 ; second pixel in y register + +; write first pixel (still in osr) + out pins, 8 side 0 + nop side 1 + out pins, 8 side 0 + +; duplicate first pixel + + mov osr, x side 1 ; move pixel data back into osr from register x + out null, 16 ; discard second pixel + + out pins, 8 side 0 + nop side 1 + out pins, 8 side 0 + +; write second pixel + + mov osr, y side 1 ; move pixel data back into osr from register y + out null, 16 ; discard the 16-bits of dummy data from the mov + + out pins, 8 side 0 + nop side 1 + out pins, 8 side 0 + +; duplicate second pixel + + mov osr, y side 1 ; move pixel data back into osr from register y + out null, 16 ; discard as above.. + + out pins, 8 side 0 + nop side 1 + out pins, 8 side 0 + +.wrap diff --git a/32blit-pico/st7789.pio b/32blit-pico/st7789-spi.pio similarity index 100% rename from 32blit-pico/st7789.pio rename to 32blit-pico/st7789-spi.pio diff --git a/32blit-pico/st7789.cpp b/32blit-pico/st7789.cpp index 13b981b93..b831fcd78 100644 --- a/32blit-pico/st7789.cpp +++ b/32blit-pico/st7789.cpp @@ -10,7 +10,12 @@ #include "pico/time.h" #include "config.h" -#include "st7789.pio.h" + +#ifdef ST7789_8BIT +#include "st7789-8bit.pio.h" +#else +#include "st7789-spi.pio.h" +#endif namespace st7789 { @@ -140,6 +145,15 @@ namespace st7789 { 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); @@ -157,25 +171,50 @@ namespace st7789 { 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; + + // < 15MHz +#if OVERCLOCK_250 + sm_config_set_clkdiv(&cfg, 9); +#else + sm_config_set_clkdiv(&cfg, 5); +#endif + +#else // SPI + const int out_width = 1; + #if OVERCLOCK_250 sm_config_set_clkdiv(&cfg, 2); // back to 62.5MHz from overclock +#endif #endif sm_config_set_out_shift(&cfg, false, true, 8); - sm_config_set_out_pins(&cfg, LCD_MOSI_PIN, 1); + 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); - pio_gpio_init(pio, LCD_MOSI_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, 1, true); + + 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 @@ -241,7 +280,11 @@ namespace st7789 { } if(width == 320 && height == 240) { +#ifdef ST7789_ROTATE_180 + madctl |= MADCTL::ROW_ORDER | MADCTL::SWAP_XY | MADCTL::SCAN_ORDER; +#else madctl |= MADCTL::COL_ORDER | MADCTL::SWAP_XY | MADCTL::SCAN_ORDER; +#endif set_window(0, 0, 320, 240); }