kopia lustrzana https://github.com/pimoroni/pimoroni-pico
UC8159: Port to PicoGraphics/DisplayDriver.
rodzic
f1f3d55a8c
commit
b497b87c95
|
@ -74,93 +74,26 @@ namespace pimoroni {
|
|||
|
||||
gpio_set_function(SCK, GPIO_FUNC_SPI);
|
||||
gpio_set_function(MOSI, GPIO_FUNC_SPI);
|
||||
|
||||
memset(frame_buffer, WHITE << 4 | WHITE, width * height / 2);
|
||||
};
|
||||
|
||||
void UC8159::setup() {
|
||||
reset();
|
||||
busy_wait();
|
||||
|
||||
/*
|
||||
Resolution Setting
|
||||
10bit horizontal followed by a 10bit vertical resolution
|
||||
we'll let struct.pack do the work here and send 16bit values
|
||||
life is too short for manual bit wrangling
|
||||
*/
|
||||
uint16_t resolution[2] = {
|
||||
__builtin_bswap16(width),
|
||||
__builtin_bswap16(height)
|
||||
};
|
||||
|
||||
command(TRES, 4, {
|
||||
(uint8_t *)resolution
|
||||
});
|
||||
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});
|
||||
|
||||
/*
|
||||
Panel Setting
|
||||
0b11000000 = Resolution select, 0b00 = 640x480, our panel is 0b11 = 600x448
|
||||
0b00100000 = LUT selection, 0 = ext flash, 1 = registers, we use ext flash
|
||||
0b00010000 = Ignore
|
||||
0b00001000 = Gate scan direction, 0 = down, 1 = up (default)
|
||||
0b00000100 = Source shift direction, 0 = left, 1 = right (default)
|
||||
0b00000010 = DC-DC converter, 0 = off, 1 = on
|
||||
0b00000001 = Soft reset, 0 = Reset, 1 = Normal (Default)
|
||||
0b11 = 600x448
|
||||
0b10 = 640x400
|
||||
*/
|
||||
sleep_ms(100);
|
||||
|
||||
command(PSR, {
|
||||
(uint8_t)((width == 640) ? 0b10101111 : 0b11101111),
|
||||
0x08 // UC8159 7-colour
|
||||
});
|
||||
|
||||
command(PWR, {
|
||||
(0x06 << 3) | // ??? - not documented in UC8159 datasheet
|
||||
(0x01 << 2) | // SOURCE_INTERNAL_DC_DC
|
||||
(0x01 << 1) | // GATE_INTERNAL_DC_DC
|
||||
0x01, // LV_SOURCE_INTERNAL_DC_DC
|
||||
0x00, // VGx_20V
|
||||
0x23, // UC8159_7C
|
||||
0x23 // UC8159_7C
|
||||
});
|
||||
|
||||
/*
|
||||
Set the PLL clock frequency to 50Hz
|
||||
0b11000000 = Ignore
|
||||
0b00111000 = M
|
||||
0b00000111 = N
|
||||
PLL = 2MHz * (M / N)
|
||||
PLL = 2MHz * (7 / 4)
|
||||
PLL = 2,800,000 ???
|
||||
*/
|
||||
command(PLL, 0x3C);
|
||||
|
||||
command(TSE, 0x00);
|
||||
|
||||
/*
|
||||
VCOM and Data Interval setting
|
||||
0b11100000 = Vborder control (0b001 = LUTB voltage)
|
||||
0b00010000 = Data polarity
|
||||
0b00001111 = Vcom and data interval (0b0111 = 10, default)
|
||||
*/
|
||||
command(CDI, (1 << 5) | 0x17);
|
||||
|
||||
/*
|
||||
Gate/Source non-overlap period
|
||||
0b11110000 = Source to Gate (0b0010 = 12nS, default)
|
||||
0b00001111 = Gate to Source
|
||||
*/
|
||||
command(TCON, 0x22);
|
||||
|
||||
// Disable externalflash
|
||||
command(DAM, 0x00);
|
||||
|
||||
command(PWS, 0xAA);
|
||||
|
||||
command(PFS, 0x00);
|
||||
|
||||
//power_off();
|
||||
command(0x50, {0x37});
|
||||
}
|
||||
|
||||
void UC8159::power_off() {
|
||||
|
@ -193,29 +126,14 @@ namespace pimoroni {
|
|||
command(reg, values.size(), (uint8_t *)values.begin());
|
||||
}
|
||||
|
||||
void UC8159::pixel(int x, int y, int v) {
|
||||
// bounds check
|
||||
if(x < 0 || y < 0 || x >= width || y >= height) return;
|
||||
|
||||
// pointer to byte in framebuffer that contains this pixel
|
||||
uint8_t *p = &frame_buffer[(x / 2) + (y * width / 2)];
|
||||
|
||||
uint8_t o = (~x & 0b1) * 4; // bit offset within byte
|
||||
uint8_t m = ~(0b1111 << o); // bit mask for byte
|
||||
uint8_t b = v << o; // bit value shifted to position
|
||||
|
||||
*p &= m; // clear bits
|
||||
*p |= b; // set value
|
||||
}
|
||||
|
||||
void UC8159::update(bool blocking) {
|
||||
void UC8159::update(const void *data, bool blocking) {
|
||||
if(blocking) {
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
command(DTM1, (width * height) / 2, frame_buffer); // transmit framebuffer
|
||||
command(DTM1, (width * height) / 2, (uint8_t *)data); // transmit framebuffer
|
||||
busy_wait();
|
||||
|
||||
command(PON); // turn on
|
||||
|
@ -231,4 +149,9 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
void UC8159::update(PicoGraphics *graphics) {
|
||||
if(graphics->pen_type != PicoGraphics::PEN_P4) return; // Incompatible buffer
|
||||
update(graphics->frame_buffer, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,19 +5,17 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
#include "../../common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_bus.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class UC8159 {
|
||||
class UC8159 : public DisplayDriver {
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
// screen properties
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
|
||||
// highest possible resolution is 160x296 which at 1 bit per pixel
|
||||
// requires 5920 bytes of frame buffer
|
||||
|
@ -34,8 +32,6 @@ namespace pimoroni {
|
|||
uint BUSY = 26;
|
||||
uint RESET = 25;
|
||||
|
||||
bool inverted = false;
|
||||
|
||||
public:
|
||||
enum colour : uint8_t {
|
||||
BLACK = 0,
|
||||
|
@ -48,53 +44,36 @@ namespace pimoroni {
|
|||
CLEAN = 7
|
||||
};
|
||||
|
||||
UC8159(uint16_t width, uint16_t height) :
|
||||
width(width), height(height), frame_buffer(new uint8_t[width * height / 2]) {
|
||||
}
|
||||
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, uint8_t *frame_buffer) :
|
||||
width(width), height(height), frame_buffer(frame_buffer) {
|
||||
}
|
||||
|
||||
UC8159(uint16_t width, uint16_t height,
|
||||
spi_inst_t *spi,
|
||||
uint CS, uint DC, uint SCK, uint MOSI,
|
||||
uint BUSY = PIN_UNUSED, uint RESET = PIN_UNUSED) :
|
||||
width(width), height(height),
|
||||
frame_buffer(new uint8_t[width * height / 2]),
|
||||
spi(spi),
|
||||
CS(CS), DC(DC), SCK(SCK), MOSI(MOSI), BUSY(BUSY), RESET(RESET) {}
|
||||
|
||||
UC8159(uint16_t width, uint16_t height,
|
||||
uint8_t *frame_buffer,
|
||||
spi_inst_t *spi,
|
||||
uint CS, uint DC, uint SCK, uint MOSI,
|
||||
uint BUSY = PIN_UNUSED, uint RESET = PIN_UNUSED) :
|
||||
width(width), height(height),
|
||||
frame_buffer(frame_buffer),
|
||||
spi(spi),
|
||||
CS(CS), DC(DC), SCK(SCK), MOSI(MOSI), BUSY(BUSY), RESET(RESET) {}
|
||||
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 init();
|
||||
void busy_wait();
|
||||
bool is_busy();
|
||||
void reset();
|
||||
void setup();
|
||||
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);
|
||||
|
||||
void update(bool blocking = true);
|
||||
void pixel(int x, int y, int v);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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