diff --git a/drivers/st7701/st7701.cpp b/drivers/st7701/st7701.cpp index 4d038f5..5ec4a9e 100644 --- a/drivers/st7701/st7701.cpp +++ b/drivers/st7701/st7701.cpp @@ -77,13 +77,12 @@ namespace pimoroni { CND2BKxSEL = 0xFF, }; -#define DISPLAY_HEIGHT 480 #define TIMING_V_PULSE 8 #define TIMING_V_BACK (5 + TIMING_V_PULSE) #define TIMING_V_DISPLAY (DISPLAY_HEIGHT + TIMING_V_BACK) #define TIMING_V_FRONT (5 + TIMING_V_DISPLAY) #define TIMING_H_FRONT 4 -#define TIMING_H_PULSE 25 +#define TIMING_H_PULSE 16 #define TIMING_H_BACK 30 #define TIMING_H_DISPLAY 480 @@ -342,11 +341,12 @@ void ST7701::start_frame_xfer() // TODO: Figure out what's actually display specific command(reg::MADCTL, 1, "\x00"); // Normal scan direction and RGB pixels command(reg::LNESET, 2, "\x3b\x00"); // (59 + 1) * 8 = 480 lines - command(reg::PORCTRL, 2, "\x0d\x05"); // 13 VBP, 5 VFP - command(reg::INVSET, 2, "\x32\x05"); + command(reg::PORCTRL, 2, "\x0d\x02"); // Display porch settings: 13 VBP, 2 VFP (these should not be changed) + command(reg::INVSET, 2, "\x31\x01"); command(reg::COLCTRL, 1, "\x08"); // LED polarity reversed command(reg::PVGAMCTRL, 16, "\x00\x11\x18\x0e\x11\x06\x07\x08\x07\x22\x04\x12\x0f\xaa\x31\x18"); command(reg::NVGAMCTRL, 16, "\x00\x11\x19\x0e\x12\x07\x08\x08\x08\x22\x04\x11\x11\xa9\x32\x18"); + command(reg::RGBCTRL, 3, "\x80\x2e\x0e"); // HV mode, H and V back porch + sync } // Command 2 BK1 - Voltages and power and stuff @@ -378,10 +378,13 @@ void ST7701::start_frame_xfer() command(0xEC, 2, "\x3c\x00"); command(0xED, 16, "\xab\x89\x76\x54\x02\xff\xff\xff\xff\xff\xff\x20\x45\x67\x98\xba"); command(0x36, 1, "\x00"); - // End Forbidden Knowledge // Command 2 BK3 command(reg::CND2BKxSEL, 5, "\x77\x01\x00\x00\x13"); + command(0xE5, 1, "\xe4"); + // End Forbidden Knowledge + + command(reg::CND2BKxSEL, 5, "\x77\x01\x00\x00\x00"); //command(reg::COLMOD, 1, "\x77"); // 24 bits per pixel... command(reg::COLMOD, 1, "\x66"); // 18 bits per pixel... //command(reg::COLMOD, 1, "\x55"); // 16 bits per pixel... diff --git a/drivers/st7701/st7701.hpp b/drivers/st7701/st7701.hpp index 455020b..fb044a9 100644 --- a/drivers/st7701/st7701.hpp +++ b/drivers/st7701/st7701.hpp @@ -13,6 +13,8 @@ #include #include +#define DISPLAY_HEIGHT 480 + namespace pimoroni { class ST7701 : public DisplayDriver { @@ -28,12 +30,8 @@ namespace pimoroni { uint spi_sck; uint spi_dat; uint lcd_bl; - uint parallel_sm; uint timing_sm; - PIO st_pio; - uint parallel_offset; uint timing_offset; - uint st_dma; uint st_dma2; uint d0 = 1; // First pin of 18-bit parallel interface @@ -66,6 +64,21 @@ namespace pimoroni { void drive_timing(); void handle_end_of_line(); + protected: + PIO st_pio; + int display_row = 0; + uint16_t* next_line_addr; + uint16_t* framebuffer; + uint16_t* next_framebuffer = nullptr; + int row_shift = 0; + + uint st_dma; + uint parallel_sm; + uint parallel_offset; + + volatile bool waiting_for_vsync = false; + + private: void common_init(); void configure_display(Rotation rotate); @@ -73,20 +86,13 @@ namespace pimoroni { void write_blocking_parallel(const uint8_t *src, size_t len); void command(uint8_t command, size_t len = 0, const char *data = NULL); - void start_line_xfer(); - void start_frame_xfer(); + virtual void start_line_xfer(); + virtual void start_frame_xfer(); // Timing status uint16_t timing_row = 0; uint16_t timing_phase = 0; - volatile bool waiting_for_vsync = false; - uint16_t* framebuffer; - uint16_t* next_framebuffer = nullptr; - - uint16_t* next_line_addr; - int display_row = 0; - int row_shift = 0; int fill_row = 0; }; diff --git a/drivers/st7701/st7701Cached.cpp b/drivers/st7701/st7701Cached.cpp new file mode 100644 index 0000000..e43e8bf --- /dev/null +++ b/drivers/st7701/st7701Cached.cpp @@ -0,0 +1,96 @@ +#include + +#include "st7701Cached.hpp" + +namespace pimoroni { + + ST7701Cached::ST7701Cached(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, + uint16_t cachelines, uint16_t* framecache, uint16_t* backbuffer, + uint d0, uint hsync, uint vsync, uint lcd_de, uint lcd_dot_clk) + : ST7701(width, height, rotation, control_pins, framecache, d0, hsync, vsync, lcd_de, lcd_dot_clk), + cachelines(cachelines), + backbuffer(backbuffer) + { + } + + + ST7701Cached::ST7701Cached(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, uint16_t* backbuffer, + uint d0, uint hsync, uint vsync, uint lcd_de, uint lcd_dot_clk) + : ST7701(width, height, rotation, control_pins, nullptr, d0, hsync, vsync, lcd_de, lcd_dot_clk), + backbuffer(backbuffer) + { + // the cache needs to be 6 lines for height 240 and 3 lines for height 480 + // memory usage stays the same. + cachelines = (height == 480) ? 3 : 6; + framebuffer = (uint16_t *)malloc(DISPLAY_HEIGHT * 2 * cachelines); + } + + void ST7701Cached::update(PicoGraphics *graphics) + { + } + + void ST7701Cached::partial_update(PicoGraphics *display, Rect region) + { + } + + void ST7701Cached::start_line_xfer() + { + hw_clear_bits(&st_pio->irq, 0x1); + + volatile uint16_t *pSrc; + volatile uint16_t *pDst; + volatile static uint8_t uEnd = 40; + + ++display_row; + + // PIO displaying display_row from cache + // We copy update_row into cache + + if (display_row > DISPLAY_HEIGHT) { + next_line_addr = 0; + } + else { + next_line_addr = &framebuffer[width * ((display_row%cachelines) >> row_shift)]; + + int update_row = (display_row + 1) % DISPLAY_HEIGHT; + int cache_line = update_row % cachelines; + next_next_line_addr = &framebuffer[width * (cache_line >> row_shift)]; + + pSrc = &backbuffer[width * (update_row >> row_shift)]; + memcpy(next_next_line_addr, (void *) pSrc, width * 2); + } + } + + void ST7701Cached::start_frame_xfer() + { + display_row = 0; + + hw_clear_bits(&st_pio->irq, 0x2); + + if (next_framebuffer) { + framebuffer = next_framebuffer; + next_framebuffer = nullptr; + } + + if (next_backbuffer) { + backbuffer = next_backbuffer; + next_backbuffer = nullptr; + } + + next_line_addr = 0; + dma_channel_abort(st_dma); + dma_channel_wait_for_finish_blocking(st_dma); + pio_sm_set_enabled(st_pio, parallel_sm, false); + pio_sm_clear_fifos(st_pio, parallel_sm); + pio_sm_exec_wait_blocking(st_pio, parallel_sm, pio_encode_mov(pio_osr, pio_null)); + pio_sm_exec_wait_blocking(st_pio, parallel_sm, pio_encode_out(pio_null, 32)); + pio_sm_exec_wait_blocking(st_pio, parallel_sm, pio_encode_jmp(parallel_offset)); + pio_sm_set_enabled(st_pio, parallel_sm, true); + display_row = 0; + next_line_addr = framebuffer; + + dma_channel_set_read_addr(st_dma, framebuffer, true); + waiting_for_vsync = false; + __sev(); + } +} \ No newline at end of file diff --git a/drivers/st7701/st7701Cached.hpp b/drivers/st7701/st7701Cached.hpp new file mode 100644 index 0000000..2b9e064 --- /dev/null +++ b/drivers/st7701/st7701Cached.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "st7701.hpp" + +namespace pimoroni { + class ST7701Cached : public ST7701 { + + private: + uint16_t* backbuffer = nullptr; + uint16_t* next_backbuffer = nullptr; + uint16_t cachelines = 0; + + public: + // Parallel init + ST7701Cached(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, + uint16_t cache_lines, uint16_t* framecache, uint16_t* backbuffer, + uint d0=1, uint hsync=19, uint vsync=20, uint lcd_de = 21, uint lcd_dot_clk = 22); + + ST7701Cached(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, uint16_t* backbuffer, + uint d0=1, uint hsync=19, uint vsync=20, uint lcd_de = 21, uint lcd_dot_clk = 22); + + void update(PicoGraphics *graphics) override; + void partial_update(PicoGraphics *display, Rect region) override; + + void set_backbuffer(uint16_t* next_fb) { + next_backbuffer = next_fb; + } + + private: + void start_line_xfer() override; + void start_frame_xfer() override; + + uint16_t *next_next_line_addr; + }; + +} \ No newline at end of file diff --git a/drivers/st7701/st7701_parallel.pio b/drivers/st7701/st7701_parallel.pio index 3b1f510..d5453af 100644 --- a/drivers/st7701/st7701_parallel.pio +++ b/drivers/st7701/st7701_parallel.pio @@ -6,8 +6,8 @@ .side_set 1 .wrap_target - mov x, y side 0 ; y needs to be set to (width/2)-1 at init time - wait 1 irq 4 side 0 ; wait for the irq from the timing SM + mov x, y side 1 ; y needs to be set to (width/2)-1 at init time + wait 1 irq 4 side 1 ; wait for the irq from the timing SM loop: out isr, 32 side 1 mov pins, ::isr side 1 [1] diff --git a/drivers/st7701/st7701_presto.cmake b/drivers/st7701/st7701_presto.cmake index c4fe455..9357700 100644 --- a/drivers/st7701/st7701_presto.cmake +++ b/drivers/st7701/st7701_presto.cmake @@ -1,7 +1,8 @@ add_library(st7701_presto INTERFACE) target_sources(st7701_presto INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/st7701.cpp) + ${CMAKE_CURRENT_LIST_DIR}/st7701.cpp + ${CMAKE_CURRENT_LIST_DIR}/st7701Cached.cpp) pico_generate_pio_header(st7701_presto ${CMAKE_CURRENT_LIST_DIR}/st7701_parallel.pio) pico_generate_pio_header(st7701_presto ${CMAKE_CURRENT_LIST_DIR}/st7701_timing.pio) diff --git a/drivers/st7701/st7701_timing.pio b/drivers/st7701/st7701_timing.pio index 50fbb8f..2ceceea 100644 --- a/drivers/st7701/st7701_timing.pio +++ b/drivers/st7701/st7701_timing.pio @@ -15,6 +15,6 @@ out x, 14 side 1 ; Loop count sync_loop: nop side 0 - jmp x--, sync_loop side 1 + jmp x--, sync_loop side 1 out exec, 16 side 0 .wrap