Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNS - I2C Temperature (HYPE-14) #12

Merged
merged 28 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
118a39a
Create outline for I2C and temperature sensor
davidbeechey Aug 21, 2024
4214a39
Merge branch 'main' into sns-i2c_temp
davidbeechey Sep 5, 2024
4b34448
Hmm trying to fix I2C problems...
davidbeechey Sep 5, 2024
4ef0cab
Fix hyped_core commit pin and read_data
kshxtij Sep 5, 2024
0d56c07
Working I2C temp sensor implementation :)
davidbeechey Sep 5, 2024
156b4ac
Finish I2C temperature sensor implementation
davidbeechey Sep 5, 2024
770c3c0
Fix typo
davidbeechey Sep 5, 2024
bf33456
Remove duplicated code
davidbeechey Sep 10, 2024
49d0ac7
Pass `TemperatureAddresses` value as an argument
davidbeechey Sep 12, 2024
4821cad
Update cargo.toml to trigger CI
davidbeechey Sep 19, 2024
5d50e56
Merge branch 'main' into sns-i2c_temp
davidbeechey Sep 19, 2024
8a36419
Update Cargo.lock
davidbeechey Sep 19, 2024
c52e441
Update to stop CI breaking
davidbeechey Sep 19, 2024
5877132
Fix typo
davidbeechey Sep 19, 2024
faf8802
Merge branch 'main' into sns-i2c_temp
davidbeechey Oct 3, 2024
47de0b8
try restructuring Cargo workspace
davidbeechey Oct 10, 2024
4fe1d4f
Fix member names
davidbeechey Oct 10, 2024
ec234bc
Add `rustup target add thumbv7em-none-eabihf`
davidbeechey Oct 10, 2024
fbd234b
Temporarily disable CI build+test checks
davidbeechey Oct 13, 2024
cb09711
Merge branch 'main' into sns-i2c_temp
davidbeechey Oct 13, 2024
5ad7cc5
Temporarily disable clippy
davidbeechey Oct 13, 2024
8080207
Restructure `io` and `boards`
davidbeechey Oct 13, 2024
5df95b9
Fix CLRF line endings
davidbeechey Oct 13, 2024
2b149c4
Reenable cargo test
kshxtij Oct 14, 2024
b443d32
Fix all clippy errors
kshxtij Oct 14, 2024
34aacdb
Fix remaining issues
davidbeechey Oct 15, 2024
0bd067f
Merge branch 'main' into sns-i2c_temp
davidbeechey Oct 15, 2024
ceb2ed1
Fix error enums
davidbeechey Oct 15, 2024
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
567 changes: 439 additions & 128 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"lib/*",
"config",
"boards/*",
"lib/*",
"config",
]
resolver = "2"
resolver = "2"
9 changes: 9 additions & 0 deletions boards/i2c_temp_test/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32L476RGTx"

[build]
target = "thumbv7em-none-eabihf"

[env]
DEFMT_LOG = "debug,smoltcp=info"
30 changes: 30 additions & 0 deletions boards/i2c_temp_test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
edition = "2021"
name = "stm-i2c-temp-test-board"
version = "0.1.0"

[dependencies]
embassy-stm32 = { version = "0.1.0", features = ["defmt", "stm32l476rg", "memory-x", "unstable-pac", "time-driver-any", "exti"] , git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}
embassy-sync = { version = "0.6.0", features = ["defmt"], git = "https://github.com/embassy-rs/embassy"}
embassy-executor = { version = "0.6.0", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}
embassy-time = { version = "0.3.1", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}
embassy-net = { version = "0.4.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}
embassy-futures = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}

defmt = "0.3"
defmt-rtt = "0.4"

cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6"
panic-probe = { version = "0.3", features = ["print-defmt"] }
rand_core = "0.6.3"
critical-section = "1.1"
embedded-storage = "0.3.1"
static_cell = "2"

hyped_io_stm32l476rg = { path = "../../lib/io/stm32l476rg" }
hyped_sensors = { path = "../../lib/sensors" }

[profile.release]
debug = 2
5 changes: 5 additions & 0 deletions boards/i2c_temp_test/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
61 changes: 61 additions & 0 deletions boards/i2c_temp_test/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#![no_std]
#![no_main]

use core::panic;
use embassy_executor::Spawner;
use embassy_stm32::i2c::I2c;
use embassy_stm32::time::Hertz;
use embassy_time::{Duration, Timer};
use hyped_io_stm32l476rg::i2c::Stm32l476rgI2c;
use hyped_sensors::temperature::{Status, Temperature};
use {defmt_rtt as _, panic_probe as _};

