diff --git a/Cargo.toml b/Cargo.toml index 930bb5fad914929b54594dfbbc5948f6350c359f..f1dd0c7157ce4899fcabfff0c570a4a0307ec593 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tudelft-quadrupel" -version = "2.0.1" +version = "2.0.2" edition = "2021" authors = [ "Anne Stijns <anstijns@gmail.com>", diff --git a/src/barometer.rs b/src/barometer.rs index 41174bcaaceb43c7ace605a48e3bb90863d0b01f..80d64aafd798bb37ff7957066c57fe7e6def393e 100644 --- a/src/barometer.rs +++ b/src/barometer.rs @@ -3,7 +3,6 @@ use crate::once_cell::OnceCell; use crate::time::Instant; use crate::twi::TWI; use core::time::Duration; -use embedded_hal::prelude::_embedded_hal_blocking_i2c_WriteRead; const MS5611_ADDR: u8 = 0b0111_0111; const REG_READ: u8 = 0x0; @@ -80,29 +79,29 @@ struct Ms5611 { static BAROMETER: Mutex<OnceCell<Ms5611>> = Mutex::new(OnceCell::uninitialized()); pub(crate) fn initialize() { - TWI.modify(|twi| { - let mut prom = [0; 8]; - let mut data = [0u8; 2]; - for c in 0..8 { - twi.write_read(MS5611_ADDR, &[REG_PROM + 2 * c], &mut data) - .unwrap(); - prom[c as usize] = u16::from_be_bytes(data); - } + // Safety: The TWI mutex is not accessed in an interrupt + let twi = unsafe { TWI.no_critical_section_lock_mut() }; - BAROMETER.modify(|baro| { - baro.initialize(Ms5611 { - pressure_sensitivity: prom[1], - pressure_offset: prom[2], - temp_coef_pressure_sensitivity: prom[3], - temp_coef_pressure_offset: prom[4], - temp_ref: prom[5], - temp_coef: prom[6], - over_sampling_ratio: OverSamplingRatio::Opt4096, - loop_state: Ms5611LoopState::Reset, - most_recent_pressure: 0, - most_recent_temperature: 0, - }) - }) + let mut prom = [0; 8]; + let mut data = [0u8; 2]; + for c in 0..8 { + _ = twi.read(MS5611_ADDR, REG_PROM + 2 * c, &mut data); + prom[c as usize] = u16::from_be_bytes(data); + } + + BAROMETER.modify(|baro| { + baro.initialize(Ms5611 { + pressure_sensitivity: prom[1], + pressure_offset: prom[2], + temp_coef_pressure_sensitivity: prom[3], + temp_coef_pressure_offset: prom[4], + temp_ref: prom[5], + temp_coef: prom[6], + over_sampling_ratio: OverSamplingRatio::Opt4096, + loop_state: Ms5611LoopState::Reset, + most_recent_pressure: 0, + most_recent_temperature: 0, + }); }); } @@ -118,9 +117,9 @@ fn update() { //We let the chip know we want to read D1. twi.write( MS5611_ADDR, - &[REG_D1 + baro.over_sampling_ratio.addr_modifier()], - ) - .unwrap(); + REG_D1 + baro.over_sampling_ratio.addr_modifier(), + &[], + ); //Then set loop state for next iteration baro.loop_state = Ms5611LoopState::ReadD1 { @@ -135,16 +134,15 @@ fn update() { //Read D1 let mut buf = [0u8; 4]; - twi.write_read(MS5611_ADDR, &[REG_READ], &mut buf[1..4]) - .unwrap(); + _ = twi.read(MS5611_ADDR, REG_READ, &mut buf[1..4]); let d1 = u32::from_be_bytes(buf); //We let the chip know we want to read D2. twi.write( MS5611_ADDR, - &[REG_D2 + baro.over_sampling_ratio.addr_modifier()], - ) - .unwrap(); + REG_D2 + baro.over_sampling_ratio.addr_modifier(), + &[], + ); //Then set loop state for next iteration baro.loop_state = Ms5611LoopState::ReadD2 { @@ -160,8 +158,7 @@ fn update() { //Read D2 let mut buf = [0u8; 4]; - twi.write_read(MS5611_ADDR, &[REG_READ], &mut buf[1..4]) - .unwrap(); + _ = twi.read(MS5611_ADDR, REG_READ, &mut buf[1..4]); let d1 = u64::from(d1); let d2 = u64::from(u32::from_be_bytes(buf)); diff --git a/src/battery.rs b/src/battery.rs index b0a0ac24e4877574c38b0df5f58bbcf00a8660cc..90b17e986683f939174b6c03ee21e4199d0d9216 100644 --- a/src/battery.rs +++ b/src/battery.rs @@ -50,7 +50,7 @@ unsafe fn ADC() { adc.adc.events_end.reset(); // Battery voltage = (result*1.2*3/255*2) = RESULT*0.007058824 adc.last_result = adc.adc.result.read().result().bits() * 7; - }) + }); } /// Returns the battery voltage in 10^-2 volt. diff --git a/src/initialize.rs b/src/initialize.rs index 429d28d4193b20643772effadcc6dfddc9bbce61..f4d140c9b275412cab0e4152ce1d86ea30daec0b 100644 --- a/src/initialize.rs +++ b/src/initialize.rs @@ -6,13 +6,14 @@ use crate::{barometer, battery, flash, led, motor, mpu, time, twi, uart}; use alloc_cortex_m::CortexMHeap; use core::mem::MaybeUninit; use nrf51_pac::Peripherals; + static INITIALIZED: Mutex<bool> = Mutex::new(false); #[global_allocator] static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); /// Initialize the drone board. This should be run at boot. -/// +//t/ /// `heap_memory` should be a pointer to statically allocated memory. /// Care should be taken that the mutable reference given here *really* is the /// only mutable reference to that area of memory. That should of course be guaranteed by @@ -62,7 +63,12 @@ pub fn initialize(heap_memory: &'static mut [MaybeUninit<u8>], debug: bool) { if debug { let _ = send_bytes(b"RTC driver initialized\n"); } - twi::initialize(nrf51_peripherals.TWI0, gpio.p0_04, gpio.p0_02); + twi::initialize( + nrf51_peripherals.TWI0, + gpio.p0_04, + gpio.p0_02, + &mut cortex_m_peripherals.NVIC, + ); if debug { let _ = send_bytes(b"TWI initialized\n"); } @@ -97,7 +103,6 @@ pub fn initialize(heap_memory: &'static mut [MaybeUninit<u8>], debug: bool) { &mut cortex_m_peripherals.NVIC, &mut nrf51_peripherals.PPI, &mut nrf51_peripherals.GPIOTE, - gpio.p0_20, ); if debug { let _ = send_bytes(b"MOTOR driver initialized\n"); diff --git a/src/lib.rs b/src/lib.rs index d02fbaca8fdfb3f67205b791112d365ab0524c07..9fb9a39525ff686c8e6f15bc54c175715a9215d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] #![feature(strict_provenance)] #![deny(missing_docs)] -#![deny(warnings)] +// #![deny(warnings)] #![deny(unused_import_braces)] #![deny(unused_results)] #![deny(trivial_casts)] diff --git a/src/motor.rs b/src/motor.rs index fc1c7dc97772b761aa8ec1ad52b29cf316635f91..2c95bf2bf8cf1fd4def75e88b92b112e8460201b 100644 --- a/src/motor.rs +++ b/src/motor.rs @@ -1,9 +1,6 @@ use crate::mutex::Mutex; -use crate::nrf51_hal::prelude::OutputPin; use crate::once_cell::OnceCell; use cortex_m::peripheral::NVIC; -use nrf51_hal::gpio::p0::P0_20; -use nrf51_hal::gpio::{Disconnected, Level, Output, PushPull}; use nrf51_pac::{interrupt, Interrupt, GPIOTE, PPI}; struct Motors { @@ -11,7 +8,6 @@ struct Motors { motor_max: u16, timer1: nrf51_pac::TIMER1, timer2: nrf51_pac::TIMER2, - pin20: P0_20<Output<PushPull>>, } const MOTOR_0_PIN: u8 = 21; @@ -63,18 +59,13 @@ pub(crate) fn initialize( nvic: &mut NVIC, ppi: &mut PPI, gpiote: &mut GPIOTE, - pin20: P0_20<Disconnected>, ) { - // Configure pin20 - let pin20 = pin20.into_push_pull_output(Level::Low); - MOTORS.modify(|motors| { motors.initialize(Motors { motor_values: [0; 4], motor_max: 400, timer1, timer2, - pin20, }); // Configure GPIOTE. GPIOTE is stands for GPIO tasks and events. @@ -270,11 +261,9 @@ unsafe fn TIMER1() { motors.timer1.tasks_capture[2].write(|w| w.bits(1)); if motors.timer1.cc[2].read().bits() < 500 { - motors.pin20.set_high().unwrap(); // Safety: Any time is allowed motors.timer1.cc[0].write(|w| w.bits(u32::from(1000 + motors.motor_values[0]))); motors.timer1.cc[1].write(|w| w.bits(u32::from(1000 + motors.motor_values[1]))); - motors.pin20.set_low().unwrap(); } } } diff --git a/src/mpu/error.rs b/src/mpu/error.rs index f1550d0114b3dd299a645d58d05a7578e07f4b0e..98aae0eb19efd437582db57043021eee4dde7de9 100644 --- a/src/mpu/error.rs +++ b/src/mpu/error.rs @@ -1,29 +1,2 @@ -use core::fmt::Formatter; -use embedded_hal::blocking::i2c::{Write, WriteRead}; - -/// Error for sensor operations. -pub enum Error<I2c> -where - I2c: WriteRead + Write, - <I2c as WriteRead>::Error: core::fmt::Debug, - <I2c as Write>::Error: core::fmt::Debug, -{ - Write(<I2c as Write>::Error), - WriteRead(<I2c as WriteRead>::Error), - WrongDevice, -} - -impl<I2c> core::fmt::Debug for Error<I2c> -where - I2c: WriteRead + Write, - <I2c as WriteRead>::Error: core::fmt::Debug, - <I2c as Write>::Error: core::fmt::Debug, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> { - match self { - Error::WriteRead(e) => f.debug_tuple("WriteReadError").field(e).finish(), - Error::Write(e) => f.debug_tuple("WriteError").field(e).finish(), - Error::WrongDevice => f.write_str("WrongDevice"), - } - } -} +#[derive(Debug)] +pub enum Error {} diff --git a/src/mpu/firmware_loader.rs b/src/mpu/firmware_loader.rs index f35fdb9a53dd9c91a5f35699fef6784c36f2f999..3159f9424aa6d430fe9dee9f91ff8be23b8636b0 100644 --- a/src/mpu/firmware_loader.rs +++ b/src/mpu/firmware_loader.rs @@ -1,54 +1,44 @@ use crate::mpu::dmp_firmware::FIRMWARE; -use crate::mpu::error::Error; use crate::mpu::registers::Register; use crate::mpu::sensor::Mpu6050; -use embedded_hal::blocking::i2c::{Write, WriteRead}; +use crate::mpu::I2c; const BANK_SIZE: usize = 256; const CHUNK_SIZE: usize = 16; -impl<I2c> Mpu6050<I2c> -where - I2c: Write + WriteRead, - <I2c as WriteRead>::Error: core::fmt::Debug, - <I2c as Write>::Error: core::fmt::Debug, -{ - pub fn load_firmware(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { +impl Mpu6050 { + pub fn load_firmware(&mut self, i2c: &mut I2c) { self.write_memory(i2c, &FIRMWARE) } - pub fn boot_firmware(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - self.write(i2c, &[Register::PrgmStart as u8, 0x04, 0x00]) + pub fn boot_firmware(&mut self, i2c: &mut I2c) { + self.write(i2c, Register::PrgmStart as u8, &[0x04, 0x00]); } - fn write_memory(&mut self, i2c: &mut I2c, data: &[u8]) -> Result<(), Error<I2c>> { + fn write_memory(&mut self, i2c: &mut I2c, data: &[u8]) { for (bank, chunk) in data.chunks(BANK_SIZE).enumerate() { - self.write_bank(i2c, bank as u8, chunk)?; + self.write_bank(i2c, bank as u8, chunk); } - Ok(()) } - fn write_bank(&mut self, i2c: &mut I2c, bank: u8, data: &[u8]) -> Result<(), Error<I2c>> { - self.set_bank(i2c, bank)?; + fn write_bank(&mut self, i2c: &mut I2c, bank: u8, data: &[u8]) { + self.set_bank(i2c, bank); for (i, chunk) in data.chunks(CHUNK_SIZE).enumerate() { - let mut prolog_and_chunk: [u8; CHUNK_SIZE + 1] = [0; CHUNK_SIZE + 1]; - prolog_and_chunk[0] = Register::MemRw as u8; + let mut prolog_and_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE]; for (i, b) in chunk.iter().enumerate() { - prolog_and_chunk[i + 1] = *b; + prolog_and_chunk[i] = *b; } - self.set_memory_start_address(i2c, (i * CHUNK_SIZE) as u8)?; - self.write(i2c, &prolog_and_chunk)?; + self.set_memory_start_address(i2c, (i * CHUNK_SIZE) as u8); + self.write(i2c, Register::MemRw as u8, &prolog_and_chunk); } - - Ok(()) } - fn set_bank(&mut self, i2c: &mut I2c, bank: u8) -> Result<(), Error<I2c>> { + fn set_bank(&mut self, i2c: &mut I2c, bank: u8) { self.write_register(i2c, Register::BankSel, bank) } - fn set_memory_start_address(&mut self, i2c: &mut I2c, addr: u8) -> Result<(), Error<I2c>> { + fn set_memory_start_address(&mut self, i2c: &mut I2c, addr: u8) { self.write_register(i2c, Register::MemStartAddr, addr) } } diff --git a/src/mpu.rs b/src/mpu/mod.rs similarity index 70% rename from src/mpu.rs rename to src/mpu/mod.rs index c935ecb695a25f337d4a9164130d962199a96be5..52efc8527958847b971abc18e5167e34732080ef 100644 --- a/src/mpu.rs +++ b/src/mpu/mod.rs @@ -1,18 +1,15 @@ use crate::mpu::config::DigitalLowPassFilter; -use crate::mpu::error::Error; use crate::mpu::sensor::Mpu6050; use crate::mutex::Mutex; use crate::once_cell::OnceCell; -use crate::twi::TWI; +use crate::twi::{TwiWrapper, TWI}; +use error::Error; use nb::Error::WouldBlock; -use nrf51_hal::Twi; -use nrf51_pac::TWI0; use structs::{Accel, Gyro, Quaternion}; #[allow(unused)] mod config; mod dmp_firmware; -mod error; mod firmware_loader; #[allow(unused)] mod registers; @@ -21,34 +18,37 @@ mod sensor; /// structs to deal with mpu output, like quaternions pub mod structs; +mod error; + /// MPU Sample Rate Divider under DMP mode pub const SAMPLE_RATE_DIVIDER_MPU: u8 = 0; /// MPU Sample Rate Divider under RAW mode pub const SAMPLE_RATE_DIVIDER_RAW: u8 = 0; +type I2c = TwiWrapper; + struct Mpu { - mpu: Mpu6050<Twi<TWI0>>, + mpu: Mpu6050, dmp_enabled: bool, } static MPU: Mutex<OnceCell<Mpu>> = Mutex::new(OnceCell::uninitialized()); pub(crate) fn initialize() { - TWI.modify(|twi| { - let mut mpu: Mpu6050<Twi<TWI0>> = Mpu6050::new(&mut **twi).unwrap(); - - mpu.initialize_dmp(twi).unwrap(); - - mpu.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU) - .unwrap(); - mpu.set_digital_lowpass_filter(twi, DigitalLowPassFilter::Filter5) - .unwrap(); - MPU.modify(|m| { - m.initialize(Mpu { - mpu, - dmp_enabled: true, - }) - }); + // Safety: The TWI mutex is not accessed in an interrupt + let twi = unsafe { TWI.no_critical_section_lock_mut() }; + + let mut mpu = Mpu6050::new(twi); + + mpu.initialize_dmp(twi); + + mpu.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU); + mpu.set_digital_lowpass_filter(twi, DigitalLowPassFilter::Filter5); + MPU.modify(|m| { + m.initialize(Mpu { + mpu, + dmp_enabled: true, + }) }); } @@ -68,10 +68,9 @@ pub fn disable_dmp() { let mpu = unsafe { MPU.no_critical_section_lock_mut() }; mpu.mpu - .set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_RAW) - .unwrap(); - mpu.mpu.disable_dmp(twi).unwrap(); - mpu.mpu.disable_fifo(twi).unwrap(); + .set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_RAW); + mpu.mpu.disable_dmp(twi); + mpu.mpu.disable_fifo(twi); mpu.dmp_enabled = false; } @@ -79,18 +78,16 @@ pub fn disable_dmp() { /// /// # Errors /// when the global constant `SAMPLE_RATE_DIVIDER_MPU` is wrong (i.e. will not panic under normal conditions) -pub fn enable_dmp() -> Result<(), Error<Twi<TWI0>>> { +pub fn enable_dmp() { // Safety: The TWI and MPU mutexes are not accessed in an interrupt let twi = unsafe { TWI.no_critical_section_lock_mut() }; let mpu = unsafe { MPU.no_critical_section_lock_mut() }; mpu.mpu - .set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU)?; - mpu.mpu.enable_dmp(twi)?; - mpu.mpu.enable_fifo(twi)?; + .set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU); + mpu.mpu.enable_dmp(twi); + mpu.mpu.enable_fifo(twi); mpu.dmp_enabled = true; - - Ok(()) } /// This reads the most recent angle from the DMP, if there are any new ones available. @@ -102,7 +99,7 @@ pub fn enable_dmp() -> Result<(), Error<Twi<TWI0>>> { /// /// # Errors /// when a TWI(I2C) operation failed -pub fn read_dmp_bytes() -> nb::Result<Quaternion, Error<Twi<TWI0>>> { +pub fn read_dmp_bytes() -> nb::Result<Quaternion, ()> { // Safety: The TWI and MPU mutexes are not accessed in an interrupt let twi = unsafe { TWI.no_critical_section_lock_mut() }; let mpu = unsafe { MPU.no_critical_section_lock_mut() }; @@ -110,15 +107,24 @@ pub fn read_dmp_bytes() -> nb::Result<Quaternion, Error<Twi<TWI0>>> { assert!(mpu.dmp_enabled); // If there isn't a full packet ready, return none - let mut len = mpu.mpu.get_fifo_count(twi)?; + let mut len = mpu.mpu.get_fifo_count(twi); if len < 28 { return Err(WouldBlock); } + // If we got mis-aligned, we skip a packet + if len % 28 != 0 { + let skip = len % 28; + let mut buf = [0; 28]; + + let _ = mpu.mpu.read_fifo(twi, &mut buf[..skip]); + return Err(WouldBlock); + } + // Keep reading while there are more full packets let mut buf = [0; 28]; while len >= 28 { - let _ = mpu.mpu.read_fifo(twi, &mut buf)?; + let _ = mpu.mpu.read_fifo(twi, &mut buf); len -= 28; } @@ -131,13 +137,13 @@ pub fn read_dmp_bytes() -> nb::Result<Quaternion, Error<Twi<TWI0>>> { /// /// # Errors /// when a TWI operation failed -pub fn read_raw() -> Result<(Accel, Gyro), Error<Twi<TWI0>>> { +pub fn read_raw() -> Result<(Accel, Gyro), Error> { // Safety: The TWI and MPU mutexes are not accessed in an interrupt let twi = unsafe { TWI.no_critical_section_lock_mut() }; let mpu = unsafe { MPU.no_critical_section_lock_mut() }; - let accel = mpu.mpu.accel(twi)?; - let gyro = mpu.mpu.gyro(twi)?; + let accel = mpu.mpu.accel(twi); + let gyro = mpu.mpu.gyro(twi); Ok((accel, gyro)) } diff --git a/src/mpu/sensor.rs b/src/mpu/sensor.rs index f5effef688f3d7e8c94b50f614463c5f7e8b890b..f2721f731dcaa5bbd2c0d7fe35e0f3e186fd63f2 100644 --- a/src/mpu/sensor.rs +++ b/src/mpu/sensor.rs @@ -1,84 +1,64 @@ +use crate::led::Green; use crate::mpu::config::Fifo; use crate::mpu::config::GyroFullScale; use crate::mpu::config::{AccelFullScale, ClockSource, DigitalLowPassFilter}; -use crate::mpu::error::Error; use crate::mpu::registers::Register; use crate::mpu::structs::{Accel, Gyro}; use crate::time::delay_ms_assembly; +use crate::twi::TwiWrapper; use core::marker::PhantomData; use core::time::Duration; use embedded_hal::blocking::i2c::{Write, WriteRead}; const MPU6050_ADDRESS: u8 = 0x68; -/// `InvenSense` MPU-6050 Driver -pub struct Mpu6050<I2c> -where - I2c: Write + WriteRead, - <I2c as WriteRead>::Error: core::fmt::Debug, - <I2c as Write>::Error: core::fmt::Debug, -{ - _p: PhantomData<I2c>, -} +pub type I2c = TwiWrapper; + +pub(crate) struct Mpu6050(PhantomData<()>); -impl<I2c> Mpu6050<I2c> -where - I2c: Write + WriteRead, - <I2c as WriteRead>::Error: core::fmt::Debug, - <I2c as Write>::Error: core::fmt::Debug, -{ +impl Mpu6050 { /// Construct a new i2c driver for the MPU-6050 - pub fn new(i2c: &mut I2c) -> Result<Self, Error<I2c>> { - let mut sensor = Self { - _p: PhantomData::default(), - }; + pub fn new(i2c: &mut I2c) -> Self { + let mut sensor = Self(PhantomData::default()); - sensor.disable_sleep(i2c)?; + sensor.disable_sleep(i2c); - Ok(sensor) + sensor } /// Load DMP firmware and perform all appropriate initialization. - pub fn initialize_dmp(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - self.reset(i2c)?; - self.disable_sleep(i2c)?; - self.reset_signal_path(i2c)?; - self.disable_dmp(i2c)?; - self.set_clock_source(i2c, ClockSource::Xgyro)?; - self.disable_interrupts(i2c)?; - self.set_fifo_enabled(i2c, Fifo::all_disabled())?; - self.set_accel_full_scale(i2c, AccelFullScale::G2)?; - self.set_sample_rate_divider(i2c, 0)?; - self.set_digital_lowpass_filter(i2c, DigitalLowPassFilter::Filter0)?; - self.load_firmware(i2c)?; - self.boot_firmware(i2c)?; - self.set_gyro_full_scale(i2c, GyroFullScale::Deg2000)?; - self.enable_fifo(i2c)?; - self.reset_fifo(i2c)?; - self.disable_dmp(i2c)?; - self.enable_dmp(i2c)?; - Ok(()) - } - - pub(crate) fn read( - &mut self, - i2c: &mut I2c, - bytes: &[u8], - response: &mut [u8], - ) -> Result<(), Error<I2c>> { - i2c.write_read(MPU6050_ADDRESS, bytes, response) - .map_err(|e| Error::WriteRead(e)) - } - - pub(crate) fn write(&mut self, i2c: &mut I2c, bytes: &[u8]) -> Result<(), Error<I2c>> { - i2c.write(MPU6050_ADDRESS, bytes) - .map_err(|e| Error::Write(e)) - } - - pub(crate) fn read_register(&mut self, i2c: &mut I2c, reg: Register) -> Result<u8, Error<I2c>> { + pub fn initialize_dmp(&mut self, i2c: &mut I2c) { + self.reset(i2c); + self.disable_sleep(i2c); + self.reset_signal_path(i2c); + self.disable_dmp(i2c); + self.set_clock_source(i2c, ClockSource::Xgyro); + self.disable_interrupts(i2c); + self.set_fifo_enabled(i2c, Fifo::all_disabled()); + self.set_accel_full_scale(i2c, AccelFullScale::G2); + self.set_sample_rate_divider(i2c, 0); + self.set_digital_lowpass_filter(i2c, DigitalLowPassFilter::Filter0); + self.load_firmware(i2c); + self.boot_firmware(i2c); + self.set_gyro_full_scale(i2c, GyroFullScale::Deg2000); + self.enable_fifo(i2c); + self.reset_fifo(i2c); + self.disable_dmp(i2c); + self.enable_dmp(i2c); + } + + pub(crate) fn read(&mut self, i2c: &mut I2c, reg: u8, response: &mut [u8]) { + let _ = i2c.read(MPU6050_ADDRESS, reg, response); + } + + pub(crate) fn write(&mut self, i2c: &mut I2c, reg_address: u8, bytes: &[u8]) { + i2c.write(MPU6050_ADDRESS, reg_address, bytes); + } + + pub(crate) fn read_register(&mut self, i2c: &mut I2c, reg: Register) -> u8 { let mut buf = [0; 1]; - self.read(i2c, &[reg as u8], &mut buf)?; - Ok(buf[0]) + self.read(i2c, reg as u8, &mut buf); + buf[0] } pub(crate) fn read_registers<'a>( @@ -86,180 +66,142 @@ where i2c: &mut I2c, reg: Register, buf: &'a mut [u8], - ) -> Result<&'a [u8], Error<I2c>> { - self.read(i2c, &[reg as u8], buf)?; - Ok(buf) + ) -> &'a [u8] { + self.read(i2c, reg as u8, buf); + buf } - pub(crate) fn write_register( - &mut self, - i2c: &mut I2c, - reg: Register, - value: u8, - ) -> Result<(), Error<I2c>> { - self.write(i2c, &[reg as u8, value]) + pub(crate) fn write_register(&mut self, i2c: &mut I2c, reg: Register, value: u8) { + self.write(i2c, reg as u8, &[value]); } // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ /// Perform power reset of the MPU - pub fn reset(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::PwrMgmt1)?; + pub fn reset(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::PwrMgmt1); value |= 1 << 7; - self.write_register(i2c, Register::PwrMgmt1, value)?; + self.write_register(i2c, Register::PwrMgmt1, value); delay_ms_assembly(200); - Ok(()) } /// Perform reset of the signal path - pub fn reset_signal_path(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn reset_signal_path(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value |= 1 << 0; - self.write_register(i2c, Register::UserCtrl, value)?; + self.write_register(i2c, Register::UserCtrl, value); delay_ms_assembly(200); - Ok(()) } /// Pick the clock-source - pub fn set_clock_source( - &mut self, - i2c: &mut I2c, - clock_source: ClockSource, - ) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::PwrMgmt1)?; + pub fn set_clock_source(&mut self, i2c: &mut I2c, clock_source: ClockSource) { + let mut value = self.read_register(i2c, Register::PwrMgmt1); value |= clock_source as u8; - self.write_register(i2c, Register::PwrMgmt1, value)?; - Ok(()) + self.write_register(i2c, Register::PwrMgmt1, value); } - pub fn disable_interrupts(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { + pub fn disable_interrupts(&mut self, i2c: &mut I2c) { self.write_register(i2c, Register::IntEnable, 0x00) } - pub fn set_accel_full_scale( - &mut self, - i2c: &mut I2c, - scale: AccelFullScale, - ) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::AccelConfig)?; + pub fn set_accel_full_scale(&mut self, i2c: &mut I2c, scale: AccelFullScale) { + let mut value = self.read_register(i2c, Register::AccelConfig); value |= (scale as u8) << 3; self.write_register(i2c, Register::AccelConfig, value) } - pub fn set_gyro_full_scale( - &mut self, - i2c: &mut I2c, - scale: GyroFullScale, - ) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::GyroConfig)?; + pub fn set_gyro_full_scale(&mut self, i2c: &mut I2c, scale: GyroFullScale) { + let mut value = self.read_register(i2c, Register::GyroConfig); value |= (scale as u8) << 3; self.write_register(i2c, Register::GyroConfig, value) } - pub fn set_sample_rate_divider(&mut self, i2c: &mut I2c, div: u8) -> Result<(), Error<I2c>> { + pub fn set_sample_rate_divider(&mut self, i2c: &mut I2c, div: u8) { self.write_register(i2c, Register::SmpRtDiv, div) } - pub fn set_digital_lowpass_filter( - &mut self, - i2c: &mut I2c, - filter: DigitalLowPassFilter, - ) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::Config)?; + pub fn set_digital_lowpass_filter(&mut self, i2c: &mut I2c, filter: DigitalLowPassFilter) { + let mut value = self.read_register(i2c, Register::Config); value |= filter as u8; self.write_register(i2c, Register::Config, value) } - pub fn reset_fifo(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn reset_fifo(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value |= 1 << 2; self.write_register(i2c, Register::UserCtrl, value) } - pub fn enable_fifo(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn enable_fifo(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value |= 1 << 6; self.write_register(i2c, Register::UserCtrl, value) } - pub fn disable_fifo(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn disable_fifo(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value &= !(1 << 6); self.write_register(i2c, Register::UserCtrl, value) } /// Set the DMP bit. /// To perform full DMP initialization, see `initialize_dmp()` - pub fn enable_dmp(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn enable_dmp(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value |= 1 << 7; self.write_register(i2c, Register::UserCtrl, value) } // Unset the DMP bit. - pub fn disable_dmp(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn disable_dmp(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value &= !(1 << 7); self.write_register(i2c, Register::UserCtrl, value) } /// Reset the DMP processor - pub fn reset_dmp(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::UserCtrl)?; + pub fn reset_dmp(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::UserCtrl); value |= 1 << 3; self.write_register(i2c, Register::UserCtrl, value) } /// Read the FIFO - pub fn read_fifo<'a>( - &mut self, - i2c: &mut I2c, - buf: &'a mut [u8], - ) -> Result<&'a [u8], Error<I2c>> { - let mut len = self.get_fifo_count(i2c)?; - - if buf.len() < len { - len = buf.len(); - } - - if len == 0 { - Ok(&buf[0..0]) - } else { - self.read_registers(i2c, Register::FifoRw, &mut buf[0..len]) - } + pub fn read_fifo<'a>(&mut self, i2c: &mut I2c, buf: &'a mut [u8]) -> &'a [u8] { + self.read_registers(i2c, Register::FifoRw, &mut buf[..]) } - pub fn get_fifo_enabled(&mut self, i2c: &mut I2c) -> Result<Fifo, Error<I2c>> { - let value = self.read_register(i2c, Register::FifoEn)?; - Ok(Fifo::from_byte(value)) + pub fn get_fifo_enabled(&mut self, i2c: &mut I2c) -> Fifo { + let value = self.read_register(i2c, Register::FifoEn); + Fifo::from_byte(value) } - pub fn set_fifo_enabled(&mut self, i2c: &mut I2c, fifo: Fifo) -> Result<(), Error<I2c>> { + pub fn set_fifo_enabled(&mut self, i2c: &mut I2c, fifo: Fifo) { self.write_register(i2c, Register::FifoEn, fifo.to_byte()) } - pub fn get_fifo_count(&mut self, i2c: &mut I2c) -> Result<usize, Error<I2c>> { + pub fn get_fifo_count(&mut self, i2c: &mut I2c) -> usize { let mut buf = [0; 2]; - let _value = self.read_registers(i2c, Register::FifoCount_H, &mut buf)?; - Ok(u16::from_be_bytes(buf) as usize) + let _value = self.read_registers(i2c, Register::FifoCount_H, &mut buf); + u16::from_be_bytes(buf) as usize } - pub fn disable_sleep(&mut self, i2c: &mut I2c) -> Result<(), Error<I2c>> { - let mut value = self.read_register(i2c, Register::PwrMgmt1)?; + pub fn disable_sleep(&mut self, i2c: &mut I2c) { + let mut value = self.read_register(i2c, Register::PwrMgmt1); value &= !(1 << 6); self.write_register(i2c, Register::PwrMgmt1, value) } - pub fn accel(&mut self, i2c: &mut I2c) -> Result<Accel, Error<I2c>> { + pub fn accel(&mut self, i2c: &mut I2c) -> Accel { let mut data = [0; 6]; - let _ = self.read_registers(i2c, Register::AccelX_H, &mut data)?; - Ok(Accel::from_bytes(data)) + let _ = self.read_registers(i2c, Register::AccelX_H, &mut data); + Accel::from_bytes(data) } - pub fn gyro(&mut self, i2c: &mut I2c) -> Result<Gyro, Error<I2c>> { + pub fn gyro(&mut self, i2c: &mut I2c) -> Gyro { let mut data = [0; 6]; - let _ = self.read_registers(i2c, Register::GyroX_H, &mut data)?; - Ok(Gyro::from_bytes(data)) + let _ = self.read_registers(i2c, Register::GyroX_H, &mut data); + Gyro::from_bytes(data) } } diff --git a/src/twi.rs b/src/twi.rs index f8ec8c3023f4eb471c406563740ad536af7681de..77262338547d2a5bd89cd9e883c63a10349101e7 100644 --- a/src/twi.rs +++ b/src/twi.rs @@ -1,26 +1,229 @@ use crate::mutex::Mutex; use crate::once_cell::OnceCell; +use core::sync::atomic::{AtomicBool, Ordering}; +use cortex_m::peripheral::NVIC; use nrf51_hal::gpio::p0::{P0_02, P0_04}; use nrf51_hal::gpio::{Disconnected, Pin}; -use nrf51_hal::twi::Pins; -use nrf51_hal::Twi; +use nrf51_pac::interrupt; use nrf51_pac::twi0::frequency::FREQUENCY_A; -use nrf51_pac::TWI0; +use nrf51_pac::{Interrupt, GPIO, TWI0}; -pub(crate) static TWI: Mutex<OnceCell<Twi<TWI0>>> = Mutex::new(OnceCell::uninitialized()); +const FREQ: FREQUENCY_A = FREQUENCY_A::K400; -pub(crate) fn initialize(twi: TWI0, scl_pin: P0_04<Disconnected>, sda_pin: P0_02<Disconnected>) { - let scl_pin = scl_pin.into_floating_input(); - let sda_pin = sda_pin.into_floating_input(); +pub(crate) static TWI: Mutex<OnceCell<TwiWrapper>> = Mutex::new(OnceCell::uninitialized()); +pub struct TwiWrapper { + twi: TWI0, + sent: AtomicBool, + recv: AtomicBool, +} + +pub enum TwiStatus { + BufEmpty, + Success, +} + +impl TwiWrapper { + fn set_sent_flag(&self, value: bool) { + self.sent.store(value, Ordering::SeqCst) + } + + fn set_recv_flag(&self, value: bool) { + self.recv.store(value, Ordering::SeqCst) + } + + fn wait(&self, flag: &AtomicBool) { + while !flag.load(Ordering::SeqCst) { + core::hint::spin_loop(); + } + } + + fn wait_sent(&self) { + self.wait(&self.sent) + } + + fn wait_recv(&self) { + self.wait(&self.recv) + } + + pub fn read(&self, addr: u8, reg_addr: u8, data: &mut [u8]) -> TwiStatus { + if data.is_empty() { + return TwiStatus::BufEmpty; + } + + self.set_sent_flag(false); + self.set_recv_flag(false); + + self.twi + .address + .write(|w| unsafe { w.address().bits(addr) }); + self.twi.txd.write(|w| unsafe { w.txd().bits(reg_addr) }); + self.twi.shorts.reset(); + self.twi.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + self.wait_sent(); + self.set_sent_flag(false); + + if data.len() == 1 { + self.twi.shorts.write(|w| w.bb_stop().set_bit()) + } else { + self.twi.shorts.write(|w| w.bb_suspend().set_bit()) + } + + self.twi.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + let mut bytes_left = data.len(); + let mut write_ptr = 0; + + loop { + self.wait_recv(); + self.set_recv_flag(false); + + data[write_ptr] = self.twi.rxd.read().rxd().bits(); + write_ptr += 1; + + bytes_left -= 1; + if bytes_left == 1 { + self.twi.shorts.write(|w| w.bb_stop().set_bit()) + } + self.twi.tasks_resume.write(|w| unsafe { w.bits(1) }); + + if bytes_left == 0 { + break; + } + } + + TwiStatus::Success + } + + pub fn write(&self, addr: u8, reg_addr: u8, data: &[u8]) { + if data.is_empty() { + self.twi + .address + .write(|w| unsafe { w.address().bits(addr) }); + self.twi.shorts.write(|w| w.bb_stop().set_bit()); + self.twi.txd.write(|w| unsafe { w.txd().bits(reg_addr) }); + self.twi.tasks_starttx.write(|w| unsafe { w.bits(1) }); + self.wait_sent(); + + return; + } + + self.set_sent_flag(false); + + self.twi + .address + .write(|w| unsafe { w.address().bits(addr) }); + self.twi.shorts.reset(); + self.twi.txd.write(|w| unsafe { w.txd().bits(reg_addr) }); + self.twi.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + self.wait_sent(); + self.set_sent_flag(false); + + for &i in data { + self.twi.txd.write(|w| unsafe { w.txd().bits(i) }); + + self.wait_sent(); + self.set_sent_flag(false); + } + + self.twi.tasks_stop.write(|w| unsafe { w.bits(1) }); + } +} + +pub(crate) fn initialize( + twi: TWI0, + scl_pin: P0_04<Disconnected>, + sda_pin: P0_02<Disconnected>, + nvic: &mut NVIC, +) { + let scl_pin = Pin::from(scl_pin.into_pullup_input()); + let sda_pin = Pin::from(sda_pin.into_pullup_input()); + + // The TWIM peripheral requires the pins to be in a mode that is not + // exposed through the GPIO API, and might it might not make sense to + // expose it there. + // + // Until we've figured out what to do about this, let's just configure + // the pins through the raw peripheral API. All of the following is + // safe, as we own the pins now and have exclusive access to their + // registers. + for &pin in &[scl_pin.pin(), sda_pin.pin()] { + unsafe { &*GPIO::ptr() }.pin_cnf[pin as usize].write(|w| { + w.dir() + .input() + .input() + .connect() + .pull() + .pullup() + .drive() + .s0d1() + .sense() + .disabled() + }); + } + + // Set pins. + twi.pselscl + .write(|w| unsafe { w.bits(scl_pin.pin().into()) }); + twi.pselsda + .write(|w| unsafe { w.bits(sda_pin.pin().into()) }); + + // Clear interrupts + twi.events_rxdready.reset(); + twi.events_txdsent.reset(); + + // Set frequency. + twi.frequency.write(|w| w.frequency().variant(FREQ)); + + // Set which interrupts we want to receive + twi.intenset + .write(|w| w.txdsent().set_bit().rxdready().set_bit().error().set_bit()); + + twi.shorts.reset(); + twi.enable.write(|w| w.enable().enabled()); + + // Initialize oncecell + // twi.events_rxdready.reset(); + // twi.events_txdsent.reset(); TWI.modify(|t| { - t.initialize(Twi::new( + t.initialize(TwiWrapper { twi, - Pins { - scl: Pin::from(scl_pin), - sda: Pin::from(sda_pin), - }, - FREQUENCY_A::K400, - )) + recv: false.into(), + sent: false.into(), + }) }); + + // Setup NVIC + NVIC::unpend(Interrupt::SPI0_TWI0); + // Safety: We are not using priority-based critical sections. + unsafe { + nvic.set_priority(Interrupt::SPI0_TWI0, 3); // Same as C template + NVIC::unmask(Interrupt::SPI0_TWI0); + } +} + +#[interrupt] +unsafe fn SPI0_TWI0() { + // Safety: interrupts are already turned off here, since we are inside an interrupt + // We might be accessing the hardware while the interrupted code also wants to, this is fine since we're only touching the EVENT registers which are not touched by the other code + let twi = unsafe { TWI.no_critical_section_lock_mut() }; + + if twi.twi.events_rxdready.read().bits() != 0 { + twi.twi.events_rxdready.reset(); + twi.recv.store(true, Ordering::SeqCst); + } + if twi.twi.events_txdsent.read().bits() != 0 { + twi.twi.events_txdsent.reset(); + twi.sent.store(true, Ordering::SeqCst); + } + + // Errors are silently ignored + if twi.twi.events_error.read().bits() != 0 { + twi.twi + .errorsrc + .write(|w| w.anack().clear_bit().overrun().clear_bit()); // Clear error source + twi.twi.events_error.reset(); + } }