增加开机功能
This commit is contained in:
3 files changed
+138
No files matched your search
@@ -13,6 +13,15 @@ DIY Meshtastic node variant based on an Ebyte nRF52840 MCU module and E22-400M33
|
||||
- **LED**: Bluetooth pairing status on P0.15 (`LED_PAIRING`). Solid on = BLE
|
||||
connected, slow blink = unpaired, fast blink = pairing, off after 30s idle.
|
||||
- **Battery ADC**: 0.5 voltage divider (equal resistors)
|
||||
- **Power button (P1.09) + self-hold latch (P0.05)**: the button supplies power
|
||||
while pressed. Hold it 2s to power on - firmware then drives P0.05 HIGH to
|
||||
latch the board on. Hold it 2s again to power off - the firmware saves the
|
||||
NodeDB first, then drops P0.05 LOW; the board keeps running on button power
|
||||
until the button is released. Low-battery cutoff (~3.2V) also drops the latch.
|
||||
Implemented in a dedicated FreeRTOS task (`powerButtonTask` in variant.cpp) -
|
||||
the nrf52 platform's weak `variant_shutdown`/`variant_nrf52LoopHook` hooks are
|
||||
inlined away by LTO and cannot be used (see the `noinline` note in
|
||||
`src/platform/nrf52/main-nrf52.cpp`).
|
||||
- **USB CDC serial**: enabled by default (nRF52840 built-in USB-ACM). Debug output
|
||||
and Meshtastic CLI communication go through the USB serial port.
|
||||
- **I2C**: SDA/SCL pins wired (P0.07/P0.12) but no I2C devices connected.
|
||||
@@ -25,6 +34,8 @@ DIY Meshtastic node variant based on an Ebyte nRF52840 MCU module and E22-400M33
|
||||
| CHARGE_DET | P0.13 | Active high (charging) |
|
||||
| BUZZER | P1.11 | PWM buzzer |
|
||||
| BATTERY_ADC | P0.03 | AIN1, 0.5 divider |
|
||||
| POWER_BTN | P1.09 | Power button, active low (to GND) |
|
||||
| POWER_LATCH | P0.05 | HIGH = keep board powered |
|
||||
| IIC_SDA | P0.07 | Wired, no device |
|
||||
| IIC_SCL | P0.12 | Wired, no device |
|
||||
| SPI_MISO | P0.26 | |
|
||||
@@ -36,6 +47,26 @@ DIY Meshtastic node variant based on an Ebyte nRF52840 MCU module and E22-400M33
|
||||
| LORA_RESET | P1.10 | |
|
||||
| LORA_RXEN | P0.02 | MCU-controlled RXEN; TXEN via DIO2 |
|
||||
|
||||
## Power button
|
||||
|
||||
- **Power on**: press and hold the button ~2s. The `powerButtonTask` FreeRTOS
|
||||
task detects P1.09 LOW for 2s, then drives P0.05 HIGH to latch the board on.
|
||||
- **Power off**: hold the button ~2s while running. The task saves the NodeDB
|
||||
(`nodeDB->saveToDisk()`), then drops P0.05 LOW. The board keeps running on
|
||||
button power until the button is released; releasing it cuts power. The
|
||||
normal shutdown sequence (shutdown melody / SystemOff) is intentionally not
|
||||
used - the task saves first and then just cuts the latch.
|
||||
- A release is required between power-on and arming power-off, so holding the
|
||||
button through the power-on latch cannot shut the board down again.
|
||||
- If the board resets while latched (button released), P1.09 reads HIGH at boot
|
||||
and `initVariant` re-latches P0.05 immediately - the board stays on through
|
||||
crashes and soft resets.
|
||||
- **Low battery cutoff**: the task checks the battery every 10s and, if it reads
|
||||
below 3.2V for 3 consecutive samples (and no USB power), saves the NodeDB and
|
||||
drops the latch. The threshold is above the firmware's own 3.1V SDS trigger so
|
||||
the latch is released before SystemOff could leave it engaged (SystemOff
|
||||
retains the latch and would drain the battery).
|
||||
|
||||
## Build & Flash
|
||||
|
||||
### Build
|
||||
@@ -106,6 +137,9 @@ openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg \
|
||||
the actual file produced by `pio run` or a shell glob.
|
||||
- USB CDC serial is available immediately after boot for debug output and the
|
||||
Meshtastic Python CLI (`meshtastic --noproto` / `meshtastic --info`).
|
||||
- During DFU flashing (bootloader reset), P0.05 is not driven, so the latch
|
||||
relies on button power or the latch circuit's hold capacitance - hold the
|
||||
power button during USB DFU if the board loses power mid-flash.
|
||||
- `MESHTASTIC_EXCLUDE_I2C=1` is set because no I2C devices are connected. Remove
|
||||
this flag from `platformio.ini` if an I2C display or sensor is added later.
|
||||
- No GPS, screen, accelerometer, magnetometer, or button is configured. Remove
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
*/
|
||||
|
||||
#include "variant.h"
|
||||
#include "PowerStatus.h" // powerStatus (battery state)
|
||||
#include "configuration.h" // millis, MESHTASTIC_LOG_LEVEL_INFO, console
|
||||
#include "freertosinc.h" // FreeRTOS (xTaskCreate, vTaskDelay)
|
||||
#include "mesh/NodeDB.h" // nodeDB
|
||||
#include "mesh/Throttle.h" // Throttle
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
@@ -30,6 +35,83 @@ const uint32_t g_ADigitalPinMap[] = {
|
||||
// P1
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||
|
||||
// Power button state machine (see variant.h). Runs in its own FreeRTOS task
|
||||
// because the nrf52 weak loop hooks are inlined away by LTO.
|
||||
static bool powerLatched = false;
|
||||
|
||||
static void logPowerButton(const char *msg)
|
||||
{
|
||||
if (console)
|
||||
console->log(MESHTASTIC_LOG_LEVEL_INFO, msg);
|
||||
}
|
||||
|
||||
static void powerButtonPowerOff()
|
||||
{
|
||||
// Save the DB first, then cut the latch. The board keeps running on button
|
||||
// power until the button is released (no SystemOff in this flow).
|
||||
nodeDB->saveToDisk();
|
||||
if (console)
|
||||
console->flush();
|
||||
nrf_gpio_pin_write(POWER_LATCH_PIN, 0);
|
||||
powerLatched = false;
|
||||
}
|
||||
|
||||
static void powerButtonTask(void *arg)
|
||||
{
|
||||
bool releaseSeen = false; // P1.09 must go HIGH once before arming power-off
|
||||
bool powerOffRequested = false;
|
||||
uint32_t lowSinceMs = 0;
|
||||
uint32_t lastBattCheck = 0;
|
||||
uint8_t lowBattCount = 0;
|
||||
|
||||
while (true) {
|
||||
bool pressed = !nrf_gpio_pin_read(POWER_BUTTON_PIN); // LOW = pressed
|
||||
|
||||
if (!powerOffRequested) {
|
||||
if (pressed) {
|
||||
if (lowSinceMs == 0)
|
||||
lowSinceMs = millis();
|
||||
else if ((uint32_t)(millis() - lowSinceMs) >= 2000) {
|
||||
if (!powerLatched) {
|
||||
// Power-on: hold the button 2s to latch the board on
|
||||
nrf_gpio_pin_write(POWER_LATCH_PIN, 1);
|
||||
powerLatched = true;
|
||||
releaseSeen = false;
|
||||
logPowerButton("Power button: latched on");
|
||||
} else if (releaseSeen) {
|
||||
// Power-off: hold the button 2s, save the DB, cut power
|
||||
logPowerButton("Power button: powering off");
|
||||
powerOffRequested = true;
|
||||
powerButtonPowerOff();
|
||||
}
|
||||
lowSinceMs = 0;
|
||||
}
|
||||
} else {
|
||||
releaseSeen = true;
|
||||
lowSinceMs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Low-battery cutoff: fires above the firmware's 3100mV SDS threshold
|
||||
// so the latch is dropped before SystemOff would leave it engaged.
|
||||
if (!powerOffRequested && !Throttle::isWithinTimespanMs(lastBattCheck, 10000)) {
|
||||
lastBattCheck = millis();
|
||||
if (powerStatus && powerStatus->getHasBattery() && !powerStatus->getHasUSB() &&
|
||||
powerStatus->getBatteryVoltageMv() > 0 && powerStatus->getBatteryVoltageMv() < 3200) {
|
||||
if (++lowBattCount >= 3) {
|
||||
logPowerButton("Power button: low battery cutoff");
|
||||
powerOffRequested = true;
|
||||
powerButtonPowerOff();
|
||||
}
|
||||
} else {
|
||||
lowBattCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
// Configure P0.18 as RESET pin (UICR->PSELRESET).
|
||||
@@ -52,7 +134,23 @@ void initVariant()
|
||||
NVIC_SystemReset(); // Reboot to apply PSELRESET (hardware reconfigures P0.18)
|
||||
}
|
||||
|
||||
// Power button + latch: button pulls P1.09 to GND, P0.05 HIGH keeps power on
|
||||
pinMode(POWER_LATCH_PIN, OUTPUT);
|
||||
digitalWrite(POWER_LATCH_PIN, LOW);
|
||||
pinMode(POWER_BUTTON_PIN, INPUT_PULLUP);
|
||||
|
||||
// If the button is not pressed at boot, power must already be latched
|
||||
// (reboot/crash while running on the latch) - re-latch immediately so the
|
||||
// board survives the reset glitch.
|
||||
if (digitalRead(POWER_BUTTON_PIN) == HIGH) {
|
||||
digitalWrite(POWER_LATCH_PIN, HIGH);
|
||||
powerLatched = true;
|
||||
}
|
||||
|
||||
// Initialize pairing LED pin (StatusLEDModule only calls digitalWrite, not pinMode)
|
||||
pinMode(LED_PAIRING, OUTPUT);
|
||||
digitalWrite(LED_PAIRING, LED_STATE_ON ^ 1); // OFF
|
||||
|
||||
// Power button state machine (created before the scheduler, runs at boot)
|
||||
xTaskCreate(powerButtonTask, "powerBtn", 2048, NULL, 10, NULL);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ MOONSHINE NRF TRAVELERS CORE PIN ASSIGNMENT (Ebyte nRF52840 + E22-400M33S)
|
||||
| P0.02 | LORA_RXEN | | P0.15 | LED |
|
||||
| P0.03 | VBAT_ADC | | P0.26 | SPI_MISO |
|
||||
| P0.04 | LORA_CS | | P0.28 | LORA_BUSY |
|
||||
| P0.05 | POWER_LATCH | | P1.09 | POWER_BTN |
|
||||
| P0.06 | SPI_MOSI | | P1.10 | LORA_RESET |
|
||||
| P0.07 | IIC_SDA | | P1.11 | BUZZER |
|
||||
| P0.08 | SPI_SCK | | P1.13 | LORA_DIO1 |
|
||||
@@ -76,6 +77,11 @@ MOONSHINE NRF TRAVELERS CORE PIN ASSIGNMENT (Ebyte nRF52840 + E22-400M33S)
|
||||
// Buzzer
|
||||
#define PIN_BUZZER (32 + 11) // P1.11
|
||||
|
||||
// Power button + self-hold latch: the button (pulled to GND) supplies power while
|
||||
// pressed; firmware drives P0.05 HIGH after a 2s hold to keep the board powered.
|
||||
#define POWER_BUTTON_PIN (32 + 9) // P1.09 - LOW = pressed
|
||||
#define POWER_LATCH_PIN (0 + 5) // P0.05 - HIGH = keep power on
|
||||
|
||||
// UART interfaces - no physical serial ports wired
|
||||
#define PIN_SERIAL1_RX (-1)
|
||||
#define PIN_SERIAL1_TX (-1)
|
||||
|
||||
Reference in New Issue
Block a user