PF1550 Driver
API reference
Loading...
Searching...
No Matches
pf1550.ipp
Go to the documentation of this file.
1
6#pragma once
7
8namespace pf1550 {
9
10template <typename BusType>
11PF1550<BusType>::PF1550(BusType* bus, uint8_t address) noexcept
12 : bus_(bus), address_(address), initialized_(false), error_flags_(0) {}
13
14template <typename BusType>
15bool PF1550<BusType>::writeReg8(uint8_t reg, uint8_t value) noexcept {
16 if (bus_ == nullptr) {
17 setError(Error::InvalidParam);
18 return false;
19 }
20 const uint8_t data = value;
21 if (!bus_->Write(address_, reg, &data, 1)) {
22 setError(Error::I2cWrite);
23 return false;
24 }
25 return true;
26}
27
28template <typename BusType>
29bool PF1550<BusType>::readReg8(uint8_t reg, uint8_t& value) noexcept {
30 if (bus_ == nullptr) {
31 setError(Error::InvalidParam);
32 return false;
33 }
34 if (!bus_->Read(address_, reg, &value, 1)) {
35 setError(Error::I2cRead);
36 return false;
37 }
38 return true;
39}
40
41template <typename BusType>
43 if (initialized_) {
44 return true;
45 }
46 if (bus_ == nullptr || !bus_->EnsureInitialized()) {
47 setError(Error::NotInitialized);
48 return false;
49 }
50 if (!VerifyDevice()) {
51 return false;
52 }
53 initialized_ = true;
54 ClearErrorFlags(static_cast<uint16_t>(Error::NotInitialized));
55 return true;
56}
57
58template <typename BusType>
59bool PF1550<BusType>::ReadDeviceId(uint8_t& id) noexcept {
60 if (!readReg8(static_cast<uint8_t>(Register::DeviceId), id)) {
61 return false;
62 }
63 return true;
64}
65
66template <typename BusType>
68 uint8_t id = 0;
69 if (!ReadDeviceId(id)) {
70 setError(Error::DeviceNotFound);
71 return false;
72 }
73 if (id != kExpectedDeviceId) {
74 setError(Error::WrongDeviceId);
75 return false;
76 }
77 return true;
78}
79
80template <typename BusType>
81bool PF1550<BusType>::ReadRegister(Register reg, uint8_t& value) noexcept {
82 return readReg8(static_cast<uint8_t>(reg), value);
83}
84
85template <typename BusType>
86bool PF1550<BusType>::WriteRegister(Register reg, uint8_t value) noexcept {
87 return writeReg8(static_cast<uint8_t>(reg), value);
88}
89
90template <typename BusType>
91bool PF1550<BusType>::ApplyProfile(std::span<const profiles::RegisterWrite> profile) noexcept {
92 if (bus_ == nullptr || !bus_->EnsureInitialized()) {
93 setError(Error::NotInitialized);
94 return false;
95 }
96
97 for (const auto& entry : profile) {
98 if (!writeReg8(entry.reg, entry.value)) {
99 setError(Error::ProfileApply);
100 return false;
101 }
102 if (entry.delay_us > 0) {
103 bus_->DelayUs(entry.delay_us);
104 }
105 }
106 return true;
107}
108
109template <typename BusType>
113
114template <typename BusType>
118
119template <typename BusType>
121 if (bus_ == nullptr) {
122 setError(Error::InvalidParam);
123 return false;
124 }
125 switch (mode) {
126 case PowerMode::Run:
127 bus_->GpioSetInactive(CtrlPin::Standby);
128 break;
130 bus_->GpioSetActive(CtrlPin::Standby);
131 break;
132 default:
133 setError(Error::InvalidParam);
134 return false;
135 }
136 return true;
137}
138
139template <typename BusType>
140bool PF1550<BusType>::SetUsbRails(bool vbus_en, bool otg_en) noexcept {
141 if (bus_ == nullptr) {
142 setError(Error::InvalidParam);
143 return false;
144 }
147 return true;
148}
149
150template <typename BusType>
151bool PF1550<BusType>::ReadPmicStatus(uint8_t& status) noexcept {
152 return readReg8(static_cast<uint8_t>(Register::StateInfo), status);
153}
154
155template <typename BusType>
157 uint8_t raw = 0;
158 if (!ReadPmicStatus(raw)) {
159 state = PmicState::Unknown;
160 return false;
161 }
162 state = DecodeStateInfo(raw);
163 return true;
164}
165
166template <typename BusType>
167bool PF1550<BusType>::ReadChargerState(ChargerState& state, uint8_t* raw_reg) noexcept {
168 uint8_t raw = 0;
169 if (!readReg8(static_cast<uint8_t>(Register::ChgSense), raw)) {
170 state = ChargerState::Unknown;
171 return false;
172 }
173 if (raw_reg != nullptr) {
174 *raw_reg = raw;
175 }
176 state = DecodeChargerSense(raw);
177 return true;
178}
179
180template <typename BusType>
181bool PF1550<BusType>::ReadOtpByte(uint8_t otp_addr, uint8_t& value) noexcept {
185 return false;
186 }
187
188 if (!writeReg8(static_cast<uint8_t>(Register::FmrAddr), otp_addr)) {
189 return false;
190 }
191 bus_->DelayUs(2000);
192 return readReg8(static_cast<uint8_t>(Register::FmrData), value);
193}
194
195template <typename BusType>
196bool PF1550<BusType>::ReadOtpRegion(uint8_t* buffer, size_t len, uint8_t start) noexcept {
197 if (buffer == nullptr || len == 0) {
198 setError(Error::InvalidParam);
199 return false;
200 }
201 for (size_t i = 0; i < len; ++i) {
202 const uint8_t addr = static_cast<uint8_t>(start + i);
203 if (addr >= OtpRegion::kEndExclusive) {
204 setError(Error::InvalidParam);
205 return false;
206 }
207 if (!ReadOtpByte(addr, buffer[i])) {
208 return false;
209 }
210 }
211 return true;
212}
213
214template <typename BusType>
215bool PF1550<BusType>::SetSwVoltage(uint8_t sw_index, SwVoltageCode run_code) noexcept {
216 return SetSwVoltageMv(sw_index, SwCodeToMillivolts(static_cast<uint8_t>(run_code)));
217}
218
219template <typename BusType>
220bool PF1550<BusType>::SetSwVoltageMv(uint8_t sw_index, uint16_t mv) noexcept {
221 // SW3_VOLT is OTP-loaded and read-only (Table 37); SW1/SW2_VOLT are writable only with DVS enabled
222 // (Table 31), where the encoding is 0.6 V + 12.5 mV x code.
223 if ((sw_index != 1U && sw_index != 2U) || !sw_dvs_enabled_[sw_index - 1U]) {
224 setError(Error::InvalidParam);
225 return false;
226 }
227 const uint8_t code = SwDvsMillivoltsToCode(mv);
228 if (code == 0xFFU) {
229 setError(Error::InvalidParam);
230 return false;
231 }
232 const Register volt_reg = sw_index == 1U ? Register::Sw1Volt : Register::Sw2Volt;
233 return writeReg8(static_cast<uint8_t>(volt_reg), code);
234}
235
236template <typename BusType>
237bool PF1550<BusType>::SetLdoVoltage(uint8_t ldo_index, LdoVoltageCode code) noexcept {
238 Register volt_reg = Register::Ldo1Volt;
239 switch (ldo_index) {
240 case 1:
241 volt_reg = Register::Ldo1Volt;
242 break;
243 case 2:
244 volt_reg = Register::Ldo2Volt;
245 break;
246 case 3:
247 volt_reg = Register::Ldo3Volt;
248 break;
249 default:
250 setError(Error::InvalidParam);
251 return false;
252 }
253 return writeReg8(static_cast<uint8_t>(volt_reg), static_cast<uint8_t>(code));
254}
255
256template <typename BusType>
257bool PF1550<BusType>::SetVbusCurrentLimitMa(uint16_t limit_ma) noexcept {
258 const uint8_t value = VbusLimitMilliampsToReg(limit_ma);
259 if (value == 0xFFU) {
260 setError(Error::InvalidParam);
261 return false;
262 }
263 return writeReg8(static_cast<uint8_t>(Register::VbusInCurrentLimit), value);
264}
265
266// ---------------------------------------------------------------------------
267// Interrupt management
268// ---------------------------------------------------------------------------
269
270template <typename BusType>
271bool PF1550<BusType>::ReadInterruptCategory(uint8_t& category) noexcept {
272 return readReg8(static_cast<uint8_t>(Register::IntCategory), category);
273}
274
275template <typename BusType>
277 faults = FaultFlags{};
278 uint8_t sw0 = 0, sw1 = 0, ldo0 = 0, temp0 = 0, misc0 = 0, chg = 0, vbus = 0;
279 bool any_fail = false;
280
281 any_fail |= !readReg8(static_cast<uint8_t>(Register::SwIntStat0), sw0);
282 any_fail |= !readReg8(static_cast<uint8_t>(Register::SwIntStat1), sw1);
283 any_fail |= !readReg8(static_cast<uint8_t>(Register::LdoIntStat0), ldo0);
284 any_fail |= !readReg8(static_cast<uint8_t>(Register::TempIntStat0), temp0);
285 any_fail |= !readReg8(static_cast<uint8_t>(Register::MiscIntStat0), misc0);
286 any_fail |= !readReg8(static_cast<uint8_t>(Register::ChgInt), chg);
287 any_fail |= !readReg8(static_cast<uint8_t>(Register::VbusSns), vbus);
288
289 if (sw0 & SwIntStat0Bits::kSw1Ls) faults.Set(FaultFlags::kSw1Ls);
290 if (sw0 & SwIntStat0Bits::kSw2Ls) faults.Set(FaultFlags::kSw2Ls);
291 if (sw0 & SwIntStat0Bits::kSw3Ls) faults.Set(FaultFlags::kSw3Ls);
292 if (sw1 & SwIntStat1Bits::kSw1Hs) faults.Set(FaultFlags::kSw1Hs);
293 if (sw1 & SwIntStat1Bits::kSw2Hs) faults.Set(FaultFlags::kSw2Hs);
294 if (sw1 & SwIntStat1Bits::kSw3Hs) faults.Set(FaultFlags::kSw3Hs);
298 if (temp0 & TempIntStat0Bits::kTherm110) faults.Set(FaultFlags::kTempWarn);
299 if (temp0 & TempIntStat0Bits::kTherm125) faults.Set(FaultFlags::kTempShdn);
300 if (misc0 & MiscIntStat0Bits::kPwrOn) faults.Set(FaultFlags::kPwrOn);
302 if (misc0 & MiscIntStat0Bits::kSysOvlo) faults.Set(FaultFlags::kVsysOv);
303 // PWRUP_I / PWRDN_I report finished mode transitions, not faults: read MISC_INT_STAT0 for them.
304 if (chg != 0) faults.Set(FaultFlags::kChgFault);
305 // VBUS_VALID is bit 5 of VBUS_SNS — invalid means !bit5.
306 if ((vbus & (1u << 5)) == 0) faults.Set(FaultFlags::kVbusInval);
307
308 if (any_fail) {
309 faults.Set(FaultFlags::kI2cReadFail);
310 setError(Error::DiagnosticRead);
311 return false;
312 }
313 return true;
314}
315
316template <typename BusType>
318 const uint8_t kClearAll = 0xFFU;
319 bool ok = true;
320 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntStat0), kClearAll);
321 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntStat1), kClearAll);
322 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntStat2), kClearAll);
323 ok &= writeReg8(static_cast<uint8_t>(Register::LdoIntStat0), kClearAll);
324 ok &= writeReg8(static_cast<uint8_t>(Register::TempIntStat0), kClearAll);
325 ok &= writeReg8(static_cast<uint8_t>(Register::OnKeyIntStat0), kClearAll);
326 ok &= writeReg8(static_cast<uint8_t>(Register::MiscIntStat0), kClearAll);
327 ok &= writeReg8(static_cast<uint8_t>(Register::ChgInt), kClearAll);
328 return ok;
329}
330
331template <typename BusType>
332bool PF1550<BusType>::SetInterruptMaskAll(bool masked) noexcept {
333 const uint8_t mask_value = masked ? 0xFFU : 0x00U;
334 bool ok = true;
335 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntMask0), mask_value);
336 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntMask1), mask_value);
337 ok &= writeReg8(static_cast<uint8_t>(Register::SwIntMask2), mask_value);
338 ok &= writeReg8(static_cast<uint8_t>(Register::LdoIntMask0), mask_value);
339 ok &= writeReg8(static_cast<uint8_t>(Register::TempIntMask0), mask_value);
340 ok &= writeReg8(static_cast<uint8_t>(Register::OnKeyIntMask0), mask_value);
341 ok &= writeReg8(static_cast<uint8_t>(Register::MiscIntMask0), mask_value);
342 ok &= writeReg8(static_cast<uint8_t>(Register::ChgIntMask), mask_value);
343 return ok;
344}
345
346// ---------------------------------------------------------------------------
347// Diagnostic snapshot + self-test
348// ---------------------------------------------------------------------------
349
350template <typename BusType>
352 struct RailMap {
353 RailId id;
354 Register volt_reg;
355 Register ctrl_reg;
356 bool is_ldo2; // true → LDO2 group B encoding
357 bool is_sw;
358 };
359 static constexpr RailMap kMap[] = {
366 };
367 bool ok = true;
368 for (const auto& m : kMap) {
369 auto& d = snap.rails[static_cast<size_t>(m.id)];
370 if (!readReg8(static_cast<uint8_t>(m.volt_reg), d.volt_reg)) { ok = false; continue; }
371 if (!readReg8(static_cast<uint8_t>(m.ctrl_reg), d.ctrl_reg)) { ok = false; continue; }
372 if (m.id == RailId::Sw3) {
373 d.set_voltage_mv = Sw3CodeToMillivolts(d.volt_reg); /* Table 37 */
374 } else if (m.is_sw) {
375 const bool dvs = sw_dvs_enabled_[m.id == RailId::Sw1 ? 0U : 1U];
376 d.set_voltage_mv = dvs ? SwDvsCodeToMillivolts(d.volt_reg) : SwCodeToMillivolts(d.volt_reg);
377 } else {
378 d.set_voltage_mv = LdoCodeToMillivolts(d.volt_reg & 0x1FU, m.is_ldo2);
379 }
380 d.enabled_run = (d.ctrl_reg & SwCtrlBits::kEn) != 0;
381 d.enabled_stby = (d.ctrl_reg & SwCtrlBits::kStbyEn) != 0;
382 }
383 // VSNVS: fixed 3.0 V, always on, no voltage or enable field (VSNVS_VOLT is unused, Table 127).
384 auto& vsnvs = snap.rails[static_cast<size_t>(RailId::Vsnvs)];
385 if (readReg8(static_cast<uint8_t>(Register::VsnvsCtrl), vsnvs.ctrl_reg)) {
386 vsnvs.set_voltage_mv = kVsnvsMillivolts;
387 vsnvs.enabled_run = true;
388 vsnvs.enabled_stby = true;
389 } else {
390 ok = false;
391 }
392 return ok;
393}
394
395template <typename BusType>
396bool PF1550<BusType>::fillFaultSnapshot(DiagnosticSnapshot& snap) noexcept {
397 if (!ReadLatchedFaults(snap.faults)) {
398 return false;
399 }
400 // Per-rail latched + live mapping.
401 uint8_t sw_sense0 = 0, sw_sense1 = 0, ldo_sense = 0;
402 (void)readReg8(static_cast<uint8_t>(Register::SwIntSense0), sw_sense0);
403 (void)readReg8(static_cast<uint8_t>(Register::SwIntSense1), sw_sense1);
404 (void)readReg8(static_cast<uint8_t>(Register::LdoIntSense0), ldo_sense);
405
406 auto mark = [&](RailId id, bool latched, bool live) {
407 auto& d = snap.rails[static_cast<size_t>(id)];
408 d.stat_latched = latched;
409 d.sense_live = live;
410 };
411 mark(RailId::Sw1,
412 snap.faults.Has(FaultFlags::kSw1Ls | FaultFlags::kSw1Hs),
413 ((sw_sense0 & SwIntStat0Bits::kSw1Ls) || (sw_sense1 & SwIntStat1Bits::kSw1Hs)) != 0);
414 mark(RailId::Sw2,
415 snap.faults.Has(FaultFlags::kSw2Ls | FaultFlags::kSw2Hs),
416 ((sw_sense0 & SwIntStat0Bits::kSw2Ls) || (sw_sense1 & SwIntStat1Bits::kSw2Hs)) != 0);
417 mark(RailId::Sw3,
418 snap.faults.Has(FaultFlags::kSw3Ls | FaultFlags::kSw3Hs),
419 ((sw_sense0 & SwIntStat0Bits::kSw3Ls) || (sw_sense1 & SwIntStat1Bits::kSw3Hs)) != 0);
420 mark(RailId::Ldo1, snap.faults.Has(FaultFlags::kLdo1Fault),
421 (ldo_sense & LdoIntStat0Bits::kLdo1Fault) != 0);
422 mark(RailId::Ldo2, snap.faults.Has(FaultFlags::kLdo2Fault),
423 (ldo_sense & LdoIntStat0Bits::kLdo2Fault) != 0);
424 mark(RailId::Ldo3, snap.faults.Has(FaultFlags::kLdo3Fault),
425 (ldo_sense & LdoIntStat0Bits::kLdo3Fault) != 0);
426 return true;
427}
428
429template <typename BusType>
431 out = DiagnosticSnapshot{};
432 bool ok = true;
433 ok &= readReg8(static_cast<uint8_t>(Register::DeviceId), out.device_id);
434 ok &= readReg8(static_cast<uint8_t>(Register::OtpFlavor), out.otp_flavor);
435 ok &= readReg8(static_cast<uint8_t>(Register::SiliconRev), out.silicon_rev);
436 ok &= readReg8(static_cast<uint8_t>(Register::IntCategory), out.int_category);
437 ok &= readReg8(static_cast<uint8_t>(Register::StateInfo), out.state_info_reg);
438 out.state = DecodeStateInfo(out.state_info_reg);
439
440 uint8_t chg_raw = 0;
441 if (readReg8(static_cast<uint8_t>(Register::ChgSense), chg_raw)) {
442 out.chg_sense_reg = chg_raw;
443 out.charger = DecodeChargerSense(chg_raw);
444 } else {
445 ok = false;
446 }
447 ok &= readReg8(static_cast<uint8_t>(Register::VbusSns), out.vbus_sns_reg);
448
449 uint8_t vbus_lim_reg = 0;
450 if (readReg8(static_cast<uint8_t>(Register::VbusInCurrentLimit), vbus_lim_reg)) {
451 out.vbus_in_limit_ma = VbusLimitRegToMilliamps(vbus_lim_reg);
452 }
453
454 ok &= fillRailSnapshot(out);
455 ok &= fillFaultSnapshot(out);
456
457 out.read_ok = ok;
458 if (!ok) {
459 setError(Error::DiagnosticRead);
460 }
461 return ok;
462}
463
464template <typename BusType>
466 bool ok = true;
467 ok &= readReg8(static_cast<uint8_t>(Register::IntCategory), snap.int_category);
468 ok &= readReg8(static_cast<uint8_t>(Register::StateInfo), snap.state_info_reg);
469 snap.state = DecodeStateInfo(snap.state_info_reg);
470 uint8_t chg_raw = 0;
471 if (readReg8(static_cast<uint8_t>(Register::ChgSense), chg_raw)) {
472 snap.chg_sense_reg = chg_raw;
473 snap.charger = DecodeChargerSense(chg_raw);
474 } else {
475 ok = false;
476 }
477 ok &= readReg8(static_cast<uint8_t>(Register::VbusSns), snap.vbus_sns_reg);
478 ok &= fillFaultSnapshot(snap);
479 snap.read_ok = ok;
480 if (!ok) {
481 setError(Error::DiagnosticRead);
482 }
483 return ok;
484}
485
486template <typename BusType>
488 out = SelfTestResult{};
489 out.ran = true;
490
491 if (!ReadDiagnosticSnapshot(out.snapshot)) {
492 out.worst_severity = FaultSeverity::kMcuKill; // could not even read PMIC
493 setError(Error::SelfTestFailed);
494 return false;
495 }
496
497 out.device_id_ok = (out.snapshot.device_id == kExpectedDeviceId);
498 out.state_run = (out.snapshot.state == PmicState::Run);
499
500 out.all_rails_enabled = true;
501 for (size_t i = 0; i < static_cast<size_t>(RailId::COUNT); ++i) {
502 // Skip VSNVS (no `EN` bit in same place).
503 if (static_cast<RailId>(i) == RailId::Vsnvs) continue;
504 if (!out.snapshot.rails[i].enabled_run) {
505 out.all_rails_enabled = false;
506 break;
507 }
508 }
509
510 out.faults = out.snapshot.faults;
511 out.worst_severity = WorstSeverityPortentaH7(out.faults);
512
513 auto sev_val = [](FaultSeverity s) noexcept {
514 return static_cast<uint8_t>(s);
515 };
516 auto raise = [&](FaultSeverity target) noexcept {
517 if (sev_val(out.worst_severity) < sev_val(target)) {
518 out.worst_severity = target;
519 }
520 };
521
522 if (!out.device_id_ok) raise(FaultSeverity::kMcuKill);
523 if (!out.state_run) raise(FaultSeverity::kCritical);
524 if (!out.all_rails_enabled) raise(FaultSeverity::kCritical);
525
526 if (out.worst_severity != FaultSeverity::kInfo) {
527 setError(Error::SelfTestFailed);
528 }
529 return out.worst_severity == FaultSeverity::kInfo;
530}
531
532} // namespace pf1550
CRTP-based PF1550 PMIC driver.
Definition pf1550.hpp:62
bool SetPowerMode(PowerMode mode) noexcept
Drive the STANDBY strap pin to RUN or STANDBY.
Definition pf1550.ipp:120
bool ReadOtpByte(uint8_t otp_addr, uint8_t &value) noexcept
Read a single OTP byte via FMRADDR/FMRDATA indirection.
Definition pf1550.ipp:181
bool ReadDeviceId(uint8_t &id) noexcept
Read DEVICE_ID (Reg 0x00).
Definition pf1550.ipp:59
bool ReadRegister(Register reg, uint8_t &value) noexcept
Read any PF1550 register by enumerated address.
Definition pf1550.ipp:81
bool ReadPmicStatus(uint8_t &status) noexcept
Read STATE_INFO (Reg 0x67) and return the raw byte.
Definition pf1550.ipp:151
bool RefreshStatusSnapshot(DiagnosticSnapshot &snap) noexcept
Refresh only the status part of a snapshot (≈14 register reads).
Definition pf1550.ipp:465
bool ReadPmicState(PmicState &state) noexcept
Decoded variant of ReadPmicStatus.
Definition pf1550.ipp:156
bool ClearLatchedFaults() noexcept
Write 0xFF to every category STAT register to clear all RW1C bits.
Definition pf1550.ipp:317
bool ReadLatchedFaults(FaultFlags &faults) noexcept
Read every category STAT register and aggregate latched faults.
Definition pf1550.ipp:276
bool ApplyPortentaH7CarrierProfile() noexcept
Apply the Portenta-H7-on-carrier profile.
Definition pf1550.ipp:115
bool ReadChargerState(ChargerState &state, uint8_t *raw_reg=nullptr) noexcept
Read CHG_SNS (Reg 0x87) — charger sub-state. Returns decoded enum.
Definition pf1550.ipp:167
bool ReadDiagnosticSnapshot(DiagnosticSnapshot &out) noexcept
Build a full diagnostic snapshot (≈30 register reads).
Definition pf1550.ipp:430
bool SetSwVoltageMv(uint8_t sw_index, uint16_t mv) noexcept
Set the RUN voltage of a DVS-enabled SW1 or SW2 in millivolts.
Definition pf1550.ipp:220
bool WriteRegister(Register reg, uint8_t value) noexcept
Write any PF1550 register by enumerated address.
Definition pf1550.ipp:86
bool ApplyPortentaH7DefaultProfile() noexcept
Apply the legacy VFR-heritage Portenta H7 default profile.
Definition pf1550.ipp:110
bool ReadInterruptCategory(uint8_t &category) noexcept
Read INT_CATEGORY (Reg 0x06).
Definition pf1550.ipp:271
PF1550(BusType *bus, uint8_t address=kDefaultI2cAddress) noexcept
Construct a driver instance bound to a CRTP bus adapter.
Definition pf1550.ipp:11
bool RunPowerSelfTest(SelfTestResult &out) noexcept
Boot-time self-test.
Definition pf1550.ipp:487
bool SetSwVoltage(uint8_t sw_index, SwVoltageCode run_code) noexcept
Set the RUN voltage of SW1 or SW2 from a SwVoltageCode.
Definition pf1550.ipp:215
bool VerifyDevice() noexcept
Read DEVICE_ID and assert it matches kExpectedDeviceId.
Definition pf1550.ipp:67
bool SetLdoVoltage(uint8_t ldo_index, LdoVoltageCode code) noexcept
Write LDOn_VOLT for n=1..3. Returns false if ldo_index is invalid.
Definition pf1550.ipp:237
bool EnsureInitialized() noexcept
Idempotently initialise the bus and verify the device.
Definition pf1550.ipp:42
bool SetVbusCurrentLimitMa(uint16_t limit_ma) noexcept
Convenience: write VBUS_IN_LIM_CNFG (0x94) from a mA value.
Definition pf1550.ipp:257
bool ApplyProfile(std::span< const profiles::RegisterWrite > profile) noexcept
Apply an arbitrary profile (sequence of register writes).
Definition pf1550.ipp:91
bool ReadOtpRegion(uint8_t *buffer, size_t len, uint8_t start=OtpRegion::kStart) noexcept
Read a contiguous region of OTP memory (default: full 0x1C..0x36 range).
Definition pf1550.ipp:196
bool SetInterruptMaskAll(bool masked) noexcept
Mask (1) or unmask (0) all interrupt categories at once.
Definition pf1550.ipp:332
bool SetUsbRails(bool vbus_en, bool otg_en) noexcept
Drive USB_VBUS_EN and USB_OTG_EN straps (HIGH = enabled on Portenta).
Definition pf1550.ipp:140
constexpr std::array< RegisterWrite, 14 > kPortentaH7Default
Portenta H7 eval MCU-domain profile (VFR heritage).
Definition pf1550_profiles.hpp:39
constexpr std::array< RegisterWrite, 14 > kPortentaH7Carrier
Portenta H7 + carrier bring-up profile (SW1-first, full SW2 enable).
Definition pf1550_profiles.hpp:73
Definition pf1550.hpp:40
Register
Symbolic register addresses used by the PF1550 driver.
Definition pf1550_registers.hpp:51
@ ChgSense
CHG_SNS — Table 154. Charger mode (precharge, fast-cc, fast-cv, eoc …).
@ SwIntStat1
SW_INT_STAT1 — high-side current limits.
@ Ldo3Volt
LDO3_VOLT.
@ Sw3Ctrl
SW3_CTRL.
@ OnKeyIntMask0
ONKEY_INT_MASK0.
@ LdoIntStat0
LDO_INT_STAT0 — Table 99. LDO1/2/3 current-limit faults.
@ MiscIntStat0
MISC_INT_STAT0 — Table 108. PWRON / VSYS / RESETBMCU events.
@ SwIntStat2
SW_INT_STAT2 — DVS done.
@ Ldo2Volt
LDO2_VOLT.
@ SwIntSense0
SW_INT_SENSE0.
@ FmrData
FRMDATA — OTP indirect data.
@ Ldo1Ctrl
LDO1_CTRL.
@ LdoIntMask0
LDO_INT_MASK0.
@ Ldo1Volt
LDO1_VOLT.
@ Sw2Volt
SW2_VOLT — Table 117.
@ FmrAddr
FMRADDR — OTP indirect address.
@ SwIntStat0
SW_INT_STAT0 — low-side current limits (SW1/2/3).
@ TempIntMask0
TEMP_INT_MASK0.
@ StateInfo
STATE_INFO — Table 146. STATE[5:0] = Wait/RUN/STANDBY/SLEEP/REGS_DISABLE.
@ LdoIntSense0
LDO_INT_SENSE0.
@ Sw2Ctrl
SW2_CTRL — Table 120.
@ Sw3Volt
SW3_VOLT — Table 122.
@ ChgIntMask
CHG_INT_MASK.
@ SwIntMask2
SW_INT_MASK2.
@ OtpFlavor
OTP_FLAVOR — Table 87. 0x00 = OTP not burned (A0EP).
@ ChgInt
CHG_INT — Table 150. SUP_I/BAT2SOC_I/CHGREV_I/CHG_I.
@ Sw1Ctrl
SW1_CTRL — EN/STBY_EN/OMODE/LPWR/DVSSPEED/FPWM/RDIS_ENB.
@ SwIntMask0
SW_INT_MASK0.
@ Ldo3Ctrl
LDO3_CTRL.
@ SwIntSense1
SW_INT_SENSE1.
@ IntCategory
INT_CATEGORY — Table 89. CHG/SW1/SW2/SW3/LDO/ONKEY/TEMP/MISC summary.
@ Sw1Volt
SW1_VOLT — RUN-mode voltage code (Table 31).
@ SiliconRev
SILICON_REV — Table 88. Metal/full-layer/fab-fin identifiers.
@ DeviceId
DEVICE_ID — Table 86. Bits[2:0] = family, [7:3] = 01111 for PF1550.
@ Ldo2Ctrl
LDO2_CTRL — must be written last in Portenta profile.
@ OnKeyIntStat0
ONKEY_INT_STAT0 — Table 105. Push / 1s/2s/3s/4s/8s long-press.
@ VbusSns
VBUS_SNS — Table 153. VBUS_VALID, DPM_SNS, OVLO, UVLO.
@ VsnvsCtrl
VSNVS_CTRL — Table 127. RTC/SNVS backup LDO control.
@ TempIntStat0
TEMP_INT_STAT0 — Table 102. Junction-temperature events.
@ VbusInCurrentLimit
VBUS input current limit ((mA/50) << 3 — Portenta uses 1500 mA → 0xA0).
@ MiscIntMask0
MISC_INT_MASK0.
@ SwIntMask1
SW_INT_MASK1.
RailId
Logical identifier for each independently-controllable PF1550 output.
Definition pf1550_diagnostics.hpp:43
@ Ldo3
LDO3 — Portenta +1V2 (STM32 DSI, ETH PHY).
@ Sw2
SW2 / BUCK2 — Portenta +3V3 / carrier VOUT.
@ Sw3
SW3 / BUCK3 — Portenta +3V1 VCORE (MCU + QSPI).
@ Ldo2
LDO2 — Portenta +1V8 (USB PHY, MIPI).
@ Sw1
SW1 / BUCK1 — Portenta +3V1SW (feeds LDO inputs).
@ Vsnvs
VSNVS — RTC / backup LDO (≤2 mA).
@ Ldo1
LDO1 — Portenta +1V0 (MIPI bridge analog).
LdoVoltageCode
Common LDO output voltage codes used on Portenta H7 (Table 41).
Definition pf1550_registers.hpp:274
constexpr uint8_t SwDvsMillivoltsToCode(uint16_t mv) noexcept
Encode a DVS-enabled SW1 / SW2 voltage (Table 31, left column).
Definition pf1550_voltage_tables.hpp:69
constexpr ChargerState DecodeChargerSense(uint8_t reg) noexcept
Convert CHG_SNS (0x87) into a typed ChargerState.
Definition pf1550_voltage_tables.hpp:236
constexpr uint16_t VbusLimitRegToMilliamps(uint8_t reg_value) noexcept
Decode VBUS_IN_LIM_CNFG (absolute address 0x94) register byte to mA.
Definition pf1550_voltage_tables.hpp:158
constexpr uint16_t SwCodeToMillivolts(uint8_t code) noexcept
SW1 / SW2 output voltage, DVS disabled (OTP_SWx_DVS_SEL = 1).
Definition pf1550_voltage_tables.hpp:47
constexpr uint16_t LdoCodeToMillivolts(uint8_t code, bool is_ldo2) noexcept
Decode a 5-bit LDO voltage register field to millivolts.
Definition pf1550_voltage_tables.hpp:118
FaultSeverity
Severity classification for a fault.
Definition pf1550_diagnostics.hpp:65
constexpr uint8_t kExpectedDeviceId
Expected DEVICE_ID[2:0] family identifier (PF1550 family = 100b).
Definition pf1550_registers.hpp:35
constexpr uint16_t SwDvsCodeToMillivolts(uint8_t code) noexcept
SW1 / SW2 output voltage, DVS enabled (OTP_SWx_DVS_SEL = 0): 0.6000 V + 12.5 mV × code (Table 31,...
Definition pf1550_voltage_tables.hpp:57
constexpr uint16_t Sw3CodeToMillivolts(uint8_t code) noexcept
SW3 output voltage (Table 37): 1.80 V + 100 mV × SW3_VOLT[3:0].
Definition pf1550_voltage_tables.hpp:82
PmicState
STATE_INFO[5:0] values (Reg 0x67) describing the PMIC state machine.
Definition pf1550_registers.hpp:226
@ Run
RUN — all OTP-sequenced regulators enabled.
constexpr uint16_t kVsnvsMillivolts
VSNVS output voltage: fixed 3.0 V (VSNVS_CTRL has no voltage field, Table 127).
Definition pf1550_registers.hpp:38
ChargerState
CHG_SNS[3:0] values (Reg 0x87) describing the charger sub-state.
Definition pf1550_registers.hpp:236
constexpr uint8_t VbusLimitMilliampsToReg(uint16_t mA) noexcept
Encode mA → VBUS_IN_LIM_CNFG (0x94) register byte (bits 7:3).
Definition pf1550_voltage_tables.hpp:188
SwVoltageCode
Common SW buck output voltage codes (RUN mode).
Definition pf1550_registers.hpp:265
constexpr FaultSeverity WorstSeverityPortentaH7(FaultFlags fl) noexcept
Return the worst-case severity across an aggregated bitmask.
Definition pf1550_diagnostics.hpp:240
constexpr PmicState DecodeStateInfo(uint8_t reg) noexcept
Convert STATE_INFO (0x67) full byte into a typed PmicState.
Definition pf1550_voltage_tables.hpp:224
PowerMode
Definition pf1550_i2c_interface.hpp:35
Full diagnostic snapshot returned by PF1550::ReadDiagnosticSnapshot().
Definition pf1550_diagnostics.hpp:140
Bitset of latched fault flags.
Definition pf1550_diagnostics.hpp:79
static constexpr uint32_t kTempShdn
THERM125I: die crossed 125 °C.
Definition pf1550_diagnostics.hpp:97
static constexpr uint32_t kLdo3Fault
Definition pf1550_diagnostics.hpp:93
static constexpr uint32_t kSw1Ls
Definition pf1550_diagnostics.hpp:83
static constexpr uint32_t kVbusInval
Definition pf1550_diagnostics.hpp:108
static constexpr uint32_t kSw3Ls
Definition pf1550_diagnostics.hpp:87
static constexpr uint32_t kVsysLow
LOW_SYS_WARN_I: VSYS crossed LOW_SYS_WARN.
Definition pf1550_diagnostics.hpp:101
static constexpr uint32_t kChgFault
Definition pf1550_diagnostics.hpp:107
static constexpr uint32_t kTempWarn
THERM110I: die crossed 110 °C.
Definition pf1550_diagnostics.hpp:96
static constexpr uint32_t kLdo1Fault
Definition pf1550_diagnostics.hpp:91
static constexpr uint32_t kLdo2Fault
Definition pf1550_diagnostics.hpp:92
static constexpr uint32_t kSw2Hs
Definition pf1550_diagnostics.hpp:86
static constexpr uint32_t kPwrOn
PWRON_I: power-on button event.
Definition pf1550_diagnostics.hpp:100
static constexpr uint32_t kSw1Hs
Definition pf1550_diagnostics.hpp:84
static constexpr uint32_t kI2cReadFail
Definition pf1550_diagnostics.hpp:112
static constexpr uint32_t kVsysOv
SYS_OVLO_I: VSYS crossed SYS_OVLO.
Definition pf1550_diagnostics.hpp:102
static constexpr uint32_t kSw3Hs
Definition pf1550_diagnostics.hpp:88
static constexpr uint32_t kSw2Ls
Definition pf1550_diagnostics.hpp:85
static constexpr uint8_t kLdo3Fault
LDO3 fault.
Definition pf1550_registers.hpp:199
static constexpr uint8_t kLdo2Fault
LDO2 fault.
Definition pf1550_registers.hpp:198
static constexpr uint8_t kLdo1Fault
LDO1 fault.
Definition pf1550_registers.hpp:197
static constexpr uint8_t kLowSysWarn
LOW_SYS_WARN_I — VSYS crossed the LOW_SYS_WARN threshold.
Definition pf1550_registers.hpp:215
static constexpr uint8_t kSysOvlo
SYS_OVLO_I — VSYS crossed the SYS_OVLO threshold.
Definition pf1550_registers.hpp:216
static constexpr uint8_t kPwrOn
PWRON_I — power-on button event.
Definition pf1550_registers.hpp:214
static constexpr uint8_t kEndExclusive
One past the last OTP byte address.
Definition pf1550_registers.hpp:327
static constexpr uint8_t kKey3Val
Definition pf1550_registers.hpp:321
static constexpr uint8_t kKey2Reg
Definition pf1550_registers.hpp:318
static constexpr uint8_t kKey1Val
Definition pf1550_registers.hpp:317
static constexpr uint8_t kKey1Reg
Definition pf1550_registers.hpp:316
static constexpr uint8_t kKey3Reg
Definition pf1550_registers.hpp:320
static constexpr uint8_t kKey2Val
Definition pf1550_registers.hpp:319
Result of a power self-test pass.
Definition pf1550_diagnostics.hpp:162
bool ran
Definition pf1550_diagnostics.hpp:163
static constexpr uint8_t kStbyEn
SW_STBY_EN — enable in STANDBY.
Definition pf1550_registers.hpp:294
static constexpr uint8_t kEn
SW_EN — enable in RUN.
Definition pf1550_registers.hpp:293
static constexpr uint8_t kSw3Ls
SW3_LS_I — SW3 low-side current limit.
Definition pf1550_registers.hpp:184
static constexpr uint8_t kSw2Ls
SW2_LS_I — SW2 low-side current limit.
Definition pf1550_registers.hpp:183
static constexpr uint8_t kSw1Ls
SW1_LS_I — SW1 low-side current limit (Table 90).
Definition pf1550_registers.hpp:182
static constexpr uint8_t kSw2Hs
SW2_HS_I — SW2 high-side current limit.
Definition pf1550_registers.hpp:191
static constexpr uint8_t kSw1Hs
SW1_HS_I — SW1 high-side current limit.
Definition pf1550_registers.hpp:190
static constexpr uint8_t kSw3Hs
SW3_HS_I — SW3 high-side current limit.
Definition pf1550_registers.hpp:192
static constexpr uint8_t kTherm110
THERM110I — die temperature crossed 110 °C (either way).
Definition pf1550_registers.hpp:204
static constexpr uint8_t kTherm125
THERM125I — die temperature crossed 125 °C (either way).
Definition pf1550_registers.hpp:205