Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "3"
members = ["lab01", "lab02", "lab03", "lab04", "lab05"]
members = ["lab01", "lab02", "lab03", "lab04", "lab05", "lab06"]

[workspace.dependencies]
# Low level access to Cortex-M processors
Expand Down
8 changes: 8 additions & 0 deletions lab06/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[build]
target = "thumbv8m.main-none-eabihf"

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip STM32U545RETxQ"

[env]
DEFMT_LOG = "debug"
32 changes: 32 additions & 0 deletions lab06/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "lab06"
version = "0.1.0"
edition = "2024"

[dependencies]
# Low level access to Cortex-M processors
cortex-m.workspace = true
# Boostrap crate for Cortex-M Processors
cortex-m-rt.workspace = true
# Defmt support
defmt.workspace = true
defmt-rtt.workspace = true
# Embedded HAL utilities
embassy-embedded-hal.workspace = true
# Async/await executor
embassy-executor.workspace = true
# Utilities for working with futures, compatible with no_std and not using alloc
embassy-futures.workspace = true
# STM32 HAL Implementation
embassy-stm32.workspace = true
# Synchronization primitives and data structures with async support
embassy-sync.workspace = true
# Timekeeping, delays and timeouts
embassy-time.workspace = true
embedded-graphics = "0.8.1"
embedded-hal = "1.0.0"
embedded-hal-async = "1.0.0"
heapless = "0.9.2"
mipidsi = "0.9.0"
# Panic handler that exits `probe-run` with an error code
panic-probe.workspace = true
46 changes: 46 additions & 0 deletions lab06/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.

// use std::env;
// use std::fs::File;
// use std::io::Write;
// use std::path::PathBuf;

fn main() {
// This section is not needed as the `embassy-stm32` crate
// provides `memory.x` and adds it to the linker's path.
//
// If using a crate that does not provide it, please
// uncomment the this section and the related imported
// items.

// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
// let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
// File::create(out.join("memory.x"))
// .unwrap()
// .write_all(include_bytes!("memory.x"))
// .unwrap();
// println!("cargo:rustc-link-search={}", out.display());

// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
// println!("cargo:rerun-if-changed=memory.x");

// Prevent the linker from page aligning segments
println!("cargo:rustc-link-arg-bins=--nmagic");

// Required for `cortex-m`
println!("cargo:rustc-link-arg-bins=-Tlink.x");
// Required for `defmt`
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
53 changes: 53 additions & 0 deletions lab06/src/bin/ex1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#![no_std]
#![no_main]

use defmt::info;
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_stm32::{
bind_interrupts,
i2c::{self, I2c},
peripherals,
};
use panic_probe as _;

bind_interrupts!(struct Irqs {
I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
});

const LOWEST_I2C_ADDR: u8 = 0x08;
const HIGHEST_I2C_ADDR: u8 = 0x77;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(Default::default());
info!("Device started");

// I2C pins
let sda = peripherals.PB7;
let scl = peripherals.PB6;

// I2C definition
let mut i2c = I2c::new(
peripherals.I2C1,
scl,
sda,
Irqs,
peripherals.GPDMA1_CH0,
peripherals.GPDMA1_CH1,
Default::default(),
);

for addr in LOWEST_I2C_ADDR..=HIGHEST_I2C_ADDR {
let mut rx_buf = [0x00u8; 1];
let res = i2c.write_read(addr, &[0x00], &mut rx_buf).await;
info!(
"Result for address 0x{:02x}: {:?} | Data: {:?}",
addr, res, rx_buf
);
}

#[allow(clippy::empty_loop)]
loop {}
}
96 changes: 96 additions & 0 deletions lab06/src/bin/ex2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#![no_std]
#![no_main]

use defmt::info;
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_stm32::{
bind_interrupts,
i2c::{self, I2c},
peripherals,
};
use embassy_time::Timer;
use panic_probe as _;

bind_interrupts!(struct Irqs {
I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
});

// Note: A0 must be hooked to low, otherwise the address is 0x77
const BMP390_ADDR: u8 = 0x76;

const REGISTER_PWR_CTRL: u8 = 0x1B;
const PWR_MODE_ON: u8 = 0b0011_0000;
const PWR_TEMP_EN: u8 = 0b0000_0010;
const PWR_VAL: u8 = PWR_MODE_ON | PWR_TEMP_EN;

const REGISTER_OSR: u8 = 0x1C;
const OSR_TEMP_X2: u8 = 0b0000_1000;
const OSR_VAL: u8 = OSR_TEMP_X2;

const REGISTER_TEMP_XLSB: u8 = 0x07;
const REGISTER_TEMP_LSB: u8 = 0x08;
const REGISTER_TEMP_MSB: u8 = 0x09;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(Default::default());
info!("Device started");

