From c1816ae9d65df4dd734af9802508766d577b7711 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 29 Sep 2022 13:46:48 +0100 Subject: [PATCH 1/7] PicoGraphics: MicroPython support for Inky Frame 4.0 --- micropython/modules/picographics/picographics.c | 1 + micropython/modules/picographics/picographics.cpp | 13 ++++++++++--- micropython/modules/picographics/picographics.h | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 590432e1..9c67df17 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -124,6 +124,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { 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_DISPLAY_INKY_FRAME_4), MP_ROM_INT(DISPLAY_INKY_FRAME_4) }, { MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) }, { MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 915d4262..b14d1561 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -105,6 +105,13 @@ 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_P4; break; + case DISPLAY_INKY_FRAME_4: + width = 640; + height = 400; + bus_type = BUS_SPI; + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + if(pen_type == -1) pen_type = PEN_P4; + break; default: return false; } @@ -187,7 +194,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) { + if(display == DISPLAY_INKY_FRAME || display == DISPLAY_INKY_FRAME_4) { 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}; @@ -196,7 +203,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } // Try to create an appropriate display driver - if (display == DISPLAY_INKY_FRAME) { + if (display == DISPLAY_INKY_FRAME || display == DISPLAY_INKY_FRAME_4) { pen_type = PEN_3BIT; // FORCE to 3BIT // TODO grab BUSY and RESET from ARG_extra_pins self->display = m_new_class(UC8159, width, height, spi_bus); @@ -273,7 +280,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_PACK) { + if (display != DISPLAY_INKY_FRAME && display != DISPLAY_INKY_FRAME_4 && display != DISPLAY_INKY_PACK) { self->display->update(self->graphics); } diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 55d9d765..43b68dc0 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -12,7 +12,8 @@ enum PicoGraphicsDisplay { DISPLAY_LCD_160X80, DISPLAY_I2C_OLED_128X128, DISPLAY_INKY_PACK, - DISPLAY_INKY_FRAME + DISPLAY_INKY_FRAME, + DISPLAY_INKY_FRAME_4 }; enum PicoGraphicsPenType { From 7f02501fa6007ffdb7612e859745c9a0c9c2e9dd Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 29 Sep 2022 14:05:21 +0100 Subject: [PATCH 2/7] UC8159: Alternate resolution support. --- drivers/uc8159/uc8159.cpp | 40 ++++++++++++++----- drivers/uc8159/uc8159.hpp | 4 ++ .../modules/picographics/picographics.cpp | 2 +- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/uc8159/uc8159.cpp b/drivers/uc8159/uc8159.cpp index f8572f93..257d6cdb 100644 --- a/drivers/uc8159/uc8159.cpp +++ b/drivers/uc8159/uc8159.cpp @@ -88,16 +88,27 @@ namespace pimoroni { 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}); + uint8_t dimensions[4] = { + uint8_t(width >> 8), + uint8_t(width), + uint8_t(height >> 8), + uint8_t(height) + }; + + if (width == 600) { + command(PSR, {0xE3, 0x08}); + } else { + command(PSR, {0xA3, 0x08}); + } + command(PWR, {0x37, 0x00, 0x23, 0x23}); + command(PFS, {0x00}); + command(BTST, {0xC7, 0xC7, 0x1D}); + command(PLL, {0x3C}); + command(TSC, {0x00}); + command(CDI, {0x37}); + command(TCON, {0x22}); + command(TRES, 4, dimensions); + command(PWS, {0xAA}); sleep_ms(100); @@ -154,6 +165,15 @@ namespace pimoroni { spi_write_blocking(spi, ®, 1); gpio_put(DC, 1); // data mode + + // HACK: Output 48 rows of data since our buffer is 400px tall + // but the display has no offset configuration and H/V scan + // are reversed. + // Any garbage data will do. + // 2px per byte, so we need width * 24 bytes + if(height == 400) { + spi_write_blocking(spi, (uint8_t *)graphics->frame_buffer, width * 24); + } graphics->frame_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) { if (length > 0) { spi_write_blocking(spi, (const uint8_t*)buf, length); diff --git a/drivers/uc8159/uc8159.hpp b/drivers/uc8159/uc8159.hpp index 0ed608bf..5cf3d12a 100644 --- a/drivers/uc8159/uc8159.hpp +++ b/drivers/uc8159/uc8159.hpp @@ -16,6 +16,8 @@ namespace pimoroni { // Variables //-------------------------------------------------- private: + uint16_t width; + uint16_t height; spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; // interface pins with our standard defaults where appropriate @@ -46,6 +48,8 @@ namespace pimoroni { UC8159(uint16_t width, uint16_t height, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : DisplayDriver(width, height, ROTATE_0), + width(width), + height(height), spi(pins.spi), CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi), BUSY(busy), RESET(reset) { init(); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index b14d1561..b3396409 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -109,7 +109,7 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, width = 640; height = 400; bus_type = BUS_SPI; - if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + if(rotate == -1) rotate = (int)Rotation::ROTATE_180; if(pen_type == -1) pen_type = PEN_P4; break; default: From 6aa1bbd2713da87dd78e08482e1e4b186bb4f6ee Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 30 Sep 2022 20:13:25 +0100 Subject: [PATCH 3/7] UC8159: 0/180 degree rotation support. --- drivers/uc8159/uc8159.cpp | 14 +++++++++++--- drivers/uc8159/uc8159.hpp | 12 +++++------- micropython/modules/picographics/picographics.cpp | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/uc8159/uc8159.cpp b/drivers/uc8159/uc8159.cpp index 257d6cdb..7f1fde21 100644 --- a/drivers/uc8159/uc8159.cpp +++ b/drivers/uc8159/uc8159.cpp @@ -96,9 +96,17 @@ namespace pimoroni { }; if (width == 600) { - command(PSR, {0xE3, 0x08}); + if (rotation == ROTATE_0) { + command(PSR, {0xE3, 0x08}); + } else { + command(PSR, {0xEF, 0x08}); + } } else { - command(PSR, {0xA3, 0x08}); + if (rotation == ROTATE_0) { + command(PSR, {0xA3, 0x08}); + } else { + command(PSR, {0xAF, 0x08}); + } } command(PWR, {0x37, 0x00, 0x23, 0x23}); command(PFS, {0x00}); @@ -171,7 +179,7 @@ namespace pimoroni { // are reversed. // Any garbage data will do. // 2px per byte, so we need width * 24 bytes - if(height == 400) { + if(height == 400 && rotation == ROTATE_0) { spi_write_blocking(spi, (uint8_t *)graphics->frame_buffer, width * 24); } graphics->frame_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) { diff --git a/drivers/uc8159/uc8159.hpp b/drivers/uc8159/uc8159.hpp index 5cf3d12a..21f0d48f 100644 --- a/drivers/uc8159/uc8159.hpp +++ b/drivers/uc8159/uc8159.hpp @@ -16,8 +16,6 @@ namespace pimoroni { // Variables //-------------------------------------------------- private: - uint16_t width; - uint16_t height; spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; // interface pins with our standard defaults where appropriate @@ -44,12 +42,12 @@ namespace pimoroni { 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, 28, PIN_UNUSED}) {}; + UC8159(uint16_t width, uint16_t height) : UC8159(width, height, ROTATE_0, {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 28, PIN_UNUSED}) {}; - UC8159(uint16_t width, uint16_t height, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : - DisplayDriver(width, height, ROTATE_0), - width(width), - height(height), + UC8159(uint16_t width, uint16_t height, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : UC8159(width, height, ROTATE_0, pins, busy, reset) {}; + + UC8159(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(); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index b3396409..7dfaf4ba 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -109,7 +109,7 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, width = 640; height = 400; bus_type = BUS_SPI; - if(rotate == -1) rotate = (int)Rotation::ROTATE_180; + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; if(pen_type == -1) pen_type = PEN_P4; break; default: @@ -206,7 +206,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size if (display == DISPLAY_INKY_FRAME || display == DISPLAY_INKY_FRAME_4) { pen_type = PEN_3BIT; // FORCE to 3BIT // TODO grab BUSY and RESET from ARG_extra_pins - self->display = m_new_class(UC8159, width, height, spi_bus); + self->display = m_new_class(UC8159, width, height, (Rotation)rotate, spi_bus); } else if (display == DISPLAY_TUFTY_2040) { self->display = m_new_class(ST7789, width, height, (Rotation)rotate, parallel_bus); From 14fec0406d94b423435065cdd4091bc94c6e0771 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 3 Oct 2022 13:46:43 +0100 Subject: [PATCH 4/7] Inky Frame: Update examples to support 4.0". --- .../examples/inky_frame/inky_frame_daily_activity.py | 5 +++-- micropython/examples/inky_frame/inky_frame_news.py | 5 +++-- .../examples/inky_frame/inky_frame_placekitten.py | 3 ++- .../examples/inky_frame/inky_frame_quote_of_the_day.py | 5 +++-- .../examples/inky_frame/inky_frame_random_joke.py | 7 ++++--- micropython/examples/inky_frame/inky_frame_xkcd_daily.py | 9 ++++++--- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/micropython/examples/inky_frame/inky_frame_daily_activity.py b/micropython/examples/inky_frame/inky_frame_daily_activity.py index cdb73277..7e1b039e 100644 --- a/micropython/examples/inky_frame/inky_frame_daily_activity.py +++ b/micropython/examples/inky_frame/inky_frame_daily_activity.py @@ -4,7 +4,8 @@ from network_manager import NetworkManager import uasyncio import ujson from urllib import urequest -from picographics import PicoGraphics, DISPLAY_INKY_FRAME +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" from machine import Pin from pimoroni_i2c import PimoroniI2C from pcf85063a import PCF85063A @@ -38,7 +39,7 @@ def status_handler(mode, status, ip): network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler) gc.collect() -graphics = PicoGraphics(DISPLAY_INKY_FRAME) +graphics = PicoGraphics(DISPLAY) WIDTH, HEIGHT = graphics.get_bounds() gc.collect() diff --git a/micropython/examples/inky_frame/inky_frame_news.py b/micropython/examples/inky_frame/inky_frame_news.py index 14f8d828..5340d444 100644 --- a/micropython/examples/inky_frame/inky_frame_news.py +++ b/micropython/examples/inky_frame/inky_frame_news.py @@ -1,4 +1,5 @@ -from picographics import PicoGraphics, DISPLAY_INKY_FRAME +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" from network_manager import NetworkManager import uasyncio from urllib import urequest @@ -27,7 +28,7 @@ URL = "http://feeds.bbci.co.uk/news/technology/rss.xml" # Frequent updates will reduce battery life! UPDATE_INTERVAL = 60 * 1 -graphics = PicoGraphics(DISPLAY_INKY_FRAME) +graphics = PicoGraphics(DISPLAY) WIDTH, HEIGHT = graphics.get_bounds() graphics.set_font("bitmap8") code = qrcode.QRCode() diff --git a/micropython/examples/inky_frame/inky_frame_placekitten.py b/micropython/examples/inky_frame/inky_frame_placekitten.py index 8c6f9366..5d3ba880 100644 --- a/micropython/examples/inky_frame/inky_frame_placekitten.py +++ b/micropython/examples/inky_frame/inky_frame_placekitten.py @@ -8,7 +8,8 @@ import sdcard import WIFI_CONFIG from urllib import urequest from network_manager import NetworkManager -from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" """ random placekitten (from a very small set) diff --git a/micropython/examples/inky_frame/inky_frame_quote_of_the_day.py b/micropython/examples/inky_frame/inky_frame_quote_of_the_day.py index 76269889..886d10e9 100644 --- a/micropython/examples/inky_frame/inky_frame_quote_of_the_day.py +++ b/micropython/examples/inky_frame/inky_frame_quote_of_the_day.py @@ -5,7 +5,8 @@ import uasyncio import WIFI_CONFIG from urllib import urequest from network_manager import NetworkManager -from picographics import PicoGraphics, DISPLAY_INKY_FRAME +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" ENDPOINT = "https://en.wikiquote.org/w/api.php?format=json&action=expandtemplates&prop=wikitext&text={{{{Wikiquote:Quote%20of%20the%20day/{3}%20{2},%20{0}}}}}" @@ -31,7 +32,7 @@ def status_handler(mode, status, ip): network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler) gc.collect() -graphics = PicoGraphics(DISPLAY_INKY_FRAME) +graphics = PicoGraphics(DISPLAY) WIDTH, HEIGHT = graphics.get_bounds() graphics.set_font("bitmap8") gc.collect() diff --git a/micropython/examples/inky_frame/inky_frame_random_joke.py b/micropython/examples/inky_frame/inky_frame_random_joke.py index 4eb7cbc5..23eb606d 100644 --- a/micropython/examples/inky_frame/inky_frame_random_joke.py +++ b/micropython/examples/inky_frame/inky_frame_random_joke.py @@ -6,7 +6,8 @@ import jpegdec import WIFI_CONFIG import uasyncio from network_manager import NetworkManager -from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" from urllib import urequest @@ -27,7 +28,7 @@ WIDTH, HEIGHT = graphics.get_bounds() FILENAME = "/sd/random-joke.jpg" JOKE_IDS = "https://pimoroni.github.io/feed2image/jokeapi-ids.txt" -JOKE_IMG = "https://pimoroni.github.io/feed2image/jokeapi-{}-600x448.jpg" +JOKE_IMG = "https://pimoroni.github.io/feed2image/jokeapi-{}-{}x{}.jpg" import sdcard # noqa: E402 - putting this at the top causes an MBEDTLS OOM error!? sd_spi = machine.SPI(0, sck=machine.Pin(18, machine.Pin.OUT), mosi=machine.Pin(19, machine.Pin.OUT), miso=machine.Pin(16, machine.Pin.OUT)) @@ -59,7 +60,7 @@ socket.close() print("Random joke ID: {}".format(random_joke_id)) -url = JOKE_IMG.format(random_joke_id) +url = JOKE_IMG.format(random_joke_id, WIDTH, HEIGHT) socket = urequest.urlopen(url) diff --git a/micropython/examples/inky_frame/inky_frame_xkcd_daily.py b/micropython/examples/inky_frame/inky_frame_xkcd_daily.py index 9b1d1d29..3eff8bb9 100644 --- a/micropython/examples/inky_frame/inky_frame_xkcd_daily.py +++ b/micropython/examples/inky_frame/inky_frame_xkcd_daily.py @@ -1,6 +1,5 @@ import gc import uos -import random import machine import jpegdec import uasyncio @@ -8,7 +7,8 @@ import sdcard import WIFI_CONFIG from urllib import urequest from network_manager import NetworkManager -from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" """ xkcd daily @@ -46,7 +46,10 @@ uos.mount(sd, "/sd") gc.collect() # Claw back some RAM! -url = ENDPOINT.format(WIDTH, HEIGHT + random.randint(0, 10)) +url = ENDPOINT + +if (WIDTH, HEIGHT) != (600, 448): + url = url.replace("xkcd-", f"xkcd-{WIDTH}x{HEIGHT}-") socket = urequest.urlopen(url) From 9424ae7081efc63a529e94c6e14fb518889cc5db Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 3 Oct 2022 14:02:19 +0100 Subject: [PATCH 5/7] Inky Frame: Improve LED PWM example to test all LEDs. --- micropython/examples/inky_frame/led_pwm.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/micropython/examples/inky_frame/led_pwm.py b/micropython/examples/inky_frame/led_pwm.py index 8df92252..d6189fdd 100644 --- a/micropython/examples/inky_frame/led_pwm.py +++ b/micropython/examples/inky_frame/led_pwm.py @@ -18,10 +18,16 @@ led_e = PWM(Pin(15)) led_activity.freq(1000) +leds = [led_activity, led_connect, led_a, led_b, led_c, led_d, led_e] +n = 0 + while True: - for duty in range(65025): - led_activity.duty_u16(duty) - sleep(0.0001) - for duty in range(65025, 0, -1): - led_activity.duty_u16(duty) - sleep(0.0001) + for _ in range(2): + for duty in range(65025, 2): + leds[n].duty_u16(duty) + sleep(0.0001) + for duty in range(65025, 0, -2): + leds[n].duty_u16(duty) + sleep(0.0001) + n += 1 + n %= len(leds) From 9663be2787afda33888236ddce052eaa6ba0c322 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 3 Oct 2022 14:37:02 +0100 Subject: [PATCH 6/7] Inky Frame: New button test, old is now button demo. --- .../examples/inky_frame/button_demo.py | 85 ++++++++++++++ .../examples/inky_frame/button_test.py | 105 +++++++----------- 2 files changed, 125 insertions(+), 65 deletions(-) create mode 100644 micropython/examples/inky_frame/button_demo.py diff --git a/micropython/examples/inky_frame/button_demo.py b/micropython/examples/inky_frame/button_demo.py new file mode 100644 index 00000000..42f9bba9 --- /dev/null +++ b/micropython/examples/inky_frame/button_demo.py @@ -0,0 +1,85 @@ +# This example shows you a simple, non-interrupt way of reading Inky Frame's buttons with a loop that checks to see if buttons are pressed. + +from pimoroni import ShiftRegister +from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7" +# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0" +from machine import Pin + +display = PicoGraphics(display=DISPLAY) + +display.set_font("bitmap8") + +# Inky Frame uses a shift register to read the buttons +SR_CLOCK = 8 +SR_LATCH = 9 +SR_OUT = 10 + +sr = ShiftRegister(SR_CLOCK, SR_LATCH, SR_OUT) + +# set up the button LEDs +button_a_led = Pin(11, Pin.OUT) +button_b_led = Pin(12, Pin.OUT) +button_c_led = Pin(13, Pin.OUT) +button_d_led = Pin(14, Pin.OUT) +button_e_led = Pin(15, Pin.OUT) + + +# a handy function we can call to clear the screen +# display.set_pen(1) is white and display.set_pen(0) is black +def clear(): + display.set_pen(1) + display.clear() + + +# set up +clear() +display.set_pen(0) +display.text("Press any button!", 10, 10, scale=4) +display.update() + +while True: + button_a_led.off() + button_b_led.off() + button_c_led.off() + button_d_led.off() + button_e_led.off() + + # read the shift register + # we can tell which button has been pressed by checking if a specific bit is 0 or 1 + result = sr.read() + button_a = sr[7] + button_b = sr[6] + button_c = sr[5] + button_d = sr[4] + button_e = sr[3] + + if button_a == 1: # if a button press is detected then... + button_a_led.on() + clear() # clear to white + display.set_pen(4) # change the pen colour + display.text("Button A pressed", 10, 10, scale=4) # display some text on the screen + display.update() # update the display + elif button_b == 1: + button_b_led.on() + clear() + display.set_pen(6) + display.text("Button B pressed", 10, 50, scale=4) + display.update() + elif button_c == 1: + button_c_led.on() + clear() + display.set_pen(5) + display.text("Button C pressed", 10, 90, scale=4) + display.update() + elif button_d == 1: + button_d_led.on() + clear() + display.set_pen(2) + display.text("Button D pressed", 10, 130, scale=4) + display.update() + elif button_e == 1: + button_e_led.on() + clear() + display.set_pen(3) + display.text("Button E pressed", 10, 170, scale=4) + display.update() diff --git a/micropython/examples/inky_frame/button_test.py b/micropython/examples/inky_frame/button_test.py index 034d6021..62c44db2 100644 --- a/micropython/examples/inky_frame/button_test.py +++ b/micropython/examples/inky_frame/button_test.py @@ -1,12 +1,10 @@ -# This example shows you a simple, non-interrupt way of reading Inky Frame's buttons with a loop that checks to see if buttons are pressed. +# This example allows you to test Inky Frame's buttons +# It does not update the screen. from pimoroni import ShiftRegister -from picographics import PicoGraphics, DISPLAY_INKY_FRAME from machine import Pin +import time -display = PicoGraphics(display=DISPLAY_INKY_FRAME) - -display.set_font("bitmap8") # Inky Frame uses a shift register to read the buttons SR_CLOCK = 8 @@ -15,70 +13,47 @@ SR_OUT = 10 sr = ShiftRegister(SR_CLOCK, SR_LATCH, SR_OUT) -# set up the button LEDs -button_a_led = Pin(11, Pin.OUT) -button_b_led = Pin(12, Pin.OUT) -button_c_led = Pin(13, Pin.OUT) -button_d_led = Pin(14, Pin.OUT) -button_e_led = Pin(15, Pin.OUT) + +# Simple class to debounce button input and handle LED +class Button: + def __init__(self, idx, led, debounce=50): + self.led = Pin(led, Pin.OUT) # LEDs are just regular IOs + self.led.on() + self._idx = idx + self._debounce_time = debounce + self._changed = time.ticks_ms() + self._last_value = None + + def debounced(self): + return time.ticks_ms() - self._changed > self._debounce_time + + def get(self, sr): + value = sr[self._idx] + if value != self._last_value and self.debounced(): + self._last_value = value + self._changed = time.ticks_ms() + return value -# a handy function we can call to clear the screen -# display.set_pen(1) is white and display.set_pen(0) is black -def clear(): - display.set_pen(1) - display.clear() +button_a = Button(7, 11) +button_b = Button(6, 12) +button_c = Button(5, 13) +button_d = Button(4, 14) +button_e = Button(3, 15) -# set up -clear() -display.set_pen(0) -display.text("Press any button!", 10, 10, scale=4) -display.update() - while True: - button_a_led.off() - button_b_led.off() - button_c_led.off() - button_d_led.off() - button_e_led.off() + sr.read() - # read the shift register - # we can tell which button has been pressed by checking if a specific bit is 0 or 1 - result = sr.read() - button_a = sr[7] - button_b = sr[6] - button_c = sr[5] - button_d = sr[4] - button_e = sr[3] + if button_a.get(sr): + button_a.led.toggle() + if button_b.get(sr): + button_b.led.toggle() + if button_c.get(sr): + button_c.led.toggle() + if button_d.get(sr): + button_d.led.toggle() + if button_e.get(sr): + button_e.led.toggle() - if button_a == 1: # if a button press is detected then... - button_a_led.on() - clear() # clear to white - display.set_pen(4) # change the pen colour - display.text("Button A pressed", 10, 10, scale=4) # display some text on the screen - display.update() # update the display - elif button_b == 1: - button_b_led.on() - clear() - display.set_pen(6) - display.text("Button B pressed", 10, 50, scale=4) - display.update() - elif button_c == 1: - button_c_led.on() - clear() - display.set_pen(5) - display.text("Button C pressed", 10, 90, scale=4) - display.update() - elif button_d == 1: - button_d_led.on() - clear() - display.set_pen(2) - display.text("Button D pressed", 10, 130, scale=4) - display.update() - elif button_e == 1: - button_e_led.on() - clear() - display.set_pen(3) - display.text("Button E pressed", 10, 170, scale=4) - display.update() + time.sleep(1.0 / 60) # Poll 60 times/second From 00ca53a30bd6e81338288ac2fa0cf06e65c5807e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 5 Oct 2022 09:57:16 +0100 Subject: [PATCH 7/7] Inky Frame: Update C++ library to support 4.0" --- .../inky_frame/inky_frame_day_planner.cpp | 8 ++++---- libraries/inky_frame/inky_frame.cpp | 2 +- libraries/inky_frame/inky_frame.hpp | 20 +++++++++++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/examples/inky_frame/inky_frame_day_planner.cpp b/examples/inky_frame/inky_frame_day_planner.cpp index 26769a99..5ab2a8e5 100644 --- a/examples/inky_frame/inky_frame_day_planner.cpp +++ b/examples/inky_frame/inky_frame_day_planner.cpp @@ -8,7 +8,7 @@ using namespace pimoroni; -InkyFrame inky; +InkyFrame inky(640, 400); datetime_t now; datetime_t today; @@ -79,7 +79,7 @@ int days_in_month(datetime_t &dt) void center_text(std::string message, int y, float scale = 1.0f) { int32_t tw = inky.measure_text(message, scale); - inky.text(message, {(600 / 2) - (tw / 2), y}, scale); + inky.text(message, {(inky.width / 2) - (tw / 2), y}, scale); } void center_text(std::string message, int x, int y, int w, float scale = 1.0f) { @@ -94,7 +94,7 @@ void render_calendar_view() { //inky.text_aspect(1.1f); inky.set_pen(InkyFrame::RED); - inky.rectangle({0, 0, width, 448}); + inky.rectangle({0, 0, width, inky.height}); inky.set_pen(InkyFrame::WHITE); @@ -343,7 +343,7 @@ void render_calendar_entries() { int spacing = 5; int xoff = 240 + spacing; int yoff = spacing; - int width = 600 - xoff - spacing; + int width = inky.width - xoff - spacing; int row_height = 50; //inky.text_tracking(1.0f); diff --git a/libraries/inky_frame/inky_frame.cpp b/libraries/inky_frame/inky_frame.cpp index 65030d48..9ac8c606 100644 --- a/libraries/inky_frame/inky_frame.cpp +++ b/libraries/inky_frame/inky_frame.cpp @@ -142,7 +142,7 @@ namespace pimoroni { // Display an image that fills the screen (286*128) void InkyFrame::image(const uint8_t* data) { - image(data, WIDTH, 0, 0, WIDTH, HEIGHT, 0, 0); + image(data, width, 0, 0, width, height, 0, 0); } // Display an image smaller than the screen (sw*sh) at dx, dy diff --git a/libraries/inky_frame/inky_frame.hpp b/libraries/inky_frame/inky_frame.hpp index 904d3983..29e2b66c 100644 --- a/libraries/inky_frame/inky_frame.hpp +++ b/libraries/inky_frame/inky_frame.hpp @@ -89,14 +89,26 @@ namespace pimoroni { I2C i2c; PCF85063A rtc; + int width; + int height; + + [[deprecated("Use instance variable width.")]] static const int WIDTH = 600; + [[deprecated("Use instance variable height.")]] static const int HEIGHT = 448; - InkyFrame() : - PicoGraphics_Pen3Bit(WIDTH, HEIGHT, nullptr), - uc8159(WIDTH, HEIGHT, {spi0, EINK_CS, CLK, MOSI, PIN_UNUSED, EINK_DC, PIN_UNUSED}), + // Default 5.7" constructor + InkyFrame() : InkyFrame(600, 448) {}; + + // 600x448 for 5.7" + // 640x400 for 4.0" + InkyFrame(int width, int height) : + PicoGraphics_Pen3Bit(width, height, nullptr), + uc8159(width, height, {spi0, EINK_CS, CLK, MOSI, PIN_UNUSED, EINK_DC, PIN_UNUSED}), i2c(4, 5), - rtc(&i2c) { + rtc(&i2c), + width(width), + height(height) { } void init();