pico display driver
parent
df663dac56
commit
90d3ab8178
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue