From 0067b101a0c07e1f96c01e207ce804d99a11fd59 Mon Sep 17 00:00:00 2001 From: AndrewCapon Date: Wed, 1 Feb 2023 11:31:49 +0000 Subject: [PATCH] Inky 7.3: Direct pen & PSRAM update. --- drivers/CMakeLists.txt | 4 +- drivers/psram_display/CMakeLists.txt | 1 + drivers/psram_display/psram_display.cmake | 10 + drivers/psram_display/psram_display.cpp | 75 +++++++ drivers/psram_display/psram_display.hpp | 128 +++++++++++ drivers/uc8159_inky7/CMakeLists.txt | 1 + drivers/uc8159_inky7/uc8159_inky7.cmake | 10 + drivers/uc8159_inky7/uc8159_inky7.cpp | 206 ++++++++++++++++++ drivers/uc8159_inky7/uc8159_inky7.hpp | 80 +++++++ examples/inky_frame/CMakeLists.txt | 3 +- examples/inky_frame/inky_frame7_test.cmake | 14 ++ examples/inky_frame/inky_frame7_test.cpp | 39 ++++ libraries/pico_graphics/pico_graphics.cmake | 1 + libraries/pico_graphics/pico_graphics.hpp | 29 +++ .../pico_graphics/pico_graphics_pen_inky7.cpp | 49 +++++ 15 files changed, 648 insertions(+), 2 deletions(-) create mode 100644 drivers/psram_display/CMakeLists.txt create mode 100644 drivers/psram_display/psram_display.cmake create mode 100644 drivers/psram_display/psram_display.cpp create mode 100644 drivers/psram_display/psram_display.hpp create mode 100644 drivers/uc8159_inky7/CMakeLists.txt create mode 100644 drivers/uc8159_inky7/uc8159_inky7.cmake create mode 100644 drivers/uc8159_inky7/uc8159_inky7.cpp create mode 100644 drivers/uc8159_inky7/uc8159_inky7.hpp create mode 100644 examples/inky_frame/inky_frame7_test.cmake create mode 100644 examples/inky_frame/inky_frame7_test.cpp create mode 100644 libraries/pico_graphics/pico_graphics_pen_inky7.cpp diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index d0d9e09c..cfd457b2 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -39,4 +39,6 @@ add_subdirectory(vl53l5cx) add_subdirectory(pcf85063a) add_subdirectory(pms5003) add_subdirectory(sh1107) -add_subdirectory(st7567) \ No newline at end of file +add_subdirectory(st7567) +add_subdirectory(psram_display) +add_subdirectory(uc8159_inky7) \ No newline at end of file diff --git a/drivers/psram_display/CMakeLists.txt b/drivers/psram_display/CMakeLists.txt new file mode 100644 index 00000000..6284176d --- /dev/null +++ b/drivers/psram_display/CMakeLists.txt @@ -0,0 +1 @@ +include(psram_display.cmake) \ No newline at end of file diff --git a/drivers/psram_display/psram_display.cmake b/drivers/psram_display/psram_display.cmake new file mode 100644 index 00000000..2563997a --- /dev/null +++ b/drivers/psram_display/psram_display.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME psram_display) +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) diff --git a/drivers/psram_display/psram_display.cpp b/drivers/psram_display/psram_display.cpp new file mode 100644 index 00000000..6e1b26f8 --- /dev/null +++ b/drivers/psram_display/psram_display.cpp @@ -0,0 +1,75 @@ +#include "psram_display.hpp" + +#include +#include +#include + +namespace pimoroni { + + enum reg { + WRITE = 0x02, + READ = 0x03, + RESET_ENABLE = 0x66, + RESET = 0x99 + }; + + void PSRamDisplay::init() { + uint baud = spi_init(spi, 31'250'000); + printf("PSRam connected at %u\n", baud); + gpio_set_function(CS, GPIO_FUNC_SIO); + gpio_set_dir(CS, GPIO_OUT); + gpio_put(CS, 1); + + gpio_set_function(SCK, GPIO_FUNC_SPI); + gpio_set_function(MOSI, GPIO_FUNC_SPI); + gpio_set_function(MISO, GPIO_FUNC_SPI); + + gpio_put(CS, 0); + uint8_t command_buffer[2] = {RESET_ENABLE, RESET}; + spi_write_blocking(spi, command_buffer, 2); + gpio_put(CS, 1); + } + + void PSRamDisplay::write(uint32_t address, size_t len, const uint8_t *data) + { + gpio_put(CS, 0); + uint8_t command_buffer[4] = {WRITE, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)}; + spi_write_blocking(spi, command_buffer, 4); + spi_write_blocking(spi, data, len); + gpio_put(CS, 1); + } + + void PSRamDisplay::write(uint32_t address, size_t len, const uint8_t byte) + { + gpio_put(CS, 0); + uint8_t command_buffer[4] = {WRITE, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)}; + spi_write_blocking(spi, command_buffer, 4); + SpiSetBlocking(byte, len); + gpio_put(CS, 1); + } + + + void PSRamDisplay::read(uint32_t address, size_t len, uint8_t *data) + { + gpio_put(CS, 0); + uint8_t command_buffer[4] = {READ, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)}; + spi_write_blocking(spi, command_buffer, 4); + spi_read_blocking(spi, 0, data, len); + gpio_put(CS, 1); + } + + void PSRamDisplay::write_pixel(const Point &p, uint8_t colour) + { + write(pointToAddress(p), 1, colour); + } + + void PSRamDisplay::write_pixel_span(const Point &p, uint l, uint8_t colour) + { + write(pointToAddress(p), l, colour); + } + + void PSRamDisplay::read_pixel_span(const Point &p, uint l, uint8_t *data) + { + read(pointToAddress(p), l, data); + } +} diff --git a/drivers/psram_display/psram_display.hpp b/drivers/psram_display/psram_display.hpp new file mode 100644 index 00000000..2eff5535 --- /dev/null +++ b/drivers/psram_display/psram_display.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include + +#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" + + +// 8 MB PSRam + +namespace pimoroni { + + class PSRamDisplay : public IDirectDisplayDriver { + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; + + // interface pins with our standard defaults where appropriate + uint CS = 3; + uint DC = PIN_UNUSED; + uint SCK = SPI_DEFAULT_SCK; + uint MOSI = SPI_DEFAULT_MOSI; + uint MISO = SPI_DEFAULT_MISO; + + uint32_t start_address = 0; + uint16_t width = 0; + uint16_t height = 0; + + absolute_time_t timeout; + + bool blocking = false; + + public: + enum colour : uint8_t { + BLACK = 0, + WHITE = 1, + GREEN = 2, + BLUE = 3, + RED = 4, + YELLOW = 5, + ORANGE = 6, + CLEAN = 7 + }; + + PSRamDisplay(uint16_t width, uint16_t height) : PSRamDisplay(width, height, {PIMORONI_SPI_DEFAULT_INSTANCE, 3, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, PIN_UNUSED, PIN_UNUSED}) {}; + + PSRamDisplay(uint16_t width, uint16_t height, SPIPins pins) : + spi(pins.spi), + CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi), + width(width), height(height) { + init(); + } + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + void test(void){ + + char writeBuffer[1024]; + char readBuffer[1024]; + + uint mb = 8; + + for(uint k = 0; k < 1024*mb; k++) + { + sprintf(writeBuffer, "%u", k); + + write(k*1024, strlen(writeBuffer)+1, (uint8_t *)writeBuffer); + } + + bool bSame = true; + for(uint k = 0; k < 1024*mb && bSame; k++) + { + sprintf(writeBuffer, "%u", k); + read(k*1024, strlen(writeBuffer)+1, (uint8_t *)readBuffer); + bSame = strcmp(writeBuffer, readBuffer) ==0; + printf("[%u] %s == %s ? %s\n", k, writeBuffer, readBuffer, bSame ? "Success" : "Failure"); + } + } + + void write_pixel(const Point &p, uint8_t colour) override; + void write_pixel_span(const Point &p, uint l, uint8_t colour) override; + void read_pixel_span(const Point &p, uint l, uint8_t *data) override; + + int __not_in_flash_func(SpiSetBlocking)(const uint16_t uSrc, size_t uLen) + { + invalid_params_if(SPI, 0 > (int)uLen); + // Deliberately overflow FIFO, then clean up afterward, to minimise amount + // of APB polling required per halfword + for (size_t i = 0; i < uLen; ++i) { + while (!spi_is_writable(spi)) + tight_loop_contents(); + spi_get_hw(spi)->dr = uSrc; + } + + while (spi_is_readable(spi)) + (void)spi_get_hw(spi)->dr; + while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS) + tight_loop_contents(); + while (spi_is_readable(spi)) + (void)spi_get_hw(spi)->dr; + + // Don't leave overrun flag set + spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS; + + return (int)uLen; + } + + private: + void init(); + void write(uint32_t address, size_t len, const uint8_t *data); + void write(uint32_t address, size_t len, const uint8_t byte); + void read(uint32_t address, size_t len, uint8_t *data); + + uint32_t pointToAddress(const Point &p) + { + return start_address + (p.y * width) + p.x; + } + }; +} diff --git a/drivers/uc8159_inky7/CMakeLists.txt b/drivers/uc8159_inky7/CMakeLists.txt new file mode 100644 index 00000000..0e900886 --- /dev/null +++ b/drivers/uc8159_inky7/CMakeLists.txt @@ -0,0 +1 @@ +include(uc8159_inky7.cmake) \ No newline at end of file diff --git a/drivers/uc8159_inky7/uc8159_inky7.cmake b/drivers/uc8159_inky7/uc8159_inky7.cmake new file mode 100644 index 00000000..922d55de --- /dev/null +++ b/drivers/uc8159_inky7/uc8159_inky7.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME uc8159_inky7) +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) diff --git a/drivers/uc8159_inky7/uc8159_inky7.cpp b/drivers/uc8159_inky7/uc8159_inky7.cpp new file mode 100644 index 00000000..bc1b2416 --- /dev/null +++ b/drivers/uc8159_inky7/uc8159_inky7.cpp @@ -0,0 +1,206 @@ +#include "uc8159_inky7.hpp" + +#include +#include +#include + +namespace pimoroni { + + enum reg { + PSR = 0x00, + PWR = 0x01, + POF = 0x02, + PFS = 0x03, + PON = 0x04, + BTST1 = 0x05, + BTST2 = 0x06, + DSLP = 0x07, + BTST3 = 0x08, + 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, + T_VDCS = 0x84, + AGID = 0x86, + CMDH = 0xAA, + CCSET =0xE0, + PWS = 0xE3, + TSSET = 0xE6 // E5 or E6 + }; + + bool UC8159Inky7::is_busy() { + if(BUSY == PIN_UNUSED) { + if(absolute_time_diff_us(get_absolute_time(), timeout) > 0) { + return true; + } else { + return false; + } + } + return !gpio_get(BUSY); + } + + void UC8159Inky7::busy_wait(uint minimum_wait_ms) { + timeout = make_timeout_time_ms(minimum_wait_ms); + while(is_busy()) { + tight_loop_contents(); + } + } + + void UC8159Inky7::reset() { + gpio_put(RESET, 0); sleep_ms(10); + gpio_put(RESET, 1); sleep_ms(10); + busy_wait(); + } + + void UC8159Inky7::init() { + // configure spi interface and pins + spi_init(spi, 20'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 UC8159Inky7::setup() { + reset(); + busy_wait(); + + command(CMDH, {0x49, 0x55, 0x20, 0x08, 0x09, 0x18}); + command(PWR, {0x3F, 0x00, 0x32, 0x2A, 0x0E, 0x2A}); + if (rotation == ROTATE_0) { + command(PSR, {0x53, 0x69}); + } else { + command(PSR, {0x5F, 0x69}); + } + //command(PSR, {0x5F, 0x69}); + command(PFS, {0x00, 0x54, 0x00, 0x44}); + command(BTST1, {0x40, 0x1F, 0x1F, 0x2C}); + command(BTST2, {0x6F, 0x1F, 0x16, 0x25}); + command(BTST3, {0x6F, 0x1F, 0x1F, 0x22}); + command(IPC, {0x00, 0x04}); + command(PLL, {0x02}); + command(TSE, {0x00}); + command(CDI, {0x3F}); + command(TCON, {0x02, 0x00}); + command(TRES, {0x03, 0x20, 0x01, 0xE0}); + command(VDCS, {0x1E}); + command(T_VDCS, {0x00}); + command(AGID, {0x00}); + command(PWS, {0x2F}); + command(CCSET, {0x00}); + command(TSSET, {0x00}); + } + + void UC8159Inky7::set_blocking(bool blocking) { + this->blocking = blocking; + } + + void UC8159Inky7::power_off() { + busy_wait(); + command(POF); // turn off + } + + void UC8159Inky7::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 UC8159Inky7::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 UC8159Inky7::command(uint8_t reg, std::initializer_list values) { + command(reg, values.size(), (uint8_t *)values.begin()); + } + + void UC8159Inky7::update(PicoGraphics *graphics) { + if(graphics->pen_type != PicoGraphics::PEN_INKY7) return; // Incompatible buffer + + if(blocking) { + busy_wait(); + } + + setup(); + + gpio_put(CS, 0); + + uint8_t reg = DTM1; + gpio_put(DC, 0); // command mode + spi_write_blocking(spi, ®, 1); + + gpio_put(DC, 1); // data mode + + uint totalLength = 0; + gpio_put(CS, 1); + graphics->frame_convert(PicoGraphics::PEN_INKY7, [this, &totalLength](void *buf, size_t length) { + if (length > 0) { + gpio_put(CS, 0); + spi_write_blocking(spi, (const uint8_t*)buf, length); + totalLength += length; + gpio_put(CS, 1); + } + }); + + gpio_put(DC, 0); // data mode + + gpio_put(CS, 1); + + busy_wait(); + + command(PON, {0}); // turn on + busy_wait(200); + + command(DRF, {0}); // start display refresh + busy_wait(200); + + if(blocking) { + busy_wait(32 * 1000); + + command(POF); // turn off + } else { + timeout = make_timeout_time_ms(32 * 1000); + } + } + +} diff --git a/drivers/uc8159_inky7/uc8159_inky7.hpp b/drivers/uc8159_inky7/uc8159_inky7.hpp new file mode 100644 index 00000000..805dff47 --- /dev/null +++ b/drivers/uc8159_inky7/uc8159_inky7.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include + +#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 UC8159Inky7 : public DisplayDriver { + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; + + // interface pins with our standard defaults where appropriate + uint CS = SPI_BG_FRONT_CS; + uint DC = 28; // 27; + uint SCK = SPI_DEFAULT_SCK; + uint MOSI = SPI_DEFAULT_MOSI; + uint BUSY = PIN_UNUSED; + uint RESET = 27; //25; + + absolute_time_t timeout; + + bool blocking = false; + + public: + enum colour : uint8_t { + BLACK = 0, + WHITE = 1, + GREEN = 2, + BLUE = 3, + RED = 4, + YELLOW = 5, + ORANGE = 6, + CLEAN = 7 + }; + + UC8159Inky7(uint16_t width, uint16_t height) : UC8159Inky7(width, height, ROTATE_0, {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 28, PIN_UNUSED}) {}; + + UC8159Inky7(uint16_t width, uint16_t height, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : UC8159Inky7(width, height, ROTATE_0, pins, busy, reset) {}; + + UC8159Inky7(uint16_t width, uint16_t height, Rotation rotation, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : + DisplayDriver(width, height, rotation), + 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(uint minimum_wait_ms=0); + void reset(); + void power_off(); + + bool is_busy() override; + void update(PicoGraphics *graphics) override; + + void set_blocking(bool blocking); + + private: + void init(); + void setup(); + void command(uint8_t reg, size_t len, const uint8_t *data); + void command(uint8_t reg, std::initializer_list 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); + }; + +} diff --git a/examples/inky_frame/CMakeLists.txt b/examples/inky_frame/CMakeLists.txt index 572bb32a..6bf38cff 100644 --- a/examples/inky_frame/CMakeLists.txt +++ b/examples/inky_frame/CMakeLists.txt @@ -1,3 +1,4 @@ include(inky_frame_jpeg_image.cmake) include(inky_frame_sleepy_head.cmake) -include(inky_frame_day_planner.cmake) \ No newline at end of file +include(inky_frame_day_planner.cmake) +include(inky_frame7_test.cmake) \ No newline at end of file diff --git a/examples/inky_frame/inky_frame7_test.cmake b/examples/inky_frame/inky_frame7_test.cmake new file mode 100644 index 00000000..aa20e1da --- /dev/null +++ b/examples/inky_frame/inky_frame7_test.cmake @@ -0,0 +1,14 @@ +set(OUTPUT_NAME inky_frame7_test) + +add_executable( + ${OUTPUT_NAME} + inky_frame7_test.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib psram_display uc8159_inky7 inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics) + +pico_enable_stdio_usb(${OUTPUT_NAME} 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/inky_frame/inky_frame7_test.cpp b/examples/inky_frame/inky_frame7_test.cpp new file mode 100644 index 00000000..481215bc --- /dev/null +++ b/examples/inky_frame/inky_frame7_test.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include +#include "drivers/psram_display/psram_display.hpp" +#include "drivers/uc8159_inky7/uc8159_inky7.hpp" + +using namespace pimoroni; + +int main() { + stdio_init_all(); + + PSRamDisplay ramDisplay(800, 480); + PicoGraphics_PenInky7 graphics(800, 480, ramDisplay); + UC8159Inky7 uc8159(800,400); + + graphics.set_pen(1); + graphics.clear(); + + for(int i =0 ; i < 100 ; i++) + { + uint size = 25 + (rand() % 50); + uint x = rand() % graphics.bounds.w; + uint y = rand() % graphics.bounds.h; + + graphics.set_pen(0); + graphics.circle(Point(x, y), size); + + graphics.set_pen(2+(i%5)); + graphics.circle(Point(x, y), size-2); + } + + uc8159.update(&graphics); + + while(true) + sleep_ms(1000); + + return 0; +} diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index 67fdd79a..40c6f78a 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -9,6 +9,7 @@ add_library(pico_graphics ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb332.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb565.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb888.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_inky7.cpp ) target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 88474e23..e75524aa 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -168,6 +168,7 @@ namespace pimoroni { PEN_RGB332, PEN_RGB565, PEN_RGB888, + PEN_INKY7 }; void *frame_buffer; @@ -486,4 +487,32 @@ namespace pimoroni { virtual void cleanup() {}; }; + template class IDirectDisplayDriver { + public: + virtual void write_pixel(const Point &p, T colour) = 0; + virtual void write_pixel_span(const Point &p, uint l, T colour) = 0; + + virtual void read_pixel(const Point &p, T &data) {}; + virtual void read_pixel_span(const Point &p, uint l, T *data) {}; + }; + + + class PicoGraphics_PenInky7 : public PicoGraphics { + public: + RGB src_color; + RGB565 color; + IDirectDisplayDriver &driver; + + PicoGraphics_PenInky7(uint16_t width, uint16_t height, IDirectDisplayDriver &direct_display_driver); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; + int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; + void frame_convert(PenType type, conversion_callback_func callback) override; + static size_t buffer_size(uint w, uint h) { + return w * h; + } + }; } diff --git a/libraries/pico_graphics/pico_graphics_pen_inky7.cpp b/libraries/pico_graphics/pico_graphics_pen_inky7.cpp new file mode 100644 index 00000000..3c10c98c --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_inky7.cpp @@ -0,0 +1,49 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + PicoGraphics_PenInky7::PicoGraphics_PenInky7(uint16_t width, uint16_t height, IDirectDisplayDriver &direct_display_driver) + : PicoGraphics(width, height, nullptr), + driver(direct_display_driver) { + this->pen_type = PEN_INKY7; + } + void PicoGraphics_PenInky7::set_pen(uint c) { + color = c & 0x7; + } + void PicoGraphics_PenInky7::set_pen(uint8_t r, uint8_t g, uint8_t b) { + } + int PicoGraphics_PenInky7::create_pen(uint8_t r, uint8_t g, uint8_t b) { + return 0; + } + void PicoGraphics_PenInky7::set_pixel(const Point &p) { + driver.write_pixel(p, color); + } + void PicoGraphics_PenInky7::set_pixel_span(const Point &p, uint l) { + driver.write_pixel_span(p, l, color); + } + void PicoGraphics_PenInky7::frame_convert(PenType type, conversion_callback_func callback) { + if(type == PEN_INKY7) { + uint byte_count = bounds.w/2; + uint8_t buffer[bounds.w]; + + for(int32_t r = 0; r < bounds.h; r++) + { + driver.read_pixel_span(Point(0, r), bounds.w, buffer); + // for(int y=0; y < 800; y++) + // buffer[y] = rand() % 7; + + // convert byte storage to nibble storage + uint8_t *pDst = buffer; + uint8_t *pSrc = buffer; + + for(uint c = 0; c < byte_count; c++) + { + uint8_t nibble = ((*pSrc++) << 4); + nibble |= ((*pSrc++) & 0xf); + *pDst++ = nibble; + } + + callback(buffer, byte_count); + } + } + } +} \ No newline at end of file