SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
axp517_pd_auto_request.ino
Go to the documentation of this file.
1
30#include <Arduino.h>
31#include <Wire.h>
32#include <PmicDrv.hpp>
33
34#ifndef PMIC_SDA
35#define PMIC_SDA 3
36#endif
37
38#ifndef PMIC_SCL
39#define PMIC_SCL 2
40#endif
41
42#ifndef PMIC_IRQ
43#define PMIC_IRQ 44
44#endif
45
46#ifndef PD_TARGET_MV
47#define PD_TARGET_MV 9000
48#endif
49
50#ifndef PD_TIMEOUT_MS
51#define PD_TIMEOUT_MS 6000
52#endif
53
54#if PMIC_IRQ < 0
55#error "AXP517 PD negotiation requires a valid PMIC_IRQ pin."
56#endif
57
60
61volatile bool irqTriggered = false;
62bool pdReady = false;
63
64static constexpr uint16_t VBUS_PRESENT_MV = 4000;
65static constexpr uint32_t VBUS_SETTLE_MS = 300;
66static constexpr uint32_t IRQ_PENDING_PRINT_MS = 1000;
67
69{
70 irqTriggered = true;
71}
72
74{
75 Serial.println("\n--- Source Capabilities ---");
76 Serial.print("Total PDO count: ");
77 Serial.println(caps.totalPdoCount);
78
79 if (caps.fixedCount == 0) {
80 Serial.println("No fixed PDO found.");
81 return;
82 }
83
84 for (uint8_t i = 0; i < caps.fixedCount; ++i) {
85 const auto &pdo = caps.fixed[i];
86
87 Serial.print("PDO");
88 Serial.print(pdo.pdoIndex1Based);
89 Serial.print(": ");
90 Serial.print(pdo.mv);
91 Serial.print(" mV / ");
92 Serial.print(pdo.maMax);
93 Serial.print(" mA, raw=0x");
94 Serial.println(pdo.rawPdo, HEX);
95 }
96}
97
98void printIrqStatus(uint64_t status)
99{
100 Serial.print("IRQ Status: high=0x");
101 Serial.print(static_cast<uint32_t>(status >> 32), HEX);
102 Serial.print(" low=0x");
103 Serial.println(static_cast<uint32_t>(status), HEX);
104}
105
107{
108 uint16_t vbusMv = 0;
109
110 if (pmic.tcpc().readVbusMv(vbusMv)) {
111 Serial.print("TCPC VBUS: ");
112 Serial.print(vbusMv);
113 Serial.println(" mV");
114 }
115}
116
118{
120 return true;
121 }
122
123 if (pmic.tcpc().isVbusPresent()) {
124 return true;
125 }
126
127 uint16_t vbusMv = 0;
128 return pmic.tcpc().readVbusMv(vbusMv) && vbusMv >= VBUS_PRESENT_MV;
129}
130
131bool waitForVbusPresent(uint32_t timeoutMs)
132{
133 uint32_t start = millis();
134
135 do {
136 if (isVbusPresentNow()) {
137 return true;
138 }
139 delay(10);
140 } while (millis() - start < timeoutMs);
141
142 return false;
143}
144
145bool isTcpcDetachAlert(uint64_t irqStatus, bool vbusPresent)
146{
147 uint16_t pdAlert = static_cast<uint16_t>(irqStatus >> 32);
148
149 if (vbusPresent) {
150 return false;
151 }
152
153 if (pdAlert & AXP517Tcpc::AlertVbusDisconnect) {
154 return true;
155 }
156
157 if ((pdAlert & AXP517Tcpc::AlertCcStatus) && !pmic.tcpc().isAttached()) {
158 return true;
159 }
160
161 if (pdAlert & AXP517Tcpc::AlertPowerStatus) {
162 return true;
163 }
164
165 return false;
166}
167
168bool isTcpcSourceActivityAlert(uint64_t irqStatus)
169{
170 uint16_t pdAlert = static_cast<uint16_t>(irqStatus >> 32);
171 return (pdAlert & (AXP517Tcpc::AlertPowerStatus |
173}
174
175bool isTcpcFaultAlert(uint64_t irqStatus)
176{
177 uint16_t pdAlert = static_cast<uint16_t>(irqStatus >> 32);
178 return (pdAlert & AXP517Tcpc::AlertFault) != 0;
179}
180
181bool isStickyTcpcAlert(uint64_t irqStatus)
182{
183 uint16_t pdAlert = static_cast<uint16_t>(irqStatus >> 32);
184 uint32_t pmicIrq = static_cast<uint32_t>(irqStatus);
185 constexpr uint16_t actionable =
194
195 return pmicIrq == 0 && pdAlert != 0 && (pdAlert & actionable) == 0;
196}
197
198void resetPdState(const char *reason)
199{
200 Serial.println(reason);
201 pdReady = false;
203 pmic.pd().reset();
204 pmic.tcpc().clearTx();
205
206 if (!pmic.irq().clearStatus()) {
207 Serial.println("Failed to clear IRQ status after PD reset.");
208 }
209}
210
212{
214
215 Serial.print("Requesting PD voltage: ");
216 Serial.print(PD_TARGET_MV);
217 Serial.println(" mV");
218
221
222 Serial.println("\n--- PD Result ---");
223 Serial.println(pdReady ? "Negotiation success." : "Negotiation failed.");
224 printVbus();
225
226 // Keep GPIO0 mux untouched in this mixed IRQ example. The PD negotiator
227 // only needs the IRQ pin level; PWRON/BAT/VBUS events still use PMIC_IRQ.
228 if (!pmic.irq().clearStatus()) {
229 Serial.println("Failed to clear IRQ status after PD request.");
230 }
231}
232
234{
235 uint64_t irqStatus = pmic.irq().readStatus(true);
236 if (irqStatus == 0) {
237 return false;
238 }
239
240 bool stickyTcpc = isStickyTcpcAlert(irqStatus);
241 if (!stickyTcpc) {
242 printIrqStatus(irqStatus);
243 }
244
245 if (pmic.irq().isPwrOnShortPress(irqStatus)) {
246 Serial.println("Power On Short Press Detected");
247 // requestPdVoltage();
248 }
249
250 if (pmic.irq().isBatteryInsert(irqStatus)) {
251 Serial.println("Battery Inserted");
252 }
253
254 if (pmic.irq().isBatteryRemove(irqStatus)) {
255 Serial.println("Battery Removed");
256 }
257
258 bool vbusInserted = pmic.irq().isVbusInsert(irqStatus);
259 bool vbusRemoved = pmic.irq().isVbusRemove(irqStatus);
260 bool tcpcSourceActivity = isTcpcSourceActivityAlert(irqStatus);
261 bool vbusPresent = isVbusPresentNow();
262 if (!pdReady && !vbusPresent && (vbusInserted || tcpcSourceActivity)) {
263 vbusPresent = waitForVbusPresent(VBUS_SETTLE_MS);
264 }
265
266 bool tcpcDetached = isTcpcDetachAlert(irqStatus, vbusPresent);
267 bool tcpcFault = isTcpcFaultAlert(irqStatus);
268 if (pdReady && (vbusRemoved || tcpcDetached || (!vbusPresent && (tcpcFault || stickyTcpc)))) {
269 if (vbusRemoved) {
270 Serial.println("VBUS Removed");
271 }
272 if (tcpcDetached) {
273 Serial.println("TCPC detached");
274 }
275 resetPdState("PD state reset.");
276 return true;
277 }
278
279 if (!pdReady && (vbusInserted || tcpcSourceActivity)) {
280 if (vbusInserted) {
281 Serial.println("VBUS Inserted");
282 } else {
283 Serial.println("TCPC VBUS activity detected");
284 }
285
286 if (vbusPresent) {
288 } else {
289 Serial.println("VBUS is not present, skip PD request.");
290 }
291 return true;
292 }
293
294 if (stickyTcpc) {
295 static uint32_t lastFaultPrint = 0;
296 if (millis() - lastFaultPrint > 1000) {
297 lastFaultPrint = millis();
298 printIrqStatus(irqStatus);
299 Serial.println(tcpcFault ? "TCPC fault pending" : "TCPC alert pending");
300 }
301 return false;
302 }
303
304 return true;
305}
306
308{
309 uint32_t deadline = millis() + 250;
310
311 while (millis() < deadline) {
312 bool handled = handlePmicIrq();
313 delay(2);
314
315 if (digitalRead(PMIC_IRQ) != LOW) {
316 return;
317 }
318
319 if (!handled) {
320 return;
321 }
322 }
323
324 if (digitalRead(PMIC_IRQ) == LOW) {
325 Serial.println("PMIC_IRQ is still LOW after drain.");
326 }
327}
328
329void setup()
330{
331 Serial.begin(115200);
332 delay(500);
333
334 Serial.println("\n=== AXP517 PD Auto Request Example ===\n");
335 Serial.print("Target voltage: ");
336 Serial.print(PD_TARGET_MV);
337 Serial.println(" mV");
338
339 if (!pmic.begin(Wire, AXP517_SLAVE_ADDRESS, PMIC_SDA, PMIC_SCL, PMIC_IRQ)) {
340 Serial.println("Failed to init AXP517 or PMIC_IRQ pin!");
341 while (1) delay(1000);
342 }
343
349 pmic.irq().clearStatus();
350
351 pinMode(PMIC_IRQ, INPUT_PULLUP);
352 attachInterrupt(PMIC_IRQ, onPmicIrq, FALLING);
353
354 Serial.print("PMIC_IRQ pin: ");
355 Serial.println(PMIC_IRQ);
356 Serial.println("Waiting for VBUS insert interrupt...");
357
359 Serial.println("VBUS already present");
361 }
362}
363
364void loop()
365{
366 static uint32_t lastPrint = 0;
367 static uint32_t lastPendingPrint = 0;
368
369 if (irqTriggered || digitalRead(PMIC_IRQ) == LOW) {
370 if (irqTriggered) {
371 Serial.println("IRQ Triggered");
372 } else if (millis() - lastPendingPrint > IRQ_PENDING_PRINT_MS) {
373 lastPendingPrint = millis();
374 Serial.println("IRQ Pending");
375 }
376 irqTriggered = false;
377 drainPmicIrq();
378 }
379
380 if (millis() - lastPrint > 2000) {
381 lastPrint = millis();
382
383 Serial.println("\n--- Status ---");
384 Serial.print("PD: ");
385 Serial.println(pdReady ? "Ready" : "Waiting");
386 printVbus();
387 }
388
389 delay(100);
390}
@license MIT License
PmicAXP517 pmic
void printVbus()
#define PMIC_SDA
bool waitForVbusPresent(uint32_t timeoutMs)
#define PMIC_SCL
#define PMIC_IRQ
bool isTcpcDetachAlert(uint64_t irqStatus, bool vbusPresent)
#define PD_TARGET_MV
bool isVbusPresentNow()
#define PD_TIMEOUT_MS
void requestPdVoltage()
void drainPmicIrq()
bool isStickyTcpcAlert(uint64_t irqStatus)
bool handlePmicIrq()
bool isTcpcSourceActivityAlert(uint64_t irqStatus)
volatile bool irqTriggered
void resetPdState(const char *reason)
void printSourceCaps(const AXP517PdNegotiator::SourceCaps &caps)
void printIrqStatus(uint64_t status)
void onPmicIrq()
AXP517PdNegotiator::SourceCaps sourceCaps
bool isTcpcFaultAlert(uint64_t irqStatus)
Status getStatus() override
Get current charger status (best-effort).
bool enable(uint64_t mask) override
Enable one or more PMIC IRQ sources.
Definition AXP517Irq.cpp:41
static bool isPwrOnShortPress(uint64_t mask)
static bool isBatteryRemove(uint64_t mask)
static constexpr uint64_t IRQ_VBUS_REMOVE
VBUS Remove.
Definition AXP517Irq.hpp:68
static constexpr uint64_t IRQ_VBUS_INSERT
VBUS Insert.
Definition AXP517Irq.hpp:67
static constexpr uint64_t IRQ_BATTERY_INSERT
Battery Insert.
Definition AXP517Irq.hpp:69
static bool isBatteryInsert(uint64_t mask)
static constexpr uint64_t IRQ_BATTERY_REMOVE
Battery Remove.
Definition AXP517Irq.hpp:70
static constexpr uint64_t IRQ_PWR_ON_SHORT_PRESS
PWR_ON pin Short PRESS.
Definition AXP517Irq.hpp:71
static bool isVbusInsert(uint64_t mask)
uint64_t readStatus(bool clear=true) override
Read the current IRQ status.
Definition AXP517Irq.cpp:93
bool clearStatus() override
Clear all pending PMIC IRQ and TCPC alert status bits.
static bool isVbusRemove(uint64_t mask)
void reset()
Reset message IDs and return to the initial wait state.
bool clearTx()
Reset the TX byte count and transmit command register.
bool isAttached()
Check whether either CC pin indicates attachment.
@ AlertTxFailed
Message transmission failed.
@ AlertPowerStatus
POWER_STATUS register changed.
@ AlertTxSuccess
Message transmission completed.
@ AlertRxHardReset
Hard Reset received.
@ AlertRxStatus
RX buffer contains a SOP message.
@ AlertTxDiscarded
Transmission discarded due to RX activity.
@ AlertFault
TCPC fault status changed.
@ AlertVbusDisconnect
VBUS sink disconnect threshold crossed.
@ AlertCcStatus
CC_STATUS register changed.
bool readVbusMv(uint16_t &mv)
Read TCPC VBUS ADC value.
bool isVbusPresent()
Check whether TCPC VBUS present status is set.
High-level driver facade for the X-Powers AXP517 PMIC.
AXP517Tcpc & tcpc()
Access the low-level AXP517 TCPC helper.
bool requestPd(uint16_t targetMv, uint32_t timeoutMs=6000, AXP517PdNegotiator::SourceCaps *outCaps=nullptr)
Request a fixed USB-PD voltage from the attached source.
AXP517PdNegotiator & pd()
Access the USB-PD sink negotiator.
AXP517Charger & charger()
Access the AXP517 charger driver.
bool begin(SensorCommCustom::CustomCallback callback, SensorCommCustomHal::CustomHalCallback hal_cb, uint8_t addr)
Initialization using a custom communication interface.
AXP517Irq & irq()
Access the AXP517 IRQ driver.
uint8_t i
Parsed Source_Capabilities message.
uint8_t totalPdoCount
Total PDO count advertised in the message.
FixedOffer fixed[7]
Parsed fixed PDO offers.
uint8_t fixedCount
Number of valid entries in fixed[].
bool vbusPresent
VBUS detected / good (USB power present)