diff --git a/drivers/uc8151/uc8151.cpp b/drivers/uc8151/uc8151.cpp index 3f134a52..1bf9cd11 100644 --- a/drivers/uc8151/uc8151.cpp +++ b/drivers/uc8151/uc8151.cpp @@ -183,7 +183,7 @@ namespace pimoroni { gpio_put(DC, 0); // command mode spi_write_blocking(spi, ®, 1); - if(data) { + if(len > 0) { gpio_put(DC, 1); // data mode spi_write_blocking(spi, (const uint8_t*)data, len); } @@ -191,6 +191,13 @@ namespace pimoroni { gpio_put(CS, 1); } + void UC8151::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 UC8151::command(uint8_t reg, std::initializer_list values) { command(reg, values.size(), (uint8_t *)values.begin()); } @@ -210,6 +217,49 @@ namespace pimoroni { *p |= b; // set bit value } + void UC8151::partial_update(int x, int y, int w, int h, bool blocking) { + // y is given in columns ("banks"), which are groups of 8 horiontal pixels + // x is given in pixels + + int cols = h / 8; + int y1 = y / 8; + //int y2 = y1 + cols; + + int rows = w; + int x1 = x; + //int x2 = x + rows; + + uint8_t partial_window[7] = { + (uint8_t)(y), + (uint8_t)(y + h - 1), + (uint8_t)(x >> 8), + (uint8_t)(x & 0xff), + (uint8_t)((x + w - 1) >> 8), + (uint8_t)((x + w - 1) & 0xff), + 0b00000001 // PT_SCAN + }; + command(PON); // turn on + command(PTIN); // enable partial mode + command(PTL, sizeof(partial_window), partial_window); + + command(DTM2); + for (auto dx = 0; dx < rows; dx++) { + int sx = dx + x1; + int sy = y1; + data(cols, &frame_buffer[sy + (sx * (height / 8))]); + } + command(DSP); // data stop + + command(DRF); // start display refresh + + if(blocking) { + busy_wait(); + + command(POF); // turn off + } + command(PTOU); // disable partial mode + } + void UC8151::update(bool blocking) { command(PON); // turn on diff --git a/drivers/uc8151/uc8151.hpp b/drivers/uc8151/uc8151.hpp index b0940ca1..db24f3fe 100644 --- a/drivers/uc8151/uc8151.hpp +++ b/drivers/uc8151/uc8151.hpp @@ -167,8 +167,11 @@ namespace pimoroni { void reset(); 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, std::initializer_list values); + void command(uint8_t reg) {command(reg, 0, nullptr);}; + void data(size_t len, const uint8_t *data); void update(bool blocking = true); + void partial_update(int x, int y, int w, int h, bool blocking = true); void off(); void pixel(int x, int y, int v); diff --git a/libraries/badger2040/badger2040.cpp b/libraries/badger2040/badger2040.cpp index 3b49e820..8df9b9b6 100644 --- a/libraries/badger2040/badger2040.cpp +++ b/libraries/badger2040/badger2040.cpp @@ -15,7 +15,7 @@ namespace pimoroni { // set clock speed to 12MHz to reduce the maximum current draw on the // battery. when updating a small, monochrome, display only every few // seconds or so then you don't need much processing power anyway... - set_sys_clock_khz(48000, true); + //set_sys_clock_khz(48000, true); gpio_set_function(ENABLE_3V3, GPIO_FUNC_SIO); gpio_set_dir(ENABLE_3V3, GPIO_OUT); @@ -166,6 +166,26 @@ namespace pimoroni { _button_states |= gpio_get_all() & mask; } + void Badger2040::partial_update(int x, int y, int w, int h) { + // wait for display to not be busy + while(uc8151.is_busy()) { + tight_loop_contents(); + } + + uc8151.partial_update(x, y, w, h, true); + + _button_states = 0; + + // wait for display to not be busy but sample buttons in case they are + // pressed during this time + while(uc8151.is_busy()) { + update_button_states(); + tight_loop_contents(); + } + + uc8151.off(); + } + void Badger2040::update() { // wait for display to not be busy while(uc8151.is_busy()) { diff --git a/libraries/badger2040/badger2040.hpp b/libraries/badger2040/badger2040.hpp index 703a6cfa..49539b04 100644 --- a/libraries/badger2040/badger2040.hpp +++ b/libraries/badger2040/badger2040.hpp @@ -22,6 +22,7 @@ namespace pimoroni { Badger2040(); void init(); void update(); + void partial_update(int x, int y, int w, int h); void halt(); void sleep();