// Copyright (c) M5Stack. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include "M5GFX.h" #if defined ( ESP_PLATFORM ) #include #include #include #include #include #include #include #include "lgfx/v1/panel/Panel_ILI9342.hpp" #include "lgfx/v1/panel/Panel_ST7735.hpp" #include "lgfx/v1/panel/Panel_ST7789.hpp" #include "lgfx/v1/panel/Panel_GC9A01.hpp" #include "lgfx/v1/panel/Panel_GDEW0154M09.hpp" #include "lgfx/v1/panel/Panel_GDEW0154D67.hpp" #include "lgfx/v1/panel/Panel_IT8951.hpp" #include "lgfx/v1/touch/Touch_CST816S.hpp" #include "lgfx/v1/touch/Touch_FT5x06.hpp" #include "lgfx/v1/touch/Touch_GT911.hpp" #if defined ( CONFIG_IDF_TARGET_ESP32P4 ) #include "lgfx/v1/platforms/esp32p4/Panel_ILI9881C.hpp" static constexpr int_fast16_t in_i2c_port = I2C_NUM_1; #elif defined ( CONFIG_IDF_TARGET_ESP32S3 ) // for M5PaperS3 #if defined (CONFIG_ESP32S3_SPIRAM_SUPPORT) && defined (CONFIG_SPIRAM_MODE_OCT) #include #endif #endif #else #include "lgfx/v1/platforms/sdl/Panel_sdl.hpp" #include "picture_frame/picture_frame.h" #endif namespace m5gfx { static constexpr char LIBRARY_NAME[] = "M5GFX"; M5GFX* M5GFX::_instance = nullptr; M5GFX::M5GFX(void) : LGFX_Device() { if (_instance == nullptr) _instance = this; } #if defined ( ESP_PLATFORM ) void i2c_write_register8_array(int_fast16_t i2c_port, uint_fast8_t i2c_addr, const uint8_t* reg_data_mask, uint32_t freq) { while (reg_data_mask[0] != 0xFF || reg_data_mask[1] != 0xFF || reg_data_mask[2] != 0xFF) { lgfx::i2c::writeRegister8(i2c_port, i2c_addr, reg_data_mask[0], reg_data_mask[1], reg_data_mask[2], freq); reg_data_mask += 3; } } static constexpr std::uint_fast8_t pi4io1_i2c_addr = 0x43; static constexpr std::uint_fast8_t pi4io2_i2c_addr = 0x44; #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32) static constexpr std::int32_t axp_i2c_freq = 400000; static constexpr std::uint_fast8_t axp_i2c_addr = 0x34; static constexpr std::int_fast16_t axp_i2c_port = I2C_NUM_1; static constexpr std::int_fast16_t axp_i2c_sda = GPIO_NUM_21; static constexpr std::int_fast16_t axp_i2c_scl = GPIO_NUM_22; struct Panel_M5Stack : public lgfx::Panel_ILI9342 { Panel_M5Stack(void) { _cfg.pin_cs = GPIO_NUM_14; _cfg.pin_rst = GPIO_NUM_33; _cfg.offset_rotation = 3; _rotation = 1; } bool init(bool use_reset) override { _cfg.invert = lgfx::gpio::command( (const uint8_t[]) { lgfx::gpio::command_mode_output , GPIO_NUM_33, lgfx::gpio::command_write_low , GPIO_NUM_33, lgfx::gpio::command_mode_input_pulldown, GPIO_NUM_33, lgfx::gpio::command_write_high , GPIO_NUM_33, lgfx::gpio::command_read , GPIO_NUM_33, lgfx::gpio::command_mode_output , GPIO_NUM_33, lgfx::gpio::command_end }); return lgfx::Panel_ILI9342::init(use_reset); } }; struct Panel_M5StackCore2 : public lgfx::Panel_ILI9342 { Panel_M5StackCore2(void) { _cfg.pin_cs = GPIO_NUM_5; _cfg.invert = true; _cfg.offset_rotation = 3; _rotation = 1; // default rotation } 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); } }; struct Light_M5StackCore2 : public lgfx::ILight { bool init(std::uint8_t brightness) override { setBrightness(brightness); return true; } void setBrightness(std::uint8_t brightness) override { if (brightness) { brightness = (brightness >> 3) + 72; lgfx::i2c::bitOn(axp_i2c_port, axp_i2c_addr, 0x12, 0x02, axp_i2c_freq); // DC3 enable } else { lgfx::i2c::bitOff(axp_i2c_port, axp_i2c_addr, 0x12, 0x02, axp_i2c_freq); // DC3 disable } // AXP192 reg 0x27 = DC3 lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x27, brightness, 0x80, axp_i2c_freq); } }; struct Light_M5StackCore2_AXP2101 : public lgfx::ILight { bool init(std::uint8_t brightness) override { setBrightness(brightness); return true; } void setBrightness(std::uint8_t brightness) override { // BLDO1 if (brightness) { brightness = ((brightness + 641) >> 5); lgfx::i2c::bitOn(axp_i2c_port, axp_i2c_addr, 0x90, 0x10, axp_i2c_freq); // BLDO1 enable } else { lgfx::i2c::bitOff(axp_i2c_port, axp_i2c_addr, 0x90, 0x10, axp_i2c_freq); // BLDO1 disable } // AXP192 reg 0x96 = BLO1 voltage setting (0.5v ~ 3.5v 100mv/step) lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x96, brightness, 0, axp_i2c_freq); } }; struct Light_M5Tough : public lgfx::ILight { bool init(std::uint8_t brightness) override { setBrightness(brightness); return true; } void setBrightness(std::uint8_t brightness) override { if (brightness) { if (brightness > 4) { brightness = (brightness / 24) + 5; } lgfx::i2c::bitOn(axp_i2c_port, axp_i2c_addr, 0x12, 0x08, axp_i2c_freq); // LDO3 enable } else { lgfx::i2c::bitOff(axp_i2c_port, axp_i2c_addr, 0x12, 0x08, axp_i2c_freq); // LDO3 disable } lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x28, brightness, 0xF0, axp_i2c_freq); } }; struct Touch_M5Tough : public lgfx::ITouch { void wakeup(void) override {} void sleep(void) override {} bool init(void) override { _inited = false; if (isSPI()) return false; if (_cfg.pin_int >= 0) { lgfx::pinMode(_cfg.pin_int, lgfx::pin_mode_t::input); } _inited = lgfx::i2c::init(_cfg.i2c_port, _cfg.pin_sda, _cfg.pin_scl).has_value(); static constexpr uint8_t irq_modechange_cmd[] = { 0x5a, 0x5a }; /// (INT mode change) lgfx::i2c::transactionWrite(_cfg.i2c_port, _cfg.i2c_addr, irq_modechange_cmd, 2); return _inited; } std::uint_fast8_t getTouchRaw(touch_point_t *tp, std::uint_fast8_t count) override { if (tp) tp->size = 0; if (!_inited || count == 0) return 0; if (count > 2) count = 2; // max 2 point. if (_cfg.pin_int >= 0) { if (gpio_in(_cfg.pin_int)) return 0; } std::size_t len = 3 + count * 6; std::uint8_t buf[2][len]; std::int32_t retry = 5; bool flip = false; std::uint8_t* tmp; for (;;) { tmp = buf[flip]; memset(tmp, 0, len); if (lgfx::i2c::beginTransaction(_cfg.i2c_port, _cfg.i2c_addr, _cfg.freq, false)) { static constexpr std::uint8_t reg_number = 2; if (lgfx::i2c::writeBytes(_cfg.i2c_port, ®_number, 1) && lgfx::i2c::restart(_cfg.i2c_port, _cfg.i2c_addr, _cfg.freq, true) && lgfx::i2c::readBytes(_cfg.i2c_port, tmp, 1) && (tmp[0] != 0)) { flip = !flip; std::size_t points = std::min(count, tmp[0]); if (points && lgfx::i2c::readBytes(_cfg.i2c_port, &tmp[1], points * 6 - 2)) {} } if (lgfx::i2c::endTransaction(_cfg.i2c_port)) {} if (tmp[0] == 0 || memcmp(buf[0], buf[1], len) == 0) break; } if (0 == --retry) return 0; } if (count > tmp[0]) count = tmp[0]; for (std::size_t idx = 0; idx < count; ++idx) { auto data = &tmp[1 + idx * 6]; tp[idx].size = 1; tp[idx].x = (data[0] & 0x0F) << 8 | data[1]; tp[idx].y = (data[2] & 0x0F) << 8 | data[3]; tp[idx].id = idx; } return count; } }; struct Panel_M5StickC : public lgfx::Panel_ST7735S { Panel_M5StickC(void) { _cfg.invert = true; _cfg.pin_cs = GPIO_NUM_5; _cfg.pin_rst = GPIO_NUM_18; _cfg.panel_width = 80; _cfg.panel_height = 160; _cfg.offset_x = 26; _cfg.offset_y = 1; _cfg.offset_rotation = 2; } protected: const std::uint8_t* getInitCommands(std::uint8_t listno) const override { static constexpr std::uint8_t list[] = { CMD_GAMMASET, 1, 0x08, // Gamma set, curve 4 0xFF,0xFF, // end }; if (listno == 2) return list; return Panel_ST7735S::getInitCommands(listno); } }; struct Light_M5StickC : public lgfx::ILight { bool init(std::uint8_t brightness) override { lgfx::i2c::init(axp_i2c_port, axp_i2c_sda, axp_i2c_scl); lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x12, 0x4D, ~0, axp_i2c_freq); setBrightness(brightness); return true; } void setBrightness(std::uint8_t brightness) override { if (brightness) { brightness = (((brightness >> 1) + 8) / 13) + 5; lgfx::i2c::bitOn(axp_i2c_port, axp_i2c_addr, 0x12, 1 << 2, axp_i2c_freq); } else { lgfx::i2c::bitOff(axp_i2c_port, axp_i2c_addr, 0x12, 1 << 2, axp_i2c_freq); } lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x28, brightness << 4, 0x0F, axp_i2c_freq); } }; struct Panel_M5StickCPlus : public lgfx::Panel_ST7789 { Panel_M5StickCPlus(void) { _cfg.invert = true; _cfg.pin_cs = GPIO_NUM_5; _cfg.pin_rst = GPIO_NUM_18; _cfg.panel_width = 135; _cfg.panel_height = 240; _cfg.offset_x = 52; _cfg.offset_y = 40; } }; #elif defined (CONFIG_IDF_TARGET_ESP32S3) static constexpr int32_t i2c_freq = 400000; static constexpr int_fast16_t aw9523_i2c_addr = 0x58; // AW9523B static constexpr int_fast16_t axp_i2c_addr = 0x34; // AXP2101 static constexpr int_fast16_t gc0308_i2c_addr = 0x21; // GC0308 static constexpr int_fast16_t i2c_port = I2C_NUM_1; static constexpr int_fast16_t i2c_sda = GPIO_NUM_12; static constexpr int_fast16_t i2c_scl = GPIO_NUM_11; struct Panel_M5StackCoreS3 : public lgfx::Panel_ILI9342 { Panel_M5StackCoreS3(void) { _cfg.pin_cs = GPIO_NUM_3; _cfg.invert = true; _cfg.offset_rotation = 3; _rotation = 1; // default rotation } void rst_control(bool level) override { uint8_t bits = level ? (1<<5) : 0; uint8_t mask = level ? ~0 : ~(1<<5); // LCD_RST lgfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x03, bits, mask, i2c_freq); } void cs_control(bool flg) override { lgfx::Panel_ILI9342::cs_control(flg); // CS操作時にGPIO35の役割を切り替える (MISO or D/C); // FSPIQ_IN_IDX==FSPI MISO / SIG_GPIO_OUT_IDX==GPIO OUT // *(volatile uint32_t*)GPIO_FUNC35_OUT_SEL_CFG_REG = flg ? FSPIQ_OUT_IDX : SIG_GPIO_OUT_IDX; // CS HIGHの場合はGPIO出力を無効化し、MISO入力として機能させる。 // CS LOW の場合はGPIO出力を有効化し、D/Cとして機能させる。 *(volatile uint32_t*)( flg ? GPIO_ENABLE1_W1TC_REG : GPIO_ENABLE1_W1TS_REG ) = 1u << (GPIO_NUM_35 & 31); } }; struct Touch_M5StackCoreS3 : public lgfx::Touch_FT5x06 { Touch_M5StackCoreS3(void) { _cfg.pin_int = GPIO_NUM_21; _cfg.pin_sda = i2c_sda; _cfg.pin_scl = i2c_scl; _cfg.i2c_addr = 0x38; _cfg.i2c_port = i2c_port; _cfg.freq = i2c_freq; _cfg.x_min = 0; _cfg.x_max = 319; _cfg.y_min = 0; _cfg.y_max = 239; _cfg.bus_shared = false; } uint_fast8_t getTouchRaw(touch_point_t* tp, uint_fast8_t count) override { uint_fast8_t res = 0; if (!gpio_in(_cfg.pin_int)) { res = lgfx::Touch_FT5x06::getTouchRaw(tp, count); if (res == 0) { /// clear INT. // レジスタ 0x00を読み出すとPort0のINTがクリアされ、レジスタ 0x01を読み出すとPort1のINTがクリアされる。 lgfx::i2c::readRegister8(i2c_port, aw9523_i2c_addr, 0x00, i2c_freq); lgfx::i2c::readRegister8(i2c_port, aw9523_i2c_addr, 0x01, i2c_freq); } } return res; } }; struct Light_M5StackCoreS3 : public lgfx::ILight { bool init(uint8_t brightness) override { setBrightness(brightness); return true; } void setBrightness(uint8_t brightness) override { if (brightness) { brightness = ((brightness + 641) >> 5); // AXP2101 reg 0x90 = LDOS ON/OFF control lgfx::i2c::bitOn(i2c_port, axp_i2c_addr, 0x90, 0x80, i2c_freq); // DLDO1 enable } else { lgfx::i2c::bitOff(i2c_port, axp_i2c_addr, 0x90, 0x80, i2c_freq); // DLDO1 disable } // AXP2101 reg 0x99 = DLDO1 voltage setting lgfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x99, brightness, 0, i2c_freq); } }; struct Light_M5StackAtomS3R : public lgfx::ILight { bool init(uint8_t brightness) override { lgfx::i2c::init(i2c_port, GPIO_NUM_45, GPIO_NUM_0); lgfx::i2c::writeRegister8(i2c_port, 48, 0x00, 0b01000000, 0, i2c_freq); lgfx::delay(1); lgfx::i2c::writeRegister8(i2c_port, 48, 0x08, 0b00000001, 0, i2c_freq); lgfx::i2c::writeRegister8(i2c_port, 48, 0x70, 0b00000000, 0, i2c_freq); setBrightness(brightness); return true; } void setBrightness(uint8_t brightness) override { lgfx::i2c::writeRegister8(i2c_port, 48, 0x0e, brightness, 0, i2c_freq); } }; struct Light_M5StackStampPLC : public lgfx::ILight { bool _is_backlight_inited = false; bool init(uint8_t brightness) override { lgfx::i2c::init(i2c_port, GPIO_NUM_13, GPIO_NUM_15); // set direction: output auto value = lgfx::i2c::readRegister8(i2c_port, pi4io1_i2c_addr, 0x03, i2c_freq).has_value(); value |= (1 << 7); lgfx::i2c::writeRegister8(i2c_port, pi4io1_i2c_addr, 0x03, value, 0, i2c_freq); // set pull mode: down value = lgfx::i2c::readRegister8(i2c_port, pi4io1_i2c_addr, 0x0d, i2c_freq).has_value(); value &= ~(1 << 7); lgfx::i2c::writeRegister8(i2c_port, pi4io1_i2c_addr, 0x0d, value, 0, i2c_freq); // set high impedance: off value = lgfx::i2c::readRegister8(i2c_port, pi4io1_i2c_addr, 0x07, i2c_freq).has_value(); value &= ~(1 << 7); lgfx::i2c::writeRegister8(i2c_port, pi4io1_i2c_addr, 0x07, value, 0, i2c_freq); _is_backlight_inited = true; setBrightness(brightness); return true; } void setBrightness(uint8_t brightness) override { if (!_is_backlight_inited) init(127); auto value = lgfx::i2c::readRegister8(i2c_port, pi4io1_i2c_addr, 0x05, i2c_freq).has_value(); if (brightness == 0) { value |= (1 << 7); } else { value &= ~(1 << 7); } lgfx::i2c::writeRegister8(i2c_port, pi4io1_i2c_addr, 0x05, value, 0, i2c_freq); } }; #endif __attribute__ ((unused)) static void _pin_level(std::int_fast16_t pin, bool level) { lgfx::pinMode(pin, lgfx::pin_mode_t::output); if (level) lgfx::gpio_hi(pin); else lgfx::gpio_lo(pin); } __attribute__ ((unused)) static void _pin_reset(std::int_fast16_t pin, bool use_reset) { lgfx::gpio_hi(pin); lgfx::pinMode(pin, lgfx::pin_mode_t::output); lgfx::delay(1); if (!use_reset) return; lgfx::gpio_lo(pin); lgfx::delay(2); lgfx::gpio_hi(pin); lgfx::delay(10); } /// TF card dummy clock送信 ; static void _send_sd_dummy_clock(int spi_host, int_fast16_t pin_cs) { static constexpr uint32_t dummy_clock[] = { ~0u, ~0u, ~0u, ~0u }; _pin_level(pin_cs, true); m5gfx::spi::writeBytes(spi_host, (const uint8_t*)dummy_clock, sizeof(dummy_clock)); _pin_level(pin_cs, false); } /// TF card をSPIモードに移行する ; __attribute__ ((unused)) static void _set_sd_spimode(int spi_host, int_fast16_t pin_cs) { m5gfx::spi::beginTransaction(spi_host, 400000, 0); _send_sd_dummy_clock(spi_host, pin_cs); uint8_t sd_cmd58[] = { 0x7A, 0, 0, 0, 0, 0xFD, 0xFF, 0xFF }; // READ_OCR command. m5gfx::spi::readBytes(spi_host, sd_cmd58, sizeof(sd_cmd58)); if (sd_cmd58[6] == sd_cmd58[7]) // not SPI mode { _send_sd_dummy_clock(spi_host, pin_cs); static constexpr uint8_t sd_cmd0[] = { 0x40, 0, 0, 0, 0, 0x95, 0xFF, 0xFF }; // GO_IDLE_STATE command. m5gfx::spi::writeBytes(spi_host, sd_cmd0, sizeof(sd_cmd0)); } _pin_level(pin_cs, true); m5gfx::spi::endTransaction(spi_host); } __attribute__ ((unused)) static std::uint32_t _read_panel_id(lgfx::Bus_SPI* bus, std::int32_t pin_cs, std::uint32_t cmd = 0x04, std::uint8_t dummy_read_bit = 1) // 0x04 = RDDID command { bus->beginTransaction(); _pin_level(pin_cs, true); bus->writeCommand(0, 8); bus->wait(); _pin_level(pin_cs, false); bus->writeCommand(cmd, 8); bus->beginRead(dummy_read_bit); std::uint32_t res = bus->readData(32); bus->endTransaction(); _pin_level(pin_cs, true); ESP_LOGD(LIBRARY_NAME, "[Autodetect] read cmd:%02x = %08x", (int)cmd, (int)res); return res; } void M5GFX::_set_backlight(lgfx::ILight* bl) { // if (_light_last) { delete _light_last; } _light_last.reset(bl); _panel_last->setLight(bl); } void M5GFX::_set_pwm_backlight(std::int16_t pin, std::uint8_t ch, std::uint32_t freq, bool invert, uint8_t offset) { auto bl = new lgfx::Light_PWM(); auto cfg = bl->config(); cfg.pin_bl = pin; cfg.freq = freq; cfg.pwm_channel = ch; cfg.offset = offset; cfg.invert = invert; bl->config(cfg); _set_backlight(bl); } bool M5GFX::init_impl(bool use_reset, bool use_clear) { if (getBoard() != board_t::board_unknown) { return true; } static constexpr char NVS_KEY[] = "AUTODETECT"; std::uint32_t nvs_board = 0; std::uint32_t nvs_handle = 0; if (0 == nvs_open(LIBRARY_NAME, NVS_READONLY, &nvs_handle)) { nvs_get_u32(nvs_handle, NVS_KEY, static_cast(&nvs_board)); nvs_close(nvs_handle); ESP_LOGI(LIBRARY_NAME, "[Autodetect] load from NVS : board:%d", (int)nvs_board); } if (0 == nvs_board) { #if defined ( M5GFX_BOARD ) nvs_board = M5GFX_BOARD; #elif defined ( ARDUINO_M5STACK_CORE_ESP32 ) || defined ( ARDUINO_M5STACK_FIRE ) || defined ( ARDUINO_M5Stack_Core_ESP32 ) nvs_board = board_t::board_M5Stack; #elif defined ( ARDUINO_M5STACK_CORE2 ) || defined ( ARDUINO_M5STACK_Core2 ) nvs_board = board_t::board_M5StackCore2; #elif defined ( ARDUINO_M5STICK_C ) || defined ( ARDUINO_M5Stick_C ) nvs_board = board_t::board_M5StickC; #elif defined ( ARDUINO_M5STICK_C_PLUS ) || defined ( ARDUINO_M5Stick_C_Plus ) nvs_board = board_t::board_M5StickCPlus; #elif defined ( ARDUINO_M5STACK_COREINK ) || defined ( ARDUINO_M5Stack_CoreInk ) nvs_board = board_t::board_M5StackCoreInk; #elif defined ( ARDUINO_M5STACK_PAPER ) || defined ( ARDUINO_M5STACK_Paper ) nvs_board = board_t::board_M5Paper; #elif defined ( ARDUINO_M5STACK_TOUGH ) nvs_board = board_t::board_M5Tough; #elif defined ( ARDUINO_M5STACK_ATOM ) || defined ( ARDUINO_M5Stack_ATOM ) nvs_board = board_t::board_M5Atom; //#elif defined ( ARDUINO_M5STACK_TIMER_CAM ) || defined ( ARDUINO_M5Stack_Timer_CAM ) #endif } auto board = (board_t)nvs_board; int retry = 4; do { if (retry == 1) use_reset = true; board = autodetect(use_reset, board); //ESP_LOGD(LIBRARY_NAME,"autodetect board:%d", (int)board); } while (board_t::board_unknown == board && --retry >= 0); _board = board; #if defined ( ARDUINO_M5STACK_ATOM ) || defined ( ARDUINO_M5Stack_ATOM ) if (board == board_t::board_unknown || board == board_t::board_M5Atom) { return false; } #endif if (nvs_board != board) { if (0 == nvs_open(LIBRARY_NAME, NVS_READWRITE, &nvs_handle)) { ESP_LOGI(LIBRARY_NAME, "[Autodetect] save to NVS : board:%d", (int)board); nvs_set_u32(nvs_handle, NVS_KEY, board); nvs_close(nvs_handle); } } /// autodetectの際にreset済みなのでここではuse_resetをfalseで呼び出す。; /// M5Paperはreset後の復帰に800msec程度掛かるのでreset省略は起動時間短縮に有効; return LGFX_Device::init_impl(false, use_clear); } board_t M5GFX::autodetect(bool use_reset, board_t board) { auto bus_spi = new Bus_SPI(); _bus_last.reset(bus_spi); panel(nullptr); auto bus_cfg = bus_spi->config(); (void)bus_cfg; // prevent compiler warning. bus_cfg.freq_write = 8000000; bus_cfg.freq_read = 8000000; bus_cfg.spi_mode = 0; bus_cfg.use_lock = true; #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32) bus_cfg.spi_host = VSPI_HOST; bus_cfg.dma_channel = 1; std::uint32_t id; std::uint32_t pkg_ver = m5gfx::get_pkg_ver(); // ESP_LOGD(LIBRARY_NAME, "pkg_ver : %02x", (int)pkg_ver); if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) /// check PICO-D4 (M5StickC,CPlus,T,T2 / CoreInk / ATOM ) { if (board == 0 || board == board_t::board_M5StickC || board == board_t::board_M5StickCPlus) { _pin_reset(GPIO_NUM_18, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_15; bus_cfg.pin_miso = GPIO_NUM_14; bus_cfg.pin_sclk = GPIO_NUM_13; bus_cfg.pin_dc = GPIO_NUM_23; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_5); if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { // check panel (ST7789) board = board_t::board_M5StickCPlus; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StickCPlus"); bus_spi->release(); bus_cfg.spi_host = HSPI_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 15000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StickCPlus(); p->bus(bus_spi); _panel_last.reset(p); _set_backlight(new Light_M5StickC()); goto init_clear; } if ((id & 0xFF) == 0x7C) { // check panel (ST7735) board = board_t::board_M5StickC; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StickC"); bus_spi->release(); bus_cfg.spi_host = HSPI_HOST; bus_cfg.freq_write = 27000000; bus_cfg.freq_read = 14000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StickC(); p->bus(bus_spi); _panel_last.reset(p); _set_backlight(new Light_M5StickC()); goto init_clear; } lgfx::pinMode(GPIO_NUM_18, lgfx::pin_mode_t::input); // LCD RST lgfx::pinMode(GPIO_NUM_5 , lgfx::pin_mode_t::input); // LCD CS bus_spi->release(); } if (board == 0 || board == board_t::board_M5StackCoreInk) { _pin_reset( GPIO_NUM_0, true); // EPDがDeepSleepしている場合は自動認識に失敗する。そのためRST制御を必ず行う。; bus_cfg.pin_mosi = GPIO_NUM_23; bus_cfg.pin_miso = GPIO_NUM_34; bus_cfg.pin_sclk = GPIO_NUM_18; bus_cfg.pin_dc = GPIO_NUM_15; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); lgfx::Panel_HasBuffer* p = nullptr; id = _read_panel_id(bus_spi, GPIO_NUM_9, 0x2f ,0); if (id == 0x00010001) { // check panel (e-paper GDEW0154D67) p = new lgfx::Panel_GDEW0154D67(); } else { id = _read_panel_id(bus_spi, GPIO_NUM_9, 0x70, 0); if ((id & 0xFFFF00FFu) == 0x00F00000u) { // check panel (e-paper GDEW0154M09) // ID of first lot : 0x00F00000u // ID of 2023/11/17 : 0x00F01600u p = new lgfx::Panel_GDEW0154M09(); } } if (p != nullptr) { _pin_level(GPIO_NUM_12, true); // POWER_HOLD_PIN 12 board = board_t::board_M5StackCoreInk; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StackCoreInk"); bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); p->bus(bus_spi); _panel_last.reset(p); auto cfg = p->config(); cfg.panel_height = 200; cfg.panel_width = 200; cfg.pin_cs = GPIO_NUM_9; cfg.pin_rst = GPIO_NUM_0; cfg.pin_busy = GPIO_NUM_4; p->config(cfg); goto init_clear; } lgfx::pinMode(GPIO_NUM_0, lgfx::pin_mode_t::input); // RST lgfx::pinMode(GPIO_NUM_9, lgfx::pin_mode_t::input); // CS bus_spi->release(); } /// LCD / EPD 検出失敗の場合はATOM 判定; } else if (pkg_ver == 6) // PICOV3_02 (StickCPlus2 / ATOM PSRAM) { if (board == 0 || board == board_t::board_M5StickCPlus2) { _pin_reset(GPIO_NUM_12, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_15; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_13; bus_cfg.pin_dc = GPIO_NUM_14; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_5); if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { // check panel (ST7789) _pin_level(GPIO_NUM_4, true); // POWER_HOLD_PIN 4 board = board_t::board_M5StickCPlus2; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StickCPlus2"); bus_spi->release(); bus_cfg.spi_host = HSPI_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 15000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StickCPlus(); { auto cfg = p->config(); cfg.pin_rst = GPIO_NUM_12; p->config(cfg); } p->bus(bus_spi); _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_27, 7, 256, false, 40); goto init_clear; } lgfx::pinMode(GPIO_NUM_12, lgfx::pin_mode_t::input); // LCD RST lgfx::pinMode(GPIO_NUM_5 , lgfx::pin_mode_t::input); // LCD CS bus_spi->release(); } if (board == 0) { board = board_t::board_M5AtomPsram; goto init_clear; } } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6) { /// AXP192の有無を最初に判定し、分岐する。; if (board == 0 || board == board_t::board_M5Station || board == board_t::board_M5StackCore2 || board == board_t::board_M5Tough) { // I2C addr 0x34 = AXP192 lgfx::i2c::init(axp_i2c_port, axp_i2c_sda, axp_i2c_scl); auto chk_axp = lgfx::i2c::readRegister8(axp_i2c_port, axp_i2c_addr, 0x03, 400000); if (chk_axp.has_value()) { uint_fast16_t axp_exists = 0; if (chk_axp.value() == 0x03) { // AXP192 found axp_exists = 192; ESP_LOGD(LIBRARY_NAME, "AXP192 found"); } else if (chk_axp.value() == 0x4A) { // AXP2101 found axp_exists = 2101; ESP_LOGD(LIBRARY_NAME, "AXP2101 found"); } if (axp_exists == 192 && (board == 0 || board == board_t::board_M5Station)) { _pin_reset(GPIO_NUM_15, use_reset); // LCD RST; bus_cfg.pin_mosi = GPIO_NUM_23; bus_cfg.pin_miso = -1; bus_cfg.pin_sclk = GPIO_NUM_18; bus_cfg.pin_dc = GPIO_NUM_19; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_5); if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { // check panel (ST7789) ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5Station"); board = board_t::board_M5Station; bus_spi->release(); bus_cfg.spi_host = HSPI_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 15000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StickCPlus(); { auto cfg = p->config(); cfg.pin_rst = 15; p->config(cfg); p->setRotation(1); } p->bus(bus_spi); _panel_last.reset(p); /// M5StationのバックライトはM5Toughと同じ; _set_backlight(new Light_M5Tough()); goto init_clear; } bus_spi->release(); lgfx::pinMode(GPIO_NUM_5 , lgfx::pin_mode_t::input); // LCD CS lgfx::pinMode(GPIO_NUM_15, lgfx::pin_mode_t::input); // LCD RST } if (axp_exists && (board == 0 || board == board_t::board_M5StackCore2 || board == board_t::board_M5Tough)) { // fore Core2 1st gen (AXP192) // AXP192_LDO2 = LCD PWR // AXP192_IO4 = LCD RST // AXP192_DC3 = LCD BL (Core2) // AXP192_LDO3 = LCD BL (Tough) // AXP192_IO1 = TP RST (Tough) static constexpr uint8_t reg_data_axp192_first[] = { 0x95, 0x84, 0x72, // GPIO4 enable 0x28, 0xF0, 0xFF, // set LDO2 3300mv // LCD PWR 0x12, 0x04, 0xFF, // LDO2 enable 0x92, 0x00, 0xF8, // GPIO1 OpenDrain (M5Tough TOUCH) 0xFF, 0xFF, 0xFF, }; static constexpr uint8_t reg_data_axp192_reset[] = { 0x96, 0x00, 0xFD, // GPIO4 LOW (LCD RST) 0x94, 0x00, 0xFD, // GPIO1 LOW (M5Tough TOUCH RST) 0xFF, 0xFF, 0xFF, }; static constexpr uint8_t reg_data_axp192_second[] = { 0x96, 0x02, 0xFF, // GPIO4 HIGH (LCD RST) 0x94, 0x02, 0xFF, // GPIO1 HIGH (M5Tough TOUCH RST) 0xFF, 0xFF, 0xFF, }; // for Core2 v1.1 (AXP2101) // ALDO2 == LCD+TOUCH RST // ALDO3 == SPK EN // ALDO4 == TF, TP, LCD PWR // BLDO1 == LCD BL // BLDO2 == Boost EN // DLDO1 == Vibration Motor static constexpr uint8_t reg_data_axp2101_first[] = { 0x90, 0x08, 0x7B, // ALDO4 ON / ALDO3 OFF, DLDO1 OFF 0x80, 0x05, 0xFF, // DCDC1 + DCDC3 ON 0x82, 0x12, 0x00, // DCDC1 3.3V 0x84, 0x6A, 0x00, // DCDC3 3.3V 0xFF, 0xFF, 0xFF, }; static constexpr uint8_t reg_data_axp2101_reset[] = { 0x90, 0x00, 0xFD, // ALDO2 OFF 0xFF, 0xFF, 0xFF, }; static constexpr uint8_t reg_data_axp2101_second[] = { 0x90, 0x02, 0xFF, // ALDO2 ON 0xFF, 0xFF, 0xFF, }; _pin_level(GPIO_NUM_5, true); bool isAxp192 = axp_exists == 192; i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_first : reg_data_axp2101_first, axp_i2c_freq); if (use_reset) { i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_reset : reg_data_axp2101_reset, axp_i2c_freq); lgfx::delay(1); } i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_second : reg_data_axp2101_second, axp_i2c_freq); lgfx::delay(1); { bus_cfg.pin_mosi = GPIO_NUM_23; bus_cfg.pin_miso = GPIO_NUM_38; bus_cfg.pin_sclk = GPIO_NUM_18; bus_cfg.pin_dc = GPIO_NUM_15; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); _set_sd_spimode(bus_cfg.spi_host, GPIO_NUM_4); id = _read_panel_id(bus_spi, GPIO_NUM_5); if ((id & 0xFF) == 0xE3) { // ILI9342c bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StackCore2(); p->bus(bus_spi); _panel_last.reset(p); // Tough のタッチコントローラ有無をチェックする; // Core2/Tough 判別条件としてCore2のTP(0x38)の有無を用いた場合、以下の問題が生じる; // ・Core2のTPがスリープしている場合は反応が得られない; // ・ToughにGoPlus2を組み合わせると0x38に反応がある; // 上記のことから、ここではToughのTP(0x2E)の有無によって判定する; if ( ! lgfx::i2c::readRegister8(axp_i2c_port, 0x2E, 0, 400000).has_value()) // 0x2E:M5Tough TOUCH { ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StackCore2"); board = board_t::board_M5StackCore2; ILight* light = nullptr; if (isAxp192) { light = new Light_M5StackCore2(); } else { light = new Light_M5StackCore2_AXP2101(); } _set_backlight(light); auto t = new lgfx::Touch_FT5x06(); _touch_last.reset(t); auto cfg = t->config(); cfg.pin_int = GPIO_NUM_39; cfg.pin_sda = GPIO_NUM_21; cfg.pin_scl = GPIO_NUM_22; cfg.i2c_addr = 0x38; cfg.i2c_port = I2C_NUM_1; cfg.freq = 400000; cfg.x_min = 0; cfg.x_max = 319; cfg.y_min = 0; cfg.y_max = 279; cfg.bus_shared = false; t->config(cfg); p->touch(t); float affine[6] = { 1, 0, 0, 0, 1, 0 }; p->setCalibrateAffine(affine); } else { ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5Tough"); board = board_t::board_M5Tough; _set_backlight(new Light_M5Tough()); auto t = new Touch_M5Tough(); _touch_last.reset(t); auto cfg = t->config(); cfg.pin_int = GPIO_NUM_39; cfg.pin_sda = GPIO_NUM_21; cfg.pin_scl = GPIO_NUM_22; cfg.i2c_addr = 0x2E; cfg.i2c_port = I2C_NUM_1; cfg.freq = 400000; cfg.x_min = 0; cfg.x_max = 319; cfg.y_min = 0; cfg.y_max = 239; cfg.bus_shared = false; t->config(cfg); p->touch(t); } goto init_clear; } lgfx::pinMode(GPIO_NUM_4, lgfx::pin_mode_t::input); // TF card CS lgfx::pinMode(GPIO_NUM_5, lgfx::pin_mode_t::input); // LCD CS bus_spi->release(); } } } } if (board == 0 || board == board_t::board_M5Stack) { _pin_reset(GPIO_NUM_33, use_reset); // LCD RST; bus_cfg.pin_mosi = GPIO_NUM_23; bus_cfg.pin_miso = GPIO_NUM_19; bus_cfg.pin_sclk = GPIO_NUM_18; bus_cfg.pin_dc = GPIO_NUM_27; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); _set_sd_spimode(bus_cfg.spi_host, GPIO_NUM_4); id = _read_panel_id(bus_spi, GPIO_NUM_14); if ((id & 0xFF) == 0xE3) { // ILI9342c ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5Stack"); board = board_t::board_M5Stack; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); auto p = new Panel_M5Stack(); p->bus(bus_spi); _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_32, 7, 44100); goto init_clear; } bus_spi->release(); lgfx::pinMode(GPIO_NUM_4 , lgfx::pin_mode_t::input); // TF card CS lgfx::pinMode(GPIO_NUM_14, lgfx::pin_mode_t::input); // LCD CS lgfx::pinMode(GPIO_NUM_33, lgfx::pin_mode_t::input); // LCD RST } if (board == 0 || board == board_t::board_M5Paper) { _pin_reset(GPIO_NUM_23, true); lgfx::pinMode(GPIO_NUM_27, lgfx::pin_mode_t::input_pullup); // M5Paper EPD busy pin if (!lgfx::gpio_in(GPIO_NUM_27)) { _pin_level(GPIO_NUM_2, true); // M5EPD_MAIN_PWR_PIN 2 lgfx::pinMode(GPIO_NUM_27, lgfx::pin_mode_t::input); bus_cfg.pin_mosi = GPIO_NUM_12; bus_cfg.pin_miso = GPIO_NUM_13; bus_cfg.pin_sclk = GPIO_NUM_14; bus_cfg.pin_dc = -1; bus_cfg.spi_3wire = false; bus_spi->config(bus_cfg); id = lgfx::millis(); _pin_level(GPIO_NUM_15, true); // M5Paper CS; bus_spi->init(); _set_sd_spimode(bus_cfg.spi_host, GPIO_NUM_4); do { vTaskDelay(1); if (lgfx::millis() - id > 1024) { id = 0; break; } } while (!lgfx::gpio_in(GPIO_NUM_27)); if (id) { bus_spi->beginTransaction(); lgfx::gpio_lo(GPIO_NUM_15); bus_spi->writeData(__builtin_bswap16(0x6000), 16); bus_spi->writeData(__builtin_bswap16(0x0302), 16); // read DevInfo id = lgfx::millis(); bus_spi->wait(); lgfx::gpio_hi(GPIO_NUM_15); do { vTaskDelay(1); if (lgfx::millis() - id > 192) { break; } } while (!lgfx::gpio_in(GPIO_NUM_27)); lgfx::gpio_lo(GPIO_NUM_15); bus_spi->writeData(__builtin_bswap16(0x1000), 16); bus_spi->writeData(__builtin_bswap16(0x0000), 16); std::uint8_t buf[40]; bus_spi->beginRead(); bus_spi->readBytes(buf, 40, false); bus_spi->endRead(); bus_spi->endTransaction(); lgfx::gpio_hi(GPIO_NUM_15); id = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; // ESP_LOGI(LIBRARY_NAME, "[Autodetect] panel size :%08x", (int)id); if (id == 0x03C0021C) { // check panel ( panel size 960(0x03C0) x 540(0x021C) ) board = board_t::board_M5Paper; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5Paper"); bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 20000000; bus_spi->config(bus_cfg); { auto p = new lgfx::Panel_IT8951(); p->bus(bus_spi); _panel_last.reset(p); auto cfg = p->config(); cfg.panel_height = 540; cfg.panel_width = 960; cfg.pin_cs = GPIO_NUM_15; cfg.pin_rst = GPIO_NUM_23; cfg.pin_busy = GPIO_NUM_27; cfg.offset_rotation = 3; p->config(cfg); } { auto t = new lgfx::Touch_GT911(); _touch_last.reset(t); auto cfg = t->config(); cfg.pin_int = GPIO_NUM_36; cfg.pin_sda = GPIO_NUM_21; cfg.pin_scl = GPIO_NUM_22; #ifdef _M5EPD_H_ cfg.i2c_port = I2C_NUM_0; #else cfg.i2c_port = I2C_NUM_1; #endif cfg.freq = 400000; cfg.x_min = 0; cfg.x_max = 539; cfg.y_min = 0; cfg.y_max = 959; cfg.offset_rotation = 1; cfg.bus_shared = false; t->config(cfg); _panel_last->touch(t); } goto init_clear; } } bus_spi->release(); lgfx::pinMode(GPIO_NUM_15, lgfx::pin_mode_t::input); // EPD CS lgfx::pinMode(GPIO_NUM_4, lgfx::pin_mode_t::input); // M5Paper TF card CS lgfx::pinMode(GPIO_NUM_2, lgfx::pin_mode_t::input); // M5EPD_MAIN_PWR_PIN 2 } lgfx::pinMode(GPIO_NUM_27, lgfx::pin_mode_t::input); // BUSY lgfx::pinMode(GPIO_NUM_23, lgfx::pin_mode_t::input); // RST } } #elif defined (CONFIG_IDF_TARGET_ESP32S3) bus_cfg.spi_host = SPI2_HOST; bus_cfg.dma_channel = SPI_DMA_CH_AUTO; std::uint32_t id; std::uint32_t pkg_ver = m5gfx::get_pkg_ver(); // ESP_LOGD(LIBRARY_NAME, "pkg_ver : %02x / board:%d", (int)pkg_ver, (int)board); switch (pkg_ver) { case 0: // EFUSE_PKG_VERSION_ESP32S3: // QFN56 if (board == 0 || board == board_t::board_M5StackCoreS3 || board == board_t::board_M5StackCoreS3SE) { lgfx::i2c::init(i2c_port, i2c_sda, i2c_scl); // ESP_LOGI("DEBUG","AW 0x10 :%02x", (int)lgfx::i2c::readRegister8(i2c_port, aw9523_i2c_addr, 0x10, 400000).value()); // ESP_LOGI("DEBUG","AXP0x03 :%02x", (int)lgfx::i2c::readRegister8(i2c_port, axp_i2c_addr, 0x03, 400000).value()); auto chk_axp = lgfx::i2c::readRegister8(i2c_port, axp_i2c_addr, 0x03, i2c_freq); if (chk_axp.has_value() && chk_axp.value() == 0x4A) { auto chk_aw = lgfx::i2c::readRegister8(i2c_port, aw9523_i2c_addr, 0x10, i2c_freq); if (chk_aw .has_value() && chk_aw .value() == 0x23) { auto result = lgfx::gpio::command( (const uint8_t[]) { lgfx::gpio::command_mode_input_pullup, GPIO_NUM_35, lgfx::gpio::command_mode_input_pullup, GPIO_NUM_36, lgfx::gpio::command_mode_input_pullup, GPIO_NUM_37, lgfx::gpio::command_read , GPIO_NUM_35, lgfx::gpio::command_read , GPIO_NUM_36, lgfx::gpio::command_read , GPIO_NUM_37, lgfx::gpio::command_end } ); /// SPIバスのプルアップが効いていない場合はVBUS 5V出力を有効化する。 /// (USBホストモジュール等、5Vが出ていないと信号線の電気を吸い込む組合せがあるため) uint8_t reg0x02 = (result == 0) ? 0b00000111 : 0b00000101; uint8_t reg0x03 = (result == 0) ? 0b10000011 : 0b00000011; m5gfx::i2c::bitOn(i2c_port, aw9523_i2c_addr, 0x02, reg0x02); //port0 output ctrl m5gfx::i2c::bitOn(i2c_port, aw9523_i2c_addr, 0x03, reg0x03); //port1 output ctrl m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x04, 0b00011000); // CONFIG_P0 m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x05, 0b00001100); // CONFIG_P1 m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x11, 0b00010000); // GCR P0 port is Push-Pull mode. m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x12, 0b11111111); // LEDMODE_P0 m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x13, 0b11111111); // LEDMODE_P1 m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x90, 0xBF); // LDOS ON/OFF control 0 m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x94, 33 - 5); // ALDO3 set to 3.3v // for GC0308 Camera m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x95, 33 - 5); // ALDO4 set to 3.3v // for TF card slot bus_cfg.pin_mosi = GPIO_NUM_37; bus_cfg.pin_miso = GPIO_NUM_35; bus_cfg.pin_sclk = GPIO_NUM_36; bus_cfg.pin_dc = GPIO_NUM_35;// MISOとLCD D/CをGPIO35でシェアしている; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); _set_sd_spimode(bus_cfg.spi_host, GPIO_NUM_4); id = _read_panel_id(bus_spi, GPIO_NUM_3); if ((id & 0xFF) == 0xE3) { // check panel (ILI9342) board = board_t::board_M5StackCoreS3; // Camera GC0308 check (not found == M5StackCoreS3SE) auto chk_gc = lgfx::i2c::readRegister8(i2c_port, gc0308_i2c_addr, 0x00, i2c_freq); if (chk_gc .has_value() && chk_gc .value() == 0x9b) { ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5StackCoreS3"); } else { board = board_M5StackCoreS3SE; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5StackCoreS3SE"); } bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); auto p = new Panel_M5StackCoreS3(); p->bus(bus_spi); _panel_last.reset(p); _set_backlight(new Light_M5StackCoreS3()); { auto t = new Touch_M5StackCoreS3(); _touch_last.reset(t); _panel_last->touch(t); } goto init_clear; } bus_spi->release(); lgfx::pinMode(GPIO_NUM_4, lgfx::pin_mode_t::input); // TF card CS lgfx::pinMode(GPIO_NUM_3, lgfx::pin_mode_t::input); // LCD CS } } lgfx::i2c::release(i2c_port); } if (board == 0 || board == board_t::board_M5Dial) { _pin_reset(GPIO_NUM_8, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_5; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_6; bus_cfg.pin_dc = GPIO_NUM_4; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_7); if ((id & 0xFFFFFF) == 0x019a00) { // check panel (GC9A01) board = board_t::board_M5Dial; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5Dial"); bus_spi->release(); bus_cfg.freq_write = 80000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_GC9A01(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_7; cfg.pin_rst = GPIO_NUM_8; cfg.panel_width = 240; cfg.panel_height = 240; cfg.readable = false; cfg.invert = true; p->config(cfg); } _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_9, 7, 44100); { auto t = new m5gfx::Touch_FT5x06(); if (t) { _touch_last.reset(t); auto cfg = t->config(); cfg.x_min = 0; cfg.x_max = 239; cfg.y_min = 0; cfg.y_max = 239; cfg.pin_int = GPIO_NUM_14; cfg.bus_shared = false; cfg.offset_rotation = 0; cfg.i2c_port = 1; cfg.i2c_addr = 0x38; cfg.pin_sda = GPIO_NUM_11; cfg.pin_scl = GPIO_NUM_12; cfg.freq = 400000; t->config(cfg); _panel_last->touch(t); } } goto init_clear; } lgfx::pinMode(GPIO_NUM_8, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } if (board == 0 || board == board_t::board_M5PaperS3) { static constexpr int_fast16_t papers3_i2c_sda = GPIO_NUM_41; static constexpr int_fast16_t papers3_i2c_scl = GPIO_NUM_42; static constexpr const uint8_t gt911_i2c_addr[] = { 0x14, 0x5D }; gpio::pin_backup_t backup_pins[] = { papers3_i2c_sda, papers3_i2c_scl }; auto result = lgfx::gpio::command( (const uint8_t[]) { lgfx::gpio::command_mode_output , papers3_i2c_scl, lgfx::gpio::command_write_low , papers3_i2c_scl, lgfx::gpio::command_mode_output , papers3_i2c_sda, lgfx::gpio::command_write_low , papers3_i2c_sda, lgfx::gpio::command_write_high , papers3_i2c_scl, lgfx::gpio::command_write_high , papers3_i2c_sda, lgfx::gpio::command_mode_input_pulldown, papers3_i2c_scl, lgfx::gpio::command_mode_input_pulldown, papers3_i2c_sda, lgfx::gpio::command_delay , 1, lgfx::gpio::command_read , papers3_i2c_scl, lgfx::gpio::command_read , papers3_i2c_sda, lgfx::gpio::command_end } ); // Check G41,G42 HIGH if (result == 0x03) { lgfx::i2c::init(i2c_port, papers3_i2c_sda, papers3_i2c_scl); { bool gt911_found = false; for (auto addr: gt911_i2c_addr) { if (lgfx::i2c::beginTransaction(i2c_port, addr, 400000).has_value()) { gt911_found = lgfx::i2c::endTransaction(i2c_port).has_value(); if (gt911_found) { break; } } } if (gt911_found) { board = board_t::board_M5PaperS3; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5PaperS3"); // PWROFF_PULSE_PIN lgfx::pinMode(GPIO_NUM_44, lgfx::pin_mode_t::output); lgfx::gpio_lo(GPIO_NUM_44); #if !(defined(CONFIG_ESP32S3_SPIRAM_SUPPORT)) ESP_LOGE(LIBRARY_NAME, "M5PaperS3 need OPI-PSRAM enabled"); #elif !defined (CONFIG_SPIRAM_MODE_OCT) ESP_LOGE(LIBRARY_NAME, "M5PaperS3 need OPI-PSRAM enabled"); #else auto bus_epd = new Bus_EPD(); _bus_last.reset(bus_epd); auto p = new lgfx::Panel_EPD(); _panel_last.reset(p); { auto bus_cfg = bus_epd->config(); bus_cfg.bus_speed = 20000000; bus_cfg.pin_data[0] = GPIO_NUM_6; bus_cfg.pin_data[1] = GPIO_NUM_14; bus_cfg.pin_data[2] = GPIO_NUM_7; bus_cfg.pin_data[3] = GPIO_NUM_12; bus_cfg.pin_data[4] = GPIO_NUM_9; bus_cfg.pin_data[5] = GPIO_NUM_11; bus_cfg.pin_data[6] = GPIO_NUM_8; bus_cfg.pin_data[7] = GPIO_NUM_10; bus_cfg.pin_pwr = GPIO_NUM_46; bus_cfg.pin_spv = GPIO_NUM_17; bus_cfg.pin_ckv = GPIO_NUM_18; bus_cfg.pin_sph = GPIO_NUM_13; bus_cfg.pin_oe = GPIO_NUM_45; bus_cfg.pin_le = GPIO_NUM_15; bus_cfg.pin_cl = GPIO_NUM_16; bus_cfg.bus_width = 8; bus_epd->config(bus_cfg); p->setBus(bus_epd); } { auto cfg_detail = p->config_detail(); cfg_detail.line_padding = 8; p->config_detail(cfg_detail); } { auto cfg = p->config(); cfg.memory_width = 960; cfg.panel_width = 960; cfg.memory_height = 540; cfg.panel_height = 540; cfg.offset_rotation = 3; cfg.offset_x = 0; cfg.offset_y = 0; cfg.bus_shared = false; p->config(cfg); } { auto t = new lgfx::Touch_GT911(); _touch_last.reset(t); auto cfg = t->config(); cfg.pin_int = GPIO_NUM_48; cfg.pin_sda = GPIO_NUM_41; cfg.pin_scl = GPIO_NUM_42; cfg.freq = 400000; cfg.i2c_port = I2C_NUM_1; cfg.x_min = 0; cfg.x_max = 539; cfg.y_min = 0; cfg.y_max = 959; cfg.offset_rotation = 1; cfg.bus_shared = false; t->config(cfg); _panel_last->touch(t); p->touch(t); } goto init_clear; #endif } } lgfx::i2c::release(i2c_port); } for (auto &bup : backup_pins) { bup.restore(); } } if (board == 0 || board == board_t::board_M5AtomS3) { _pin_reset(GPIO_NUM_34, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_21; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_17; bus_cfg.pin_dc = GPIO_NUM_33; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_15); if ((id & 0xFFFFFF) == 0x079100) { // check panel (GC9107) board = board_t::board_M5AtomS3; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5AtomS3"); bus_spi->release(); bus_cfg.spi_host = SPI3_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_GC9107(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_15; cfg.pin_rst = GPIO_NUM_34; cfg.panel_width = 128; cfg.panel_height = 128; cfg.offset_y = 32; cfg.readable = false; p->config(cfg); } _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_16, 7, 256, false, 48); goto init_clear; } lgfx::pinMode(GPIO_NUM_48, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } if (board == 0 || board == board_t::board_M5DinMeter) { _pin_reset(GPIO_NUM_8, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_5; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_6; bus_cfg.pin_dc = GPIO_NUM_4; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_7); if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { // check panel (ST7789) board = board_t::board_M5DinMeter; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5DinMeter"); bus_spi->release(); bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_ST7789(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_7; cfg.pin_rst = GPIO_NUM_8; cfg.panel_width = 135; cfg.panel_height = 240; cfg.offset_x = 52; cfg.offset_y = 40; cfg.offset_rotation = 2; cfg.readable = true; cfg.invert = true; p->config(cfg); } _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_9, 7, 256, false, 16); goto init_clear; } lgfx::pinMode(GPIO_NUM_8, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } if (board == 0 || board == board_t::board_M5Cardputer || board == board_t::board_M5VAMeter) { _pin_reset(GPIO_NUM_33, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_35; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_36; bus_cfg.pin_dc = GPIO_NUM_34; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_37); // check panel (ST7789) if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { board = board_t::board_M5Cardputer; gpio::pin_backup_t backup_pins[] = { GPIO_NUM_5, GPIO_NUM_6 }; auto result = lgfx::gpio::command( (const uint8_t[]) { lgfx::gpio::command_mode_input_pulldown, GPIO_NUM_6, lgfx::gpio::command_mode_input_pulldown, GPIO_NUM_5, lgfx::gpio::command_read , GPIO_NUM_6, lgfx::gpio::command_read , GPIO_NUM_5, lgfx::gpio::command_end } ); for (auto &bup : backup_pins) { bup.restore(); } if (result == 3) { m5gfx::i2c::i2c_temporary_switcher_t backup_i2c_setting(1, GPIO_NUM_5, GPIO_NUM_6); result = (m5gfx::i2c::transactionWrite(1, 0x40, nullptr, 0).has_value() && m5gfx::i2c::transactionWrite(1, 0x41, nullptr, 0).has_value()); backup_i2c_setting.restore(); if (result) { board = board_t::board_M5VAMeter; } } bus_spi->release(); bus_cfg.spi_host = SPI3_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_ST7789(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_37; cfg.pin_rst = GPIO_NUM_33; cfg.panel_height = 240; cfg.offset_rotation = 0; cfg.readable = true; cfg.invert = true; int rotation = 0; int bl_freq = 256; int bl_offset = 16; if (board == board_t::board_M5Cardputer) { ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5Cardputer"); cfg.panel_width = 135; cfg.offset_x = 52; cfg.offset_y = 40; rotation = 1; } else { ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5VAMeter"); cfg.panel_width = 240; cfg.offset_x = 0; cfg.offset_y = 0; bl_freq = 512; bl_offset = 64; } p->config(cfg); p->setRotation(rotation); _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_38, 7, bl_freq, false, bl_offset); } goto init_clear; } lgfx::pinMode(GPIO_NUM_33, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } if (board == 0 || board == board_t::board_M5AirQ) { _pin_reset( GPIO_NUM_2, true); // EPDがDeepSleepしている場合は自動認識に失敗する。そのためRST制御を必ず行う。; bus_cfg.pin_mosi = GPIO_NUM_6; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_5; bus_cfg.pin_dc = GPIO_NUM_3; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); lgfx::Panel_HasBuffer* p = nullptr; id = _read_panel_id(bus_spi, GPIO_NUM_4, 0x2f ,0); if (id == 0x00010001) { // check panel (e-paper GDEW0154D67) p = new lgfx::Panel_GDEW0154D67(); } else { id = _read_panel_id(bus_spi, GPIO_NUM_4, 0x70, 0); if ((id & 0xFFFF00FFu) == 0x00F00000u) { // check panel (e-paper GDEW0154M09) // ID of first lot : 0x00F00000u // ID of 2023/11/17 : 0x00F01600u p = new lgfx::Panel_GDEW0154M09(); } } if (p != nullptr) { _pin_level(GPIO_NUM_46, true); // POWER_HOLD_PIN 46 board = board_t::board_M5AirQ; ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5AirQ"); bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); p->bus(bus_spi); _panel_last.reset(p); auto cfg = p->config(); cfg.panel_height = 200; cfg.panel_width = 200; cfg.pin_cs = GPIO_NUM_4; cfg.pin_rst = GPIO_NUM_2; cfg.pin_busy = GPIO_NUM_1; p->config(cfg); goto init_clear; } lgfx::pinMode(GPIO_NUM_2, lgfx::pin_mode_t::input); // RST lgfx::pinMode(GPIO_NUM_4, lgfx::pin_mode_t::input); // CS bus_spi->release(); } if (board == 0 || board == board_t::board_M5StampPLC) { _pin_reset(GPIO_NUM_3, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_8; bus_cfg.pin_miso = GPIO_NUM_9; bus_cfg.pin_sclk = GPIO_NUM_7; bus_cfg.pin_dc = GPIO_NUM_6; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); _set_sd_spimode(bus_cfg.spi_host, GPIO_NUM_10); id = _read_panel_id(bus_spi, GPIO_NUM_12); // check panel (ST7789) if ((id & 0xFB) == 0x81) // 0x81 or 0x85 { board = board_t::board_M5StampPLC; bus_spi->release(); bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_ST7789(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_12; cfg.pin_rst = GPIO_NUM_3; cfg.panel_width = 135; cfg.panel_height = 240; cfg.offset_x = 52; cfg.offset_y = 40; cfg.offset_rotation = 0; cfg.readable = true; cfg.invert = true; cfg.bus_shared = true; p->config(cfg); p->setRotation(1); } _panel_last.reset(p); _set_backlight(new Light_M5StackStampPLC()); goto init_clear; } lgfx::pinMode(GPIO_NUM_3, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } break; case 1: // EFUSE_PKG_VERSION_ESP32S3PICO: // LGA56 if (board == 0 || board == board_t::board_M5AtomS3R) { _pin_reset(GPIO_NUM_48, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_21; bus_cfg.pin_miso = (gpio_num_t)-1; //GPIO_NUM_NC; bus_cfg.pin_sclk = GPIO_NUM_15; bus_cfg.pin_dc = GPIO_NUM_42; bus_cfg.spi_mode = 0; bus_cfg.spi_3wire = true; bus_spi->config(bus_cfg); bus_spi->init(); id = _read_panel_id(bus_spi, GPIO_NUM_14); if ((id & 0xFFFFFF) == 0x079100) { // check panel (GC9107) board = board_t::board_M5AtomS3R; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5AtomS3R"); bus_spi->release(); bus_cfg.spi_host = SPI3_HOST; bus_cfg.freq_write = 40000000; bus_cfg.freq_read = 16000000; bus_spi->config(bus_cfg); bus_spi->init(); auto p = new Panel_GC9107(); p->bus(bus_spi); { auto cfg = p->config(); cfg.pin_cs = GPIO_NUM_14; cfg.pin_rst = GPIO_NUM_48; cfg.panel_width = 128; cfg.panel_height = 128; cfg.offset_y = 32; cfg.readable = false; cfg.bus_shared = false; p->config(cfg); } _panel_last.reset(p); _set_backlight(new Light_M5StackAtomS3R()); goto init_clear; } lgfx::pinMode(GPIO_NUM_48, lgfx::pin_mode_t::input); // LCD RST bus_spi->release(); } break; default: break; } #elif defined (CONFIG_IDF_TARGET_ESP32P4) std::uint32_t id; std::uint32_t pkg_ver = m5gfx::get_pkg_ver(); ESP_LOGD(LIBRARY_NAME, "pkg_ver : %02x", (int)pkg_ver); if (true) // pkg_ver == EFUSE_RD_CHIP_VER_PKG_ { if (board == 0 || board == board_t::board_M5Tab5) { // SDA = GPIO_NUM_31 // SCL = GPIO_NUM_32 // TP INT = GPIO_NUM_23 lgfx::pinMode(GPIO_NUM_23, lgfx::pin_mode_t::output); // TP INT lgfx::gpio_hi(GPIO_NUM_23); // select I2C Addr (high=0x14 / low=0x5D) lgfx::i2c::init(in_i2c_port, GPIO_NUM_31, GPIO_NUM_32); id = lgfx::i2c::readRegister8(in_i2c_port, pi4io1_i2c_addr, 0x01).has_value() && lgfx::i2c::readRegister8(in_i2c_port, pi4io2_i2c_addr, 0x01).has_value(); if (id != 0) { board = board_t::board_M5Tab5; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5Tab5"); static constexpr const uint8_t reg_data_io1_1[] = { 0x03, 0b01111111, 0, // PI4IO_REG_IO_DIR 0x05, 0b01010110, 0, // PI4IO_REG_OUT_SET (bit5=GT911 TouchReset LOW) 0x07, 0b00000000, 0, // PI4IO_REG_OUT_H_IM 0x0D, 0b01111111, 0, // PI4IO_REG_PULL_SEL 0x0B, 0b01111111, 0, // PI4IO_REG_PULL_EN 0xFF,0xFF,0xFF, }; static constexpr const uint8_t reg_data_io1_2[] = { 0x05, 0b01110110, 0, // PI4IO_REG_OUT_SET (bit5=GT911 TouchReset HIGH) 0xFF,0xFF,0xFF, }; static constexpr const uint8_t reg_data_io2[] = { 0x03, 0b10111001, 0, // PI4IO_REG_IO_DIR 0x07, 0b00000110, 0, // PI4IO_REG_OUT_H_IM 0x0D, 0b10111001, 0, // PI4IO_REG_PULL_SEL 0x0B, 0b11111001, 0, // PI4IO_REG_PULL_EN 0x09, 0b01000000, 0, // PI4IO_REG_IN_DEF_STA 0x11, 0b10111111, 0, // PI4IO_REG_INT_MASK 0x05, 0b10001001, 0, // PI4IO_REG_OUT_SET 0xFF,0xFF,0xFF, }; i2c_write_register8_array(in_i2c_port, pi4io1_i2c_addr, reg_data_io1_1, 400000); i2c_write_register8_array(in_i2c_port, pi4io2_i2c_addr, reg_data_io2, 400000); i2c_write_register8_array(in_i2c_port, pi4io1_i2c_addr, reg_data_io1_2, 400000); auto p = new Panel_ILI9881C(); { auto cfg = p->config(); cfg.panel_width = 720; cfg.panel_height = 1280; cfg.memory_width = 720; cfg.memory_height = 1280; cfg.readable = true; p->config(cfg); } _panel_last.reset(p); _set_pwm_backlight(GPIO_NUM_22, 7, 44100); { auto t = new m5gfx::Touch_GT911(); if (t) { _touch_last.reset(t); auto cfg = t->config(); cfg.pin_rst = -1; cfg.pin_sda = GPIO_NUM_31; cfg.pin_scl = GPIO_NUM_32; cfg.pin_int = GPIO_NUM_23; cfg.freq = 400000; cfg.x_min = 0; cfg.x_max = 719; cfg.y_min = 0; cfg.y_max = 1279; cfg.i2c_port = 1; cfg.bus_shared = true; cfg.offset_rotation = 0; t->config(cfg); _panel_last->touch(t); } } goto init_clear; } } } #endif board = board_t::board_unknown; goto init_clear; init_clear: panel(_panel_last.get()); return board; } #else bool M5GFX::init_impl(bool use_reset, bool use_clear) { board_t b = board_t::board_unknown; #if defined (M5GFX_BOARD) b = M5GFX_BOARD; #endif _board = autodetect(use_reset, b); return LGFX_Device::init_impl(use_reset, use_clear); } board_t M5GFX::autodetect(bool use_reset, board_t board) { (void)use_reset; auto p = new Panel_sdl(); _panel_last.reset(p); auto pnl_cfg = p->config(); int_fast16_t w = 320; int_fast16_t h = 240; int_fast16_t r = 0; int scale = 1; #if defined (M5GFX_SCALE) #if M5GFX_SCALE > 1 scale = M5GFX_SCALE; #endif #endif if (board == 0) { board = board_M5Stack; } const char* title; switch (board) { case board_M5Stack: title = "M5Stack"; break; case board_M5StackCore2: title = "M5StackCore2"; break; case board_M5StackCoreS3: title = "M5StackCoreS3"; break; case board_M5StackCoreS3SE:title = "M5StackCoreS3SE";break; case board_M5StickC: title = "M5StickC"; break; case board_M5StickCPlus: title = "M5StickCPlus"; break; case board_M5StickCPlus2: title = "M5StickCPlus2"; break; case board_M5StackCoreInk: title = "M5StackCoreInk"; break; case board_M5Paper: title = "M5Paper"; break; case board_M5PaperS3: title = "M5PaperS3"; break; case board_M5Tough: title = "M5Tough"; break; case board_M5Station: title = "M5Station"; break; case board_M5AtomS3: title = "M5AtomS3"; break; case board_M5AtomS3R: title = "M5AtomS3R"; break; case board_M5Dial: title = "M5Dial"; break; case board_M5Cardputer: title = "M5Cardputer"; break; case board_M5DinMeter: title = "M5DinMeter"; break; case board_M5AirQ: title = "M5AirQ"; break; case board_M5VAMeter: title = "M5VAMeter"; break; case board_M5StampPLC: title = "M5StampPLC"; break; case board_M5Tab5: title = "M5Tab5"; break; default: title = "M5GFX"; break; } p->setWindowTitle(title); switch (board) { case board_M5AtomS3: case board_M5AtomS3R: w = 128; h = 128; break; case board_M5Paper: case board_M5PaperS3: w = 960; h = 540; pnl_cfg.offset_rotation = 3; p->setColorDepth(lgfx::color_depth_t::grayscale_8bit); r = 1; break; case board_M5StackCoreInk: case board_M5AirQ: w = 200; h = 200; p->setColorDepth(lgfx::color_depth_t::grayscale_8bit); break; case board_M5StickC: w = 80; h = 160; break; case board_M5Station: case board_M5Cardputer: w = 240; h = 135; pnl_cfg.offset_rotation = 3; r = 1; break; case board_M5StickCPlus: case board_M5StickCPlus2: case board_M5DinMeter: case board_M5StampPLC: w = 135; h = 240; break; case board_M5StackCore2: pnl_cfg.offset_rotation = 3; r = 1; break; case board_M5Stack: case board_M5StackCoreS3: case board_M5StackCoreS3SE: pnl_cfg.offset_rotation = 3; r = 1; break; case board_M5Dial: w = 240; h = 240; break; case board_M5VAMeter: w = 240; h = 240; break; case board_M5Tab5: w = 720; h = 1280; break; default: break; } #if defined (M5GFX_SHORTCUT_MOD) p->setShortcutKeymod(M5GFX_SHORTCUT_MOD); #endif #if defined (M5GFX_SHOW_FRAME) auto pf = getPictureFrame(board); if (pf) { p->setFrameImage(pf->img, pf->w, pf->h, pf->x, pf->y); } #endif pnl_cfg.memory_width = w; pnl_cfg.panel_width = w; pnl_cfg.memory_height = h; pnl_cfg.panel_height = h; pnl_cfg.bus_shared = false; p->config(pnl_cfg); p->setScaling(scale, scale); #if defined (M5GFX_ROTATION) p->setFrameRotation(M5GFX_ROTATION); #endif p->setRotation(r); auto t = new lgfx::Touch_sdl(); _touch_last.reset(t); { auto cfg = t->config(); cfg.x_min = 0; cfg.x_max = w - 1; cfg.y_min = 0; cfg.y_max = h - 1; cfg.bus_shared = false; t->config(cfg); p->touch(t); // float affine[6] = { 1, 0, 0, 0, 1, 0 }; // p->setCalibrateAffine(affine); } panel(_panel_last.get()); return board; } #endif /// end of if defined (ESP_PLATFORM) void M5GFX::progressBar(int x, int y, int w, int h, uint8_t val) { drawRect(x, y, w, h, 0x09F1); fillRect(x + 1, y + 1, w * (((float)val) / 100.0f), h - 1, 0x09F1); } void M5GFX::pushState(void) { DisplayState s; s.gfxFont = _font; s.style = _text_style; s.metrics = _font_metrics; s.cursor_x = _cursor_x; s.cursor_y = _cursor_y; _displayStateStack.push_back(s); } void M5GFX::popState(void) { if (_displayStateStack.empty()) return; DisplayState s = _displayStateStack.back(); _displayStateStack.pop_back(); _font = s.gfxFont; _text_style = s.style; _font_metrics = s.metrics; _cursor_x = s.cursor_x; _cursor_y = s.cursor_y; } }