pico display driver

pull/1/head
Jonathan Williamson 2021-01-16 12:26:03 +00:00
parent df663dac56
commit 90d3ab8178
8 changed files with 417 additions and 224 deletions

View File

@ -1,10 +1,15 @@
#include "st7789.hpp"
#include <cstdlib>
#include <math.h>
#include "hardware/dma.h"
#include "hardware/pwm.h"
namespace pimoroni {
void ST7789::init() {
void ST7789::init(bool auto_init_sequence) {
// configure spi interface and pins
spi_init(spi, spi_baud);
gpio_set_function(dc, GPIO_FUNC_SIO);
@ -13,23 +18,6 @@ namespace pimoroni {
gpio_set_function(cs, GPIO_FUNC_SIO);
gpio_set_dir(cs, GPIO_OUT);
// if framesync is enabled then the fs pin is toggled
// high during vsync
if(vsync != -1) {
gpio_set_function(fs, GPIO_FUNC_SIO);
gpio_set_dir(fs, GPIO_IN);
gpio_set_pulls(fs, false, true)
}
// if a backlight pin is provided then set it up for
// pwm control
if(bl != -1) {
pwm_config cfg = pwm_get_default_config();
pwm_config_wrap(&cfg, 65535);
pwm_init(pwm_gpio_to_slice(bl), &cfg, true);
gpio_set_function(bl, GPIO_FUNC_PWM);
}
gpio_set_function(sck, GPIO_FUNC_SPI);
gpio_set_function(mosi, GPIO_FUNC_SPI);
@ -37,104 +25,111 @@ namespace pimoroni {
gpio_set_function(miso, GPIO_FUNC_SPI);
}
// if supported by the display then the vsync pin is
// toggled high during vertical blanking period
if(vsync != -1) {
gpio_set_function(vsync, GPIO_FUNC_SIO);
gpio_set_dir(vsync, GPIO_IN);
gpio_set_pulls(vsync, false, true);
}
// if a backlight pin is provided then set it up for
// pwm control
if(bl != -1) {
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);
}
// if auto_init_sequence then send initialisation sequence
// for our standard displays based on the width and height
if(auto_init_sequence) {
command(reg::SWRESET);
sleep_ms(150);
if(width == 240 && height == 240) {
command(reg::MADCTL, 1, "\x04"); // row/column addressing order - rgb pixel order
command(reg::TEON, 1, "\x00"); // enable frame sync signal if used
command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel
}else if(width == 240 && height == 135) {
command(reg::MADCTL, 1, "\x70");
command(reg::COLMOD, 1, "\x05");
}
command(reg::INVON); // set inversion mode
command(reg::SLPOUT); // leave sleep mode
command(reg::DISPON); // turn display on
sleep_ms(100);
// setup correct addressing window
if(width == 240 && height == 240) {
command(reg::CASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 columns
command(reg::RASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 rows
}else if(width == 240 && height == 135) {
command(reg::RASET, 4, "\x00\x35\x00\xbb"); // 53 .. 187 (135 rows)
command(reg::CASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns)
}
}
// the dma transfer works but without vsync it's not that useful as you could
// be updating the framebuffer during transfer...
//
// this could be avoided by creating another buffer to draw into and flip
// buffers (but costs another ~100kb of ram)
//
// it's probably not worth it for this particular usecase but will consider it
// some more...
// setup spi for 16-bit transfers
// spi_set_format(spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
// initialise dma channel for transmitting pixel data to screen
dma_channel = dma_claim_unused_channel(true);
dma_channel_config config = dma_channel_get_default_config(dma_channel);
//channel_config_set_bswap(&config, true); // byte swap to reverse little endian
dma_channel_configure(
dma_channel,
&config,
&spi_get_hw(spi)->dr,
buffer,
sizeof(uint16_t) * width * height,
false);
// dma_channel = dma_claim_unused_channel(true);
// dma_channel_config config = dma_channel_get_default_config(dma_channel);
// channel_config_set_transfer_data_size(&config, DMA_SIZE_16);
// channel_config_set_dreq(&config, spi_get_index(spi) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
// dma_channel_configure(
// dma_channel, &config, &spi_get_hw(spi)->dr, frame_buffer, width * height, false);
}
void ST7789::init_240x240() {
init();
void ST7789::command(uint8_t command, size_t len, const char *data) {
//dma_channel_wait_for_finish_blocking(dma_channel);
width = 240;
height = 240;
row_stride = width * sizeof(uint16_t);
gpio_put(cs, 0);
// only initialise the buffer if one hasn't been supplied
if(!buffer) {
buffer = malloc(sizeof(uint16_t) * width * height);
}
// initialise our standard 240x240 LCD as 16-bit colour
// with an RGB subpixel element order.
command(register::SWRESET);
sleep_ms(150);
command(register::MADCTL, 1, "\x04"); // row/column addressing order - rgb pixel order
command(register::TEON, 1, "\x00"); // enable frame sync signal if used
command(register::COLMOD, 1, "\x05"); // 16 bits per pixel
command(register::SLPOUT); // leave sleep mode
command(register::DISPON); // turn display on
sleep_ms(100);
// set writing "window" to the full display
command(register::CASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 columns
command(register::RASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 rows
// put into write mode
command(register::RAMWR);
}
void ST7789::init_240x135() {
init();
width = 240;
height = 135;
row_stride = width * sizeof(uint16_t);
// only initialise the buffer if one hasn't been supplied
if(!buffer) {
buffer = malloc(sizeof(uint16_t) * width * height);
}
// initialise our standard 240x135 LCD as 16-bit colour
// with an RGB subpixel element order.
command(register::SWRESET);
sleep_ms(150);
command(register::MADCTL, 1, "\x70");
command(register::COLMOD, 1, "\x05");
command(register::SLPOUT); // leave sleep mode
command(register::DISPON); // turn display on
sleep_ms(100);
command(register::RASET, 4, "\x00\x35\x00\xbb"); // 53 .. 187 (135 rows)
command(register::CASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns)
}
void ST7789::command(uint8_t command, size_t len = 0, const char *data = NULL) {
gpio_put(pin::CS, 0);
gpio_put(pin::DC, 0); // command mode
spi_write_blocking(spi0, &command, 1);
gpio_put(dc, 0); // command mode
spi_write_blocking(spi, &command, 1);
if(data) {
gpio_put(pin::DC, 1); // data mode
spi_write_blocking(spi0, (const uint8_t*)data, len);
gpio_put(dc, 1); // data mode
spi_write_blocking(spi, (const uint8_t*)data, len);
}
gpio_put(pin::CS, 1);
gpio_put(cs, 1);
}
void ST7789::update() {
void ST7789::update(bool dont_block) {
ST7789::command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer);
/*if(dma_channel_is_busy(dma_channel) && dont_block) {
return;
}
dma_channel_wait_for_finish_blocking(dma_channel);
command(register::RAMWR);
dma_channel_start(dma_channel);
uint8_t r = reg::RAMWR;
gpio_put(cs, 0);
gpio_put(dc, 0); // command mode
spi_write_blocking(spi, &r, 1);
gpio_put(dc, 1); // data mode
dma_channel_set_read_addr(dma_channel, frame_buffer, true);*/
}
void ST7789::set_backlight(uint8_t brightness) {
@ -146,6 +141,6 @@ namespace pimoroni {
}
void ST7789::vsync_callback(gpio_irq_callback_t callback) {
gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, &callback);
gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, callback);
}
}

View File

@ -1,14 +1,13 @@
#pragma once
#include "hardware/spi.h"
#include "hardware/gpio.h"
namespace pimoroni {
class ST7789 {
spi_inst_t *spi = spi0_hw;
spi_inst_t *spi = spi0;
// framebuffer for storing pixel data
uint16_t *buffer;
uint32_t dma_channel;
// screen properties
@ -28,18 +27,28 @@ namespace pimoroni {
uint32_t spi_baud = 64 * 1024 * 1024;
public:
ST7789(spi_inst_t *spi, uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1) :
spi(spi), cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso) {}
// frame buffer where pixel data is stored
uint16_t *frame_buffer;
void init();
void init_240x240();
void init_240x235();
public:
ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer) :
width(width), height(height), frame_buffer(frame_buffer) {}
ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer,
spi_inst_t *spi,
uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1) :
width(width), height(height), frame_buffer(frame_buffer),
spi(spi),
cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso) {}
void init(bool auto_init_sequence = true);
void command(uint8_t command, size_t len = 0, const char *data = NULL);
void vsync_callback(gpio_irq_callback_t callback);
void update();
void update(bool dont_block = false);
void set_backlight(uint8_t brightness);
uint16_t pen(uint8_t r, uint8_t g, uint8_t b);
enum register {
enum reg {
SWRESET = 0x01,
TEON = 0x35,
MADCTL = 0x36,

View File

@ -0,0 +1,92 @@
#include "pico_graphics.hpp"
namespace pimoroni {
void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {
this->pen = create_pen(r, g, b);
}
void PicoGraphics::set_pen(uint16_t pen) {
this->pen = pen;
}
uint16_t PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {
uint16_t p = ((r & 0b11111000) << 8) |
((g & 0b11111100) << 3) |
((b & 0b11111000) >> 3);
// endian swap, this should be possible another way...
return ((p & 0xff00) >> 8) | ((p & 0xff) << 8);
}
uint16_t* PicoGraphics::ptr(int32_t x, int32_t y) {
return this->frame_buffer + x + y * this->width;
}
void PicoGraphics::pixel(int32_t x, int32_t y) {
if(x < 0 || y < 0 || x >= this->width || y >= this->height) { return; }
*ptr(x, y) = pen;
}
void PicoGraphics::pixel_span(int32_t x, int32_t y, int32_t l) {
if(x + l < 0 || y < 0 || x >= this->width || y >= this->height) { return; }
if(x < 0) {l += x; x = 0;}
if(x + l >= this->width) {l = this->width - x;}
uint16_t *p = ptr(x, y);
while(l--) {
*p++ = pen;
}
}
void PicoGraphics::rectangle(int32_t x, int32_t y, int32_t width, int32_t height) {
// clip and/or discard depending on rectangle visibility
if(x >= this->width || y >= this->height) { return; }
if(x < 0) { width += x; x = 0; }
if(y < 0) { height += y; y = 0; }
if(width <= 0 || height <= 0) { return; }
if(x + width >= this->width) { width = this->width - x; }
if(y + height >= this->height) { height = this->height - y; }
uint16_t *p = ptr(x, y);
while(height--) {
for(uint32_t i = 0; i < width; i++) {
*p++ = this->pen;
}
p += this->width - width; // move to next scanline
}
}
void PicoGraphics::circle(int32_t x, int32_t y, int32_t radius) {
// circle in screen bounds?
if(x + radius < 0 || y + radius < 0 || x - radius >= this->width || y - radius >= this->height) { return; }
int ox = radius, oy = 0, err = -radius;
while (ox >= oy)
{
int last_oy = oy;
err += oy; oy++; err += oy;
pixel_span(x - ox, y + last_oy, ox * 2 + 1);
if (last_oy != 0) {
pixel_span(x - ox, y - last_oy, ox * 2 + 1);
}
if (err >= 0) {
if (ox != last_oy) {
pixel_span(x - last_oy, y + ox, last_oy * 2 + 1);
if (ox != 0) {
pixel_span(x - last_oy, y - ox, last_oy * 2 + 1);
}
err -= ox; ox--; err -= ox;
}
}
}
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <cstdint>
// a tiny little graphics library for our Pico products
// supports only 16-bit (565) RGB framebuffers
namespace pimoroni {
class PicoGraphics {
public:
uint16_t width;
uint16_t height;
uint16_t *frame_buffer;
uint16_t pen;
public:
PicoGraphics(uint16_t width, uint16_t height, uint16_t *frame_buffer)
: frame_buffer(frame_buffer), width(width), height(height) {}
void set_pen(uint8_t r, uint8_t g, uint8_t b);
void set_pen(uint16_t p);
uint16_t create_pen(uint8_t r, uint8_t g, uint8_t b);
uint16_t* ptr(int32_t x, int32_t y);
void pixel(int32_t x, int32_t y);
void pixel_span(int32_t x, int32_t y, int32_t l);
void rectangle(int32_t x, int32_t y, int32_t w, int32_t h);
void circle(int32_t x, int32_t y, int32_t r);
//void polygon(std::vector);
};
}

View File

@ -14,7 +14,9 @@ add_executable(
display
demo.cpp
image_data.cpp
pico_display.cpp
../../../drivers/st7789/st7789.cpp
../../../libraries/pico_graphics/pico_graphics.cpp
)
# Pull in pico libraries that we need

View File

@ -1,49 +1,33 @@
#include <string.h>
#include <math.h>
#include <vector>
#include <cstdlib>
#include "hardware/pwm.h"
#include "../../drivers/st7789/st7789.hpp"
#include "pico_display.hpp"
using namespace pimoroni;
extern unsigned char image_tif[];
extern unsigned int image_tif_len;
enum pin {
LED_R = 6,
LED_G = 7,
LED_B = 8,
BUTTON_A = 12,
BUTTON_B = 13,
BUTTON_X = 14,
BUTTON_Y = 15
};
ST7789 screen;
void flip() {
// write to screen
}
PicoDisplay pico_display;
/*
void pixel(int x, int y, uint16_t c) {
x *= 2;
y *= 2;
screen.buffer[x + y * 240] = c;
screen.buffer[x + 1 + y * 240] = c;
screen.buffer[x + 1 + (y + 1) * 240] = c;
screen.buffer[x + (y + 1) * 240] = c;
pico_display.frame_buffer[x + y * 240] = c;
pico_display.frame_buffer[x + 1 + y * 240] = c;
pico_display.frame_buffer[x + 1 + (y + 1) * 240] = c;
pico_display.frame_buffer[x + (y + 1) * 240] = c;
}
void rect(int x, int y, int w, int h, uint16_t c) {
for(int rx = x; rx < x + w; rx++) {
for(int ry = y; ry < y + h; ry++) {
pixel(rx, ry, c);
}
}
}
}*/
uint8_t arrow[] = {
0b00010000,
@ -67,7 +51,7 @@ uint8_t tick[] = {
0b00000000,
};
/*
void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) {
for(int ay = 0; ay < 8; ay++) {
uint8_t sl = p[ay];
@ -83,116 +67,98 @@ void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) {
}
}
}
}
}*/
int main() {
pico_display.set_backlight(100);
//screen.buffer = (uint16_t*)(image_tif + 292);
screen.init_240x135();
screen.set_backlight(100);
// rgb led to a soft white
pwm_config cfg1 = pwm_get_default_config();
pwm_config_set_wrap(&cfg1, 255);
pwm_config_set_output_polarity(&cfg1, true, true);
pwm_init(pwm_gpio_to_slice_num(pin::LED_R), &cfg1, true);
gpio_set_function(pin::LED_R, GPIO_FUNC_PWM);
pwm_set_gpio_level(pin::LED_R, 50);
pwm_config cfg2 = pwm_get_default_config();
pwm_config_set_wrap(&cfg2, 255);
pwm_config_set_output_polarity(&cfg2, true, true);
pwm_init(pwm_gpio_to_slice_num(pin::LED_G), &cfg2, true);
gpio_set_function(pin::LED_G, GPIO_FUNC_PWM);
pwm_set_gpio_level(pin::LED_G, 50);
pwm_config cfg3 = pwm_get_default_config();
pwm_config_set_wrap(&cfg3, 255);
pwm_config_set_output_polarity(&cfg3, true, true);
pwm_init(pwm_gpio_to_slice_num(pin::LED_B), &cfg3, true);
gpio_set_function(pin::LED_B, GPIO_FUNC_PWM);
pwm_set_gpio_level(pin::LED_B, 50);
// setup button inputs
gpio_set_function(pin::BUTTON_A, GPIO_FUNC_SIO); gpio_set_dir(pin::BUTTON_A, GPIO_IN); gpio_pull_up(pin::BUTTON_A);
gpio_set_function(pin::BUTTON_B, GPIO_FUNC_SIO); gpio_set_dir(pin::BUTTON_B, GPIO_IN); gpio_pull_up(pin::BUTTON_B);
gpio_set_function(pin::BUTTON_X, GPIO_FUNC_SIO); gpio_set_dir(pin::BUTTON_X, GPIO_IN); gpio_pull_up(pin::BUTTON_X);
gpio_set_function(pin::BUTTON_Y, GPIO_FUNC_SIO); gpio_set_dir(pin::BUTTON_Y, GPIO_IN); gpio_pull_up(pin::BUTTON_Y);
uint16_t white = screen.pen(255, 255, 255);
uint16_t black = screen.pen(0, 0, 0);
uint16_t red = screen.pen(255, 0, 0);
uint16_t green = screen.pen(0, 255, 0);
uint16_t dark_grey = screen.pen(20, 40, 60);
uint16_t dark_green = screen.pen(10, 100, 10);
uint16_t blue = screen.pen(0, 0, 255);
// uint16_t white = pico_display.create_pen(255, 255, 255);
// uint16_t black = pico_display.create_pen(0, 0, 0);
// uint16_t red = pico_display.create_pen(255, 0, 0);
// uint16_t green = pico_display.create_pen(0, 255, 0);
// uint16_t dark_grey = pico_display.create_pen(20, 40, 60);
// uint16_t dark_green = pico_display.create_pen(10, 100, 10);
// uint16_t blue = pico_display.create_pen(0, 0, 255);
bool a_pressed = false;
bool b_pressed = false;
bool x_pressed = false;
bool y_pressed = false;
struct pt {
float x;
float y;
uint8_t r;
float dx;
float dy;
uint16_t pen;
};
std::vector<pt> shapes;
for(int i = 0; i < 1000; i++) {
pt shape;
shape.x = rand() % 240;
shape.y = rand() % 135;
shape.r = (rand() % 10) + 3;
shape.dx = float(rand() % 255) / 128.0f;
shape.dy = float(rand() % 255) / 128.0f;
shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255);
shapes.push_back(shape);
}
uint32_t i = 0;
while(true) {
//rect(0, 0, 120, 67, dark_grey);
//memset(framebuffer, 0x05, 240 * 135 * 2);
pico_display.set_pen(120, 40, 60);
pico_display.rectangle(0, 0, 240, 135);
// we need to be careful to clamp the input to
// sin here because otherwise the fast float
// library will choke
float sin_step = fmod(i / 5.0f, M_PI * 2.0f);
int bounce = sin(sin_step) * 4.0f;
for(auto &shape : shapes) {
shape.x += shape.dx;
shape.y += shape.dy;
if(shape.x < 0) shape.dx *= -1;
if(shape.x >= pico_display.width) shape.dx *= -1;
if(shape.y < 0) shape.dy *= -1;
if(shape.y >= pico_display.height) shape.dy *= -1;
pico_display.set_pen(shape.pen);
pico_display.circle(shape.x, shape.y, shape.r);
}
float led_step = fmod(i / 20.0f, M_PI * 2.0f);
int r = (sin(led_step) * 25.0f) + 25.0f;
// int g = (sin(led_step + 2.09f) * 25.0f) + 25.0f;
// int b = (sin(led_step + 4.18f) * 25.0f) + 25.0f;
// pwm_set_gpio_level(pin::LED_R, r);
// pwm_set_gpio_level(pin::LED_G, g);
// pwm_set_gpio_level(pin::LED_B, b);
pico_display.set_led(r, r / 1.2f, r);
pwm_set_gpio_level(pin::LED_R, r);
pwm_set_gpio_level(pin::LED_G, r / 1.2f);
pwm_set_gpio_level(pin::LED_B, r);
if(!gpio_get(pin::BUTTON_A)) { a_pressed = true; }
if(!gpio_get(pin::BUTTON_B)) { b_pressed = true; }
if(!gpio_get(pin::BUTTON_X)) { x_pressed = true; }
if(!gpio_get(pin::BUTTON_Y)) { y_pressed = true; }
if(a_pressed) {
rect(0, 0, 18, 18, dark_green);
sprite(tick, 5, 5, true, green);
/*
if(pico_display.is_pressed(pico_display.A)) {
pico_display.rectangle(0, 0, 18, 18);
//sprite(tick, 5, 5, true, green);
}else{
sprite(arrow, 10 + bounce, 10, true, white);
//sprite(arrow, 10 + bounce, 10, true, white);
}
if(b_pressed) {
rect(0, 49, 18, 18, dark_green);
sprite(tick, 5, 54, true, green);
if(pico_display.is_pressed(pico_display.B)) {
pico_display.rectangle(0, 49, 18, 18);
//sprite(tick, 5, 54, true, green);
}else{
sprite(arrow, 10 - bounce, 50, true, white);
//sprite(arrow, 10 - bounce, 50, true, white);
}
if(x_pressed) {
rect(102, 0, 18, 18, dark_green);
sprite(tick, 107, 5, true, green);
if(pico_display.is_pressed(pico_display.X)) {
pico_display.rectangle(102, 0, 18, 18);
//sprite(tick, 107, 5, true, green);
}else{
sprite(arrow, 102 - bounce, 10, false, white);
//sprite(arrow, 102 - bounce, 10, false, white);
}
if(y_pressed) {
rect(102, 49, 18, 18, dark_green);
sprite(tick, 107, 54, true, green);
if(pico_display.is_pressed(pico_display.Y)) {
pico_display.rectangle(102, 49, 18, 18);
//sprite(tick, 107, 54, true, green);
}else{
sprite(arrow, 102 + bounce, 50, false, white);
//sprite(arrow, 102 + bounce, 50, false, white);
}
*/
// update screen
// switch st7789 into data mode
screen.update();
pico_display.update();
i++;
}

View File

@ -0,0 +1,69 @@
#include <math.h>
#include "hardware/pwm.h"
#include "pico_display.hpp"
const uint8_t LED_R = 6;
const uint8_t LED_G = 7;
const uint8_t LED_B = 8;
namespace pimoroni {
PicoDisplay::PicoDisplay()
: screen(240, 135, __fb), PicoGraphics(240, 135, __fb) {
// setup the rgb led for pwm control
pwm_config cfg = pwm_get_default_config();
pwm_config_set_output_polarity(&cfg, true, true);
// red
pwm_set_wrap(pwm_gpio_to_slice_num(LED_R), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_R), &cfg, true);
gpio_set_function(LED_R, GPIO_FUNC_PWM);
// green
pwm_set_wrap(pwm_gpio_to_slice_num(LED_G), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_G), &cfg, true);
gpio_set_function(LED_G, GPIO_FUNC_PWM);
// blue
pwm_set_wrap(pwm_gpio_to_slice_num(LED_B), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_B), &cfg, true);
gpio_set_function(LED_B, GPIO_FUNC_PWM);
// setup button inputs
gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A);
gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B);
gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X);
gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y);
// initialise the screen
screen.init();
}
void PicoDisplay::set_led(uint8_t r, uint8_t g, uint8_t b) {
// gamma correct the provided 0-255 brightness value onto a
// 0-65535 range for the pwm counter
static const float gamma = 2.8;
uint16_t value;
// red
value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65536.0f + 0.5f);
pwm_set_gpio_level(LED_R, value);
// green
value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65536.0f + 0.5f);
pwm_set_gpio_level(LED_G, value);
// blue
value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65536.0f + 0.5f);
pwm_set_gpio_level(LED_B, value);
}
bool PicoDisplay::is_pressed(uint8_t button) {
return !gpio_get(button);
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "../../drivers/st7789/st7789.hpp"
#include "../../libraries/pico_graphics/pico_graphics.hpp"
namespace pimoroni {
class PicoDisplay : public PicoGraphics {
uint16_t __fb[240 * 135];
ST7789 screen;
public:
PicoDisplay();
void set_backlight(uint8_t brightness) {screen.set_backlight(brightness);}
void update() {screen.update();}
void set_led(uint8_t r, uint8_t g, uint8_t b);
bool is_pressed(uint8_t button);
static const uint8_t A = 12;
static const uint8_t B = 13;
static const uint8_t X = 14;
static const uint8_t Y = 15;
};
}