UC8159: Port to PicoGraphics/DisplayDriver.

driver/uc8159
Phil Howard 2022-06-14 09:57:00 +01:00
rodzic f1f3d55a8c
commit b497b87c95
6 zmienionych plików z 82 dodań i 142 usunięć

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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);
};
}

Wyświetl plik

@ -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"
)
)

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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);