Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ The library declares these Arduino dependencies:
- `Adafruit BME280 Library`
- `BH1750` version 1.3.0 or newer from
[claws/BH1750](https://github.com/claws/BH1750)
- `SparkFun MMC5983MA Magnetometer Arduino Library` version 1.1.5 or newer
for the onboard MMC5983MA magnetometer
- `ICM42670P` version 1.0.8 or newer from TDK InvenSense as the compatible
driver used by the onboard ICM42607P example
- `Adafruit NeoPixel`
- `ESP32Servo` for ESP32-based RadioCore boards
- `NonBlockingRTTTL` version 1.4.0 or newer for non-blocking buzzer melodies
Expand All @@ -47,6 +51,23 @@ that fork manually in the Arduino sketchbook `libraries` directory. It is not
listed in `library.properties` because NV3001B support has not been merged into
the Arduino Library Manager version of `GFX Library for Arduino`.

`DEPG1020BNS770F1_Display`, `E0213A367_Display`, and
`DEPG0290BNS800_Display` require the development version of
`heltec-eink-modules` containing the external RD02E constructors and RC52
platform support. The public Library Manager `4.6.0` package does not contain
these interfaces. From the Arduino sketchbook `libraries` directory, install
the verified revision with:

```powershell
git clone https://github.com/Quency-D/heltec-eink-modules.git
git -C heltec-eink-modules checkout 7f5f0dafe3bce0a39350901ae3cc8c745463045f
```

`GFX_Root` is bundled with `heltec-eink-modules` and does not need a separate
installation. The Heltec Arduino core used to select RC32 or RC52 is a board
environment requirement, not an Arduino library dependency; no minimum core
version is asserted here.

## Examples

Open the examples from `File > Examples > RadioCore_Kit` in the Arduino
Expand All @@ -56,11 +77,17 @@ compile time.
| Example | Purpose | Documentation |
| --- | --- | --- |
| `BH1750_Read` | Read ambient light over Sensor I2C | [Guide](examples/BH1750_Read/README.md) |
| `MMC5983MA_Read` | Read the onboard three-axis magnetic field in gauss on RC32 and RC52 | [Guide](examples/MMC5983MA_Read/README.md) |
| `ICM42607P_Read` | Read onboard acceleration in g and angular rate in degrees per second on RC32 and RC52 | [Guide](examples/ICM42607P_Read/README.md) |
| `CH01_Read` | Estimate CH01 gas concentration and trend | [Guide](examples/CH01_Read/README.md) |
| `CO01_Read` | Run the CO01 warm-up cycle and estimate concentration | [Guide](examples/CO01_Read/README.md) |
| `VO01_Read` | Estimate VO01 gas concentration and trend | [Guide](examples/VO01_Read/README.md) |
| `Soil_Moisture_Read` | Read and calibrate an analog soil moisture sensor | [Guide](examples/Soil_Moisture_Read/README.md) |
| `NV3001B_Display` | Exercise the 128-by-220 color TFT | [Guide](examples/NV3001B_Display/README.md) |
| `DEPG1020BNS770F1_Display` | Startup black/white test, full baseline, and partial-window updates on the 960-by-640 panel (RC32/RC52) | [Guide](examples/DEPG1020BNS770F1_Display/README.md) |
| `E0213A367_Display` | Refresh the 122-by-250 drawable E0213A367 e-paper panel on RC32 or RC52 | [Guide](examples/E0213A367_Display/README.md) |
| `DEPG0290BNS800_Display` | Test full refresh and fast-window updates on the 296-by-128 landscape panel (RC32/RC52) | [Guide](examples/DEPG0290BNS800_Display/README.md) |
| `Rotary_Encoder` | Report rotary direction, signed count, and user-button presses on RC32 and RC52 | [Sketch](examples/Rotary_Encoder/Rotary_Encoder.ino) |
| `WS2812` | Run a three-color breathing animation | [Sketch](examples/WS2812/WS2812.ino) |
| `Buzzer_Control` | Play and repeat an RTTTL melody through the board-designated buzzer output | [Sketch](examples/Buzzer_Control/Buzzer_Control.ino) |
| `Motor_Control` | Drive two direction inputs on an external motor driver | [Sketch](examples/Motor_Control/Motor_Control.ino) |
Expand All @@ -81,10 +108,19 @@ A new board declares only the capabilities it supports:

- Sensor I2C instance, pins, frequency, and optional sensor-power control for
`BH1750_Read`.
- Onboard MMC5983MA and ICM42607P capability flags plus any shared sensor-reset
pin and release level required by their examples.
- ADC pins and optional power controls for `CH01_Read`, `VO01_Read`,
`CO01_Read`, and `Soil_Moisture_Read`; CO01 also requires its control pin.
- NV3001B pins, active levels, SPI frequency, and one supported display
transport for `NV3001B_Display`.
- RD02E driver-board pins and active levels for the shared paged
DEPG1020BNS770F1, E0213A367, and DEPG0290BNS800 examples. Document the
connector mapping and shared-pin conflicts.
- A rotary encoder I2C address and phase masks for `Rotary_Encoder`, plus an
independently declared user-button pin, active level, and input mode. The
current RC32 and RC52 mappings share the configured Sensor I2C bus and power
rail.
- A data pin for `WS2812`, a buzzer output pin and any shared peripheral power
control required by `Buzzer_Control`, two motor-driver inputs for
`Motor_Control`, a relay output and active level for `Relay_Control`, and two
Expand Down
67 changes: 64 additions & 3 deletions docs/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The shared Arduino package for the RadioCore hardware family.
_Avoid_: RadioCore Library, sensor driver bundle, full board support package

**Sensor I2C**:
The board-designated I2C bus used by RadioCore examples for external sensors.
The board-designated I2C bus used by RadioCore onboard and external sensors.
It may map to different `TwoWire` instances or pins on different boards.
_Avoid_: default Wire, I2C0

Expand All @@ -19,6 +19,16 @@ The board-controlled power domain that supplies external sensors and may be
shared with other peripherals.
_Avoid_: sensor VCC pin, sensor enable pin, Vext

**MMC5983MA magnetometer**:
The board-integrated three-axis magnetic-field sensor on Sensor I2C in RC32
and RC52.
_Avoid_: MMC5983, compass module, external magnetometer

**ICM42607P motion sensor**:
The board-integrated inertial sensor on Sensor I2C in RC32 and RC52; its
compatible Arduino driver dependency is named ICM42670P.
_Avoid_: ICM42670P sensor, external IMU

**Board configuration**:
Compile-time hardware facts for one RadioCore board, without peripheral
initialization or example behavior.
Expand All @@ -29,10 +39,51 @@ The 128-by-220 color TFT panel configured by RadioCore display examples.
_Avoid_: OLED, generic screen

**Display transport**:
The board-selected SPI mechanism used to send commands and pixels to the
NV3001B display.
The board-selected SPI mechanism used to send commands and pixels to a
configured display device, including the NV3001B display or an e-paper driver
board.
_Avoid_: default SPI, display bus

**DEPG1020BNS770F1 e-paper panel**:
The 960-by-640 monochrome e-paper panel driven by an SSD1677 controller.
_Avoid_: generic 10.2-inch display, TFT, grayscale panel

**E0213A367 e-paper panel**:
The 128-by-250 monochrome e-paper panel with a 122-by-250 drawable area,
connected through the RD02E e-paper driver board in RadioCore examples.
_Avoid_: generic 2.13-inch display, Wireless Paper display

**DEPG0290BNS800 e-paper panel**:
The 128-by-296 monochrome e-paper panel identified by its FPC-7519 rev.b
connector marking and supported by the matching heltec-eink-modules driver.
_Avoid_: generic 2.9-inch display, DEPG0290BNS75A, Vision Master display

**RD02E e-paper driver board**:
The external board that supplies switched power and high-voltage drive circuits
for compatible e-paper panels, including DEPG1020BNS770F1, E0213A367, and
DEPG0290BNS800, and exposes their controller logic interface.
_Avoid_: bare panel, passive adapter, TFT connector

**Full-screen e-paper refresh**:
A monochrome update that refreshes the complete e-paper image in one operation.
_Avoid_: partial refresh, fast refresh, grayscale refresh

**Partial-window e-paper refresh**:
A monochrome update that uses the panel's partial-refresh waveform to update
an explicitly selected region while preserving the surrounding displayed image.
_Avoid_: full-screen refresh, automatic change detection, grayscale refresh

**Fast-window e-paper update**:
A differential fast refresh whose image-RAM writes are restricted to a selected
window while the surrounding displayed image is preserved; it does not imply
that the controller drives only the selected gate region.
_Avoid_: proven local gate scan, full-screen refresh, grayscale refresh

**E-paper reference image**:
Controller-side image data that provides a baseline for subsequent partial
refreshes, distinct from the MCU drawing buffer and the physically visible image.
_Avoid_: MCU framebuffer, visible image

**Analog gas sensor**:
A CH01, VO01, or CO01 device that represents gas concentration as an analog output
voltage.
Expand Down Expand Up @@ -90,6 +141,16 @@ The board-designated digital signal connected to the logic input of an
external relay module or driver.
_Avoid_: relay coil output, load power output

**Rotary encoder input**:
The board-designated two-channel user control whose rotation produces previous
or next steps.
_Avoid_: rotary button, generic GPIO input

**User button input**:
The board-designated momentary digital input reported independently from
rotary encoder movement.
_Avoid_: rotary encoder press, enter key

**Servo control interface**:
The board-designated pair of servo PWM signals and enable signal used to
connect an external dual-servo driver such as the RS-SV01.
Expand Down
7 changes: 7 additions & 0 deletions docs/adr/0001-keep-e-paper-drivers-outside-radiocore-kit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Keep e-paper panel drivers outside RadioCore_Kit

RadioCore_Kit owns RadioCore board configuration and board-adaptive examples,
while reusable e-paper panel drivers remain in `heltec-eink-modules`. This keeps
the e-paper library independently usable and avoids coupling panel-controller
behavior to RadioCore hardware, at the cost of coordinating compatible releases
across the two repositories.
174 changes: 174 additions & 0 deletions examples/DEPG0290BNS800_Display/DEPG0290BNS800_Display.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* RadioCore DEPG0290BNS800 e-paper example
*
* Uses an RD02E driver board and the existing DEPG0290BNS800 display class
* from heltec-eink-modules. A successful full refresh establishes the image
* baseline before repeated fast-window updates.
*/
#include <Arduino.h>
#include <RadioCore_Kit.h>

#if !RADIOCORE_HAS_DEPG0290BNS800_DISPLAY
#error "DEPG0290BNS800_Display requires a supported RadioCore board configuration."
#else

#include <heltec-eink-modules.h>

namespace {

constexpr uint16_t kPageHeight = 32;
constexpr uint32_t kStartupFrameHoldMs = 1000UL;
constexpr uint32_t kRefreshRestMs = 2000UL;
constexpr uint8_t kFastUpdatesBeforeFull = 10;
// In landscape orientation, logical Y maps to the controller's byte-addressed
// X axis. This window is byte aligned and stays inside the 296 x 128 canvas.
constexpr uint16_t kWindowLeft = 8;
constexpr uint16_t kWindowTop = 72;
constexpr uint16_t kWindowWidth = 280;
constexpr uint16_t kWindowHeight = 48;

DEPG0290BNS800 display(
RADIOCORE_DEPG0290BNS800_DC,
RADIOCORE_DEPG0290BNS800_CS,
RADIOCORE_DEPG0290BNS800_BUSY,
RADIOCORE_DEPG0290BNS800_RST,
RADIOCORE_DEPG0290BNS800_ENABLE,
static_cast<SwitchType>(RADIOCORE_DEPG0290BNS800_ENABLE_ACTIVE),
RADIOCORE_DEPG0290BNS800_MOSI,
RADIOCORE_DEPG0290BNS800_SCK,
kPageHeight);

uint32_t refreshCount = 0;
uint8_t fastUpdateCount = 0;
bool hasBaseline = false;

bool showStartupFrame(uint16_t color)
{
display.fastmodeOff();
display.fullscreen();
if (!display.timedOut()) {
DRAW(display) {
display.fillScreen(color);
}
}
return !display.timedOut();
}

void drawUpdateRegion(uint32_t count)
{
// DRAW runs twice in fast mode. Never advance state inside this function.
display.fillRect(kWindowLeft, kWindowTop, kWindowWidth, kWindowHeight, WHITE);
display.setTextColor(BLACK);
display.setTextSize(2);
display.setCursor(12, 84);
display.print(F("Refresh: "));
display.println(count);

if (count & 1UL) {
display.fillRect(248, 80, 32, 32, BLACK);
} else {
display.drawRect(248, 80, 32, 32, BLACK);
}
}

void drawTestPage(uint32_t count)
{
display.drawRect(0, 0, display.width(), display.height(), BLACK);
display.drawRect(4, 4, display.width() - 8, display.height() - 8, BLACK);

display.setTextColor(BLACK);
display.setTextSize(2);
display.setCursor(12, 12);
display.println(F("RadioCore"));

display.setTextSize(1);
display.setCursor(176, 16);
display.println(F("FAST WINDOW UPDATE"));
display.setCursor(12, 40);
display.print(F("Board: "));
display.println(F(RADIOCORE_DEPG0290BNS800_BOARD_NAME));
display.setCursor(12, 54);
display.println(F("DEPG0290BNS800 296 x 128 BW"));
display.drawLine(8, 68, display.width() - 9, 68, BLACK);

drawUpdateRegion(count);
}

} // namespace

void setup()
{
Serial.begin(115200);
delay(100);

Serial.println();
Serial.print(F("RadioCore DEPG0290BNS800 example: "));
Serial.println(F(RADIOCORE_DEPG0290BNS800_BOARD_NAME));

display.landscape();

Serial.println(F("Startup self-test: full-screen black."));
if (!showStartupFrame(BLACK)) {
Serial.println(F("E-paper BUSY timeout during the black startup frame."));
Serial.println(F("Startup self-test aborted; the next cycle will try a normal full refresh."));
delay(kRefreshRestMs);
return;
}
delay(kStartupFrameHoldMs);

Serial.println(F("Startup self-test: full-screen white."));
if (!showStartupFrame(WHITE)) {
Serial.println(F("E-paper BUSY timeout during the white startup frame."));
Serial.println(F("Startup self-test aborted; the next cycle will try a normal full refresh."));
delay(kRefreshRestMs);
return;
}
delay(kStartupFrameHoldMs);
}

void loop()
{
const bool fullRefresh = !hasBaseline ||
fastUpdateCount >= kFastUpdatesBeforeFull;
const uint32_t nextCount = refreshCount + 1;
Serial.print(fullRefresh ? F("Starting full refresh ") : F("Starting fast window update "));
Serial.println(nextCount);

if (fullRefresh) {
display.fastmodeOff();
display.fullscreen();
} else {
display.fastmodeOn(false);
display.setWindow(kWindowLeft, kWindowTop, kWindowWidth, kWindowHeight);
}

if (!display.timedOut()) {
DRAW(display) {
if (fullRefresh) {
drawTestPage(nextCount);
} else {
drawUpdateRegion(nextCount);
}
}
}

if (display.timedOut()) {
hasBaseline = false;
fastUpdateCount = 0;
Serial.println(F("E-paper BUSY timeout; the driver board was powered down."));
Serial.println(F("The next cycle will rebuild the image with a full refresh."));
} else {
refreshCount = nextCount;
hasBaseline = true;
if (fullRefresh) {
fastUpdateCount = 0;
} else {
++fastUpdateCount;
}
Serial.println(F("Refresh complete; driver-board power remains on. Resting 2 s."));
}

delay(kRefreshRestMs);
}

#endif // RADIOCORE_HAS_DEPG0290BNS800_DISPLAY
Loading
Loading