1use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
37use embassy_stm32::exti::ExtiInput;
38use embassy_stm32::gpio::Output;
39use embassy_stm32::mode::Async;
40use embassy_stm32::spi;
41use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
42use embassy_sync::signal::Signal;
43use embassy_time::Duration;
44use embassy_time::Timer;
45use embassy_time::with_timeout;
46use embedded_hal_async::spi::SpiDevice as _;
47
48use crate::synch_at;
49use veloxity_core::errors;
50use veloxity_core::packets;
51
52const SPI_READ: u8 = 0x80;
54const SPI_WRITE: u8 = 0x00;
55
56const OFFSET_REG: u8 = 0x45;
58const WHO_AM_I_REG: u8 = 0x4F;
59
60const CFG_REG_A: u8 = 0x60;
61const CFG_REG_B: u8 = 0x61;
62const CFG_REG_C: u8 = 0x62;
63const INT_CTRL_REG: u8 = 0x63;
64const INT_SOURCE_REG: u8 = 0x64;
65const INT_THS_L_REG: u8 = 0x65;
66const INT_THS_H_REG: u8 = 0x66;
67const STATUS_REG: u8 = 0x67;
68const OUT_TEMP: u8 = 0x6E;
69
70const WHO_AM_I: u8 = 0x40;
72
73pub static MAG_SIGNAL: Signal<
74 CriticalSectionRawMutex,
75 Result<packets::MagPacket, errors::SensorError>,
76> = Signal::<CriticalSectionRawMutex, Result<packets::MagPacket, errors::SensorError>>::new();
77
78pub struct Iis2mdcSensor {
79 pub dev: SpiDevice<
80 'static,
81 CriticalSectionRawMutex,
82 spi::Spi<'static, Async, spi::mode::Master>,
83 Output<'static>,
84 >,
85 pub drdy: ExtiInput<'static, Async>,
86}
87
88impl Iis2mdcSensor {
89 async fn read_register(&mut self, reg_addr: u8) -> Result<u8, errors::SensorError> {
90 let tx = [reg_addr | SPI_READ, 0x00];
91 let mut rx = [0u8; 2];
92 self.dev.transfer(&mut rx, &tx).await.map_err(|e| match e {
93 _ => errors::SensorError::GenericSensorError("SPI failed: read_register"),
94 })?;
95 Ok(rx[1])
96 }
97
98 async fn write_register(&mut self, reg_addr: u8, value: u8) -> Result<(), errors::SensorError> {
99 let tx = [reg_addr | SPI_WRITE, value];
100 self.dev.write(&tx).await.map_err(|e| match e {
102 _ => errors::SensorError::GenericSensorError("SPI failed: write_register"),
103 })?;
104 Ok(())
105 }
106
107 async fn initialize_sensor(&mut self) -> Result<u8, errors::SensorError> {
108 let who_am_i = self.read_register(WHO_AM_I_REG).await?;
110 if who_am_i == WHO_AM_I {
111 } else {
112 return Err(errors::SensorError::GenericSensorError(
113 "IIS2MDC Chip ID mismatch",
114 ));
115 }
116
117 self.write_register(CFG_REG_A, 0x20).await?;
126 Timer::after_micros(10).await; self.write_register(CFG_REG_A, 0x40).await?;
128 Timer::after_micros(21).await; self.write_register(CFG_REG_A, 0x83).await?;
145
146 self.write_register(CFG_REG_B, 0x12).await?;
156
157 self.write_register(CFG_REG_C, 0x31).await?;
170
171 self.write_register(INT_CTRL_REG, 0x00).await?;
174 self.write_register(INT_SOURCE_REG, 0x00).await?;
175 self.write_register(INT_THS_L_REG, 0x00).await?;
176 self.write_register(INT_THS_H_REG, 0x00).await?;
177
178 let status = self.read_register(STATUS_REG).await?;
180
181 let mut offset = [0u8; 7];
183 self.dev
184 .transfer(&mut offset, &[OFFSET_REG | SPI_READ, 0, 0, 0, 0, 0, 0])
185 .await
186 .map_err(|e| match e {
187 _ => errors::SensorError::GenericSensorError("SPI failed: initialize_sensor"),
188 })?;
189
190 let _offset = [
191 (((offset[1] as u16) | (offset[2] as u16) << 8) as i16) * 3 / 2,
192 (((offset[3] as u16) | (offset[4] as u16) << 8) as i16) * 3 / 2,
193 (((offset[5] as u16) | (offset[6] as u16) << 8) as i16) * 3 / 2,
194 ];
195
196 Ok(status)
197 }
198
199 async fn get_flux_and_temperature_data(
200 &mut self,
201 ) -> Result<(u16, [u8; 8], [u8; 3]), errors::SensorError> {
202 self.write_register(CFG_REG_A, 0x81).await?;
204
205 let _drdy_result = with_timeout(
207 Duration::from_micros(9_600),
208 self.drdy.wait_for_rising_edge(),
209 )
210 .await
211 .is_ok();
212
213 let mut flux_data = [0u8; 8];
214 self.dev
216 .transfer(
217 &mut flux_data,
218 &[STATUS_REG | SPI_READ, 0, 0, 0, 0, 0, 0, 0],
219 )
220 .await
221 .map_err(|e| match e {
222 _ => errors::SensorError::GenericSensorError(
223 "SPI failed: get_flux_and_temperature_data",
224 ),
225 })?;
226
227 let mut raw_temperature = [0u8; 3];
228 self.dev
229 .transfer(&mut raw_temperature, &[OUT_TEMP | SPI_READ, 0, 0])
230 .await
231 .map_err(|e| match e {
232 _ => errors::SensorError::GenericSensorError(
233 "SPI failed: get_flux_and_temperature_data",
234 ),
235 })?;
236
237 let status = flux_data[1] as u16;
238 Ok((status, flux_data, raw_temperature))
239 }
240
241 fn process_flux_data(&self, flux_data: [u8; 8], flux_previous: &mut [i16; 3]) -> [f32; 3] {
242 let raw_flux = [
243 ((flux_data[2] as u16) | ((flux_data[3] as u16) << 8)) as i16,
244 ((flux_data[4] as u16) | ((flux_data[5] as u16) << 8)) as i16,
245 ((flux_data[6] as u16) | ((flux_data[7] as u16) << 8)) as i16,
246 ];
247
248 let flux = [
249 -f32::from(raw_flux[0] + flux_previous[0]) / 2. * 1.5e-7, f32::from(raw_flux[1] + flux_previous[1]) / 2. * 1.5e-7,
251 f32::from(raw_flux[2] + flux_previous[2]) / 2. * 1.5e-7,
252 ];
253
254 *flux_previous = raw_flux;
255
256 flux
257 }
258
259 fn process_temperature_data(&self, raw_temperature: [u8; 3]) -> f32 {
260 let temperature =
261 f32::from(((raw_temperature[1] as u16) | ((raw_temperature[2] as u16) << 8)) as i16)
262 / 8.0
263 + 25.0;
264 temperature
265 }
266
267 pub async fn run(&mut self) {
268 let _status = match self.initialize_sensor().await {
269 Ok(status) => status,
270 Err(e) => {
271 MAG_SIGNAL.signal(Err(e));
272 return;
273 }
274 };
275
276 let mut flux_previous = [0_i16; 3];
277 let sample_period = Duration::from_hz(100);
278
279 loop {
280 let timestamp = synch_at(sample_period);
281 Timer::at(timestamp).await;
282
283 let (status, flux_data, raw_temperature) =
285 match self.get_flux_and_temperature_data().await {
286 Ok(data) => data,
287 Err(e) => {
288 MAG_SIGNAL.signal(Err(e));
289 continue;
290 }
291 };
292
293 if status == 0x000F {
294 let flux = self.process_flux_data(flux_data, &mut flux_previous);
295 let temperature = self.process_temperature_data(raw_temperature);
296
297 let header = packets::RosflightPacketHeader {
298 timestamp: timestamp.as_micros(),
299 status,
300 };
301 let mag_packet = packets::MagPacket {
302 header,
303 flux,
304 temperature,
305 };
306 MAG_SIGNAL.signal(Ok(mag_packet)); } else {
308 MAG_SIGNAL.signal(Err(errors::SensorError::GenericSensorError("Bad Status")));
309 }
310 }
311 }
312}
313
314#[embassy_executor::task]
315pub async fn task(mut iis: Iis2mdcSensor) {
316 iis.run().await;
317}