diff --git a/README.md b/README.md index 0b8a063c..e01979d9 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ so the SD manager itself stays device-agnostic. |---|---|---|---|---| | **Xteink X4** | ESP32-C3 | SSD1677 | 800×480 | B/W + 4-level grayscale | | **Xteink X3** | ESP32-C3 | UC8253 | 792×528 | B/W + 4-level grayscale; BQ27220 I²C battery gauge; shares the C3 binary with X4 | +| **OnePage** | ESP32-C61 | SSD1677 | 800×480 | B/W + 4-level grayscale, 4-key front resistor ADC ladder + 3 side keys, shared SPI MicroSD with power gating, Wi-Fi 6 + BLE 5.4 wireless page-turner remote host | | **de-link** | ESP32-S3 | SSD1677 | 800×480 | B/W + grayscale, PWM frontlight, native 4-bit SDMMC SD | | **M5Stack PaperColor** | ESP32-S3 | ED2208 | 400×600 Spectra-6 color | native interrupted-refresh driver, optional M5GFX backend, built-in speaker (ES8311 codec + AW8737A amp), 2x RGB LEDs | | **Murphy M3** | ESP32-S3 | UC8253 | 240×416 | B/W (90°-rotated framebuffer, full/fast LUTs), CHSC6x touch, PWM frontlight | @@ -145,8 +146,8 @@ found so the caller can `display.setDisplayX3()`. Call it before profile. In builds without an Xteink profile the helpers compile to no-ops that return false without touching any pins, so an unconditional call is safe on every device. Devices on a different MCU build their own binary, selected with a -`-DFREEINK_DEVICE_*` flag. A build targets exactly one of the three MCU families — ESP32-C3 (X3/X4), -ESP32-S3 (de-link/PaperColor/Murphy/LilyGo/Sticky/X4 Pro/Paper Mono/PaperS3), or classic ESP32 (M5Paper); +`-DFREEINK_DEVICE_*` flag. A build targets exactly one of the four MCU families — ESP32-C3 (X3/X4), +ESP32-C61 (OnePage), ESP32-S3 (de-link/PaperColor/Murphy/LilyGo/Sticky/X4 Pro/Paper Mono/PaperS3), or classic ESP32 (M5Paper); `BoardConfig` rejects mixing families at compile time. #### Per-batch panel controllers (`applyXteinkDisplayController()`) @@ -160,9 +161,7 @@ batch. `XteinkDetect` resolves which silicon a unit carries at boot: ```cpp #include -// Before FreeInkDisplay::begin() — promotes BoardConfig::ACTIVE.displayController -// to the UltraChip sibling when this unit carries it, so begin() selects the -// matching driver. No-op (returns false) on builds without a probe-capable device. +// Detect and apply the display controller for this unit's batch: freeink::applyXteinkDisplayController(); display.begin(); ``` @@ -295,7 +294,18 @@ wasTouchReleased/getTouchPoint`; it delivers coordinates raw-panel-oriented and app owns display-orientation mapping. GT911 additionally provides allocation-free multi-contact snapshots, completed 2-4 finger translation gestures, and completed two-finger rotations with a signed angle, center, and duration. The GT911 boards set -their `TouchConfig` in the board profile (e.g. `BoardConfig::LILYGO_T5_PRO_GT911`). +### OnePage Reader board support (ESP32-C61) + +The OnePage Reader is an open-hardware DIY e-reader built around the **ESP32-C61** +RISC-V wireless SoC. Complete hardware specifications, pinout, power gating, and +board profile details are documented in [docs/onepage-c61-support.md](docs/onepage-c61-support.md). + +Key characteristics: +- **Display**: SSD1677 800×480 on SPI @ 20MHz. +- **MicroSD**: SPI mode sharing the bus with EPD, powered via GPIO27 power rail. +- **Input**: 4-key front resistor ADC ladder on GPIO4 (`OnePageAdcLadder`) + 3 discrete active-low side keys (`UP=6, DOWN=9, POWER=2`). +- **Battery / Power**: ADC sampling on GPIO5 with charge-pause control on GPIO10 (`BAT_CHG_EN`). +- **Bluetooth**: Wi-Fi 6 + BLE 5.4 with BLE HID Central / page-turner remote host support. ## Build composition — devices × capabilities @@ -310,6 +320,7 @@ MCU (a C3-vs-S3 mix is a compile error): |---|---| | `-DFREEINK_DEVICE_X4` | X4 only — links just SSD1677 (tightest) | | `-DFREEINK_DEVICE_X3 -DFREEINK_DEVICE_X4` | X3 **and** X4 in one C3 binary, runtime-selected via `setDisplayX3()` | +| `-DFREEINK_DEVICE_ONEPAGE` | OnePage (C61, SSD1677 800×480 + 4-key ADC ladder + 3 side keys + shared SD) | | `-DFREEINK_DEVICE_DELINK` | de-link (S3, SSD1677 + frontlight) | | `-DFREEINK_DEVICE_M5` | M5 PaperColor (S3, ED2208 + color) | | `-DFREEINK_DEVICE_MURPHY` | Murphy M3 (S3, UC8253 + touch + frontlight) | diff --git a/docs/onepage-c61-support.md b/docs/onepage-c61-support.md new file mode 100644 index 00000000..e9e44c9c --- /dev/null +++ b/docs/onepage-c61-support.md @@ -0,0 +1,82 @@ +# OnePage ESP32-C61 Board Support + +## Overview + +**OnePage Reader** is an open-hardware DIY E-reader built around the **ESP32-C61** RISC-V wireless SoC. +Main ecosystem repo: [MoveCall/onepage-reader](https://github.com/MoveCall/onepage-reader) + +This document describes the FreeInk SDK board support profile for OnePage (`FREEINK_DEVICE_ONEPAGE`). + +## Hardware Specifications + +| Subsystem | Specification / Pinout | +|:---|:---| +| **SoC** | ESP32-C61 (ESP32-C61HR2, 160MHz RISC-V, Wi-Fi 6, BLE 5.4, 16MB Flash, 2MB PSRAM @ 40MHz) | +| **Display** | 4.26" E-Ink Display (GDEQ0426T82), **SSD1677** controller, **800 × 480** resolution, 4-level grayscale | +| **Display SPI** | SCLK: `GPIO22`, MOSI: `GPIO23`, CS: `GPIO25`, DC: `GPIO8`, RST: `GPIO27`, BUSY: `GPIO29` · **20 MHz** | +| **MicroSD Card** | SPI mode (shared SPI bus with EPD): SCLK: `GPIO22`, MISO: `GPIO24`, MOSI: `GPIO23`, CS: `GPIO26` · **20 MHz** | +| **Buttons (Front 4-Key)** | Single resistor ADC ladder on `GPIO4` (ADC1_CH2):
• `BACK`: 2400..2800 mV (~2592 mV)
• `LEFT`: 1780..2140 mV (~1956 mV)
• `RIGHT`: 1140..1500 mV (~1316 mV)
• `CONFIRM` (ENTER): 0..250 mV (~0 mV) | +| **Buttons (Side 3-Key)** | Active-low GPIO buttons with internal pull-up:
• `UP` (PREV): `GPIO6`
• `DOWN` (NEXT): `GPIO9`
• `POWER` (WAKE): `GPIO2` (Deep-sleep wakeup source) | +| **Battery & Charging** | • Battery ADC: `GPIO5` (ADC1_CH3, multiplier ×2.0)
• USB / Charge Detect: `GPIO11` (UART0_RXD, LM66200 ST open-drain, low = USB present)
• Charge Pause: `GPIO10` (`BAT_CHG_EN`, drive LOW during ADC sample to avoid charger offset) | +| **Power Architecture** | `GPIO27` serves as both EPD RST and shared SD power rail enable. Silenced before deep sleep. | +| **Bluetooth Remote** | BLE HID Central / Host support for wireless page turners | + +## FreeInk SDK Profile + +In FreeInk SDK (`BoardConfig.h`): + +```cpp +constexpr BoardProfile ONEPAGE = { + Board::OnePage, + "onepage", + InputStyle::OnePageAdcLadder, + DisplayController::SSD1677, + 800, + 480, + {22, 23, 25, 8, 27, 29, PIN_UNASSIGNED}, // display SPI + 20000000, // 20 MHz + {22, 24, 23, 26, PIN_UNASSIGNED, false, 20000000, true}, // microSD + {PIN_UNASSIGNED, PIN_UNASSIGNED, PIN_UNASSIGNED, PIN_UNASSIGNED, 6, 9, 2, false, 4}, // input + 5, // batteryAdc (GPIO5) + 11, // batteryChargeStatus (GPIO11) + 2.0f, // batteryDividerMultiplier + 11, // usbDetect (GPIO11) + NO_TOUCH, + NO_FRONTLIGHT, + NO_AUDIO, + NO_LEDS, + NO_FLIP, + NO_SDMMC, + NO_GAUGE, + NO_MIC, + NO_SENSORS, + 1.0f, // uiScale + {PIN_UNASSIGNED, PIN_UNASSIGNED, 10, true},// chargeEnable (GPIO10) + 0, + {9, 3, 3, 3}, + false // batteryChargeStatusActiveHigh: false +}; +``` + +## Build Configuration + +Add the following to your project's `platformio.ini`: + +```ini +[env:onepage] +extends = base +board = onepage-c61 +board_build.mcu = esp32c61 +custom_sdkconfig = + CONFIG_SPIRAM=y + CONFIG_SPIRAM_MODE_QUAD=y + CONFIG_SPIRAM_SPEED_40M=y + CONFIG_SPIRAM_USE_MALLOC=y + CONFIG_SPIRAM_BOOT_INIT=y + CONFIG_SPIRAM_BOOT_HW_INIT=y + CONFIG_BT_LE_SLEEP_ENABLE=y + CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +build_flags = + ${base.build_flags} + -DFREEINK_DEVICE_ONEPAGE=1 +``` diff --git a/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp b/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp index b6d78bbc..1687668c 100644 --- a/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp +++ b/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp @@ -456,7 +456,20 @@ uint16_t BatteryMonitor::readMillivolts() const { const uint16_t mv = esp_adc_cal_raw_to_voltage(raw, &adc_chars); #else // ESP-IDF 5.x has analogReadMilliVolts - const uint16_t mv = analogReadMilliVolts(_adcPin); + // OnePage only: pause charging around the read. Other boards with a + // chargeEnable pin (e.g. Sticky) must NOT have it glitched during battery reads. + uint16_t mv = 0; + if (BoardConfig::isOnePage() && BoardConfig::ACTIVE.power.chargeEnable >= 0) { + const int8_t ce = BoardConfig::ACTIVE.power.chargeEnable; + const bool activeHigh = BoardConfig::ACTIVE.power.chargeEnableActiveHigh; + pinMode(ce, OUTPUT); + digitalWrite(ce, activeHigh ? LOW : HIGH); // pause charging + delay(5); + mv = analogReadMilliVolts(_adcPin); + digitalWrite(ce, activeHigh ? HIGH : LOW); // resume charging + } else { + mv = analogReadMilliVolts(_adcPin); + } #endif return static_cast(mv * _dividerMultiplier); diff --git a/libs/hardware/BoardConfig/include/BoardConfig.h b/libs/hardware/BoardConfig/include/BoardConfig.h index 1b9935fc..5489a653 100644 --- a/libs/hardware/BoardConfig/include/BoardConfig.h +++ b/libs/hardware/BoardConfig/include/BoardConfig.h @@ -72,39 +72,43 @@ #ifndef FREEINK_DEVICE_EEGO_A4 #define FREEINK_DEVICE_EEGO_A4 0 #endif +#ifndef FREEINK_DEVICE_ONEPAGE +#define FREEINK_DEVICE_ONEPAGE 0 +#endif // --- 2) Coherence: exactly one MCU family, at least one device --------------- #if !(FREEINK_DEVICE_X4 || FREEINK_DEVICE_X3 || FREEINK_DEVICE_X4PRO || FREEINK_DEVICE_X4CLASSIC || FREEINK_DEVICE_M5 || \ FREEINK_DEVICE_MURPHY || FREEINK_DEVICE_DELINK || FREEINK_DEVICE_LILYGO || FREEINK_DEVICE_M5PAPER || \ FREEINK_DEVICE_STICKY || FREEINK_DEVICE_PAPERMONO || FREEINK_DEVICE_PAPERS3 || FREEINK_DEVICE_MURPHY_M4 || \ - FREEINK_DEVICE_EEGO_A4) + FREEINK_DEVICE_EEGO_A4 || FREEINK_DEVICE_ONEPAGE) #error \ - "FreeInk: no device selected. Pass at least one -DFREEINK_DEVICE_ (X4, X3, X4PRO, X4CLASSIC, M5, MURPHY, DELINK, LILYGO, M5PAPER, STICKY, PAPERMONO, PAPERS3, MURPHY_M4, EEGO_A4) in your build env — see platformio.sample.ini." + "FreeInk: no device selected. Pass at least one -DFREEINK_DEVICE_ (X4, X3, X4PRO, X4CLASSIC, M5, MURPHY, DELINK, LILYGO, M5PAPER, STICKY, PAPERMONO, PAPERS3, MURPHY_M4, EEGO_A4, ONEPAGE) in your build env — see platformio.sample.ini." #endif // Each device belongs to one MCU family; a binary targets exactly one. X3/X4 are // ESP32-C3; M5 PaperColor/Murphy/de-link/LilyGo are ESP32-S3; M5Paper v1.1 is the -// classic ESP32 (ESP32-D0WDQ6). The three families differ in deep-sleep wakeup, -// SPI peripheral count, and toolchain, so they never share a binary. +// classic ESP32 (ESP32-D0WDQ6); OnePage is ESP32-C61. The families differ in +// deep-sleep wakeup, SPI peripheral count, and toolchain, so they never share a binary. #define FREEINK_MCU_C3 (FREEINK_DEVICE_X3 || FREEINK_DEVICE_X4) +#define FREEINK_MCU_C61 (FREEINK_DEVICE_ONEPAGE) #define FREEINK_MCU_S3 \ (FREEINK_DEVICE_M5 || FREEINK_DEVICE_MURPHY || FREEINK_DEVICE_DELINK || FREEINK_DEVICE_LILYGO || \ FREEINK_DEVICE_STICKY || FREEINK_DEVICE_X4PRO || FREEINK_DEVICE_X4CLASSIC || FREEINK_DEVICE_PAPERMONO || \ FREEINK_DEVICE_PAPERS3 || FREEINK_DEVICE_MURPHY_M4 || FREEINK_DEVICE_EEGO_A4) #define FREEINK_MCU_ESP32 (FREEINK_DEVICE_M5PAPER) -#if (FREEINK_MCU_C3 + FREEINK_MCU_S3 + FREEINK_MCU_ESP32) != 1 +#if (FREEINK_MCU_C3 + FREEINK_MCU_C61 + FREEINK_MCU_S3 + FREEINK_MCU_ESP32) != 1 #error \ - "FreeInk: all selected devices must share one MCU family — ESP32-C3 (X3/X4), ESP32-S3 (M5/Murphy/de-link/LilyGo/Sticky/X4Pro), or ESP32 (M5Paper). Build one binary per family." + "FreeInk: all selected devices must share one MCU family — ESP32-C3 (X3/X4), ESP32-C61 (OnePage), ESP32-S3 (M5/Murphy/de-link/LilyGo/Sticky/X4Pro), or ESP32 (M5Paper). Build one binary per family." #endif // --- 3) Derive panel drivers from the device set ----------------------------- // Sticky reuses SSD1677: its 800x480 panel rides a 24-pin FPC whose GDR/RESE/BS1 // + dual VSH1/VSH2 + external VGH/VGL/VSL/VCOM charge pump is the SSD1677 -// application circuit (same controller + resolution as X4 / de-link). +// application circuit (same controller + resolution as X4 / de-link / OnePage). // X4 Pro is a distinct ESP32-S3 device (NOT the C3 X4): its 800x480 panel may // use SSD1677, UC8179, or UC8279, recovered from OEM firmware and hardware // references — see docs/xteink-x4pro-support.md. #if FREEINK_DEVICE_X4 || FREEINK_DEVICE_DELINK || FREEINK_DEVICE_STICKY || FREEINK_DEVICE_X4PRO || \ - FREEINK_DEVICE_X4CLASSIC || FREEINK_DEVICE_MURPHY_M4 + FREEINK_DEVICE_X4CLASSIC || FREEINK_DEVICE_MURPHY_M4 || FREEINK_DEVICE_ONEPAGE #define FREEINK_DRIVER_SSD1677 1 #else #define FREEINK_DRIVER_SSD1677 0 @@ -376,6 +380,7 @@ enum class Board : uint8_t { PaperMono, M5PaperS3, // ESP32-S3 sibling of M5Paper v1.1: same ED047TC1 glass, no IT8951 — raw parallel via LovyanGFX EegoA4, // EEGO Reader A4: ESP32-S3, UC8279C 768x552 SPI panel, GSLX680 touch, PCF8563 RTC + OnePage, // OnePage: ESP32-C61, SSD1677 800x480 SPI panel, 4-key ADC ladder + 3 side keys }; // How the board reports button presses. @@ -386,6 +391,7 @@ enum class InputStyle : uint8_t { DigitalConfirmPowerHold, // confirm click, power hold on a shared GPIO DigitalFiveKey, // 3 physical GPIO keys + synthesized events (Murphy M3) DigitalTwoButton, // short up/down; holds synthesize back/confirm/power + OnePageAdcLadder, // OnePage: 4 front keys on GPIO4 ADC ladder + 3 side GPIO keys }; // Panel controller silicon. Drivers are selected from this at begin(). @@ -498,6 +504,7 @@ struct InputPins { int8_t down; int8_t power; bool powerActiveHigh; // true = pressed reads HIGH (INPUT_PULLDOWN); false = active-LOW (INPUT_PULLUP) + int8_t adcLadderPin = PIN_UNASSIGNED; // ADC pin for single resistor ladder (e.g. OnePage GPIO4) }; // Capacitive touch panel description (TouchController::None disables it). @@ -1698,6 +1705,44 @@ constexpr BoardProfile XTEINK_X4_CLASSIC = { {9, 7, 3, 7}, // bezel insets: carried from X4 Pro (same glass), pending measurement true}; // batteryChargeStatusActiveHigh: GPIO21 STAT driven HIGH while charging +constexpr BoardProfile ONEPAGE = { + Board::OnePage, + "onepage", + InputStyle::OnePageAdcLadder, + DisplayController::SSD1677, + 800, + 480, + // Display SPI: SCLK 22, MOSI 23, CS 25, DC 8, RST 27, BUSY 29, powerEnable PIN_UNASSIGNED + {22, 23, 25, 8, 27, 29, PIN_UNASSIGNED}, + 20000000, // displaySpiHz: 20MHz + // MicroSD (shared SPI bus): SCLK 22, MISO 24, MOSI 23, CS 26, powerEnable 27 + {22, 24, 23, 26, 27, false, 20000000, true}, + // Input: 4-key front ADC ladder on GPIO4 + 3 side GPIO keys (UP=6, DOWN=9, POWER=2) + // {back, confirm, left, right, up, down, power, powerActiveHigh, adcLadderPin} + {PIN_UNASSIGNED, PIN_UNASSIGNED, PIN_UNASSIGNED, PIN_UNASSIGNED, 6, 9, 2, false, 4}, + 5, // batteryAdc: GPIO5 (ADC1_CH3) + 11, // batteryChargeStatus: GPIO11 (LM66200 ST open-drain, low=USB present) + 2.0f, // batteryDividerMultiplier + 11, // usbDetect: GPIO11 (LM66200 ST) + NO_TOUCH, // touch: no touch + NO_FRONTLIGHT, // frontlight: none + NO_AUDIO, // audio: none + NO_LEDS, // leds: none + NO_FLIP, // orientation + NO_SDMMC, // sdmmc: none (SPI) + NO_GAUGE, // batteryGauge: none (ADC) + NO_MIC, // mic + NO_SENSORS, // sensors + 1.0f, // uiScale: 1.0 + // Power: latch0, latch1, chargeEnable (GPIO10, active-high) + {PIN_UNASSIGNED, PIN_UNASSIGNED, 10, true}, + 0, // displayControllerVariant + {0, 0, 0, 0}, // viewableInsets: full 800x480 panel frame + false}; // batteryChargeStatusActiveHigh: false (low = USB present) + +static_assert(ONEPAGE.displayWidth / 8 * ONEPAGE.displayHeight == 48000, + "OnePage framebuffer must be 48,000 bytes (800/8 x 480)"); + // Largest framebuffer (bytes) over the devices compiled into this build, derived // from the profiles above. The display facade sizes its static framebuffer to // this so one binary holds whichever panel is runtime-selected; a single-device @@ -1720,12 +1765,15 @@ constexpr uint32_t MAX_FRAMEBUFFER_BYTES = cmax( FREEINK_DEVICE_PAPERMONO ? panelBytes(PAPER_MONO) : 0u), cmax(cmax(FREEINK_DEVICE_PAPERS3 ? panelBytes(M5PAPER_S3) : 0u, FREEINK_DEVICE_MURPHY_M4 ? panelBytes(MURPHY_M4) : 0u), - FREEINK_DEVICE_EEGO_A4 ? panelBytes(EEGO_A4) : 0u)))); + cmax(FREEINK_DEVICE_EEGO_A4 ? panelBytes(EEGO_A4) : 0u, + FREEINK_DEVICE_ONEPAGE ? panelBytes(ONEPAGE) : 0u))))); // Compile-time default device — the profile ACTIVE starts as. With a single // device in the build this is the only device; with several same-MCU devices it // is the boot default until the consumer calls selectDevice(). -#if FREEINK_DEVICE_PAPERMONO +#if FREEINK_DEVICE_ONEPAGE +constexpr BoardProfile DEFAULT_DEVICE = ONEPAGE; +#elif FREEINK_DEVICE_PAPERMONO constexpr BoardProfile DEFAULT_DEVICE = PAPER_MONO; #elif FREEINK_DEVICE_EEGO_A4 constexpr BoardProfile DEFAULT_DEVICE = EEGO_A4; @@ -1840,6 +1888,11 @@ inline bool selectDevice(Board which) { case Board::EegoA4: ACTIVE = EEGO_A4; break; +#endif +#if FREEINK_DEVICE_ONEPAGE + case Board::OnePage: + ACTIVE = ONEPAGE; + break; #endif default: return false; @@ -1862,6 +1915,7 @@ inline bool isX4Pro() { return ACTIVE.board == Board::XteinkX4Pro; } inline bool isX4Classic() { return ACTIVE.board == Board::XteinkX4Classic; } inline bool isPaperMono() { return ACTIVE.board == Board::PaperMono; } inline bool isEegoA4() { return ACTIVE.board == Board::EegoA4; } +inline bool isOnePage() { return ACTIVE.board == Board::OnePage; } inline bool hasTouch() { return ACTIVE.touch.controller != TouchController::None; } inline bool hasHomeKey() { return ACTIVE.touch.hasHomeKey; } inline bool hasPwmFrontlight() { return ACTIVE.frontlight.gpio != PIN_UNASSIGNED || ACTIVE.frontlight.viaPm1Pwm; } diff --git a/libs/hardware/InputManager/src/InputManager.cpp b/libs/hardware/InputManager/src/InputManager.cpp index 219f0039..4219266f 100644 --- a/libs/hardware/InputManager/src/InputManager.cpp +++ b/libs/hardware/InputManager/src/InputManager.cpp @@ -99,6 +99,21 @@ void InputManager::begin() { return; } + if (BoardConfig::ACTIVE.inputStyle == BoardConfig::InputStyle::OnePageAdcLadder) { + if (BoardConfig::ACTIVE.input.adcLadderPin >= 0) { + pinMode(BoardConfig::ACTIVE.input.adcLadderPin, INPUT); + } + analogSetAttenuation(ADC_11db); + if (BoardConfig::ACTIVE.input.up >= 0) pinMode(BoardConfig::ACTIVE.input.up, INPUT_PULLUP); + if (BoardConfig::ACTIVE.input.down >= 0) pinMode(BoardConfig::ACTIVE.input.down, INPUT_PULLUP); + if (BoardConfig::ACTIVE.input.power >= 0) { + pinMode(BoardConfig::ACTIVE.input.power, + BoardConfig::ACTIVE.input.powerActiveHigh ? INPUT_PULLDOWN : INPUT_PULLUP); + } + beginTouch(); + return; + } + const int8_t pins[] = {BoardConfig::ACTIVE.input.back, BoardConfig::ACTIVE.input.confirm, BoardConfig::ACTIVE.input.left, BoardConfig::ACTIVE.input.right, BoardConfig::ACTIVE.input.up, BoardConfig::ACTIVE.input.down}; @@ -146,6 +161,31 @@ void InputManager::readButtonAdc(ButtonAdcSample& group1, ButtonAdcSample& group uint8_t InputManager::getState() { uint8_t state = 0; + if (BoardConfig::ACTIVE.inputStyle == BoardConfig::InputStyle::OnePageAdcLadder) { + if (BoardConfig::ACTIVE.input.adcLadderPin >= 0) { + const int mv = analogReadMilliVolts(BoardConfig::ACTIVE.input.adcLadderPin); + if (mv >= 2400 && mv <= 2800) state |= (1 << BTN_BACK); // ~2592 mV + else if (mv >= 1780 && mv <= 2140) state |= (1 << BTN_LEFT); // ~1956 mV + else if (mv >= 1140 && mv <= 1500) state |= (1 << BTN_RIGHT); // ~1316 mV + else if (mv >= 0 && mv <= 250) state |= (1 << BTN_CONFIRM); // ~0 mV (ENTER) + } + if (BoardConfig::ACTIVE.input.up >= 0 && digitalRead(BoardConfig::ACTIVE.input.up) == LOW) { + state |= (1 << BTN_UP); + } + if (BoardConfig::ACTIVE.input.down >= 0 && digitalRead(BoardConfig::ACTIVE.input.down) == LOW) { + state |= (1 << BTN_DOWN); + } + if (BoardConfig::ACTIVE.input.power >= 0) { + const int activeLevel = BoardConfig::ACTIVE.input.powerActiveHigh ? HIGH : LOW; + if (digitalRead(BoardConfig::ACTIVE.input.power) == activeLevel) { + state |= (1 << BTN_POWER); + } + } + state |= serviceTouch(); + if (s_buttonHook) state |= s_buttonHook(); + return state; + } + if (BoardConfig::ACTIVE.inputStyle != BoardConfig::InputStyle::XteinkAdcLadder) { state = getDigitalState(); state |= serviceTouch(); // run the touch machine; OR any synthesized button diff --git a/libs/hardware/PowerManager/src/PowerManager.cpp b/libs/hardware/PowerManager/src/PowerManager.cpp index f3f8601d..e361c630 100644 --- a/libs/hardware/PowerManager/src/PowerManager.cpp +++ b/libs/hardware/PowerManager/src/PowerManager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -92,7 +93,9 @@ void PowerManager::powerDownRailsForSleep() { void PowerManager::deepSleep() { esp_sleep_config_gpio_isolate(); +#if !FREEINK_MCU_C61 gpio_deep_sleep_hold_en(); +#endif esp_deep_sleep_start(); while (true) { } // esp_deep_sleep_start() does not return; satisfy [[noreturn]] diff --git a/libs/hardware/SDCardManager/src/SDCardManager.cpp b/libs/hardware/SDCardManager/src/SDCardManager.cpp index 8a2af346..480a9388 100644 --- a/libs/hardware/SDCardManager/src/SDCardManager.cpp +++ b/libs/hardware/SDCardManager/src/SDCardManager.cpp @@ -113,7 +113,7 @@ bool SDCardManager::begin() { pinMode(BoardConfig::ACTIVE.sd.powerEnable, OUTPUT); // ON level: HIGH for active-high enables, LOW for active-low ones. digitalWrite(BoardConfig::ACTIVE.sd.powerEnable, BoardConfig::ACTIVE.sd.powerActiveHigh ? HIGH : LOW); - delay(10); + delay(BoardConfig::isOnePage() ? 80 : 10); } // Shared SPI bus: when the display controller sits on the same SCLK as the SD @@ -142,7 +142,13 @@ bool SDCardManager::begin() { if (SD_SCLK >= 0 && SD_MOSI >= 0 && SD_MISO >= 0) { SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS); } - cardReady = sd.begin(SD_CS, SPI_FQ); + // Other boards keep the single attempt so a missing card fails fast. + const int attempts = BoardConfig::isOnePage() ? 5 : 1; + for (int attempt = 0; attempt < attempts; ++attempt) { + cardReady = sd.begin(SD_CS, SPI_FQ); + if (cardReady || attempt + 1 == attempts) break; + delay(80); + } #if FREEINK_MCU_S3 || FREEINK_MCU_ESP32 } #endif diff --git a/platformio.sample.ini b/platformio.sample.ini index 73a9e5cc..7705c182 100644 --- a/platformio.sample.ini +++ b/platformio.sample.ini @@ -319,6 +319,26 @@ build_flags = -DUSE_BLOCK_DEVICE_INTERFACE=1 -DFREEINK_DEVICE_PAPERMONO=1 +; --- OnePage Reader — ESP32-C61, SSD1677 800x480, 4-key ADC ladder + 3 side keys - +; Open-hardware DIY e-reader ecosystem (ESP32-C61HR2, 16MB flash, 2MB PSRAM @40MHz). +; MicroSD shares SPI bus with EPD (20MHz). BLE HID host support for page-turner remotes. +[env:onepage] +extends = base +board = onepage-c61 +board_build.mcu = esp32c61 +custom_sdkconfig = + CONFIG_SPIRAM=y + CONFIG_SPIRAM_MODE_QUAD=y + CONFIG_SPIRAM_SPEED_40M=y + CONFIG_SPIRAM_USE_MALLOC=y + CONFIG_SPIRAM_BOOT_INIT=y + CONFIG_SPIRAM_BOOT_HW_INIT=y + CONFIG_BT_LE_SLEEP_ENABLE=y + CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +build_flags = + ${base.build_flags} + -DFREEINK_DEVICE_ONEPAGE=1 + ; --- Example: enable the wolfSSL TLS 1.3 networking stack ---------------------- ; Add SecureNet to lib_deps + a wolfSSL source lib, then: ; -DFREEINK_NET_WOLFSSL=1