Skip to content

Commit 40cbd31

Browse files
author
Connor Truono
committed
Register-to-units conversions for acceleration and temperature output
1 parent 5aa4f3b commit 40cbd31

File tree

1 file changed

+136
-14
lines changed

1 file changed

+136
-14
lines changed

src/lib.rs

Lines changed: 136 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ impl<I2C: embedded_hal_async::i2c::I2c> Lis2dw12<I2C> {
8181

8282
/// Modifies the specified register by first reading then setting or resetting specified bits
8383
/// If a bit is marked in both set and reset masks, then that bit will not be updated
84-
pub async fn modify_reg(&mut self, reg: Register, bits_to_reset: u8, bits_to_set: u8) -> Result<(), I2C::Error> {
84+
pub async fn modify_reg_bits(
85+
&mut self,
86+
reg: Register,
87+
bits_to_reset: u8,
88+
bits_to_set: u8,
89+
) -> Result<(), I2C::Error> {
8590
// Filter masks to clear overlap bits
8691
let both_mask: u8 = bits_to_reset & bits_to_set;
8792
let reset_mask: u8 = bits_to_reset & !both_mask;
@@ -97,94 +102,211 @@ impl<I2C: embedded_hal_async::i2c::I2c> Lis2dw12<I2C> {
97102
self.write_reg(reg, current).await
98103
}
99104

100-
/// Reads the device temperature with 12 bit precision
105+
/// Modifies the specified register by first reading then replacing the masked bits with the value's bits
106+
pub async fn modify_reg_field(&mut self, reg: Register, val: u8, mask: u8) -> Result<(), I2C::Error> {
107+
// Read current value of that register
108+
let mut current: u8 = self.read_reg(reg).await?;
109+
110+
// Update the register value with the new masked bits
111+
current = (current & !mask) | (val & mask);
112+
113+
self.write_reg(reg, current).await
114+
}
115+
116+
/// Reads the device temperature with 12 bit precision. The LSB bits 3..0 are unused 0
117+
/// Offset: 0 LSB = 25 deg C
118+
/// Scale: 16 LSB / deg C (Note: LSB bits 3..0 are unused 0, so the LSB is at bit 4)
101119
pub async fn temp_12bit(&mut self) -> Result<i16, I2C::Error> {
102120
let mut temp: i16 = 0;
103121
temp += ((self.read_reg(Register::TempOutHigh).await?) as i16) << 8;
104122
temp += (self.read_reg(Register::TempOutLow).await?) as i16;
105-
temp >>= 4;
106123
Ok(temp)
107124
}
108125

109126
/// Reads the device temperature with 8 bit precision
127+
/// Offset: 0 LSB = 25 deg C
128+
/// Scale: 1 deg C / LSB
110129
pub async fn temp_8bit(&mut self) -> Result<i8, I2C::Error> {
111130
Ok(self.read_reg(Register::TempOut).await? as i8)
112131
}
113132

114-
/// Reads the device acceleration in the X axis
133+
/// Reads the current temperature and returns the value in degrees Celcius
134+
pub async fn temp_celcius(&mut self) -> Result<f32, I2C::Error> {
135+
Ok(Lis2dw12::<I2C>::convert_temp_reg_to_celcius(self.temp_12bit().await?))
136+
}
137+
138+
/// Reads the device acceleration register in the X axis
115139
pub async fn acc_x(&mut self) -> Result<i16, I2C::Error> {
116140
let mut accx: i16 = 0;
117141
accx += ((self.read_reg(Register::XOutHigh).await?) as i16) << 8;
118142
accx += (self.read_reg(Register::XOutLow).await?) as i16;
119143
Ok(accx)
120144
}
121145

122-
/// Reads the device acceleration in the Y axis
146+
/// Reads the device acceleration register in the Y axis
123147
pub async fn acc_y(&mut self) -> Result<i16, I2C::Error> {
124148
let mut accy: i16 = 0;
125149
accy += ((self.read_reg(Register::YOutHigh).await?) as i16) << 8;
126150
accy += (self.read_reg(Register::YOutLow).await?) as i16;
127151
Ok(accy)
128152
}
129153

130-
/// Reads the device acceleration in the Z axis
154+
/// Reads the device acceleration register in the Z axis
131155
pub async fn acc_z(&mut self) -> Result<i16, I2C::Error> {
132156
let mut accz: i16 = 0;
133157
accz += ((self.read_reg(Register::ZOutHigh).await?) as i16) << 8;
134158
accz += (self.read_reg(Register::ZOutLow).await?) as i16;
135159
Ok(accz)
136160
}
137161

138-
/// Reads the 3D device acceleration
162+
/// Reads the 3D device acceleration from registers
139163
pub async fn acc(&mut self) -> Result<(i16, i16, i16), I2C::Error> {
140164
Ok((self.acc_x().await?, self.acc_y().await?, self.acc_z().await?))
141165
}
142166

167+
/// Returns the 3D device acceleration in Gs
168+
pub async fn acc_gs(&mut self) -> Result<(f32, f32, f32), I2C::Error> {
169+
let full_scale = self.full_scale_range().await?;
170+
let (accx, accy, accz) = self.acc().await?;
171+
Ok((
172+
Lis2dw12::<I2C>::convert_acc_to_gs(accx, full_scale),
173+
Lis2dw12::<I2C>::convert_acc_to_gs(accy, full_scale),
174+
Lis2dw12::<I2C>::convert_acc_to_gs(accz, full_scale),
175+
))
176+
}
177+
178+
/// Returns the 3D device acceleration in milli-Gs
179+
pub async fn acc_mgs(&mut self) -> Result<(f32, f32, f32), I2C::Error> {
180+
let full_scale = self.full_scale_range().await?;
181+
let (accx, accy, accz) = self.acc().await?;
182+
Ok((
183+
Lis2dw12::<I2C>::convert_acc_to_mgs(accx, full_scale),
184+
Lis2dw12::<I2C>::convert_acc_to_mgs(accy, full_scale),
185+
Lis2dw12::<I2C>::convert_acc_to_mgs(accz, full_scale),
186+
))
187+
}
188+
189+
/// Returns the 3D device acceleration in micro-Gs
190+
pub async fn acc_ugs(&mut self) -> Result<(f32, f32, f32), I2C::Error> {
191+
let full_scale = self.full_scale_range().await?;
192+
let (accx, accy, accz) = self.acc().await?;
193+
Ok((
194+
Lis2dw12::<I2C>::convert_acc_to_ugs(accx, full_scale),
195+
Lis2dw12::<I2C>::convert_acc_to_ugs(accy, full_scale),
196+
Lis2dw12::<I2C>::convert_acc_to_ugs(accz, full_scale),
197+
))
198+
}
199+
200+
/// Reads the tap threshold value in the X axis from its register fields
143201
pub async fn tap_threshold_x(&mut self) -> Result<u8, I2C::Error> {
144-
self.read_reg(Register::TapThresholdX).await
202+
Ok(self.read_reg(Register::TapThresholdX).await? & 0x1F)
145203
}
146204

205+
/// Reads the tap threshold value in the Y axis from its register fields
147206
pub async fn tap_threshold_y(&mut self) -> Result<u8, I2C::Error> {
148-
self.read_reg(Register::TapThresholdY).await
207+
Ok(self.read_reg(Register::TapThresholdY).await? & 0x1F)
149208
}
150209

210+
/// Reads the tap threshold value in the Z axis from its register fields
151211
pub async fn tap_threshold_z(&mut self) -> Result<u8, I2C::Error> {
152-
self.read_reg(Register::TapThresholdZ).await
212+
Ok(self.read_reg(Register::TapThresholdZ).await? & 0x1F)
153213
}
154214

215+
/// Sets the tap threshold value in the X axis
216+
/// Does not update the rest of the register
155217
pub async fn set_tap_threshold_x(&mut self, ths: u8) -> Result<(), I2C::Error> {
156-
self.write_reg(Register::TapThresholdX, ths).await
218+
self.modify_reg_field(Register::TapThresholdX, ths, 0x1F).await
157219
}
158220

221+
/// Sets the tap threshold value in the Y axis
222+
/// Does not update the rest of the register
159223
pub async fn set_tap_threshold_y(&mut self, ths: u8) -> Result<(), I2C::Error> {
160-
self.write_reg(Register::TapThresholdY, ths).await
224+
self.modify_reg_field(Register::TapThresholdY, ths, 0x1F).await
161225
}
162226

227+
/// Sets the tap threshold value in the Z axis
228+
/// Does not update the rest of the register
163229
pub async fn set_tap_threshold_z(&mut self, ths: u8) -> Result<(), I2C::Error> {
164-
self.write_reg(Register::TapThresholdZ, ths).await
230+
self.modify_reg_field(Register::TapThresholdZ, ths, 0x1F).await
165231
}
166232

233+
/// Reads the Status register
167234
pub async fn status(&mut self) -> Result<StatusReg, I2C::Error> {
168235
let reg: u8 = self.read_reg(Register::Status).await?;
169236
Ok(reg.into())
170237
}
171238

239+
/// Reads the full scale range from Control Register 6
172240
pub async fn full_scale_range(&mut self) -> Result<Control6FullScale, I2C::Error> {
173241
let ctrl6: ControlReg6 = self.read_reg(Register::Control6).await?.into();
174242
Ok(ctrl6.fs())
175243
}
176244

245+
/// Sets the full scale range in Control Register 6
177246
pub async fn set_full_scale_range(&mut self, new_fs: Control6FullScale) -> Result<(), I2C::Error> {
178247
let mut ctrl6: ControlReg6 = self.read_reg(Register::Control6).await?.into();
179248
ctrl6.set_fs(new_fs);
180249
self.write_reg(Register::Control6, ctrl6.into()).await
181250
}
182251

252+
/// Returns free fall duration by stitching FF_DUR5 from WAKE_UP_DUR register onto FF register output
183253
pub async fn free_fall_duration(&mut self) -> Result<u8, I2C::Error> {
184-
// Get full free fall duration by stitching FF_DUR5 from WAKE_UP_DUR register onto FF register output
185254
let ff_reg: FreeFallReg = self.read_reg(Register::FreeFall).await?.into();
186255
let wu_reg: WakeUpDurationReg = self.read_reg(Register::WakeUpDuration).await?.into();
187256
let ff_dur: u8 = u8::from(ff_reg.ff_dur()) + (u8::from(wu_reg.ff_dur5()) << 5);
188257
Ok(ff_dur)
189258
}
259+
260+
// -------------------------- Helper Functions --------------------------
261+
262+
/// Converts i16 temperature representation to degrees Celcius
263+
/// For use with 8bit temp register, convert to i16 and shift data to upper (MSB) byte for input
264+
pub fn convert_temp_reg_to_celcius(temp_in: i16) -> f32 {
265+
// Convert temp int to float
266+
let mut temp: f32 = temp_in as f32;
267+
268+
// Divide out temp offset: bit 8 (LSB of upper byte) = 1 deg C
269+
temp /= 256f32;
270+
271+
// Add offset of 25 deg C at 0
272+
temp += 25f32;
273+
274+
temp
275+
}
276+
277+
/// Converts the acceleration register data to acceleration in Gs
278+
pub fn convert_acc_to_gs(acc_in: i16, full_scale: Control6FullScale) -> f32 {
279+
let acc: f32 = acc_in as f32;
280+
let factor: f32 = match full_scale {
281+
Control6FullScale::Scale2g => 1f32 / 16384f32,
282+
Control6FullScale::Scale4g => 1f32 / 8192f32,
283+
Control6FullScale::Scale8g => 1f32 / 4096f32,
284+
Control6FullScale::Scale16g => 1f32 / 2048f32,
285+
};
286+
acc * factor
287+
}
288+
289+
/// Converts the acceleration register data to acceleration in milli-Gs
290+
pub fn convert_acc_to_mgs(acc_in: i16, full_scale: Control6FullScale) -> f32 {
291+
let acc: f32 = acc_in as f32;
292+
let factor: f32 = match full_scale {
293+
Control6FullScale::Scale2g => 1000f32 / 16384f32,
294+
Control6FullScale::Scale4g => 1000f32 / 8192f32,
295+
Control6FullScale::Scale8g => 1000f32 / 4096f32,
296+
Control6FullScale::Scale16g => 1000f32 / 2048f32,
297+
};
298+
acc * factor
299+
}
300+
301+
/// Converts the acceleration register data to acceleration in micro-Gs
302+
pub fn convert_acc_to_ugs(acc_in: i16, full_scale: Control6FullScale) -> f32 {
303+
let acc: f32 = acc_in as f32;
304+
let factor: f32 = match full_scale {
305+
Control6FullScale::Scale2g => 1_000_000f32 / 16384f32,
306+
Control6FullScale::Scale4g => 1_000_000f32 / 8192f32,
307+
Control6FullScale::Scale8g => 1_000_000f32 / 4096f32,
308+
Control6FullScale::Scale16g => 1_000_000f32 / 2048f32,
309+
};
310+
acc * factor
311+
}
190312
}

0 commit comments

Comments
 (0)