Skip to content

Commit

Permalink
ST7701: Rework DMA to fix flicker.
Browse files Browse the repository at this point in the history
Now we're happy that MicroPython can run from PSRAM, we can assume a RAM
framebuffer and remove a bunch of complexity.
  • Loading branch information
MichaelBell committed Oct 15, 2024
1 parent ac14a5c commit dcfa4eb
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 44 deletions.
69 changes: 27 additions & 42 deletions drivers/st7701/st7701.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,16 @@ 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 (480 + TIMING_V_BACK)
#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_BACK 30
#define TIMING_H_DISPLAY 480

#define LOW_PRIO_IRQ0 (NUM_IRQS - NUM_USER_IRQS)

static ST7701* st7701_inst;

// This ISR is triggered whenever the timing SM's FIFO is not full
Expand Down Expand Up @@ -161,24 +159,9 @@ void __no_inline_not_in_flash_func(ST7701::start_line_xfer())
{
hw_clear_bits(&st_pio->irq, 0x1);

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);

if ((intptr_t)framebuffer >= 0x20000000) {
dma_channel_set_read_addr(st_dma, &framebuffer[width * (display_row >> row_shift)], true);
}
else {
dma_channel_set_read_addr(st_dma, &line_buffer[width * ((display_row >> row_shift) & (NUM_LINE_BUFFERS - 1))], true);
}
++display_row;

irq_set_pending(LOW_PRIO_IRQ0);
if (display_row == DISPLAY_HEIGHT) next_line_addr = 0;
else next_line_addr = &framebuffer[width * (display_row >> row_shift)];
}

void ST7701::start_frame_xfer()
Expand All @@ -192,9 +175,18 @@ void ST7701::start_frame_xfer()
init_framebuffer();
}

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;
fill_row = 0;
irq_set_pending(LOW_PRIO_IRQ0);
next_line_addr = framebuffer;
dma_channel_set_read_addr(st_dma, framebuffer, true);

waiting_for_vsync = false;
__sev();
Expand All @@ -213,18 +205,6 @@ void ST7701::init_framebuffer() {
framebuffer += 0x2000000;
}

void __no_inline_not_in_flash_func(line_fill_isr()) {
st7701_inst->fill_next_line();
}

void __no_inline_not_in_flash_func(ST7701::fill_next_line()) {
if ((intptr_t)framebuffer >= 0x20000000) return;
while (fill_row < height && fill_row < (display_row >> row_shift) + NUM_LINE_BUFFERS - 1) {
memcpy(&line_buffer[width * (fill_row & (NUM_LINE_BUFFERS - 1))], &framebuffer[width * fill_row], width << 1);
++fill_row;
}
}

ST7701::ST7701(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, uint16_t* framebuffer, uint16_t* linebuffer,
uint d0, uint hsync, uint vsync, uint lcd_de, uint lcd_dot_clk) :
DisplayDriver(width, height, rotation),
Expand Down Expand Up @@ -335,25 +315,28 @@ void __no_inline_not_in_flash_func(ST7701::fill_next_line()) {
pio_sm_set_enabled(st_pio, timing_sm, true);

st_dma = dma_claim_unused_channel(true);
st_dma2 = dma_claim_unused_channel(true);

dma_channel_config config = dma_channel_get_default_config(st_dma);
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
channel_config_set_high_priority(&config, true);
channel_config_set_dreq(&config, pio_get_dreq(st_pio, parallel_sm, true));
channel_config_set_bswap(&config, true);
channel_config_set_chain_to(&config, st_dma2);
dma_channel_configure(st_dma, &config, &st_pio->txf[parallel_sm], line_buffer, width >> 1, false);

config = dma_channel_get_default_config(st_dma2);
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
channel_config_set_read_increment(&config, false);
dma_channel_configure(st_dma2, &config, &dma_hw->ch[st_dma].al3_read_addr_trig, &next_line_addr, 1, false);

hw_set_bits(&bus_ctrl_hw->priority, (BUSCTRL_BUS_PRIORITY_PROC1_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS | BUSCTRL_BUS_PRIORITY_DMA_W_BITS));

printf("Begin SPI setup\n");

common_init();

printf("Setup screen timing\n");
current = irq_get_exclusive_handler(LOW_PRIO_IRQ0);
if(current) irq_remove_handler(LOW_PRIO_IRQ0, current);
irq_set_exclusive_handler(LOW_PRIO_IRQ0, line_fill_isr);
irq_set_enabled(LOW_PRIO_IRQ0, true);
irq_set_pending(LOW_PRIO_IRQ0);

// Setup timing
hw_set_bits(&st_pio->inte1, 0x010 << timing_sm); // TX not full
Expand Down Expand Up @@ -475,14 +458,16 @@ void __no_inline_not_in_flash_func(ST7701::fill_next_line()) {
current = irq_get_exclusive_handler(pio_get_irq_num(st_pio, 1));
if(current) irq_remove_handler(pio_get_irq_num(st_pio, 1), current);

irq_set_enabled(LOW_PRIO_IRQ0, false);

next_line_addr = 0;
if(dma_channel_is_claimed(st_dma)) {
while (dma_channel_is_busy(st_dma))
;
dma_channel_abort(st_dma);
dma_channel_unclaim(st_dma);
}
if(dma_channel_is_claimed(st_dma2)) {
dma_channel_unclaim(st_dma2);
}

if(pio_sm_is_claimed(st_pio, parallel_sm)) {
pio_sm_set_enabled(st_pio, parallel_sm, false);
Expand Down
4 changes: 2 additions & 2 deletions drivers/st7701/st7701.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace pimoroni {
uint parallel_offset;
uint timing_offset;
uint st_dma;
uint line_dma;
uint st_dma2;

uint d0 = 1; // First pin of 18-bit parallel interface
uint hsync = 19;
Expand Down Expand Up @@ -67,7 +67,6 @@ namespace pimoroni {
// Only to be called by ISR
void drive_timing();
void handle_end_of_line();
void fill_next_line();

private:
void common_init();
Expand All @@ -89,6 +88,7 @@ namespace pimoroni {
uint16_t* next_framebuffer = nullptr;

uint16_t* line_buffer;
uint16_t* next_line_addr;
int display_row = 0;
int row_shift = 0;
int fill_row = 0;
Expand Down

0 comments on commit dcfa4eb

Please sign in to comment.