From caec8cde9ca751401827d832b338f6d72d42faaa Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 1/6] Fix ESP32 I2C transaction locking (#353) --- src/lgfx/v1/platforms/esp32/common.inl | 78 +++++++++++++++++++------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/src/lgfx/v1/platforms/esp32/common.inl b/src/lgfx/v1/platforms/esp32/common.inl index 9eadafbf..b8160655 100644 --- a/src/lgfx/v1/platforms/esp32/common.inl +++ b/src/lgfx/v1/platforms/esp32/common.inl @@ -24,6 +24,7 @@ Contributors: #include "common.hpp" #include +#include #include #include #include @@ -1426,16 +1427,17 @@ namespace lgfx cpp::result state; SemaphoreHandle_t mtx = nullptr; + std::atomic owner { nullptr }; void lock(uint32_t msec = portMAX_DELAY) { if (mtx == nullptr) { - mtx = xSemaphoreCreateMutex(); + mtx = xSemaphoreCreateRecursiveMutex(); } - xSemaphoreTake(mtx, msec); + xSemaphoreTakeRecursive(mtx, msec); } void unlock(void) { - xSemaphoreGive(mtx); + xSemaphoreGiveRecursive(mtx); } gpio_num_t pin_scl = (gpio_num_t)-1; @@ -1841,6 +1843,8 @@ namespace lgfx { i2c_context[i2c_port].state = i2c_context_t::state_t::state_disconnect; } + // Error cleanup may leave state as an error; ownership still ends here. + i2c_context[i2c_port].owner.store(nullptr); i2c_context[i2c_port].unlock(); } return res; @@ -2143,6 +2147,8 @@ namespace lgfx { if (isSoftPort(i2c_port)) { return soft_i2c_restart(i2c_port, i2c_addr, freq, read); } if (i2c_port >= LGFX_I2C_PORT_NUM) { return cpp::fail(error_t::invalid_arg); } + if (i2c_context[i2c_port].owner.load() != xTaskGetCurrentTaskHandle()) + { return cpp::fail(error_t::mode_mismatch); } if (i2c_addr < I2C_7BIT_ADDR_MIN || i2c_addr > I2C_10BIT_ADDR_MAX) return cpp::fail(error_t::invalid_arg); auto res = i2c_wait(i2c_port); @@ -2266,16 +2272,28 @@ namespace lgfx return res; } + // Do not call endTransaction after a failed beginTransaction. + // Only the task whose beginTransaction succeeded may end that transaction. cpp::result beginTransaction(int i2c_port, int i2c_addr, uint32_t freq, bool read) { if (isSoftPort(i2c_port)) { return soft_i2c_beginTransaction(i2c_port, i2c_addr, freq, read); } if (i2c_port >= LGFX_I2C_PORT_NUM) return cpp::fail(error_t::invalid_arg); + // Reject invalid addresses before taking the lock or saving shared bus registers. + if (i2c_addr < I2C_7BIT_ADDR_MIN || i2c_addr > I2C_10BIT_ADDR_MAX) return cpp::fail(error_t::invalid_arg); if ((uint32_t)i2c_context[i2c_port].pin_sda >= GPIO_NUM_MAX || (uint32_t)i2c_context[i2c_port].pin_scl >= GPIO_NUM_MAX) return cpp::fail(error_t::invalid_arg); //ESP_LOGI("LGFX", "i2c::beginTransaction : port:%d / addr:%02x / freq:%d / rw:%d", i2c_port, i2c_addr, freq, read); auto dev = getDev(i2c_port); i2c_context[i2c_port].lock(); + // Recursive locking supports RMW, not nested transactions. Error cleanup can + // leave state set to an error, so use the active owner rather than state. + if (i2c_context[i2c_port].owner.load() == xTaskGetCurrentTaskHandle()) + { + i2c_context[i2c_port].unlock(); + return cpp::fail(error_t::mode_mismatch); + } + i2c_context[i2c_port].owner.store(xTaskGetCurrentTaskHandle()); if (getBusBusy(dev)) { @@ -2362,6 +2380,9 @@ namespace lgfx { if (isSoftPort(i2c_port)) { return soft_i2c_endTransaction(i2c_port); } if (i2c_port >= LGFX_I2C_PORT_NUM) return cpp::fail(error_t::invalid_arg); + // A failed begin or a different task must not stop another owner's transfer. + if (i2c_context[i2c_port].owner.load() != xTaskGetCurrentTaskHandle()) + { return cpp::fail(error_t::mode_mismatch); } return i2c_wait(i2c_port, true); } //*/ @@ -2384,6 +2405,8 @@ namespace lgfx { if (isSoftPort(i2c_port)) { return soft_i2c_writeBytes(i2c_port, data, length); } if (i2c_port >= LGFX_I2C_PORT_NUM) { return cpp::fail(error_t::invalid_arg); } + if (i2c_context[i2c_port].owner.load() != xTaskGetCurrentTaskHandle()) + { return cpp::fail(error_t::mode_mismatch); } if (i2c_context[i2c_port].state.has_error()) { return cpp::fail(i2c_context[i2c_port].state.error()); } if (i2c_context[i2c_port].state != i2c_context_t::state_write) { return cpp::fail(error_t::mode_mismatch); } cpp::result res {}; @@ -2423,6 +2446,8 @@ namespace lgfx { if (isSoftPort(i2c_port)) { return soft_i2c_readBytes(i2c_port, readdata, length, last_nack); } if (i2c_port >= LGFX_I2C_PORT_NUM) { return cpp::fail(error_t::invalid_arg); } + if (i2c_context[i2c_port].owner.load() != xTaskGetCurrentTaskHandle()) + { return cpp::fail(error_t::mode_mismatch); } if (i2c_context[i2c_port].state.has_error()) { return cpp::fail(i2c_context[i2c_port].state.error()); } if (i2c_context[i2c_port].state != i2c_context_t::state_read) { return cpp::fail(error_t::mode_mismatch); } cpp::result res {}; @@ -2509,33 +2534,27 @@ namespace lgfx cpp::result transactionWrite(int i2c_port, int addr, const uint8_t *writedata, uint8_t writelen, uint32_t freq) { - cpp::result res; - if ((res = beginTransaction(i2c_port, addr, freq, false)).has_value() - ) - { - res = writeBytes(i2c_port, writedata, writelen); - } + auto res = beginTransaction(i2c_port, addr, freq, false); + if (res.has_error()) { return res; } // No transaction was acquired. + res = writeBytes(i2c_port, writedata, writelen); auto last = endTransaction(i2c_port); return res.has_error() ? res : last; } cpp::result transactionRead(int i2c_port, int addr, uint8_t *readdata, uint8_t readlen, uint32_t freq) { - cpp::result res; - if ((res = beginTransaction(i2c_port, addr, freq, true)).has_value() - ) - { - res = readBytes(i2c_port, readdata, readlen, true); - } + auto res = beginTransaction(i2c_port, addr, freq, true); + if (res.has_error()) { return res; } // No transaction was acquired. + res = readBytes(i2c_port, readdata, readlen, true); auto last = endTransaction(i2c_port); return res.has_error() ? res : last; } cpp::result transactionWriteRead(int i2c_port, int addr, const uint8_t *writedata, uint8_t writelen, uint8_t *readdata, size_t readlen, uint32_t freq) { - cpp::result res; - if ((res = beginTransaction(i2c_port, addr, freq, false)).has_value() - && (res = writeBytes(i2c_port, writedata, writelen)).has_value() + auto res = beginTransaction(i2c_port, addr, freq, false); + if (res.has_error()) { return res; } // No transaction was acquired. + if ((res = writeBytes(i2c_port, writedata, writelen)).has_value() && (res = restart(i2c_port, addr, freq, true)).has_value() ) { @@ -2555,12 +2574,33 @@ namespace lgfx cpp::result writeRegister8(int i2c_port, int addr, uint8_t reg, uint8_t data, uint8_t mask, uint32_t freq) { uint8_t tmp[2] = { reg, data }; - if (mask) + if (!mask) { return transactionWrite(i2c_port, addr, tmp, 2, freq); } + + // Soft ports are not covered by the atomic hardware read/modify/write. + if (isSoftPort(i2c_port)) { auto res = transactionWriteRead(i2c_port, addr, ®, 1, &tmp[1], 1, freq); if (res.has_error()) { return res; } tmp[1] = (tmp[1] & mask) | data; + return transactionWrite(i2c_port, addr, tmp, 2, freq); } + + // Keep the read/modify/write atomic while retaining the STOP between transfers. + // Each transfer takes the recursive mutex again and releases only its own level. + // This serializes lgfx callers only; other drivers on a shared bus can transfer + // between the STOP and the next START. + if (i2c_port >= LGFX_I2C_PORT_NUM) { return cpp::fail(error_t::invalid_arg); } + i2c_context[i2c_port].lock(); + SemaphoreHandle_t mutex = i2c_context[i2c_port].mtx; + struct lock_guard_t + { + SemaphoreHandle_t mutex; + ~lock_guard_t() { xSemaphoreGiveRecursive(mutex); } + } guard { mutex }; + + auto res = transactionWriteRead(i2c_port, addr, ®, 1, &tmp[1], 1, freq); + if (res.has_error()) { return res; } + tmp[1] = (tmp[1] & mask) | data; return transactionWrite(i2c_port, addr, tmp, 2, freq); } From 2b37deb414140a29b14f93abee29fdca8d4fb9b9 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 2/6] Panel_M5UnitLCD: fix ARGB image writes, reads after image writes and the first draw after reset (#355) --- src/lgfx/v1/panel/Panel_M5UnitLCD.inl | 36 ++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/lgfx/v1/panel/Panel_M5UnitLCD.inl b/src/lgfx/v1/panel/Panel_M5UnitLCD.inl index 1a9e7a51..8f854593 100644 --- a/src/lgfx/v1/panel/Panel_M5UnitLCD.inl +++ b/src/lgfx/v1/panel/Panel_M5UnitLCD.inl @@ -60,6 +60,16 @@ namespace lgfx startWrite(true); _bus->writeCommand(CMD_READ_ID, 8); } while (!(_bus->readBytes(buf, 4, true) && buf[0] == 0x77 && buf[1] == 0x89) && --retry); + // The unit answers READ_ID before it finishes starting up (about 250 ms more), and + // pixel data streamed in that period is dropped. Queue a one-pixel fill and wait until + // the unit has consumed it: a NOP is consumed at once and says nothing about drawing. + writeFillRectPreclipped(0, 0, 1, 1, 0); + _buff_free_count = 0; + retry = 4; + do + { + _check_repeat(0, 255); + } while (_buff_free_count < 255 && --retry); } } @@ -588,15 +598,30 @@ if (bytelen != rleDecode(dest, res, bytes)*bytes) { void Panel_M5UnitLCD::writeImageARGB(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param) { - _set_window(x, y, x + w - 1, y); - auto buf = (uint32_t*)param->src_data; + // The unit blends ARGB itself, so source pixels are sent as they are, row by row, + // starting from the clipped source position held in param. + _set_window(x, y, x + w - 1, y + h - 1); + auto src = (const uint32_t*)param->src_data; + // bgra8888_t (argb8888_4Byte) holds the bytes in the reverse order of argb8888_t, + // so its raw value already has the byte order the unit expects. + bool swap = (param->src_depth != argb8888_4Byte); if (!_check_repeat(CMD_WRITE_RAW_32)) { writeCommand(CMD_WRITE_RAW_32, 1); } - for (size_t i = 0; i < w; ++i) + for (;;) { - _bus->writeCommand(getSwap32(buf[i]), 32); + uint32_t x32 = param->src_x32; + uint32_t y32 = param->src_y32; + for (size_t i = 0; i < w; ++i) + { + uint32_t idx = (x32 >> pixelcopy_t::FP_SCALE) + (y32 >> pixelcopy_t::FP_SCALE) * param->src_bitwidth; + _bus->writeCommand(swap ? getSwap32(src[idx]) : src[idx], 32); + x32 += param->src_x32_add; + y32 += param->src_y32_add; + } + if (!--h) { break; } + param->src_y++; } _raw_color = ~0u; } @@ -608,6 +633,9 @@ if (bytelen != rleDecode(dest, res, bytes)*bytes) { do { _check_repeat(0, 255); } while (_buff_free_count < 255 && --retry); + // Always send the window: after an image write the unit returns zeros when the + // read reuses the cached column range, so CASET must not be skipped here. + _xs = _xe = _ys = _ye = INT16_MAX; _set_window(x, y, x+w-1, y+h-1); _bus->writeCommand(CMD_READ_RAW | ((_read_bits >> 3) & 3), 8); From fd946399a961ddbbc4fcaec33b66046a682daeb3 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 3/6] Accept struct color types in setBaseColor() and setTextColor() (#358) --- src/lgfx/v1/LGFXBase.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lgfx/v1/LGFXBase.hpp b/src/lgfx/v1/LGFXBase.hpp index 8d38b085..2548a206 100644 --- a/src/lgfx/v1/LGFXBase.hpp +++ b/src/lgfx/v1/LGFXBase.hpp @@ -131,7 +131,7 @@ namespace lgfx LGFX_INLINE_T void setColor(T color) { setRawColor(_write_conv.convert(color)); } LGFX_INLINE void setRawColor(uint32_t c) { *((uint32_t*)&_color) = c; } LGFX_INLINE uint32_t getRawColor(void) const { return *((uint32_t*)&_color); } - LGFX_INLINE_T void setBaseColor(T c) { _base_rgb888 = hasPalette() ? c : convert_to_rgb888(c); } + LGFX_INLINE_T void setBaseColor(T c) { _base_rgb888 = hasPalette() ? static_cast(c) : convert_to_rgb888(c); } LGFX_INLINE uint32_t getBaseColor(void) const { return _base_rgb888; } LGFX_INLINE color_conv_t* getColorConverter(void) { return &_write_conv; } LGFX_INLINE color_depth_t getColorDepth(void) const { return _write_conv.depth; } @@ -690,7 +690,7 @@ namespace lgfx template void setTextColor(T color) { - _text_style.fore_rgb888 = _text_style.back_rgb888 = this->hasPalette() ? color : convert_to_rgb888(color); + _text_style.fore_rgb888 = _text_style.back_rgb888 = this->hasPalette() ? static_cast(color) : convert_to_rgb888(color); } template void setTextColor(T1 fgcolor, T2 bgcolor) { @@ -698,8 +698,8 @@ namespace lgfx _text_style.fore_rgb888 = convert_to_rgb888(fgcolor); _text_style.back_rgb888 = convert_to_rgb888(bgcolor); } else { - _text_style.fore_rgb888 = fgcolor; - _text_style.back_rgb888 = bgcolor; + _text_style.fore_rgb888 = static_cast(fgcolor); + _text_style.back_rgb888 = static_cast(bgcolor); } } From b3d99aae8480a0b6ff61daec6287e69d4a4f4029 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 4/6] ESP32 I2C: decide TwoWire::end() in one place; recover a controller left bus busy Port of the develop change (#368) to the master layout: the TwoWire::end() guard becomes LGFX_TWOWIRE_HAS_END (git version first, esp_arduino_version.h when core_version.h is missing; #366) for release() and the pin search, and beginTransaction() runs i2c_stop() when the bus is still busy after the 128 us wait (#362). The unused member setPins() that develop removed is left as it is. --- src/lgfx/v1/platforms/esp32/common.inl | 47 ++++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/lgfx/v1/platforms/esp32/common.inl b/src/lgfx/v1/platforms/esp32/common.inl index b8160655..4adf875c 100644 --- a/src/lgfx/v1/platforms/esp32/common.inl +++ b/src/lgfx/v1/platforms/esp32/common.inl @@ -1163,6 +1163,23 @@ namespace lgfx #include #endif +// TwoWire::end() exists from core 2.0.1 (0x44c11981 is 2.0.0). Some board packages lack +// core_version.h; they are judged by esp_arduino_version.h, which 2.0.1 and 2.0.2 still +// report as 2.0.0, hence the git version first. +#if defined ( ARDUINO ) && __has_include () && defined ( ESP_IDF_VERSION_VAL ) + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + #if defined ( ARDUINO_ESP32_GIT_VER ) + #if ARDUINO_ESP32_GIT_VER != 0x44c11981 + #define LGFX_TWOWIRE_HAS_END + #endif + #elif defined ( ESP_ARDUINO_VERSION_VAL ) + #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 1) + #define LGFX_TWOWIRE_HAS_END + #endif + #endif + #endif +#endif + #if !defined ( I2C_ACK_ERR_INT_RAW_M ) #define I2C_ACK_ERR_INT_RAW_M I2C_NACK_INT_RAW_M #endif @@ -1882,17 +1899,13 @@ namespace lgfx #endif { #if defined ( ARDUINO ) && __has_include () && defined ( ESP_IDF_VERSION_VAL ) - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - #if defined ARDUINO_ESP32_GIT_VER - #if ARDUINO_ESP32_GIT_VER != 0x44c11981 - #if LGFX_HP_I2C_NUM == 1 + #if defined ( LGFX_TWOWIRE_HAS_END ) + #if LGFX_HP_I2C_NUM == 1 auto twowire = &Wire; - #else + #else auto twowire = ((i2c_port == 0) ? &Wire : &Wire1); - #endif - twowire->end(); - #endif #endif + twowire->end(); #endif #elif __has_include() auto bus_handle = i2c_context[i2c_port].i2c_bus_handle; @@ -2307,6 +2320,16 @@ namespace lgfx } i2c_context[i2c_port].save_reg(dev); + // Still busy although no transfer of ours is running: a slave glitch can leave the + // controller waiting for a STOP forever (ESP32 has no FSM reset bit). Recover the bus + // and the controller as the ESP-IDF driver does before it starts a command (the C2 and + // C3 skip the peripheral reset there and rely on fsm_rst below). + if (getBusBusy(dev)) + { + ESP_LOGV("LGFX", "i2c::beginTransaction : bus busy, recover"); + i2c_stop(i2c_port); + } + // A low power port reaches its pads through the low power IO domain, which set_pin() // knows nothing about: routing them through the normal GPIO matrix here would // disconnect the port from its own pins on every transaction. A shared port keeps @@ -2649,18 +2672,12 @@ namespace lgfx #if defined ( ARDUINO ) && __has_include () _twowire = nullptr; if (search_sda >=0 && search_scl >= 0) { -#if defined ( ARDUINO ) && __has_include () && defined ( ESP_IDF_VERSION_VAL ) - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - #if defined ARDUINO_ESP32_GIT_VER - #if ARDUINO_ESP32_GIT_VER != 0x44c11981 +#if defined ( LGFX_TWOWIRE_HAS_END ) _twowire = &Wire; #if defined (I2CEXT1_SDA_IN_IDX) if (i2c_port != 0) { _twowire = &Wire1; } #endif _twowire->end(); - #endif - #endif - #endif #endif } #endif From 0d8a4e915812f8222ba497624d1c02478f10bf14 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 5/6] Core2: reset the LCD through the AXP2101 bit on the new PMIC Port of the develop change (#354) to the master layout. The Core2 panel's rst_control() toggled reg 0x96 bit1, the LCD reset (GPIO4) on the AXP192 but the BLDO1 (backlight) voltage on the AXP2101, so every panel init on Core2 v1.1 nudged the backlight voltage and never reset the LCD. The panel now carries its reset register: reg 0x90 bit1 (ALDO2 enable, the bit lcd_reset() already uses) on the AXP2101, reg 0x96 bit1 on the AXP192 as before. --- src/M5GFX.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/M5GFX.cpp b/src/M5GFX.cpp index 483c2c52..04736f74 100644 --- a/src/M5GFX.cpp +++ b/src/M5GFX.cpp @@ -332,13 +332,19 @@ namespace m5gfx this->_rotation = 1; // default rotation } + /// LCD reset line on the PMIC: AXP192 reg 0x96 bit1 (GPIO4), AXP2101 reg 0x90 bit1 (ALDO2 enable). + /// On the AXP2101, reg 0x96 is the BLDO1 (backlight) voltage, so it must not be used there. + void setResetReg(uint8_t reg) { _rst_reg = reg; } + void rst_control(bool level) override { uint8_t bits = level ? 2 : 0; uint8_t mask = level ? ~0 : ~2; - // AXP192 reg 0x96 = GPIO3&4 control - lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x96, bits, mask, axp_i2c_freq); + lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, _rst_reg, bits, mask, axp_i2c_freq); } + + private: + uint8_t _rst_reg = 0x96; }; using Panel_M5StackCore2 = Panel_M5StackCore2_T; using Panel_M5StackCore2E = Panel_M5StackCore2_T; @@ -1498,14 +1504,20 @@ namespace m5gfx } } _log_ili9342_variant(variant, keys); + // Same LCD reset bit as lcd_reset() (reg_data_axp2101_reset on the AXP2101). + const uint8_t rst_reg = isAxp192 ? 0x96 : 0x90; if (variant == ili9342_variant_t::e) { - p = new Panel_M5StackCore2E(); + auto pe = new Panel_M5StackCore2E(); + pe->setResetReg(rst_reg); + p = pe; _set_ili9342e_read(p, bus_cfg.freq_read); } else { - p = new Panel_M5StackCore2(); + auto pc = new Panel_M5StackCore2(); + pc->setResetReg(rst_reg); + p = pc; } } p->bus(bus_spi); From 6d3a593220807538d9e65a5061e0b671b1b12aeb Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:33 +0000 Subject: [PATCH 6/6] Bump version to 0.2.34 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/lgfx/v1/gitTagVersion.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 091eab28..9ae67db9 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -2,4 +2,4 @@ description: Graphics library for M5Stack series issues: https://github.com/m5stack/M5GFX/issues repository: https://github.com/m5stack/M5GFX.git url: https://github.com/m5stack/M5GFX.git -version: 0.2.33 +version: 0.2.34 diff --git a/library.json b/library.json index a2aa8858..4ad6698e 100644 --- a/library.json +++ b/library.json @@ -10,7 +10,7 @@ "type": "git", "url": "https://github.com/m5stack/M5GFX.git" }, - "version": "0.2.33", + "version": "0.2.34", "frameworks": ["arduino", "espidf", "*"], "platforms": ["espressif32", "native"], "headers": "M5GFX.h" diff --git a/library.properties b/library.properties index 969f287f..1a350ec2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5GFX -version=0.2.33 +version=0.2.34 author=M5Stack maintainer=M5Stack sentence=Library for M5Stack All Display diff --git a/src/lgfx/v1/gitTagVersion.h b/src/lgfx/v1/gitTagVersion.h index fec6df4b..6ff80fc0 100644 --- a/src/lgfx/v1/gitTagVersion.h +++ b/src/lgfx/v1/gitTagVersion.h @@ -1,4 +1,4 @@ #define LGFX_VERSION_MAJOR 1 #define LGFX_VERSION_MINOR 2 -#define LGFX_VERSION_PATCH 33 +#define LGFX_VERSION_PATCH 34 #define LOVYANGFX_VERSION F( LGFX_VERSION_MAJOR "." LGFX_VERSION_MINOR "." LGFX_VERSION_PATCH )