From c152a83c1bc135291d2cf8c7a8cfced1e28322b3 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Thu, 8 Oct 2026 16:00:41 +0300 Subject: [PATCH 1/2] add: configuration pins for i2c scanner --- src/apps/tests/scan_i2c/scan_i2c.cpp | 128 ++++++++++++++++++++++++--- src/apps/tests/scan_i2c/scan_i2c.h | 7 ++ src/keira/localizations/lang_en.h | 4 + src/keira/localizations/lang_uk.h | 4 + 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/src/apps/tests/scan_i2c/scan_i2c.cpp b/src/apps/tests/scan_i2c/scan_i2c.cpp index dd2bff05..026d516a 100644 --- a/src/apps/tests/scan_i2c/scan_i2c.cpp +++ b/src/apps/tests/scan_i2c/scan_i2c.cpp @@ -5,33 +5,140 @@ #include "keira/utils/string.h" +#if LILKA_VERSION >= 2 +static constexpr uint32_t I2C_FREQUENCIES[] = {100000, 400000, 1000000}; +static constexpr uint8_t I2C_FREQUENCY_COUNT = sizeof(I2C_FREQUENCIES) / sizeof(I2C_FREQUENCIES[0]); + +struct ScanI2CPin { + const char* name; + uint8_t gpio; +}; + +// Extension header pins usable for I2C (TX/RX are free: console runs over USB CDC) +static const ScanI2CPin I2C_PINS[] = { + {"P3", LILKA_P3}, + {"P4", LILKA_P4}, + {"P5", LILKA_P5}, + {"P6", LILKA_P6}, + {"P7", LILKA_P7}, + {"P8", LILKA_P8}, + {"TX", TX}, + {"RX", RX}, +}; +static constexpr uint8_t I2C_PIN_COUNT = sizeof(I2C_PINS) / sizeof(I2C_PINS[0]); + +enum ScanI2CMenuItem { + SCAN_I2C_MENU_SDA, + SCAN_I2C_MENU_SCL, + SCAN_I2C_MENU_FREQUENCY, + SCAN_I2C_MENU_SCAN, + SCAN_I2C_MENU_BACK, +}; +#endif + ScanI2CApp::ScanI2CApp() : App("I2C Scanner") { } void ScanI2CApp::run() { #if LILKA_VERSION >= 2 + lilka::Menu menu("I2C"); + menu.addActivationButton(K_BTN_BACK); + + while (true) { + int16_t cursor = menu.getCursor(); + menu.clearItems(); + menu.addItem( + K_S_I2C_SCANNER_SDA, + 0, + lilka::colors::White, + StringFormat("%s (GPIO %d)", I2C_PINS[sdaIndex].name, I2C_PINS[sdaIndex].gpio) + ); + menu.addItem( + K_S_I2C_SCANNER_SCL, + 0, + lilka::colors::White, + StringFormat("%s (GPIO %d)", I2C_PINS[sclIndex].name, I2C_PINS[sclIndex].gpio) + ); + menu.addItem( + K_S_I2C_SCANNER_FREQUENCY, + 0, + lilka::colors::White, + StringFormat("%d kHz", static_cast(I2C_FREQUENCIES[freqIndex] / 1000)) + ); + menu.addItem(K_S_I2C_SCANNER_SCAN); + menu.addItem(K_S_MENU_BACK); + menu.setCursor(cursor); + + while (!menu.isFinished()) { + menu.update(); + menu.draw(canvas); + queueDraw(); + } + + if (menu.getButton() == K_BTN_BACK) return; + + switch (menu.getCursor()) { + case SCAN_I2C_MENU_SDA: + sdaIndex = nextPinIndex(sdaIndex, sclIndex); + break; + case SCAN_I2C_MENU_SCL: + sclIndex = nextPinIndex(sclIndex, sdaIndex); + break; + case SCAN_I2C_MENU_FREQUENCY: + freqIndex = (freqIndex + 1) % I2C_FREQUENCY_COUNT; + break; + case SCAN_I2C_MENU_SCAN: + scan(); + break; + default: + return; + } + } +#else + lilka::Alert alert(K_S_ERROR, K_S_LILKA_V2_OR_HIGHER_REQUIRED); + alert.draw(canvas); + queueDraw(); + while (!alert.isFinished()) { + alert.update(); + } +#endif +} + +uint8_t ScanI2CApp::nextPinIndex(uint8_t current, uint8_t other) const { +#if LILKA_VERSION >= 2 + uint8_t next = (current + 1) % I2C_PIN_COUNT; + if (next == other) next = (next + 1) % I2C_PIN_COUNT; + return next; +#else + return current; +#endif +} + +void ScanI2CApp::scan() { +#if LILKA_VERSION >= 2 + const uint8_t sda = I2C_PINS[sdaIndex].gpio; + const uint8_t scl = I2C_PINS[sclIndex].gpio; + const uint32_t freq = I2C_FREQUENCIES[freqIndex]; + lilka::Canvas buffer(canvas->width(), canvas->height()); buffer.begin(); - buffer.fillScreen(0); buffer.setFont(FONT_9x15); buffer.fillScreen(lilka::colors::Black); buffer.setTextBound(4, 0, canvas->width() - 8, canvas->height()); buffer.setCursor(4, 20); - buffer.println(StringFormat(K_S_I2C_INIT_ABOUT, LILKA_P3, LILKA_P4)); - Wire.begin(LILKA_P3, LILKA_P4, 100000); + buffer.println(StringFormat(K_S_I2C_INIT_ABOUT, sda, scl)); + Wire.begin(sda, scl, freq); buffer.println(K_S_I2C_SCANNER_SCAN_START); canvas->drawCanvas(&buffer); queueDraw(); uint8_t found = 0; for (uint16_t address = 1; address <= 127; address++) { - // Wire.requestFrom(addr, 0, true); Wire.beginTransmission(address); if (Wire.endTransmission() == 0) { buffer.printf("%02X", address); - // lilka::display found++; } else { buffer.print("."); @@ -48,15 +155,10 @@ void ScanI2CApp::run() { Wire.end(); - while (!lilka::controller.getState().a.justPressed) { + while (true) { + lilka::State state = lilka::controller.getState(); + if (state.a.justPressed || state.b.justPressed) break; taskYIELD(); } -#else - lilka::Alert alert(K_S_ERROR, K_S_LILKA_V2_OR_HIGHER_REQUIRED); - alert.draw(canvas); - queueDraw(); - while (!alert.isFinished()) { - alert.update(); - } #endif } diff --git a/src/apps/tests/scan_i2c/scan_i2c.h b/src/apps/tests/scan_i2c/scan_i2c.h index 8a9dc26e..08624769 100644 --- a/src/apps/tests/scan_i2c/scan_i2c.h +++ b/src/apps/tests/scan_i2c/scan_i2c.h @@ -7,5 +7,12 @@ class ScanI2CApp : public App { ScanI2CApp(); private: + // Indices into I2C_PINS / I2C_FREQUENCIES + uint8_t sdaIndex = 0; // LILKA_P3 + uint8_t sclIndex = 1; // LILKA_P4 + uint8_t freqIndex = 0; + void run() override; + void scan(); + uint8_t nextPinIndex(uint8_t current, uint8_t other) const; }; diff --git a/src/keira/localizations/lang_en.h b/src/keira/localizations/lang_en.h index 1112bb22..ef16ed7d 100644 --- a/src/keira/localizations/lang_en.h +++ b/src/keira/localizations/lang_en.h @@ -179,6 +179,10 @@ #define K_S_I2C_SCANNER_SCAN_START "Starting I2C scan..." #define K_S_I2C_SCANNER_SCAN_DONE "I2C scan done." #define K_S_I2C_SCANNER_DEVICES_FOUND "Found %d devices." +#define K_S_I2C_SCANNER_SDA "SDA" +#define K_S_I2C_SCANNER_SCL "SCL" +#define K_S_I2C_SCANNER_FREQUENCY "Frequency" +#define K_S_I2C_SCANNER_SCAN "Scan" /////////////////////////////////////////////////////////////////////////////////////////////////////// // apps/demos/transform.cpp /////////////////////////////////////////////////////////////////////////// diff --git a/src/keira/localizations/lang_uk.h b/src/keira/localizations/lang_uk.h index a7f0bfc7..941e6db6 100644 --- a/src/keira/localizations/lang_uk.h +++ b/src/keira/localizations/lang_uk.h @@ -172,6 +172,10 @@ #define K_S_I2C_SCANNER_SCAN_START "Starting I2C scan..." #define K_S_I2C_SCANNER_SCAN_DONE "I2C scan done." #define K_S_I2C_SCANNER_DEVICES_FOUND "Found %d devices." +#define K_S_I2C_SCANNER_SDA "SDA" +#define K_S_I2C_SCANNER_SCL "SCL" +#define K_S_I2C_SCANNER_FREQUENCY "Частота" +#define K_S_I2C_SCANNER_SCAN "Сканувати" /////////////////////////////////////////////////////////////////////////////////////////////////////// // apps/demos/transform.cpp /////////////////////////////////////////////////////////////////////////// From 5072f0090b4a32f7fbbd526492b4f7d525db2520 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Thu, 8 Oct 2026 21:33:25 +0300 Subject: [PATCH 2/2] fix: use helpers functions --- src/apps/tests/scan_i2c/scan_i2c.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/apps/tests/scan_i2c/scan_i2c.cpp b/src/apps/tests/scan_i2c/scan_i2c.cpp index 026d516a..e45fdebb 100644 --- a/src/apps/tests/scan_i2c/scan_i2c.cpp +++ b/src/apps/tests/scan_i2c/scan_i2c.cpp @@ -95,12 +95,7 @@ void ScanI2CApp::run() { } } #else - lilka::Alert alert(K_S_ERROR, K_S_LILKA_V2_OR_HIGHER_REQUIRED); - alert.draw(canvas); - queueDraw(); - while (!alert.isFinished()) { - alert.update(); - } + alert(K_S_ERROR, K_S_LILKA_V2_OR_HIGHER_REQUIRED); #endif }