-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbattery.rs
90 lines (74 loc) · 2.64 KB
/
battery.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use super::OsResult;
use esp_idf_svc::{
hal::{
adc::{
attenuation::DB_11,
oneshot::{config::AdcChannelConfig, AdcChannelDriver, AdcDriver},
Adc, Resolution, ADC1,
},
gpio::Gpio35,
},
sys::{
adc_atten_t, esp_adc_cal_characteristics_t, esp_adc_cal_characterize,
esp_adc_cal_raw_to_voltage,
},
};
use pwmp_client::pwmp_types::{aliases::BatteryVoltage, dec, Decimal};
use std::{thread::sleep, time::Duration};
const ATTEN: adc_atten_t = DB_11;
const DIVIDER_R1: f32 = 20_000.0; // 20kOhm
const DIVIDER_R2: f32 = 6800.0; // 6.8kOhm
type BatteryGpio = Gpio35;
type BatteryAdc = ADC1;
type BatteryDriver = AdcDriver<'static, BatteryAdc>;
type BatteryChDriver = AdcChannelDriver<'static, BatteryGpio, BatteryDriver>;
pub const CRITICAL_VOLTAGE: Decimal = dec!(2.70);
pub const RESOLUTION: Resolution = Resolution::Resolution12Bit;
pub const ADC_CONFIG: AdcChannelConfig = AdcChannelConfig {
attenuation: ATTEN,
calibration: true,
resolution: Resolution::Resolution12Bit,
};
pub struct Battery(BatteryChDriver);
impl Battery {
pub fn new(adc: BatteryAdc, gpio: BatteryGpio) -> OsResult<Self> {
let driver = BatteryDriver::new(adc)?;
let ch_driver = BatteryChDriver::new(driver, gpio, &ADC_CONFIG)?;
Ok(Self(ch_driver))
}
pub fn read_voltage(&mut self, samples: u16) -> OsResult<BatteryVoltage> {
let div_out = self.read_raw_voltage(samples)?;
// Vout = Vin * (R2 / (R1 + R2)) => Vin = Vout * (R1 + R2) / R2
let vin = div_out * (DIVIDER_R1 + DIVIDER_R2) / DIVIDER_R2;
let voltage = vin.clamp(0.0, 4.2);
let mut decimal = Decimal::from_f32_retain(voltage).unwrap();
decimal.rescale(2);
Ok(decimal)
}
pub fn read_raw_voltage(&mut self, samples: u16) -> OsResult<f32> {
Ok(Self::raw_to_voltage(self.read_raw(samples)?))
}
fn raw_to_voltage(raw: u16) -> f32 {
let mut characteristics = esp_adc_cal_characteristics_t::default();
unsafe {
esp_adc_cal_characterize(
ADC1::unit(),
ATTEN,
RESOLUTION.into(),
1100,
&mut characteristics,
);
}
let millivolts = unsafe { esp_adc_cal_raw_to_voltage(raw as u32, &characteristics) };
millivolts as f32 / 1000.0
}
fn read_raw(&mut self, samples: u16) -> OsResult<u16> {
let mut avg = 0.0f32;
for _ in 0..samples {
avg += self.0.read()? as f32;
sleep(Duration::from_millis(20));
}
avg /= samples as f32;
Ok(avg as u16)
}
}