Skip to content
13 changes: 8 additions & 5 deletions drivers/st7701/st7701.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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...
Expand Down
32 changes: 19 additions & 13 deletions drivers/st7701/st7701.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <algorithm>
#include <cstring>

#define DISPLAY_HEIGHT 480

namespace pimoroni {

class ST7701 : public DisplayDriver {
Expand All @@ -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
Expand Down Expand Up @@ -66,27 +64,35 @@ 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);
void write_blocking_dma(const uint8_t *src, size_t len);
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;
};

Expand Down
96 changes: 96 additions & 0 deletions drivers/st7701/st7701Cached.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <pico/sync.h>

#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();
}
}
36 changes: 36 additions & 0 deletions drivers/st7701/st7701Cached.hpp
Original file line number Diff line number Diff line change
@@ -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;
};

}
4 changes: 2 additions & 2 deletions drivers/st7701/st7701_parallel.pio
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
3 changes: 2 additions & 1 deletion drivers/st7701/st7701_presto.cmake
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
2 changes: 1 addition & 1 deletion drivers/st7701/st7701_timing.pio
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading