ST7789/PicoGraphics: Refactor for init & rotation.

This commit is contained in:
Phil Howard 2022-05-28 01:00:56 +01:00
parent ef6179e77d
commit a483b2aad4
16 changed files with 324 additions and 262 deletions

11
common/pimoroni_bus.cmake Normal file
View File

@ -0,0 +1,11 @@
set(LIB_NAME pimoroni_bus)
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)

15
common/pimoroni_bus.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "pimoroni_bus.hpp"
namespace pimoroni {
SPIPins get_spi_pins(BG_SPI_SLOT slot) {
switch(slot) {
case PICO_EXPLORER_ONBOARD:
return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, PIN_UNUSED};
case BG_SPI_FRONT:
return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM};
case BG_SPI_BACK:
return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_BACK_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_BACK_PWM};
}
return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM};
};
}

26
common/pimoroni_bus.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "pimoroni_common.hpp"
#include "hardware/gpio.h"
#include "hardware/spi.h"
namespace pimoroni {
struct SPIPins {
spi_inst_t *spi;
uint cs;
uint sck;
uint mosi;
uint miso;
uint bl;
};
struct ParallelPins {
uint cs;
uint dc;
uint wr_sck;
uint rd_sck;
uint d0;
uint bl;
};
SPIPins get_spi_pins(BG_SPI_SLOT slot);
}

View File

@ -53,6 +53,13 @@ namespace pimoroni {
INTERSTATE_75,
SERVO_2040
};
enum Rotation {
ROTATE_0 = 0,
ROTATE_90 = 90,
ROTATE_180 = 180,
ROTATE_270 = 270
};
enum Polarity {
ACTIVE_LOW = 0,

View File

@ -9,4 +9,4 @@ target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma)
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma)

View File

