abcd
This commit is contained in:
+125
-16
@@ -3,7 +3,8 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::{Config, bind_interrupts, dma::InterruptHandler, i2c::{self, ErrorInterruptHandler, EventInterruptHandler, I2c}, peripherals::{DMA1_CH1, DMA1_CH2, I2C2}};
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::{Config, bind_interrupts, dma::InterruptHandler, i2c::{self, ErrorInterruptHandler, EventInterruptHandler, I2c, Master}, peripherals::{DMA1_CH1, DMA1_CH2, I2C2}};
|
||||
use embassy_time::Timer;
|
||||
|
||||
use defmt_rtt as _;
|
||||
@@ -15,7 +16,49 @@ bind_interrupts!(struct Irqs {
|
||||
I2C2_3 => EventInterruptHandler<I2C2>, ErrorInterruptHandler<I2C2>;
|
||||
});
|
||||
|
||||
const ADDR: u8 = 0x1A;
|
||||
const SENSOR: u8 = 0x1A;
|
||||
const EEPROM: u8 = 0x1B;
|
||||
|
||||
type Bus = I2c<'static, Async, Master>;
|
||||
|
||||
/// Read a 16-bit word from the sensor EEPROM (read-only sequence, never writes).
|
||||
async fn eeprom_word(i2c: &mut Bus, addr: u16) -> u16 {
|
||||
i2c.write(EEPROM, &[0x09, (addr >> 8) as u8, addr as u8]).await.unwrap(); // SET_ADDRESS
|
||||
i2c.write(EEPROM, &[0x06]).await.unwrap(); // NORMAL_READ
|
||||
let mut b = [0u8; 2];
|
||||
i2c.write_read(EEPROM, &[0x0B], &mut b).await.unwrap(); // GET_DATA
|
||||
i2c.write(EEPROM, &[0x01]).await.unwrap(); // ACTIVE
|
||||
(b[1] as u16) << 8 | b[0] as u16
|
||||
}
|
||||
|
||||
/// Reconstruct a little-endian float stored across two EEPROM words.
|
||||
async fn eeprom_f32(i2c: &mut Bus, lo_addr: u16, hi_addr: u16) -> f32 {
|
||||
let lo = eeprom_word(i2c, lo_addr).await as u32;
|
||||
let hi = eeprom_word(i2c, hi_addr).await as u32;
|
||||
f32::from_bits(hi << 16 | lo)
|
||||
}
|
||||
|
||||
/// Run one conversion with the given configuration byte and read both halves.
|
||||
async fn read_block(i2c: &mut Bus, config: u8) -> ([u8; 130], [u8; 130]) {
|
||||
i2c.write(SENSOR, &[0x01, config]).await.unwrap();
|
||||
let mut status = [0u8; 1];
|
||||
loop {
|
||||
i2c.write_read(SENSOR, &[0x02], &mut status).await.unwrap();
|
||||
if status[0] & 0x01 != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut top = [0u8; 130];
|
||||
let mut bottom = [0u8; 130];
|
||||
i2c.write_read(SENSOR, &[0x0A], &mut top).await.unwrap();
|
||||
i2c.write_read(SENSOR, &[0x0B], &mut bottom).await.unwrap();
|
||||
(top, bottom)
|
||||
}
|
||||
|
||||
/// Pixel `j` (0..63) of a half-block buffer: word0 is PTAT/VDD, pixels start at byte 2.
|
||||
fn px(buf: &[u8; 130], j: usize) -> u16 {
|
||||
(buf[2 * j + 2] as u16) << 8 | buf[2 * j + 3] as u16
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
@@ -26,22 +69,88 @@ async fn main(_spawner: Spawner) {
|
||||
i2c_cfg.scl_pullup = false;
|
||||
let mut i2c = I2c::new(p.I2C2, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2, Irqs, i2c_cfg);
|
||||
|
||||
i2c.write(ADDR, &[0x01, 0x01]).await.unwrap();
|
||||
Timer::after_millis(30).await;
|
||||
// --- read calibration data from EEPROM (read-only) ---
|
||||
let mbit = eeprom_word(&mut i2c, 0x001A).await as u8;
|
||||
let bias = eeprom_word(&mut i2c, 0x001B).await as u8;
|
||||
let clk = eeprom_word(&mut i2c, 0x001C).await as u8;
|
||||
let bpa = eeprom_word(&mut i2c, 0x001D).await as u8;
|
||||
let pu = eeprom_word(&mut i2c, 0x001E).await as u8;
|
||||
let gradscale = eeprom_word(&mut i2c, 0x0008).await as u8;
|
||||
let ptatgr = eeprom_f32(&mut i2c, 0x0034, 0x0035).await;
|
||||
let ptatoff = eeprom_f32(&mut i2c, 0x0036, 0x0037).await;
|
||||
|
||||
// Start a PTAT measurement of block 0 (1<<3 | 1).
|
||||
i2c.write(ADDR, &[0x01, 0x09]).await.unwrap();
|
||||
|
||||
let mut status = [0u8; 1];
|
||||
while {
|
||||
i2c.write_read(ADDR, &[0x02], &mut status).await.unwrap();
|
||||
status[0] & 0x01 == 0
|
||||
} {
|
||||
Timer::after_millis(250).await;
|
||||
// ThGrad and ThOffset (16x16 signed), bottom half is stored row-reversed.
|
||||
let mut thgrad = [[0i16; 16]; 16];
|
||||
let mut thoffset = [[0i16; 16]; 16];
|
||||
for (base, dst) in [(0x0100u16, &mut thgrad), (0x0200u16, &mut thoffset)] {
|
||||
for m in 0..8 {
|
||||
for n in 0..16 {
|
||||
dst[m][n] = eeprom_word(&mut i2c, base + (n + m * 16) as u16).await as i16;
|
||||
}
|
||||
}
|
||||
for k in 0..8 {
|
||||
for n in 0..16 {
|
||||
dst[15 - k][n] = eeprom_word(&mut i2c, base + 128 + (n + k * 16) as u16).await as i16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut data = [0u8; 258];
|
||||
i2c.write_read(ADDR, &[0x0A], &mut data).await.unwrap();
|
||||
// --- wake up sensor and load calibration into trim registers ---
|
||||
i2c.write(SENSOR, &[0x01, 0x01]).await.unwrap();
|
||||
Timer::after_millis(30).await;
|
||||
for (reg, val) in [(0x03, mbit), (0x04, bias), (0x05, bias), (0x06, clk), (0x07, bpa), (0x08, bpa), (0x09, pu)] {
|
||||
i2c.write(SENSOR, &[reg, val]).await.unwrap();
|
||||
Timer::after_millis(5).await;
|
||||
}
|
||||
|
||||
info!("Measurement: {:?}", data);
|
||||
// --- read both pixel blocks (each carries a PTAT value + its pixels) ---
|
||||
let (top0, bot0) = read_block(&mut i2c, 0x09).await; // block 0, PTAT
|
||||
let (top1, bot1) = read_block(&mut i2c, 0x19).await; // block 1, PTAT
|
||||
// --- electrical offset (blind measurement) ---
|
||||
let (eo_top, eo_bot) = read_block(&mut i2c, 0x0B).await;
|
||||
|
||||
// ambient temperature from averaged PTAT (datasheet 11.1)
|
||||
let ptat = |b: &[u8; 130]| (b[0] as u32) << 8 | b[1] as u32;
|
||||
let ptat_av = ((ptat(&top0) + ptat(&top1) + ptat(&bot0) + ptat(&bot1)) / 4) as f32;
|
||||
let ambient_dk = ptat_av * ptatgr + ptatoff;
|
||||
let ambient_c = ambient_dk / 10.0 - 273.15;
|
||||
|
||||
// sort raw pixels into a 16x16 image (datasheet ordering)
|
||||
let mut image = [[0i32; 16]; 16];
|
||||
let gradscale_div = 1i32 << gradscale;
|
||||
for n in 0..16 {
|
||||
let raw = [
|
||||
px(&top0, n), px(&top0, n + 16), px(&top0, n + 32), px(&top0, n + 48),
|
||||
px(&top1, n), px(&top1, n + 16), px(&top1, n + 32), px(&top1, n + 48),
|
||||
px(&bot1, n + 48), px(&bot1, n + 32), px(&bot1, n + 16), px(&bot1, n),
|
||||
px(&bot0, n + 48), px(&bot0, n + 32), px(&bot0, n + 16), px(&bot0, n),
|
||||
];
|
||||
let eo = [
|
||||
px(&eo_top, n), px(&eo_top, n + 16), px(&eo_top, n + 32), px(&eo_top, n + 48),
|
||||
px(&eo_bot, n + 48), px(&eo_bot, n + 32), px(&eo_bot, n + 16), px(&eo_bot, n),
|
||||
];
|
||||
for m in 0..16 {
|
||||
// thermal-offset compensation (11.2) + electrical-offset compensation (11.3)
|
||||
let comp = raw[m] as i32
|
||||
- (thgrad[m][n] as i32 * ptat_av as i32) / gradscale_div
|
||||
- thoffset[m][n] as i32;
|
||||
let eo_row = if m < 8 { m % 4 } else { m % 4 + 4 };
|
||||
image[m][n] = comp - eo[eo_row] as i32;
|
||||
}
|
||||
}
|
||||
|
||||
let mut min = i32::MAX;
|
||||
let mut max = i32::MIN;
|
||||
for row in &image {
|
||||
for &v in row {
|
||||
min = min.min(v);
|
||||
max = max.max(v);
|
||||
}
|
||||
}
|
||||
|
||||
info!("ambient temperature: {} C (PTAT_av={})", ambient_c, ptat_av);
|
||||
info!("compensated image range: {}..{}", min, max);
|
||||
for m in 0..16 {
|
||||
info!("row {}: {}", m, image[m]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user