Merge pull request #327 from pimoroni/feature/merged-st7789
ST7789: Create generic display driver
This commit is contained in:
commit
db60553322
|
@ -3,9 +3,6 @@
|
|||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
namespace pimoroni {
|
||||
uint8_t madctl;
|
||||
uint16_t caset[2] = {0, 0};
|
||||
|
@ -20,11 +17,6 @@ namespace pimoroni {
|
|||
HORIZ_ORDER = 0b00000100
|
||||
};
|
||||
|
||||
#define ROT_240_240_0 0
|
||||
#define ROT_240_240_90 MADCTL::SWAP_XY | MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER
|
||||
#define ROT_240_240_180 MADCTL::SCAN_ORDER | MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER | MADCTL::ROW_ORDER
|
||||
#define ROT_240_240_270 MADCTL::SWAP_XY | MADCTL::HORIZ_ORDER | MADCTL::ROW_ORDER
|
||||
|
||||
enum reg {
|
||||
SWRESET = 0x01,
|
||||
TEOFF = 0x34,
|
||||
|
@ -54,155 +46,118 @@ namespace pimoroni {
|
|||
PWMFRSEL = 0xCC
|
||||
};
|
||||
|
||||
void ST7789::init(bool auto_init_sequence, bool round, uint32_t spi_baud) {
|
||||
// configure spi interface and pins
|
||||
spi_init(spi, spi_baud);
|
||||
void ST7789::init() {
|
||||
command(reg::SWRESET);
|
||||
|
||||
gpio_set_function(dc, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(dc, GPIO_OUT);
|
||||
sleep_ms(150);
|
||||
|
||||
gpio_set_function(cs, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(cs, GPIO_OUT);
|
||||
// Common init
|
||||
command(reg::TEON); // enable frame sync signal if used
|
||||
command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel
|
||||
|
||||
gpio_set_function(sck, GPIO_FUNC_SPI);
|
||||
gpio_set_function(mosi, GPIO_FUNC_SPI);
|
||||
command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
|
||||
command(reg::LCMCTRL, 1, "\x2c");
|
||||
command(reg::VDVVRHEN, 1, "\x01");
|
||||
command(reg::VRHS, 1, "\x12");
|
||||
command(reg::VDVS, 1, "\x20");
|
||||
command(reg::PWCTRL1, 2, "\xa4\xa1");
|
||||
command(reg::FRCTRL2, 1, "\x0f");
|
||||
|
||||
if(miso != PIN_UNUSED) {
|
||||
gpio_set_function(miso, GPIO_FUNC_SPI);
|
||||
if(width == 240 && height == 240) {
|
||||
command(reg::GCTRL, 1, "\x14");
|
||||
command(reg::VCOMS, 1, "\x37");
|
||||
command(reg::GMCTRP1, 14, "\xD0\x04\x0D\x11\x13\x2B\x3F\x54\x4C\x18\x0D\x0B\x1F\x23");
|
||||
command(reg::GMCTRN1, 14, "\xD0\x04\x0C\x11\x13\x2C\x3F\x44\x51\x2F\x1F\x1F\x20\x23");
|
||||
}
|
||||
|
||||
// if supported by the display then the vsync pin is
|
||||
// toggled high during vertical blanking period
|
||||
if(vsync != PIN_UNUSED) {
|
||||
gpio_set_function(vsync, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(vsync, GPIO_IN);
|
||||
gpio_set_pulls(vsync, false, true);
|
||||
if((width == 320 && height == 240)
|
||||
|| (width == 240 && height == 320)) {
|
||||
command(reg::GCTRL, 1, "\x35");
|
||||
command(reg::VCOMS, 1, "\x1f");
|
||||
command(0xd6, 1, "\xa1"); // ???
|
||||
command(reg::GMCTRP1, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D");
|
||||
command(reg::GMCTRN1, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31");
|
||||
}
|
||||
|
||||
// if a backlight pin is provided then set it up for
|
||||
// pwm control
|
||||
command(reg::INVON); // set inversion mode
|
||||
command(reg::SLPOUT); // leave sleep mode
|
||||
command(reg::DISPON); // turn display on
|
||||
|
||||
sleep_ms(100);
|
||||
|
||||
configure_display(false);
|
||||
|
||||
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
|
||||
update(); // Send the new buffer to the display to clear any previous content
|
||||
sleep_ms(50); // Wait for the update to apply
|
||||
set_backlight(255); // Turn backlight on now surprises have passed
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
command(reg::TEON); // enable frame sync signal if used
|
||||
command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel
|
||||
|
||||
if(width == 240 && height == 240) {
|
||||
command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
|
||||
command(reg::GCTRL, 1, "\x14");
|
||||
command(reg::VCOMS, 1, "\x37");
|
||||
command(reg::LCMCTRL, 1, "\x2c");
|
||||
command(reg::VDVVRHEN, 1, "\x01");
|
||||
command(reg::VRHS, 1, "\x12");
|
||||
command(reg::VDVS, 1, "\x20");
|
||||
command(reg::PWCTRL1, 2, "\xa4\xa1");
|
||||
command(reg::FRCTRL2, 1, "\x0f");
|
||||
command(reg::GMCTRP1, 14, "\xD0\x04\x0D\x11\x13\x2B\x3F\x54\x4C\x18\x0D\x0B\x1F\x23");
|
||||
command(reg::GMCTRN1, 14, "\xD0\x04\x0C\x11\x13\x2C\x3F\x44\x51\x2F\x1F\x1F\x20\x23");
|
||||
}
|
||||
|
||||
if(width == 320 && height == 240) {
|
||||
command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33");
|
||||
command(reg::GCTRL, 1, "\x35");
|
||||
command(reg::VCOMS, 1, "\x1f");
|
||||
command(reg::LCMCTRL, 1, "\x2c");
|
||||
command(reg::VDVVRHEN, 1, "\x01");
|
||||
command(reg::VRHS, 1, "\x12");
|
||||
command(reg::VDVS, 1, "\x20");
|
||||
command(reg::FRCTRL2, 1, "\x0f");
|
||||
command(reg::PWCTRL1, 2, "\xa4\xa1");
|
||||
command(0xd6, 1, "\xa1"); // ???
|
||||
command(reg::GMCTRP1, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D");
|
||||
command(reg::GMCTRN1, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31");
|
||||
}
|
||||
|
||||
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) {
|
||||
caset[0] = 0;
|
||||
caset[1] = 239;
|
||||
raset[0] = round ? 40 : 0;
|
||||
raset[1] = round ? 279 : 239;
|
||||
madctl = MADCTL::HORIZ_ORDER;
|
||||
}
|
||||
|
||||
if(width == 240 && height == 135) {
|
||||
caset[0] = 40; // 240 cols
|
||||
caset[1] = 279;
|
||||
raset[0] = 53; // 135 rows
|
||||
raset[1] = 187;
|
||||
madctl = MADCTL::COL_ORDER | MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
|
||||
}
|
||||
|
||||
if(width == 135 && height == 240) {
|
||||
caset[0] = 52; // 135 cols
|
||||
caset[1] = 186;
|
||||
raset[0] = 40; // 240 rows
|
||||
void ST7789::configure_display(bool rotate180) {
|
||||
// 240x240 Square and Round LCD Breakouts
|
||||
// TODO: How can we support 90 degree rotations here?
|
||||
if(width == 240 && height == 240) {
|
||||
caset[0] = 0;
|
||||
caset[1] = 239;
|
||||
if(round) {
|
||||
raset[0] = 40;
|
||||
raset[1] = 279;
|
||||
madctl = 0;
|
||||
}
|
||||
|
||||
if(width == 320 && height == 240) {
|
||||
caset[0] = 0;
|
||||
caset[1] = 319;
|
||||
raset[0] = 0;
|
||||
raset[1] = 239;
|
||||
madctl = 0x70;
|
||||
}
|
||||
|
||||
// Byte swap the 16bit rows/cols values
|
||||
caset[0] = __builtin_bswap16(caset[0]);
|
||||
caset[1] = __builtin_bswap16(caset[1]);
|
||||
raset[0] = __builtin_bswap16(raset[0]);
|
||||
raset[1] = __builtin_bswap16(raset[1]);
|
||||
|
||||
command(reg::CASET, 4, (char *)caset);
|
||||
command(reg::RASET, 4, (char *)raset);
|
||||
command(reg::MADCTL, 1, (char *)&madctl);
|
||||
|
||||
if(bl != PIN_UNUSED) {
|
||||
update(); // Send the new buffer to the display to clear any previous content
|
||||
sleep_ms(50); // Wait for the update to apply
|
||||
set_backlight(255); // Turn backlight on now surprises have passed
|
||||
} else {
|
||||
raset[0] = rotate180 ? 80 : 0;
|
||||
raset[1] = rotate180 ? 329 : 239;
|
||||
}
|
||||
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
madctl |= MADCTL::HORIZ_ORDER;
|
||||
}
|
||||
|
||||
// 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...
|
||||
// Pico Display
|
||||
if(width == 240 && height == 135) {
|
||||
caset[0] = 40; // 240 cols
|
||||
caset[1] = 279;
|
||||
raset[0] = 53; // 135 rows
|
||||
raset[1] = 187;
|
||||
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
|
||||
}
|
||||
|
||||
// setup spi for 16-bit transfers
|
||||
// spi_set_format(spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
// Pico Display at 90 degree rotation
|
||||
if(width == 135 && height == 240) {
|
||||
caset[0] = 52; // 135 cols
|
||||
caset[1] = 186;
|
||||
raset[0] = 40; // 240 rows
|
||||
raset[1] = 279;
|
||||
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
}
|
||||
|
||||
// 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_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);
|
||||
// Pico Display 2.0
|
||||
if(width == 320 && height == 240) {
|
||||
caset[0] = 0;
|
||||
caset[1] = 319;
|
||||
raset[0] = 0;
|
||||
raset[1] = 239;
|
||||
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
|
||||
}
|
||||
|
||||
// Pico Display 2.0 at 90 degree rotation
|
||||
if(width == 240 && height == 320) {
|
||||
caset[0] = 0;
|
||||
caset[1] = 239;
|
||||
raset[0] = 0;
|
||||
raset[1] = 319;
|
||||
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
}
|
||||
|
||||
// Byte swap the 16bit rows/cols values
|
||||
caset[0] = __builtin_bswap16(caset[0]);
|
||||
caset[1] = __builtin_bswap16(caset[1]);
|
||||
raset[0] = __builtin_bswap16(raset[0]);
|
||||
raset[1] = __builtin_bswap16(raset[1]);
|
||||
|
||||
command(reg::CASET, 4, (char *)caset);
|
||||
command(reg::RASET, 4, (char *)raset);
|
||||
command(reg::MADCTL, 1, (char *)&madctl);
|
||||
}
|
||||
|
||||
spi_inst_t* ST7789::get_spi() const {
|
||||
|
@ -230,8 +185,6 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void ST7789::command(uint8_t command, size_t len, const char *data) {
|
||||
//dma_channel_wait_for_finish_blocking(dma_channel);
|
||||
|
||||
gpio_put(cs, 0);
|
||||
|
||||
gpio_put(dc, 0); // command mode
|
||||
|
@ -245,25 +198,8 @@ namespace pimoroni {
|
|||
gpio_put(cs, 1);
|
||||
}
|
||||
|
||||
void ST7789::update(bool dont_block) {
|
||||
void ST7789::update() {
|
||||
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);
|
||||
|
||||
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) {
|
||||
|
@ -274,12 +210,7 @@ namespace pimoroni {
|
|||
pwm_set_gpio_level(bl, value);
|
||||
}
|
||||
|
||||
void ST7789::vsync_callback(gpio_irq_callback_t callback) {
|
||||
gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, callback);
|
||||
}
|
||||
|
||||
void ST7789::flip(){
|
||||
madctl ^= MADCTL::ROW_ORDER | MADCTL::COL_ORDER;
|
||||
command(reg::MADCTL, 1, (char *)&madctl);
|
||||
configure_display(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/pwm.h"
|
||||
#include "../../common/pimoroni_common.hpp"
|
||||
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class ST7789 {
|
||||
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
|
@ -17,60 +18,67 @@ namespace pimoroni {
|
|||
// screen properties
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t row_stride;
|
||||
uint32_t dma_channel;
|
||||
bool round;
|
||||
|
||||
// interface pins with our standard defaults where appropriate
|
||||
uint cs = SPI_BG_FRONT_CS;
|
||||
uint dc = SPI_DEFAULT_MISO;
|
||||
uint sck = SPI_DEFAULT_SCK;
|
||||
uint mosi = SPI_DEFAULT_MOSI;
|
||||
uint miso = PIN_UNUSED; // used as data/command
|
||||
uint bl = SPI_BG_FRONT_PWM;
|
||||
uint cs;
|
||||
uint dc;
|
||||
uint sck;
|
||||
uint mosi;
|
||||
uint bl;
|
||||
uint vsync = PIN_UNUSED; // only available on some products
|
||||
|
||||
// The ST7789 requires 16 ns between SPI rising edges.
|
||||
// 16 ns = 62,500,000 Hz
|
||||
static const uint32_t SPI_BAUD = 62'500'000;
|
||||
|
||||
|
||||
public:
|
||||
// frame buffer where pixel data is stored
|
||||
uint16_t *frame_buffer;
|
||||
|
||||
ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, BG_SPI_SLOT slot) :
|
||||
width(width), height(height), frame_buffer(frame_buffer) {
|
||||
switch(slot) {
|
||||
case PICO_EXPLORER_ONBOARD:
|
||||
cs = SPI_BG_FRONT_CS;
|
||||
bl = PIN_UNUSED;
|
||||
break;
|
||||
case BG_SPI_FRONT:
|
||||
cs = SPI_BG_FRONT_CS;
|
||||
bl = SPI_BG_FRONT_PWM;
|
||||
break;
|
||||
case BG_SPI_BACK:
|
||||
cs = SPI_BG_BACK_CS;
|
||||
bl = SPI_BG_BACK_PWM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ST7789(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer,
|
||||
spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint miso = PIN_UNUSED, uint bl = PIN_UNUSED) :
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
|
||||
spi(spi),
|
||||
width(width), height(height),
|
||||
cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), bl(bl), frame_buffer(frame_buffer) {}
|
||||
width(width), height(height), round(round),
|
||||
cs(cs), dc(dc), sck(sck), mosi(mosi), bl(bl), frame_buffer(frame_buffer) {
|
||||
|
||||
if(!this->frame_buffer) {
|
||||
this->frame_buffer = new uint16_t[width * height];
|
||||
}
|
||||
|
||||
// configure spi interface and pins
|
||||
spi_init(spi, SPI_BAUD);
|
||||
|
||||
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);
|
||||
|
||||
gpio_set_function(sck, GPIO_FUNC_SPI);
|
||||
gpio_set_function(mosi, GPIO_FUNC_SPI);
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
void init(bool auto_init_sequence = true, bool round = false, uint32_t spi_baud = SPI_BAUD);
|
||||
void init();
|
||||
void configure_display(bool rotate180);
|
||||
|
||||
spi_inst_t* get_spi() const;
|
||||
uint get_cs() const;
|
||||
|
@ -80,10 +88,33 @@ namespace pimoroni {
|
|||
uint get_bl() const;
|
||||
|
||||
void command(uint8_t command, size_t len = 0, const char *data = NULL);
|
||||
void vsync_callback(gpio_irq_callback_t callback);
|
||||
void update(bool dont_block = false);
|
||||
void update();
|
||||
void set_backlight(uint8_t brightness);
|
||||
void flip();
|
||||
|
||||
static uint get_slot_cs(BG_SPI_SLOT slot) {
|
||||
switch(slot) {
|
||||
case PICO_EXPLORER_ONBOARD:
|
||||
return SPI_BG_FRONT_CS;
|
||||
case BG_SPI_FRONT:
|
||||
return SPI_BG_FRONT_CS;
|
||||
case BG_SPI_BACK:
|
||||
return SPI_BG_BACK_CS;
|
||||
}
|
||||
return PIN_UNUSED;
|
||||
};
|
||||
|
||||
static uint get_slot_bl(BG_SPI_SLOT slot) {
|
||||
switch(slot) {
|
||||
case PICO_EXPLORER_ONBOARD:
|
||||
return PIN_UNUSED;
|
||||
case BG_SPI_FRONT:
|
||||
return SPI_BG_FRONT_PWM;
|
||||
case BG_SPI_BACK:
|
||||
return SPI_BG_BACK_PWM;
|
||||
}
|
||||
return PIN_UNUSED;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ add_executable(
|
|||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_colourlcd240x240)
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib generic_st7789)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
#include "breakout_colourlcd240x240.hpp"
|
||||
#include "generic_st7789.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
uint16_t buffer[BreakoutColourLCD240x240::WIDTH * BreakoutColourLCD240x240::HEIGHT];
|
||||
BreakoutColourLCD240x240 lcd(buffer);
|
||||
const int WIDTH = 240;
|
||||
const int HEIGHT = 240;
|
||||
|
||||
ST7789Generic lcd(WIDTH, HEIGHT, false, nullptr, BG_SPI_FRONT);
|
||||
|
||||
int main() {
|
||||
lcd.init();
|
||||
//lcd.configure_display(false);
|
||||
lcd.set_backlight(255);
|
||||
|
||||
struct pt {
|
||||
|
@ -24,9 +26,11 @@ int main() {
|
|||
std::vector<pt> shapes;
|
||||
for(int i = 0; i < 100; i++) {
|
||||
pt shape;
|
||||
shape.x = rand() % lcd.bounds.w;
|
||||
shape.y = rand() % lcd.bounds.h;
|
||||
shape.r = (rand() % 10) + 3;
|
||||
shape.x = rand() % (lcd.bounds.w - (shape.r * 2));
|
||||
shape.y = rand() % (lcd.bounds.h - (shape.r * 2));
|
||||
shape.x += shape.r;
|
||||
shape.y += shape.r;
|
||||
shape.dx = float(rand() % 255) / 64.0f;
|
||||
shape.dy = float(rand() % 255) / 64.0f;
|
||||
shape.pen = lcd.create_pen(rand() % 255, rand() % 255, rand() % 255);
|
||||
|
@ -40,15 +44,18 @@ int main() {
|
|||
for(auto &shape : shapes) {
|
||||
shape.x += shape.dx;
|
||||
shape.y += shape.dy;
|
||||
if(shape.x < 0) shape.dx *= -1;
|
||||
if(shape.x >= lcd.bounds.w) shape.dx *= -1;
|
||||
if(shape.y < 0) shape.dy *= -1;
|
||||
if(shape.y >= lcd.bounds.h) shape.dy *= -1;
|
||||
if(shape.x < shape.r) shape.dx *= -1;
|
||||
if(shape.x >= lcd.bounds.w - shape.r) shape.dx *= -1;
|
||||
if(shape.y < shape.r) shape.dy *= -1;
|
||||
if(shape.y >= lcd.bounds.h - shape.r) shape.dy *= -1;
|
||||
|
||||
lcd.set_pen(shape.pen);
|
||||
lcd.circle(Point(shape.x, shape.y), shape.r);
|
||||
}
|
||||
|
||||
lcd.set_pen(255, 255, 255);
|
||||
lcd.text("Hello World", Point(0, 0), 240);
|
||||
|
||||
// update screen
|
||||
lcd.update();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ add_executable(
|
|||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_roundlcd)
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib generic_st7789)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -3,7 +3,7 @@
|
|||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "breakout_roundlcd.hpp"
|
||||
#include "generic_st7789.hpp"
|
||||
#include "time.h"
|
||||
|
||||
// Place a 1.3 Round SPI LCD in the *front* slot of breakout garden.
|
||||
|
@ -11,10 +11,12 @@
|
|||
using namespace pimoroni;
|
||||
|
||||
|
||||
uint16_t buffer[BreakoutRoundLCD::WIDTH * BreakoutRoundLCD::HEIGHT];
|
||||
BreakoutRoundLCD display(buffer, BG_SPI_FRONT);
|
||||
const int WIDTH = 240;
|
||||
const int HEIGHT = 240;
|
||||
|
||||
constexpr float RADIUS = BreakoutRoundLCD::WIDTH / 2;
|
||||
ST7789Generic display(WIDTH, HEIGHT, true, nullptr, BG_SPI_FRONT);
|
||||
|
||||
constexpr float RADIUS = WIDTH / 2;
|
||||
|
||||
Pen from_hsv(float h, float s, float v) {
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
|
@ -39,7 +41,6 @@ Pen from_hsv(float h, float s, float v) {
|
|||
}
|
||||
|
||||
int main() {
|
||||
display.init();
|
||||
display.set_backlight(255);
|
||||
|
||||
uint32_t steps = 70;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
add_executable(
|
||||
display
|
||||
pico_display_demo
|
||||
demo.cpp
|
||||
image_data.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(display pico_stdlib hardware_spi hardware_pwm hardware_dma pico_display)
|
||||
target_link_libraries(pico_display_demo pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled pico_display generic_st7789)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(display)
|
||||
pico_add_extra_outputs(pico_display_demo)
|
|
@ -4,84 +4,25 @@
|
|||
#include <cstdlib>
|
||||
|
||||
#include "pico_display.hpp"
|
||||
#include "generic_st7789.hpp"
|
||||
#include "rgbled.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
extern unsigned char image_tif[];
|
||||
extern unsigned int image_tif_len;
|
||||
const bool ROTATE_180 = false;
|
||||
|
||||
uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
|
||||
PicoDisplay pico_display(buffer);
|
||||
/*
|
||||
void pixel(int x, int y, uint16_t c) {
|
||||
x *= 2;
|
||||
y *= 2;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// Swap WIDTH and HEIGHT to rotate 90 degrees
|
||||
ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, buffer);
|
||||
|
||||
uint8_t arrow[] = {
|
||||
0b00010000,
|
||||
0b00110000,
|
||||
0b01110000,
|
||||
0b11111111,
|
||||
0b11111111,
|
||||
0b01110000,
|
||||
0b00110000,
|
||||
0b00010000
|
||||
};
|
||||
RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B);
|
||||
|
||||
uint8_t tick[] = {
|
||||
0b00000000,
|
||||
0b00000010,
|
||||
0b00000111,
|
||||
0b01001110,
|
||||
0b11111100,
|
||||
0b00111000,
|
||||
0b00010000,
|
||||
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];
|
||||
for(int ax = 0; ax < 8; ax++) {
|
||||
if(flip) {
|
||||
if((0b10000000 >> ax) & sl) {
|
||||
pixel(ax + x, ay + y, c);
|
||||
}
|
||||
}else{
|
||||
if((0b1 << ax) & sl) {
|
||||
pixel(ax + x, ay + y, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
int main() {
|
||||
pico_display.init();
|
||||
pico_display.configure_display(ROTATE_180);
|
||||
pico_display.set_backlight(100);
|
||||
|
||||
// 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);
|
||||
|
||||
struct pt {
|
||||
float x;
|
||||
float y;
|
||||
|
@ -92,7 +33,7 @@ int main() {
|
|||
};
|
||||
|
||||
std::vector<pt> shapes;
|
||||
for(int i = 0; i < 1000; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
pt shape;
|
||||
shape.x = rand() % 240;
|
||||
shape.y = rand() % 135;
|
||||
|
@ -121,8 +62,8 @@ int main() {
|
|||
}
|
||||
|
||||
float led_step = fmod(i / 20.0f, M_PI * 2.0f);
|
||||
int r = (sin(led_step) * 25.0f) + 25.0f;
|
||||
pico_display.set_led(r, r / 1.2f, r);
|
||||
int r = (sin(led_step) * 32.0f) + 32.0f;
|
||||
led.set_rgb(r, r / 1.2f, r);
|
||||
|
||||
|
||||
std::vector<Point> poly;
|
||||
|
@ -134,9 +75,9 @@ int main() {
|
|||
poly.push_back(Point(30, 45));
|
||||
|
||||
pico_display.set_pen(255, 255, 0);
|
||||
//pico_display.pixel(Point(0, 0));
|
||||
pico_display.polygon(poly);
|
||||
|
||||
|
||||
pico_display.set_pen(0, 255, 255);
|
||||
pico_display.triangle(Point(50, 50), Point(130, 80), Point(80, 110));
|
||||
|
||||
|
@ -155,39 +96,10 @@ int main() {
|
|||
pico_display.line(Point(120, 67), Point(cx + 120, cy + 67));
|
||||
}
|
||||
}
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
*/
|
||||
// update screen
|
||||
pico_display.update();
|
||||
|
||||
sleep_ms(1000 / 60);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(OUTPUT_NAME display_2)
|
||||
set(OUTPUT_NAME pico_display2_demo)
|
||||
|
||||
add_executable(
|
||||
${OUTPUT_NAME}
|
||||
|
@ -6,7 +6,7 @@ add_executable(
|
|||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries( ${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma pico_display_2)
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled button pico_display_2 generic_st7789)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs( ${OUTPUT_NAME})
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -4,11 +4,25 @@
|
|||
#include <cstdlib>
|
||||
|
||||
#include "pico_display_2.hpp"
|
||||
#include "generic_st7789.hpp"
|
||||
#include "rgbled.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
const bool ROTATE_180 = false;
|
||||
|
||||
uint16_t buffer[PicoDisplay2::WIDTH * PicoDisplay2::HEIGHT];
|
||||
PicoDisplay2 pico_display(buffer);
|
||||
|
||||
// Swap WIDTH and HEIGHT to rotate 90 degrees
|
||||
ST7789Generic pico_display(PicoDisplay2::WIDTH, PicoDisplay2::HEIGHT, buffer);
|
||||
|
||||
RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B);
|
||||
|
||||
Button button_a(PicoDisplay2::A);
|
||||
Button button_b(PicoDisplay2::B);
|
||||
Button button_x(PicoDisplay2::X);
|
||||
Button button_y(PicoDisplay2::Y);
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
|
@ -31,7 +45,7 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
|||
}
|
||||
|
||||
int main() {
|
||||
pico_display.init();
|
||||
pico_display.configure_display(ROTATE_180);
|
||||
pico_display.set_backlight(255);
|
||||
|
||||
struct pt {
|
||||
|
@ -58,11 +72,11 @@ int main() {
|
|||
Point text_location(0, 0);
|
||||
|
||||
while(true) {
|
||||
if(pico_display.is_pressed(pico_display.A)) text_location.x -= 1;
|
||||
if(pico_display.is_pressed(pico_display.B)) text_location.x += 1;
|
||||
if(button_a.raw()) text_location.x -= 1;
|
||||
if(button_b.raw()) text_location.x += 1;
|
||||
|
||||
if(pico_display.is_pressed(pico_display.X)) text_location.y -= 1;
|
||||
if(pico_display.is_pressed(pico_display.Y)) text_location.y += 1;
|
||||
if(button_x.raw()) text_location.y -= 1;
|
||||
if(button_y.raw()) text_location.y += 1;
|
||||
|
||||
pico_display.set_pen(120, 40, 60);
|
||||
pico_display.clear();
|
||||
|
@ -97,7 +111,7 @@ int main() {
|
|||
// we want a full colour cycle to take. 5000 = 5 sec.
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
from_hsv((float)millis() / 5000.0f, 1.0f, 0.5f + sinf(millis() / 100.0f / 3.14159f) * 0.5f, r, g, b);
|
||||
pico_display.set_led(r, g, b);
|
||||
led.set_rgb(r, g, b);
|
||||
|
||||
|
||||
pico_display.set_pen(255, 255, 255);
|
||||
|
|
|
@ -5,8 +5,6 @@ add_subdirectory(breakout_encoder)
|
|||
add_subdirectory(breakout_ioexpander)
|
||||
add_subdirectory(breakout_ltr559)
|
||||
add_subdirectory(breakout_colourlcd160x80)
|
||||
add_subdirectory(breakout_colourlcd240x240)
|
||||
add_subdirectory(breakout_roundlcd)
|
||||
add_subdirectory(breakout_rgbmatrix5x5)
|
||||
add_subdirectory(breakout_matrix11x7)
|
||||
add_subdirectory(breakout_mics6814)
|
||||
|
@ -19,6 +17,7 @@ add_subdirectory(breakout_sgp30)
|
|||
add_subdirectory(breakout_as7262)
|
||||
add_subdirectory(breakout_msa301)
|
||||
add_subdirectory(breakout_bh1745)
|
||||
add_subdirectory(generic_st7789)
|
||||
add_subdirectory(pico_graphics)
|
||||
add_subdirectory(pico_display)
|
||||
add_subdirectory(pico_display_2)
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
namespace pimoroni {
|
||||
|
||||
BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) {
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf, spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint miso, uint bl)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, spi, cs, dc, sck, mosi, miso, bl) {
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, spi, cs, dc, sck, mosi, bl) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf, BG_SPI_SLOT slot)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, slot) {
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(slot)) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
void BreakoutColourLCD240x240::init() {
|
||||
// initialise the screen
|
||||
screen.init();
|
||||
}
|
||||
|
||||
spi_inst_t* BreakoutColourLCD240x240::get_spi() const {
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace pimoroni {
|
|||
public:
|
||||
BreakoutColourLCD240x240(uint16_t *buf);
|
||||
BreakoutColourLCD240x240(uint16_t *buf, spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint miso = PIN_UNUSED, uint bl = PIN_UNUSED);
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED);
|
||||
BreakoutColourLCD240x240(uint16_t *buf, BG_SPI_SLOT slot);
|
||||
|
||||
|
||||
|
|
|
@ -3,23 +3,24 @@
|
|||
namespace pimoroni {
|
||||
|
||||
BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) {
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint miso, uint bl)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, spi, cs, dc, sck, mosi, miso, bl) {
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf, spi, cs, dc, sck, mosi, bl) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, slot) {
|
||||
BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(slot)) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
void BreakoutRoundLCD::init() {
|
||||
// initialise the screen
|
||||
screen.init(true, true);
|
||||
}
|
||||
|
||||
spi_inst_t* BreakoutRoundLCD::get_spi() const {
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace pimoroni {
|
|||
public:
|
||||
BreakoutRoundLCD(uint16_t *buf);
|
||||
BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint miso = PIN_UNUSED, uint bl = PIN_UNUSED);
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED);
|
||||
BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot);
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(generic_st7789.cmake)
|
|
@ -0,0 +1,106 @@
|
|||
# Genereic ST7789 - Pico Display Pack & Pico Display Pack 2.0" and 240x240 Square & Round LCD Breakouts <!-- omit in toc -->
|
||||
|
||||
Our Pico Display Packs offers a vibrant 1.14" (240x135) or 2.0" (320x240) IPS LCD screen for your Raspberry Pi Pico it also includes four switches and and an RGB LED!
|
||||
|
||||
We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details.
|
||||
|
||||
- [Example Program](#example-program)
|
||||
- [Function Reference](#function-reference)
|
||||
- [PicoGraphics](#picographics)
|
||||
- [set_backlight](#set_backlight)
|
||||
- [update](#update)
|
||||
|
||||
## Example Program
|
||||
|
||||
The following example sets up Pico Display, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed.
|
||||
|
||||
```c++
|
||||
#include "pico_display.hpp"
|
||||
#include "generic_st7789.hpp"
|
||||
#include "rgbled.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
const bool ROTATE_180 = false;
|
||||
|
||||
uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
|
||||
|
||||
// Swap WIDTH and HEIGHT to rotate 90 degrees
|
||||
ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, buffer);
|
||||
|
||||
// RGB LED controller
|
||||
RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B);
|
||||
|
||||
// Buttons
|
||||
Button button_a(PicoDisplay::A);
|
||||
Button button_b(PicoDisplay::B);
|
||||
Button button_x(PicoDisplay::X);
|
||||
Button button_y(PicoDisplay::Y);
|
||||
|
||||
int main() {
|
||||
pico_display.configure_display(ROTATE_180);
|
||||
|
||||
// set the backlight to a value between 0 and 255
|
||||
// the backlight is driven via PWM and is gamma corrected by our
|
||||
// library to give a gorgeous linear brightness range.
|
||||
pico_display.set_backlight(100);
|
||||
|
||||
while(true) {
|
||||
// detect if the A button is pressed (could be A, B, X, or Y)
|
||||
if(button_a.raw()) {
|
||||
// make the led glow green
|
||||
// parameters are red, green, blue all between 0 and 255
|
||||
// these are also gamma corrected
|
||||
led.set_rgb(0, 255, 0);
|
||||
}
|
||||
|
||||
// set the colour of the pen
|
||||
// parameters are red, green, blue all between 0 and 255
|
||||
pico_display.set_pen(30, 40, 50);
|
||||
|
||||
// fill the screen with the current pen colour
|
||||
pico_display.clear();
|
||||
|
||||
// draw a box to put some text in
|
||||
pico_display.set_pen(10, 20, 30);
|
||||
Rect text_rect(10, 10, 150, 150);
|
||||
pico_display.rectangle(text_rect);
|
||||
|
||||
// write some text inside the box with 10 pixels of margin
|
||||
// automatically word wrapping
|
||||
text_rect.deflate(10);
|
||||
pico_display.set_pen(110, 120, 130);
|
||||
pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w);
|
||||
|
||||
// now we've done our drawing let's update the screen
|
||||
pico_display.update();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Function Reference
|
||||
|
||||
### PicoGraphics
|
||||
|
||||
The generic ST7789 driver uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference).
|
||||
|
||||
You will also need to use the RGBLED library to drive the RGB LED, and the Button library for the four buttons.
|
||||
|
||||
### set_backlight
|
||||
|
||||
Set the display backlight from 0-255.
|
||||
|
||||
```c++
|
||||
pico_display.set_backlight(brightness);
|
||||
```
|
||||
|
||||
Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off."
|
||||
|
||||
### update
|
||||
|
||||
To display your changes on Pico Display's screen you need to call `update`:
|
||||
|
||||
```c++
|
||||
pico_display.update();
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
set(LIB_NAME generic_st7789)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics)
|
|
@ -0,0 +1,47 @@
|
|||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "generic_st7789.hpp"
|
||||
|
||||
|
||||
namespace pimoroni {
|
||||
spi_inst_t* ST7789Generic::get_spi() const {
|
||||
return st7789.get_spi();
|
||||
}
|
||||
|
||||
int ST7789Generic::get_cs() const {
|
||||
return st7789.get_cs();
|
||||
}
|
||||
|
||||
int ST7789Generic::get_dc() const {
|
||||
return st7789.get_dc();
|
||||
}
|
||||
|
||||
int ST7789Generic::get_sck() const {
|
||||
return st7789.get_sck();
|
||||
}
|
||||
|
||||
int ST7789Generic::get_mosi() const {
|
||||
return st7789.get_mosi();
|
||||
}
|
||||
|
||||
int ST7789Generic::get_bl() const {
|
||||
return st7789.get_bl();
|
||||
}
|
||||
|
||||
void ST7789Generic::update() {
|
||||
st7789.update();
|
||||
}
|
||||
|
||||
void ST7789Generic::flip() {
|
||||
st7789.configure_display(true);
|
||||
}
|
||||
|
||||
void ST7789Generic::set_backlight(uint8_t brightness) {
|
||||
st7789.set_backlight(brightness);
|
||||
}
|
||||
|
||||
void ST7789Generic::configure_display(bool rotate180) {
|
||||
st7789.configure_display(rotate180);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/st7789/st7789.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class ST7789Generic : public PicoGraphics {
|
||||
private:
|
||||
ST7789 st7789;
|
||||
|
||||
public:
|
||||
ST7789Generic(uint16_t width, uint16_t height, bool round=false, uint16_t *frame_buffer=nullptr) :
|
||||
PicoGraphics(width, height, frame_buffer),
|
||||
st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
this->frame_buffer = st7789.frame_buffer;
|
||||
this->st7789.init();
|
||||
};
|
||||
|
||||
ST7789Generic(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer, BG_SPI_SLOT slot) :
|
||||
PicoGraphics(width, height, frame_buffer),
|
||||
st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) {
|
||||
this->frame_buffer = st7789.frame_buffer;
|
||||
this->st7789.init();
|
||||
};
|
||||
|
||||
ST7789Generic(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer,
|
||||
spi_inst_t *spi,
|
||||
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
|
||||
PicoGraphics(width, height, frame_buffer),
|
||||
st7789(width, height, round, frame_buffer, spi, cs, dc, sck, mosi, bl) {
|
||||
this->frame_buffer = st7789.frame_buffer;
|
||||
this->st7789.init();
|
||||
};
|
||||
|
||||
spi_inst_t* get_spi() const;
|
||||
int get_cs() const;
|
||||
int get_dc() const;
|
||||
int get_sck() const;
|
||||
int get_mosi() const;
|
||||
int get_bl() const;
|
||||
|
||||
void update();
|
||||
[[deprecated("Use configure_display(true) instead.")]] void flip();
|
||||
void set_backlight(uint8_t brightness);
|
||||
void configure_display(bool rotate180);
|
||||
};
|
||||
|
||||
}
|
|
@ -19,49 +19,60 @@ The following example sets up Pico Display, displays some basic demo text and gr
|
|||
|
||||
```c++
|
||||
#include "pico_display.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
#include "generic_st7789.hpp"
|
||||
#include "rgbled.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
|
||||
PicoDisplay pico_display(buffer);
|
||||
|
||||
// Swap WIDTH and HEIGHT to rotate 90 degrees
|
||||
ST7789Generic display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, buffer);
|
||||
|
||||
// Create an RGB LED
|
||||
RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B);
|
||||
|
||||
// And each button
|
||||
Button button_a(PicoDisplay::A);
|
||||
Button button_b(PicoDisplay::B);
|
||||
Button button_x(PicoDisplay::X);
|
||||
Button button_y(PicoDisplay::Y);
|
||||
|
||||
int main() {
|
||||
pico_display.init();
|
||||
|
||||
// set the backlight to a value between 0 and 255
|
||||
// the backlight is driven via PWM and is gamma corrected by our
|
||||
// library to give a gorgeous linear brightness range.
|
||||
pico_display.set_backlight(100);
|
||||
display.set_backlight(100);
|
||||
|
||||
while(true) {
|
||||
// detect if the A button is pressed (could be A, B, X, or Y)
|
||||
if(pico_display.is_pressed(pico_display.A)) {
|
||||
if(button_a.raw(display.A)) {
|
||||
// make the led glow green
|
||||
// parameters are red, green, blue all between 0 and 255
|
||||
// these are also gamma corrected
|
||||
pico_display.set_led(0, 255, 0);
|
||||
led.set_rgb(0, 255, 0);
|
||||
}
|
||||
|
||||
// set the colour of the pen
|
||||
// parameters are red, green, blue all between 0 and 255
|
||||
pico_display.set_pen(30, 40, 50);
|
||||
display.set_pen(30, 40, 50);
|
||||
|
||||
// fill the screen with the current pen colour
|
||||
pico_display.clear();
|
||||
display.clear();
|
||||
|
||||
// draw a box to put some text in
|
||||
pico_display.set_pen(10, 20, 30);
|
||||
display.set_pen(10, 20, 30);
|
||||
Rect text_rect(10, 10, 150, 150);
|
||||
pico_display.rectangle(text_rect);
|
||||
display.rectangle(text_rect);
|
||||
|
||||
// write some text inside the box with 10 pixels of margin
|
||||
// automatically word wrapping
|
||||
text_rect.deflate(10);
|
||||
pico_display.set_pen(110, 120, 130);
|
||||
pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w);
|
||||
display.set_pen(110, 120, 130);
|
||||
display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w);
|
||||
|
||||
// now we've done our drawing let's update the screen
|
||||
pico_display.update();
|
||||
display.update();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -72,52 +83,32 @@ int main() {
|
|||
|
||||
Pico Display uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference).
|
||||
|
||||
### init
|
||||
### configure_display
|
||||
|
||||
Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO:
|
||||
Configures an ST7789 display. Done by default, but you can use this to set 180 degree rotation like so:
|
||||
|
||||
```c++
|
||||
pico_display.init();
|
||||
display.configure_display(true);
|
||||
```
|
||||
|
||||
### flip
|
||||
|
||||
Deprecated: calls `configure_display(true);`
|
||||
|
||||
### set_backlight
|
||||
|
||||
Set the display backlight from 0-255.
|
||||
|
||||
```c++
|
||||
pico_display.set_backlight(brightness);
|
||||
display.set_backlight(brightness);
|
||||
```
|
||||
|
||||
Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off."
|
||||
|
||||
### set_led
|
||||
|
||||
Sets the RGB LED on Pico Display with an RGB triplet:
|
||||
|
||||
```c++
|
||||
pico_display.set_led(r, g, b);
|
||||
```
|
||||
|
||||
Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off."
|
||||
|
||||
### is_pressed
|
||||
|
||||
Reads the GPIO pin connected to one of Pico Display's buttons, returning a `bool` - `true` if it's pressed and `false` if it is released.
|
||||
|
||||
```c++
|
||||
pico_display.is_pressed(button);
|
||||
```
|
||||
|
||||
The button vaule should be a `uint8_t` denoting a pin, and constants `A`, `B`, `X` and `Y` are supplied to make it easier. e:
|
||||
|
||||
```c++
|
||||
bool is_a_button_pressed = pico_display.is_pressed(PicoDisplay::A)
|
||||
```
|
||||
|
||||
### update
|
||||
|
||||
To display your changes on Pico Display's screen you need to call `update`:
|
||||
|
||||
```c++
|
||||
pico_display.update();
|
||||
```
|
||||
display.update();
|
||||
```
|
||||
|
|
|
@ -6,19 +6,17 @@
|
|||
|
||||
#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(uint16_t *buf)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, BG_SPI_FRONT) {
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
PicoDisplay::PicoDisplay(uint16_t *buf, int width, int height)
|
||||
: PicoGraphics(width, height, buf), screen(width, height, buf, BG_SPI_FRONT) {
|
||||
: PicoGraphics(width, height, buf), screen(width, height, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
|
@ -47,9 +45,6 @@ namespace pimoroni {
|
|||
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::update() {
|
||||
|
|
|
@ -11,10 +11,13 @@ namespace pimoroni {
|
|||
static const int HEIGHT = 135;
|
||||
static const int PORTRAIT_WIDTH = 135;
|
||||
static const int PORTRAIT_HEIGHT = 240;
|
||||
static const uint8_t A = 12;
|
||||
static const uint8_t A = 12;
|
||||
static const uint8_t B = 13;
|
||||
static const uint8_t X = 14;
|
||||
static const uint8_t Y = 15;
|
||||
static const uint8_t LED_R = 6;
|
||||
static const uint8_t LED_G = 7;
|
||||
static const uint8_t LED_B = 8;
|
||||
|
||||
uint16_t *__fb;
|
||||
private:
|
||||
|
|
|
@ -6,19 +6,17 @@
|
|||
|
||||
#include "pico_display_2.hpp"
|
||||
|
||||
const uint8_t LED_R = 6;
|
||||
const uint8_t LED_G = 7;
|
||||
const uint8_t LED_B = 8;
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
PicoDisplay2::PicoDisplay2(uint16_t *buf)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, BG_SPI_FRONT) {
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
PicoDisplay2::PicoDisplay2(uint16_t *buf, int width, int height)
|
||||
: PicoGraphics(width, height, buf), screen(width, height, buf, BG_SPI_FRONT) {
|
||||
: PicoGraphics(width, height, buf), screen(width, height, false, buf,
|
||||
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
|
@ -47,9 +45,6 @@ namespace pimoroni {
|
|||
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(true, false);
|
||||
}
|
||||
|
||||
void PicoDisplay2::update() {
|
||||
|
|
|
@ -11,10 +11,13 @@ namespace pimoroni {
|
|||
static const int HEIGHT = 240;
|
||||
static const int PORTRAIT_WIDTH = 240;
|
||||
static const int PORTRAIT_HEIGHT = 320;
|
||||
static const uint8_t A = 12;
|
||||
static const uint8_t A = 12;
|
||||
static const uint8_t B = 13;
|
||||
static const uint8_t X = 14;
|
||||
static const uint8_t Y = 15;
|
||||
static const uint8_t LED_R = 6;
|
||||
static const uint8_t LED_G = 7;
|
||||
static const uint8_t LED_B = 8;
|
||||
|
||||
uint16_t *__fb;
|
||||
private:
|
||||
|
|
|
@ -15,8 +15,9 @@ const uint8_t MOTOR2P = 11;
|
|||
namespace pimoroni {
|
||||
|
||||
PicoExplorer::PicoExplorer(uint16_t *buf)
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, PICO_EXPLORER_ONBOARD) {
|
||||
__fb = buf;
|
||||
: PicoGraphics(WIDTH, HEIGHT, buf),
|
||||
screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(PICO_EXPLORER_ONBOARD), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(PICO_EXPLORER_ONBOARD)) {
|
||||
__fb = buf;
|
||||
}
|
||||
|
||||
void PicoExplorer::init() {
|
||||
|
@ -48,9 +49,6 @@ namespace pimoroni {
|
|||
|
||||
pwm_init(pwm_gpio_to_slice_num(MOTOR2P), &motor_pwm_cfg, true);
|
||||
gpio_set_function(MOTOR2P, GPIO_FUNC_PWM);
|
||||
|
||||
// initialise the screen
|
||||
screen.init();
|
||||
}
|
||||
|
||||
void PicoExplorer::update() {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import time
|
||||
import random
|
||||
from breakout_colourlcd240x240 import BreakoutColourLCD240x240
|
||||
from st7789 import ST7789
|
||||
|
||||
width = BreakoutColourLCD240x240.WIDTH
|
||||
height = BreakoutColourLCD240x240.HEIGHT
|
||||
WIDTH, HEIGHT = 240, 240
|
||||
|
||||
display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565)
|
||||
display = BreakoutColourLCD240x240(display_buffer)
|
||||
display = ST7789(WIDTH, HEIGHT, round=False)
|
||||
|
||||
display.set_backlight(1.0)
|
||||
|
||||
|
@ -27,8 +25,8 @@ for i in range(0, 100):
|
|||
r = random.randint(0, 10) + 3
|
||||
balls.append(
|
||||
Ball(
|
||||
random.randint(r, r + (width - 2 * r)),
|
||||
random.randint(r, r + (height - 2 * r)),
|
||||
random.randint(r, r + (WIDTH - 2 * r)),
|
||||
random.randint(r, r + (HEIGHT - 2 * r)),
|
||||
r,
|
||||
(14 - r) / 2,
|
||||
(14 - r) / 2,
|
||||
|
@ -44,9 +42,9 @@ while True:
|
|||
ball.x += ball.dx
|
||||
ball.y += ball.dy
|
||||
|
||||
xmax = width - ball.r
|
||||
xmax = WIDTH - ball.r
|
||||
xmin = ball.r
|
||||
ymax = height - ball.r
|
||||
ymax = HEIGHT - ball.r
|
||||
ymin = ball.r
|
||||
|
||||
if ball.x < xmin or ball.x > xmax:
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import time
|
||||
import math
|
||||
from breakout_roundlcd import BreakoutRoundLCD
|
||||
from st7789 import ST7789
|
||||
|
||||
width = BreakoutRoundLCD.WIDTH
|
||||
height = BreakoutRoundLCD.HEIGHT
|
||||
WIDTH, HEIGHT = 240, 240
|
||||
|
||||
display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565)
|
||||
display = BreakoutRoundLCD(display_buffer)
|
||||
display = ST7789(WIDTH, HEIGHT, round=True)
|
||||
|
||||
display.set_backlight(1.0)
|
||||
|
||||
RADIUS = width // 2
|
||||
RADIUS = WIDTH // 2
|
||||
|
||||
|
||||
def hsv_to_rgb(h, s, v):
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import picodisplay as display # Comment this line out to use PicoDisplay2
|
||||
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
|
||||
import st7789
|
||||
import qrcode
|
||||
|
||||
# Set the display resolution
|
||||
# in most cases you can swap WIDTH weith HEIGHT for portrait mode
|
||||
WIDTH, HEIGHT = 240, 135 # Pico Display
|
||||
# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0
|
||||
|
||||
display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False)
|
||||
|
||||
|
||||
def measure_qr_code(size, code):
|
||||
w, h = code.get_size()
|
||||
|
@ -20,22 +26,17 @@ def draw_qr_code(ox, oy, size, code):
|
|||
display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size)
|
||||
|
||||
|
||||
width = display.get_width()
|
||||
height = display.get_height()
|
||||
|
||||
code = qrcode.QRCode()
|
||||
code.set_text("shop.pimoroni.com")
|
||||
|
||||
display.init(bytearray(width * height * 2))
|
||||
|
||||
display.set_pen(128, 128, 128)
|
||||
display.clear()
|
||||
display.set_pen(0, 0, 0)
|
||||
|
||||
size, module_size = measure_qr_code(height, code)
|
||||
left = int((width // 2) - (size // 2))
|
||||
top = int((height // 2) - (size // 2))
|
||||
draw_qr_code(left, top, height, code)
|
||||
size, module_size = measure_qr_code(HEIGHT, code)
|
||||
left = int((WIDTH // 2) - (size // 2))
|
||||
top = int((HEIGHT // 2) - (size // 2))
|
||||
draw_qr_code(left, top, HEIGHT, code)
|
||||
|
||||
display.update()
|
||||
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
# This example shows you a simple, non-interrupt way of reading Pico Display's buttons with a loop that checks to see if buttons are pressed.
|
||||
|
||||
import picodisplay as display # Comment this line out to use PicoDisplay2
|
||||
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
|
||||
import st7789
|
||||
import utime
|
||||
from pimoroni import Button
|
||||
|
||||
# Initialise display with a bytearray display buffer
|
||||
buf = bytearray(display.get_width() * display.get_height() * 2)
|
||||
display.init(buf)
|
||||
# Set the display resolution
|
||||
# in most cases you can swap WIDTH weith HEIGHT for portrait mode
|
||||
WIDTH, HEIGHT = 240, 135 # Pico Display
|
||||
# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0
|
||||
|
||||
display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False)
|
||||
display.set_backlight(0.5)
|
||||
|
||||
|
||||
button_a = Button(12)
|
||||
button_b = Button(13)
|
||||
button_x = Button(14)
|
||||
button_y = Button(15)
|
||||
|
||||
|
||||
# sets up a handy function we can call to clear the screen
|
||||
def clear():
|
||||
display.set_pen(0, 0, 0)
|
||||
|
@ -18,28 +27,28 @@ def clear():
|
|||
|
||||
|
||||
while True:
|
||||
if display.is_pressed(display.BUTTON_A): # if a button press is detected then...
|
||||
if button_a.read(): # if a button press is detected then...
|
||||
clear() # clear to black
|
||||
display.set_pen(255, 255, 255) # change the pen colour
|
||||
display.text("Button A pressed", 10, 10, 240, 4) # display some text on the screen
|
||||
display.update() # update the display
|
||||
utime.sleep(1) # pause for a sec
|
||||
clear() # clear to black again
|
||||
elif display.is_pressed(display.BUTTON_B):
|
||||
elif button_b.read():
|
||||
clear()
|
||||
display.set_pen(0, 255, 255)
|
||||
display.text("Button B pressed", 10, 10, 240, 4)
|
||||
display.update()
|
||||
utime.sleep(1)
|
||||
clear()
|
||||
elif display.is_pressed(display.BUTTON_X):
|
||||
elif button_x.read():
|
||||
clear()
|
||||
display.set_pen(255, 0, 255)
|
||||
display.text("Button X pressed", 10, 10, 240, 4)
|
||||
display.update()
|
||||
utime.sleep(1)
|
||||
clear()
|
||||
elif display.is_pressed(display.BUTTON_Y):
|
||||
elif button_y.read():
|
||||
clear()
|
||||
display.set_pen(255, 255, 0)
|
||||
display.text("Button Y pressed", 10, 10, 240, 4)
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import time
|
||||
import random
|
||||
import picodisplay as display # Comment this line out to use PicoDisplay2
|
||||
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
|
||||
import st7789
|
||||
|
||||
width = display.get_width()
|
||||
height = display.get_height()
|
||||
# Set the display resolution, in most cases you can flip these for portrait mode
|
||||
WIDTH, HEIGHT = 240, 135 # Pico Display
|
||||
# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0
|
||||
|
||||
display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565)
|
||||
display.init(display_buffer)
|
||||
display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False)
|
||||
|
||||
display.set_backlight(1.0)
|
||||
|
||||
|
@ -28,8 +27,8 @@ for i in range(0, 100):
|
|||
r = random.randint(0, 10) + 3
|
||||
balls.append(
|
||||
Ball(
|
||||
random.randint(r, r + (width - 2 * r)),
|
||||
random.randint(r, r + (height - 2 * r)),
|
||||
random.randint(r, r + (WIDTH - 2 * r)),
|
||||
random.randint(r, r + (HEIGHT - 2 * r)),
|
||||
r,
|
||||
(14 - r) / 2,
|
||||
(14 - r) / 2,
|
||||
|
@ -45,9 +44,9 @@ while True:
|
|||
ball.x += ball.dx
|
||||
ball.y += ball.dy
|
||||
|
||||
xmax = width - ball.r
|
||||
xmax = WIDTH - ball.r
|
||||
xmin = ball.r
|
||||
ymax = height - ball.r
|
||||
ymax = HEIGHT - ball.r
|
||||
ymin = ball.r
|
||||
|
||||
if ball.x < xmin or ball.x > xmax:
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
# This example borrows a CircuitPython hsv_to_rgb function to cycle through some rainbows on Pico Display's screen and RGB LED . If you're into rainbows, HSV (Hue, Saturation, Value) is very useful!
|
||||
|
||||
import utime
|
||||
import picodisplay as display # Comment this line out to use PicoDisplay2
|
||||
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
|
||||
import st7789
|
||||
from pimoroni import RGBLED
|
||||
|
||||
# Set up and initialise Pico Display
|
||||
buf = bytearray(display.get_width() * display.get_height() * 2)
|
||||
display.init(buf)
|
||||
# Set the display resolution
|
||||
# in most cases you can swap WIDTH weith HEIGHT for portrait mode
|
||||
WIDTH, HEIGHT = 240, 135 # Pico Display
|
||||
# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0
|
||||
|
||||
display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False)
|
||||
display.set_backlight(0.8)
|
||||
|
||||
led = RGBLED(6, 7, 8)
|
||||
|
||||
|
||||
# From CPython Lib/colorsys.py
|
||||
def hsv_to_rgb(h, s, v):
|
||||
|
@ -39,7 +44,7 @@ h = 0
|
|||
while True:
|
||||
h += 1
|
||||
r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic
|
||||
display.set_led(r, g, b) # Set LED to a converted HSV value
|
||||
led.set_rgb(r, g, b) # Set LED to a converted HSV value
|
||||
display.set_pen(r, g, b) # Set pen to a converted HSV value
|
||||
display.clear() # Fill the screen with the colour
|
||||
display.set_pen(0, 0, 0) # Set pen to black
|
||||
|
|
|
@ -3,17 +3,21 @@
|
|||
|
||||
import machine
|
||||
import utime
|
||||
import gc
|
||||
|
||||
# Pico Display boilerplate
|
||||
import picodisplay as display # Comment this line out to use PicoDisplay2
|
||||
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
|
||||
import st7789
|
||||
from pimoroni import RGBLED
|
||||
|
||||
width = display.get_width()
|
||||
height = display.get_height()
|
||||
gc.collect()
|
||||
display_buffer = bytearray(width * height * 2)
|
||||
display.init(display_buffer)
|
||||
# Set the display resolution
|
||||
# in most cases you can swap WIDTH weith HEIGHT for portrait mode
|
||||
WIDTH, HEIGHT = 135, 240 # Pico Display
|
||||
# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0
|
||||
|
||||
display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False)
|
||||
|
||||
# Set the display backlight to 50%
|
||||
display.set_backlight(0.5)
|
||||
|
||||
led = RGBLED(6, 7, 8)
|
||||
|
||||
# reads from Pico's temp sensor and converts it into a more manageable number
|
||||
sensor_temp = machine.ADC(4)
|
||||
|
@ -22,9 +26,6 @@ temp_min = 10
|
|||
temp_max = 30
|
||||
bar_width = 5
|
||||
|
||||
# Set the display backlight to 50%
|
||||
display.set_backlight(0.5)
|
||||
|
||||
temperatures = []
|
||||
|
||||
colors = [(0, 0, 255), (0, 255, 0), (255, 255, 0), (255, 0, 0)]
|
||||
|
@ -62,7 +63,7 @@ while True:
|
|||
temperatures.append(temperature)
|
||||
|
||||
# shifts the temperatures history to the left by one sample
|
||||
if len(temperatures) > width // bar_width:
|
||||
if len(temperatures) > WIDTH // bar_width:
|
||||
temperatures.pop(0)
|
||||
|
||||
i = 0
|
||||
|
@ -71,14 +72,14 @@ while True:
|
|||
display.set_pen(*temperature_to_color(t))
|
||||
|
||||
# draws the reading as a tall, thin rectangle
|
||||
display.rectangle(i, height - (round(t) * 4), bar_width, height)
|
||||
display.rectangle(i, HEIGHT - (round(t) * 4), bar_width, HEIGHT)
|
||||
|
||||
# the next tall thin rectangle needs to be drawn
|
||||
# "bar_width" (default: 5) pixels to the right of the last one
|
||||
i += bar_width
|
||||
|
||||
# heck lets also set the LED to match
|
||||
display.set_led(*temperature_to_color(temperature))
|
||||
led.set_rgb(*temperature_to_color(temperature))
|
||||
|
||||
# draws a white background for the text
|
||||
display.set_pen(255, 255, 255)
|
||||
|
|
|
@ -120,7 +120,7 @@ mp_obj_t BreakoutColourLCD240x240_make_new(const mp_obj_type_t *type, size_t n_a
|
|||
|
||||
spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1;
|
||||
self->breakout = new BreakoutColourLCD240x240((uint16_t *)bufinfo.buf, spi,
|
||||
args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, PIN_UNUSED, args[ARG_bl].u_int);
|
||||
args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, args[ARG_bl].u_int);
|
||||
}
|
||||
|
||||
self->breakout->init();
|
||||
|
|
|
@ -120,7 +120,7 @@ mp_obj_t BreakoutRoundLCD_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
|||
|
||||
spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1;
|
||||
self->breakout = new BreakoutRoundLCD((uint16_t *)bufinfo.buf, spi,
|
||||
args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, PIN_UNUSED, args[ARG_bl].u_int);
|
||||
args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, args[ARG_bl].u_int);
|
||||
}
|
||||
|
||||
self->breakout->init();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
add_library(usermod_hub75 INTERFACE)
|
||||
|
||||
target_sources(usermod_pico_display INTERFACE
|
||||
target_sources(usermod_hub75 INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/hub75.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/hub75.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/hub75/hub75.cpp
|
||||
|
|
|
@ -12,7 +12,6 @@ include(breakout_ioexpander/micropython)
|
|||
include(breakout_ltr559/micropython)
|
||||
include(breakout_colourlcd160x80/micropython)
|
||||
include(breakout_as7262/micropython)
|
||||
include(breakout_roundlcd/micropython)
|
||||
include(breakout_rgbmatrix5x5/micropython)
|
||||
include(breakout_matrix11x7/micropython)
|
||||
include(breakout_msa301/micropython)
|
||||
|
@ -22,7 +21,6 @@ include(breakout_potentiometer/micropython)
|
|||
include(breakout_rtc/micropython)
|
||||
include(breakout_trackball/micropython)
|
||||
include(breakout_sgp30/micropython)
|
||||
include(breakout_colourlcd240x240/micropython)
|
||||
include(breakout_bh1745/micropython)
|
||||
include(breakout_bme68x/micropython)
|
||||
include(breakout_bme280/micropython)
|
||||
|
@ -34,8 +32,6 @@ include(breakout_vl53l5cx/micropython)
|
|||
include(pico_scroll/micropython)
|
||||
include(pico_rgb_keypad/micropython)
|
||||
include(pico_unicorn/micropython)
|
||||
include(pico_display/micropython)
|
||||
include(pico_display_2/micropython)
|
||||
include(pico_explorer/micropython)
|
||||
include(pico_wireless/micropython)
|
||||
|
||||
|
@ -50,4 +46,6 @@ include(motor/micropython)
|
|||
include(ulab/code/micropython)
|
||||
include(qrcode/micropython/micropython)
|
||||
|
||||
include(st7789/micropython)
|
||||
|
||||
include(modules_py/modules_py)
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
#include "pico_display.h"
|
||||
|
||||
/***** Constants *****/
|
||||
enum buttons
|
||||
{
|
||||
BUTTON_A = 0,
|
||||
BUTTON_B,
|
||||
BUTTON_X,
|
||||
BUTTON_Y,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// picodisplay Module
|
||||
|
@ -61,10 +52,13 @@ STATIC const mp_map_elem_t picodisplay_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay_circle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay_character_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay_text_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(14) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(15) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_INT(6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_INT(7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_INT(8) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_picodisplay_globals, picodisplay_globals_table);
|
||||
|
||||
|
|
|
@ -96,36 +96,11 @@ mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) {
|
|||
}
|
||||
|
||||
mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj) {
|
||||
bool buttonPressed = false;
|
||||
|
||||
if(display != nullptr) {
|
||||
int buttonID = mp_obj_get_int(button_obj);
|
||||
switch(buttonID) {
|
||||
case 0:
|
||||
buttonPressed = display->is_pressed(PicoDisplay::A);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buttonPressed = display->is_pressed(PicoDisplay::B);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buttonPressed = display->is_pressed(PicoDisplay::X);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
buttonPressed = display->is_pressed(PicoDisplay::Y);
|
||||
break;
|
||||
|
||||
default:
|
||||
mp_raise_ValueError("button not valid. Expected 0 to 3");
|
||||
break;
|
||||
}
|
||||
return display->is_pressed(mp_obj_get_int(button_obj)) ? mp_const_true : mp_const_false;
|
||||
}
|
||||
else
|
||||
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
|
||||
|
||||
return buttonPressed ? mp_const_true : mp_const_false;
|
||||
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
#include "pico_display_2.h"
|
||||
|
||||
/***** Constants *****/
|
||||
enum buttons
|
||||
{
|
||||
BUTTON_A = 0,
|
||||
BUTTON_B,
|
||||
BUTTON_X,
|
||||
BUTTON_Y,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// picodisplay2 Module
|
||||
|
@ -61,10 +52,13 @@ STATIC const mp_map_elem_t picodisplay2_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay2_circle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay2_character_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay2_text_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(14) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(15) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_INT(6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_INT(7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_INT(8) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_picodisplay2_globals, picodisplay2_globals_table);
|
||||
|
||||
|
|
|
@ -96,36 +96,11 @@ mp_obj_t picodisplay2_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) {
|
|||
}
|
||||
|
||||
mp_obj_t picodisplay2_is_pressed(mp_obj_t button_obj) {
|
||||
bool buttonPressed = false;
|
||||
|
||||
if(display2 != nullptr) {
|
||||
int buttonID = mp_obj_get_int(button_obj);
|
||||
switch(buttonID) {
|
||||
case 0:
|
||||
buttonPressed = display2->is_pressed(PicoDisplay2::A);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buttonPressed = display2->is_pressed(PicoDisplay2::B);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buttonPressed = display2->is_pressed(PicoDisplay2::X);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
buttonPressed = display2->is_pressed(PicoDisplay2::Y);
|
||||
break;
|
||||
|
||||
default:
|
||||
mp_raise_ValueError("button not valid. Expected 0 to 3");
|
||||
break;
|
||||
}
|
||||
return display2->is_pressed(mp_obj_get_int(button_obj)) ? mp_const_true : mp_const_false;
|
||||
}
|
||||
else
|
||||
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
|
||||
|
||||
return buttonPressed ? mp_const_true : mp_const_false;
|
||||
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t picodisplay2_set_pen(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
set(MOD_NAME st7789)
|
||||
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
|
||||
add_library(usermod_${MOD_NAME} INTERFACE)
|
||||
|
||||
target_sources(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/generic_st7789/generic_st7789.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp
|
||||
)
|
||||
|
||||
target_include_directories(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
|
||||
-DMODULE_${MOD_NAME_UPPER}_ENABLED=1
|
||||
)
|
||||
|
||||
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
|
|
@ -0,0 +1,62 @@
|
|||
#include "st7789.h"
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_update_obj, GenericST7789_update);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_backlight_obj, 1, GenericST7789_set_backlight);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_pen_obj, 1, GenericST7789_set_pen);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 1, GenericST7789_create_pen);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_clip_obj, 1, GenericST7789_set_clip);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_remove_clip_obj, GenericST7789_remove_clip);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_clear_obj, GenericST7789_clear);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_pixel_obj, 1, GenericST7789_pixel);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_pixel_span_obj, 1, GenericST7789_pixel_span);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_rectangle_obj, 1, GenericST7789_rectangle);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_circle_obj, 1, GenericST7789_circle);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_character_obj, 1, GenericST7789_character);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_text_obj, 1, GenericST7789_text);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_polygon_obj, 2, GenericST7789_polygon);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_triangle_obj, 1, GenericST7789_triangle);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line);
|
||||
|
||||
STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&GenericST7789_set_clip_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&GenericST7789_remove_clip_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&GenericST7789_clear_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&GenericST7789_pixel_span_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&GenericST7789_rectangle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&GenericST7789_circle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&GenericST7789_character_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&GenericST7789_text_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&GenericST7789_polygon_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict_table);
|
||||
|
||||
/***** Class Definition *****/
|
||||
const mp_obj_type_t GenericST7789_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_st7789,
|
||||
.print = GenericST7789_print,
|
||||
.make_new = GenericST7789_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict,
|
||||
};
|
||||
|
||||
/***** Module Globals *****/
|
||||
STATIC const mp_map_elem_t st7789_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table);
|
||||
|
||||
/***** Module Definition *****/
|
||||
const mp_obj_module_t st7789_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_st7789_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_st7789, st7789_user_cmodule, MODULE_ST7789_ENABLED);
|
|
@ -0,0 +1,559 @@
|
|||
#include "libraries/generic_st7789/generic_st7789.hpp"
|
||||
|
||||
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
|
||||
|
||||
#define IS_VALID_PERIPH(spi, pin) ((((pin) & 8) >> 3) == (spi))
|
||||
#define IS_VALID_SCK(spi, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(spi, pin))
|
||||
#define IS_VALID_MOSI(spi, pin) (((pin) & 3) == 3 && IS_VALID_PERIPH(spi, pin))
|
||||
#define IS_VALID_MISO(spi, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(spi, pin))
|
||||
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
extern "C" {
|
||||
#include "st7789.h"
|
||||
|
||||
/***** Variables Struct *****/
|
||||
typedef struct _GenericST7789_obj_t {
|
||||
mp_obj_base_t base;
|
||||
ST7789Generic *st7789;
|
||||
uint16_t *buffer;
|
||||
} GenericST7789_obj_t;
|
||||
|
||||
/***** Print *****/
|
||||
void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind; //Unused input parameter
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
|
||||
|
||||
mp_print_str(print, "ST7789(");
|
||||
|
||||
mp_print_str(print, "spi = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int((self->st7789->get_spi() == spi0) ? 0 : 1), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", cs = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_cs()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", dc = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_dc()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", sck = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_sck()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", mosi = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_mosi()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", bl = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_bl()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ")");
|
||||
}
|
||||
|
||||
/***** Constructor *****/
|
||||
mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
GenericST7789_obj_t *self = nullptr;
|
||||
|
||||
enum { ARG_width, ARG_height, ARG_round, ARG_rotate180, ARG_slot, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_round, MP_ARG_OBJ, {.u_obj = mp_const_false} },
|
||||
{ MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} },
|
||||
{ MP_QSTR_slot, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_cs, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_CS} },
|
||||
{ MP_QSTR_dc, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MISO} },
|
||||
{ MP_QSTR_sck, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_SCK} },
|
||||
{ MP_QSTR_mosi, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MOSI} },
|
||||
{ MP_QSTR_bl, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_PWM} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
self = m_new_obj(GenericST7789_obj_t);
|
||||
self->base.type = &GenericST7789_type;
|
||||
|
||||
bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true;
|
||||
bool round = args[ARG_round].u_obj == mp_const_true;
|
||||
int width = args[ARG_width].u_int;
|
||||
int height = args[ARG_height].u_int;
|
||||
|
||||
if (args[ARG_buffer].u_obj != mp_const_none) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
|
||||
self->buffer = (uint16_t *)bufinfo.buf;
|
||||
if(bufinfo.len < (size_t)(width * height * 2)) {
|
||||
mp_raise_ValueError("Supplied buffer is too small!");
|
||||
}
|
||||
} else {
|
||||
self->buffer = m_new(uint16_t, width * height);
|
||||
}
|
||||
|
||||
if(args[ARG_slot].u_int != -1) {
|
||||
BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int;
|
||||
self->st7789 = new ST7789Generic(width, height, round, self->buffer, slot);
|
||||
if (rotate180) {
|
||||
self->st7789->configure_display(true);
|
||||
}
|
||||
} else {
|
||||
// Get SPI bus.
|
||||
int spi_id = args[ARG_spi].u_int;
|
||||
int sck = args[ARG_sck].u_int;
|
||||
int mosi = args[ARG_mosi].u_int;
|
||||
int dc = args[ARG_dc].u_int;
|
||||
int cs = args[ARG_cs].u_int;
|
||||
int bl = args[ARG_bl].u_int;
|
||||
|
||||
if(spi_id == -1) {
|
||||
spi_id = (sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin
|
||||
}
|
||||
if(spi_id < 0 || spi_id > 1) {
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
|
||||
}
|
||||
|
||||
if(!IS_VALID_SCK(spi_id, sck)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin"));
|
||||
}
|
||||
|
||||
if(!IS_VALID_MOSI(spi_id, mosi)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin"));
|
||||
}
|
||||
spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1;
|
||||
self->st7789 = new ST7789Generic(width, height, round, self->buffer,
|
||||
spi, cs, dc, sck, mosi, bl);
|
||||
if (rotate180) {
|
||||
self->st7789->configure_display(true);
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
mp_obj_t GenericST7789_update(mp_obj_t self_in) {
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
|
||||
self->st7789->update();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_brightness };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
float brightness = mp_obj_get_float(args[ARG_brightness].u_obj);
|
||||
|
||||
if(brightness < 0 || brightness > 1.0f)
|
||||
mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0");
|
||||
else
|
||||
self->st7789->set_backlight((uint8_t)(brightness * 255.0f));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
|
||||
if(n_args <= 2) {
|
||||
enum { ARG_self, ARG_pen };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int pen = args[ARG_pen].u_int;
|
||||
|
||||
if(pen < 0 || pen > 0xffff)
|
||||
mp_raise_ValueError("p is not a valid pen.");
|
||||
else
|
||||
self->st7789->set_pen(pen);
|
||||
}
|
||||
else {
|
||||
enum { ARG_self, ARG_r, ARG_g, ARG_b };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int r = args[ARG_r].u_int;
|
||||
int g = args[ARG_g].u_int;
|
||||
int b = args[ARG_b].u_int;
|
||||
|
||||
if(r < 0 || r > 255)
|
||||
mp_raise_ValueError("r out of range. Expected 0 to 255");
|
||||
else if(g < 0 || g > 255)
|
||||
mp_raise_ValueError("g out of range. Expected 0 to 255");
|
||||
else if(b < 0 || b > 255)
|
||||
mp_raise_ValueError("b out of range. Expected 0 to 255");
|
||||
else
|
||||
self->st7789->set_pen(r, g, b);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
int pen = 0;
|
||||
|
||||
enum { ARG_self, ARG_r, ARG_g, ARG_b };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int r = args[ARG_r].u_int;
|
||||
int g = args[ARG_g].u_int;
|
||||
int b = args[ARG_b].u_int;
|
||||
|
||||
if(r < 0 || r > 255)
|
||||
mp_raise_ValueError("r out of range. Expected 0 to 255");
|
||||
else if(g < 0 || g > 255)
|
||||
mp_raise_ValueError("g out of range. Expected 0 to 255");
|
||||
else if(b < 0 || b > 255)
|
||||
mp_raise_ValueError("b out of range. Expected 0 to 255");
|
||||
else
|
||||
pen = self->st7789->create_pen(r, g, b);
|
||||
|
||||
return mp_obj_new_int(pen);
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int w = args[ARG_w].u_int;
|
||||
int h = args[ARG_h].u_int;
|
||||
|
||||
Rect r(x, y, w, h);
|
||||
self->st7789->set_clip(r);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in) {
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
|
||||
self->st7789->remove_clip();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_clear(mp_obj_t self_in) {
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
|
||||
self->st7789->clear();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
|
||||
Point p(x, y);
|
||||
self->st7789->pixel(p);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_l };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int l = args[ARG_l].u_int;
|
||||
|
||||
Point p(x, y);
|
||||
self->st7789->pixel_span(p, l);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int w = args[ARG_w].u_int;
|
||||
int h = args[ARG_h].u_int;
|
||||
|
||||
Rect r(x, y, w, h);
|
||||
self->st7789->rectangle(r);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_r };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int r = args[ARG_r].u_int;
|
||||
|
||||
Point p(x, y);
|
||||
self->st7789->circle(p, r);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int c = mp_obj_get_int(args[ARG_char].u_obj);
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int scale = args[ARG_scale].u_int;
|
||||
|
||||
self->st7789->character((char)c, Point(x, y), scale);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
mp_obj_t text_obj = args[ARG_text].u_obj;
|
||||
if(mp_obj_is_str_or_bytes(text_obj)) {
|
||||
GET_STR_DATA_LEN(text_obj, str, str_len);
|
||||
|
||||
std::string t((const char*)str);
|
||||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int wrap = args[ARG_wrap].u_int;
|
||||
int scale = args[ARG_scale].u_int;
|
||||
|
||||
self->st7789->text(t, Point(x, y), wrap, scale);
|
||||
}
|
||||
else if(mp_obj_is_float(text_obj)) {
|
||||
mp_raise_TypeError("can't convert 'float' object to str implicitly");
|
||||
}
|
||||
else if(mp_obj_is_int(text_obj)) {
|
||||
mp_raise_TypeError("can't convert 'int' object to str implicitly");
|
||||
}
|
||||
else if(mp_obj_is_bool(text_obj)) {
|
||||
mp_raise_TypeError("can't convert 'bool' object to str implicitly");
|
||||
}
|
||||
else {
|
||||
mp_raise_TypeError("can't convert object to str implicitly");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
size_t num_tuples = n_args - 1;
|
||||
const mp_obj_t *tuples = pos_args + 1;
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], GenericST7789_obj_t);
|
||||
|
||||
// Check if there is only one argument, which might be a list
|
||||
if(n_args == 2) {
|
||||
if(mp_obj_is_type(pos_args[1], &mp_type_list)) {
|
||||
mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t);
|
||||
if(points->len > 0) {
|
||||
num_tuples = points->len;
|
||||
tuples = points->items;
|
||||
}
|
||||
else {
|
||||
mp_raise_ValueError("poly(): cannot provide an empty list");
|
||||
}
|
||||
}
|
||||
else {
|
||||
mp_raise_TypeError("poly(): can't convert object to list");
|
||||
}
|
||||
}
|
||||
|
||||
if(num_tuples > 0) {
|
||||
std::vector<Point> points;
|
||||
for(size_t i = 0; i < num_tuples; i++) {
|
||||
mp_obj_t obj = tuples[i];
|
||||
if(!mp_obj_is_type(obj, &mp_type_tuple)) {
|
||||
mp_raise_ValueError("poly(): can't convert object to tuple");
|
||||
}
|
||||
else {
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t);
|
||||
if(tuple->len != 2) {
|
||||
mp_raise_ValueError("poly(): tuple must only contain two numbers");
|
||||
}
|
||||
points.push_back(Point(
|
||||
mp_obj_get_int(tuple->items[0]),
|
||||
mp_obj_get_int(tuple->items[1]))
|
||||
);
|
||||
}
|
||||
}
|
||||
self->st7789->polygon(points);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x1 = args[ARG_x1].u_int;
|
||||
int y1 = args[ARG_y1].u_int;
|
||||
int x2 = args[ARG_x1].u_int;
|
||||
int y2 = args[ARG_y1].u_int;
|
||||
int x3 = args[ARG_x1].u_int;
|
||||
int y3 = args[ARG_y1].u_int;
|
||||
|
||||
Point p1(x1, y1);
|
||||
Point p2(x2, y2);
|
||||
Point p3(x3, y3);
|
||||
self->st7789->triangle(p1, p2, p3);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
|
||||
|
||||
int x1 = args[ARG_x1].u_int;
|
||||
int y1 = args[ARG_y1].u_int;
|
||||
int x2 = args[ARG_x1].u_int;
|
||||
int y2 = args[ARG_y1].u_int;
|
||||
|
||||
Point p1(x1, y1);
|
||||
Point p2(x2, y2);
|
||||
self->st7789->line(p1, p2);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
#include "py/objstr.h"
|
||||
|
||||
/***** Extern of Class Definition *****/
|
||||
extern const mp_obj_type_t GenericST7789_type;
|
||||
|
||||
/***** Extern of Class Methods *****/
|
||||
extern void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||
extern mp_obj_t GenericST7789_update(mp_obj_t self_in);
|
||||
extern mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
|
||||
extern mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in);
|
||||
extern mp_obj_t GenericST7789_clear(mp_obj_t self_in);
|
||||
extern mp_obj_t GenericST7789_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
|
@ -10,6 +10,10 @@ HEADER_I2C_PINS = {"sda": 20, "scl": 21}
|
|||
NORMAL_DIR = 0x00
|
||||
REVERSED_DIR = 0x01
|
||||
|
||||
BREAKOUT_GARDEN_SPI_SLOT_FRONT = 0
|
||||
BREAKOUT_GARDEN_SPI_SLOT_BACK = 1
|
||||
PICO_EXPLORER_SPI_ONBOARD = 2
|
||||
|
||||
|
||||
class Analog:
|
||||
def __init__(self, pin, amplifier_gain=1, resistor=0, offset=0):
|
||||
|
|
Loading…
Reference in New Issue