@ -70,8 +70,7 @@ namespace pimoroni {
command(reg::GMCTRN1, 14, "\xD0\x04\x0C\x11\x13\x2C\x3F\x44\x51\x2F\x1F\x1F\x20\x23");
}
if((width == 320 && height == 240)
|| (width == 240 && height == 320)) {
if(width == 320 && height == 240) {
command(reg::GCTRL, 1, "\x35");
command(reg::VCOMS, 1, "\x1f");
command(0xd6, 1, "\xa1"); // ???
@ -85,7 +84,7 @@ namespace pimoroni {
sleep_ms(100);
configure_display(false);
configure_display(rotation);
if(bl != PIN_UNUSED) {
//update(); // Send the new buffer to the display to clear any previous content
@ -94,9 +93,15 @@ namespace pimoroni {
}
}
void ST7789::configure_display(bool rotate180) {
void ST7789::configure_display(Rotation rotate) {
bool rotate180 = rotate == ROTATE_180 || rotate == ROTATE_90;
if(rotate == ROTATE_90 || rotate == ROTATE_270) {
std::swap(width, height);
}
// 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;
@ -108,6 +113,7 @@ namespace pimoroni {
raset[1] = rotate180 ? 329 : 239;
}
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
if (rotate == ROTATE_90) madctl |= MADCTL::SWAP_XY;
madctl |= MADCTL::HORIZ_ORDER;
}
@ -160,30 +166,6 @@ namespace pimoroni {
command(reg::MADCTL, 1, (char *)&madctl);
}
spi_inst_t* ST7789::get_spi() const {
return spi;
}
uint ST7789::get_cs() const {
return cs;
}
uint ST7789::get_dc() const {
return dc;
}
uint ST7789::get_sck() const {
return wr_sck;
}
uint ST7789::get_mosi() const {
return d0;
}
uint ST7789::get_bl() const {
return bl;
}
void ST7789::write_blocking_parallel(const uint8_t *src, size_t len) {
uint32_t mask = 0xff << d0;
while(len--) {
@ -226,10 +208,21 @@ namespace pimoroni {
// 8-bit framebuffer with palette conversion update
void ST7789::update(uint16_t *palette) {
command(reg::RAMWR);
uint8_t command = reg::RAMWR;
uint16_t row[width];
gpio_put(dc, 1); // data mode
gpio_put(dc, 0); // command mode
gpio_put(cs, 0);
if(spi) {
spi_write_blocking(spi, &command, 1);
} else {
write_blocking_parallel(&command, 1);
}
gpio_put(dc, 1); // data mode
for(auto y = 0u; y < height; y++) {
for(auto x = 0u; x < width; x++) {
auto i = y * width + x;
@ -242,6 +235,7 @@ namespace pimoroni {
write_blocking_parallel((const uint8_t*)row, width * sizeof(uint16_t));
}
}
gpio_put(cs, 1);
}
@ -252,8 +246,4 @@ namespace pimoroni {
uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f);
pwm_set_gpio_level(bl, value);
}
void ST7789::flip(){
configure_display(true);
}
}

View File

@ -3,22 +3,28 @@
#include "hardware/spi.h"
#include "hardware/gpio.h"
#include "hardware/pwm.h"
#include "../../common/pimoroni_common.hpp"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_bus.hpp"
#include <algorithm>
namespace pimoroni {
class ST7789 {
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
public:
// screen properties
uint16_t width;
uint16_t height;
Rotation rotation;
bool round;
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
// screen properties
uint16_t width;
uint16_t height;
bool round;
// interface pins with our standard defaults where appropriate
uint cs;
@ -35,22 +41,16 @@ namespace pimoroni {
public:
// frame buffer where pixel data is stored
void *frame_buffer;
// Parallel init
ST7789(uint16_t width, uint16_t height, void *frame_buffer,
uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) :
ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) :
spi(nullptr),
width(width), height(height), round(false),
cs(cs), dc(dc), wr_sck(wr_sck), rd_sck(rd_sck), d0(d0), bl(bl), frame_buffer(frame_buffer) {
width(width), height(height), rotation(rotation), round(false),
cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) {
gpio_set_function(cs, GPIO_FUNC_SIO);
gpio_set_dir(cs, GPIO_OUT);
gpio_set_function(dc, GPIO_FUNC_SIO);
gpio_set_dir(dc, GPIO_OUT);
gpio_set_function(wr_sck, GPIO_FUNC_SIO);
gpio_set_dir(wr_sck, GPIO_OUT);
@ -68,22 +68,14 @@ namespace pimoroni {
}
// Serial init
ST7789(uint16_t width, uint16_t height, bool round, void *frame_buffer,
spi_inst_t *spi,
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
spi(spi),
width(width), height(height), round(round),
cs(cs), dc(dc), wr_sck(sck), d0(mosi), bl(bl), frame_buffer(frame_buffer) {
ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) :
spi(pins.spi),
width(width), height(height), rotation(rotation), round(round),
cs(pins.cs), dc(pins.miso), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) {
// 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(wr_sck, GPIO_FUNC_SPI);
gpio_set_function(d0, GPIO_FUNC_SPI);
@ -91,52 +83,26 @@ namespace pimoroni {
}
void init();
void configure_display(bool rotate180);
spi_inst_t* get_spi() const;
uint get_cs() const;
uint get_dc() const;
uint get_sck() const;
uint get_mosi() const;
uint get_bl() const;
void command(uint8_t command, size_t len = 0, const char *data = NULL);
void set_backlight(uint8_t brightness);
void update();
void update(uint16_t *palette);
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;
};
private:
void configure_display(Rotation rotate);
void write_blocking_parallel(const uint8_t *src, size_t len);
void common_init() {
if(!this->frame_buffer) {
this->frame_buffer = new uint8_t[width * height];
}
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);
// if a backlight pin is provided then set it up for
// pwm control
if(bl != PIN_UNUSED) {

View File

@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
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)
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma pimoroni_bus st7789 pico_graphics)

View File

@ -5,43 +5,11 @@
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(palette);
}
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);
}
}

View File

@ -2,6 +2,7 @@
#include "drivers/st7789/st7789.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "common/pimoroni_bus.hpp"
namespace pimoroni {
@ -10,50 +11,32 @@ namespace pimoroni {
ST7789 st7789;
public:
ST7789Generic(uint16_t width, uint16_t height, bool round=false, void *frame_buffer=nullptr) :
ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *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 = (Pen *)st7789.frame_buffer;
this->st7789.init();
this->st7789.update(palette);
st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) {
common_init();
};
ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, BG_SPI_SLOT slot) :
ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) :
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 = (Pen *)st7789.frame_buffer;
this->st7789.init();
this->st7789.update(palette);
st7789(width, height, rotation, round, frame_buffer, bus_pins) {
common_init();
};
ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer,
spi_inst_t *spi,
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) :
PicoGraphics(width, height, frame_buffer),
st7789(width, height, round, frame_buffer, spi, cs, dc, sck, mosi, bl) {
this->frame_buffer = (Pen *)st7789.frame_buffer;
this->st7789.init();
this->st7789.update(palette);
st7789(width, height, rotation, frame_buffer, bus_pins) {
common_init();
};
ST7789Generic(uint16_t width, uint16_t height, void *frame_buffer,
uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) :
PicoGraphics(width, height, frame_buffer),
st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) {
this->frame_buffer = (Pen *)st7789.frame_buffer;
this->st7789.init();
this->st7789.update(palette);
};
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 common_init() {
this->frame_buffer = (Pen *)st7789.frame_buffer;
this->st7789.init();
this->set_dimensions(this->st7789.width, this->st7789.height);
this->st7789.update(palette);
}
void update();
[[deprecated("Use configure_display(true) instead.")]] void flip();
void set_backlight(uint8_t brightness);
void configure_display(bool rotate180);
void set_framebuffer(void* frame_buffer) {

View File

@ -87,6 +87,13 @@ namespace pimoroni {
return __builtin_bswap16(p);
}
void set_dimensions(int width, int height) {
bounds.w = width;
bounds.h = height;
clip.w = width;
clip.h = height;
}
int create_pen(uint8_t r, uint8_t g, uint8_t b);
void empty_palette();

View File

@ -1,11 +1,15 @@
import time
import random
from st7789 import ST7789
from st7789 import ST7789, PALETTE_USER
WIDTH, HEIGHT = 240, 240
display = ST7789(WIDTH, HEIGHT, round=False)
# We're creating 100 balls with their own individual colour and 1 BG colour
# for a total of 101 colours, which will all fit in the 256 entry palette!
display.set_palette_mode(PALETTE_USER)
display.set_backlight(1.0)
@ -33,9 +37,11 @@ for i in range(0, 100):
display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
)
)
BG = display.create_pen(40, 40, 40)
while True:
display.set_pen(40, 40, 40)
display.set_pen(BG)
display.clear()
for ball in balls:
@ -58,3 +64,4 @@ while True:
display.update()
time.sleep(0.01)

View File

@ -0,0 +1,19 @@
set(MOD_NAME pimoroni_bus)
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}/../../../common/pimoroni_bus.cpp
)
target_include_directories(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
MODULE_${MOD_NAME_UPPER}_ENABLED=1
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})

