mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 19:08:18 +00:00
fix heltec v3/4/4.3 0% battery
This commit is contained in:
@@ -9,13 +9,14 @@
|
||||
* LoRa SPI2 pins: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa control: DIO1=14, BUSY=13, RESET=12
|
||||
* Display I2C0: SDA=17, SCL=18 (SSD1306 @ 0x3C)
|
||||
* Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K
|
||||
* Battery ADC: GPIO1 = ADC1 ch0 (&adc0), enable GPIO37 active-HIGH, divider 100K/390K
|
||||
* Vext: GPIO36 (active-LOW, powers OLED) — regulator + vin-supply in overlay
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/adc/adc.h>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
@@ -33,22 +34,36 @@
|
||||
buttons: buttons {
|
||||
};
|
||||
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }.
|
||||
* Upstream vbatt node uses voltage-divider compatible which ZephCore
|
||||
* doesn't use. Multiplier: 3300mV full-scale * 5.42x = 17886.
|
||||
* (5.42x is Arduino's empirical divider factor for V3/V4.) */
|
||||
* doesn't use (deleted below).
|
||||
*
|
||||
* IMPORTANT: the battery pin is GPIO1 = ADC unit 1 channel 0. In the
|
||||
* upstream esp32s3 DTS the node *labelled* adc0 is unit 1 and the node
|
||||
* labelled adc1 is unit 2 (the label is 0-indexed, the unit is 1-indexed).
|
||||
* So GPIO1 lives on &adc0. The previous &adc1 (unit 2) channel 0 mapped to
|
||||
* ADC2_CH0 = GPIO11 = the SX1262 MISO — wrong peripheral, always read 0.
|
||||
*
|
||||
* Multiplier: Vref_internal(1100) * divider_ratio(5.2) = 5720, matching the
|
||||
* Heltec Wireless Tracker on the same 100K/390K divider (was 17886, which
|
||||
* assumed a 3300mV full-scale that ADC_REF_INTERNAL does not provide). */
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 0>;
|
||||
vbat-mv-multiplier = <17886>;
|
||||
io-channels = <&adc0 0>;
|
||||
vbat-mv-multiplier = <5720>;
|
||||
};
|
||||
|
||||
/* Battery ADC enable — GPIO37 (gpio1 pin 5) must be driven to read.
|
||||
* Upstream has adc_ctrl power-domain-gpio; ZephCore expects a
|
||||
* regulator-fixed named vbat_enable. */
|
||||
* Upstream has an adc_ctrl power-domain-gpio on the same GPIO37; it is
|
||||
* deleted below so this regulator is the sole owner (else the two fight
|
||||
* over the pin and the per-read enable/disable in ZephyrBoard is not
|
||||
* deterministic). Active-HIGH on V3.2/V4 (transistor in the enable path);
|
||||
* the previous GPIO_ACTIVE_LOW never powered the divider so the read was 0.
|
||||
* ZephyrBoard toggles this per read, so between reads the divider draws
|
||||
* nothing. (Early V3 boards may need GPIO_ACTIVE_LOW — see GH #50.) */
|
||||
vbat_enable: vbat-enable {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-enable";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
/* Vext — GPIO36, active-LOW enables rail (matches Arduino periph_power / MeshCore
|
||||
@@ -162,3 +177,37 @@
|
||||
|
||||
/* After SSD1306 no longer references vext_ctrl, remove upstream power-domain node. */
|
||||
/delete-node/ &vext_ctrl;
|
||||
|
||||
/* Battery ADC channel configuration on adc0 (ADC unit 1 -> GPIO1).
|
||||
* adc0 is status="disabled" upstream, so enable it here. Without the channel
|
||||
* node adc_channel_setup_dt() fails and getBattMilliVolts() returns 0 before it
|
||||
* ever performs a conversion — the primary cause of the hard "0% (0mV)".
|
||||
* ADC_GAIN_1 = 0 dB with ADC_REF_INTERNAL (~1100 mV); the divider output for a
|
||||
* 3.0-4.2 V cell (~580-810 mV) sits well inside range. */
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Remove the upstream 'vbatt' voltage-divider (io-channels on &adc1 = unit 2 =
|
||||
* GPIO11 = SX1262 MISO — wrong node) and the adc_ctrl power-domain that also
|
||||
* claims GPIO37 and fights the vbat_enable regulator above. */
|
||||
/ {
|
||||
/delete-node/ vbatt;
|
||||
};
|
||||
/delete-node/ &adc_ctrl;
|
||||
|
||||
/* ADC unit 2 (label adc1) is unused on this board; keep it disabled so nothing
|
||||
* can claim GPIO11 (SX1262 MISO) as an ADC pad. */
|
||||
&adc1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
* Heltec WiFi LoRa 32 V4 — ZephCore overlay
|
||||
*
|
||||
* The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM,
|
||||
* vext_enable, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* vext_enable, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* This overlay adds ZephCore-specific integration on top.
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, GC1109 CSD=2, CPS=46 (V4.2 — for V4.3/KCT8103L see heltec_wifi_lora32_v43)
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
* Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K
|
||||
* Battery ADC: GPIO1 = ADC1_CH0 (&adc0), enable GPIO37 active-HIGH, divider 100K/390K
|
||||
* Vext: GPIO36 (active-HIGH, powers OLED)
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35
|
||||
@@ -26,17 +26,21 @@
|
||||
};
|
||||
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }.
|
||||
* Multiplier: 3300mV full-scale * 5.42x empirical divider = 17886 mV.
|
||||
* (Same as V3 — identical resistor divider topology.) */
|
||||
* GPIO1 = ADC unit 1 = node &adc0 (label is 0-indexed, unit is 1-indexed);
|
||||
* the old &adc1 was unit 2 = GPIO11 = SX1262 MISO — always read 0.
|
||||
* Multiplier: Vref_internal(1100) * divider_ratio(5.2) = 5720 on the
|
||||
* 100K/390K divider (was 17886, which assumed a 3300mV full-scale that
|
||||
* ADC_REF_INTERNAL does not provide). Channel config is in the DTS. */
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 0>;
|
||||
vbat-mv-multiplier = <17886>;
|
||||
io-channels = <&adc0 0>;
|
||||
vbat-mv-multiplier = <5720>;
|
||||
};
|
||||
|
||||
/* Battery ADC enable — ZephCore uses vbat_enable regulator alias.
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path.
|
||||
* The DTS adc_ctrl node is power-domain-gpio which ZephCore doesn't use;
|
||||
* this regulator-fixed is the actual driver. */
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path. ZephyrBoard
|
||||
* toggles this per read (enable, sample, disable), so the divider draws
|
||||
* nothing between reads. The DTS no longer defines an adc_ctrl power-domain
|
||||
* on the same GPIO37, so this regulator is the sole owner. */
|
||||
vbat_enable: vbat-enable {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-enable";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35 (PWM via LEDC0)
|
||||
* Vext: GPIO36 active-HIGH (powers OLED and sensors)
|
||||
* BatADC: GPIO1 (ADC1 ch0), enable GPIO37 active-LOW
|
||||
* BatADC: GPIO1 = ADC1_CH0 (&adc0), enable GPIO37 active-HIGH (vbat_enable in overlay)
|
||||
*
|
||||
* V4.2 (this file) — GC1109 PA, TX_EN on GPIO46.
|
||||
* V4.3 (KCT8103L PA, CTX on GPIO5) → see heltec_wifi_lora32_v43.
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/lora/sx126x.h>
|
||||
#include <zephyr/dt-bindings/adc/adc.h>
|
||||
#include <espressif/partitions_0x0_amp_16M.dtsi>
|
||||
|
||||
/ {
|
||||
@@ -78,12 +79,9 @@
|
||||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
compatible = "voltage-divider";
|
||||
io-channels = <&adc1 0>; /* GPIO1 = ADC1 ch0 */
|
||||
output-ohms = <100000>;
|
||||
full-ohms = <(100000 + 390000)>;
|
||||
};
|
||||
/* No 'vbatt' voltage-divider node: ZephCore reads the battery via
|
||||
* zephyr,user { io-channels } (see board.overlay), and a voltage-divider
|
||||
* on &adc1 ch0 would target GPIO11 = the SX1262 MISO. See &adc0 below. */
|
||||
|
||||
/* Vext — powers OLED and external peripherals (active-HIGH on GPIO36).
|
||||
* regulator-fixed + SSD1306 vin-supply: powers rail at boot without relying on
|
||||
@@ -96,14 +94,9 @@
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
/* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery.
|
||||
* ZephCore uses the vbat_enable regulator alias for this. */
|
||||
adc_ctrl: adc_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5, active-LOW */
|
||||
#power-domain-cells = <0>;
|
||||
label = "ADC Control";
|
||||
};
|
||||
/* No adc_ctrl power-domain node: it would claim GPIO37 (gpio1 pin 5) with
|
||||
* the opposite polarity and fight the vbat_enable regulator in board.overlay,
|
||||
* which is the actual per-read driver for the ADC divider enable. */
|
||||
|
||||
/* FEM LDO power supply — GPIO7 powers the GC1109/KCT8103L LDO.
|
||||
* Must be HIGH before any radio operation. Keep always-on. */
|
||||
@@ -126,8 +119,30 @@
|
||||
};
|
||||
};
|
||||
|
||||
&adc1 {
|
||||
/* Battery ADC on adc0 (ADC unit 1 -> GPIO1 = ADC1_CH0). The node *labelled*
|
||||
* adc0 is unit 1; the node labelled adc1 is unit 2 (= GPIO11 = SX1262 MISO).
|
||||
* The channel@0 config is required — without it adc_channel_setup_dt() fails and
|
||||
* getBattMilliVolts() returns 0 before ever performing a conversion. ADC_GAIN_1
|
||||
* (0 dB) with ADC_REF_INTERNAL (~1100 mV); the 100K/390K divider output for a
|
||||
* 3.0-4.2 V cell sits well inside range. */
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
||||
/* ADC unit 2 (label adc1) is unused; keep it disabled so nothing can claim
|
||||
* GPIO11 (SX1262 MISO) as an ADC pad. */
|
||||
&adc1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
* Heltec WiFi LoRa 32 V4.3 — ZephCore overlay
|
||||
*
|
||||
* The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM,
|
||||
* vext_enable, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* vext_enable, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* This overlay adds ZephCore-specific integration on top.
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, KCT8103L CSD=2, CTX=5
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
* Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K
|
||||
* Battery ADC: GPIO1 = ADC1_CH0 (&adc0), enable GPIO37 active-HIGH, divider 100K/390K
|
||||
* Vext: GPIO36 (active-HIGH, powers OLED)
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35
|
||||
@@ -26,17 +26,21 @@
|
||||
};
|
||||
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }.
|
||||
* Multiplier: 3300mV full-scale * 5.42x empirical divider = 17886 mV.
|
||||
* (Same as V3 — identical resistor divider topology.) */
|
||||
* GPIO1 = ADC unit 1 = node &adc0 (label is 0-indexed, unit is 1-indexed);
|
||||
* the old &adc1 was unit 2 = GPIO11 = SX1262 MISO — always read 0.
|
||||
* Multiplier: Vref_internal(1100) * divider_ratio(5.2) = 5720 on the
|
||||
* 100K/390K divider (was 17886, which assumed a 3300mV full-scale that
|
||||
* ADC_REF_INTERNAL does not provide). Channel config is in the DTS. */
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 0>;
|
||||
vbat-mv-multiplier = <17886>;
|
||||
io-channels = <&adc0 0>;
|
||||
vbat-mv-multiplier = <5720>;
|
||||
};
|
||||
|
||||
/* Battery ADC enable — ZephCore uses vbat_enable regulator alias.
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path.
|
||||
* The DTS adc_ctrl node is power-domain-gpio which ZephCore doesn't use;
|
||||
* this regulator-fixed is the actual driver. */
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path. ZephyrBoard
|
||||
* toggles this per read (enable, sample, disable), so the divider draws
|
||||
* nothing between reads. The DTS no longer defines an adc_ctrl power-domain
|
||||
* on the same GPIO37, so this regulator is the sole owner. */
|
||||
vbat_enable: vbat-enable {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-enable";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35 (PWM via LEDC0)
|
||||
* Vext: GPIO36 active-HIGH (powers OLED and sensors)
|
||||
* BatADC: GPIO1 (ADC1 ch0), enable GPIO37 active-LOW
|
||||
* BatADC: GPIO1 = ADC1_CH0 (&adc0), enable GPIO37 active-HIGH (vbat_enable in overlay)
|
||||
*
|
||||
* V4.3 vs V4.2 difference — FEM chip changed:
|
||||
* V4.2: GC1109 PA — TX_EN on GPIO46 (CPS)
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/lora/sx126x.h>
|
||||
#include <zephyr/dt-bindings/adc/adc.h>
|
||||
#include <espressif/partitions_0x0_amp_16M.dtsi>
|
||||
|
||||
/ {
|
||||
@@ -77,12 +78,9 @@
|
||||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
compatible = "voltage-divider";
|
||||
io-channels = <&adc1 0>; /* GPIO1 = ADC1 ch0 */
|
||||
output-ohms = <100000>;
|
||||
full-ohms = <(100000 + 390000)>;
|
||||
};
|
||||
/* No 'vbatt' voltage-divider node: ZephCore reads the battery via
|
||||
* zephyr,user { io-channels } (see board.overlay), and a voltage-divider
|
||||
* on &adc1 ch0 would target GPIO11 = the SX1262 MISO. See &adc0 below. */
|
||||
|
||||
/* Vext — powers OLED and external peripherals (active-HIGH on GPIO36).
|
||||
* regulator-fixed + SSD1306 vin-supply: powers rail at boot without relying on
|
||||
@@ -95,13 +93,9 @@
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
/* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery */
|
||||
adc_ctrl: adc_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5, active-LOW */
|
||||
#power-domain-cells = <0>;
|
||||
label = "ADC Control";
|
||||
};
|
||||
/* No adc_ctrl power-domain node: it would claim GPIO37 (gpio1 pin 5) with
|
||||
* the opposite polarity and fight the vbat_enable regulator in board.overlay,
|
||||
* which is the actual per-read driver for the ADC divider enable. */
|
||||
|
||||
/* FEM LDO power supply — GPIO7 powers the KCT8103L LDO.
|
||||
* Must be HIGH before any radio operation. Keep always-on. */
|
||||
@@ -124,8 +118,30 @@
|
||||
};
|
||||
};
|
||||
|
||||
&adc1 {
|
||||
/* Battery ADC on adc0 (ADC unit 1 -> GPIO1 = ADC1_CH0). The node *labelled*
|
||||
* adc0 is unit 1; the node labelled adc1 is unit 2 (= GPIO11 = SX1262 MISO).
|
||||
* The channel@0 config is required — without it adc_channel_setup_dt() fails and
|
||||
* getBattMilliVolts() returns 0 before ever performing a conversion. ADC_GAIN_1
|
||||
* (0 dB) with ADC_REF_INTERNAL (~1100 mV); the 100K/390K divider output for a
|
||||
* 3.0-4.2 V cell sits well inside range. */
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
||||
/* ADC unit 2 (label adc1) is unused; keep it disabled so nothing can claim
|
||||
* GPIO11 (SX1262 MISO) as an ADC pad. */
|
||||
&adc1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
|
||||
Reference in New Issue
Block a user