kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Merge pull request #322 from pimoroni/driver/uc8159
PicoGraphics support for UC8159-based displayspatch-ff-use-strfunc
commit
fde585867e
|
@ -28,6 +28,7 @@ add_subdirectory(icp10125)
|
|||
add_subdirectory(scd4x)
|
||||
add_subdirectory(hub75)
|
||||
add_subdirectory(uc8151)
|
||||
add_subdirectory(uc8159)
|
||||
add_subdirectory(uc8151_legacy)
|
||||
add_subdirectory(pwm)
|
||||
add_subdirectory(servo)
|
||||
|
@ -37,4 +38,3 @@ add_subdirectory(vl53l5cx)
|
|||
add_subdirectory(pcf85063a)
|
||||
add_subdirectory(pms5003)
|
||||
add_subdirectory(sh1107)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(uc8159.cmake)
|
|
@ -0,0 +1,10 @@
|
|||
set(DRIVER_NAME uc8159)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
target_sources(${DRIVER_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
|
||||
|
||||
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi)
|
|
@ -0,0 +1,157 @@
|
|||
#include "uc8159.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
enum reg {
|
||||
PSR = 0x00,
|
||||
PWR = 0x01,
|
||||
POF = 0x02,
|
||||
PFS = 0x03,
|
||||
PON = 0x04,
|
||||
BTST = 0x06,
|
||||
DSLP = 0x07,
|
||||
DTM1 = 0x10,
|
||||
DSP = 0x11,
|
||||
DRF = 0x12,
|
||||
IPC = 0x13,
|
||||
PLL = 0x30,
|
||||
TSC = 0x40,
|
||||
TSE = 0x41,
|
||||
TSW = 0x42,
|
||||
TSR = 0x43,
|
||||
CDI = 0x50,
|
||||
LPD = 0x51,
|
||||
TCON = 0x60,
|
||||
TRES = 0x61,
|
||||
DAM = 0x65,
|
||||
REV = 0x70,
|
||||
FLG = 0x71,
|
||||
AMV = 0x80,
|
||||
VV = 0x81,
|
||||
VDCS = 0x82,
|
||||
PWS = 0xE3,
|
||||
TSSET = 0xE5
|
||||
};
|
||||
|
||||
bool UC8159::is_busy() {
|
||||
return !gpio_get(BUSY);
|
||||
}
|
||||
|
||||
void UC8159::busy_wait() {
|
||||
while(is_busy()) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
||||
void UC8159::reset() {
|
||||
gpio_put(RESET, 0); sleep_ms(10);
|
||||
gpio_put(RESET, 1); sleep_ms(10);
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
void UC8159::init() {
|
||||
// configure spi interface and pins
|
||||
spi_init(spi, 3'000'000);
|
||||
|
||||
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_put(CS, 1);
|
||||
|
||||
gpio_set_function(RESET, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(RESET, GPIO_OUT);
|
||||
gpio_put(RESET, 1);
|
||||
|
||||
gpio_set_function(BUSY, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(BUSY, GPIO_IN);
|
||||
gpio_set_pulls(BUSY, true, false);
|
||||
|
||||
gpio_set_function(SCK, GPIO_FUNC_SPI);
|
||||
gpio_set_function(MOSI, GPIO_FUNC_SPI);
|
||||
};
|
||||
|
||||
void UC8159::setup() {
|
||||
reset();
|
||||
busy_wait();
|
||||
|
||||
command(0x00, {0xE3, 0x08});
|
||||
command(0x01, {0x37, 0x00, 0x23, 0x23});
|
||||
command(0x03, {0x00});
|
||||
command(0x06, {0xC7, 0xC7, 0x1D});
|
||||
command(0x30, {0x3C});
|
||||
command(0x40, {0x00});
|
||||
command(0x50, {0x37});
|
||||
command(0x60, {0x22});
|
||||
command(0x61, {0x02, 0x58, 0x01, 0xC0});
|
||||
command(0xE3, {0xAA});
|
||||
|
||||
sleep_ms(100);
|
||||
|
||||
command(0x50, {0x37});
|
||||
}
|
||||
|
||||
void UC8159::power_off() {
|
||||
busy_wait();
|
||||
command(POF); // turn off
|
||||
}
|
||||
|
||||
void UC8159::command(uint8_t reg, size_t len, const uint8_t *data) {
|
||||
gpio_put(CS, 0);
|
||||
|
||||
gpio_put(DC, 0); // command mode
|
||||
spi_write_blocking(spi, ®, 1);
|
||||
|
||||
if(len > 0) {
|
||||
gpio_put(DC, 1); // data mode
|
||||
spi_write_blocking(spi, (const uint8_t*)data, len);
|
||||
}
|
||||
|
||||
gpio_put(CS, 1);
|
||||
}
|
||||
|
||||
void UC8159::data(size_t len, const uint8_t *data) {
|
||||
gpio_put(CS, 0);
|
||||
gpio_put(DC, 1); // data mode
|
||||
spi_write_blocking(spi, (const uint8_t*)data, len);
|
||||
gpio_put(CS, 1);
|
||||
}
|
||||
|
||||
void UC8159::command(uint8_t reg, std::initializer_list<uint8_t> values) {
|
||||
command(reg, values.size(), (uint8_t *)values.begin());
|
||||
}
|
||||
|
||||
void UC8159::update(const void *data, bool blocking) {
|
||||
if(blocking) {
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
command(DTM1, (width * height) / 2, (uint8_t *)data); // transmit framebuffer
|
||||
busy_wait();
|
||||
|
||||
command(PON); // turn on
|
||||
busy_wait();
|
||||
|
||||
command(DRF); // start display refresh
|
||||
busy_wait();
|
||||
|
||||
if(blocking) {
|
||||
busy_wait();
|
||||
|
||||
command(POF); // turn off
|
||||
}
|
||||
}
|
||||
|
||||
void UC8159::update(PicoGraphics *graphics) {
|
||||
if(graphics->pen_type != PicoGraphics::PEN_P4) return; // Incompatible buffer
|
||||
update(graphics->frame_buffer, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_bus.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class UC8159 : public DisplayDriver {
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
|
||||
// highest possible resolution is 160x296 which at 1 bit per pixel
|
||||
// requires 5920 bytes of frame buffer
|
||||
//uint8_t frame_buffer[5920] = {0};
|
||||
uint8_t *frame_buffer;
|
||||
|
||||
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
|
||||
|
||||
// interface pins with our standard defaults where appropriate
|
||||
uint CS = SPI_BG_FRONT_CS;
|
||||
uint DC = 27;
|
||||
uint SCK = SPI_DEFAULT_SCK;
|
||||
uint MOSI = SPI_DEFAULT_MOSI;
|
||||
uint BUSY = 26;
|
||||
uint RESET = 25;
|
||||
|
||||
public:
|
||||
enum colour : uint8_t {
|
||||
BLACK = 0,
|
||||
WHITE = 1,
|
||||
GREEN = 2,
|
||||
BLUE = 3,
|
||||
RED = 4,
|
||||
YELLOW = 5,
|
||||
ORANGE = 6,
|
||||
CLEAN = 7
|
||||
};
|
||||
|
||||
UC8159(uint16_t width, uint16_t height) : UC8159(width, height, {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 27, PIN_UNUSED}) {};
|
||||
|
||||
UC8159(uint16_t width, uint16_t height, SPIPins pins, uint busy=26, uint reset=25) :
|
||||
DisplayDriver(width, height, ROTATE_0),
|
||||
spi(pins.spi),
|
||||
CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi), BUSY(busy), RESET(reset) {
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
void busy_wait();
|
||||
void reset();
|
||||
void power_off();
|
||||
|
||||
bool is_busy() override;
|
||||
void update(PicoGraphics *graphics) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void setup();
|
||||
void update(const void *data, bool blocking = true);
|
||||
void command(uint8_t reg, size_t len, const uint8_t *data);
|
||||
void command(uint8_t reg, std::initializer_list<uint8_t> values);
|
||||
void command(uint8_t reg, const uint8_t data) {command(reg, 0, &data);};
|
||||
void command(uint8_t reg) {command(reg, 0, nullptr);};
|
||||
void data(size_t len, const uint8_t *data);
|
||||
};
|
||||
|
||||
}
|
|
@ -31,3 +31,4 @@ add_subdirectory(tufty2040)
|
|||
add_subdirectory(servo2040)
|
||||
add_subdirectory(motor2040)
|
||||
add_subdirectory(adcfft)
|
||||
add_subdirectory(jpegdec)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(jpegdec.cmake)
|
|
@ -0,0 +1,16 @@
|
|||
#include "JPEGDEC.h"
|
||||
/*
|
||||
int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) {
|
||||
return 0;
|
||||
}
|
||||
int32_t seekMem(JPEGFILE *pFile, int32_t iPosition) {
|
||||
return 0;
|
||||
}
|
||||
int32_t readFile(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) {
|
||||
return 0;
|
||||
}
|
||||
int32_t seekFile(JPEGFILE *pFile, int32_t iPosition) {
|
||||
return 0;
|
||||
}
|
||||
void closeFile(void *handle) {
|
||||
}*/
|
|
@ -0,0 +1,10 @@
|
|||
add_library(jpegdec
|
||||
${CMAKE_CURRENT_LIST_DIR}/jpeg.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/JPEGDEC.cpp
|
||||
)
|
||||
|
||||
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/JPEGDEC.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function")
|
||||
|
||||
target_include_directories(jpegdec INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(jpegdec pico_stdlib)
|
|
@ -99,10 +99,16 @@ namespace pimoroni {
|
|||
void PicoGraphics_PenP4::set_pixel_dither(const Point &p, const RGB &c) {
|
||||
if(!bounds.contains(p)) return;
|
||||
|
||||
uint used_palette_entries = 0;
|
||||
for(auto i = 0u; i < palette_size; i++) {
|
||||
if(!used[i]) break;
|
||||
used_palette_entries++;
|
||||
}
|
||||
|
||||
if(!cache_built) {
|
||||
for(uint i = 0; i < 512; i++) {
|
||||
RGB cache_col((i & 0x1C0) >> 1, (i & 0x38) << 2, (i & 0x7) << 5);
|
||||
get_dither_candidates(cache_col, palette, palette_size, candidate_cache[i]);
|
||||
get_dither_candidates(cache_col, palette, used_palette_entries, candidate_cache[i]);
|
||||
}
|
||||
cache_built = true;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,62 @@ typedef struct _ModPicoGraphics_obj_t {
|
|||
typedef struct _JPEG_obj_t {
|
||||
mp_obj_base_t base;
|
||||
JPEGDEC *jpeg;
|
||||
mp_obj_t file;
|
||||
mp_buffer_info_t buf;
|
||||
ModPicoGraphics_obj_t *graphics;
|
||||
} _JPEG_obj_t;
|
||||
|
||||
|
||||
PicoGraphics *current_graphics = nullptr;
|
||||
|
||||
|
||||
void *jpegdec_open_callback(const char *filename, int32_t *size) {
|
||||
mp_obj_t fn = mp_obj_new_str(filename, (mp_uint_t)strlen(filename));
|
||||
|
||||
mp_obj_t args[2] = {
|
||||
fn,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_r),
|
||||
};
|
||||
|
||||
// Stat the file to get its size
|
||||
// example tuple response: (32768, 0, 0, 0, 0, 0, 5153, 1654709815, 1654709815, 1654709815)
|
||||
mp_obj_t stat = mp_vfs_stat(fn);
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t);
|
||||
*size = mp_obj_get_int(tuple->items[6]);
|
||||
|
||||
mp_obj_t fhandle = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
|
||||
|
||||
return (void *)fhandle;
|
||||
}
|
||||
|
||||
void jpegdec_close_callback(void *handle) {
|
||||
mp_stream_close((mp_obj_t)handle);
|
||||
}
|
||||
|
||||
int32_t jpegdec_read_callback(JPEGFILE *jpeg, uint8_t *p, int32_t c) {
|
||||
mp_obj_t fhandle = jpeg->fHandle;
|
||||
int error;
|
||||
return mp_stream_read_exactly(fhandle, p, c, &error);
|
||||
}
|
||||
|
||||
// Re-implementation of stream.c/STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args)
|
||||
int32_t jpegdec_seek_callback(JPEGFILE *jpeg, int32_t p) {
|
||||
mp_obj_t fhandle = jpeg->fHandle;
|
||||
struct mp_stream_seek_t seek_s;
|
||||
seek_s.offset = p;
|
||||
seek_s.whence = SEEK_SET;
|
||||
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(fhandle);
|
||||
|
||||
int error;
|
||||
mp_uint_t res = stream_p->ioctl(fhandle, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
mp_raise_OSError(error);
|
||||
}
|
||||
|
||||
return seek_s.offset;
|
||||
}
|
||||
|
||||
int JPEGDraw(JPEGDRAW *pDraw) {
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
|
@ -105,56 +155,25 @@ mp_obj_t _JPEG_del(mp_obj_t self_in) {
|
|||
return mp_const_none;
|
||||
}
|
||||
|
||||
static int _open(_JPEG_obj_t *self) {
|
||||
int result = self->jpeg->openRAM((uint8_t *)self->buf.buf, self->buf.len, JPEGDraw);
|
||||
if (result == 1) {
|
||||
switch(self->graphics->graphics->pen_type) {
|
||||
case PicoGraphics::PEN_RGB332:
|
||||
case PicoGraphics::PEN_RGB565:
|
||||
case PicoGraphics::PEN_P8:
|
||||
case PicoGraphics::PEN_P4:
|
||||
self->jpeg->setPixelType(RGB565_BIG_ENDIAN);
|
||||
break;
|
||||
// TODO 2-bit is currently unsupported
|
||||
case PicoGraphics::PEN_P2:
|
||||
self->jpeg->setPixelType(TWO_BIT_DITHERED);
|
||||
break;
|
||||
case PicoGraphics::PEN_1BIT:
|
||||
self->jpeg->setPixelType(ONE_BIT_DITHERED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// open_FILE
|
||||
mp_obj_t _JPEG_openFILE(mp_obj_t self_in, mp_obj_t filename) {
|
||||
_JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t);
|
||||
mp_obj_t args[2] = {
|
||||
filename,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_r),
|
||||
};
|
||||
|
||||
// Stat the file to get its size
|
||||
// example tuple response: (32768, 0, 0, 0, 0, 0, 5153, 1654709815, 1654709815, 1654709815)
|
||||
mp_obj_t stat = mp_vfs_stat(filename);
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t);
|
||||
size_t filesize = mp_obj_get_int(tuple->items[6]);
|
||||
// TODO Check for valid filename, and maybe that file exists?
|
||||
|
||||
self->file = filename;
|
||||
|
||||
self->buf.buf = (void *)m_new(uint8_t, filesize);
|
||||
mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
|
||||
int errcode;
|
||||
self->buf.len = mp_stream_rw(file, self->buf.buf, filesize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
||||
if (errcode != 0) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to open file!"));
|
||||
}
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
// open_RAM
|
||||
mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) {
|
||||
_JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t);
|
||||
mp_get_buffer_raise(buffer, &self->buf, MP_BUFFER_READ);
|
||||
|
||||
// TODO Check for valid buffer
|
||||
|
||||
self->file = buffer;
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
|
@ -177,12 +196,53 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
|
|||
int y = args[ARG_y].u_int;
|
||||
int f = args[ARG_scale].u_int;
|
||||
|
||||
if(_open(self) != 1) return mp_const_false;
|
||||
// Just-in-time open of the filename/buffer we stored in self->file via open_RAM or open_file
|
||||
|
||||
// Source is a filename
|
||||
int result = -1;
|
||||
|
||||
if(mp_obj_is_str_or_bytes(self->file)){
|
||||
GET_STR_DATA_LEN(self->file, str, str_len);
|
||||
|
||||
std::string t((const char*)str);
|
||||
|
||||
result = self->jpeg->open(
|
||||
t.c_str(),
|
||||
jpegdec_open_callback,
|
||||
jpegdec_close_callback,
|
||||
jpegdec_read_callback,
|
||||
jpegdec_seek_callback,
|
||||
JPEGDraw);
|
||||
|
||||
// Source is a buffer
|
||||
} else {
|
||||
mp_get_buffer_raise(self->file, &self->buf, MP_BUFFER_READ);
|
||||
|
||||
result = self->jpeg->openRAM((uint8_t *)self->buf.buf, self->buf.len, JPEGDraw);
|
||||
}
|
||||
|
||||
if(result != 1) mp_raise_msg(&mp_type_RuntimeError, "JPEG: could not read file/buffer.");
|
||||
|
||||
// Force a specific data output type to best match our PicoGraphics buffer
|
||||
switch(self->graphics->graphics->pen_type) {
|
||||
case PicoGraphics::PEN_RGB332:
|
||||
case PicoGraphics::PEN_RGB565:
|
||||
case PicoGraphics::PEN_P8:
|
||||
case PicoGraphics::PEN_P4:
|
||||
self->jpeg->setPixelType(RGB565_BIG_ENDIAN);
|
||||
break;
|
||||
// TODO 2-bit is currently unsupported
|
||||
case PicoGraphics::PEN_P2:
|
||||
self->jpeg->setPixelType(TWO_BIT_DITHERED);
|
||||
break;
|
||||
case PicoGraphics::PEN_1BIT:
|
||||
self->jpeg->setPixelType(ONE_BIT_DITHERED);
|
||||
break;
|
||||
}
|
||||
|
||||
// We need to store a pointer to the PicoGraphics surface
|
||||
// since the JPEGDRAW struct has no userdata
|
||||
current_graphics = self->graphics->graphics;
|
||||
int result = -1;
|
||||
|
||||
if(self->graphics->graphics->pen_type == PicoGraphics::PEN_P4 || self->graphics->graphics->pen_type == PicoGraphics::PEN_1BIT) {
|
||||
uint8_t *buf = new uint8_t[2048];
|
||||
|
@ -191,7 +251,12 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
|
|||
} else {
|
||||
result = self->jpeg->decode(x, y, f);
|
||||
}
|
||||
|
||||
current_graphics = nullptr;
|
||||
|
||||
// Close the file since we've opened it on-demand
|
||||
self->jpeg->close();
|
||||
|
||||
return result == 1 ? mp_const_true : mp_const_false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ target_sources(usermod_${MOD_NAME} INTERFACE
|
|||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/sh1107/sh1107.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/uc8151/uc8151.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/uc8159/uc8159.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_1bit.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_1bitY.cpp
|
||||
|
@ -35,4 +36,4 @@ set_source_files_properties(
|
|||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
"-Wno-discarded-qualifiers"
|
||||
)
|
||||
)
|
||||
|
|
|
@ -119,6 +119,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_160X80), MP_ROM_INT(DISPLAY_LCD_160X80) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_I2C_OLED_128X128), MP_ROM_INT(DISPLAY_I2C_OLED_128X128) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_PACK), MP_ROM_INT(DISPLAY_INKY_PACK) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME), MP_ROM_INT(DISPLAY_INKY_FRAME) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) },
|
||||
|
@ -138,4 +139,4 @@ const mp_obj_module_t picographics_user_cmodule = {
|
|||
MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule, MODULE_PICOGRAPHICS_ENABLED);
|
||||
#else
|
||||
MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "drivers/st7735/st7735.hpp"
|
||||
#include "drivers/sh1107/sh1107.hpp"
|
||||
#include "drivers/uc8151/uc8151.hpp"
|
||||
#include "drivers/uc8159/uc8159.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_bus.hpp"
|
||||
|
@ -82,6 +83,12 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
|
|||
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
|
||||
if(pen_type == -1) pen_type = PEN_1BIT;
|
||||
break;
|
||||
case DISPLAY_INKY_FRAME:
|
||||
width = 600;
|
||||
height = 448;
|
||||
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
|
||||
if(pen_type == -1) pen_type = PEN_P4;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -108,13 +115,14 @@ size_t get_required_buffer_size(PicoGraphicsPenType pen_type, uint width, uint h
|
|||
mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
ModPicoGraphics_obj_t *self = nullptr;
|
||||
|
||||
enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer, ARG_pen_type };
|
||||
enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer, ARG_pen_type, ARG_extra_pins };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_rotate, MP_ARG_INT, { .u_int = -1 } },
|
||||
{ MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } },
|
||||
{ MP_QSTR_pen_type, MP_ARG_INT, { .u_int = -1 } },
|
||||
{ MP_QSTR_extra_pins, MP_ARG_OBJ, { .u_obj = mp_const_none } },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
|
@ -135,7 +143,19 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|
|||
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
|
||||
|
||||
// Try to create an appropriate display driver
|
||||
if (display == DISPLAY_TUFTY_2040) {
|
||||
if (display == DISPLAY_INKY_FRAME) {
|
||||
pen_type = PEN_P4; // FORCE to P4 since it's the only supported mode
|
||||
// TODO grab BUSY and RESET from ARG_extra_pins
|
||||
if (args[ARG_bus].u_obj == mp_const_none) {
|
||||
self->display = m_new_class(UC8159, width, height);
|
||||
} else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) {
|
||||
_PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
|
||||
self->display = m_new_class(UC8159, width, height, *(SPIPins *)(bus->pins));
|
||||
} else {
|
||||
mp_raise_ValueError("SPIBus expected!");
|
||||
}
|
||||
}
|
||||
else if (display == DISPLAY_TUFTY_2040) {
|
||||
if (args[ARG_bus].u_obj == mp_const_none) {
|
||||
self->display = m_new_class(ST7789, width, height, (Rotation)rotate, {10, 11, 12, 13, 14, 2});
|
||||
} else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) {
|
||||
|
@ -230,7 +250,9 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|
|||
self->graphics->clear();
|
||||
|
||||
// Update the LCD from the graphics library
|
||||
self->display->update(self->graphics);
|
||||
if (display != DISPLAY_INKY_FRAME) {
|
||||
self->display->update(self->graphics);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
@ -393,8 +415,21 @@ mp_obj_t ModPicoGraphics_update(mp_obj_t self_in) {
|
|||
self->graphics->scanline_interrupt = nullptr;
|
||||
}
|
||||
*/
|
||||
|
||||
while(self->display->is_busy()) {
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
#endif
|
||||
}
|
||||
|
||||
self->display->update(self->graphics);
|
||||
|
||||
while(self->display->is_busy()) {
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
#endif
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ enum PicoGraphicsDisplay {
|
|||
DISPLAY_ENVIRO_PLUS,
|
||||
DISPLAY_LCD_160X80,
|
||||
DISPLAY_I2C_OLED_128X128,
|
||||
DISPLAY_INKY_PACK
|
||||
DISPLAY_INKY_PACK,
|
||||
DISPLAY_INKY_FRAME
|
||||
};
|
||||
|
||||
enum PicoGraphicsPenType {
|
||||
|
@ -76,4 +77,4 @@ extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t frame
|
|||
|
||||
extern mp_int_t ModPicoGraphics_get_framebuffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
|
||||
|
||||
extern mp_obj_t ModPicoGraphics__del__(mp_obj_t self_in);
|
||||
extern mp_obj_t ModPicoGraphics__del__(mp_obj_t self_in);
|
||||
|
|
Ładowanie…
Reference in New Issue