View File

@ -32,6 +32,9 @@ 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);
// Utility
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_get_bounds_obj, GenericST7789_get_bounds);
STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) },
@ -55,6 +58,7 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) },
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&GenericST7789_get_bounds_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&GenericST7789_set_framebuffer_obj) },
};
STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict_table);
@ -63,7 +67,6 @@ STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict
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,
};
@ -71,22 +74,37 @@ const mp_obj_type_t GenericST7789_type = {
const mp_obj_type_t GenericST7789Parallel_type = {
{ &mp_type_type },
.name = MP_QSTR_st7789,
.print = GenericST7789_print,
.make_new = GenericST7789Parallel_make_new,
.locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict,
};
const mp_obj_type_t GenericST7789SPI_type = {
{ &mp_type_type },
.name = MP_QSTR_st7789,
.make_new = GenericST7789SPI_make_new,
.locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict,
};
/***** Module Globals *****/
STATIC const mp_map_elem_t st7789_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) },
{ MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type },
{ MP_ROM_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type },
{ MP_ROM_QSTR(MP_QSTR_ST7789SPI), (mp_obj_t)&GenericST7789Parallel_type },
{ MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) },
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) },
{ MP_ROM_QSTR(MP_QSTR_PALETTE_RGB332), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_PALETTE_USER), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(2) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(3) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(4) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(5) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(6) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table);

View File