/// Test task that just reads the temperature from the sensor and prints it to the console
#[embassy_executor::task]
async fn temp() -> ! {
let p = embassy_stm32::init(Default::default());
let i2c = I2c::new_blocking(p.I2C1, p.PB8, p.PB9, Hertz(100_000), Default::default());
let hyped_i2c = Stm32l476rgI2c::new(i2c);

let mut temperature_sensor = Temperature::new(hyped_i2c).expect(
"Failed to create temperature sensor. Check the wiring and the I2C address of the sensor.",
);

loop {
match temperature_sensor.check_status() {
Status::TempOverUpperLimit => {
defmt::error!("Temperature is over the upper limit.");
}
Status::TempUnderLowerLimit => {
defmt::error!("Temperature is under the lower limit.");
}
Status::Busy => {
defmt::warn!("Temperature sensor is busy.");
}
Status::Unknown => {
panic!("Could not get the status of the temperature sensor.")
}
Status::Ok => {}
}

match temperature_sensor.read() {
Some(temperature) => {
defmt::info!("Temperature: {:?}", temperature);
}
None => {
defmt::info!("Failed to read temperature.");
}
}
}
}

#[embassy_executor::main]
async fn main(spawner: Spawner) -> ! {
spawner.spawn(temp()).unwrap();

// Some other tasks...

loop {
Timer::after(Duration::from_secs(1)).await;
}
}
2 changes: 1 addition & 1 deletion lib/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ rust-mqtt = { version = "0.3.0", default-features = false, features = ["defmt"]
embedded-io-async = { version = "0.6.1" }
rand_core = "0.6.3"
serde = { version = "1.0", default-features = false, features = ["derive"] }
embassy-net = { version = "0.4.0", default-features = false, features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
embassy-net = { version = "0.4.0", default-features = false, features = ["defmt", "tcp", "proto-ipv4", "medium-ip"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}

[features]
std = []
19 changes: 18 additions & 1 deletion lib/core/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum DigitalSignal {
High,
Low,
Expand All @@ -13,3 +13,20 @@ impl DigitalSignal {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_from_bool() {
assert_eq!(DigitalSignal::from_bool(true), DigitalSignal::High);
assert_eq!(DigitalSignal::from_bool(false), DigitalSignal::Low);
}
}

#[derive(Debug)]
pub enum Status {
Ready,
NotReady,
}
7 changes: 7 additions & 0 deletions lib/io/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "hyped_io"
version = "0.1.0"
edition = "2021"

[dependencies]
heapless = "0.8.0"
10 changes: 10 additions & 0 deletions lib/io/src/i2c.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// I2C trait used to abstract the I2C peripheral
pub trait HypedI2c {
fn read_byte(&mut self, device_address: u8, register_address: u8) -> Option<u8>;
fn write_byte_to_register(
&mut self,
device_address: u8,
register_address: u8,
data: u8,
) -> Result<(), ()>;
}
3 changes: 3 additions & 0 deletions lib/io/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![no_std]

pub mod i2c;
9 changes: 9 additions & 0 deletions lib/io/stm32l476rg/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "hyped_io_stm32l476rg"
version = "0.1.0"
edition = "2021"

[dependencies]
embassy-stm32 = { version = "0.1.0", features = ["defmt", "stm32l476rg", "memory-x", "unstable-pac", "time-driver-any", "exti"] , git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"}

hyped_io = { path = "../" }
43 changes: 43 additions & 0 deletions lib/io/stm32l476rg/src/i2c.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use embassy_stm32::{i2c::I2c, mode::Blocking};
use hyped_io::i2c::HypedI2c;

pub struct Stm32l476rgI2c<'d> {
i2c: I2c<'d, Blocking>,
}

impl<'d> HypedI2c for Stm32l476rgI2c<'d> {
/// Read a byte from a register on a device
fn read_byte(&mut self, device_address: u8, register_address: u8) -> Option<u8> {
let mut read = [0];
let result =
self.i2c
.blocking_write_read(device_address, [register_address].as_ref(), &mut read);
match result {
Ok(_) => Some(read[0]),
Err(_) => None,
}
}

/// Write a byte to a register on a device
fn write_byte_to_register(
&mut self,
device_addres: u8,
register_address: u8,
data: u8,
) -> Result<(), ()> {
let result = self
.i2c
.blocking_write(device_addres, [register_address, data].as_ref());
match result {
Ok(_) => Ok(()),
Err(_) => Err(()),
}
}
}

impl<'d> Stm32l476rgI2c<'d> {
/// Create a new instance of our I2C implementation for the STM32L476RG
pub fn new(i2c: I2c<'d, Blocking>) -> Self {
Self { i2c }
}
}
3 changes: 3 additions & 0 deletions lib/io/stm32l476rg/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![no_std]

pub mod i2c;
10 changes: 10 additions & 0 deletions lib/sensors/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "hyped_sensors"
version = "0.1.0"
edition = "2021"

[dependencies]
heapless = "0.8.0"

hyped_io = { path = "../io" }
# hyped_core = { path = "../core" }
3 changes: 3 additions & 0 deletions lib/sensors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![no_std]

pub mod temperature;
122 changes: 122 additions & 0 deletions lib/sensors/src/temperature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use hyped_io::i2c::HypedI2c;

/// Temperature implements the logic to read the temperature from the STTS22H temperature sensor
/// using the I2C peripheral provided by the HypedI2c trait. The temperature sensor is configured
/// to continuous mode with a sampling rate of 200Hz. The temperature is read from the sensor and
/// converted to a floating point value in degrees Celsius.
///
/// Data sheet: https://www.st.com/resource/en/datasheet/stts22h.pdf
pub struct Temperature<T: HypedI2c> {
i2c: T,
device_address: u8,
}

impl<T: HypedI2c> Temperature<T> {
/// Create a new instance of the temperature sensor and attempt to configure it
pub fn new(mut i2c: T) -> Result<Self, ()> {
// Set up the temperature sensor by sending the configuration settings to the STTS22H_CTRL register
match i2c.write_byte_to_register(
TemperatureAddresses::Address3f as u8,
STTS22H_CTRL,
STTS22H_CONFIG_SETTINGS,
) {
Ok(_) => Ok(Self {
i2c,
device_address: TemperatureAddresses::Address3f as u8,
}),
Err(_) => Err(()),
}
}

/// Read the temperature from the sensor and return it as a floating point value in degrees Celsius
pub fn read(&mut self) -> Option<f32> {
// Set up the temperature sensor by sending the configuration settings to the STTS22H_CTRL register
let write_result = self.i2c.write_byte_to_register(
self.device_address,
STTS22H_CTRL,
STTS22H_CONFIG_SETTINGS,
);
if write_result.is_err() {
return None;
}

// Read the high and low bytes of the temperature and combine them to get the temperature
let temperature_high_byte =
match self.i2c.read_byte(self.device_address, STTS22H_DATA_TEMP_H) {
Some(byte) => byte,
None => {
return None;
}
};
let temperature_low_byte =
match self.i2c.read_byte(self.device_address, STTS22H_DATA_TEMP_L) {
Some(byte) => byte,
None => {
return None;
}
};
let combined = ((temperature_high_byte as u16) << 8 | temperature_low_byte as u16) as f32;
let temperature = combined * STTS22H_TEMP_SCALING_FACTOR;

Some(temperature)
}

/// Check the status of the temperature sensor
pub fn check_status(&mut self) -> Status {
return match self.i2c.read_byte(self.device_address, STTS22H_STATUS) {
Some(byte) => Status::from_byte(byte),
None => Status::Unknown,
};
}
}

/// Represents the possible I2C addresses for the STTS22H temperature sensor
#[repr(u8)]
enum TemperatureAddresses {
Address3f = 0x3f,
// Other possible addresses
#[allow(dead_code)]
Address38 = 0x38,
#[allow(dead_code)]
Address3c = 0x3c,
#[allow(dead_code)]
Address3e = 0x3e,
}

/// Represents the possible statuses of the temperature sensor
pub enum Status {
Busy,
TempOverUpperLimit,
TempUnderLowerLimit,
Ok,
Unknown,
}

impl Status {
/// Convert a byte read from the STTS22H_STATUS register to a Status enum
pub fn from_byte(byte: u8) -> Self {
match byte {
STTS22H_STATUS_BUSY => Self::Busy,
STTS22H_TEMP_OVER_UPPER_LIMIT => Self::TempOverUpperLimit,
STTS22H_TEMP_UNDER_LOWER_LIMIT => Self::TempUnderLowerLimit,
_ => Self::Ok,
}
}
}

// Registers for the STTS22H temperature sensor
const STTS22H_CTRL: u8 = 0x04;
const STTS22H_DATA_TEMP_L: u8 = 0x06;
const STTS22H_DATA_TEMP_H: u8 = 0x07;
const STTS22H_STATUS: u8 = 0x05;

// Values to check the status of the temperature sensor from the STTS22H_STATUS register
const STTS22H_STATUS_BUSY: u8 = 0x01;
const STTS22H_TEMP_OVER_UPPER_LIMIT: u8 = 0x02;
const STTS22H_TEMP_UNDER_LOWER_LIMIT: u8 = 0x04;

// These settings set the sensor to continuous mode, sets IF_ADD_INC, and sets the sampling rate to 200Hz
const STTS22H_CONFIG_SETTINGS: u8 = 0x3c;

// Scaling factor to convert the temperature from the sensor to degrees Celsius
const STTS22H_TEMP_SCALING_FACTOR: f32 = 0.01;