#include "../core/module.h" #include "../core/ui.h" #include "../core/pins.h" // Voltage sensing. Reads the ADC behind an external divider and reports // a live voltage plus a guess at the logic family, so you know what // you're probing BEFORE you drive a pin into it. Min/max are held so a // brief transient (e.g. a bus idling high) is captured. // // The ESP32-S3 ADC is non-linear near the rails; we use the Arduino // analogReadMilliVolts() calibration path and apply the divider ratio. class VSense : public Module { float v = 0, vmin = 99, vmax = 0; uint32_t lastMs = 0; public: const char* name() const override { return "V-Sense"; } const char* blurb() const override { return "target voltage probe"; } void onEnter() override { analogReadResolution(12); pinMode(pins::VSENSE_ADC, INPUT); vmin = 99; vmax = 0; } bool onKey(char c) override { if (c == 'r') { vmin = 99; vmax = 0; return true; } // reset hold return false; } void tick() override { if (millis() - lastMs < 100) return; lastMs = millis(); uint32_t mv = analogReadMilliVolts(pins::VSENSE_ADC); v = (mv / 1000.0f) * pins::VSENSE_RATIO; if (v < vmin) vmin = v; if (v > vmax) vmax = v; } void draw() override { ui::lineC(0, ui::accent(), "Vin = %5.2f V", v); ui::line(1, "min %4.2f max %4.2f (ratio %.1f)", vmin, vmax, pins::VSENSE_RATIO); ui::lineC(3, family(v).color, "logic: %s", family(v).name); ui::line(5, "wire target -> divider -> G%d", pins::VSENSE_ADC); ui::hintBar("[r]eset hold [`]back"); } private: struct Fam { const char* name; uint16_t color; }; Fam family(float x) { if (x < 0.3f) return {"floating / GND", ui::fg()}; if (x < 1.5f) return {"1.2V core rail", ui::warn()}; if (x < 2.1f) return {"1.8V logic", ui::warn()}; if (x < 3.0f) return {"2.5V logic", ui::warn()}; if (x < 3.9f) return {"3.3V logic OK", ui::accent()}; if (x < 6.0f) return {"5V ! shift req", ui::bad()}; return {"HIGH >6V DANGER", ui::bad()}; } }; Module* makeVSense() { return new VSense(); }