@ -1,4 +1,6 @@
#include "libraries/generic_st7789/generic_st7789.hpp"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_bus.hpp"
#include "micropython/modules/util.hpp"
@ -9,57 +11,101 @@ using namespace pimoroni;
extern "C" {
#include "st7789.h"
/***** Variables Struct *****/
enum ST7789Display {
DISPLAY_LCD_240X240=0,
DISPLAY_ROUND_LCD_240X240,
DISPLAY_PICO_DISPLAY,
DISPLAY_PICO_DISPLAY_2,
DISPLAY_PICO_EXPLORER,
DISPLAY_TUFTY_2040,
DISPLAY_ENVIRO_PLUS
};
typedef struct _GenericST7789_obj_t {
mp_obj_base_t base;
ST7789Generic *st7789;
bool parallel;
void *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);
if(self->parallel) {
mp_print_str(print, "ST7789Parallel()");
} else {
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 };
enum { ARG_display, ARG_rotate, ARG_slot, ARG_buffer };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED },
{ MP_QSTR_rotate, MP_ARG_INT, { .u_int = Rotation::ROTATE_0 } },
{ MP_QSTR_slot, MP_ARG_INT, { .u_int = 0 } },
{ MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } },
};
// 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;
Rotation rotate = (Rotation)args[ARG_rotate].u_int;
bool round = false;
int width = 0;
int height = 0;
ST7789Display display = (ST7789Display)args[ARG_display].u_int;
switch(display) {
case DISPLAY_PICO_DISPLAY:
width = 240;
height = 135;
break;
case DISPLAY_PICO_DISPLAY_2:
case DISPLAY_TUFTY_2040:
width = 320;
height = 240;
break;
case DISPLAY_PICO_EXPLORER:
case DISPLAY_LCD_240X240:
case DISPLAY_ENVIRO_PLUS:
width = 240;
height = 240;
break;
case DISPLAY_ROUND_LCD_240X240:
width = 240;
height = 240;
round = true;
break;
}
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 = bufinfo.buf;
if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) {
mp_raise_ValueError("Supplied buffer is too small!");
}
} else {
self->buffer = m_new(uint8_t, width * height * sizeof(Pen));
}
if (display == DISPLAY_TUFTY_2040) {
self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2});
} else {
BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int;
self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, get_spi_pins(slot));
}
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t GenericST7789SPI_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_rotate, ARG_round, 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_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} },
{ 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} },
@ -75,10 +121,9 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t
self = m_new_obj(GenericST7789_obj_t);
self->base.type = &GenericST7789_type;
self->parallel = false;
bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true;
bool round = args[ARG_round].u_obj == mp_const_true;
Rotation rotate = (Rotation)args[ARG_rotate].u_int;
int width = args[ARG_width].u_int;
int height = args[ARG_height].u_int;
@ -93,50 +138,42 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t
self->buffer = m_new(uint8_t, width * height * sizeof(Pen));
}
if(args[ARG_slot].u_int != -1) {
BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int;
self->st7789 = m_new_class(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;
int spi_id = args[ARG_spi].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);
}
// Get SPI bus.
SPIPins bus_pins = {
nullptr,
(uint)args[ARG_cs].u_int,
(uint)args[ARG_sck].u_int,
(uint)args[ARG_mosi].u_int,
(uint)args[ARG_dc].u_int,
args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int
};
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 = m_new_class(ST7789Generic, width, height, round, self->buffer,
spi, cs, dc, sck, mosi, bl);
if (rotate180) {
self->st7789->configure_display(true);
}
if(spi_id == -1) {
spi_id = (bus_pins.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, (int)bus_pins.sck)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin"));
}
if(!IS_VALID_MOSI(spi_id, (int)bus_pins.mosi)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin"));
}
bus_pins.spi = (spi_id == 0) ? spi0 : spi1;
self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, bus_pins);
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t GenericST7789Parallel_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_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate180, ARG_buffer };
enum { ARG_width, ARG_height, ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate, ARG_buffer };
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 },
@ -147,7 +184,7 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args
{ MP_QSTR_d0, MP_ARG_INT, {.u_int = 14} },
{ MP_QSTR_bl, MP_ARG_INT, {.u_int = 2} },
{ MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} },
{ MP_QSTR_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} },
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
@ -155,11 +192,10 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_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);
GenericST7789_obj_t *self = m_new_obj(GenericST7789_obj_t);
self->base.type = &GenericST7789_type;
self->parallel = true;
bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true;
Rotation rotate = (Rotation)args[ARG_rotate].u_int;
int width = args[ARG_width].u_int;
int height = args[ARG_height].u_int;
@ -174,18 +210,16 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args
self->buffer = m_new(uint8_t, width * height);
}
int cs = args[ARG_cs].u_int;
int dc = args[ARG_dc].u_int;
int wr_sck = args[ARG_wr_sck].u_int;
int rd_sck = args[ARG_rd_sck].u_int;
int d0 = args[ARG_d0].u_int;
int bl = args[ARG_bl].u_int;
ParallelPins bus_pins = {
(uint)args[ARG_cs].u_int,
(uint)args[ARG_dc].u_int,
(uint)args[ARG_wr_sck].u_int,
(uint)args[ARG_rd_sck].u_int,
(uint)args[ARG_d0].u_int,
args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int
};
self->st7789 = m_new_class(ST7789Generic, width, height, self->buffer,
cs, dc, wr_sck, rd_sck, d0, bl);
if (rotate180) {
self->st7789->configure_display(true);
}
self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, bus_pins);
return MP_OBJ_FROM_PTR(self);
}
@ -208,6 +242,14 @@ mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) {
return mp_const_none;
}
mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in) {
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
mp_obj_t tuple[2];
tuple[0] = mp_obj_new_int(self->st7789->bounds.w);
tuple[1] = mp_obj_new_int(self->st7789->bounds.h);
return mp_obj_new_tuple(2, tuple);
}
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();

View File

@ -9,10 +9,9 @@ extern mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b);
extern mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b);
// 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 GenericST7789SPI_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 GenericST7789Parallel_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_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer);
extern mp_obj_t GenericST7789_update(mp_obj_t self_in);
extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness);
@ -38,4 +37,8 @@ extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_m
extern mp_obj_t GenericST7789_measure_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);
extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
// Utility
extern mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in);
extern mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer);