2021-03-24 12:18:56 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "hardware/spi.h"
|
|
|
|
#include "hardware/gpio.h"
|
2022-05-12 18:40:37 +01:00
|
|
|
#include "hardware/pwm.h"
|
2022-05-28 01:00:56 +01:00
|
|
|
#include "common/pimoroni_common.hpp"
|
|
|
|
#include "common/pimoroni_bus.hpp"
|
|
|
|
|
|
|
|
#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 {
|
|
|
|
|
|
|
|
class ST7789 {
|
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:
|
|
|
|
// screen properties
|
|
|
|
uint16_t width;
|
|
|
|
uint16_t height;
|
|
|
|
Rotation rotation;
|
|
|
|
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
|
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-28 01:00:56 +01:00
|
|
|
|
2021-04-20 10:54:10 +01:00
|
|
|
// frame buffer where pixel data is stored
|
2022-05-26 11:51:15 +01:00
|
|
|
void *frame_buffer;
|
2021-04-20 10:54:10 +01:00
|
|
|
|
2022-05-25 10:44:14 +01:00
|
|
|
// Parallel init
|
2022-05-28 01:00:56 +01:00
|
|
|
ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) :
|
2022-05-25 10:44:14 +01:00
|
|
|
spi(nullptr),
|
2022-05-28 01:00:56 +01:00
|
|
|
width(width), height(height), rotation(rotation), round(false),
|
|
|
|
cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) {
|
2022-05-25 10:44:14 +01:00
|
|
|
|
|
|
|
gpio_set_function(wr_sck, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(wr_sck, GPIO_OUT);
|
|
|
|
|
|
|
|
gpio_set_function(rd_sck, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(rd_sck, GPIO_OUT);
|
|
|
|
|
|
|
|
for(auto i = 0u; i < 8; i++) {
|
|
|
|
gpio_set_function(d0 + i, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(d0 + i, GPIO_OUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
gpio_put(rd_sck, 1);
|
|
|
|
|
|
|
|
common_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serial init
|
2022-05-28 01:00:56 +01:00
|
|
|
ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) :
|
|
|
|
spi(pins.spi),
|
|
|
|
width(width), height(height), rotation(rotation), round(round),
|
2022-05-28 23:00:43 +01:00
|
|
|
cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) {
|
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-05-25 10:44:14 +01:00
|
|
|
common_init();
|
|
|
|
}
|
2022-05-12 18:40:37 +01:00
|
|
|
|
|
|
|
void init();
|
2021-03-24 12:18:56 +00:00
|
|
|
void command(uint8_t command, size_t len = 0, const char *data = NULL);
|
2022-05-28 01:00:56 +01:00
|
|
|
void set_backlight(uint8_t brightness);
|
|
|
|
|
2022-05-26 11:51:15 +01:00
|
|
|
void update();
|
2022-05-25 17:22:20 +01:00
|
|
|
void update(uint16_t *palette);
|
2022-05-25 10:44:14 +01:00
|
|
|
|
|
|
|
private:
|
2022-05-28 01:00:56 +01:00
|
|
|
void configure_display(Rotation rotate);
|
2022-05-25 10:44:14 +01:00
|
|
|
void write_blocking_parallel(const uint8_t *src, size_t len);
|
|
|
|
void common_init() {
|
|
|
|
if(!this->frame_buffer) {
|
2022-05-25 17:22:20 +01:00
|
|
|
this->frame_buffer = new uint8_t[width * height];
|
2022-05-25 10:44:14 +01:00
|
|
|
}
|
|
|
|
|
2022-05-28 01:00:56 +01:00
|
|
|
gpio_set_function(dc, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(dc, GPIO_OUT);
|
|
|
|
|
|
|
|
gpio_set_function(cs, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(cs, GPIO_OUT);
|
|
|
|
|
2022-05-25 10:44:14 +01:00
|
|
|
// if a backlight pin is provided then set it up for
|
|
|
|
// pwm control
|
|
|
|
if(bl != PIN_UNUSED) {
|
|
|
|
pwm_config cfg = pwm_get_default_config();
|
|
|
|
pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535);
|
|
|
|
pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true);
|
|
|
|
gpio_set_function(bl, GPIO_FUNC_PWM);
|
|
|
|
set_backlight(0); // Turn backlight off initially to avoid nasty surprises
|
|
|
|
}
|
|
|
|
}
|
2021-03-24 12:18:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|