SensorLib 0.5.1
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
AXP517Adc.cpp
Go to the documentation of this file.
1
30#include "../../../SensorBuildOpt.h"
31#if !SENSORLIB_EXCLUDE_PMIC_AXP517
32
33#include "AXP517Adc.hpp"
34#include "AXP517Regs.hpp"
35
36
37AXP517Adc::AXP517Adc(AXP517Core &core) : _core(core)
38{
39}
40
41namespace
42{
43bool readRegisterPair(AXP517Core &core, uint8_t highReg, uint8_t lowReg,
44 uint8_t &high, uint8_t &low)
45{
46 // The AXP517 PMIC register window does not auto-increment on a burst read.
47 // Read each address explicitly and retry if the high byte changed at a
48 // conversion boundary.
49 for (uint8_t attempt = 0; attempt < 3; ++attempt) {
50 int highBefore = core.readReg(highReg);
51 int lowValue = core.readReg(lowReg);
52 int highAfter = core.readReg(highReg);
53 if (highBefore < 0 || lowValue < 0 || highAfter < 0) return false;
54 if (highBefore == highAfter) {
55 high = static_cast<uint8_t>(highBefore);
56 low = static_cast<uint8_t>(lowValue);
57 return true;
58 }
59 }
60 return false;
61}
62
63bool selectAndReadAdcData(AXP517Core &core, uint8_t selector,
64 uint8_t &high, uint8_t &low)
65{
66 int dataSelect = core.readReg(axp517_regs::adc::DATA_SEL);
67 if (dataSelect < 0) return false;
68
69 if ((dataSelect & 0x0F) != selector) {
70 const uint8_t next = static_cast<uint8_t>((dataSelect & 0xF0) | selector);
71 if (core.writeReg(axp517_regs::adc::DATA_SEL, next) < 0) return false;
72
73 // REG9C/9D retains the previous multiplexed channel briefly after
74 // REG9B changes. Allow a fresh conversion before consuming the data.
75 core.delayMs(10);
76 }
77
78 return readRegisterPair(core, axp517_regs::adc::DATA_H,
79 axp517_regs::adc::DATA_L, high, low);
80}
81} // namespace
82
83static uint8_t axp517_channelToMask(PmicAdcBase::Channel ch)
84{
85 switch (ch) {
86 case PmicAdcBase::Channel::BAT_VOLTAGE: return 0x01;
88 case PmicAdcBase::Channel::VBUS_VOLTAGE: return 0x04;
89 case PmicAdcBase::Channel::VSYS_VOLTAGE: return 0x08;
91 case PmicAdcBase::Channel::BAT_CURRENT: return 0x60; // BAT_CHARGE | BAT_DISCHARGE
92 case PmicAdcBase::Channel::VBUS_CURRENT: return 0x80;
93 default: return 0;
94 }
95}
96
97bool AXP517Adc::enableChannels(uint32_t mask)
98{
99 uint8_t hwMask = 0;
100 forEachChannel(mask, [&](uint32_t bit) {
101 auto ch = static_cast<Channel>(bit);
102 hwMask |= axp517_channelToMask(ch);
103 });
104 if (hwMask == 0) return false;
105 int regVal = _core.readReg(axp517_regs::adc::ENABLE);
106 if (regVal < 0) return false;
107 regVal |= hwMask;
108 return _core.writeReg(axp517_regs::adc::ENABLE, static_cast<uint8_t>(regVal)) == 0;
109}
110
111bool AXP517Adc::disableChannels(uint32_t mask)
112{
113 uint8_t hwMask = 0;
114 forEachChannel(mask, [&](uint32_t bit) {
115 auto ch = static_cast<Channel>(bit);
116 hwMask |= axp517_channelToMask(ch);
117 });
118 if (hwMask == 0) return false;
119 int regVal = _core.readReg(axp517_regs::adc::ENABLE);
120 if (regVal < 0) return false;
121 regVal &= ~hwMask;
122 return _core.writeReg(axp517_regs::adc::ENABLE, static_cast<uint8_t>(regVal)) == 0;
123}
124
125bool AXP517Adc::read(Channel ch, float &out)
126{
127 int16_t adcVal;
128 uint8_t buffer[2] = {0, 0};
129 out = NAN; // Default to NaN for unsupported channels or read errors
130
131 if (ch == Channel::VBUS_VOLTAGE || ch == Channel::VBUS_CURRENT ||
133
134 int status0 = _core.readReg(axp517_regs::bmu::STATUS0);
135 if (status0 < 0) {
136 return false;
137 }
138 bool vbusPresent = (status0 >> 5) & 0x01;
139 bool batPresent = (status0 >> 3) & 0x01;
140
141 if (ch == Channel::VBUS_VOLTAGE || ch == Channel::VBUS_CURRENT) {
142 if (!vbusPresent) {
143 // VBUS is not present
144 out = 0.0f;
145 return true;
146 }
147 }
148
149 if (ch == Channel::BAT_VOLTAGE || ch == Channel::BAT_CURRENT) {
150 if (!batPresent) {
151 // Battery is not present
152 out = 0.0f;
153 return true;
154 }
155 }
156 }
157
158 switch (ch) {
160 if (!readRegisterPair(_core, axp517_regs::adc::VBUS_VOLT_H,
161 axp517_regs::adc::VBUS_VOLT_L, buffer[0], buffer[1]))
162 return false;
163 out = ((buffer[0] & 0x3F) << 8 | buffer[1]) * axp517_regs::factory::FACTORY_VBUS_VOLTAGE;
164 break;
166 if (!readRegisterPair(_core, axp517_regs::adc::VBUS_CURR_H,
167 axp517_regs::adc::VBUS_CURR_L, buffer[0], buffer[1]))
168 return false;
169 adcVal = (static_cast<int16_t>((buffer[0] & 0x3F) << 8 | buffer[1]));
171 break;
173 if (!readRegisterPair(_core, axp517_regs::adc::BAT_VOLT_H,
174 axp517_regs::adc::BAT_VOLT_L, buffer[0], buffer[1]))
175 return false;
176 out = ((buffer[0] & 0x3F) << 8 | buffer[1]) * axp517_regs::factory::FACTORY_VBAT_VOLTAGE;
177 break;
179 if (!readRegisterPair(_core, axp517_regs::adc::BAT_CURR_H,
180 axp517_regs::adc::BAT_CURR_L, buffer[0], buffer[1]))
181 return false;
182 adcVal = (static_cast<int16_t>(buffer[0]) << 8) | buffer[1];
183 out = static_cast<float>(adcVal) * axp517_regs::factory::FACTORY_BAT_CURRENT;
184 break;
186 if (!selectAndReadAdcData(_core, 0x01, buffer[0], buffer[1])) return false;
187 adcVal = ((buffer[0] & 0x3F) << 8) | buffer[1];
188 out = static_cast<int16_t>((buffer[0] & 0x3F) << 8 | buffer[1]) * axp517_regs::factory::FACTORY_VSYS_VOLTAGE;
189 break;
191 if (!selectAndReadAdcData(_core, 0x00, buffer[0], buffer[1])) return false;
192 adcVal = ((buffer[0] & 0x3F) << 8) | buffer[1];
193 out = (3552.0f - adcVal) / 1.79f + 25.0f;
194 break;
196 if (_core.readRegBuff(axp517_regs::gauge::BAT_TEMP, buffer, 1) < 0) {
197 return false;
198 }
199 out = static_cast<float>(buffer[0]);
200 break;
202 if (_core.readRegBuff(axp517_regs::gauge::BAT_PERCENT, buffer, 1) < 0) {
203 return false;
204 }
205 out = static_cast<float>(buffer[0]);
206 break;
207 default:
208 return false;
209 }
210 return true;
211}
212
213#endif
@license MIT License
@license MIT License
AXP517Adc(AXP517Core &core)
Construct an AXP517 ADC driver.
Definition AXP517Adc.cpp:37
bool enableChannels(uint32_t mask) override
Enable one or more ADC channels.
Definition AXP517Adc.cpp:97
bool read(Channel ch, float &out) override
Read an ADC channel.
bool disableChannels(uint32_t mask) override
Disable one or more ADC channels.
AXP517 low-level core driver.
void delayMs(uint32_t ms)
Delay using the active platform HAL.
static void forEachChannel(uint32_t mask, Func fn)
Helper to iterate over set bits in a bitmask.
Channel
ADC channel bitmask.
@ BAT_PERCENTAGE
Battery percentage.
@ DIE_TEMPERATURE
Die temperature.
@ BAT_VOLTAGE
Battery voltage.
@ BAT_TEMPERATURE
Battery temperature.
@ BAT_CURRENT
Battery current.
@ VBUS_CURRENT
VBUS current.
@ VBUS_VOLTAGE
VBUS voltage.
@ VSYS_VOLTAGE
VSYS voltage.
int readReg(uint8_t reg) const
int writeReg(uint8_t reg, uint8_t val)
int readRegBuff(uint8_t reg, uint8_t *buf, size_t len) const
static constexpr uint8_t BAT_VOLT_H
BAT voltage ADC high.
static constexpr uint8_t ENABLE
ADC channel enable control.
static constexpr uint8_t VBUS_CURR_H
VBUS current ADC high.
static constexpr uint8_t BAT_CURR_H
BAT current ADC high.
static constexpr uint8_t DATA_H
ADC data high.
static constexpr uint8_t VBUS_CURR_L
VBUS current ADC low.
static constexpr uint8_t BAT_CURR_L
BAT current ADC low.
static constexpr uint8_t VBUS_VOLT_H
VBUS voltage ADC high.
static constexpr uint8_t VBUS_VOLT_L
VBUS voltage ADC low.
static constexpr uint8_t BAT_VOLT_L
BAT voltage ADC low.
static constexpr uint8_t DATA_SEL
ADC data select.
static constexpr uint8_t DATA_L
ADC data low.
static constexpr uint8_t STATUS0
BMU status0.
static constexpr float FACTORY_BAT_CURRENT
16-Bit(including sign bit)
static constexpr float FACTORY_VBUS_CURRENT
14-Bit(including sign bit)
static constexpr float FACTORY_VBAT_VOLTAGE
14-Bit(including sign bit)
static constexpr float FACTORY_VSYS_VOLTAGE
14-Bit(including sign bit)
static constexpr float FACTORY_VBUS_VOLTAGE
14-Bit(including sign bit)
static constexpr uint8_t BAT_PERCENT
Battery percentage (RO)
static constexpr uint8_t BAT_TEMP
Battery temperature (RO)