stm_32/peripherals/
ist8308.rs1pub use embassy_stm32::mode::Async;
37pub use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
38pub use embassy_sync::signal::Signal;
39use veloxity_core::{errors, packets};
40
41use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
43use embassy_stm32::i2c::I2c;
44use embedded_hal_async::i2c::I2c as _;
45
46use crate::synch_at;
48use embassy_time::Duration;
49use embassy_time::Timer;
50
51pub static MAG_SIGNAL: Signal<
54 CriticalSectionRawMutex,
55 Result<packets::MagPacket, errors::SensorError>,
56> = Signal::<CriticalSectionRawMutex, Result<packets::MagPacket, errors::SensorError>>::new();
57
58fn publish_mag(result: Result<packets::MagPacket, errors::SensorError>) {
59 #[cfg(feature = "runtime-diagnostics")]
60 crate::runtime_diagnostics::record_signal_publish(
61 crate::runtime_diagnostics::SensorKind::Mag,
62 MAG_SIGNAL.signaled(),
63 result.is_err(),
64 );
65 MAG_SIGNAL.signal(result);
66}
67
68const ROSFLIGHT_C_SCALE_X_T_PER_LSB: f32 = 1.515e-7;
74const ROSFLIGHT_C_SCALE_YZ_T_PER_LSB: f32 = 1.1515e-7;
75
76pub struct Ist8308Sensor {
77 pub dev: I2cDevice<
78 'static,
79 CriticalSectionRawMutex,
80 I2c<'static, Async, embassy_stm32::i2c::mode::Master>,
81 >,
82}
83
84impl Ist8308Sensor {
85 async fn write_read(
86 &mut self,
87 address: u8,
88 register: &[u8],
89 data: &mut [u8],
90 ) -> Result<(), ()> {
91 match self.dev.write(address, register).await {
92 Err(_e) => return Err(()),
93 Ok(_) => {}
94 }
95
96 Timer::after(Duration::from_micros(0)).await;
97
98 match self.dev.read(address, data).await {
100 Err(_e) => return Err(()),
101 Ok(_) => {}
102 }
103
104 Ok(())
105 }
106
107 pub async fn run(&mut self) {
108 const ADDRESS: u8 = 0x0C;
109
110 const WAI_REG: u8 = 0x00;
113 let mut device_id = [0u8; 1];
114 if self
115 .write_read(ADDRESS, &[WAI_REG], &mut device_id)
116 .await
117 .is_err()
118 {
119 publish_mag(Err(errors::SensorError::GenericSensorError(
120 "IST8308 Mag failed: reading WAI_REG",
121 )));
122 return;
123 }
124 const DEVICE_ID: u8 = 0x08;
125 if device_id[0] != DEVICE_ID {
126 publish_mag(Err(errors::SensorError::GenericSensorError(
127 "IST8308 Mag failed: bad device ID",
128 )));
129 return;
130 }
131
132 const CNTL3_REG: u8 = 0x32;
135 const CNTL3_VAL_SRST: u8 = 1;
136 if self
137 .dev
138 .write(ADDRESS, &[CNTL3_REG, CNTL3_VAL_SRST])
139 .await
140 .is_err()
141 {
142 publish_mag(Err(errors::SensorError::GenericSensorError(
143 "IST8308 Mag failed: writing CNTL3_REG",
144 )));
145 return;
146 }
147 Timer::after(Duration::from_millis(20)).await; let mut cntrl3 = [0u8; 1];
151 if self
152 .write_read(ADDRESS, &[CNTL3_REG], &mut cntrl3)
153 .await
154 .is_err()
155 {
156 publish_mag(Err(errors::SensorError::GenericSensorError(
157 "IST8308 Mag failed: reading CNTL3_REG",
158 )));
159 return;
160 }
161 if (cntrl3[0] & 0x01) != 0 {
162 publish_mag(Err(errors::SensorError::GenericSensorError(
163 "IST8308 Mag failed: bad status CNTL3_REG",
164 )));
165 return;
166 }
167
168 const CNTL4_REG: u8 = 0x34;
173 const CNTL4_VAL_DYNAMIC_RANGE_500: u8 = 0;
174
175 if self
176 .dev
177 .write(ADDRESS, &[CNTL4_REG, CNTL4_VAL_DYNAMIC_RANGE_500])
178 .await
179 .is_err()
180 {
181 publish_mag(Err(errors::SensorError::GenericSensorError(
182 "IST8308 Mag failed: writing CNTL4_REG",
183 )));
184 return;
185 }
186
187 const OSRCNTL_REG: u8 = 0x41;
188 const OSRCNTL_VAL_Y_16: u8 = 4 << 3;
189 const OSRCNTL_VAL_XZ_16: u8 = 4;
190
191 if self
192 .dev
193 .write(
194 ADDRESS,
195 &[OSRCNTL_REG, OSRCNTL_VAL_Y_16 | OSRCNTL_VAL_XZ_16],
196 )
197 .await
198 .is_err()
199 {
200 publish_mag(Err(errors::SensorError::GenericSensorError(
201 "IST8308 Mag failed: writing OSRCNTL_REG",
202 )));
203 return;
204 }
205
206 const CNTL2_REG: u8 = 0x31;
210 const CNTL2_VAL_SINGLE_MODE: u8 = 0x01;
211 if self
212 .dev
213 .write(ADDRESS, &[CNTL2_REG, CNTL2_VAL_SINGLE_MODE])
214 .await
215 .is_err()
216 {
217 publish_mag(Err(errors::SensorError::GenericSensorError(
218 "IST8308 Mag failed: writing CNTL2_REG",
219 )));
220 return;
221 }
222
223 const STAT1_REG: u8 = 0x10;
224 const STAT1_VAL_DRDY: u8 = 0x01;
225 let loop_period = Duration::from_hz(100);
226 loop {
227 let period_start = synch_at(loop_period);
230 Timer::at(period_start).await;
231
232 if self
233 .dev
234 .write(ADDRESS, &[CNTL2_REG, CNTL2_VAL_SINGLE_MODE])
235 .await
236 .is_err()
237 {
238 #[cfg(feature = "runtime-diagnostics")]
239 crate::runtime_diagnostics::record_mag_i2c_error();
240 publish_mag(Err(errors::SensorError::GenericSensorError(
241 "IST8308 Mag failed: commanding single conversion",
242 )));
243 continue;
244 }
245 #[cfg(feature = "runtime-diagnostics")]
246 crate::runtime_diagnostics::record_mag_conversion_command();
247
248 let timestamp = period_start + Duration::from_micros(8_900);
249 Timer::at(timestamp).await;
250 if self.dev.write(ADDRESS, &[STAT1_REG]).await.is_err() {
251 #[cfg(feature = "runtime-diagnostics")]
252 crate::runtime_diagnostics::record_mag_i2c_error();
253 publish_mag(Err(errors::SensorError::GenericSensorError(
254 "IST8308 Mag failed: selecting STAT1_REG",
255 )));
256 continue;
257 }
258
259 Timer::at(period_start + Duration::from_micros(9_200)).await;
260
261 let mut data = [0u8; 7];
263 if self.dev.read(ADDRESS, &mut data).await.is_err() {
264 #[cfg(feature = "runtime-diagnostics")]
265 crate::runtime_diagnostics::record_mag_i2c_error();
266 publish_mag(Err(errors::SensorError::GenericSensorError(
267 "IST8308 Mag failed: reading STAT1_REG",
268 )));
269 continue;
270 }
271
272 let status = data[0];
273 let data_ready = status == STAT1_VAL_DRDY;
274 #[cfg(feature = "runtime-diagnostics")]
275 crate::runtime_diagnostics::record_mag_drdy(data_ready);
276 if data_ready {
277 let flux = [
278 f32::from((((data[2] as u16) << 8) | (data[1] as u16)) as i16)
279 * ROSFLIGHT_C_SCALE_X_T_PER_LSB,
280 f32::from((((data[4] as u16) << 8) | (data[3] as u16)) as i16)
281 * ROSFLIGHT_C_SCALE_YZ_T_PER_LSB,
282 -f32::from((((data[6] as u16) << 8) | (data[5] as u16)) as i16)
284 * ROSFLIGHT_C_SCALE_YZ_T_PER_LSB,
285 ]; let timestamp_us = timestamp.as_micros();
288
289 let header = packets::RosflightPacketHeader {
290 timestamp: timestamp_us,
291 status: status as u16,
292 };
293
294 let mag_packet = packets::MagPacket {
295 header,
296 flux,
297 temperature: 0.0f32,
298 };
299 publish_mag(Ok(mag_packet)); }
302 }
303 }
304}
305
306#[embassy_executor::task]
307pub async fn task(mut ist: Ist8308Sensor) {
308 ist.run().await;
309}