pamoja_sensors/ina226.rs
1//! Texas Instruments INA226 high-side or low-side current, voltage, and power monitor.
2//!
3//! The INA226 measures the voltage across a shunt resistor and the bus voltage on
4//! common-mode voltages from 0 V to 36 V and, once its calibration register is
5//! programmed, computes current and power on the chip. It adds programmable
6//! conversion times and averaging, and an alert pin driven by a single limit
7//! register. This module builds the calibration and configuration values and decodes
8//! each register into a physical quantity, following the datasheet's equations and
9//! its worked example, so a battery-balancer or rack-power node reads amps and watts
10//! directly.
11//!
12//! Shunt voltages are returned in nanovolts, bus voltages in microvolts, and current
13//! and power in microamps and microwatts, so the 2.5 µV and 1.25 mV register LSBs
14//! convert exactly without floating point. `f32` conveniences sit beside them.
15
16use crate::SensorError;
17
18#[cfg(feature = "embedded-hal")]
19mod driver;
20#[cfg(feature = "embedded-hal")]
21pub mod sim;
22
23#[cfg(feature = "embedded-hal")]
24pub use driver::{Ina226, STATUS_POLLS};
25
26/// The INA226 register pointer addresses.
27pub mod register {
28 /// Configuration register: reset, averaging, conversion times, and operating mode.
29 pub const CONFIGURATION: u8 = 0x00;
30 /// Shunt voltage register, signed, 2.5 µV per count.
31 pub const SHUNT_VOLTAGE: u8 = 0x01;
32 /// Bus voltage register, positive only, 1.25 mV per count.
33 pub const BUS_VOLTAGE: u8 = 0x02;
34 /// Power register, scaled by the calibration register.
35 pub const POWER: u8 = 0x03;
36 /// Current register, signed, scaled by the calibration register.
37 pub const CURRENT: u8 = 0x04;
38 /// Calibration register, sets the current and power scale.
39 pub const CALIBRATION: u8 = 0x05;
40 /// Mask/Enable register: alert function selection and status flags.
41 pub const MASK_ENABLE: u8 = 0x06;
42 /// Alert limit register, compared against the selected alert function.
43 pub const ALERT_LIMIT: u8 = 0x07;
44 /// Manufacturer ID register, reads [`MANUFACTURER_ID`](super::MANUFACTURER_ID).
45 pub const MANUFACTURER_ID: u8 = 0xFE;
46 /// Die ID register: the device ID in bits 15:4 and the die revision in bits 3:0.
47 pub const DIE_ID: u8 = 0xFF;
48}
49
50/// The value the manufacturer ID register always reads (0x5449, "TI").
51pub const MANUFACTURER_ID: u16 = 0x5449;
52
53/// The 12-bit device ID carried in bits 15:4 of the die ID register.
54pub const DEVICE_ID: u16 = 0x226;
55
56/// The power-on value of the configuration register (0x4127): averaging off, 1.1 ms
57/// conversion time for both bus and shunt, and continuous shunt-and-bus conversion.
58pub const CONFIG_RESET: u16 = 0x4127;
59
60/// The shunt voltage register LSB, 2.5 µV, in nanovolts.
61pub const SHUNT_LSB_NANOVOLTS: i32 = 2_500;
62
63/// The bus voltage register LSB, 1.25 mV, in microvolts.
64pub const BUS_LSB_MICROVOLTS: u32 = 1_250;
65
66/// The fixed ratio between the power LSB and the programmed current LSB.
67pub const POWER_LSB_RATIO: u32 = 25;
68
69/// The base I2C address, selected when both address pins are tied to ground.
70pub const BASE_ADDRESS: u8 = 0x40;
71
72/// What an address pin is tied to; each of A1 and A0 takes one of four levels.
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74#[repr(u8)]
75pub enum AddressPin {
76 /// Tied to GND.
77 Ground = 0,
78 /// Tied to VS.
79 Supply = 1,
80 /// Tied to SDA.
81 Sda = 2,
82 /// Tied to SCL.
83 Scl = 3,
84}
85
86/// Returns the 7-bit I2C address selected by the A1 and A0 pins.
87///
88/// The address is `1 0 0 A1 A0` where each pin contributes two bits in the order
89/// GND, VS, SDA, SCL, giving the sixteen addresses 0x40 through 0x4F.
90///
91/// # Arguments
92///
93/// * `a1` - what the A1 pin is tied to.
94/// * `a0` - what the A0 pin is tied to.
95///
96/// # Returns
97///
98/// The 7-bit target address, before the read/write bit is appended.
99pub fn address(a1: AddressPin, a0: AddressPin) -> u8 {
100 BASE_ADDRESS | ((a1 as u8) << 2) | a0 as u8
101}
102
103/// The number of samples the ADC averages before updating the result registers.
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
105#[repr(u8)]
106pub enum Averaging {
107 /// No averaging, every conversion is reported.
108 Samples1 = 0,
109 /// Average of 4 samples.
110 Samples4 = 1,
111 /// Average of 16 samples.
112 Samples16 = 2,
113 /// Average of 64 samples.
114 Samples64 = 3,
115 /// Average of 128 samples.
116 Samples128 = 4,
117 /// Average of 256 samples.
118 Samples256 = 5,
119 /// Average of 512 samples.
120 Samples512 = 6,
121 /// Average of 1024 samples.
122 Samples1024 = 7,
123}
124
125impl Averaging {
126 fn from_bits(bits: u16) -> Self {
127 match bits & 0x07 {
128 0 => Self::Samples1,
129 1 => Self::Samples4,
130 2 => Self::Samples16,
131 3 => Self::Samples64,
132 4 => Self::Samples128,
133 5 => Self::Samples256,
134 6 => Self::Samples512,
135 _ => Self::Samples1024,
136 }
137 }
138
139 /// Returns the number of samples this setting averages.
140 ///
141 /// # Returns
142 ///
143 /// The sample count, from 1 to 1024.
144 pub fn samples(self) -> u16 {
145 match self {
146 Self::Samples1 => 1,
147 Self::Samples4 => 4,
148 Self::Samples16 => 16,
149 Self::Samples64 => 64,
150 Self::Samples128 => 128,
151 Self::Samples256 => 256,
152 Self::Samples512 => 512,
153 Self::Samples1024 => 1024,
154 }
155 }
156}
157
158/// The ADC conversion time for one shunt or bus voltage measurement.
159#[derive(Clone, Copy, Debug, PartialEq, Eq)]
160#[repr(u8)]
161pub enum ConversionTime {
162 /// 140 µs.
163 Us140 = 0,
164 /// 204 µs.
165 Us204 = 1,
166 /// 332 µs.
167 Us332 = 2,
168 /// 588 µs.
169 Us588 = 3,
170 /// 1.1 ms.
171 Us1100 = 4,
172 /// 2.116 ms.
173 Us2116 = 5,
174 /// 4.156 ms.
175 Us4156 = 6,
176 /// 8.244 ms.
177 Us8244 = 7,
178}
179
180impl ConversionTime {
181 fn from_bits(bits: u16) -> Self {
182 match bits & 0x07 {
183 0 => Self::Us140,
184 1 => Self::Us204,
185 2 => Self::Us332,
186 3 => Self::Us588,
187 4 => Self::Us1100,
188 5 => Self::Us2116,
189 6 => Self::Us4156,
190 _ => Self::Us8244,
191 }
192 }
193
194 /// Returns the typical conversion time this setting selects.
195 ///
196 /// # Returns
197 ///
198 /// The conversion time in microseconds.
199 pub fn microseconds(self) -> u32 {
200 match self {
201 Self::Us140 => 140,
202 Self::Us204 => 204,
203 Self::Us332 => 332,
204 Self::Us588 => 588,
205 Self::Us1100 => 1_100,
206 Self::Us2116 => 2_116,
207 Self::Us4156 => 4_156,
208 Self::Us8244 => 8_244,
209 }
210 }
211}
212
213/// The operating mode: which inputs are converted, and whether once or continuously.
214///
215/// Both `000` and `100` select power-down; this type reads either as
216/// [`Mode::PowerDown`] and writes it back as `000`.
217#[derive(Clone, Copy, Debug, PartialEq, Eq)]
218#[repr(u8)]
219pub enum Mode {
220 /// Power-down (shutdown); registers stay readable and writable.
221 PowerDown = 0,
222 /// One shunt voltage conversion, then idle.
223 ShuntTriggered = 1,
224 /// One bus voltage conversion, then idle.
225 BusTriggered = 2,
226 /// One shunt and one bus voltage conversion, then idle.
227 ShuntAndBusTriggered = 3,
228 /// Shunt voltage conversions back to back.
229 ShuntContinuous = 5,
230 /// Bus voltage conversions back to back.
231 BusContinuous = 6,
232 /// Shunt and bus voltage conversions back to back, the power-on mode.
233 ShuntAndBusContinuous = 7,
234}
235
236impl Mode {
237 fn from_bits(bits: u16) -> Self {
238 match bits & 0x07 {
239 1 => Self::ShuntTriggered,
240 2 => Self::BusTriggered,
241 3 => Self::ShuntAndBusTriggered,
242 5 => Self::ShuntContinuous,
243 6 => Self::BusContinuous,
244 7 => Self::ShuntAndBusContinuous,
245 _ => Self::PowerDown,
246 }
247 }
248
249 /// Returns whether this mode converts the shunt voltage.
250 ///
251 /// # Returns
252 ///
253 /// `true` for the shunt-only and shunt-and-bus modes.
254 pub fn measures_shunt(self) -> bool {
255 self as u8 & 0x01 != 0
256 }
257
258 /// Returns whether this mode converts the bus voltage.
259 ///
260 /// # Returns
261 ///
262 /// `true` for the bus-only and shunt-and-bus modes.
263 pub fn measures_bus(self) -> bool {
264 self as u8 & 0x02 != 0
265 }
266
267 /// Returns whether this mode keeps converting after the first result.
268 ///
269 /// # Returns
270 ///
271 /// `true` for the three continuous modes.
272 pub fn is_continuous(self) -> bool {
273 matches!(
274 self,
275 Self::ShuntContinuous | Self::BusContinuous | Self::ShuntAndBusContinuous
276 )
277 }
278}
279
280/// The configuration register (0x00), decoded into its fields.
281///
282/// Bit 14 is reserved and reads as `1` after reset; [`Configuration::to_register`]
283/// writes it that way so the reset value round-trips unchanged.
284#[derive(Clone, Copy, Debug, PartialEq, Eq)]
285pub struct Configuration {
286 /// Set to trigger a system reset equivalent to power-on; the bit self-clears.
287 pub reset: bool,
288 /// How many samples are averaged before the result registers update.
289 pub averaging: Averaging,
290 /// The conversion time for each bus voltage measurement.
291 pub bus_conversion_time: ConversionTime,
292 /// The conversion time for each shunt voltage measurement.
293 pub shunt_conversion_time: ConversionTime,
294 /// Which inputs are converted, and whether once or continuously.
295 pub mode: Mode,
296}
297
298impl Configuration {
299 /// The power-on configuration, the decoded form of [`CONFIG_RESET`].
300 pub const RESET: Self = Self {
301 reset: false,
302 averaging: Averaging::Samples1,
303 bus_conversion_time: ConversionTime::Us1100,
304 shunt_conversion_time: ConversionTime::Us1100,
305 mode: Mode::ShuntAndBusContinuous,
306 };
307
308 /// Decodes a configuration register value.
309 ///
310 /// # Arguments
311 ///
312 /// * `raw` - the 16-bit configuration register.
313 ///
314 /// # Returns
315 ///
316 /// The decoded fields; reserved bits are ignored.
317 pub fn from_register(raw: u16) -> Self {
318 Self {
319 reset: raw & 0x8000 != 0,
320 averaging: Averaging::from_bits(raw >> 9),
321 bus_conversion_time: ConversionTime::from_bits(raw >> 6),
322 shunt_conversion_time: ConversionTime::from_bits(raw >> 3),
323 mode: Mode::from_bits(raw),
324 }
325 }
326
327 /// Encodes the fields as a configuration register value.
328 ///
329 /// # Returns
330 ///
331 /// The 16-bit register to write, with reserved bit 14 set as at reset.
332 pub fn to_register(self) -> u16 {
333 (if self.reset { 0x8000 } else { 0 })
334 | 0x4000
335 | ((self.averaging as u16) << 9)
336 | ((self.bus_conversion_time as u16) << 6)
337 | ((self.shunt_conversion_time as u16) << 3)
338 | self.mode as u16
339 }
340
341 /// Returns how often the result registers update with these settings.
342 ///
343 /// One update takes the averaged sample count times the sum of the conversion
344 /// times of the inputs the mode measures, as the datasheet's timing examples
345 /// work it.
346 ///
347 /// # Returns
348 ///
349 /// The update interval in microseconds, or `0` in power-down.
350 pub fn update_microseconds(self) -> u32 {
351 let shunt = if self.mode.measures_shunt() {
352 self.shunt_conversion_time.microseconds()
353 } else {
354 0
355 };
356 let bus = if self.mode.measures_bus() {
357 self.bus_conversion_time.microseconds()
358 } else {
359 0
360 };
361 u32::from(self.averaging.samples()) * (shunt + bus)
362 }
363}
364
365impl Default for Configuration {
366 fn default() -> Self {
367 Self::RESET
368 }
369}
370
371/// The five limit comparisons the alert pin can be assigned to.
372#[derive(Clone, Copy, Debug, PartialEq, Eq)]
373pub enum AlertFunction {
374 /// Shunt voltage above the alert limit (SOL, bit 15).
375 ShuntOverLimit,
376 /// Shunt voltage below the alert limit (SUL, bit 14).
377 ShuntUnderLimit,
378 /// Bus voltage above the alert limit (BOL, bit 13).
379 BusOverLimit,
380 /// Bus voltage below the alert limit (BUL, bit 12).
381 BusUnderLimit,
382 /// Power above the alert limit (POL, bit 11).
383 PowerOverLimit,
384}
385
386/// The Mask/Enable register (0x06): which alert function drives the pin, how the
387/// pin behaves, and the status flags the chip reports back.
388///
389/// The alert limit register is compared in the units of the selected function, so
390/// build it with [`shunt_register`], [`bus_register`], or [`power_register`].
391#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
392pub struct MaskEnable {
393 /// Assert the alert pin when the shunt voltage exceeds the limit (SOL).
394 pub shunt_over_limit: bool,
395 /// Assert the alert pin when the shunt voltage drops below the limit (SUL).
396 pub shunt_under_limit: bool,
397 /// Assert the alert pin when the bus voltage exceeds the limit (BOL).
398 pub bus_over_limit: bool,
399 /// Assert the alert pin when the bus voltage drops below the limit (BUL).
400 pub bus_under_limit: bool,
401 /// Assert the alert pin when the power exceeds the limit (POL).
402 pub power_over_limit: bool,
403 /// Also assert the alert pin when a conversion completes (CNVR).
404 pub conversion_ready: bool,
405 /// Status: the selected alert function, not conversion-ready, caused the last
406 /// alert (AFF).
407 pub alert_function_flag: bool,
408 /// Status: all conversions, averaging, and multiplications are complete (CVRF).
409 pub conversion_ready_flag: bool,
410 /// Status: an arithmetic overflow occurred and current and power may be invalid
411 /// (OVF).
412 pub math_overflow: bool,
413 /// Alert pin polarity: `true` for inverted (active-high), `false` for the default
414 /// active-low (APOL).
415 pub alert_active_high: bool,
416 /// Latch the alert pin and flag until this register is read, rather than clearing
417 /// when the fault clears (LEN).
418 pub alert_latch: bool,
419}
420
421impl MaskEnable {
422 /// Decodes a Mask/Enable register value.
423 ///
424 /// # Arguments
425 ///
426 /// * `raw` - the 16-bit Mask/Enable register.
427 ///
428 /// # Returns
429 ///
430 /// The decoded enables and flags; reserved bits are ignored.
431 pub fn from_register(raw: u16) -> Self {
432 Self {
433 shunt_over_limit: raw & 0x8000 != 0,
434 shunt_under_limit: raw & 0x4000 != 0,
435 bus_over_limit: raw & 0x2000 != 0,
436 bus_under_limit: raw & 0x1000 != 0,
437 power_over_limit: raw & 0x0800 != 0,
438 conversion_ready: raw & 0x0400 != 0,
439 alert_function_flag: raw & 0x0010 != 0,
440 conversion_ready_flag: raw & 0x0008 != 0,
441 math_overflow: raw & 0x0004 != 0,
442 alert_active_high: raw & 0x0002 != 0,
443 alert_latch: raw & 0x0001 != 0,
444 }
445 }
446
447 /// Encodes the enables and flags as a Mask/Enable register value.
448 ///
449 /// # Returns
450 ///
451 /// The 16-bit register to write.
452 pub fn to_register(self) -> u16 {
453 let mut raw = 0;
454 for (set, bit) in [
455 (self.shunt_over_limit, 0x8000),
456 (self.shunt_under_limit, 0x4000),
457 (self.bus_over_limit, 0x2000),
458 (self.bus_under_limit, 0x1000),
459 (self.power_over_limit, 0x0800),
460 (self.conversion_ready, 0x0400),
461 (self.alert_function_flag, 0x0010),
462 (self.conversion_ready_flag, 0x0008),
463 (self.math_overflow, 0x0004),
464 (self.alert_active_high, 0x0002),
465 (self.alert_latch, 0x0001),
466 ] {
467 if set {
468 raw |= bit;
469 }
470 }
471 raw
472 }
473
474 /// Returns the alert function the pin actually responds to.
475 ///
476 /// Only one limit function can drive the pin at a time; when several are
477 /// enabled the chip honors the most significant bit.
478 ///
479 /// # Returns
480 ///
481 /// The highest-priority enabled function, or `None` if no limit function is
482 /// enabled.
483 pub fn active_alert_function(self) -> Option<AlertFunction> {
484 if self.shunt_over_limit {
485 Some(AlertFunction::ShuntOverLimit)
486 } else if self.shunt_under_limit {
487 Some(AlertFunction::ShuntUnderLimit)
488 } else if self.bus_over_limit {
489 Some(AlertFunction::BusOverLimit)
490 } else if self.bus_under_limit {
491 Some(AlertFunction::BusUnderLimit)
492 } else if self.power_over_limit {
493 Some(AlertFunction::PowerOverLimit)
494 } else {
495 None
496 }
497 }
498}
499
500/// The die ID register (0xFF), split into its device and revision fields.
501#[derive(Clone, Copy, Debug, PartialEq, Eq)]
502pub struct DieId {
503 /// The 12-bit device identifier, [`DEVICE_ID`] for an INA226.
504 pub device: u16,
505 /// The 4-bit die revision.
506 pub revision: u8,
507}
508
509impl DieId {
510 /// Splits a die ID register value into its fields.
511 ///
512 /// # Arguments
513 ///
514 /// * `raw` - the 16-bit die ID register.
515 ///
516 /// # Returns
517 ///
518 /// The device ID from bits 15:4 and the revision from bits 3:0.
519 pub fn from_register(raw: u16) -> Self {
520 Self {
521 device: raw >> 4,
522 revision: (raw & 0x0F) as u8,
523 }
524 }
525}
526
527/// Checks that the identification registers belong to an INA226.
528///
529/// A node reads both registers at start-up so a wrong part on the address, or a bus
530/// that reads all ones, is caught before its readings are trusted.
531///
532/// # Arguments
533///
534/// * `manufacturer_id` - the manufacturer ID register (0xFE).
535/// * `die_id` - the die ID register (0xFF).
536///
537/// # Returns
538///
539/// The decoded die ID when both registers match.
540///
541/// # Errors
542///
543/// [`SensorError::Identity`] if the manufacturer ID is not [`MANUFACTURER_ID`] or
544/// the device field of the die ID is not [`DEVICE_ID`].
545pub fn identify(manufacturer_id: u16, die_id: u16) -> Result<DieId, SensorError> {
546 let die = DieId::from_register(die_id);
547 if manufacturer_id != MANUFACTURER_ID || die.device != DEVICE_ID {
548 return Err(SensorError::Identity);
549 }
550 Ok(die)
551}
552
553/// Computes the calibration register value for a chosen current resolution and shunt.
554///
555/// This is the datasheet's calibration equation, `CAL = 0.00512 / (Current_LSB *
556/// R_SHUNT)`, expressed in integer micro-units: with the current LSB in microamps
557/// and the shunt in milliohms, the fixed `0.00512` becomes `5_120_000`.
558///
559/// # Arguments
560///
561/// * `current_lsb_microamps` - the amps-per-count the current register should carry.
562/// * `shunt_milliohms` - the shunt resistor value, in milliohms.
563///
564/// # Returns
565///
566/// The value to program into the calibration register, truncated as the datasheet
567/// does and capped at the register's 15-bit width. Returns `0` if either argument
568/// is `0`, which is the chip's own uncalibrated state.
569pub fn calibration(current_lsb_microamps: u32, shunt_milliohms: u32) -> u16 {
570 let denominator = current_lsb_microamps.saturating_mul(shunt_milliohms);
571 if denominator == 0 {
572 return 0;
573 }
574 (5_120_000 / denominator).min(0x7FFF) as u16
575}
576
577/// Returns the smallest current LSB, in microamps, that still spans a full-scale
578/// current.
579///
580/// The current register is 15 bits of magnitude, so the minimum resolution is the
581/// maximum expected current divided by 2^15, rounded up to the next whole microamp.
582/// The datasheet then rounds this up further to a convenient round number.
583///
584/// # Arguments
585///
586/// * `max_expected_microamps` - the largest current the application will measure.
587///
588/// # Returns
589///
590/// The minimum current LSB in microamps.
591pub fn minimum_current_lsb_microamps(max_expected_microamps: u32) -> u32 {
592 max_expected_microamps.div_ceil(32_768)
593}
594
595/// Decodes the shunt voltage register to nanovolts.
596///
597/// # Arguments
598///
599/// * `raw` - the signed shunt voltage register.
600///
601/// # Returns
602///
603/// The shunt voltage in nanovolts, at 2.5 µV per count.
604pub fn shunt_nanovolts(raw: i16) -> i32 {
605 i32::from(raw) * SHUNT_LSB_NANOVOLTS
606}
607
608/// Decodes the shunt voltage register to millivolts as a float.
609///
610/// # Arguments
611///
612/// * `raw` - the signed shunt voltage register.
613///
614/// # Returns
615///
616/// The shunt voltage in millivolts.
617pub fn shunt_millivolts_f32(raw: i16) -> f32 {
618 f32::from(raw) * 0.0025
619}
620
621/// Decodes the bus voltage register to microvolts.
622///
623/// Bit 15 is always zero on the chip, since the bus voltage is positive only, and
624/// is ignored here.
625///
626/// # Arguments
627///
628/// * `raw` - the bus voltage register.
629///
630/// # Returns
631///
632/// The bus voltage in microvolts, at 1.25 mV per count.
633pub fn bus_microvolts(raw: u16) -> u32 {
634 u32::from(raw & 0x7FFF) * BUS_LSB_MICROVOLTS
635}
636
637/// Decodes the bus voltage register to volts as a float.
638///
639/// # Arguments
640///
641/// * `raw` - the bus voltage register.
642///
643/// # Returns
644///
645/// The bus voltage in volts.
646pub fn bus_volts_f32(raw: u16) -> f32 {
647 f32::from(raw & 0x7FFF) * 0.00125
648}
649
650/// Decodes the current register to microamps for a given current LSB.
651///
652/// # Arguments
653///
654/// * `raw` - the signed current register.
655/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
656///
657/// # Returns
658///
659/// The current in microamps.
660pub fn current_microamps(raw: i16, current_lsb_microamps: u32) -> i32 {
661 i32::from(raw) * current_lsb_microamps as i32
662}
663
664/// Decodes the current register to amps as a float.
665///
666/// # Arguments
667///
668/// * `raw` - the signed current register.
669/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
670///
671/// # Returns
672///
673/// The current in amps.
674pub fn current_amps_f32(raw: i16, current_lsb_microamps: u32) -> f32 {
675 current_microamps(raw, current_lsb_microamps) as f32 * 1e-6
676}
677
678/// Decodes the power register to microwatts for a given current LSB.
679///
680/// The power LSB is fixed by the datasheet at twenty-five times the current LSB.
681///
682/// # Arguments
683///
684/// * `raw` - the power register.
685/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
686///
687/// # Returns
688///
689/// The power in microwatts.
690pub fn power_microwatts(raw: u16, current_lsb_microamps: u32) -> u32 {
691 u32::from(raw) * (POWER_LSB_RATIO * current_lsb_microamps)
692}
693
694/// Decodes the power register to watts as a float.
695///
696/// # Arguments
697///
698/// * `raw` - the power register.
699/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
700///
701/// # Returns
702///
703/// The power in watts.
704pub fn power_watts_f32(raw: u16, current_lsb_microamps: u32) -> f32 {
705 power_microwatts(raw, current_lsb_microamps) as f32 * 1e-6
706}
707
708/// Builds the shunt voltage register a monitor reports for a shunt voltage.
709///
710/// The inverse of [`shunt_nanovolts`], so a node can be written and tested against
711/// what a monitor sends without one attached. The same value serves as the alert
712/// limit for the shunt over- and under-limit functions.
713///
714/// # Arguments
715///
716/// * `nanovolts` - the shunt voltage in nanovolts.
717///
718/// # Returns
719///
720/// The signed shunt voltage register, at 2.5 µV per count.
721pub fn shunt_register(nanovolts: i32) -> i16 {
722 (nanovolts / SHUNT_LSB_NANOVOLTS) as i16
723}
724
725/// Builds the bus voltage register a monitor reports for a bus voltage.
726///
727/// The inverse of [`bus_microvolts`]. The same value serves as the alert limit for
728/// the bus over- and under-limit functions.
729///
730/// # Arguments
731///
732/// * `microvolts` - the bus voltage in microvolts.
733///
734/// # Returns
735///
736/// The bus voltage register, at 1.25 mV per count.
737pub fn bus_register(microvolts: u32) -> u16 {
738 (microvolts / BUS_LSB_MICROVOLTS) as u16
739}
740
741/// Builds the current register a monitor reports for a current.
742///
743/// The inverse of [`current_microamps`].
744///
745/// # Arguments
746///
747/// * `microamps` - the current in microamps.
748/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
749///
750/// # Returns
751///
752/// The signed current register, or zero if `current_lsb_microamps` is zero.
753pub fn current_register(microamps: i32, current_lsb_microamps: u32) -> i16 {
754 if current_lsb_microamps == 0 {
755 return 0;
756 }
757 (microamps / current_lsb_microamps as i32) as i16
758}
759
760/// Builds the power register a monitor reports for a power.
761///
762/// The inverse of [`power_microwatts`]. The same value serves as the alert limit for
763/// the power over-limit function.
764///
765/// # Arguments
766///
767/// * `microwatts` - the power in microwatts.
768/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
769///
770/// # Returns
771///
772/// The power register, or zero if `current_lsb_microamps` is zero.
773pub fn power_register(microwatts: u32, current_lsb_microamps: u32) -> u16 {
774 if current_lsb_microamps == 0 {
775 return 0;
776 }
777 (microwatts / (POWER_LSB_RATIO * current_lsb_microamps)) as u16
778}
779
780/// Reproduces the chip's current calculation from a shunt reading and calibration.
781///
782/// This is the datasheet's `Current = ShuntVoltage * CalibrationRegister / 2048`,
783/// so a simulator can fill the current register the way the chip would.
784///
785/// # Arguments
786///
787/// * `shunt` - the signed shunt voltage register.
788/// * `calibration` - the programmed calibration register.
789///
790/// # Returns
791///
792/// The signed current register the chip would hold.
793pub fn current_register_from_shunt(shunt: i16, calibration: u16) -> i16 {
794 (i32::from(shunt) * i32::from(calibration) / 2048) as i16
795}
796
797/// Reproduces the chip's power calculation from the current and bus registers.
798///
799/// This is the datasheet's `Power = Current * BusVoltage / 20000`. The power
800/// register is unsigned, so the magnitude of the current is used.
801///
802/// # Arguments
803///
804/// * `current` - the signed current register.
805/// * `bus` - the bus voltage register.
806///
807/// # Returns
808///
809/// The power register the chip would hold.
810pub fn power_register_from_current(current: i16, bus: u16) -> u16 {
811 (u32::from(current.unsigned_abs()) * u32::from(bus & 0x7FFF) / 20_000) as u16
812}
813
814/// One set of results, with the current resolution they were taken at.
815///
816/// The four data registers are kept as read; the methods apply the datasheet's
817/// scaling. The overflow flag is the one the Mask/Enable register carried when the
818/// conversion finished.
819#[derive(Clone, Copy, Debug, PartialEq, Eq)]
820pub struct Reading {
821 /// The Shunt Voltage register.
822 pub shunt: i16,
823 /// The Bus Voltage register.
824 pub bus: u16,
825 /// The Current register.
826 pub current: i16,
827 /// The Power register.
828 pub power: u16,
829 /// The programmed current resolution, in microamps per count.
830 pub current_lsb_microamps: u32,
831 /// The math overflow flag: the current and power may be invalid.
832 pub math_overflow: bool,
833}
834
835impl Reading {
836 /// Returns the shunt voltage in nanovolts.
837 pub fn shunt_nanovolts(&self) -> i32 {
838 shunt_nanovolts(self.shunt)
839 }
840
841 /// Returns the shunt voltage in millivolts.
842 pub fn shunt_millivolts(&self) -> f32 {
843 shunt_millivolts_f32(self.shunt)
844 }
845
846 /// Returns the bus voltage in microvolts.
847 pub fn bus_microvolts(&self) -> u32 {
848 bus_microvolts(self.bus)
849 }
850
851 /// Returns the bus voltage in volts.
852 pub fn bus_volts(&self) -> f32 {
853 bus_volts_f32(self.bus)
854 }
855
856 /// Returns the current in microamps.
857 pub fn current_microamps(&self) -> i32 {
858 current_microamps(self.current, self.current_lsb_microamps)
859 }
860
861 /// Returns the current in amps.
862 pub fn current_amps(&self) -> f32 {
863 current_amps_f32(self.current, self.current_lsb_microamps)
864 }
865
866 /// Returns the power in microwatts.
867 pub fn power_microwatts(&self) -> u32 {
868 power_microwatts(self.power, self.current_lsb_microamps)
869 }
870
871 /// Returns the power in watts.
872 pub fn power_watts(&self) -> f32 {
873 power_watts_f32(self.power, self.current_lsb_microamps)
874 }
875}
876
877#[cfg(test)]
878mod driver_support_tests {
879 use super::*;
880
881 #[test]
882 fn a_reading_scales_its_registers_like_the_free_functions() {
883 let reading = Reading {
884 shunt: shunt_register(50_000_000),
885 bus: bus_register(12_000_000),
886 current: current_register(1_000_000, 100),
887 power: power_register(12_000_000, 100),
888 current_lsb_microamps: 100,
889 math_overflow: false,
890 };
891 assert_eq!(reading.shunt_nanovolts(), 50_000_000);
892 assert!((reading.shunt_millivolts() - 50.0).abs() < 1e-3);
893 assert_eq!(reading.bus_microvolts(), 12_000_000);
894 assert!((reading.bus_volts() - 12.0).abs() < 1e-3);
895 assert_eq!(reading.current_microamps(), 1_000_000);
896 assert!((reading.current_amps() - 1.0).abs() < 1e-3);
897 assert_eq!(reading.power_microwatts(), 12_000_000);
898 assert!((reading.power_watts() - 12.0).abs() < 1e-3);
899 }
900}
901
902#[cfg(test)]
903mod tests {
904 use super::*;
905
906 // The datasheet's worked example (section 6.5.1, Table 6-1): a 10 A load across
907 // a 2 mΩ shunt, 12 V common mode, current LSB rounded to 1 mA/bit.
908 const CURRENT_LSB: u32 = 1_000; // 1 mA in microamps
909
910 #[test]
911 fn every_register_survives_a_round_trip_through_its_builder() {
912 // Table 6-1: 20 mV shunt, 11.98 V bus, 10 A, 119.8 W.
913 assert_eq!(shunt_register(20_000_000), 0x1F40);
914 assert_eq!(shunt_nanovolts(shunt_register(20_000_000)), 20_000_000);
915 assert_eq!(shunt_nanovolts(shunt_register(-80_000_000)), -80_000_000);
916 assert_eq!(bus_register(11_980_000), 0x2570);
917 assert_eq!(bus_microvolts(bus_register(11_980_000)), 11_980_000);
918 assert_eq!(current_register(10_000_000, CURRENT_LSB), 0x2710);
919 assert_eq!(
920 current_microamps(current_register(10_000_000, CURRENT_LSB), CURRENT_LSB),
921 10_000_000
922 );
923 assert_eq!(current_register(-2_500_000, CURRENT_LSB), -2_500);
924 assert_eq!(power_register(119_800_000, CURRENT_LSB), 0x12B8);
925 assert_eq!(
926 power_microwatts(power_register(119_800_000, CURRENT_LSB), CURRENT_LSB),
927 119_800_000
928 );
929 assert_eq!(current_register(1, 0), 0);
930 assert_eq!(power_register(1, 0), 0);
931 }
932
933 #[test]
934 fn calibration_matches_the_datasheet_example() {
935 // Equation 1 with Current_LSB = 1 mA/bit and R_SHUNT = 2 mΩ: 2560 = A00h.
936 assert_eq!(calibration(CURRENT_LSB, 2), 2_560);
937 assert_eq!(calibration(CURRENT_LSB, 2), 0xA00);
938 }
939
940 #[test]
941 fn calibration_is_capped_at_the_register_width() {
942 // Table 7-11: the calibration value occupies FS14..FS0.
943 assert_eq!(calibration(1, 1), 0x7FFF);
944 }
945
946 #[test]
947 fn minimum_current_lsb_matches_the_datasheet_example() {
948 // Equation 2, section 6.5.1: 15 A / 2^15 = 457.7 µA/bit, up to the next
949 // whole microamp.
950 assert_eq!(minimum_current_lsb_microamps(15_000_000), 458);
951 }
952
953 #[test]
954 fn shunt_register_decodes_per_the_datasheet() {
955 // Table 6-1: 1F40h = 8000 at 2.5 µV per count is 20 mV.
956 assert_eq!(shunt_nanovolts(0x1F40), 20_000_000);
957 // Section 7.1.2 worked two's complement: -80 mV is 8300h.
958 assert_eq!(
959 shunt_nanovolts(i16::from_be_bytes([0x83, 0x00])),
960 -80_000_000
961 );
962 // Section 7.1.2: full scale 7FFFh is 81.92 mV (81.9175 mV exactly, per the
963 // electrical characteristics input range).
964 assert_eq!(shunt_nanovolts(0x7FFF), 81_917_500);
965 assert!((shunt_millivolts_f32(0x1F40) - 20.0).abs() < 1e-4);
966 }
967
968 #[test]
969 fn bus_register_decodes_per_the_datasheet() {
970 // Table 6-1: 2570h = 9584 at 1.25 mV per count is 11.98 V.
971 assert_eq!(bus_microvolts(0x2570), 11_980_000);
972 // Section 7.1.3: full scale 7FFFh is 40.96 V.
973 assert_eq!(bus_microvolts(0x7FFF), 40_958_750);
974 // Table 7-8: D15 is always zero, so it carries no value if it ever reads set.
975 assert_eq!(bus_microvolts(0xA570), bus_microvolts(0x2570));
976 assert!((bus_volts_f32(0x2570) - 11.98).abs() < 1e-4);
977 }
978
979 #[test]
980 fn current_register_decodes_to_the_example_load() {
981 // Table 6-1: 2710h = 10000 at 1 mA per count is 10 A.
982 assert_eq!(current_microamps(0x2710, CURRENT_LSB), 10_000_000);
983 assert!((current_amps_f32(0x2710, CURRENT_LSB) - 10.0).abs() < 1e-5);
984 }
985
986 #[test]
987 fn power_register_decodes_to_the_example_load() {
988 // Table 6-1: 12B8h = 4792 at 25 mW per count (25 times the 1 mA current
989 // LSB) is 119.8 W; the table prints the figure as 119.82 W.
990 assert_eq!(power_microwatts(0x12B8, CURRENT_LSB), 119_800_000);
991 assert!((power_watts_f32(0x12B8, CURRENT_LSB) - 119.8).abs() < 1e-3);
992 }
993
994 #[test]
995 fn chip_arithmetic_reproduces_the_datasheet_example() {
996 // Equation 3: 8000 * 2560 / 2048 = 10000 = 2710h.
997 assert_eq!(current_register_from_shunt(0x1F40, 0xA00), 0x2710);
998 // Equation 4: 10000 * 9584 / 20000 = 4792 = 12B8h.
999 assert_eq!(power_register_from_current(0x2710, 0x2570), 0x12B8);
1000 // A reversed current gives the same power magnitude.
1001 assert_eq!(current_register_from_shunt(-0x1F40, 0xA00), -0x2710);
1002 assert_eq!(power_register_from_current(-0x2710, 0x2570), 0x12B8);
1003 // Nothing is computed until the calibration register is programmed
1004 // (Table 7-1, note 2).
1005 assert_eq!(current_register_from_shunt(0x1F40, 0), 0);
1006 }
1007
1008 #[test]
1009 fn configuration_reset_value_matches_the_datasheet() {
1010 // Table 7-1 / Table 7-2: power-on reset 4127h, averaging 1, 1.1 ms for both
1011 // conversions, shunt and bus continuous. Table 6-1 step 1 writes the same.
1012 let config = Configuration::from_register(CONFIG_RESET);
1013 assert_eq!(config, Configuration::RESET);
1014 assert_eq!(config, Configuration::default());
1015 assert!(!config.reset);
1016 assert_eq!(config.averaging, Averaging::Samples1);
1017 assert_eq!(config.bus_conversion_time, ConversionTime::Us1100);
1018 assert_eq!(config.shunt_conversion_time, ConversionTime::Us1100);
1019 assert_eq!(config.mode, Mode::ShuntAndBusContinuous);
1020 assert_eq!(config.to_register(), 0x4127);
1021 }
1022
1023 #[test]
1024 fn configuration_fields_land_on_their_datasheet_bits() {
1025 // Table 7-2: RST in D15, AVG in D11:9, VBUSCT in D8:6, VSHCT in D5:3, MODE
1026 // in D2:0.
1027 let config = Configuration {
1028 reset: true,
1029 averaging: Averaging::Samples1024,
1030 bus_conversion_time: ConversionTime::Us8244,
1031 shunt_conversion_time: ConversionTime::Us8244,
1032 mode: Mode::ShuntAndBusContinuous,
1033 };
1034 assert_eq!(
1035 config.to_register(),
1036 0x8000 | 0x4000 | 0x0E00 | 0x01C0 | 0x0038 | 0x0007
1037 );
1038 assert_eq!(Configuration::from_register(config.to_register()), config);
1039
1040 let config = Configuration {
1041 reset: false,
1042 averaging: Averaging::Samples16,
1043 bus_conversion_time: ConversionTime::Us140,
1044 shunt_conversion_time: ConversionTime::Us588,
1045 mode: Mode::ShuntTriggered,
1046 };
1047 assert_eq!(config.to_register(), 0x4000 | 0x0400 | 0x0018 | 0x0001);
1048 assert_eq!(Configuration::from_register(config.to_register()), config);
1049
1050 // Table 7-6: both 000 and 100 are power-down.
1051 assert_eq!(Configuration::from_register(0x4120).mode, Mode::PowerDown);
1052 assert_eq!(Configuration::from_register(0x4124).mode, Mode::PowerDown);
1053 }
1054
1055 #[test]
1056 fn averaging_table_decodes_per_the_datasheet() {
1057 // Table 7-3.
1058 let table = [1, 4, 16, 64, 128, 256, 512, 1024];
1059 for (bits, samples) in table.into_iter().enumerate() {
1060 let averaging = Averaging::from_bits(bits as u16);
1061 assert_eq!(averaging as u16, bits as u16);
1062 assert_eq!(averaging.samples(), samples, "AVG = {bits:03b}");
1063 }
1064 }
1065
1066 #[test]
1067 fn conversion_time_table_decodes_per_the_datasheet() {
1068 // Tables 7-4 and 7-5, the same eight settings for bus and shunt.
1069 let table = [140, 204, 332, 588, 1_100, 2_116, 4_156, 8_244];
1070 for (bits, microseconds) in table.into_iter().enumerate() {
1071 let time = ConversionTime::from_bits(bits as u16);
1072 assert_eq!(time as u16, bits as u16);
1073 assert_eq!(time.microseconds(), microseconds, "CT = {bits:03b}");
1074 }
1075 }
1076
1077 #[test]
1078 fn mode_table_decodes_per_the_datasheet() {
1079 // Table 7-6.
1080 assert_eq!(Mode::from_bits(0b000), Mode::PowerDown);
1081 assert_eq!(Mode::from_bits(0b001), Mode::ShuntTriggered);
1082 assert_eq!(Mode::from_bits(0b010), Mode::BusTriggered);
1083 assert_eq!(Mode::from_bits(0b011), Mode::ShuntAndBusTriggered);
1084 assert_eq!(Mode::from_bits(0b100), Mode::PowerDown);
1085 assert_eq!(Mode::from_bits(0b101), Mode::ShuntContinuous);
1086 assert_eq!(Mode::from_bits(0b110), Mode::BusContinuous);
1087 assert_eq!(Mode::from_bits(0b111), Mode::ShuntAndBusContinuous);
1088 assert!(Mode::ShuntContinuous.measures_shunt());
1089 assert!(!Mode::ShuntContinuous.measures_bus());
1090 assert!(Mode::BusTriggered.measures_bus());
1091 assert!(!Mode::BusTriggered.is_continuous());
1092 assert!(Mode::ShuntAndBusContinuous.is_continuous());
1093 assert!(!Mode::PowerDown.measures_shunt());
1094 assert!(!Mode::PowerDown.measures_bus());
1095 }
1096
1097 #[test]
1098 fn update_interval_matches_the_datasheet_timing_examples() {
1099 // Section 6.4.1: 588 µs for both conversions averaged over 4 samples updates
1100 // about every 4.7 ms, as does 4.156 ms shunt with 588 µs bus and no averaging.
1101 let config = Configuration {
1102 averaging: Averaging::Samples4,
1103 bus_conversion_time: ConversionTime::Us588,
1104 shunt_conversion_time: ConversionTime::Us588,
1105 ..Configuration::RESET
1106 };
1107 assert_eq!(config.update_microseconds(), 4_704);
1108 let config = Configuration {
1109 averaging: Averaging::Samples1,
1110 bus_conversion_time: ConversionTime::Us588,
1111 shunt_conversion_time: ConversionTime::Us4156,
1112 ..Configuration::RESET
1113 };
1114 assert_eq!(config.update_microseconds(), 4_744);
1115 assert_eq!(Configuration::RESET.update_microseconds(), 2_200);
1116 let config = Configuration {
1117 mode: Mode::ShuntContinuous,
1118 ..config
1119 };
1120 assert_eq!(config.update_microseconds(), 4_156);
1121 let config = Configuration {
1122 mode: Mode::PowerDown,
1123 ..config
1124 };
1125 assert_eq!(config.update_microseconds(), 0);
1126 }
1127
1128 #[test]
1129 fn address_table_matches_the_datasheet() {
1130 // Table 6-2, in its row order GND, VS, SDA, SCL for each pin.
1131 use AddressPin::*;
1132 let pins = [Ground, Supply, Sda, Scl];
1133 let mut expected = 0x40;
1134 for a1 in pins {
1135 for a0 in pins {
1136 assert_eq!(address(a1, a0), expected, "A1 = {a1:?}, A0 = {a0:?}");
1137 expected += 1;
1138 }
1139 }
1140 assert_eq!(address(Ground, Ground), 0b1000000);
1141 assert_eq!(address(Supply, Ground), 0b1000100);
1142 assert_eq!(address(Sda, Scl), 0b1001011);
1143 assert_eq!(address(Scl, Scl), 0b1001111);
1144 }
1145
1146 #[test]
1147 fn identification_registers_match_the_datasheet() {
1148 // Table 7-1: manufacturer ID 5449h; die ID 2260h or 2261h (note 3).
1149 assert_eq!(MANUFACTURER_ID, 0x5449);
1150 assert_eq!(
1151 identify(0x5449, 0x2260),
1152 Ok(DieId {
1153 device: 0x226,
1154 revision: 0
1155 })
1156 );
1157 assert_eq!(
1158 identify(0x5449, 0x2261),
1159 Ok(DieId {
1160 device: 0x226,
1161 revision: 1
1162 })
1163 );
1164 // An unpowered or absent part reads all ones.
1165 assert_eq!(identify(0xFFFF, 0xFFFF), Err(SensorError::Identity));
1166 // Another TI part on the same address.
1167 assert_eq!(identify(0x5449, 0x2280), Err(SensorError::Identity));
1168 assert_eq!(identify(0x0000, 0x2260), Err(SensorError::Identity));
1169 }
1170
1171 #[test]
1172 fn mask_enable_decodes_the_alert_bits() {
1173 // Table 7-12: SOL D15, SUL D14, BOL D13, BUL D12, POL D11, CNVR D10, AFF D4,
1174 // CVRF D3, OVF D2, APOL D1, LEN D0.
1175 let mask = MaskEnable::from_register(0x8001);
1176 assert!(mask.shunt_over_limit);
1177 assert!(mask.alert_latch);
1178 assert_eq!(
1179 mask.active_alert_function(),
1180 Some(AlertFunction::ShuntOverLimit)
1181 );
1182 assert_eq!(mask.to_register(), 0x8001);
1183
1184 let mask = MaskEnable::from_register(0x0418);
1185 assert!(mask.conversion_ready);
1186 assert!(mask.alert_function_flag);
1187 assert!(mask.conversion_ready_flag);
1188 assert!(!mask.math_overflow);
1189 assert_eq!(mask.active_alert_function(), None);
1190 assert_eq!(mask.to_register(), 0x0418);
1191
1192 assert!(MaskEnable::from_register(0x0004).math_overflow);
1193 assert!(MaskEnable::from_register(0x0002).alert_active_high);
1194 assert_eq!(MaskEnable::from_register(0x0000), MaskEnable::default());
1195 assert_eq!(MaskEnable::default().to_register(), 0x0000);
1196
1197 for bit in 0..16 {
1198 let raw = 1u16 << bit;
1199 let reserved = (5..=9).contains(&bit);
1200 assert_eq!(
1201 MaskEnable::from_register(raw).to_register(),
1202 if reserved { 0 } else { raw },
1203 "bit {bit}"
1204 );
1205 }
1206 }
1207
1208 #[test]
1209 fn the_highest_alert_function_bit_takes_priority() {
1210 // Section 7.1.7: with several functions enabled, the most significant wins.
1211 assert_eq!(
1212 MaskEnable::from_register(0xF800).active_alert_function(),
1213 Some(AlertFunction::ShuntOverLimit)
1214 );
1215 assert_eq!(
1216 MaskEnable::from_register(0x7800).active_alert_function(),
1217 Some(AlertFunction::ShuntUnderLimit)
1218 );
1219 assert_eq!(
1220 MaskEnable::from_register(0x3800).active_alert_function(),
1221 Some(AlertFunction::BusOverLimit)
1222 );
1223 assert_eq!(
1224 MaskEnable::from_register(0x1800).active_alert_function(),
1225 Some(AlertFunction::BusUnderLimit)
1226 );
1227 assert_eq!(
1228 MaskEnable::from_register(0x0800).active_alert_function(),
1229 Some(AlertFunction::PowerOverLimit)
1230 );
1231 assert_eq!(
1232 MaskEnable::from_register(0x0400).active_alert_function(),
1233 None
1234 );
1235 }
1236
1237 #[test]
1238 fn integer_conversions_track_the_floating_point_reference() {
1239 // Equation 1 in its floating-point form, CAL = 0.00512 / (Current_LSB *
1240 // R_SHUNT), swept over current LSBs and shunts a design would choose.
1241 for &lsb in &[50u32, 100, 250, 458, 500, 1_000, 2_000, 5_000, 10_000] {
1242 for &shunt in &[1u32, 2, 5, 10, 25, 100, 500, 1_000] {
1243 let reference = 0.00512 / (f64::from(lsb) * 1e-6 * f64::from(shunt) * 1e-3);
1244 let expected = reference.trunc().min(32_767.0);
1245 let actual = f64::from(calibration(lsb, shunt));
1246 assert!(
1247 (actual - expected).abs() <= 1.0,
1248 "lsb {lsb} µA, shunt {shunt} mΩ: {actual} vs {expected}"
1249 );
1250 }
1251 }
1252
1253 // The 2.5 µV, 1.25 mV, and 25 x Current_LSB scalings against their float
1254 // forms across the register range.
1255 for raw in (-32_768..=32_767).step_by(997) {
1256 let shunt = f64::from(shunt_nanovolts(raw as i16)) * 1e-9;
1257 assert!((shunt - f64::from(raw) * 2.5e-6).abs() < 1e-12);
1258 let current = f64::from(current_microamps(raw as i16, 458)) * 1e-6;
1259 assert!((current - f64::from(raw) * 458e-6).abs() < 1e-9);
1260 }
1261 for raw in (0..=0x7FFF).step_by(499) {
1262 let bus = f64::from(bus_microvolts(raw as u16)) * 1e-6;
1263 assert!((bus - f64::from(raw) * 1.25e-3).abs() < 1e-9);
1264 let power = f64::from(power_microwatts(raw as u16, 458)) * 1e-6;
1265 assert!((power - f64::from(raw) * 25.0 * 458e-6).abs() < 1e-9);
1266 }
1267 }
1268
1269 #[test]
1270 fn an_uncalibrated_request_returns_zero() {
1271 assert_eq!(calibration(0, 2), 0);
1272 assert_eq!(calibration(CURRENT_LSB, 0), 0);
1273 }
1274}