// I2C pins
let sda = peripherals.PB7;
let scl = peripherals.PB6;

// I2C definition
let mut i2c = I2c::new(
peripherals.I2C1,
scl,
sda,
Irqs,
peripherals.GPDMA1_CH0,
peripherals.GPDMA1_CH1,
Default::default(),
);

i2c.write(BMP390_ADDR, &[REGISTER_PWR_CTRL, PWR_VAL])
.await
.unwrap();

i2c.write(BMP390_ADDR, &[REGISTER_OSR, OSR_VAL])
.await
.unwrap();

loop {
let mut raw_temp_data = [0u8; 3];
i2c.write_read(BMP390_ADDR, &[REGISTER_TEMP_XLSB], &mut raw_temp_data)
.await
.unwrap();

let mut raw_xlsb = [0u8; 1];
let mut raw_lsb = [0u8; 1];
let mut raw_msb = [0u8; 1];
i2c.write_read(BMP390_ADDR, &[REGISTER_TEMP_XLSB], &mut raw_xlsb)
.await
.unwrap();
i2c.write_read(BMP390_ADDR, &[REGISTER_TEMP_LSB], &mut raw_lsb)
.await
.unwrap();
i2c.write_read(BMP390_ADDR, &[REGISTER_TEMP_MSB], &mut raw_msb)
.await
.unwrap();

info!("Raw data: {:?}", raw_temp_data);
info!(
"Raw byte by byte: {:?}",
[raw_xlsb[0], raw_lsb[0], raw_msb[0]]
);

let raw_temp: i32 = ((raw_temp_data[2] as i32) << 16)
| ((raw_temp_data[1] as i32) << 8)
| (raw_temp_data[0] as i32);
info!("Raw temperature value: {}", raw_temp);

Timer::after_millis(400).await;
}
}
93 changes: 93 additions & 0 deletions lab06/src/bin/ex3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#![no_std]
#![no_main]

use defmt::info;
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_stm32::{
bind_interrupts,
i2c::{self, I2c},
peripherals,
};
use embassy_time::Timer;
use panic_probe as _;

bind_interrupts!(struct Irqs {
I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
});

// Note: A0 must be hooked to low, otherwise the address is 0x77
const BMP390_ADDR: u8 = 0x76;

const REGISTER_PWR_CTRL: u8 = 0x1B;
const PWR_MODE_ON: u8 = 0b0011_0000;
const PWR_TEMP_EN: u8 = 0b0000_0010;
const PWR_VAL: u8 = PWR_MODE_ON | PWR_TEMP_EN;

const REGISTER_OSR: u8 = 0x1C;
const OSR_TEMP_X2: u8 = 0b0000_1000;
const OSR_VAL: u8 = OSR_TEMP_X2;

const REGISTER_TEMP_XLSB: u8 = 0x07;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(Default::default());
info!("Device started");

// I2C pins
let sda = peripherals.PB7;
let scl = peripherals.PB6;

// I2C definition
let mut i2c = I2c::new(
peripherals.I2C1,
scl,
sda,
Irqs,
peripherals.GPDMA1_CH0,
peripherals.GPDMA1_CH1,
Default::default(),
);

i2c.write(BMP390_ADDR, &[REGISTER_PWR_CTRL, PWR_VAL])
.await
.unwrap();

i2c.write(BMP390_ADDR, &[REGISTER_OSR, OSR_VAL])
.await
.unwrap();

// Mock calibration parameters
let nvm_par_t1: u16 = 27504;
let nvm_par_t2: u16 = 26435;
let nvm_par_t3: i8 = -50;

let par_t1 = (nvm_par_t1 as f32) / 0.00390625; // 2^-8
let par_t2 = (nvm_par_t2 as f32) / 1073741824.0; // 2^30
let par_t3 = (nvm_par_t3 as f32) / 281474976710656.0; // 2^48

loop {
let mut raw_temp_data = [0u8; 3];
i2c.write_read(BMP390_ADDR, &[REGISTER_TEMP_XLSB], &mut raw_temp_data)
.await
.unwrap();

let raw_temp: i32 = ((raw_temp_data[2] as i32) << 16)
| ((raw_temp_data[1] as i32) << 8)
| (raw_temp_data[0] as i32);
info!("Raw temperature value: {}", raw_temp);

// Based on Appendix 8.5: Temperature compensation
// `raw_temp` is the u32 value read from registers 0x07..0x09
let partial_data1 = (raw_temp as f32) - par_t1;
let partial_data2 = partial_data1 * par_t2;

// t_lin is the compensated temperature in degrees Celsius
let t_lin = partial_data2 + (partial_data1 * partial_data1) * par_t3;

info!("Compensated temperature value: {} °C", t_lin);
Timer::after_millis(400).await;
}
}
Loading
Loading