From 7a6a70dfc864311120edc375703889fd0ee70a7d Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Sat, 26 Oct 2024 16:41:10 -0400 Subject: [PATCH 01/22] Add adc crate init. --- Cargo.lock | 4 ++++ crates/ads126x/Cargo.toml | 6 ++++++ crates/ads126x/src/lib.rs | 14 ++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 crates/ads126x/Cargo.toml create mode 100644 crates/ads126x/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 205bf6d..101ca2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,10 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ads126x" +version = "0.1.0" + [[package]] name = "atomic-polyfill" version = "1.0.3" diff --git a/crates/ads126x/Cargo.toml b/crates/ads126x/Cargo.toml new file mode 100644 index 0000000..a656335 --- /dev/null +++ b/crates/ads126x/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ads126x" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/crates/ads126x/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From d07ef83b056f31663718b6c790f2f88841e61c5d Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Tue, 29 Oct 2024 22:04:04 -0400 Subject: [PATCH 02/22] WIP: Init driver --- Cargo.lock | 11 ++ boards/pressure/src/data_manager.rs | 4 +- boards/pressure/src/main.rs | 33 ++-- boards/strain/src/data_manager.rs | 4 +- boards/strain/src/main.rs | 33 ++-- boards/temperature/src/data_manager.rs | 4 +- boards/temperature/src/main.rs | 33 ++-- crates/ads126x/Cargo.toml | 19 ++ crates/ads126x/src/error.rs | 4 + crates/ads126x/src/lib.rs | 178 ++++++++++++++++++- crates/ads126x/tests/example.rs | 39 ++++ crates/common-arm/src/lib.rs | 2 +- examples/rtic-playground/src/data_manager.rs | 4 +- examples/rtic-playground/src/main.rs | 33 ++-- 14 files changed, 327 insertions(+), 74 deletions(-) create mode 100644 crates/ads126x/src/error.rs create mode 100644 crates/ads126x/tests/example.rs diff --git a/Cargo.lock b/Cargo.lock index 101ca2d..ff0ed16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,17 @@ version = 3 [[package]] name = "ads126x" version = "0.1.0" +dependencies = [ + "bitflags 2.6.0", + "cortex-m", + "defmt", + "defmt-test", + "embedded-hal 0.2.7", + "heapless 0.7.17", + "nb 1.1.0", + "panic-probe", + "stm32h7xx-hal", +] [[package]] name = "atomic-polyfill" diff --git a/boards/pressure/src/data_manager.rs b/boards/pressure/src/data_manager.rs index 2729860..67b5834 100644 --- a/boards/pressure/src/data_manager.rs +++ b/boards/pressure/src/data_manager.rs @@ -114,7 +114,7 @@ impl DataManager { pub fn handle_data(&mut self, data: Message) { match data.data { messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data{ + messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { messages::sensor::SbgData::EkfNavAcc(_) => { self.ekf_nav_acc = Some(data); } @@ -154,7 +154,7 @@ impl DataManager { messages::sensor::SbgData::GpsPos2(_) => { self.gps_pos_2 = Some(data); } - } + }, messages::sensor::SensorData::RecoverySensing(_) => { self.recovery_sensing = Some(data); } diff --git a/boards/pressure/src/main.rs b/boards/pressure/src/main.rs index d703bc0..2553651 100644 --- a/boards/pressure/src/main.rs +++ b/boards/pressure/src/main.rs @@ -327,9 +327,9 @@ mod app { loop { cx.shared.em.run(|| { let message = Message::new( - cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), COM_ID, messages::state::State::new(messages::state::StateData::Initializing), ); @@ -363,10 +363,13 @@ mod app { stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, }; - let message = - messages::Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, sensor::Sensor::new(x)); + let message = messages::Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + sensor::Sensor::new(x), + ); cx.shared.em.run(|| { spawn!(send_gs, message)?; @@ -385,10 +388,13 @@ mod app { .lock(|data_manager| data_manager.state.clone()); cx.shared.em.run(|| { if let Some(x) = state_data { - let message = - Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, messages::state::State::new(x)); + let message = Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + messages::state::State::new(x), + ); spawn!(send_gs, message)?; } // if there is none we still return since we simply don't have data yet. Ok(()) @@ -442,8 +448,7 @@ mod app { } #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) - { + async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { cx.shared.em.run(|| { cx.shared.rtc.lock(|rtc| { let message = messages::Message::new( @@ -572,4 +577,4 @@ mod app { sbg.set_low(); }); } -} \ No newline at end of file +} diff --git a/boards/strain/src/data_manager.rs b/boards/strain/src/data_manager.rs index 2729860..67b5834 100644 --- a/boards/strain/src/data_manager.rs +++ b/boards/strain/src/data_manager.rs @@ -114,7 +114,7 @@ impl DataManager { pub fn handle_data(&mut self, data: Message) { match data.data { messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data{ + messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { messages::sensor::SbgData::EkfNavAcc(_) => { self.ekf_nav_acc = Some(data); } @@ -154,7 +154,7 @@ impl DataManager { messages::sensor::SbgData::GpsPos2(_) => { self.gps_pos_2 = Some(data); } - } + }, messages::sensor::SensorData::RecoverySensing(_) => { self.recovery_sensing = Some(data); } diff --git a/boards/strain/src/main.rs b/boards/strain/src/main.rs index d703bc0..2553651 100644 --- a/boards/strain/src/main.rs +++ b/boards/strain/src/main.rs @@ -327,9 +327,9 @@ mod app { loop { cx.shared.em.run(|| { let message = Message::new( - cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), COM_ID, messages::state::State::new(messages::state::StateData::Initializing), ); @@ -363,10 +363,13 @@ mod app { stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, }; - let message = - messages::Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, sensor::Sensor::new(x)); + let message = messages::Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + sensor::Sensor::new(x), + ); cx.shared.em.run(|| { spawn!(send_gs, message)?; @@ -385,10 +388,13 @@ mod app { .lock(|data_manager| data_manager.state.clone()); cx.shared.em.run(|| { if let Some(x) = state_data { - let message = - Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, messages::state::State::new(x)); + let message = Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + messages::state::State::new(x), + ); spawn!(send_gs, message)?; } // if there is none we still return since we simply don't have data yet. Ok(()) @@ -442,8 +448,7 @@ mod app { } #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) - { + async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { cx.shared.em.run(|| { cx.shared.rtc.lock(|rtc| { let message = messages::Message::new( @@ -572,4 +577,4 @@ mod app { sbg.set_low(); }); } -} \ No newline at end of file +} diff --git a/boards/temperature/src/data_manager.rs b/boards/temperature/src/data_manager.rs index 2729860..67b5834 100644 --- a/boards/temperature/src/data_manager.rs +++ b/boards/temperature/src/data_manager.rs @@ -114,7 +114,7 @@ impl DataManager { pub fn handle_data(&mut self, data: Message) { match data.data { messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data{ + messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { messages::sensor::SbgData::EkfNavAcc(_) => { self.ekf_nav_acc = Some(data); } @@ -154,7 +154,7 @@ impl DataManager { messages::sensor::SbgData::GpsPos2(_) => { self.gps_pos_2 = Some(data); } - } + }, messages::sensor::SensorData::RecoverySensing(_) => { self.recovery_sensing = Some(data); } diff --git a/boards/temperature/src/main.rs b/boards/temperature/src/main.rs index d703bc0..2553651 100644 --- a/boards/temperature/src/main.rs +++ b/boards/temperature/src/main.rs @@ -327,9 +327,9 @@ mod app { loop { cx.shared.em.run(|| { let message = Message::new( - cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), COM_ID, messages::state::State::new(messages::state::StateData::Initializing), ); @@ -363,10 +363,13 @@ mod app { stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, }; - let message = - messages::Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, sensor::Sensor::new(x)); + let message = messages::Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + sensor::Sensor::new(x), + ); cx.shared.em.run(|| { spawn!(send_gs, message)?; @@ -385,10 +388,13 @@ mod app { .lock(|data_manager| data_manager.state.clone()); cx.shared.em.run(|| { if let Some(x) = state_data { - let message = - Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, messages::state::State::new(x)); + let message = Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + messages::state::State::new(x), + ); spawn!(send_gs, message)?; } // if there is none we still return since we simply don't have data yet. Ok(()) @@ -442,8 +448,7 @@ mod app { } #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) - { + async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { cx.shared.em.run(|| { cx.shared.rtc.lock(|rtc| { let message = messages::Message::new( @@ -572,4 +577,4 @@ mod app { sbg.set_low(); }); } -} \ No newline at end of file +} diff --git a/crates/ads126x/Cargo.toml b/crates/ads126x/Cargo.toml index a656335..cca5983 100644 --- a/crates/ads126x/Cargo.toml +++ b/crates/ads126x/Cargo.toml @@ -4,3 +4,22 @@ version = "0.1.0" edition = "2021" [dependencies] +defmt = {workspace = true} +embedded-hal = {workspace = true} +bitflags = { version = "2.3.1", features = ["serde"] } +nb = "1.1.0" +heapless = {workspace = true} + +[dev-dependencies] +defmt-test = { workspace = true } +panic-probe = { workspace = true } +stm32h7xx-hal = { workspace = true } +cortex-m = { workspace = true } + +[[test]] +name = "example" +harness = false + +[lib] +name = "ads126x" +harness = false \ No newline at end of file diff --git a/crates/ads126x/src/error.rs b/crates/ads126x/src/error.rs new file mode 100644 index 0000000..33223bc --- /dev/null +++ b/crates/ads126x/src/error.rs @@ -0,0 +1,4 @@ +pub enum ADS126xError { + IO, + InvalidInputData, +} diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index b93cf3f..9f28da9 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -1,14 +1,174 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +#![no_std] +#![no_main] + +mod error; + +use error::ADS126xError; + +use bitflags::bitflags; +use embedded_hal::spi::FullDuplex; +use heapless::Vec; + +pub struct ADS126x +where + SPI: FullDuplex, +{ + spi: SPI, +} + +bitflags! { + pub struct StatusRegister: u8 { + const ADC2 = 0b1000_0000; + const ADC1 = 0b0100_0000; + const EXTCLK = 0b0010_0000; + const REF_ALM = 0b0001_0000; + const PGAL_ALM = 0b0000_1000; + const PGAH_ALM = 0b0000_0100; + const PGAD_ALM = 0b0000_0010; + const RESET = 0b0000_0001; + } +} + +impl StatusRegister { + pub fn is_adc2_data_new(&self) -> bool { + self.contains(StatusRegister::ADC2) + } + + pub fn is_adc1_data_new(&self) -> bool { + self.contains(StatusRegister::ADC1) + } + + pub fn is_extclk(&self) -> bool { + self.contains(StatusRegister::EXTCLK) + } + + pub fn is_ref_alm(&self) -> bool { + self.contains(StatusRegister::REF_ALM) + } + + pub fn is_pgal_alm(&self) -> bool { + self.contains(StatusRegister::PGAL_ALM) + } + + pub fn is_pgah_alm(&self) -> bool { + self.contains(StatusRegister::PGAH_ALM) + } + + pub fn is_pgad_alm(&self) -> bool { + self.contains(StatusRegister::PGAD_ALM) + } + + pub fn is_reset(&self) -> bool { + self.contains(StatusRegister::RESET) + } +} + +pub enum ADCCommand { + NOP, + RESET, + START1, + STOP1, + START2, + STOP2, + RDATA1, + RDATA2, + SYOCAL1, + SYGCAL1, + SFOCAL1, + SYOCAL2, + SYGCAL2, + SFOCAL2, + RREG(u8, u8), // (register address, number of registers) + WREG(u8, u8), // (register address, number of registers) } -#[cfg(test)] -mod tests { - use super::*; +pub enum Register { + ID = 0x00, + POWER = 0x01, + INTERFACE = 0x02, + MODE0 = 0x03, + MODE1 = 0x04, + MODE2 = 0x05, + INPMUX = 0x06, + OFCAL0 = 0x07, + OFCAL1 = 0x08, + OFCAL2 = 0x09, + FSCAL0 = 0x0A, + FSCAL1 = 0x0B, + FSCAL2 = 0x0C, + IDACMUX = 0x0D, + IDACMAG = 0x0E, + REFMUX = 0x0F, + TDACP = 0x10, + TDACN = 0x11, + GPIOCON = 0x12, + GPIODIR = 0x13, + GPIODAT = 0x14, + ADC2CFG = 0x15, + ADC2MUX = 0x16, + ADC2OFC0 = 0x17, + ADC2OFC1 = 0x18, + ADC2FSC0 = 0x19, + ADC2FSC1 = 0x1A, +} + +impl ADS126x +where + SPI: FullDuplex, +{ + pub fn new(spi: SPI) -> Self { + Self { spi } + } + + pub fn send_command(&mut self, command: ADCCommand) -> Result<(), ADS126xError> { + let (opcode1, opcode2) = match command { + ADCCommand::NOP => (0x00, None), + ADCCommand::RESET => (0x06, None), + ADCCommand::START1 => (0x08, None), + ADCCommand::STOP1 => (0x0A, None), + ADCCommand::START2 => (0x0C, None), + ADCCommand::STOP2 => (0x0E, None), + ADCCommand::RDATA1 => (0x12, None), + ADCCommand::RDATA2 => (0x14, None), + ADCCommand::SYOCAL1 => (0x16, None), + ADCCommand::SYGCAL1 => (0x17, None), + ADCCommand::SFOCAL1 => (0x19, None), + ADCCommand::SYOCAL2 => (0x1B, None), + ADCCommand::SYGCAL2 => (0x1C, None), + ADCCommand::SFOCAL2 => (0x1E, None), + ADCCommand::RREG(addr, num) => (0x20 | addr, Some(num)), + ADCCommand::WREG(addr, num) => (0x40 | addr, Some(num)), + }; + + self.spi.send(opcode1).map_err(|_| ADS126xError::IO)?; + if let Some(op2) = opcode2 { + self.spi.send(op2).map_err(|_| ADS126xError::IO)?; + } + Ok(()) + } + + pub fn read_register(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { + if num > 27 { + return Err(ADS126xError::InvalidInputData); + } + self.send_command(ADCCommand::RREG(reg as u8, num - 1))?; + let mut buffer: Vec = Vec::new(); + for _ in 0..num { + buffer + .push(self.spi.read().map_err(|_| ADS126xError::IO)?) + .map_err(|_| ADS126xError::InvalidInputData)?; + } + Ok(buffer) + } - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + pub fn write_register(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { + if data.len() > 27 { + return Err(ADS126xError::InvalidInputData); + } + self.send_command(ADCCommand::WREG(reg as u8, data.len() as u8 - 1))?; + for &byte in data { + self.spi.send(byte).map_err(|_| ADS126xError::IO)?; + } + Ok(()) } } diff --git a/crates/ads126x/tests/example.rs b/crates/ads126x/tests/example.rs new file mode 100644 index 0000000..8e70eb4 --- /dev/null +++ b/crates/ads126x/tests/example.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use defmt::info; +use panic_probe as _; +use stm32h7xx_hal::pac; +use stm32h7xx_hal::prelude::*; + +#[defmt_test::tests] +mod tests { + use super::*; + + #[init] + fn init() { + let _cp = cortex_m::Peripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + let pwr = dp.PWR.constrain(); + let pwrcfg = pwr.freeze(); + + info!("Power enabled"); + // RCC + let mut rcc = dp.RCC.constrain(); + let reset = rcc.get_reset_reason(); + + info!("Reset reason: {:?}", reset); + + let _ccdr = rcc + .use_hse(48.MHz()) // check the clock hardware + .sys_ck(200.MHz()) + .freeze(pwrcfg, &dp.SYSCFG); + info!("RCC configured"); + } + + #[test] + fn example_test() { + assert!(true); + } +} diff --git a/crates/common-arm/src/lib.rs b/crates/common-arm/src/lib.rs index 4896d13..32d46e0 100644 --- a/crates/common-arm/src/lib.rs +++ b/crates/common-arm/src/lib.rs @@ -15,4 +15,4 @@ pub use crate::error::hydra_error::{ErrorContextTrait, HydraError, SpawnError}; pub use crate::logging::HydraLogging; pub use crate::sd_manager::SdManager; -use defmt_rtt as _; // global logger \ No newline at end of file +use defmt_rtt as _; // global logger diff --git a/examples/rtic-playground/src/data_manager.rs b/examples/rtic-playground/src/data_manager.rs index 2729860..67b5834 100644 --- a/examples/rtic-playground/src/data_manager.rs +++ b/examples/rtic-playground/src/data_manager.rs @@ -114,7 +114,7 @@ impl DataManager { pub fn handle_data(&mut self, data: Message) { match data.data { messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data{ + messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { messages::sensor::SbgData::EkfNavAcc(_) => { self.ekf_nav_acc = Some(data); } @@ -154,7 +154,7 @@ impl DataManager { messages::sensor::SbgData::GpsPos2(_) => { self.gps_pos_2 = Some(data); } - } + }, messages::sensor::SensorData::RecoverySensing(_) => { self.recovery_sensing = Some(data); } diff --git a/examples/rtic-playground/src/main.rs b/examples/rtic-playground/src/main.rs index d703bc0..2553651 100644 --- a/examples/rtic-playground/src/main.rs +++ b/examples/rtic-playground/src/main.rs @@ -327,9 +327,9 @@ mod app { loop { cx.shared.em.run(|| { let message = Message::new( - cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), COM_ID, messages::state::State::new(messages::state::StateData::Initializing), ); @@ -363,10 +363,13 @@ mod app { stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, }; - let message = - messages::Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, sensor::Sensor::new(x)); + let message = messages::Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + sensor::Sensor::new(x), + ); cx.shared.em.run(|| { spawn!(send_gs, message)?; @@ -385,10 +388,13 @@ mod app { .lock(|data_manager| data_manager.state.clone()); cx.shared.em.run(|| { if let Some(x) = state_data { - let message = - Message::new(cx.shared.rtc.lock(|rtc| { - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()) - }), COM_ID, messages::state::State::new(x)); + let message = Message::new( + cx.shared + .rtc + .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), + COM_ID, + messages::state::State::new(x), + ); spawn!(send_gs, message)?; } // if there is none we still return since we simply don't have data yet. Ok(()) @@ -442,8 +448,7 @@ mod app { } #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) - { + async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { cx.shared.em.run(|| { cx.shared.rtc.lock(|rtc| { let message = messages::Message::new( @@ -572,4 +577,4 @@ mod app { sbg.set_low(); }); } -} \ No newline at end of file +} From 7c1af852bb3b91ed50e1fdd417f1dc008d85b134 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sun, 3 Nov 2024 19:57:59 -0500 Subject: [PATCH 03/22] Convert RREG and WREG to use Register not u8 --- crates/ads126x/src/lib.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 9f28da9..59cef78 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -78,10 +78,11 @@ pub enum ADCCommand { SYOCAL2, SYGCAL2, SFOCAL2, - RREG(u8, u8), // (register address, number of registers) - WREG(u8, u8), // (register address, number of registers) + RREG(Register, u8), // (register address, number of registers) + WREG(Register, u8), // (register address, number of registers) } +#[repr(u8)] pub enum Register { ID = 0x00, POWER = 0x01, @@ -136,8 +137,8 @@ where ADCCommand::SYOCAL2 => (0x1B, None), ADCCommand::SYGCAL2 => (0x1C, None), ADCCommand::SFOCAL2 => (0x1E, None), - ADCCommand::RREG(addr, num) => (0x20 | addr, Some(num)), - ADCCommand::WREG(addr, num) => (0x40 | addr, Some(num)), + ADCCommand::RREG(addr, num) => (0x20 | addr as u8, Some(num)), + ADCCommand::WREG(addr, num) => (0x40 | addr as u8, Some(num)), }; self.spi.send(opcode1).map_err(|_| ADS126xError::IO)?; @@ -151,7 +152,7 @@ where if num > 27 { return Err(ADS126xError::InvalidInputData); } - self.send_command(ADCCommand::RREG(reg as u8, num - 1))?; + self.send_command(ADCCommand::RREG(reg, num - 1))?; let mut buffer: Vec = Vec::new(); for _ in 0..num { buffer @@ -165,7 +166,7 @@ where if data.len() > 27 { return Err(ADS126xError::InvalidInputData); } - self.send_command(ADCCommand::WREG(reg as u8, data.len() as u8 - 1))?; + self.send_command(ADCCommand::WREG(reg, data.len() as u8 - 1))?; for &byte in data { self.spi.send(byte).map_err(|_| ADS126xError::IO)?; } From 48c63fd45e55b961a8434b65270e75821d57b7a7 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sun, 3 Nov 2024 23:01:04 -0500 Subject: [PATCH 04/22] Added getters and setters for ID, POWER, and INTERFACE registers --- crates/ads126x/src/lib.rs | 75 ++++++++++++++++----------- crates/ads126x/src/register.rs | 94 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 31 deletions(-) create mode 100644 crates/ads126x/src/register.rs diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 59cef78..e7e5869 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -2,8 +2,10 @@ #![no_main] mod error; +mod register; use error::ADS126xError; +use register::{Register, IdRegister, PowerRegister, InterfaceRegister}; use bitflags::bitflags; use embedded_hal::spi::FullDuplex; @@ -82,37 +84,6 @@ pub enum ADCCommand { WREG(Register, u8), // (register address, number of registers) } -#[repr(u8)] -pub enum Register { - ID = 0x00, - POWER = 0x01, - INTERFACE = 0x02, - MODE0 = 0x03, - MODE1 = 0x04, - MODE2 = 0x05, - INPMUX = 0x06, - OFCAL0 = 0x07, - OFCAL1 = 0x08, - OFCAL2 = 0x09, - FSCAL0 = 0x0A, - FSCAL1 = 0x0B, - FSCAL2 = 0x0C, - IDACMUX = 0x0D, - IDACMAG = 0x0E, - REFMUX = 0x0F, - TDACP = 0x10, - TDACN = 0x11, - GPIOCON = 0x12, - GPIODIR = 0x13, - GPIODAT = 0x14, - ADC2CFG = 0x15, - ADC2MUX = 0x16, - ADC2OFC0 = 0x17, - ADC2OFC1 = 0x18, - ADC2FSC0 = 0x19, - ADC2FSC1 = 0x1A, -} - impl ADS126x where SPI: FullDuplex, @@ -162,6 +133,13 @@ where Ok(buffer) } + /// Reads data from only the single provided register. + /// To read multiple registers, see [read_register](ADS126x::read_register). + pub fn read_single_register(&mut self, reg: Register) -> Result { + let data = self.read_register(reg, 1)?; + Ok(data[0]) + } + pub fn write_register(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); @@ -172,4 +150,39 @@ where } Ok(()) } + + pub fn get_id(&mut self) -> Result { + let bits = self.read_single_register(Register::ID)?; + let data = IdRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn get_power(&mut self) -> Result { + let bits = self.read_single_register(Register::POWER)?; + let data = PowerRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_power(&mut self, reg: &PowerRegister) -> Result<(), ADS126xError> { + self.write_register(Register::POWER, &[reg.bits()]) + } + + pub fn get_interface(&mut self) -> Result { + let bits = self.read_single_register(Register::INTERFACE)?; + let data = InterfaceRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<(), ADS126xError> { + self.write_register(Register::INTERFACE, &[reg.bits()]) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs new file mode 100644 index 0000000..570ab2a --- /dev/null +++ b/crates/ads126x/src/register.rs @@ -0,0 +1,94 @@ +use bitflags::bitflags; + +#[repr(u8)] +pub enum Register { + ID = 0x00, + POWER = 0x01, + INTERFACE = 0x02, + MODE0 = 0x03, + MODE1 = 0x04, + MODE2 = 0x05, + INPMUX = 0x06, + OFCAL0 = 0x07, + OFCAL1 = 0x08, + OFCAL2 = 0x09, + FSCAL0 = 0x0A, + FSCAL1 = 0x0B, + FSCAL2 = 0x0C, + IDACMUX = 0x0D, + IDACMAG = 0x0E, + REFMUX = 0x0F, + TDACP = 0x10, + TDACN = 0x11, + GPIOCON = 0x12, + GPIODIR = 0x13, + GPIODAT = 0x14, + ADC2CFG = 0x15, + ADC2MUX = 0x16, + ADC2OFC0 = 0x17, + ADC2OFC1 = 0x18, + ADC2FSC0 = 0x19, + ADC2FSC1 = 0x1A, +} + +bitflags! { + pub struct IdRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +pub enum DevId { + ADS1262 = 0b000, + ADS1263 = 0b001, +} + +impl IdRegister { + pub fn get_rev_id(&self) -> u8 { + self.bits() & 0b0001_1111 + } + + pub fn get_dev_id(&self) -> DevId { + match (self.bits() & 0b1110_0000) >> 5 { + 0b000 => DevId::ADS1262, + 0b001 => DevId::ADS1263, + + _ => panic!("Device ID must be 0b000 or 0b001."), + } + } +} + +bitflags! { + pub struct PowerRegister: u8 { + const INTREF = 0b0000_0001; + const VBIAS = 0b0000_0010; + const RESET = 0b0001_0000; + } +} + +bitflags! { + pub struct InterfaceRegister: u8 { + const STATUS = 0b0000_0100; + const TIMEOUT = 0b0000_1000; + + const _ = 0b0000_0011; // Source may set CDC bits + } +} + +pub enum Crc { + DISABLED = 0b00, + ENABLED = 0b01, + RESERVED = 0b11, +} + +impl InterfaceRegister { + pub fn get_crc(&self) -> Crc { + match self.bits() & 0b0000_0011 { + 0b00 => Crc::DISABLED, + 0b01 => Crc::ENABLED, + 0b11 => Crc::RESERVED, + + // Exhaustive list for possible combinations of 2 bits + _ => unreachable!("Only 2 bits should be set.") + } + } +} From 645acecd6248891523f680396c3d19a74a0ccff7 Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Mon, 4 Nov 2024 19:26:17 -0500 Subject: [PATCH 05/22] Rename read_register to read_multiple_registers. Remove call to read_multiple_registers for a single register call. --- crates/ads126x/src/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index e7e5869..d6d486d 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -119,7 +119,7 @@ where Ok(()) } - pub fn read_register(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { + pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { if num > 27 { return Err(ADS126xError::InvalidInputData); } @@ -135,9 +135,11 @@ where /// Reads data from only the single provided register. /// To read multiple registers, see [read_register](ADS126x::read_register). - pub fn read_single_register(&mut self, reg: Register) -> Result { - let data = self.read_register(reg, 1)?; - Ok(data[0]) + pub fn read_register(&mut self, reg: Register) -> Result { + // zero since number of registers read - 1, so 1-1=0. + self.send_command(ADCCommand::RREG(reg, 0))?; + let data = self.spi.read().map_err(|_| ADS126xError::IO)?; + Ok(data) } pub fn write_register(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { @@ -152,7 +154,7 @@ where } pub fn get_id(&mut self) -> Result { - let bits = self.read_single_register(Register::ID)?; + let bits = self.read_register(Register::ID)?; let data = IdRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -161,7 +163,7 @@ where } pub fn get_power(&mut self) -> Result { - let bits = self.read_single_register(Register::POWER)?; + let bits = self.read_register(Register::POWER)?; let data = PowerRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -174,7 +176,7 @@ where } pub fn get_interface(&mut self) -> Result { - let bits = self.read_single_register(Register::INTERFACE)?; + let bits = self.read_register(Register::INTERFACE)?; let data = InterfaceRegister::from_bits(bits); match data { Some(reg) => Ok(reg), From 1f0417cd1ac2461efc57d70c4253a917d0399959 Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Mon, 4 Nov 2024 19:27:59 -0500 Subject: [PATCH 06/22] Update doc --- crates/ads126x/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index d6d486d..6ceb7b6 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -134,7 +134,7 @@ where } /// Reads data from only the single provided register. - /// To read multiple registers, see [read_register](ADS126x::read_register). + /// To read multiple registers, see [read_multiple_registers](ADS126x::read_multiple_registers). pub fn read_register(&mut self, reg: Register) -> Result { // zero since number of registers read - 1, so 1-1=0. self.send_command(ADCCommand::RREG(reg, 0))?; From f261ee8bc0f219e4f23983b7bead5aafd73d7f18 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Mon, 4 Nov 2024 20:45:36 -0500 Subject: [PATCH 07/22] Converted WREG to single and multiple variant --- crates/ads126x/src/lib.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 6ceb7b6..5e5931f 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -119,6 +119,8 @@ where Ok(()) } + /// Reads data from multiple registers starting at the provided register. + /// To read a single register, see [read_register](ADS126x::read_register). pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { if num > 27 { return Err(ADS126xError::InvalidInputData); @@ -142,7 +144,9 @@ where Ok(data) } - pub fn write_register(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { + /// Writes data to multiple registers starting at the provided register. + /// To write data to a single register, see [write_register](ADS126x::write_register). + pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); } @@ -153,6 +157,13 @@ where Ok(()) } + /// Writes data to only the single provided register. + /// To write data to multiple registers, see [write_multiple_registers](ADS126x::write_multiple_registers). + pub fn write_register(&mut self, reg: Register, data: u8) -> Result<(), ADS126xError> { + self.send_command(ADCCommand::WREG(reg, 0))?; + self.spi.send(data).map_err(|_| ADS126xError::IO) + } + pub fn get_id(&mut self) -> Result { let bits = self.read_register(Register::ID)?; let data = IdRegister::from_bits(bits); @@ -172,7 +183,7 @@ where } pub fn set_power(&mut self, reg: &PowerRegister) -> Result<(), ADS126xError> { - self.write_register(Register::POWER, &[reg.bits()]) + self.write_register(Register::POWER, reg.bits()) } pub fn get_interface(&mut self) -> Result { @@ -185,6 +196,6 @@ where } pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<(), ADS126xError> { - self.write_register(Register::INTERFACE, &[reg.bits()]) + self.write_register(Register::INTERFACE, reg.bits()) } } From fe7fa316ab283f8ac1d84f07e9994fb8c5fa73b2 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Mon, 4 Nov 2024 23:43:16 -0500 Subject: [PATCH 08/22] Added set_crc and removed RESERVED from Crc enum --- crates/ads126x/src/register.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index 570ab2a..f7fa1f9 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -77,7 +77,6 @@ bitflags! { pub enum Crc { DISABLED = 0b00, ENABLED = 0b01, - RESERVED = 0b11, } impl InterfaceRegister { @@ -85,10 +84,16 @@ impl InterfaceRegister { match self.bits() & 0b0000_0011 { 0b00 => Crc::DISABLED, 0b01 => Crc::ENABLED, - 0b11 => Crc::RESERVED, + + 0b11 => panic!("Reserved state is set. Should not be 0b11."), // Exhaustive list for possible combinations of 2 bits _ => unreachable!("Only 2 bits should be set.") } } + + pub fn set_crc(&mut self, crc: Crc) { + let crc_bits = crc as u8 & 0b0000_0011; + self.insert(InterfaceRegister::from_bits_truncate(crc_bits)); + } } From 6437ec72cc00c0eccc48c7419f2c39472441f399 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Tue, 5 Nov 2024 17:38:36 -0500 Subject: [PATCH 09/22] Convert CRC from enum to bitflag --- crates/ads126x/src/register.rs | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index f7fa1f9..46d77bf 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -66,34 +66,11 @@ bitflags! { } bitflags! { + /// WARNING: If CRC is 0b11 set by ADC, it will reflect as CRC enabled not reserved. + /// CRC only accounts for 0b00 disabled and 0b01 enabled. pub struct InterfaceRegister: u8 { + const CRC = 0b0000_0001; const STATUS = 0b0000_0100; const TIMEOUT = 0b0000_1000; - - const _ = 0b0000_0011; // Source may set CDC bits - } -} - -pub enum Crc { - DISABLED = 0b00, - ENABLED = 0b01, -} - -impl InterfaceRegister { - pub fn get_crc(&self) -> Crc { - match self.bits() & 0b0000_0011 { - 0b00 => Crc::DISABLED, - 0b01 => Crc::ENABLED, - - 0b11 => panic!("Reserved state is set. Should not be 0b11."), - - // Exhaustive list for possible combinations of 2 bits - _ => unreachable!("Only 2 bits should be set.") - } - } - - pub fn set_crc(&mut self, crc: Crc) { - let crc_bits = crc as u8 & 0b0000_0011; - self.insert(InterfaceRegister::from_bits_truncate(crc_bits)); } } From ea70a003a8fb811ae211eb2320729ff223481e2f Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sat, 9 Nov 2024 13:08:59 -0500 Subject: [PATCH 10/22] Moved status register to register module --- crates/ads126x/src/lib.rs | 48 ---------------------------------- crates/ads126x/src/register.rs | 47 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 5e5931f..16816d0 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -7,7 +7,6 @@ mod register; use error::ADS126xError; use register::{Register, IdRegister, PowerRegister, InterfaceRegister}; -use bitflags::bitflags; use embedded_hal::spi::FullDuplex; use heapless::Vec; @@ -18,53 +17,6 @@ where spi: SPI, } -bitflags! { - pub struct StatusRegister: u8 { - const ADC2 = 0b1000_0000; - const ADC1 = 0b0100_0000; - const EXTCLK = 0b0010_0000; - const REF_ALM = 0b0001_0000; - const PGAL_ALM = 0b0000_1000; - const PGAH_ALM = 0b0000_0100; - const PGAD_ALM = 0b0000_0010; - const RESET = 0b0000_0001; - } -} - -impl StatusRegister { - pub fn is_adc2_data_new(&self) -> bool { - self.contains(StatusRegister::ADC2) - } - - pub fn is_adc1_data_new(&self) -> bool { - self.contains(StatusRegister::ADC1) - } - - pub fn is_extclk(&self) -> bool { - self.contains(StatusRegister::EXTCLK) - } - - pub fn is_ref_alm(&self) -> bool { - self.contains(StatusRegister::REF_ALM) - } - - pub fn is_pgal_alm(&self) -> bool { - self.contains(StatusRegister::PGAL_ALM) - } - - pub fn is_pgah_alm(&self) -> bool { - self.contains(StatusRegister::PGAH_ALM) - } - - pub fn is_pgad_alm(&self) -> bool { - self.contains(StatusRegister::PGAD_ALM) - } - - pub fn is_reset(&self) -> bool { - self.contains(StatusRegister::RESET) - } -} - pub enum ADCCommand { NOP, RESET, diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index 46d77bf..fc2df66 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -31,6 +31,53 @@ pub enum Register { ADC2FSC1 = 0x1A, } +bitflags! { + pub struct StatusRegister: u8 { + const ADC2 = 0b1000_0000; + const ADC1 = 0b0100_0000; + const EXTCLK = 0b0010_0000; + const REF_ALM = 0b0001_0000; + const PGAL_ALM = 0b0000_1000; + const PGAH_ALM = 0b0000_0100; + const PGAD_ALM = 0b0000_0010; + const RESET = 0b0000_0001; + } +} + +impl StatusRegister { + pub fn is_adc2_data_new(&self) -> bool { + self.contains(StatusRegister::ADC2) + } + + pub fn is_adc1_data_new(&self) -> bool { + self.contains(StatusRegister::ADC1) + } + + pub fn is_extclk(&self) -> bool { + self.contains(StatusRegister::EXTCLK) + } + + pub fn is_ref_alm(&self) -> bool { + self.contains(StatusRegister::REF_ALM) + } + + pub fn is_pgal_alm(&self) -> bool { + self.contains(StatusRegister::PGAL_ALM) + } + + pub fn is_pgah_alm(&self) -> bool { + self.contains(StatusRegister::PGAH_ALM) + } + + pub fn is_pgad_alm(&self) -> bool { + self.contains(StatusRegister::PGAD_ALM) + } + + pub fn is_reset(&self) -> bool { + self.contains(StatusRegister::RESET) + } +} + bitflags! { pub struct IdRegister: u8 { const _ = !0; // Source may set any bits From 2621498d56aa303d711f1a55ed06a5fd8cb177bd Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sat, 9 Nov 2024 22:46:24 -0500 Subject: [PATCH 11/22] Added MODE register impls --- crates/ads126x/src/lib.rs | 80 ++++++++++--- crates/ads126x/src/register.rs | 166 ++++++++++++++++++++++++++- crates/ads126x/src/register/enums.rs | 112 ++++++++++++++++++ 3 files changed, 338 insertions(+), 20 deletions(-) create mode 100644 crates/ads126x/src/register/enums.rs diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 16816d0..b646dbf 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -5,11 +5,22 @@ mod error; mod register; use error::ADS126xError; -use register::{Register, IdRegister, PowerRegister, InterfaceRegister}; +use register::{ + IdRegister, + InterfaceRegister, + Mode0Register, + Mode1Register, + Mode2Register, + PowerRegister, + Register +}; use embedded_hal::spi::FullDuplex; use heapless::Vec; +/// The [`Result`] type for ADS126x operations. +pub type Result = core::result::Result; + pub struct ADS126x where SPI: FullDuplex, @@ -44,7 +55,7 @@ where Self { spi } } - pub fn send_command(&mut self, command: ADCCommand) -> Result<(), ADS126xError> { + pub fn send_command(&mut self, command: ADCCommand) -> Result<()> { let (opcode1, opcode2) = match command { ADCCommand::NOP => (0x00, None), ADCCommand::RESET => (0x06, None), @@ -72,8 +83,8 @@ where } /// Reads data from multiple registers starting at the provided register. - /// To read a single register, see [read_register](ADS126x::read_register). - pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { + /// To read a single register, see [`ADS126x::read_register`]. + pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result> { if num > 27 { return Err(ADS126xError::InvalidInputData); } @@ -88,8 +99,8 @@ where } /// Reads data from only the single provided register. - /// To read multiple registers, see [read_multiple_registers](ADS126x::read_multiple_registers). - pub fn read_register(&mut self, reg: Register) -> Result { + /// To read multiple registers, see [`ADS126x::read_multiple_registers`]. + pub fn read_register(&mut self, reg: Register) -> Result { // zero since number of registers read - 1, so 1-1=0. self.send_command(ADCCommand::RREG(reg, 0))?; let data = self.spi.read().map_err(|_| ADS126xError::IO)?; @@ -97,8 +108,8 @@ where } /// Writes data to multiple registers starting at the provided register. - /// To write data to a single register, see [write_register](ADS126x::write_register). - pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { + /// To write data to a single register, see [`ADS126x::write_register`]. + pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<()> { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); } @@ -110,13 +121,13 @@ where } /// Writes data to only the single provided register. - /// To write data to multiple registers, see [write_multiple_registers](ADS126x::write_multiple_registers). - pub fn write_register(&mut self, reg: Register, data: u8) -> Result<(), ADS126xError> { + /// To write data to multiple registers, see [`ADS126x::write_multiple_registers`]. + pub fn write_register(&mut self, reg: Register, data: u8) -> Result<()> { self.send_command(ADCCommand::WREG(reg, 0))?; self.spi.send(data).map_err(|_| ADS126xError::IO) } - pub fn get_id(&mut self) -> Result { + pub fn get_id(&mut self) -> Result { let bits = self.read_register(Register::ID)?; let data = IdRegister::from_bits(bits); match data { @@ -125,7 +136,7 @@ where } } - pub fn get_power(&mut self) -> Result { + pub fn get_power(&mut self) -> Result { let bits = self.read_register(Register::POWER)?; let data = PowerRegister::from_bits(bits); match data { @@ -134,11 +145,11 @@ where } } - pub fn set_power(&mut self, reg: &PowerRegister) -> Result<(), ADS126xError> { + pub fn set_power(&mut self, reg: &PowerRegister) -> Result<()> { self.write_register(Register::POWER, reg.bits()) } - pub fn get_interface(&mut self) -> Result { + pub fn get_interface(&mut self) -> Result { let bits = self.read_register(Register::INTERFACE)?; let data = InterfaceRegister::from_bits(bits); match data { @@ -147,7 +158,46 @@ where } } - pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<(), ADS126xError> { + pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<()> { self.write_register(Register::INTERFACE, reg.bits()) } + + pub fn get_mode0(&mut self) -> Result { + let bits = self.read_register(Register::MODE0)?; + let data = Mode0Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode0(&mut self, reg: &Mode0Register) -> Result<()> { + self.write_register(Register::MODE0, reg.bits()) + } + + pub fn get_mode1(&mut self) -> Result { + let bits = self.read_register(Register::MODE1)?; + let data = Mode1Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode1(&mut self, reg: &Mode1Register) -> Result<()> { + self.write_register(Register::MODE1, reg.bits()) + } + + pub fn get_mode2(&mut self) -> Result { + let bits = self.read_register(Register::MODE2)?; + let data = Mode2Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode2(&mut self, reg: &Mode2Register) -> Result<()> { + self.write_register(Register::MODE2, reg.bits()) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index fc2df66..ae2fb64 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -1,3 +1,6 @@ +mod enums; + +pub use enums::*; use bitflags::bitflags; #[repr(u8)] @@ -84,11 +87,6 @@ bitflags! { } } -pub enum DevId { - ADS1262 = 0b000, - ADS1263 = 0b001, -} - impl IdRegister { pub fn get_rev_id(&self) -> u8 { self.bits() & 0b0001_1111 @@ -121,3 +119,161 @@ bitflags! { const TIMEOUT = 0b0000_1000; } } + +bitflags! { + pub struct Mode0Register: u8 { + const RUNMODE = 0b0100_0000; + const REFREV = 0b1000_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode0Register { + pub fn get_delay(&self) -> ConversionDelay { + match self.bits() & 0b0000_1111 { + 0b0000 => ConversionDelay::DNone, + 0b0001 => ConversionDelay::D8_7us, + 0b0010 => ConversionDelay::D17us, + 0b0011 => ConversionDelay::D35us, + 0b0100 => ConversionDelay::D69us, + 0b0101 => ConversionDelay::D139us, + 0b0110 => ConversionDelay::D278us, + 0b0111 => ConversionDelay::D555us, + 0b1000 => ConversionDelay::D1_1ms, + 0b1001 => ConversionDelay::D2_2ms, + 0b1010 => ConversionDelay::D4_4ms, + 0b1011 => ConversionDelay::D8_8ms, + + 0b1100..=0b1111 => panic!("Unknown conversion delay"), + _ => unreachable!(), + } + } + + pub fn set_delay(&mut self, delay: ConversionDelay) { + let bits = delay as u8; + self.insert(Mode0Register::from_bits_retain(bits)); + } + + pub fn get_chop(&self) -> ChopMode { + match (self.bits() & 0b0011_0000) >> 4 { + 0b00 => ChopMode::Disabled, + 0b01 => ChopMode::InChopEnabled, + 0b10 => ChopMode::IdacEnabled, + 0b11 => ChopMode::InChopAndIdacEnabled, + + _ => unreachable!(), + } + } + + pub fn set_chop(&mut self, chop: ChopMode) { + let bits = chop as u8; + self.insert(Mode0Register::from_bits_retain(bits << 4)); + } +} + +bitflags! { + pub struct Mode1Register: u8 { + const SBPOL = 0b0000_1000; + const SBADC = 0b0001_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode1Register { + pub fn get_sbmag(&self) -> SensorBiasMagnitude { + match self.bits() & 0b0000_0111 { + 0b000 => SensorBiasMagnitude::BNone, + 0b001 => SensorBiasMagnitude::B0_5uA, + 0b010 => SensorBiasMagnitude::B2uA, + 0b011 => SensorBiasMagnitude::B10uA, + 0b100 => SensorBiasMagnitude::B50uA, + 0b101 => SensorBiasMagnitude::B200uA, + 0b110 => SensorBiasMagnitude::R10MOhm, + + 0b111 => panic!("Reserved SBMAG"), + _ => unreachable!() + } + } + + pub fn set_sbmag(&mut self, sbmag: SensorBiasMagnitude) { + let bits = sbmag as u8; + self.insert(Mode1Register::from_bits_retain(bits)); + } + + pub fn get_filter(&self) -> DigitalFilter { + match (self.bits() & 0b1110_0000) >> 5 { + 0b000 => DigitalFilter::Sinc1, + 0b001 => DigitalFilter::Sinc2, + 0b010 => DigitalFilter::Sinc3, + 0b011 => DigitalFilter::Sinc4, + 0b100 => DigitalFilter::FIR, + + 0b101..=0b111 => panic!("Reserved filter"), + _ => unreachable!() + } + } + + pub fn set_filter(&mut self, filter: DigitalFilter) { + let bits = filter as u8; + self.insert(Mode1Register::from_bits_retain(bits << 5)); + } +} + +bitflags! { + pub struct Mode2Register: u8 { + const BYPASS = 0b1000_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode2Register { + pub fn get_dr(&self) -> DataRate { + match self.bits() & 0b0000_1111 { + 0b0000 => DataRate::SPS2_5, + 0b0001 => DataRate::SPS5, + 0b0010 => DataRate::SPS10, + 0b0011 => DataRate::SPS16_6, + 0b0100 => DataRate::SPS20, + 0b0101 => DataRate::SPS50, + 0b0110 => DataRate::SPS60, + 0b0111 => DataRate::SPS100, + 0b1000 => DataRate::SPS400, + 0b1001 => DataRate::SPS1200, + 0b1010 => DataRate::SPS2400, + 0b1011 => DataRate::SPS4800, + 0b1100 => DataRate::SPS7200, + 0b1101 => DataRate::SPS14400, + 0b1110 => DataRate::SPS19200, + 0b1111 => DataRate::SPS38400, + + _ => unreachable!() + } + } + + pub fn set_dr(&mut self, rate: DataRate) { + let bits = rate as u8; + self.insert(Mode2Register::from_bits_retain(bits)); + } + + pub fn get_gain(&self) -> PGAGain { + match (self.bits() & 0b0111_0000) >> 4 { + 0b000 => PGAGain::VV1, + 0b001 => PGAGain::VV2, + 0b010 => PGAGain::VV4, + 0b011 => PGAGain::VV8, + 0b100 => PGAGain::VV16, + 0b101 => PGAGain::VV32, + + 0b110 | 0b111 => panic!("Reserved gain"), + _ => unreachable!() + } + } + + pub fn set_gain(&mut self, gain: PGAGain) { + let bits = gain as u8; + self.insert(Mode2Register::from_bits_retain(bits << 4)); + } +} diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs new file mode 100644 index 0000000..5ef296d --- /dev/null +++ b/crates/ads126x/src/register/enums.rs @@ -0,0 +1,112 @@ +pub enum DevId { + ADS1262 = 0b000, + ADS1263 = 0b001, +} + +/// Conversion delays follow the pattern `D`. +/// - `len` is the length of time where _ is a substitute for a decimal point. +/// - `units` are the units of time where us is microseconds and ms is milliseconds. +/// +/// D8_7us = delay of 8.7 microseconds. D8_8ms = delay of 8.8 milliseconds. +#[repr(u8)] +pub enum ConversionDelay { + DNone = 0b0000, + D8_7us = 0b0001, + D17us = 0b0010, + D35us = 0b0011, + D69us = 0b0100, + D139us = 0b0101, + D278us = 0b0110, + D555us = 0b0111, + D1_1ms = 0b1000, + D2_2ms = 0b1001, + D4_4ms = 0b1010, + D8_8ms = 0b1011, +} + +impl ConversionDelay { + /// Returns the delay in nanoseconds. + pub fn delay(&self) -> u32 { + match self { + Self::DNone => 0, + Self::D8_7us => 8_700, + Self::D17us => 17_000, + Self::D35us => 35_000, + Self::D69us => 69_000, + Self::D139us => 139_000, + Self::D278us => 278_000, + Self::D555us => 555_000, + Self::D1_1ms => 1_100_000, + Self::D2_2ms => 2_200_000, + Self::D4_4ms => 4_400_000, + Self::D8_8ms => 8_800_000, + } + } +} + +#[repr(u8)] +pub enum ChopMode { + Disabled = 0b00, + InChopEnabled = 0b01, + IdacEnabled = 0b10, + InChopAndIdacEnabled = 0b11, +} + +/// SBMAGs follow the pattern `B` or `R`. +/// - `mag` is the magnitude of current or resistance where _ is a substitute for a decimal point. +/// - `units` are the units of current or resistance where uA is microamperes and MOhm is megaohms. +/// +/// B0_5uA = 0.5 microamps of current. R10MOhm = resistance of 10 megaohms. +#[repr(u8)] +pub enum SensorBiasMagnitude { + BNone = 0b000, + B0_5uA = 0b001, + B2uA = 0b010, + B10uA = 0b011, + B50uA = 0b100, + B200uA = 0b101, + R10MOhm = 0b110, +} + +#[repr(u8)] +pub enum DigitalFilter { + Sinc1 = 0b000, + Sinc2 = 0b001, + Sinc3 = 0b010, + Sinc4 = 0b011, + FIR = 0b100, +} + +/// Data rates follow the pattern `SPS`. +/// - `num` is the SPS rate where _ is a substitute for a decimal point. +/// +/// SPS2_5 = 2.5 SPS. +#[repr(u8)] +pub enum DataRate { + SPS2_5 = 0b0000, + SPS5 = 0b0001, + SPS10 = 0b0010, + SPS16_6 = 0b0011, // 16.6666... = 50/3 + SPS20 = 0b0100, + SPS50 = 0b0101, + SPS60 = 0b0110, + SPS100 = 0b0111, + SPS400 = 0b1000, + SPS1200 = 0b1001, + SPS2400 = 0b1010, + SPS4800 = 0b1011, + SPS7200 = 0b1100, + SPS14400 = 0b1101, + SPS19200 = 0b1110, + SPS38400 = 0b1111, +} + +#[repr(u8)] +pub enum PGAGain { + VV1 = 0b000, + VV2 = 0b001, + VV4 = 0b010, + VV8 = 0b011, + VV16 = 0b100, + VV32 = 0b101, +} From adea264291e6cdac2aea264cba3acebfc8c73901 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Mon, 11 Nov 2024 22:10:31 -0500 Subject: [PATCH 12/22] Added more registers --- crates/ads126x/src/lib.rs | 104 +++++++++++- crates/ads126x/src/register.rs | 228 ++++++++++++++++++++++++++- crates/ads126x/src/register/enums.rs | 93 +++++++++++ 3 files changed, 414 insertions(+), 11 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index b646dbf..576ccf4 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -6,13 +6,7 @@ mod register; use error::ADS126xError; use register::{ - IdRegister, - InterfaceRegister, - Mode0Register, - Mode1Register, - Mode2Register, - PowerRegister, - Register + IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register }; use embedded_hal::spi::FullDuplex; @@ -84,6 +78,8 @@ where /// Reads data from multiple registers starting at the provided register. /// To read a single register, see [`ADS126x::read_register`]. + /// + /// Vector returns byte for each register read in order registers were read (increasing address). pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result> { if num > 27 { return Err(ADS126xError::InvalidInputData); @@ -109,6 +105,8 @@ where /// Writes data to multiple registers starting at the provided register. /// To write data to a single register, see [`ADS126x::write_register`]. + /// + /// Data has byte for each register in order registers are written to (increasing address). pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<()> { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); @@ -200,4 +198,96 @@ where pub fn set_mode2(&mut self, reg: &Mode2Register) -> Result<()> { self.write_register(Register::MODE2, reg.bits()) } + + pub fn get_inpmux(&mut self) -> Result { + let bits = self.read_register(Register::INPMUX)?; + let data = InpMuxRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_inpmux(&mut self, reg: &InpMuxRegister) -> Result<()> { + self.write_register(Register::INPMUX, reg.bits()) + } + + pub fn get_ofcal(&mut self) -> Result { + let mut bytes = self.read_multiple_registers(Register::OFCAL0, 3)?; // [OFCAL0, OFCAL1, OFCAL2] + bytes.reverse(); // [OFCAL2, OFCAL1, OFCAL0] + let mut res: u32 = 0; + for &b in &bytes[3..0] { + res <<= 8; // Shift previous bits left one byte + res |= b as u32; // Append new byte to the end + } + Ok(res) + } + + pub fn set_ofcal(&mut self, ofcal: u32) -> Result<()> { + let mut bytes: [u8; 4] = [0; 4]; + for i in 0..4 { + let b = (ofcal >> (8 * i)) & 0xFF; // Get desired byte + bytes[i] = u8::try_from(b).unwrap(); // Should not panic as & 0xFF ensures b is a u8 + } + self.write_multiple_registers(Register::OFCAL0, &bytes[0..3]) + } + + pub fn get_fscal(&mut self) -> Result { + let mut bytes = self.read_multiple_registers(Register::FSCAL0, 3)?; // [FSCAL0, FSCAL1, FSCAL2] + bytes.reverse(); // [FSCAL2, FSCAL1, FSCAL0] + let mut res: u32 = 0; + for &b in &bytes[3..0] { + res <<= 8; // Shift previous bits left one byte + res |= b as u32; // Append new byte to the end + } + Ok(res) + } + + pub fn set_fscal(&mut self, fscal: u32) -> Result<()> { + let mut bytes: [u8; 4] = [0; 4]; + for i in 0..4 { + let b = (fscal >> (8 * i)) & 0xFF; // Get desired byte + bytes[i] = u8::try_from(b).unwrap(); // Should not panic as & 0xFF ensures b is a u8 + } + self.write_multiple_registers(Register::FSCAL0, &bytes[0..3]) + } + + pub fn get_idacmux(&mut self) -> Result { + let bits = self.read_register(Register::IDACMUX)?; + let data = IdacMuxRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_idacmux(&mut self, reg: &IdacMuxRegister) -> Result<()> { + self.write_register(Register::IDACMUX, reg.bits()) + } + + pub fn get_idacmag(&mut self) -> Result { + let bits = self.read_register(Register::IDACMAG)?; + let data = IdacMagRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_idacmag(&mut self, reg: &IdacMagRegister) -> Result<()> { + self.write_register(Register::IDACMAG, reg.bits()) + } + + pub fn get_refmux(&mut self) -> Result { + let bits = self.read_register(Register::REFMUX)?; + let data = RefMuxRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_refmux(&mut self, reg: &RefMuxRegister) -> Result<()> { + self.write_register(Register::REFMUX, reg.bits()) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index ae2fb64..4873704 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -193,7 +193,7 @@ impl Mode1Register { 0b110 => SensorBiasMagnitude::R10MOhm, 0b111 => panic!("Reserved SBMAG"), - _ => unreachable!() + _ => unreachable!(), } } @@ -211,7 +211,7 @@ impl Mode1Register { 0b100 => DigitalFilter::FIR, 0b101..=0b111 => panic!("Reserved filter"), - _ => unreachable!() + _ => unreachable!(), } } @@ -249,7 +249,7 @@ impl Mode2Register { 0b1110 => DataRate::SPS19200, 0b1111 => DataRate::SPS38400, - _ => unreachable!() + _ => unreachable!(), } } @@ -268,7 +268,7 @@ impl Mode2Register { 0b101 => PGAGain::VV32, 0b110 | 0b111 => panic!("Reserved gain"), - _ => unreachable!() + _ => unreachable!(), } } @@ -277,3 +277,223 @@ impl Mode2Register { self.insert(Mode2Register::from_bits_retain(bits << 4)); } } + +bitflags! { + pub struct InpMuxRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +impl InpMuxRegister { + pub fn get_muxn(&self) -> NegativeInpMux { + match self.bits() & 0b0000_1111 { + 0b0000 => NegativeInpMux::AIN0, + 0b0001 => NegativeInpMux::AIN1, + 0b0010 => NegativeInpMux::AIN2, + 0b0011 => NegativeInpMux::AIN3, + 0b0100 => NegativeInpMux::AIN4, + 0b0101 => NegativeInpMux::AIN5, + 0b0110 => NegativeInpMux::AIN6, + 0b0111 => NegativeInpMux::AIN7, + 0b1000 => NegativeInpMux::AIN8, + 0b1001 => NegativeInpMux::AIN9, + 0b1010 => NegativeInpMux::AINCOM, + 0b1011 => NegativeInpMux::TempSensMonNeg, + 0b1100 => NegativeInpMux::AnlgPwrSupMonNeg, + 0b1101 => NegativeInpMux::DgtlPwrSubMonNeg, + 0b1110 => NegativeInpMux::TDACTestSignalNeg, + 0b1111 => NegativeInpMux::Float, + + _ => unreachable!(), + } + } + + pub fn set_muxn(&mut self, muxn: NegativeInpMux) { + let bits = muxn as u8; + self.insert(InpMuxRegister::from_bits_retain(bits)); + } + + pub fn get_muxp(&self) -> PositiveInpMux { + match (self.bits() & 0b1111_0000) >> 4 { + 0b0000 => PositiveInpMux::AIN0, + 0b0001 => PositiveInpMux::AIN1, + 0b0010 => PositiveInpMux::AIN2, + 0b0011 => PositiveInpMux::AIN3, + 0b0100 => PositiveInpMux::AIN4, + 0b0101 => PositiveInpMux::AIN5, + 0b0110 => PositiveInpMux::AIN6, + 0b0111 => PositiveInpMux::AIN7, + 0b1000 => PositiveInpMux::AIN8, + 0b1001 => PositiveInpMux::AIN9, + 0b1010 => PositiveInpMux::AINCOM, + 0b1011 => PositiveInpMux::TempSensMonPos, + 0b1100 => PositiveInpMux::AnlgPwrSupMonPos, + 0b1101 => PositiveInpMux::DgtlPwrSubMonPos, + 0b1110 => PositiveInpMux::TDACTestSignalPos, + 0b1111 => PositiveInpMux::Float, + + _ => unreachable!(), + } + } + + pub fn set_muxp(&mut self, muxp: PositiveInpMux) { + let bits = muxp as u8; + self.insert(InpMuxRegister::from_bits_retain(bits << 4)); + } +} + +bitflags! { + pub struct IdacMuxRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +impl IdacMuxRegister { + pub fn get_mux1(&self) -> IdacOutMux { + match self.bits() & 0b0000_1111 { + 0b0000 => IdacOutMux::AIN0, + 0b0001 => IdacOutMux::AIN1, + 0b0010 => IdacOutMux::AIN2, + 0b0011 => IdacOutMux::AIN3, + 0b0100 => IdacOutMux::AIN4, + 0b0101 => IdacOutMux::AIN5, + 0b0110 => IdacOutMux::AIN6, + 0b0111 => IdacOutMux::AIN7, + 0b1000 => IdacOutMux::AIN8, + 0b1001 => IdacOutMux::AIN9, + 0b1010 => IdacOutMux::AINCOM, + 0b1011 => IdacOutMux::NoConnection, + + 0b1100..=0b1111 => panic!("Reserved IDAC Output Multiplexer"), + _ => unreachable!(), + } + } + + pub fn set_mux1(&mut self, mux1: IdacOutMux) { + let bits = mux1 as u8; + self.insert(IdacMuxRegister::from_bits_retain(bits)); + } + + pub fn get_mux2(&self) -> IdacOutMux { + match (self.bits() & 0b1111_0000) >> 4 { + 0b0000 => IdacOutMux::AIN0, + 0b0001 => IdacOutMux::AIN1, + 0b0010 => IdacOutMux::AIN2, + 0b0011 => IdacOutMux::AIN3, + 0b0100 => IdacOutMux::AIN4, + 0b0101 => IdacOutMux::AIN5, + 0b0110 => IdacOutMux::AIN6, + 0b0111 => IdacOutMux::AIN7, + 0b1000 => IdacOutMux::AIN8, + 0b1001 => IdacOutMux::AIN9, + 0b1010 => IdacOutMux::AINCOM, + 0b1011 => IdacOutMux::NoConnection, + + 0b1100..=0b1111 => panic!("Reserved IDAC Output Multiplexer"), + _ => unreachable!(), + } + } + + pub fn set_mux2(&mut self, mux2: IdacOutMux) { + let bits = mux2 as u8; + self.insert(IdacMuxRegister::from_bits_retain(bits << 4)); + } +} + +bitflags! { + pub struct IdacMagRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +impl IdacMagRegister { + pub fn get_mag1(&self) -> IdacCurMag { + match self.bits() & 0b0000_1111 { + 0b0000 => IdacCurMag::I50uA, + 0b0001 => IdacCurMag::I100uA, + 0b0010 => IdacCurMag::I250uA, + 0b0011 => IdacCurMag::I500uA, + 0b0100 => IdacCurMag::I750uA, + 0b0101 => IdacCurMag::I1000uA, + 0b0110 => IdacCurMag::I1500uA, + 0b0111 => IdacCurMag::I2000uA, + 0b1000 => IdacCurMag::I2500uA, + 0b1001 => IdacCurMag::I3000uA, + + 0b1010..=0b1111 => panic!("Reserved IDAC Magnitude Multiplexer"), + _ => unreachable!(), + } + } + + pub fn set_mag1(&mut self, mag1: IdacCurMag) { + let bits = mag1 as u8; + self.insert(IdacMagRegister::from_bits_retain(bits)); + } + + pub fn get_mag2(&self) -> IdacCurMag { + match (self.bits() & 0b1111_0000) >> 4 { + 0b0000 => IdacCurMag::I50uA, + 0b0001 => IdacCurMag::I100uA, + 0b0010 => IdacCurMag::I250uA, + 0b0011 => IdacCurMag::I500uA, + 0b0100 => IdacCurMag::I750uA, + 0b0101 => IdacCurMag::I1000uA, + 0b0110 => IdacCurMag::I1500uA, + 0b0111 => IdacCurMag::I2000uA, + 0b1000 => IdacCurMag::I2500uA, + 0b1001 => IdacCurMag::I3000uA, + + 0b1010..=0b1111 => panic!("Reserved IDAC Output Multiplexer"), + _ => unreachable!(), + } + } + + pub fn set_mag2(&mut self, mag2: IdacCurMag) { + let bits = mag2 as u8; + self.insert(IdacMagRegister::from_bits_retain(bits << 4)); + } +} + +bitflags! { + pub struct RefMuxRegister: u8 { + const _ = 0b0011_1111; + } +} + +impl RefMuxRegister { + pub fn get_rmuxn(&self) -> RefNegativeInp { + match self.bits() & 0b0000_0111 { + 0b000 => RefNegativeInp::Int2_5VRef, + 0b001 => RefNegativeInp::ExtAIN1, + 0b010 => RefNegativeInp::ExtAIN3, + 0b011 => RefNegativeInp::ExtAIN5, + 0b100 => RefNegativeInp::IntAnlgSup, + + 0b101..=0b111 => panic!("Reserved Reference Negative Input"), + _ => unreachable!(), + } + } + + pub fn set_rmuxn(&mut self, rmuxn: RefNegativeInp) { + let bits = rmuxn as u8; + self.insert(RefMuxRegister::from_bits_retain(bits)); + } + + pub fn get_rmuxp(&self) -> RefPositiveInp { + match (self.bits() & 0b0011_1000) >> 3 { + 0b000 => RefPositiveInp::Int2_5VRef, + 0b001 => RefPositiveInp::ExtAIN0, + 0b010 => RefPositiveInp::ExtAIN2, + 0b011 => RefPositiveInp::ExtAIN4, + 0b100 => RefPositiveInp::IntAnlgSup, + + 0b101..=0b111 => panic!("Reserved Reference Positive Input"), + _ => unreachable!() + } + } + + pub fn set_rmuxp(&mut self, rmuxp: RefPositiveInp) { + let bits = rmuxp as u8; + self.insert(RefMuxRegister::from_bits_retain(bits << 3)); + } +} diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs index 5ef296d..e089ff0 100644 --- a/crates/ads126x/src/register/enums.rs +++ b/crates/ads126x/src/register/enums.rs @@ -110,3 +110,96 @@ pub enum PGAGain { VV16 = 0b100, VV32 = 0b101, } + +#[repr(u8)] +pub enum NegativeInpMux { + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, + TempSensMonNeg = 0b1011, + AnlgPwrSupMonNeg = 0b1100, + DgtlPwrSubMonNeg = 0b1101, + TDACTestSignalNeg = 0b1110, + Float = 0b1111, +} + +#[repr(u8)] +pub enum PositiveInpMux { + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, + TempSensMonPos = 0b1011, + AnlgPwrSupMonPos = 0b1100, + DgtlPwrSubMonPos = 0b1101, + TDACTestSignalPos = 0b1110, + Float = 0b1111, +} + +#[repr(u8)] +pub enum IdacOutMux { + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, + NoConnection = 0b1011, +} + +/// Current magnitudes follow the pattern `I`. +/// - `mag` is the magnitude of current. +/// - `units` are uA meaning microamperes. +/// +/// I50uA = 50 microamps of current. +#[repr(u8)] +pub enum IdacCurMag { + I50uA = 0b0000, + I100uA = 0b0001, + I250uA = 0b0010, + I500uA = 0b0011, + I750uA = 0b0100, + I1000uA = 0b0101, + I1500uA = 0b0110, + I2000uA = 0b0111, + I2500uA = 0b1000, + I3000uA = 0b1001, +} + +#[repr(u8)] +pub enum RefNegativeInp { + Int2_5VRef = 0b000, + ExtAIN1 = 0b001, + ExtAIN3 = 0b010, + ExtAIN5 = 0b011, + IntAnlgSup = 0b100, +} + +#[repr(u8)] +pub enum RefPositiveInp { + Int2_5VRef = 0b000, + ExtAIN0 = 0b001, + ExtAIN2 = 0b010, + ExtAIN4 = 0b011, + IntAnlgSup = 0b100, +} From d50bebcf29660e317b2ccd1d947c549ed3736244 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Wed, 13 Nov 2024 21:11:40 -0500 Subject: [PATCH 13/22] Removed redundant StatusRegister impl block --- crates/ads126x/src/register.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index 4873704..c97127c 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -47,40 +47,6 @@ bitflags! { } } -impl StatusRegister { - pub fn is_adc2_data_new(&self) -> bool { - self.contains(StatusRegister::ADC2) - } - - pub fn is_adc1_data_new(&self) -> bool { - self.contains(StatusRegister::ADC1) - } - - pub fn is_extclk(&self) -> bool { - self.contains(StatusRegister::EXTCLK) - } - - pub fn is_ref_alm(&self) -> bool { - self.contains(StatusRegister::REF_ALM) - } - - pub fn is_pgal_alm(&self) -> bool { - self.contains(StatusRegister::PGAL_ALM) - } - - pub fn is_pgah_alm(&self) -> bool { - self.contains(StatusRegister::PGAH_ALM) - } - - pub fn is_pgad_alm(&self) -> bool { - self.contains(StatusRegister::PGAD_ALM) - } - - pub fn is_reset(&self) -> bool { - self.contains(StatusRegister::RESET) - } -} - bitflags! { pub struct IdRegister: u8 { const _ = !0; // Source may set any bits From 27e7134ecafabc0920c0ee5e5adc1044a377f9be Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Wed, 13 Nov 2024 22:29:46 -0500 Subject: [PATCH 14/22] Added more registers --- crates/ads126x/src/lib.rs | 67 +++++++++++++- crates/ads126x/src/register.rs | 128 +++++++++++++++++++++++++++ crates/ads126x/src/register/enums.rs | 48 +++++++--- 3 files changed, 232 insertions(+), 11 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 576ccf4..0031943 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -6,7 +6,7 @@ mod register; use error::ADS126xError; use register::{ - IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register + GpioConRegister, GpioDatRegister, GpioDirRegister, IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register, TdacnRegister, TdacpRegister }; use embedded_hal::spi::FullDuplex; @@ -290,4 +290,69 @@ where pub fn set_refmux(&mut self, reg: &RefMuxRegister) -> Result<()> { self.write_register(Register::REFMUX, reg.bits()) } + + pub fn get_tdacp(&mut self) -> Result { + let bits = self.read_register(Register::TDACP)?; + let data = TdacpRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_tdacp(&mut self, reg: &TdacpRegister) -> Result<()> { + self.write_register(Register::TDACP, reg.bits()) + } + + pub fn get_tdacn(&mut self) -> Result { + let bits = self.read_register(Register::TDACN)?; + let data = TdacnRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_tdacn(&mut self, reg: &TdacnRegister) -> Result<()> { + self.write_register(Register::TDACN, reg.bits()) + } + + pub fn get_gpiocon(&mut self) -> Result { + let bits = self.read_register(Register::GPIOCON)?; + let data = GpioConRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_gpiocon(&mut self, reg: &GpioConRegister) -> Result<()> { + self.write_register(Register::GPIOCON, reg.bits()) + } + + pub fn get_gpiodir(&mut self) -> Result { + let bits = self.read_register(Register::GPIODIR)?; + let data = GpioDirRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_gpiodir(&mut self, reg: &GpioDirRegister) -> Result<()> { + self.write_register(Register::GPIODIR, reg.bits()) + } + + pub fn get_gpiodat(&mut self) -> Result { + let bits = self.read_register(Register::GPIODAT)?; + let data = GpioDatRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_gpiodat(&mut self, reg: &GpioDatRegister) -> Result<()> { + self.write_register(Register::GPIODAT, reg.bits()) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index c97127c..f80e077 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -463,3 +463,131 @@ impl RefMuxRegister { self.insert(RefMuxRegister::from_bits_retain(bits << 3)); } } + +bitflags! { + pub struct TdacpRegister: u8 { + const OUTP = 0b1000_0000; + + const _ = 0b1001_1111; + } +} + +impl TdacpRegister { + pub fn get_magp(&self) -> TdacOutMag { + match self.bits() & 0b0001_1111 { + 0b01001 => TdacOutMag::V4_5, + 0b01000 => TdacOutMag::V3_5, + 0b00111 => TdacOutMag::V3, + 0b00110 => TdacOutMag::V2_75, + 0b00101 => TdacOutMag::V2_625, + 0b00100 => TdacOutMag::V2_5625, + 0b00011 => TdacOutMag::V2_53125, + 0b00010 => TdacOutMag::V2_515625, + 0b00001 => TdacOutMag::V2_5078125, + 0b00000 => TdacOutMag::V2_5, + 0b10001 => TdacOutMag::V2_4921875, + 0b10010 => TdacOutMag::V2_484375, + 0b10011 => TdacOutMag::V2_46875, + 0b10100 => TdacOutMag::V2_4375, + 0b10101 => TdacOutMag::V2_375, + 0b10110 => TdacOutMag::V2_25, + 0b10111 => TdacOutMag::V2, + 0b11000 => TdacOutMag::V1_5, + 0b11001 => TdacOutMag::V0_5, + + 0b01010..=0b10000 | 0b11010..=0b11111 => panic!("Reserved MAGP"), + _ => unreachable!(), + } + } + + pub fn set_magp(&mut self, magp: TdacOutMag) { + let bits = magp as u8; + self.insert(TdacpRegister::from_bits_retain(bits)); + } +} + +bitflags! { + pub struct TdacnRegister: u8 { + const OUTN = 0b1000_0000; + + const _ = 0b1001_1111; + } +} + +impl TdacnRegister { + pub fn get_magn(&self) -> TdacOutMag { + match self.bits() & 0b0001_1111 { + 0b01001 => TdacOutMag::V4_5, + 0b01000 => TdacOutMag::V3_5, + 0b00111 => TdacOutMag::V3, + 0b00110 => TdacOutMag::V2_75, + 0b00101 => TdacOutMag::V2_625, + 0b00100 => TdacOutMag::V2_5625, + 0b00011 => TdacOutMag::V2_53125, + 0b00010 => TdacOutMag::V2_515625, + 0b00001 => TdacOutMag::V2_5078125, + 0b00000 => TdacOutMag::V2_5, + 0b10001 => TdacOutMag::V2_4921875, + 0b10010 => TdacOutMag::V2_484375, + 0b10011 => TdacOutMag::V2_46875, + 0b10100 => TdacOutMag::V2_4375, + 0b10101 => TdacOutMag::V2_375, + 0b10110 => TdacOutMag::V2_25, + 0b10111 => TdacOutMag::V2, + 0b11000 => TdacOutMag::V1_5, + 0b11001 => TdacOutMag::V0_5, + + 0b01010..=0b10000 | 0b11010..=0b11111 => panic!("Reserved MAGN"), + _ => unreachable!(), + } + } + + pub fn set_magn(&mut self, magn: TdacOutMag) { + let bits = magn as u8; + self.insert(TdacnRegister::from_bits_retain(bits)); + } +} + +bitflags! { + pub struct GpioConRegister: u8 { + const CON0 = 0b0000_0001; // GPIO[0] -> AIN3 + const CON1 = 0b0000_0010; // GPIO[1] -> AIN4 + const CON2 = 0b0000_0100; // GPIO[2] -> AIN5 + const CON3 = 0b0000_1000; // GPIO[3] -> AIN6 + const CON4 = 0b0001_0000; // GPIO[4] -> AIN7 + const CON5 = 0b0010_0000; // GPIO[5] -> AIN8 + const CON6 = 0b0100_0000; // GPIO[6] -> AIN9 + const CON7 = 0b1000_0000; // GPIO[7] -> AINCOM + } +} + +bitflags! { + /// Setting `DIR` to: + /// - 0 = `GPIO` is output + /// - 1 = `GPIO` is input + pub struct GpioDirRegister: u8 { + const DIR0 = 0b0000_0001; + const DIR1 = 0b0000_0010; + const DIR2 = 0b0000_0100; + const DIR3 = 0b0000_1000; + const DIR4 = 0b0001_0000; + const DIR5 = 0b0010_0000; + const DIR6 = 0b0100_0000; + const DIR7 = 0b1000_0000; + } +} + +bitflags! { + /// If `GPIO` is output, read returns 0b. + /// If `GPIO` is input, write sets `GPIO` to high (if 1) or low (if 0). + pub struct GpioDatRegister: u8 { + const DAT0 = 0b0000_0001; + const DAT1 = 0b0000_0010; + const DAT2 = 0b0000_0100; + const DAT3 = 0b0000_1000; + const DAT4 = 0b0001_0000; + const DAT5 = 0b0010_0000; + const DAT6 = 0b0100_0000; + const DAT7 = 0b1000_0000; + } +} diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs index e089ff0..dc7f133 100644 --- a/crates/ads126x/src/register/enums.rs +++ b/crates/ads126x/src/register/enums.rs @@ -174,16 +174,16 @@ pub enum IdacOutMux { /// I50uA = 50 microamps of current. #[repr(u8)] pub enum IdacCurMag { - I50uA = 0b0000, - I100uA = 0b0001, - I250uA = 0b0010, - I500uA = 0b0011, - I750uA = 0b0100, - I1000uA = 0b0101, - I1500uA = 0b0110, - I2000uA = 0b0111, - I2500uA = 0b1000, - I3000uA = 0b1001, + I50uA = 0b0000, + I100uA = 0b0001, + I250uA = 0b0010, + I500uA = 0b0011, + I750uA = 0b0100, + I1000uA = 0b0101, + I1500uA = 0b0110, + I2000uA = 0b0111, + I2500uA = 0b1000, + I3000uA = 0b1001, } #[repr(u8)] @@ -203,3 +203,31 @@ pub enum RefPositiveInp { ExtAIN4 = 0b011, IntAnlgSup = 0b100, } + +/// Voltages are with respect to V_AVSS. +/// Output magnitudes follow the pattern `V`. +/// - `num` is the output magnitude in volts where _ is a substitute for a decimal point. +/// +/// V4_5 = 4.5 V. +#[repr(u8)] +pub enum TdacOutMag { + V4_5 = 0b01001, + V3_5 = 0b01000, + V3 = 0b00111, + V2_75 = 0b00110, + V2_625 = 0b00101, + V2_5625 = 0b00100, + V2_53125 = 0b00011, + V2_515625 = 0b00010, + V2_5078125 = 0b00001, + V2_5 = 0b00000, + V2_4921875 = 0b10001, + V2_484375 = 0b10010, + V2_46875 = 0b10011, + V2_4375 = 0b10100, + V2_375 = 0b10101, + V2_25 = 0b10110, + V2 = 0b10111, + V1_5 = 0b11000, + V0_5 = 0b11001, +} From ff34e4a6cdc115abbfacdba38e41fb0e121d5e83 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sat, 16 Nov 2024 23:32:38 -0500 Subject: [PATCH 15/22] Implemented last registers --- crates/ads126x/src/lib.rs | 109 +++++++++++++++++------ crates/ads126x/src/register.rs | 126 +++++++++++++++++++++++++++ crates/ads126x/src/register/enums.rs | 29 ++++++ 3 files changed, 237 insertions(+), 27 deletions(-) diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 0031943..7c9ef3f 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -6,7 +6,7 @@ mod register; use error::ADS126xError; use register::{ - GpioConRegister, GpioDatRegister, GpioDirRegister, IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register, TdacnRegister, TdacpRegister + Adc2CfgRegister, Adc2MuxRegister, GpioConRegister, GpioDatRegister, GpioDirRegister, IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register, TdacnRegister, TdacpRegister }; use embedded_hal::spi::FullDuplex; @@ -213,43 +213,39 @@ where } pub fn get_ofcal(&mut self) -> Result { - let mut bytes = self.read_multiple_registers(Register::OFCAL0, 3)?; // [OFCAL0, OFCAL1, OFCAL2] - bytes.reverse(); // [OFCAL2, OFCAL1, OFCAL0] - let mut res: u32 = 0; - for &b in &bytes[3..0] { - res <<= 8; // Shift previous bits left one byte - res |= b as u32; // Append new byte to the end - } + let bytes = self.read_multiple_registers(Register::OFCAL0, 3)?; // [OFCAL0, OFCAL1, OFCAL2] + let res = (bytes[2] as u32) << 16 | + (bytes[1] as u32) << 8 | + (bytes[0] as u32); Ok(res) } pub fn set_ofcal(&mut self, ofcal: u32) -> Result<()> { - let mut bytes: [u8; 4] = [0; 4]; - for i in 0..4 { - let b = (ofcal >> (8 * i)) & 0xFF; // Get desired byte - bytes[i] = u8::try_from(b).unwrap(); // Should not panic as & 0xFF ensures b is a u8 - } - self.write_multiple_registers(Register::OFCAL0, &bytes[0..3]) + // Will not panic as & 0xFF ensures values are u8 + let res: [u8; 3] = [ + u8::try_from(ofcal & 0xFF).unwrap(), + u8::try_from((ofcal >> 8) & 0xFF).unwrap(), + u8::try_from((ofcal >> 16) & 0xFF).unwrap(), + ]; + self.write_multiple_registers(Register::OFCAL0, &res) } pub fn get_fscal(&mut self) -> Result { - let mut bytes = self.read_multiple_registers(Register::FSCAL0, 3)?; // [FSCAL0, FSCAL1, FSCAL2] - bytes.reverse(); // [FSCAL2, FSCAL1, FSCAL0] - let mut res: u32 = 0; - for &b in &bytes[3..0] { - res <<= 8; // Shift previous bits left one byte - res |= b as u32; // Append new byte to the end - } + let bytes = self.read_multiple_registers(Register::FSCAL0, 3)?; // [FSCAL0, FSCAL1, FSCAL2] + let res = (bytes[2] as u32) << 16 | + (bytes[1] as u32) << 8 | + (bytes[0] as u32); Ok(res) } pub fn set_fscal(&mut self, fscal: u32) -> Result<()> { - let mut bytes: [u8; 4] = [0; 4]; - for i in 0..4 { - let b = (fscal >> (8 * i)) & 0xFF; // Get desired byte - bytes[i] = u8::try_from(b).unwrap(); // Should not panic as & 0xFF ensures b is a u8 - } - self.write_multiple_registers(Register::FSCAL0, &bytes[0..3]) + // Will not panic as & 0xFF ensures values are u8 + let res: [u8; 3] = [ + u8::try_from(fscal & 0xFF).unwrap(), + u8::try_from((fscal >> 8) & 0xFF).unwrap(), + u8::try_from((fscal >> 16) & 0xFF).unwrap(), + ]; + self.write_multiple_registers(Register::FSCAL0, &res) } pub fn get_idacmux(&mut self) -> Result { @@ -355,4 +351,63 @@ where pub fn set_gpiodat(&mut self, reg: &GpioDatRegister) -> Result<()> { self.write_register(Register::GPIODAT, reg.bits()) } + + pub fn get_adc2cfg(&mut self) -> Result { + let bits = self.read_register(Register::ADC2CFG)?; + let data = Adc2CfgRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_adc2cfg(&mut self, reg: &Adc2CfgRegister) -> Result<()> { + self.write_register(Register::ADC2CFG, reg.bits()) + } + + + pub fn get_adc2mux(&mut self) -> Result { + let bits = self.read_register(Register::ADC2MUX)?; + let data = Adc2MuxRegister::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_adc2mux(&mut self, reg: &Adc2MuxRegister) -> Result<()> { + self.write_register(Register::ADC2MUX, reg.bits()) + } + + pub fn get_adc2ofc(&mut self) -> Result { + let bytes = self.read_multiple_registers(Register::ADC2OFC0, 2)?; // [ADC2OFC0, ADC2OFC1] + let res = (bytes[1] as u16) << 8 | + (bytes[0] as u16); + Ok(res) + } + + pub fn set_adc2ofc(&mut self, ofc2: u16) -> Result<()> { + // Will not panic as & 0xFF ensures values are u8 + let res: [u8; 2] = [ + u8::try_from(ofc2 & 0xFF).unwrap(), + u8::try_from((ofc2 >> 8) & 0xFF).unwrap(), + ]; + self.write_multiple_registers(Register::ADC2OFC0, &res) + } + + pub fn get_adc2fsc(&mut self) -> Result { + let bytes = self.read_multiple_registers(Register::ADC2FSC0, 2)?; // [ADC2FSC0, ADC2FSC1] + let res = (bytes[1] as u16) << 8 | + (bytes[0] as u16); + Ok(res) + } + + pub fn set_adc2fsc(&mut self, fsc2: u32) -> Result<()> { + // Will not panic as & 0xFF ensures values are u8 + let res: [u8; 2] = [ + u8::try_from(fsc2 & 0xFF).unwrap(), + u8::try_from((fsc2 >> 8) & 0xFF).unwrap(), + ]; + self.write_multiple_registers(Register::ADC2FSC0, &res) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index f80e077..c03a91f 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -591,3 +591,129 @@ bitflags! { const DAT7 = 0b1000_0000; } } + +bitflags! { + pub struct Adc2CfgRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +impl Adc2CfgRegister { + pub fn get_gain2(&self) -> Adc2Gain { + match self.bits() & 0b0000_0111 { + 0b000 => Adc2Gain::VV1, + 0b001 => Adc2Gain::VV2, + 0b010 => Adc2Gain::VV4, + 0b011 => Adc2Gain::VV8, + 0b100 => Adc2Gain::VV16, + 0b101 => Adc2Gain::VV32, + 0b110 => Adc2Gain::VV64, + 0b111 => Adc2Gain::VV128, + + _ => unreachable!(), + } + } + + pub fn set_gain2(&mut self, gain2: Adc2Gain) { + let bits = gain2 as u8; + self.insert(Adc2CfgRegister::from_bits_retain(bits)); + } + + pub fn get_ref2(&self) -> Adc2RefInp { + match (self.bits() & 0b0011_1000) >> 3 { + 0b000 => Adc2RefInp::Int2_5VRef, + 0b001 => Adc2RefInp::ExtAIN0_1, + 0b010 => Adc2RefInp::ExtAIN2_3, + 0b011 => Adc2RefInp::ExtAIN4_5, + 0b100 => Adc2RefInp::IntAnlgSup, + + 0b101..=0b111 => panic!("Reserved ADC2 reference input"), + _ => unreachable!(), + } + } + + pub fn set_ref2(&mut self, ref2: Adc2RefInp) { + let bits = ref2 as u8; + self.insert(Adc2CfgRegister::from_bits_retain(bits << 3)); + } + + pub fn get_dr2(&self) -> Adc2DataRate { + match (self.bits() & 0b1100_0000) >> 6 { + 0b00 => Adc2DataRate::SPS10, + 0b01 => Adc2DataRate::SPS100, + 0b10 => Adc2DataRate::SPS400, + 0b11 => Adc2DataRate::SPS800, + + _ => unreachable!(), + } + } + + pub fn set_dr2(&mut self, dr2: Adc2DataRate) { + let bits = dr2 as u8; + self.insert(Adc2CfgRegister::from_bits_retain(bits << 6)); + } +} + +bitflags! { + pub struct Adc2MuxRegister: u8 { + const _ = !0; // Source may set any bits + } +} + +impl Adc2MuxRegister { + pub fn get_muxn2(&self) -> NegativeInpMux { + match self.bits() & 0b0000_1111 { + 0b0000 => NegativeInpMux::AIN0, + 0b0001 => NegativeInpMux::AIN1, + 0b0010 => NegativeInpMux::AIN2, + 0b0011 => NegativeInpMux::AIN3, + 0b0100 => NegativeInpMux::AIN4, + 0b0101 => NegativeInpMux::AIN5, + 0b0110 => NegativeInpMux::AIN6, + 0b0111 => NegativeInpMux::AIN7, + 0b1000 => NegativeInpMux::AIN8, + 0b1001 => NegativeInpMux::AIN9, + 0b1010 => NegativeInpMux::AINCOM, + 0b1011 => NegativeInpMux::TempSensMonNeg, + 0b1100 => NegativeInpMux::AnlgPwrSupMonNeg, + 0b1101 => NegativeInpMux::DgtlPwrSubMonNeg, + 0b1110 => NegativeInpMux::TDACTestSignalNeg, + 0b1111 => NegativeInpMux::Float, + + _ => unreachable!(), + } + } + + pub fn set_muxn2(&mut self, muxn2: NegativeInpMux) { + let bits = muxn2 as u8; + self.insert(Adc2MuxRegister::from_bits_retain(bits)); + } + + pub fn get_muxp2(&self) -> PositiveInpMux { + match (self.bits() & 0b1111_0000) >> 4 { + 0b0000 => PositiveInpMux::AIN0, + 0b0001 => PositiveInpMux::AIN1, + 0b0010 => PositiveInpMux::AIN2, + 0b0011 => PositiveInpMux::AIN3, + 0b0100 => PositiveInpMux::AIN4, + 0b0101 => PositiveInpMux::AIN5, + 0b0110 => PositiveInpMux::AIN6, + 0b0111 => PositiveInpMux::AIN7, + 0b1000 => PositiveInpMux::AIN8, + 0b1001 => PositiveInpMux::AIN9, + 0b1010 => PositiveInpMux::AINCOM, + 0b1011 => PositiveInpMux::TempSensMonPos, + 0b1100 => PositiveInpMux::AnlgPwrSupMonPos, + 0b1101 => PositiveInpMux::DgtlPwrSubMonPos, + 0b1110 => PositiveInpMux::TDACTestSignalPos, + 0b1111 => PositiveInpMux::Float, + + _ => unreachable!(), + } + } + + pub fn set_muxp2(&mut self, muxp2: PositiveInpMux) { + let bits = muxp2 as u8; + self.insert(Adc2MuxRegister::from_bits_retain(bits << 4)); + } +} diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs index dc7f133..b7c6268 100644 --- a/crates/ads126x/src/register/enums.rs +++ b/crates/ads126x/src/register/enums.rs @@ -231,3 +231,32 @@ pub enum TdacOutMag { V1_5 = 0b11000, V0_5 = 0b11001, } + +#[repr(u8)] +pub enum Adc2Gain { + VV1 = 0b000, + VV2 = 0b001, + VV4 = 0b010, + VV8 = 0b011, + VV16 = 0b100, + VV32 = 0b101, + VV64 = 0b110, + VV128 = 0b111, +} + +#[repr(u8)] +pub enum Adc2RefInp { + Int2_5VRef = 0b000, + ExtAIN0_1 = 0b001, + ExtAIN2_3 = 0b010, + ExtAIN4_5 = 0b011, + IntAnlgSup = 0b100, +} + +#[repr(u8)] +pub enum Adc2DataRate { + SPS10 = 0b00, + SPS100 = 0b01, + SPS400 = 0b10, + SPS800 = 0b11, +} From ca58815ccc27486e0ccabcd2bfe224d0e5b37d44 Mon Sep 17 00:00:00 2001 From: Bradley Myers Date: Sat, 16 Nov 2024 23:54:59 -0500 Subject: [PATCH 16/22] Align Register values --- crates/ads126x/src/register.rs | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index c03a91f..11ec3b9 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -5,33 +5,33 @@ use bitflags::bitflags; #[repr(u8)] pub enum Register { - ID = 0x00, - POWER = 0x01, + ID = 0x00, + POWER = 0x01, INTERFACE = 0x02, - MODE0 = 0x03, - MODE1 = 0x04, - MODE2 = 0x05, - INPMUX = 0x06, - OFCAL0 = 0x07, - OFCAL1 = 0x08, - OFCAL2 = 0x09, - FSCAL0 = 0x0A, - FSCAL1 = 0x0B, - FSCAL2 = 0x0C, - IDACMUX = 0x0D, - IDACMAG = 0x0E, - REFMUX = 0x0F, - TDACP = 0x10, - TDACN = 0x11, - GPIOCON = 0x12, - GPIODIR = 0x13, - GPIODAT = 0x14, - ADC2CFG = 0x15, - ADC2MUX = 0x16, - ADC2OFC0 = 0x17, - ADC2OFC1 = 0x18, - ADC2FSC0 = 0x19, - ADC2FSC1 = 0x1A, + MODE0 = 0x03, + MODE1 = 0x04, + MODE2 = 0x05, + INPMUX = 0x06, + OFCAL0 = 0x07, + OFCAL1 = 0x08, + OFCAL2 = 0x09, + FSCAL0 = 0x0A, + FSCAL1 = 0x0B, + FSCAL2 = 0x0C, + IDACMUX = 0x0D, + IDACMAG = 0x0E, + REFMUX = 0x0F, + TDACP = 0x10, + TDACN = 0x11, + GPIOCON = 0x12, + GPIODIR = 0x13, + GPIODAT = 0x14, + ADC2CFG = 0x15, + ADC2MUX = 0x16, + ADC2OFC0 = 0x17, + ADC2OFC1 = 0x18, + ADC2FSC0 = 0x19, + ADC2FSC1 = 0x1A, } bitflags! { From 4908acd44a9323b189c4cf5ef7a361d44477b2e0 Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Sun, 17 Nov 2024 22:00:41 -0500 Subject: [PATCH 17/22] Start init and add default example to Mode2Register. --- crates/ads126x/Cargo.toml | 2 +- crates/ads126x/src/lib.rs | 46 +++++++++++++++++++++++++++++++--- crates/ads126x/src/register.rs | 4 +++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/crates/ads126x/Cargo.toml b/crates/ads126x/Cargo.toml index cca5983..498c859 100644 --- a/crates/ads126x/Cargo.toml +++ b/crates/ads126x/Cargo.toml @@ -9,12 +9,12 @@ embedded-hal = {workspace = true} bitflags = { version = "2.3.1", features = ["serde"] } nb = "1.1.0" heapless = {workspace = true} +cortex-m = { workspace = true } [dev-dependencies] defmt-test = { workspace = true } panic-probe = { workspace = true } stm32h7xx-hal = { workspace = true } -cortex-m = { workspace = true } [[test]] name = "example" diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 7c9ef3f..4330059 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -10,16 +10,19 @@ use register::{ }; use embedded_hal::spi::FullDuplex; +use embedded_hal::digital::v2::OutputPin; use heapless::Vec; /// The [`Result`] type for ADS126x operations. pub type Result = core::result::Result; -pub struct ADS126x +pub struct ADS126x where SPI: FullDuplex, + GpioPin: OutputPin, { spi: SPI, + reset_pin: GpioPin, } pub enum ADCCommand { @@ -41,12 +44,47 @@ pub enum ADCCommand { WREG(Register, u8), // (register address, number of registers) } -impl ADS126x +fn delay(delay: u32) { + for _ in 0..delay { + cortex_m::asm::nop(); + } +} + +impl ADS126x where SPI: FullDuplex, + GpioPin: OutputPin, { - pub fn new(spi: SPI) -> Self { - Self { spi } + pub fn new(spi: SPI, reset_pin: GpioPin) -> Self { + Self { spi, reset_pin } + } + + pub fn init(&mut self) -> Result<()> { + self.reset()?; + // write configuration registers + delay(65536); // must wait 2^16 clock cycles, is this SPI clock? + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(register::DataRate::SPS1200); + self.set_mode2(&mode2_cfg)?; + + // Set the rest of the registers below + // ... + + // start adc1 + self.send_command(ADCCommand::START1)?; + // start adc2 + self.send_command(ADCCommand::START2)?; + Ok(()) + } + + fn reset(&mut self) -> Result<()> { + self.reset_pin.set_high().map_err(|_| ADS126xError::IO)?; + delay(1000); + self.reset_pin.set_low().map_err(|_| ADS126xError::IO)?; + delay(1000); + self.reset_pin.set_high().map_err(|_| ADS126xError::IO)?; + delay(1000); + Ok(()) } pub fn send_command(&mut self, command: ADCCommand) -> Result<()> { diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index 11ec3b9..dadfae6 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -196,6 +196,10 @@ bitflags! { } impl Mode2Register { + pub fn default() -> Self { + Mode2Register::from_bits_truncate(0b0000_0100) + } + pub fn get_dr(&self) -> DataRate { match self.bits() & 0b0000_1111 { 0b0000 => DataRate::SPS2_5, From 840a32def287cf65892e464707b92ef654755b06 Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Thu, 21 Nov 2024 21:28:52 -0500 Subject: [PATCH 18/22] Add default constructors to registers. --- crates/ads126x/src/register.rs | 136 +++++++++++++++++++++++++++ crates/ads126x/src/register/enums.rs | 7 ++ 2 files changed, 143 insertions(+) diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index dadfae6..4904043 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -76,6 +76,37 @@ bitflags! { } } +impl PowerRegister { + pub fn default() -> Self { + PowerRegister::from_bits_truncate(0b0001_0001) + } + + pub fn set_vbias(&mut self, vbias: bool) { + if vbias { + self.insert(PowerRegister::VBIAS); + } else { + self.remove(PowerRegister::VBIAS); + } + } + + pub fn set_intref(&mut self, intref: bool) { + if intref { + self.insert(PowerRegister::INTREF); + } else { + self.remove(PowerRegister::INTREF); + } + } + + pub fn get_reset(&self) -> bool { + self.contains(PowerRegister::RESET) + } + + // must be cleared if set to detect further resets. + pub fn clear_reset(&mut self) { + self.remove(PowerRegister::RESET); + } +} + bitflags! { /// WARNING: If CRC is 0b11 set by ADC, it will reflect as CRC enabled not reserved. /// CRC only accounts for 0b00 disabled and 0b01 enabled. @@ -86,6 +117,50 @@ bitflags! { } } +impl InterfaceRegister { + pub fn default() -> Self { + InterfaceRegister::from_bits_truncate(0b0000_0101) + } + + pub fn get_crc(&self) -> CrcMode { + match self.bits() & 0b0000_0001 { + 0b00 => CrcMode::Disabled, + 0b01 => CrcMode::Checksum, + 0b10 => CrcMode::CRC, + _ => unreachable!(), + } + } + + pub fn set_crc(&mut self, crc: CrcMode) { + let bits = crc as u8; + self.insert(InterfaceRegister::from_bits_retain(bits)); + } + + pub fn get_status(&self) -> bool { + self.contains(InterfaceRegister::STATUS) + } + + pub fn set_status(&mut self, status: bool) { + if status { + self.insert(InterfaceRegister::STATUS); + } else { + self.remove(InterfaceRegister::STATUS); + } + } + + pub fn get_timeout(&self) -> bool { + self.contains(InterfaceRegister::TIMEOUT) + } + + pub fn set_timeout(&mut self, timeout: bool) { + if timeout { + self.insert(InterfaceRegister::TIMEOUT); + } else { + self.remove(InterfaceRegister::TIMEOUT); + } + } +} + bitflags! { pub struct Mode0Register: u8 { const RUNMODE = 0b0100_0000; @@ -96,6 +171,10 @@ bitflags! { } impl Mode0Register { + pub fn default() -> Self { + Mode0Register::from_bits_truncate(0b0000_0000) + } + pub fn get_delay(&self) -> ConversionDelay { match self.bits() & 0b0000_1111 { 0b0000 => ConversionDelay::DNone, @@ -148,6 +227,10 @@ bitflags! { } impl Mode1Register { + pub fn default() -> Self { + Mode1Register::from_bits_truncate(0b1000_0000) + } + pub fn get_sbmag(&self) -> SensorBiasMagnitude { match self.bits() & 0b0000_0111 { 0b000 => SensorBiasMagnitude::BNone, @@ -255,6 +338,10 @@ bitflags! { } impl InpMuxRegister { + pub fn default() -> Self { + InpMuxRegister::from_bits_truncate(0b0000_0001) + } + pub fn get_muxn(&self) -> NegativeInpMux { match self.bits() & 0b0000_1111 { 0b0000 => NegativeInpMux::AIN0, @@ -319,6 +406,10 @@ bitflags! { } impl IdacMuxRegister { + pub fn default() -> Self { + IdacMuxRegister::from_bits_truncate(0b1011_1011) + } + pub fn get_mux1(&self) -> IdacOutMux { match self.bits() & 0b0000_1111 { 0b0000 => IdacOutMux::AIN0, @@ -377,6 +468,10 @@ bitflags! { } impl IdacMagRegister { + pub fn default() -> Self { + IdacMagRegister::from_bits_truncate(0b0000_0000) + } + pub fn get_mag1(&self) -> IdacCurMag { match self.bits() & 0b0000_1111 { 0b0000 => IdacCurMag::I50uA, @@ -431,6 +526,10 @@ bitflags! { } impl RefMuxRegister { + pub fn default() -> Self { + RefMuxRegister::from_bits_truncate(0b0000_0000) + } + pub fn get_rmuxn(&self) -> RefNegativeInp { match self.bits() & 0b0000_0111 { 0b000 => RefNegativeInp::Int2_5VRef, @@ -477,6 +576,11 @@ bitflags! { } impl TdacpRegister { + // there is no defined default values in the datasheet so just zeros. + pub fn default() -> Self { + TdacpRegister::from_bits_truncate(0b0000_0000) + } + pub fn get_magp(&self) -> TdacOutMag { match self.bits() & 0b0001_1111 { 0b01001 => TdacOutMag::V4_5, @@ -519,6 +623,11 @@ bitflags! { } impl TdacnRegister { + // there is no defined default values in the datasheet so just zeros. + pub fn default() -> Self { + TdacnRegister::from_bits_truncate(0b0000_0000) + } + pub fn get_magn(&self) -> TdacOutMag { match self.bits() & 0b0001_1111 { 0b01001 => TdacOutMag::V4_5, @@ -565,6 +674,12 @@ bitflags! { } } +impl GpioConRegister { + pub fn default() -> Self { + GpioConRegister::from_bits_truncate(0b0000_0000) + } +} + bitflags! { /// Setting `DIR` to: /// - 0 = `GPIO` is output @@ -581,6 +696,12 @@ bitflags! { } } +impl GpioDirRegister { + pub fn default() -> Self { + GpioDirRegister::from_bits_truncate(0b0000_0000) + } +} + bitflags! { /// If `GPIO` is output, read returns 0b. /// If `GPIO` is input, write sets `GPIO` to high (if 1) or low (if 0). @@ -596,6 +717,13 @@ bitflags! { } } +impl GpioDatRegister { + // there is no defined default values in the datasheet so just zeros. + pub fn default() -> Self { + GpioDatRegister::from_bits_truncate(0b0000_0000) + } +} + bitflags! { pub struct Adc2CfgRegister: u8 { const _ = !0; // Source may set any bits @@ -603,6 +731,10 @@ bitflags! { } impl Adc2CfgRegister { + pub fn default() -> Self { + Adc2CfgRegister::from_bits_truncate(0b0000_0000) + } + pub fn get_gain2(&self) -> Adc2Gain { match self.bits() & 0b0000_0111 { 0b000 => Adc2Gain::VV1, @@ -665,6 +797,10 @@ bitflags! { } impl Adc2MuxRegister { + pub fn default() -> Self { + Adc2MuxRegister::from_bits_truncate(0b0000_0001) + } + pub fn get_muxn2(&self) -> NegativeInpMux { match self.bits() & 0b0000_1111 { 0b0000 => NegativeInpMux::AIN0, diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs index b7c6268..48f8430 100644 --- a/crates/ads126x/src/register/enums.rs +++ b/crates/ads126x/src/register/enums.rs @@ -68,6 +68,13 @@ pub enum SensorBiasMagnitude { R10MOhm = 0b110, } +#[repr(u8)] +pub enum CrcMode { + Disabled = 0b00, + Checksum = 0b01, + CRC = 0b10, +} + #[repr(u8)] pub enum DigitalFilter { Sinc1 = 0b000, From 6d2ce9f42aae32f5c1289c334dcdea22542a27ff Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Sun, 8 Dec 2024 20:18:54 -0500 Subject: [PATCH 19/22] Rework driver to avoid taking ownership of spi peripheral. --- Cargo.lock | 2 +- Cargo.toml | 3 +- boards/temperature/Cargo.toml | 1 + boards/temperature/src/adc_manager.rs | 80 +++++ boards/temperature/src/main.rs | 6 + crates/ads126x/src/lib.rs | 436 ++++++++++++++++---------- crates/ads126x/src/register.rs | 66 ++-- crates/ads126x/src/register/enums.rs | 258 +++++++-------- 8 files changed, 531 insertions(+), 321 deletions(-) create mode 100644 boards/temperature/src/adc_manager.rs diff --git a/Cargo.lock b/Cargo.lock index ff0ed16..d7de0cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -939,7 +939,6 @@ dependencies = [ [[package]] name = "stm32h7xx-hal" version = "0.16.0" -source = "git+https://github.com/uorocketry/stm32h7xx-hal#412160269f1729d55bc52de17463695db2c6bc6c" dependencies = [ "bare-metal 1.0.0", "cast", @@ -1006,6 +1005,7 @@ dependencies = [ name = "temperature" version = "0.1.0" dependencies = [ + "ads126x", "chrono", "common-arm", "cortex-m", diff --git a/Cargo.toml b/Cargo.toml index 8cb4cf7..7415b95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,9 @@ members = ["boards/*", "examples/*", "crates/*"] default-members = ["boards/*", "examples/*"] [workspace.dependencies.stm32h7xx-hal] -git = "https://github.com/uorocketry/stm32h7xx-hal" +# git = "https://github.com/uorocketry/stm32h7xx-hal" # We use 35 even though we have the 33. +path = "/home/bonjour/Rocketry/stm32h7xx-hal" features = ["defmt", "rt", "stm32h735", "can", "rtc"] [workspace.dependencies.serde] diff --git a/boards/temperature/Cargo.toml b/boards/temperature/Cargo.toml index 81939a3..494b916 100644 --- a/boards/temperature/Cargo.toml +++ b/boards/temperature/Cargo.toml @@ -22,6 +22,7 @@ defmt-rtt = { workspace = true } panic-probe = { workspace = true } chrono = { workspace = true } messages = {workspace = true} +ads126x = {path = "../../crates/ads126x"} [dev-dependencies] defmt-test = { workspace = true } diff --git a/boards/temperature/src/adc_manager.rs b/boards/temperature/src/adc_manager.rs new file mode 100644 index 0000000..cd9be5e --- /dev/null +++ b/boards/temperature/src/adc_manager.rs @@ -0,0 +1,80 @@ +use ads126x::{ + register::{DataRate, Mode1Register, Mode2Register}, + ADCCommand, Ads126x, +}; + +use common_arm::spawn; +use stm32h7xx_hal::{ + gpio::{Output, Pin, PushPull}, + spi::Spi, +}; + +use crate::app::delay; + +pub struct AdcManager { + pub spi: Spi, + pub adc1: Ads126x>>, + pub adc2: Ads126x>>, + pub adc1_cs: Pin<'A', 4, Output>, + pub adc2_cs: Pin<'A', 5, Output>, +} + +impl AdcManager { + pub fn new( + spi: Spi, + adc1_pin: Pin<'A', 0, Output>, + adc2_pin: Pin<'A', 1, Output>, + adc1_cs: Pin<'A', 4, Output>, + adc2_cs: Pin<'A', 5, Output>, + ) -> Self { + Self { + spi, + adc1: Ads126x::new(adc1_pin), + adc2: Ads126x::new(adc2_pin), + adc1_cs, + adc2_cs, + } + } + + pub fn init_adc1(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc2_cs.set_high(); + self.adc1_cs.set_low(); + self.adc1.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } + + pub fn init_adc2(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc1_cs.set_high(); + self.adc2_cs.set_low(); + self.adc2.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } +} diff --git a/boards/temperature/src/main.rs b/boards/temperature/src/main.rs index 2553651..d8ec809 100644 --- a/boards/temperature/src/main.rs +++ b/boards/temperature/src/main.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] +mod adc_manager; mod communication; mod data_manager; mod types; @@ -380,6 +381,11 @@ mod app { } } + #[task(priority = 3)] + async fn delay(_cx: delay::Context, delay: u32) { + Mono::delay(delay.millis()).await; + } + #[task(shared = [data_manager, &em, rtc])] async fn state_send(mut cx: state_send::Context) { let state_data = cx diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 4330059..f918978 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -1,27 +1,28 @@ #![no_std] #![no_main] -mod error; -mod register; +pub mod error; +pub mod register; use error::ADS126xError; use register::{ - Adc2CfgRegister, Adc2MuxRegister, GpioConRegister, GpioDatRegister, GpioDirRegister, IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register, TdacnRegister, TdacpRegister + Adc2CfgRegister, Adc2MuxRegister, GpioConRegister, GpioDatRegister, GpioDirRegister, + IdRegister, IdacMagRegister, IdacMuxRegister, InpMuxRegister, InterfaceRegister, Mode0Register, + Mode1Register, Mode2Register, PowerRegister, RefMuxRegister, Register, TdacnRegister, + TdacpRegister, }; -use embedded_hal::spi::FullDuplex; use embedded_hal::digital::v2::OutputPin; +use embedded_hal::spi::FullDuplex; use heapless::Vec; /// The [`Result`] type for ADS126x operations. pub type Result = core::result::Result; -pub struct ADS126x +pub struct Ads126x where - SPI: FullDuplex, - GpioPin: OutputPin, + GpioPin: OutputPin, { - spi: SPI, reset_pin: GpioPin, } @@ -50,34 +51,15 @@ fn delay(delay: u32) { } } -impl ADS126x +impl Ads126x where - SPI: FullDuplex, - GpioPin: OutputPin, + GpioPin: OutputPin, { - pub fn new(spi: SPI, reset_pin: GpioPin) -> Self { - Self { spi, reset_pin } + pub fn new(reset_pin: GpioPin) -> Self { + Self { reset_pin } } - pub fn init(&mut self) -> Result<()> { - self.reset()?; - // write configuration registers - delay(65536); // must wait 2^16 clock cycles, is this SPI clock? - let mut mode2_cfg = Mode2Register::default(); - mode2_cfg.set_dr(register::DataRate::SPS1200); - self.set_mode2(&mode2_cfg)?; - - // Set the rest of the registers below - // ... - - // start adc1 - self.send_command(ADCCommand::START1)?; - // start adc2 - self.send_command(ADCCommand::START2)?; - Ok(()) - } - - fn reset(&mut self) -> Result<()> { + pub fn reset(&mut self) -> Result<()> { self.reset_pin.set_high().map_err(|_| ADS126xError::IO)?; delay(1000); self.reset_pin.set_low().map_err(|_| ADS126xError::IO)?; @@ -87,7 +69,10 @@ where Ok(()) } - pub fn send_command(&mut self, command: ADCCommand) -> Result<()> { + pub fn send_command(&mut self, command: ADCCommand, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { let (opcode1, opcode2) = match command { ADCCommand::NOP => (0x00, None), ADCCommand::RESET => (0x06, None), @@ -107,64 +92,88 @@ where ADCCommand::WREG(addr, num) => (0x40 | addr as u8, Some(num)), }; - self.spi.send(opcode1).map_err(|_| ADS126xError::IO)?; + spi.send(opcode1).map_err(|_| ADS126xError::IO)?; if let Some(op2) = opcode2 { - self.spi.send(op2).map_err(|_| ADS126xError::IO)?; + spi.send(op2).map_err(|_| ADS126xError::IO)?; } Ok(()) } /// Reads data from multiple registers starting at the provided register. /// To read a single register, see [`ADS126x::read_register`]. - /// + /// /// Vector returns byte for each register read in order registers were read (increasing address). - pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result> { + pub fn read_multiple_registers( + &mut self, + reg: Register, + num: u8, + spi: &mut SPI, + ) -> Result> + where + SPI: FullDuplex, + { if num > 27 { return Err(ADS126xError::InvalidInputData); } - self.send_command(ADCCommand::RREG(reg, num - 1))?; + self.send_command(ADCCommand::RREG(reg, num - 1), spi)?; let mut buffer: Vec = Vec::new(); for _ in 0..num { buffer - .push(self.spi.read().map_err(|_| ADS126xError::IO)?) + .push(spi.read().map_err(|_| ADS126xError::IO)?) .map_err(|_| ADS126xError::InvalidInputData)?; } Ok(buffer) } - /// Reads data from only the single provided register. /// To read multiple registers, see [`ADS126x::read_multiple_registers`]. - pub fn read_register(&mut self, reg: Register) -> Result { - // zero since number of registers read - 1, so 1-1=0. - self.send_command(ADCCommand::RREG(reg, 0))?; - let data = self.spi.read().map_err(|_| ADS126xError::IO)?; + pub fn read_register(&mut self, reg: Register, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + // zero since number of registers read - 1, so 1-1=0. + self.send_command(ADCCommand::RREG(reg, 0), spi)?; + let data = spi.read().map_err(|_| ADS126xError::IO)?; Ok(data) } /// Writes data to multiple registers starting at the provided register. /// To write data to a single register, see [`ADS126x::write_register`]. - /// + /// /// Data has byte for each register in order registers are written to (increasing address). - pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<()> { + pub fn write_multiple_registers( + &mut self, + reg: Register, + data: &[u8], + spi: &mut SPI, + ) -> Result<()> + where + SPI: FullDuplex, + { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); } - self.send_command(ADCCommand::WREG(reg, data.len() as u8 - 1))?; + self.send_command(ADCCommand::WREG(reg, data.len() as u8 - 1), spi)?; for &byte in data { - self.spi.send(byte).map_err(|_| ADS126xError::IO)?; + spi.send(byte).map_err(|_| ADS126xError::IO)?; } Ok(()) } /// Writes data to only the single provided register. /// To write data to multiple registers, see [`ADS126x::write_multiple_registers`]. - pub fn write_register(&mut self, reg: Register, data: u8) -> Result<()> { - self.send_command(ADCCommand::WREG(reg, 0))?; - self.spi.send(data).map_err(|_| ADS126xError::IO) - } - - pub fn get_id(&mut self) -> Result { - let bits = self.read_register(Register::ID)?; + pub fn write_register(&mut self, reg: Register, data: u8, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.send_command(ADCCommand::WREG(reg, 0), spi)?; + spi.send(data).map_err(|_| ADS126xError::IO) + } + + pub fn get_id(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::ID, spi)?; let data = IdRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -172,8 +181,11 @@ where } } - pub fn get_power(&mut self) -> Result { - let bits = self.read_register(Register::POWER)?; + pub fn get_power(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::POWER, spi)?; let data = PowerRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -181,12 +193,18 @@ where } } - pub fn set_power(&mut self, reg: &PowerRegister) -> Result<()> { - self.write_register(Register::POWER, reg.bits()) + pub fn set_power(&mut self, reg: &PowerRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::POWER, reg.bits(), spi) } - pub fn get_interface(&mut self) -> Result { - let bits = self.read_register(Register::INTERFACE)?; + pub fn get_interface(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::INTERFACE, spi)?; let data = InterfaceRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -194,12 +212,18 @@ where } } - pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<()> { - self.write_register(Register::INTERFACE, reg.bits()) + pub fn set_interface(&mut self, reg: &InterfaceRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::INTERFACE, reg.bits(), spi) } - pub fn get_mode0(&mut self) -> Result { - let bits = self.read_register(Register::MODE0)?; + pub fn get_mode0(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::MODE0, spi)?; let data = Mode0Register::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -207,12 +231,18 @@ where } } - pub fn set_mode0(&mut self, reg: &Mode0Register) -> Result<()> { - self.write_register(Register::MODE0, reg.bits()) + pub fn set_mode0(&mut self, reg: &Mode0Register, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::MODE0, reg.bits(), spi) } - - pub fn get_mode1(&mut self) -> Result { - let bits = self.read_register(Register::MODE1)?; + + pub fn get_mode1(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::MODE1, spi)?; let data = Mode1Register::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -220,12 +250,18 @@ where } } - pub fn set_mode1(&mut self, reg: &Mode1Register) -> Result<()> { - self.write_register(Register::MODE1, reg.bits()) + pub fn set_mode1(&mut self, reg: &Mode1Register, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::MODE1, reg.bits(), spi) } - - pub fn get_mode2(&mut self) -> Result { - let bits = self.read_register(Register::MODE2)?; + + pub fn get_mode2(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::MODE2, spi)?; let data = Mode2Register::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -233,12 +269,18 @@ where } } - pub fn set_mode2(&mut self, reg: &Mode2Register) -> Result<()> { - self.write_register(Register::MODE2, reg.bits()) + pub fn set_mode2(&mut self, reg: &Mode2Register, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::MODE2, reg.bits(), spi) } - pub fn get_inpmux(&mut self) -> Result { - let bits = self.read_register(Register::INPMUX)?; + pub fn get_inpmux(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::INPMUX, spi)?; let data = InpMuxRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -246,48 +288,62 @@ where } } - pub fn set_inpmux(&mut self, reg: &InpMuxRegister) -> Result<()> { - self.write_register(Register::INPMUX, reg.bits()) + pub fn set_inpmux(&mut self, reg: &InpMuxRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::INPMUX, reg.bits(), spi) } - pub fn get_ofcal(&mut self) -> Result { - let bytes = self.read_multiple_registers(Register::OFCAL0, 3)?; // [OFCAL0, OFCAL1, OFCAL2] - let res = (bytes[2] as u32) << 16 | - (bytes[1] as u32) << 8 | - (bytes[0] as u32); + pub fn get_ofcal(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bytes = self.read_multiple_registers(Register::OFCAL0, 3, spi)?; // [OFCAL0, OFCAL1, OFCAL2] + let res = (bytes[2] as u32) << 16 | (bytes[1] as u32) << 8 | (bytes[0] as u32); Ok(res) } - - pub fn set_ofcal(&mut self, ofcal: u32) -> Result<()> { + + pub fn set_ofcal(&mut self, ofcal: u32, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { // Will not panic as & 0xFF ensures values are u8 let res: [u8; 3] = [ u8::try_from(ofcal & 0xFF).unwrap(), u8::try_from((ofcal >> 8) & 0xFF).unwrap(), u8::try_from((ofcal >> 16) & 0xFF).unwrap(), ]; - self.write_multiple_registers(Register::OFCAL0, &res) + self.write_multiple_registers(Register::OFCAL0, &res, spi) } - pub fn get_fscal(&mut self) -> Result { - let bytes = self.read_multiple_registers(Register::FSCAL0, 3)?; // [FSCAL0, FSCAL1, FSCAL2] - let res = (bytes[2] as u32) << 16 | - (bytes[1] as u32) << 8 | - (bytes[0] as u32); + pub fn get_fscal(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bytes = self.read_multiple_registers(Register::FSCAL0, 3, spi)?; // [FSCAL0, FSCAL1, FSCAL2] + let res = (bytes[2] as u32) << 16 | (bytes[1] as u32) << 8 | (bytes[0] as u32); Ok(res) } - - pub fn set_fscal(&mut self, fscal: u32) -> Result<()> { + + pub fn set_fscal(&mut self, fscal: u32, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { // Will not panic as & 0xFF ensures values are u8 let res: [u8; 3] = [ u8::try_from(fscal & 0xFF).unwrap(), u8::try_from((fscal >> 8) & 0xFF).unwrap(), u8::try_from((fscal >> 16) & 0xFF).unwrap(), ]; - self.write_multiple_registers(Register::FSCAL0, &res) + self.write_multiple_registers(Register::FSCAL0, &res, spi) } - pub fn get_idacmux(&mut self) -> Result { - let bits = self.read_register(Register::IDACMUX)?; + pub fn get_idacmux(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::IDACMUX, spi)?; let data = IdacMuxRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -295,12 +351,18 @@ where } } - pub fn set_idacmux(&mut self, reg: &IdacMuxRegister) -> Result<()> { - self.write_register(Register::IDACMUX, reg.bits()) + pub fn set_idacmux(&mut self, reg: &IdacMuxRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::IDACMUX, reg.bits(), spi) } - pub fn get_idacmag(&mut self) -> Result { - let bits = self.read_register(Register::IDACMAG)?; + pub fn get_idacmag(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::IDACMAG, spi)?; let data = IdacMagRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -308,12 +370,18 @@ where } } - pub fn set_idacmag(&mut self, reg: &IdacMagRegister) -> Result<()> { - self.write_register(Register::IDACMAG, reg.bits()) + pub fn set_idacmag(&mut self, reg: &IdacMagRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::IDACMAG, reg.bits(), spi) } - pub fn get_refmux(&mut self) -> Result { - let bits = self.read_register(Register::REFMUX)?; + pub fn get_refmux(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::REFMUX, spi)?; let data = RefMuxRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -321,12 +389,18 @@ where } } - pub fn set_refmux(&mut self, reg: &RefMuxRegister) -> Result<()> { - self.write_register(Register::REFMUX, reg.bits()) + pub fn set_refmux(&mut self, reg: &RefMuxRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::REFMUX, reg.bits(), spi) } - pub fn get_tdacp(&mut self) -> Result { - let bits = self.read_register(Register::TDACP)?; + pub fn get_tdacp(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::TDACP, spi)?; let data = TdacpRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -334,12 +408,18 @@ where } } - pub fn set_tdacp(&mut self, reg: &TdacpRegister) -> Result<()> { - self.write_register(Register::TDACP, reg.bits()) + pub fn set_tdacp(&mut self, reg: &TdacpRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::TDACP, reg.bits(), spi) } - pub fn get_tdacn(&mut self) -> Result { - let bits = self.read_register(Register::TDACN)?; + pub fn get_tdacn(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::TDACN, spi)?; let data = TdacnRegister::from_bits(bits); match data { Some(reg) => Ok(reg), @@ -347,105 +427,147 @@ where } } - pub fn set_tdacn(&mut self, reg: &TdacnRegister) -> Result<()> { - self.write_register(Register::TDACN, reg.bits()) + pub fn set_tdacn(&mut self, reg: &TdacnRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::TDACN, reg.bits(), spi) } - pub fn get_gpiocon(&mut self) -> Result { - let bits = self.read_register(Register::GPIOCON)?; + pub fn get_gpiocon(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::GPIOCON, spi)?; let data = GpioConRegister::from_bits(bits); match data { Some(reg) => Ok(reg), None => Err(ADS126xError::InvalidInputData), - } + } } - pub fn set_gpiocon(&mut self, reg: &GpioConRegister) -> Result<()> { - self.write_register(Register::GPIOCON, reg.bits()) + pub fn set_gpiocon(&mut self, reg: &GpioConRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::GPIOCON, reg.bits(), spi) } - pub fn get_gpiodir(&mut self) -> Result { - let bits = self.read_register(Register::GPIODIR)?; + pub fn get_gpiodir(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::GPIODIR, spi)?; let data = GpioDirRegister::from_bits(bits); match data { Some(reg) => Ok(reg), None => Err(ADS126xError::InvalidInputData), - } + } } - pub fn set_gpiodir(&mut self, reg: &GpioDirRegister) -> Result<()> { - self.write_register(Register::GPIODIR, reg.bits()) + pub fn set_gpiodir(&mut self, reg: &GpioDirRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::GPIODIR, reg.bits(), spi) } - pub fn get_gpiodat(&mut self) -> Result { - let bits = self.read_register(Register::GPIODAT)?; + pub fn get_gpiodat(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::GPIODAT, spi)?; let data = GpioDatRegister::from_bits(bits); match data { Some(reg) => Ok(reg), None => Err(ADS126xError::InvalidInputData), - } + } } - pub fn set_gpiodat(&mut self, reg: &GpioDatRegister) -> Result<()> { - self.write_register(Register::GPIODAT, reg.bits()) + pub fn set_gpiodat(&mut self, reg: &GpioDatRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::GPIODAT, reg.bits(), spi) } - pub fn get_adc2cfg(&mut self) -> Result { - let bits = self.read_register(Register::ADC2CFG)?; + pub fn get_adc2cfg(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::ADC2CFG, spi)?; let data = Adc2CfgRegister::from_bits(bits); match data { Some(reg) => Ok(reg), None => Err(ADS126xError::InvalidInputData), - } + } } - pub fn set_adc2cfg(&mut self, reg: &Adc2CfgRegister) -> Result<()> { - self.write_register(Register::ADC2CFG, reg.bits()) + pub fn set_adc2cfg(&mut self, reg: &Adc2CfgRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::ADC2CFG, reg.bits(), spi) } - - pub fn get_adc2mux(&mut self) -> Result { - let bits = self.read_register(Register::ADC2MUX)?; + pub fn get_adc2mux(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bits = self.read_register(Register::ADC2MUX, spi)?; let data = Adc2MuxRegister::from_bits(bits); match data { Some(reg) => Ok(reg), None => Err(ADS126xError::InvalidInputData), - } + } } - pub fn set_adc2mux(&mut self, reg: &Adc2MuxRegister) -> Result<()> { - self.write_register(Register::ADC2MUX, reg.bits()) + pub fn set_adc2mux(&mut self, reg: &Adc2MuxRegister, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { + self.write_register(Register::ADC2MUX, reg.bits(), spi) } - pub fn get_adc2ofc(&mut self) -> Result { - let bytes = self.read_multiple_registers(Register::ADC2OFC0, 2)?; // [ADC2OFC0, ADC2OFC1] - let res = (bytes[1] as u16) << 8 | - (bytes[0] as u16); + pub fn get_adc2ofc(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bytes = self.read_multiple_registers(Register::ADC2OFC0, 2, spi)?; // [ADC2OFC0, ADC2OFC1] + let res = (bytes[1] as u16) << 8 | (bytes[0] as u16); Ok(res) } - - pub fn set_adc2ofc(&mut self, ofc2: u16) -> Result<()> { + + pub fn set_adc2ofc(&mut self, ofc2: u16, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { // Will not panic as & 0xFF ensures values are u8 let res: [u8; 2] = [ u8::try_from(ofc2 & 0xFF).unwrap(), u8::try_from((ofc2 >> 8) & 0xFF).unwrap(), ]; - self.write_multiple_registers(Register::ADC2OFC0, &res) + self.write_multiple_registers(Register::ADC2OFC0, &res, spi) } - pub fn get_adc2fsc(&mut self) -> Result { - let bytes = self.read_multiple_registers(Register::ADC2FSC0, 2)?; // [ADC2FSC0, ADC2FSC1] - let res = (bytes[1] as u16) << 8 | - (bytes[0] as u16); + pub fn get_adc2fsc(&mut self, spi: &mut SPI) -> Result + where + SPI: FullDuplex, + { + let bytes = self.read_multiple_registers(Register::ADC2FSC0, 2, spi)?; // [ADC2FSC0, ADC2FSC1] + let res = (bytes[1] as u16) << 8 | (bytes[0] as u16); Ok(res) } - - pub fn set_adc2fsc(&mut self, fsc2: u32) -> Result<()> { + + pub fn set_adc2fsc(&mut self, fsc2: u32, spi: &mut SPI) -> Result<()> + where + SPI: FullDuplex, + { // Will not panic as & 0xFF ensures values are u8 let res: [u8; 2] = [ u8::try_from(fsc2 & 0xFF).unwrap(), u8::try_from((fsc2 >> 8) & 0xFF).unwrap(), ]; - self.write_multiple_registers(Register::ADC2FSC0, &res) + self.write_multiple_registers(Register::ADC2FSC0, &res, spi) } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index 4904043..56d5f35 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -1,37 +1,37 @@ mod enums; -pub use enums::*; use bitflags::bitflags; +pub use enums::*; #[repr(u8)] pub enum Register { - ID = 0x00, - POWER = 0x01, + ID = 0x00, + POWER = 0x01, INTERFACE = 0x02, - MODE0 = 0x03, - MODE1 = 0x04, - MODE2 = 0x05, - INPMUX = 0x06, - OFCAL0 = 0x07, - OFCAL1 = 0x08, - OFCAL2 = 0x09, - FSCAL0 = 0x0A, - FSCAL1 = 0x0B, - FSCAL2 = 0x0C, - IDACMUX = 0x0D, - IDACMAG = 0x0E, - REFMUX = 0x0F, - TDACP = 0x10, - TDACN = 0x11, - GPIOCON = 0x12, - GPIODIR = 0x13, - GPIODAT = 0x14, - ADC2CFG = 0x15, - ADC2MUX = 0x16, - ADC2OFC0 = 0x17, - ADC2OFC1 = 0x18, - ADC2FSC0 = 0x19, - ADC2FSC1 = 0x1A, + MODE0 = 0x03, + MODE1 = 0x04, + MODE2 = 0x05, + INPMUX = 0x06, + OFCAL0 = 0x07, + OFCAL1 = 0x08, + OFCAL2 = 0x09, + FSCAL0 = 0x0A, + FSCAL1 = 0x0B, + FSCAL2 = 0x0C, + IDACMUX = 0x0D, + IDACMAG = 0x0E, + REFMUX = 0x0F, + TDACP = 0x10, + TDACN = 0x11, + GPIOCON = 0x12, + GPIODIR = 0x13, + GPIODAT = 0x14, + ADC2CFG = 0x15, + ADC2MUX = 0x16, + ADC2OFC0 = 0x17, + ADC2OFC1 = 0x18, + ADC2FSC0 = 0x19, + ADC2FSC1 = 0x1A, } bitflags! { @@ -101,7 +101,7 @@ impl PowerRegister { self.contains(PowerRegister::RESET) } - // must be cleared if set to detect further resets. + // must be cleared if set to detect further resets. pub fn clear_reset(&mut self) { self.remove(PowerRegister::RESET); } @@ -557,7 +557,7 @@ impl RefMuxRegister { 0b100 => RefPositiveInp::IntAnlgSup, 0b101..=0b111 => panic!("Reserved Reference Positive Input"), - _ => unreachable!() + _ => unreachable!(), } } @@ -576,7 +576,7 @@ bitflags! { } impl TdacpRegister { - // there is no defined default values in the datasheet so just zeros. + // there is no defined default values in the datasheet so just zeros. pub fn default() -> Self { TdacpRegister::from_bits_truncate(0b0000_0000) } @@ -617,13 +617,13 @@ impl TdacpRegister { bitflags! { pub struct TdacnRegister: u8 { const OUTN = 0b1000_0000; - + const _ = 0b1001_1111; } } impl TdacnRegister { - // there is no defined default values in the datasheet so just zeros. + // there is no defined default values in the datasheet so just zeros. pub fn default() -> Self { TdacnRegister::from_bits_truncate(0b0000_0000) } @@ -718,7 +718,7 @@ bitflags! { } impl GpioDatRegister { - // there is no defined default values in the datasheet so just zeros. + // there is no defined default values in the datasheet so just zeros. pub fn default() -> Self { GpioDatRegister::from_bits_truncate(0b0000_0000) } diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs index 48f8430..38ff242 100644 --- a/crates/ads126x/src/register/enums.rs +++ b/crates/ads126x/src/register/enums.rs @@ -6,15 +6,15 @@ pub enum DevId { /// Conversion delays follow the pattern `D`. /// - `len` is the length of time where _ is a substitute for a decimal point. /// - `units` are the units of time where us is microseconds and ms is milliseconds. -/// +/// /// D8_7us = delay of 8.7 microseconds. D8_8ms = delay of 8.8 milliseconds. #[repr(u8)] pub enum ConversionDelay { - DNone = 0b0000, + DNone = 0b0000, D8_7us = 0b0001, - D17us = 0b0010, - D35us = 0b0011, - D69us = 0b0100, + D17us = 0b0010, + D35us = 0b0011, + D69us = 0b0100, D139us = 0b0101, D278us = 0b0110, D555us = 0b0111, @@ -28,11 +28,11 @@ impl ConversionDelay { /// Returns the delay in nanoseconds. pub fn delay(&self) -> u32 { match self { - Self::DNone => 0, + Self::DNone => 0, Self::D8_7us => 8_700, - Self::D17us => 17_000, - Self::D35us => 35_000, - Self::D69us => 69_000, + Self::D17us => 17_000, + Self::D35us => 35_000, + Self::D69us => 69_000, Self::D139us => 139_000, Self::D278us => 278_000, Self::D555us => 555_000, @@ -46,25 +46,25 @@ impl ConversionDelay { #[repr(u8)] pub enum ChopMode { - Disabled = 0b00, - InChopEnabled = 0b01, - IdacEnabled = 0b10, + Disabled = 0b00, + InChopEnabled = 0b01, + IdacEnabled = 0b10, InChopAndIdacEnabled = 0b11, } /// SBMAGs follow the pattern `B` or `R`. /// - `mag` is the magnitude of current or resistance where _ is a substitute for a decimal point. /// - `units` are the units of current or resistance where uA is microamperes and MOhm is megaohms. -/// +/// /// B0_5uA = 0.5 microamps of current. R10MOhm = resistance of 10 megaohms. #[repr(u8)] pub enum SensorBiasMagnitude { - BNone = 0b000, - B0_5uA = 0b001, - B2uA = 0b010, - B10uA = 0b011, - B50uA = 0b100, - B200uA = 0b101, + BNone = 0b000, + B0_5uA = 0b001, + B2uA = 0b010, + B10uA = 0b011, + B50uA = 0b100, + B200uA = 0b101, R10MOhm = 0b110, } @@ -72,7 +72,7 @@ pub enum SensorBiasMagnitude { pub enum CrcMode { Disabled = 0b00, Checksum = 0b01, - CRC = 0b10, + CRC = 0b10, } #[repr(u8)] @@ -81,28 +81,28 @@ pub enum DigitalFilter { Sinc2 = 0b001, Sinc3 = 0b010, Sinc4 = 0b011, - FIR = 0b100, + FIR = 0b100, } /// Data rates follow the pattern `SPS`. /// - `num` is the SPS rate where _ is a substitute for a decimal point. -/// +/// /// SPS2_5 = 2.5 SPS. #[repr(u8)] pub enum DataRate { - SPS2_5 = 0b0000, - SPS5 = 0b0001, - SPS10 = 0b0010, - SPS16_6 = 0b0011, // 16.6666... = 50/3 - SPS20 = 0b0100, - SPS50 = 0b0101, - SPS60 = 0b0110, - SPS100 = 0b0111, - SPS400 = 0b1000, - SPS1200 = 0b1001, - SPS2400 = 0b1010, - SPS4800 = 0b1011, - SPS7200 = 0b1100, + SPS2_5 = 0b0000, + SPS5 = 0b0001, + SPS10 = 0b0010, + SPS16_6 = 0b0011, // 16.6666... = 50/3 + SPS20 = 0b0100, + SPS50 = 0b0101, + SPS60 = 0b0110, + SPS100 = 0b0111, + SPS400 = 0b1000, + SPS1200 = 0b1001, + SPS2400 = 0b1010, + SPS4800 = 0b1011, + SPS7200 = 0b1100, SPS14400 = 0b1101, SPS19200 = 0b1110, SPS38400 = 0b1111, @@ -110,160 +110,160 @@ pub enum DataRate { #[repr(u8)] pub enum PGAGain { - VV1 = 0b000, - VV2 = 0b001, - VV4 = 0b010, - VV8 = 0b011, + VV1 = 0b000, + VV2 = 0b001, + VV4 = 0b010, + VV8 = 0b011, VV16 = 0b100, VV32 = 0b101, } #[repr(u8)] pub enum NegativeInpMux { - AIN0 = 0b0000, - AIN1 = 0b0001, - AIN2 = 0b0010, - AIN3 = 0b0011, - AIN4 = 0b0100, - AIN5 = 0b0101, - AIN6 = 0b0110, - AIN7 = 0b0111, - AIN8 = 0b1000, - AIN9 = 0b1001, - AINCOM = 0b1010, - TempSensMonNeg = 0b1011, - AnlgPwrSupMonNeg = 0b1100, - DgtlPwrSubMonNeg = 0b1101, + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, + TempSensMonNeg = 0b1011, + AnlgPwrSupMonNeg = 0b1100, + DgtlPwrSubMonNeg = 0b1101, TDACTestSignalNeg = 0b1110, - Float = 0b1111, + Float = 0b1111, } #[repr(u8)] pub enum PositiveInpMux { - AIN0 = 0b0000, - AIN1 = 0b0001, - AIN2 = 0b0010, - AIN3 = 0b0011, - AIN4 = 0b0100, - AIN5 = 0b0101, - AIN6 = 0b0110, - AIN7 = 0b0111, - AIN8 = 0b1000, - AIN9 = 0b1001, - AINCOM = 0b1010, - TempSensMonPos = 0b1011, - AnlgPwrSupMonPos = 0b1100, - DgtlPwrSubMonPos = 0b1101, + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, + TempSensMonPos = 0b1011, + AnlgPwrSupMonPos = 0b1100, + DgtlPwrSubMonPos = 0b1101, TDACTestSignalPos = 0b1110, - Float = 0b1111, + Float = 0b1111, } #[repr(u8)] pub enum IdacOutMux { - AIN0 = 0b0000, - AIN1 = 0b0001, - AIN2 = 0b0010, - AIN3 = 0b0011, - AIN4 = 0b0100, - AIN5 = 0b0101, - AIN6 = 0b0110, - AIN7 = 0b0111, - AIN8 = 0b1000, - AIN9 = 0b1001, - AINCOM = 0b1010, + AIN0 = 0b0000, + AIN1 = 0b0001, + AIN2 = 0b0010, + AIN3 = 0b0011, + AIN4 = 0b0100, + AIN5 = 0b0101, + AIN6 = 0b0110, + AIN7 = 0b0111, + AIN8 = 0b1000, + AIN9 = 0b1001, + AINCOM = 0b1010, NoConnection = 0b1011, } /// Current magnitudes follow the pattern `I`. /// - `mag` is the magnitude of current. /// - `units` are uA meaning microamperes. -/// +/// /// I50uA = 50 microamps of current. #[repr(u8)] pub enum IdacCurMag { - I50uA = 0b0000, - I100uA = 0b0001, - I250uA = 0b0010, - I500uA = 0b0011, - I750uA = 0b0100, - I1000uA = 0b0101, - I1500uA = 0b0110, - I2000uA = 0b0111, - I2500uA = 0b1000, - I3000uA = 0b1001, + I50uA = 0b0000, + I100uA = 0b0001, + I250uA = 0b0010, + I500uA = 0b0011, + I750uA = 0b0100, + I1000uA = 0b0101, + I1500uA = 0b0110, + I2000uA = 0b0111, + I2500uA = 0b1000, + I3000uA = 0b1001, } #[repr(u8)] pub enum RefNegativeInp { Int2_5VRef = 0b000, - ExtAIN1 = 0b001, - ExtAIN3 = 0b010, - ExtAIN5 = 0b011, + ExtAIN1 = 0b001, + ExtAIN3 = 0b010, + ExtAIN5 = 0b011, IntAnlgSup = 0b100, } #[repr(u8)] pub enum RefPositiveInp { Int2_5VRef = 0b000, - ExtAIN0 = 0b001, - ExtAIN2 = 0b010, - ExtAIN4 = 0b011, + ExtAIN0 = 0b001, + ExtAIN2 = 0b010, + ExtAIN4 = 0b011, IntAnlgSup = 0b100, } /// Voltages are with respect to V_AVSS. /// Output magnitudes follow the pattern `V`. /// - `num` is the output magnitude in volts where _ is a substitute for a decimal point. -/// +/// /// V4_5 = 4.5 V. #[repr(u8)] pub enum TdacOutMag { - V4_5 = 0b01001, - V3_5 = 0b01000, - V3 = 0b00111, - V2_75 = 0b00110, - V2_625 = 0b00101, - V2_5625 = 0b00100, - V2_53125 = 0b00011, - V2_515625 = 0b00010, + V4_5 = 0b01001, + V3_5 = 0b01000, + V3 = 0b00111, + V2_75 = 0b00110, + V2_625 = 0b00101, + V2_5625 = 0b00100, + V2_53125 = 0b00011, + V2_515625 = 0b00010, V2_5078125 = 0b00001, - V2_5 = 0b00000, + V2_5 = 0b00000, V2_4921875 = 0b10001, - V2_484375 = 0b10010, - V2_46875 = 0b10011, - V2_4375 = 0b10100, - V2_375 = 0b10101, - V2_25 = 0b10110, - V2 = 0b10111, - V1_5 = 0b11000, - V0_5 = 0b11001, + V2_484375 = 0b10010, + V2_46875 = 0b10011, + V2_4375 = 0b10100, + V2_375 = 0b10101, + V2_25 = 0b10110, + V2 = 0b10111, + V1_5 = 0b11000, + V0_5 = 0b11001, } #[repr(u8)] pub enum Adc2Gain { - VV1 = 0b000, - VV2 = 0b001, - VV4 = 0b010, - VV8 = 0b011, - VV16 = 0b100, - VV32 = 0b101, - VV64 = 0b110, + VV1 = 0b000, + VV2 = 0b001, + VV4 = 0b010, + VV8 = 0b011, + VV16 = 0b100, + VV32 = 0b101, + VV64 = 0b110, VV128 = 0b111, } #[repr(u8)] pub enum Adc2RefInp { Int2_5VRef = 0b000, - ExtAIN0_1 = 0b001, - ExtAIN2_3 = 0b010, - ExtAIN4_5 = 0b011, + ExtAIN0_1 = 0b001, + ExtAIN2_3 = 0b010, + ExtAIN4_5 = 0b011, IntAnlgSup = 0b100, } #[repr(u8)] pub enum Adc2DataRate { - SPS10 = 0b00, - SPS100 = 0b01, - SPS400 = 0b10, - SPS800 = 0b11, + SPS10 = 0b00, + SPS100 = 0b01, + SPS400 = 0b10, + SPS800 = 0b11, } From fcf04c9832cdb0af3ef0f7ce620b9b125dc5f65c Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Mon, 9 Dec 2024 18:03:02 -0500 Subject: [PATCH 20/22] Change path to git path for HAL import. --- Cargo.lock | 1 + Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7de0cd..d5c18f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -939,6 +939,7 @@ dependencies = [ [[package]] name = "stm32h7xx-hal" version = "0.16.0" +source = "git+https://github.com/uorocketry/stm32h7xx-hal#412160269f1729d55bc52de17463695db2c6bc6c" dependencies = [ "bare-metal 1.0.0", "cast", diff --git a/Cargo.toml b/Cargo.toml index 7415b95..5f3e807 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,9 @@ members = ["boards/*", "examples/*", "crates/*"] default-members = ["boards/*", "examples/*"] [workspace.dependencies.stm32h7xx-hal] -# git = "https://github.com/uorocketry/stm32h7xx-hal" +git = "https://github.com/uorocketry/stm32h7xx-hal" # We use 35 even though we have the 33. -path = "/home/bonjour/Rocketry/stm32h7xx-hal" +#path = "/home/bonjour/Rocketry/stm32h7xx-hal" features = ["defmt", "rt", "stm32h735", "can", "rtc"] [workspace.dependencies.serde] From 2f996068b8e4be258d2bfb8c38223fd0c109bd1a Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Mon, 9 Dec 2024 22:21:45 -0500 Subject: [PATCH 21/22] Create temperature board adc manager. --- Cargo.toml | 1 - boards/temperature/src/adc_manager.rs | 26 ++++++++++--------- boards/temperature/src/main.rs | 37 ++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f3e807..8cb4cf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ default-members = ["boards/*", "examples/*"] [workspace.dependencies.stm32h7xx-hal] git = "https://github.com/uorocketry/stm32h7xx-hal" # We use 35 even though we have the 33. -#path = "/home/bonjour/Rocketry/stm32h7xx-hal" features = ["defmt", "rt", "stm32h735", "can", "rtc"] [workspace.dependencies.serde] diff --git a/boards/temperature/src/adc_manager.rs b/boards/temperature/src/adc_manager.rs index cd9be5e..45bf5bb 100644 --- a/boards/temperature/src/adc_manager.rs +++ b/boards/temperature/src/adc_manager.rs @@ -11,26 +11,28 @@ use stm32h7xx_hal::{ use crate::app::delay; + +// There is an option to use interrupts using the data ready pins, but for now we will poll. pub struct AdcManager { - pub spi: Spi, - pub adc1: Ads126x>>, - pub adc2: Ads126x>>, - pub adc1_cs: Pin<'A', 4, Output>, - pub adc2_cs: Pin<'A', 5, Output>, + pub spi: Spi, + pub adc1: Ads126x>>, + pub adc2: Ads126x>>, + pub adc1_cs: Pin<'C', 10, Output>, + pub adc2_cs: Pin<'D', 2, Output>, } impl AdcManager { pub fn new( - spi: Spi, - adc1_pin: Pin<'A', 0, Output>, - adc2_pin: Pin<'A', 1, Output>, - adc1_cs: Pin<'A', 4, Output>, - adc2_cs: Pin<'A', 5, Output>, + spi: Spi, + adc1_rst: Pin<'C', 11, Output>, + adc2_rst: Pin<'E', 0, Output>, + adc1_cs: Pin<'C', 10, Output>, + adc2_cs: Pin<'D', 2, Output>, ) -> Self { Self { spi, - adc1: Ads126x::new(adc1_pin), - adc2: Ads126x::new(adc2_pin), + adc1: Ads126x::new(adc1_rst), + adc2: Ads126x::new(adc2_rst), adc1_cs, adc2_cs, } diff --git a/boards/temperature/src/main.rs b/boards/temperature/src/main.rs index d8ec809..f3d7e01 100644 --- a/boards/temperature/src/main.rs +++ b/boards/temperature/src/main.rs @@ -29,6 +29,8 @@ use stm32h7xx_hal::gpio::{Output, PushPull}; use stm32h7xx_hal::prelude::*; use stm32h7xx_hal::rtc; use stm32h7xx_hal::{rcc, rcc::rec}; +use messages::Message; +use stm32h7xx_hal::{gpio::{Alternate, Pin}, hal::spi}; use types::COM_ID; // global logger const DATA_CHANNEL_CAPACITY: usize = 10; @@ -45,8 +47,8 @@ fn panic() -> ! { #[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, dispatchers = [EXTI0, EXTI1, EXTI2, SPI3, SPI2])] mod app { - use messages::Message; - use stm32h7xx_hal::gpio::{Alternate, Pin}; + + use adc_manager::AdcManager; use super::*; @@ -57,12 +59,13 @@ mod app { // sd_manager: SdManager< // stm32h7xx_hal::spi::Spi, // PA4>, - // >, + // >, radio_manager: RadioManager, can_command_manager: CanCommandManager, can_data_manager: CanDataManager, sbg_power: PB4>, rtc: rtc::Rtc, + adc_manager: AdcManager, } #[local] struct LocalResources { @@ -131,7 +134,9 @@ mod app { // GPIO let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); let gpiod = ctx.device.GPIOD.split(ccdr.peripheral.GPIOD); + let gpioc = ctx.device.GPIOC.split(ccdr.peripheral.GPIOC); let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB); + let gpioe = ctx.device.GPIOE.split(ccdr.peripheral.GPIOE); let pins = gpiob.pb14.into_alternate(); let mut c0 = ctx @@ -251,6 +256,31 @@ mod app { // let sd_manager = SdManager::new(spi_sd, cs_sd); + // ADC setup + let adc_spi: stm32h7xx_hal::spi::Spi< + stm32h7xx_hal::stm32::SPI4, + stm32h7xx_hal::spi::Enabled, + u8, + > = ctx.device.SPI4.spi( + ( + gpioe.pe2.into_alternate(), + gpioe.pe5.into_alternate(), + gpioe.pe6.into_alternate(), + ), + stm32h7xx_hal::spi::Config::new(spi::MODE_0), + 1.MHz(), + ccdr.peripheral.SPI4, + &ccdr.clocks, + ); + + let adc1_cs = gpioc.pc10.into_push_pull_output(); + let adc2_cs = gpiod.pd2.into_push_pull_output(); + + let adc1_rst = gpioc.pc11.into_push_pull_output(); + let adc2_rst = gpioe.pe0.into_push_pull_output(); + + let adc_manager = AdcManager::new(adc_spi, adc1_rst, adc2_rst, adc1_cs, adc2_cs); + // leds let led_red = gpioa.pa2.into_push_pull_output(); let led_green = gpioa.pa3.into_push_pull_output(); @@ -314,6 +344,7 @@ mod app { can_data_manager, sbg_power, rtc, + adc_manager }, LocalResources { led_red, From 9d80d8542ab89057dda16df83ad8e1ea21cb46e4 Mon Sep 17 00:00:00 2001 From: Noah Sprenger Date: Fri, 13 Dec 2024 18:44:33 -0500 Subject: [PATCH 22/22] Add ADC manager to all boards. --- Cargo.lock | 2 + boards/pressure/Cargo.toml | 1 + boards/pressure/src/adc_manager.rs | 81 +++++++++++++++++++++++++++ boards/pressure/src/main.rs | 6 ++ boards/strain/Cargo.toml | 1 + boards/strain/src/adc_manager.rs | 81 +++++++++++++++++++++++++++ boards/strain/src/main.rs | 6 ++ boards/temperature/src/adc_manager.rs | 1 - boards/temperature/src/main.rs | 18 +++--- 9 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 boards/pressure/src/adc_manager.rs create mode 100644 boards/strain/src/adc_manager.rs diff --git a/Cargo.lock b/Cargo.lock index d5c18f1..089e2b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,6 +628,7 @@ dependencies = [ name = "pressure" version = "0.1.0" dependencies = [ + "ads126x", "chrono", "common-arm", "cortex-m", @@ -961,6 +962,7 @@ dependencies = [ name = "strain" version = "0.1.0" dependencies = [ + "ads126x", "chrono", "common-arm", "cortex-m", diff --git a/boards/pressure/Cargo.toml b/boards/pressure/Cargo.toml index cabae2e..d157ffc 100644 --- a/boards/pressure/Cargo.toml +++ b/boards/pressure/Cargo.toml @@ -22,6 +22,7 @@ defmt-rtt = { workspace = true } panic-probe = { workspace = true } chrono = { workspace = true } messages = {workspace = true} +ads126x = {path = "../../crates/ads126x"} [dev-dependencies] defmt-test = { workspace = true } diff --git a/boards/pressure/src/adc_manager.rs b/boards/pressure/src/adc_manager.rs new file mode 100644 index 0000000..73e8d1f --- /dev/null +++ b/boards/pressure/src/adc_manager.rs @@ -0,0 +1,81 @@ +use ads126x::{ + register::{DataRate, Mode1Register, Mode2Register}, + ADCCommand, Ads126x, +}; + +use common_arm::spawn; +use stm32h7xx_hal::{ + gpio::{Output, Pin, PushPull}, + spi::Spi, +}; + +use crate::app::delay; + +// There is an option to use interrupts using the data ready pins, but for now we will poll. +pub struct AdcManager { + pub spi: Spi, + pub adc1: Ads126x>>, + pub adc2: Ads126x>>, + pub adc1_cs: Pin<'C', 10, Output>, + pub adc2_cs: Pin<'D', 2, Output>, +} + +impl AdcManager { + pub fn new( + spi: Spi, + adc1_rst: Pin<'C', 11, Output>, + adc2_rst: Pin<'E', 0, Output>, + adc1_cs: Pin<'C', 10, Output>, + adc2_cs: Pin<'D', 2, Output>, + ) -> Self { + Self { + spi, + adc1: Ads126x::new(adc1_rst), + adc2: Ads126x::new(adc2_rst), + adc1_cs, + adc2_cs, + } + } + + pub fn init_adc1(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc2_cs.set_high(); + self.adc1_cs.set_low(); + self.adc1.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } + + pub fn init_adc2(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc1_cs.set_high(); + self.adc2_cs.set_low(); + self.adc2.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } +} diff --git a/boards/pressure/src/main.rs b/boards/pressure/src/main.rs index 2553651..b320b16 100644 --- a/boards/pressure/src/main.rs +++ b/boards/pressure/src/main.rs @@ -3,6 +3,7 @@ mod communication; mod data_manager; +mod adc_manager; mod types; use chrono::NaiveDate; @@ -322,6 +323,11 @@ mod app { ) } + #[task(priority = 3)] + async fn delay(_cx: delay::Context, delay: u32) { + Mono::delay(delay.millis()).await; + } + #[task(priority = 3, shared = [&em, rtc])] async fn generate_random_messages(mut cx: generate_random_messages::Context) { loop { diff --git a/boards/strain/Cargo.toml b/boards/strain/Cargo.toml index f0735f3..f12215c 100644 --- a/boards/strain/Cargo.toml +++ b/boards/strain/Cargo.toml @@ -22,6 +22,7 @@ defmt-rtt = { workspace = true } panic-probe = { workspace = true } chrono = { workspace = true } messages = {workspace = true} +ads126x = {path = "../../crates/ads126x"} [dev-dependencies] defmt-test = { workspace = true } diff --git a/boards/strain/src/adc_manager.rs b/boards/strain/src/adc_manager.rs new file mode 100644 index 0000000..73e8d1f --- /dev/null +++ b/boards/strain/src/adc_manager.rs @@ -0,0 +1,81 @@ +use ads126x::{ + register::{DataRate, Mode1Register, Mode2Register}, + ADCCommand, Ads126x, +}; + +use common_arm::spawn; +use stm32h7xx_hal::{ + gpio::{Output, Pin, PushPull}, + spi::Spi, +}; + +use crate::app::delay; + +// There is an option to use interrupts using the data ready pins, but for now we will poll. +pub struct AdcManager { + pub spi: Spi, + pub adc1: Ads126x>>, + pub adc2: Ads126x>>, + pub adc1_cs: Pin<'C', 10, Output>, + pub adc2_cs: Pin<'D', 2, Output>, +} + +impl AdcManager { + pub fn new( + spi: Spi, + adc1_rst: Pin<'C', 11, Output>, + adc2_rst: Pin<'E', 0, Output>, + adc1_cs: Pin<'C', 10, Output>, + adc2_cs: Pin<'D', 2, Output>, + ) -> Self { + Self { + spi, + adc1: Ads126x::new(adc1_rst), + adc2: Ads126x::new(adc2_rst), + adc1_cs, + adc2_cs, + } + } + + pub fn init_adc1(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc2_cs.set_high(); + self.adc1_cs.set_low(); + self.adc1.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } + + pub fn init_adc2(&mut self) -> Result<(), ads126x::error::ADS126xError> { + self.adc1_cs.set_high(); + self.adc2_cs.set_low(); + self.adc2.reset()?; + + spawn!(delay, 1000); + + let mut mode1_cfg = Mode1Register::default(); + mode1_cfg.set_filter(ads126x::register::DigitalFilter::Sinc1); + self.adc1.set_mode1(&mode1_cfg, &mut self.spi)?; + + let mut mode2_cfg = Mode2Register::default(); + mode2_cfg.set_dr(DataRate::SPS1200); + self.adc1.set_mode2(&mode2_cfg, &mut self.spi)?; + + self.adc1.send_command(ADCCommand::START1, &mut self.spi)?; + self.adc1.send_command(ADCCommand::START2, &mut self.spi)?; + + Ok(()) + } +} diff --git a/boards/strain/src/main.rs b/boards/strain/src/main.rs index 2553651..b320b16 100644 --- a/boards/strain/src/main.rs +++ b/boards/strain/src/main.rs @@ -3,6 +3,7 @@ mod communication; mod data_manager; +mod adc_manager; mod types; use chrono::NaiveDate; @@ -322,6 +323,11 @@ mod app { ) } + #[task(priority = 3)] + async fn delay(_cx: delay::Context, delay: u32) { + Mono::delay(delay.millis()).await; + } + #[task(priority = 3, shared = [&em, rtc])] async fn generate_random_messages(mut cx: generate_random_messages::Context) { loop { diff --git a/boards/temperature/src/adc_manager.rs b/boards/temperature/src/adc_manager.rs index 45bf5bb..73e8d1f 100644 --- a/boards/temperature/src/adc_manager.rs +++ b/boards/temperature/src/adc_manager.rs @@ -11,7 +11,6 @@ use stm32h7xx_hal::{ use crate::app::delay; - // There is an option to use interrupts using the data ready pins, but for now we will poll. pub struct AdcManager { pub spi: Spi, diff --git a/boards/temperature/src/main.rs b/boards/temperature/src/main.rs index f3d7e01..74e2136 100644 --- a/boards/temperature/src/main.rs +++ b/boards/temperature/src/main.rs @@ -18,6 +18,7 @@ use fdcan::{ filter::{StandardFilter, StandardFilterSlot}, }; use messages::command::RadioRate; +use messages::Message; use messages::{sensor, Data}; use panic_probe as _; use rtic_monotonics::systick::prelude::*; @@ -28,10 +29,13 @@ use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::gpio::{Output, PushPull}; use stm32h7xx_hal::prelude::*; use stm32h7xx_hal::rtc; +use stm32h7xx_hal::{ + gpio::{Alternate, Pin}, + hal::spi, +}; use stm32h7xx_hal::{rcc, rcc::rec}; -use messages::Message; -use stm32h7xx_hal::{gpio::{Alternate, Pin}, hal::spi}; use types::COM_ID; // global logger +use adc_manager::AdcManager; const DATA_CHANNEL_CAPACITY: usize = 10; @@ -46,10 +50,6 @@ fn panic() -> ! { #[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, dispatchers = [EXTI0, EXTI1, EXTI2, SPI3, SPI2])] mod app { - - - use adc_manager::AdcManager; - use super::*; #[shared] @@ -59,7 +59,7 @@ mod app { // sd_manager: SdManager< // stm32h7xx_hal::spi::Spi, // PA4>, - // >, + // >, radio_manager: RadioManager, can_command_manager: CanCommandManager, can_data_manager: CanDataManager, @@ -256,7 +256,7 @@ mod app { // let sd_manager = SdManager::new(spi_sd, cs_sd); - // ADC setup + // ADC setup let adc_spi: stm32h7xx_hal::spi::Spi< stm32h7xx_hal::stm32::SPI4, stm32h7xx_hal::spi::Enabled, @@ -344,7 +344,7 @@ mod app { can_data_manager, sbg_power, rtc, - adc_manager + adc_manager, }, LocalResources { led_red,