diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index d0d9e09c..d1978c9d 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -39,4 +39,7 @@ 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(inky73) +add_subdirectory(shiftregister) \ No newline at end of file diff --git a/drivers/inky73/CMakeLists.txt b/drivers/inky73/CMakeLists.txt new file mode 100644 index 00000000..0c783cc6 --- /dev/null +++ b/drivers/inky73/CMakeLists.txt @@ -0,0 +1 @@ +include(inky73.cmake) \ No newline at end of file diff --git a/drivers/inky73/inky73.cmake b/drivers/inky73/inky73.cmake new file mode 100644 index 00000000..0489400e --- /dev/null +++ b/drivers/inky73/inky73.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME inky73) +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 shiftregister) diff --git a/drivers/inky73/inky73.cpp b/drivers/inky73/inky73.cpp new file mode 100644 index 00000000..be54affa --- /dev/null +++ b/drivers/inky73/inky73.cpp @@ -0,0 +1,196 @@ +#include "inky73.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 Inky73::is_busy() { + return !(sr.read() & 128); + } + + void Inky73::busy_wait() { + while(is_busy()) { + tight_loop_contents(); + } + } + + void Inky73::reset() { + gpio_put(RESET, 0); sleep_ms(10); + gpio_put(RESET, 1); sleep_ms(10); + busy_wait(); + } + + void Inky73::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(SCK, GPIO_FUNC_SPI); + gpio_set_function(MOSI, GPIO_FUNC_SPI); + }; + + void Inky73::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 Inky73::set_blocking(bool blocking) { + this->blocking = blocking; + } + + void Inky73::power_off() { + busy_wait(); + command(POF); // turn off + } + + void Inky73::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 Inky73::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 Inky73::command(uint8_t reg, std::initializer_list values) { + command(reg, values.size(), (uint8_t *)values.begin()); + } + + void Inky73::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(); + + command(DRF, {0}); // start display refresh + busy_wait(); + + if(blocking) { + busy_wait(); + + command(POF); // turn off + } + } + + bool Inky73::is_pressed(Button button) { + return sr.read() & button; + } + +} diff --git a/drivers/inky73/inky73.hpp b/drivers/inky73/inky73.hpp new file mode 100644 index 00000000..14c7b6ff --- /dev/null +++ b/drivers/inky73/inky73.hpp @@ -0,0 +1,94 @@ +#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" +#include "drivers/shiftregister/shiftregister.hpp" + +namespace pimoroni { + + class Inky73 : 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 RESET = 27; //25; + + uint SR_CLOCK = 8; + uint SR_LATCH = 9; + uint SR_DATA = 10; + + bool blocking = false; + + ShiftRegister sr = ShiftRegister(SR_CLOCK, SR_LATCH, SR_DATA); + + public: + enum Button : uint8_t { + BUTTON_A = 1, + BUTTON_B = 2, + BUTTON_C = 4, + BUTTON_D = 8, + BUTTON_E = 16 + }; + + enum colour : uint8_t { + BLACK = 0, + WHITE = 1, + GREEN = 2, + BLUE = 3, + RED = 4, + YELLOW = 5, + ORANGE = 6, + CLEAN = 7 + }; + + Inky73(uint16_t width, uint16_t height) : Inky73(width, height, ROTATE_0, {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 28, PIN_UNUSED}) {}; + + Inky73(uint16_t width, uint16_t height, SPIPins pins, uint reset=27) : Inky73(width, height, ROTATE_0, pins, reset) {}; + + Inky73(uint16_t width, uint16_t height, Rotation rotation, SPIPins pins, uint reset=27) : + DisplayDriver(width, height, rotation), + spi(pins.spi), + CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi), RESET(reset) { + init(); + } + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + void busy_wait(); + void reset(); + void power_off(); + + bool is_busy() override; + void update(PicoGraphics *graphics) override; + + void set_blocking(bool blocking); + + bool is_pressed(Button button); + + 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/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/shiftregister/CMakeLists.txt b/drivers/shiftregister/CMakeLists.txt new file mode 100644 index 00000000..5dc6ee3b --- /dev/null +++ b/drivers/shiftregister/CMakeLists.txt @@ -0,0 +1 @@ +include(shiftregister.cmake) \ No newline at end of file diff --git a/drivers/shiftregister/shiftregister.cmake b/drivers/shiftregister/shiftregister.cmake new file mode 100644 index 00000000..3959a18c --- /dev/null +++ b/drivers/shiftregister/shiftregister.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME shiftregister) +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) diff --git a/drivers/shiftregister/shiftregister.cpp b/drivers/shiftregister/shiftregister.cpp new file mode 100644 index 00000000..d03172d1 --- /dev/null +++ b/drivers/shiftregister/shiftregister.cpp @@ -0,0 +1,5 @@ +#include "shiftregister.hpp" + +namespace pimoroni { + +} \ No newline at end of file diff --git a/drivers/shiftregister/shiftregister.hpp b/drivers/shiftregister/shiftregister.hpp new file mode 100644 index 00000000..0002b70e --- /dev/null +++ b/drivers/shiftregister/shiftregister.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "pico/stdlib.h" +#include "hardware/spi.h" +#include "hardware/gpio.h" + +namespace pimoroni { + template class ShiftRegister { + private: + uint CLOCK = 0; + uint LATCH = 0; + uint DATA = 0; + + public: + ShiftRegister(uint clock, uint latch, uint data) : + CLOCK(clock), + LATCH(latch), + DATA(data) { + gpio_init(CLOCK); + gpio_set_function(CLOCK, GPIO_FUNC_SIO); + gpio_set_dir(CLOCK, GPIO_OUT); + + gpio_init(LATCH); + gpio_set_function(LATCH, GPIO_FUNC_SIO); + gpio_set_dir(LATCH, GPIO_OUT); + + gpio_init(DATA); + gpio_set_function(DATA, GPIO_FUNC_SIO); + gpio_set_dir(DATA, GPIO_IN); + } + T read() { + gpio_put(LATCH, 0); + __asm("NOP;"); + gpio_put(LATCH, 1); + __asm("NOP;"); + T out = 0; + for (auto i = 0u; i < sizeof(T) * 8; i++) { + out <<= 1; + out |= gpio_get(DATA); + gpio_put(CLOCK, 1); + __asm("NOP;"); + gpio_put(CLOCK, 0); + __asm("NOP;"); + } + return out; + } + }; +} \ No newline at end of file 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..9ea9f9d9 --- /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 inky73 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..c7794fa0 --- /dev/null +++ b/examples/inky_frame/inky_frame7_test.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include +#include "drivers/psram_display/psram_display.hpp" +#include "drivers/inky73/inky73.hpp" + +using namespace pimoroni; + +uint LED_PIN = 8; + +int main() { + stdio_init_all(); + + gpio_init(LED_PIN); + gpio_set_function(LED_PIN, GPIO_FUNC_SIO); + gpio_set_dir(LED_PIN, GPIO_OUT); + + PSRamDisplay ramDisplay(800, 480); + PicoGraphics_PenInky7 graphics(800, 480, ramDisplay); + Inky73 inky7(800,400); + + while (true) { + while(!inky7.is_pressed(Inky73::BUTTON_A)) { + sleep_ms(10); + } + 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); + } + + gpio_put(LED_PIN, 1); + inky7.update(&graphics); + gpio_put(LED_PIN, 0); + } + + 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..72f78203 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,62 @@ 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: + static const uint16_t palette_size = 8; + RGB palette[8] = { + /* + {0x2b, 0x2a, 0x37}, + {0xdc, 0xcb, 0xba}, + {0x35, 0x56, 0x33}, + {0x33, 0x31, 0x47}, + {0x9c, 0x3b, 0x2e}, + {0xd3, 0xa9, 0x34}, + {0xab, 0x58, 0x37}, + {0xb2, 0x8e, 0x67} + */ + { 0, 0, 0}, // black + {255, 255, 255}, // white + { 0, 255, 0}, // green + { 0, 0, 255}, // blue + {255, 0, 0}, // red + {255, 255, 0}, // yellow + {255, 128, 0}, // orange + {220, 180, 200} // clean / taupe?! + }; + + std::array, 512> candidate_cache; + bool cache_built = false; + std::array candidates; + + 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 get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); + void set_pixel_dither(const Point &p, const RGB &c) 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..37891599 --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_inky7.cpp @@ -0,0 +1,92 @@ +#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::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { + RGB error; + for(size_t i = 0; i < candidates.size(); i++) { + candidates[i] = (col + error).closest(palette, len); + error += (col - palette[candidates[i]]); + } + + // sort by a rough approximation of luminance, this ensures that neighbouring + // pixels in the dither matrix are at extreme opposites of luminence + // giving a more balanced output + std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) { + return palette[a].luminance() > palette[b].luminance(); + }); + } + void PicoGraphics_PenInky7::set_pixel_dither(const Point &p, const RGB &c) { + if(!bounds.contains(p)) return; + + if(!cache_built) { + for(uint i = 0; i < 512; i++) { + uint r = (i & 0x1c0) >> 1; + uint g = (i & 0x38) << 2; + uint b = (i & 0x7) << 5; + RGB cache_col( + r | (r >> 3) | (r >> 6), + g | (g >> 3) | (g >> 6), + b | (b >> 3) | (b >> 6) + ); + get_dither_candidates(cache_col, palette, palette_size, candidate_cache[i]); + } + cache_built = true; + } + + uint cache_key = ((c.r & 0xE0) << 1) | ((c.g & 0xE0) >> 2) | ((c.b & 0xE0) >> 5); + //get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + //color = candidates[pattern[pattern_index]]; + color = candidate_cache[cache_key][dither16_pattern[pattern_index]]; + set_pixel(p); + } + 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 diff --git a/micropython/_board/board-fixup.sh b/micropython/_board/board-fixup.sh index ad62502c..def0254e 100755 --- a/micropython/_board/board-fixup.sh +++ b/micropython/_board/board-fixup.sh @@ -16,6 +16,6 @@ if [[ ! -d "$MPY_DIR/boards/$BOARD" ]] && [[ -d "$FIXUP_DIR/$NAME/$BOARD/" ]]; t fi if [[ -f "$FIXUP_DIR/$NAME/fixup.sh" ]]; then - echo "Running custom fixup[.sh" + echo "Running custom fixup.sh" bash "$FIXUP_DIR/$NAME/fixup.sh" "$FIXUP_DIR/$NAME" "$MPY_DIR" -fi \ No newline at end of file +fi diff --git a/micropython/_board/picow_enviro/PICO_W_ENVIRO/mpconfigboard.h b/micropython/_board/picow_enviro/PICO_W_ENVIRO/mpconfigboard.h index 43a9fbaf..227e7e3f 100644 --- a/micropython/_board/picow_enviro/PICO_W_ENVIRO/mpconfigboard.h +++ b/micropython/_board/picow_enviro/PICO_W_ENVIRO/mpconfigboard.h @@ -17,9 +17,6 @@ // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose // #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 -#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT -#ifdef CYW43_WL_GPIO_LED_PIN -#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN -#endif +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT #define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) diff --git a/micropython/_board/picow_enviro/PICO_W_ENVIRO/pins.csv b/micropython/_board/picow_enviro/PICO_W_ENVIRO/pins.csv new file mode 100644 index 00000000..8debb632 --- /dev/null +++ b/micropython/_board/picow_enviro/PICO_W_ENVIRO/pins.csv @@ -0,0 +1,30 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 +LED,EXT_GPIO0 diff --git a/micropython/_board/picow_inky_frame/PICO_W_INKY/manifest.py b/micropython/_board/picow_inky_frame/PICO_W_INKY/manifest.py index c957ba5f..b446b0a0 100644 --- a/micropython/_board/picow_inky_frame/PICO_W_INKY/manifest.py +++ b/micropython/_board/picow_inky_frame/PICO_W_INKY/manifest.py @@ -3,4 +3,5 @@ include("../manifest.py") require("mip") require("ntptime") require("urequests") +require("urllib.urequest") require("umqtt.simple") \ No newline at end of file diff --git a/micropython/_board/picow_inky_frame/PICO_W_INKY/mpconfigboard.h b/micropython/_board/picow_inky_frame/PICO_W_INKY/mpconfigboard.h index 43a9fbaf..227e7e3f 100644 --- a/micropython/_board/picow_inky_frame/PICO_W_INKY/mpconfigboard.h +++ b/micropython/_board/picow_inky_frame/PICO_W_INKY/mpconfigboard.h @@ -17,9 +17,6 @@ // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose // #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 -#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT -#ifdef CYW43_WL_GPIO_LED_PIN -#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN -#endif +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT #define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) diff --git a/micropython/_board/picow_inky_frame/PICO_W_INKY/pins.csv b/micropython/_board/picow_inky_frame/PICO_W_INKY/pins.csv new file mode 100644 index 00000000..8debb632 --- /dev/null +++ b/micropython/_board/picow_inky_frame/PICO_W_INKY/pins.csv @@ -0,0 +1,30 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 +LED,EXT_GPIO0 diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index fb0ba23c..3b22452a 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -145,7 +145,10 @@ MICROPY_EVENT_POLL_HOOK } else if (current_graphics->pen_type == PicoGraphics::PEN_RGB888) { current_graphics->set_pen(RGB((RGB565)pDraw->pPixels[i]).to_rgb888()); current_graphics->pixel({pDraw->x + x, pDraw->y + y}); - } else if (current_graphics->pen_type == PicoGraphics::PEN_P8 || current_graphics->pen_type == PicoGraphics::PEN_P4 || current_graphics->pen_type == PicoGraphics::PEN_3BIT) { + } else if (current_graphics->pen_type == PicoGraphics::PEN_P8 + || current_graphics->pen_type == PicoGraphics::PEN_P4 + || current_graphics->pen_type == PicoGraphics::PEN_3BIT + || current_graphics->pen_type == PicoGraphics::PEN_INKY7) { current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)pDraw->pPixels[i])); } else { current_graphics->set_pen(pDraw->pPixels[i]); @@ -262,6 +265,7 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args case PicoGraphics::PEN_P8: case PicoGraphics::PEN_P4: case PicoGraphics::PEN_3BIT: + case PicoGraphics::PEN_INKY7: self->jpeg->setPixelType(RGB565_BIG_ENDIAN); break; // TODO 2-bit is currently unsupported diff --git a/micropython/modules/picographics/micropython.cmake b/micropython/modules/picographics/micropython.cmake index 42455790..888561f4 100644 --- a/micropython/modules/picographics/micropython.cmake +++ b/micropython/modules/picographics/micropython.cmake @@ -11,6 +11,9 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/uc8151/uc8151.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/uc8159/uc8159.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7567/st7567.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/inky73/inky73.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/shiftregister/shiftregister.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/psram_display/psram_display.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 @@ -20,6 +23,7 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb332.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb565.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb888.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_inky7.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp ) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 6d801fb6..6a39bbff 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -150,6 +150,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X64), MP_ROM_INT(DISPLAY_INTERSTATE75_128X64) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_192X64), MP_ROM_INT(DISPLAY_INTERSTATE75_192X64) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_256X64), MP_ROM_INT(DISPLAY_INTERSTATE75_256X64) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME_7), MP_ROM_INT(DISPLAY_INKY_FRAME_7) }, { MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index b394bcaf..ba45d5f0 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -4,6 +4,8 @@ #include "drivers/uc8151/uc8151.hpp" #include "drivers/uc8159/uc8159.hpp" #include "drivers/st7567/st7567.hpp" +#include "drivers/inky73/inky73.hpp" +#include "drivers/psram_display/psram_display.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" @@ -192,6 +194,14 @@ 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_RGB888; break; + case DISPLAY_INKY_FRAME_7: + width = 800; + height = 480; + bus_type = BUS_SPI; + // Portrait to match labelling + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + if(pen_type == -1) pen_type = PEN_INKY7; + break; default: return false; } @@ -214,6 +224,8 @@ size_t get_required_buffer_size(PicoGraphicsPenType pen_type, uint width, uint h return PicoGraphics_PenRGB565::buffer_size(width, height); case PEN_RGB888: return PicoGraphics_PenRGB888::buffer_size(width, height); + case PEN_INKY7: + return PicoGraphics_PenInky7::buffer_size(width, height); default: return 0; } @@ -276,7 +288,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size self->i2c = (_PimoroniI2C_obj_t *)MP_OBJ_TO_PTR(PimoroniI2C_make_new(&PimoroniI2C_type, 0, 0, nullptr)); i2c_bus = (pimoroni::I2C *)(self->i2c->i2c); } else if (bus_type == BUS_SPI) { - if(display == DISPLAY_INKY_FRAME || display == DISPLAY_INKY_FRAME_4) { + if(display == DISPLAY_INKY_FRAME || display == DISPLAY_INKY_FRAME_4 || display == DISPLAY_INKY_FRAME_7) { spi_bus = {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 28, PIN_UNUSED}; } else if (display == DISPLAY_INKY_PACK) { spi_bus = {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 20, PIN_UNUSED}; @@ -292,6 +304,11 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size // TODO grab BUSY and RESET from ARG_extra_pins self->display = m_new_class(UC8159, width, height, (Rotation)rotate, spi_bus); + } else if (display == DISPLAY_INKY_FRAME_7) { + pen_type = PEN_INKY7; + // TODO grab BUSY and RESET from ARG_extra_pins + self->display = m_new_class(Inky73, width, height, (Rotation)rotate, spi_bus); + } else if (display == DISPLAY_TUFTY_2040) { self->display = m_new_class(ST7789, width, height, (Rotation)rotate, parallel_bus); @@ -324,15 +341,19 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size size_t required_size = get_required_buffer_size((PicoGraphicsPenType)pen_type, width, height); if(required_size == 0) mp_raise_ValueError("Unsupported pen type!"); - 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)(required_size)) { - mp_raise_ValueError("Supplied buffer is too small!"); - } + if(pen_type == PEN_INKY7) { + self->buffer = m_new_class(PSRamDisplay, width, height); } else { - self->buffer = m_new(uint8_t, required_size); + 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)(required_size)) { + mp_raise_ValueError("Supplied buffer is too small!"); + } + } else { + self->buffer = m_new(uint8_t, required_size); + } } // Create an instance of the graphics library @@ -363,6 +384,9 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size case PEN_RGB888: self->graphics = m_new_class(PicoGraphics_PenRGB888, self->display->width, self->display->height, self->buffer); break; + case PEN_INKY7: + self->graphics = m_new_class(PicoGraphics_PenInky7, self->display->width, self->display->height, *(IDirectDisplayDriver *)self->buffer); + break; default: break; } @@ -376,7 +400,7 @@ 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 - if (display != DISPLAY_INKY_FRAME && display != DISPLAY_INKY_FRAME_4 && display != DISPLAY_INKY_PACK) { + if (display != DISPLAY_INKY_FRAME && display != DISPLAY_INKY_FRAME_4 && display != DISPLAY_INKY_PACK && display != DISPLAY_INKY_FRAME_7) { self->display->update(self->graphics); } diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index d07ad4fd..2393ea61 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -23,7 +23,8 @@ enum PicoGraphicsDisplay { DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, - DISPLAY_INTERSTATE75_256X64, + DISPLAY_INTERSTATE75_256X64, + DISPLAY_INKY_FRAME_7, }; enum PicoGraphicsPenType { @@ -34,7 +35,8 @@ enum PicoGraphicsPenType { PEN_P8, PEN_RGB332, PEN_RGB565, - PEN_RGB888 + PEN_RGB888, + PEN_INKY7, }; enum PicoGraphicsBusType { diff --git a/micropython/modules_py/inky_frame.py b/micropython/modules_py/inky_frame.py index 283ee70d..1892a6ed 100644 --- a/micropython/modules_py/inky_frame.py +++ b/micropython/modules_py/inky_frame.py @@ -14,6 +14,9 @@ LED_C = 13 LED_D = 14 LED_E = 15 +LED_BUSY = 6 +LED_WIFI = 7 + SHIFT_STATE = get_shift_state() reset_shift_state() @@ -66,3 +69,6 @@ button_b = Button(sr, 6, LED_B) button_c = Button(sr, 5, LED_C) button_d = Button(sr, 4, LED_D) button_e = Button(sr, 3, LED_E) + +led_busy = Pin(LED_BUSY, Pin.OUT) +led_wifi = Pin(LED_WIFI, Pin.OUT)