2021-03-24 12:18:56 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "hardware/spi.h"
|
2022-06-16 17:38:57 +01:00
|
|
|
#include "hardware/dma.h"
|
2021-03-24 12:18:56 +00:00
|
|
|
#include "hardware/gpio.h"
|
2022-06-16 17:38:57 +01:00
|
|
|
#include "hardware/pio.h"
|
2022-05-12 18:40:37 +01:00
|
|
|
#include "hardware/pwm.h"
|
2022-08-04 20:26:45 +01:00
|
|
|
#include "hardware/clocks.h"
|
2022-05-28 01:00:56 +01:00
|
|
|
#include "common/pimoroni_common.hpp"
|
|
|
|
#include "common/pimoroni_bus.hpp"
|
2022-06-06 17:54:15 +01:00
|
|
|
#include "libraries/pico_graphics/pico_graphics.hpp"
|
2022-05-28 01:00:56 +01:00
|
|
|
|
2022-06-16 17:38:57 +01:00
|
|
|
|
|
|
|
#include "st7789_parallel.pio.h"
|
|
|
|
|
2022-05-28 01:00:56 +01:00
|
|
|
#include <algorithm>
|
2021-03-24 12:18:56 +00:00
|
|
|
|
2022-05-12 18:40:37 +01:00
|
|
|
|
2021-03-24 12:18:56 +00:00
|
|
|
namespace pimoroni {
|
|
|
|
|
2022-06-07 16:37:06 +01:00
|
|
|
class ST7789 : public DisplayDriver {
|
2021-04-20 10:54:10 +01:00
|
|
|
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
|
2022-05-28 01:00:56 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
bool round;
|
2021-04-23 13:22:00 +01:00
|
|
|
|
|
|
|
//--------------------------------------------------
|
|
|
|
// Variables
|
|
|
|
//--------------------------------------------------
|
|
|
|
private:
|
2021-04-23 13:35:19 +01:00
|
|
|
|
2021-03-24 12:18:56 +00:00
|
|
|
// interface pins with our standard defaults where appropriate
|
2022-05-12 18:40:37 +01:00
|
|
|
uint cs;
|
|
|
|
uint dc;
|
2022-05-25 10:44:14 +01:00
|
|
|
uint wr_sck;
|
|
|
|
uint rd_sck = PIN_UNUSED;
|
|
|
|
uint d0;
|
2022-05-12 18:40:37 +01:00
|
|
|
uint bl;
|
2021-04-20 10:54:10 +01:00
|
|
|
uint vsync = PIN_UNUSED; // only available on some products
|
2022-06-16 17:38:57 +01:00
|
|
|
uint parallel_sm;
|
|
|
|
PIO parallel_pio;
|
|
|
|
uint parallel_offset;
|
2022-09-17 20:16:57 +01:00
|
|
|
uint st_dma;
|
2022-06-16 17:38:57 +01:00
|
|
|
|
2021-03-24 12:18:56 +00:00
|
|
|
|
Improve ST7789 frame rate ~4x
The ST7789's Tscycw (time between serial write clock cycles) is
16 ns. This can be found on page 44 of the datasheet I'm using:
https://www.waveshare.com/w/upload/a/ae/ST7789_Datasheet.pdf
(I do not know which manufacturer Pimoroni products use and if
their parts might be different. But it seems like this wouldn't
change.)
The existing code sets the SPI baud to 16 * 1000 * 1000. But baud
is Hz, not seconds. That 16 * 1000 * 1000 doesn't represent 16 ns.
It represents 16,000,000 Hz.
16 ns * (1 Hz / s) = 62,500,000 Hz.
This commit changes the baud from 16 * 1000 * 1000 to 62'500'000,
representing ~4x speed improvement in SPI and thus ~4x frame rate
improvement, since the display's frame rate is currently
SPI-limited.
A before & after video can be seen here:
https://www.youtube.com/watch?v=n2y19TCnATo
Note that also on page 44 of that datasheet Tscycr (the read speed)
is only 150 ns, not 16 ns. Right now, the Pimoroni code doesn't read
any values back from the ST7789 so it is safe to operate at the
higher speed.
Also note that the 16 * 1000 * 1000 is the requested baud. The actual
baud is the closest the Pico can get, which is 15,625,000.
The new requested baud of 62'500'000 results in an exact match.
2021-11-11 23:20:21 +00:00
|
|
|
// The ST7789 requires 16 ns between SPI rising edges.
|
|
|
|
// 16 ns = 62,500,000 Hz
|
|
|
|
static const uint32_t SPI_BAUD = 62'500'000;
|
2021-03-24 12:18:56 +00:00
|
|
|
|
2022-05-12 12:04:55 +01:00
|
|
|
|
2021-03-24 12:18:56 +00:00
|
|
|
public:
|
2022-05-25 10:44:14 +01:00
|
|
|
// Parallel init
|
2022-06-07 12:55:02 +01:00
|
|
|
ST7789(uint16_t width, uint16_t height, Rotation rotation, ParallelPins pins) :
|
2022-06-07 16:37:06 +01:00
|
|
|
DisplayDriver(width, height, rotation),
|
|
|
|
spi(nullptr), round(false),
|
2022-06-06 17:54:15 +01:00
|
|
|
cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) {
|
2022-06-16 17:38:57 +01:00
|
|
|
|
|
|
|
parallel_pio = pio1;
|
|
|
|
parallel_sm = pio_claim_unused_sm(parallel_pio, true);
|
|
|
|
parallel_offset = pio_add_program(parallel_pio, &st7789_parallel_program);
|
2022-05-25 10:44:14 +01:00
|
|
|
|
2022-06-16 17:38:57 +01:00
|
|
|
//gpio_init(wr_sck);
|
|
|
|
//gpio_set_dir(wr_sck, GPIO_OUT);
|
|
|
|
//gpio_set_function(wr_sck, GPIO_FUNC_SIO);
|
|
|
|
pio_gpio_init(parallel_pio, wr_sck);
|
2022-05-25 10:44:14 +01:00
|
|
|
|
|
|
|
gpio_set_function(rd_sck, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(rd_sck, GPIO_OUT);
|
|
|
|
|
|
|
|
for(auto i = 0u; i < 8; i++) {
|
2022-06-16 17:38:57 +01:00
|
|
|
//gpio_set_function(d0 + i, GPIO_FUNC_SIO);
|
|
|
|
//gpio_set_dir(d0 + i, GPIO_OUT);
|
|
|
|
//gpio_init(d0 + 0); gpio_set_dir(d0 + i, GPIO_OUT);
|
|
|
|
pio_gpio_init(parallel_pio, d0 + i);
|
2022-05-25 10:44:14 +01:00
|
|
|
}
|
2022-06-16 17:38:57 +01:00
|
|
|
|
|
|
|
pio_sm_set_consecutive_pindirs(parallel_pio, parallel_sm, d0, 8, true);
|
|
|
|
pio_sm_set_consecutive_pindirs(parallel_pio, parallel_sm, wr_sck, 1, true);
|
|
|
|
|
|
|
|
pio_sm_config c = st7789_parallel_program_get_default_config(parallel_offset);
|
|
|
|
|
|
|
|
sm_config_set_out_pins(&c, d0, 8);
|
|
|
|
sm_config_set_sideset_pins(&c, wr_sck);
|
|
|
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
|
|
|
sm_config_set_out_shift(&c, false, true, 8);
|
2022-08-04 20:26:45 +01:00
|
|
|
|
|
|
|
// Determine clock divider
|
|
|
|
constexpr uint32_t max_pio_clk = 32 * MHZ;
|
|
|
|
const uint32_t sys_clk_hz = clock_get_hz(clk_sys);
|
|
|
|
const uint32_t clk_div = (sys_clk_hz + max_pio_clk - 1) / max_pio_clk;
|
|
|
|
sm_config_set_clkdiv(&c, clk_div);
|
2022-06-16 17:38:57 +01:00
|
|
|
|
|
|
|
pio_sm_init(parallel_pio, parallel_sm, parallel_offset, &c);
|
|
|
|
pio_sm_set_enabled(parallel_pio, parallel_sm, true);
|
|
|
|
|
|
|
|
|
2022-09-17 20:16:57 +01:00
|
|
|
st_dma = dma_claim_unused_channel(true);
|
|
|
|
dma_channel_config config = dma_channel_get_default_config(st_dma);
|
2022-06-16 17:38:57 +01:00
|
|
|
channel_config_set_transfer_data_size(&config, DMA_SIZE_8);
|
|
|
|
channel_config_set_bswap(&config, false);
|
|
|
|
channel_config_set_dreq(&config, pio_get_dreq(parallel_pio, parallel_sm, true));
|
2022-09-17 20:16:57 +01:00
|
|
|
dma_channel_configure(st_dma, &config, ¶llel_pio->txf[parallel_sm], NULL, 0, false);
|
2022-05-25 10:44:14 +01:00
|
|
|
|
|
|
|
gpio_put(rd_sck, 1);
|
|
|
|
|
|
|
|
common_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serial init
|
2022-06-07 12:55:02 +01:00
|
|
|
ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, SPIPins pins) :
|
2022-06-07 16:37:06 +01:00
|
|
|
DisplayDriver(width, height, rotation),
|
|
|
|
spi(pins.spi), round(round),
|
2022-06-06 17:54:15 +01:00
|
|
|
cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) {
|
2022-05-12 18:40:37 +01:00
|
|
|
|
2022-05-25 10:44:14 +01:00
|
|
|
// configure spi interface and pins
|
|
|
|
spi_init(spi, SPI_BAUD);
|
2022-05-12 18:40:37 +01:00
|
|
|
|
2022-05-25 10:44:14 +01:00
|
|
|
gpio_set_function(wr_sck, GPIO_FUNC_SPI);
|
|
|
|
gpio_set_function(d0, GPIO_FUNC_SPI);
|
2022-05-12 18:40:37 +01:00
|
|
|
|
2022-09-17 20:16:57 +01:00
|
|
|
st_dma = 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_8);
|
|
|
|
channel_config_set_bswap(&config, false);
|
|
|
|
channel_config_set_dreq(&config, spi_get_dreq(spi, true));
|
|
|
|
dma_channel_configure(st_dma, &config, &spi_get_hw(spi)->dr, NULL, 0, false);
|
|
|
|
|
2022-05-25 10:44:14 +01:00
|
|
|
common_init();
|
|
|
|
}
|
2022-05-12 18:40:37 +01:00
|
|
|
|
2022-06-16 17:38:57 +01:00
|
|
|
void cleanup() override;
|
2022-06-07 16:37:06 +01:00
|
|
|
void update(PicoGraphics *graphics) override;
|
|
|
|
void set_backlight(uint8_t brightness) override;
|
2022-05-25 10:44:14 +01:00
|
|
|
|
|
|
|
private:
|
2022-06-07 16:37:06 +01:00
|
|
|
void common_init();
|
2022-05-28 01:00:56 +01:00
|
|
|
void configure_display(Rotation rotate);
|
2022-09-17 20:16:57 +01:00
|
|
|
void write_blocking_dma(const uint8_t *src, size_t len);
|
2022-05-25 10:44:14 +01:00
|
|
|
void write_blocking_parallel(const uint8_t *src, size_t len);
|
2022-06-07 16:37:06 +01:00
|
|
|
void command(uint8_t command, size_t len = 0, const char *data = NULL);
|
2021-03-24 12:18:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|