From 09a7513ceffe97753be9946a4c182974791d540f Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 25 Jan 2019 17:13:10 +0100 Subject: [PATCH] Store singleton directly in I2C type to take ownership Make the I2C type generic over a new I2cTrait so that all I2C busses are suppored. --- src/bin/async-await.rs | 6 +++--- src/bin/polling.rs | 4 ++-- src/i2c.rs | 45 ++++++++++++++++++++++-------------------- src/init/mod.rs | 8 ++++---- src/touch.rs | 5 +++-- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/bin/async-await.rs b/src/bin/async-await.rs index 5a7fd3f0..1ff09fc2 100644 --- a/src/bin/async-await.rs +++ b/src/bin/async-await.rs @@ -21,7 +21,6 @@ extern crate futures; extern crate smoltcp; extern crate spin; -use alloc::boxed::Box; use alloc::sync::Arc; use alloc::vec::Vec; use alloc_cortex_m::CortexMHeap; @@ -43,6 +42,7 @@ use smoltcp::{ }; use stm32f7::stm32f7x6::{ CorePeripherals, Interrupt, Peripherals, ETHERNET_DMA, ETHERNET_MAC, RCC, SAI2, SYSCFG, + self as device, }; use stm32f7_discovery::{ ethernet, @@ -135,7 +135,7 @@ fn run() -> ! { // example allocation let _xs = vec![1, 2, 3]; - let mut i2c_3 = init::init_i2c_3(Box::leak(Box::new(peripherals.I2C3)), &mut rcc); + let mut i2c_3 = init::init_i2c_3(peripherals.I2C3, &mut rcc); i2c_3.test_1(); i2c_3.test_2(); @@ -340,7 +340,7 @@ where F: Framebuffer, { touch_int_stream: S, - i2c_3_mutex: Arc>>, + i2c_3_mutex: Arc>>, layer_mutex: Arc>>, } diff --git a/src/bin/polling.rs b/src/bin/polling.rs index d68dc97c..e5ba894d 100644 --- a/src/bin/polling.rs +++ b/src/bin/polling.rs @@ -32,7 +32,7 @@ use smoltcp::{ wire::{EthernetAddress, IpEndpoint, Ipv4Address, IpCidr}, dhcp::Dhcpv4Client, }; -use stm32f7::stm32f7x6::{CorePeripherals, Interrupt, Peripherals}; +use stm32f7::stm32f7x6::{self as device, CorePeripherals, Interrupt, Peripherals}; use stm32f7_discovery::{ ethernet, gpio::{GpioPort, InputPin, OutputPin}, @@ -111,7 +111,7 @@ fn main() -> ! { let _xs = vec![1, 2, 3]; - let mut i2c_3 = init::init_i2c_3(&peripherals.I2C3, &mut rcc); + let mut i2c_3 = init::init_i2c_3(peripherals.I2C3, &mut rcc); i2c_3.test_1(); i2c_3.test_2(); diff --git a/src/i2c.rs b/src/i2c.rs index 911fcc09..9ddf6000 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -2,16 +2,24 @@ use core::iter::TrustedLen; use core::marker::PhantomData; +use core::ops::Deref; use embedded_hal; use stm32f7::stm32f7x6::{ - i2c1::{self, RegisterBlock}, + i2c1, RCC, + self as device, }; -// TODO use &mut when svd2rust API has changed (modification should require &mut) -//pub struct I2C<'a>(&'a mut RegisterBlock); +pub trait I2cTrait: Deref { + +} + +impl I2cTrait for device::I2C1 {} +impl I2cTrait for device::I2C2 {} +impl I2cTrait for device::I2C3 {} + /// Represents an I2C (Inter-Integrated Circuit) bus. -pub struct I2C<'a>(&'a RegisterBlock); +pub struct I2C(I); /// Errors that can happen while accessing the I2C bus. #[derive(Debug)] @@ -49,8 +57,8 @@ fn icr_clear_all(w: &mut i2c1::icr::W) -> &mut i2c1::icr::W { /// An active connection to a device on the I2C bus. /// /// Allows reading and writing the registers of the device. -pub struct I2cConnection<'a, 'i: 'a, T: RegisterType> { - i2c: &'a mut I2C<'i>, +pub struct I2cConnection<'a, I: I2cTrait, T: RegisterType> { + i2c: &'a mut I2C, device_address: Address, register_type: PhantomData, } @@ -107,7 +115,7 @@ impl RegisterType for u16 { } } -impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> { +impl<'a, I: I2cTrait, T: RegisterType> I2cConnection<'a, I, T> { fn start(&mut self, read: bool, bytes: u8) { self.i2c.0.cr2.write(|w| { w.sadd().bits(self.device_address.0); // slave_address @@ -213,7 +221,7 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> { } } -impl<'a> I2C<'a> { +impl I2C { /// Connects to the specified device and run the closure `f` with the connection as argument. /// /// This function takes an exclusive reference to the `I2C` type because it blocks the I2C @@ -221,7 +229,7 @@ impl<'a> I2C<'a> { pub fn connect(&mut self, device_address: Address, f: F) -> Result<(), Error> where T: RegisterType, - F: FnOnce(I2cConnection) -> Result<(), Error>, + F: FnOnce(I2cConnection) -> Result<(), Error>, { { let conn = I2cConnection { @@ -384,29 +392,29 @@ impl<'a> I2C<'a> { } } -impl<'a> embedded_hal::blocking::i2c::Read for I2C<'a> { +impl embedded_hal::blocking::i2c::Read for I2C { type Error = Error; fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.connect( Address::bits_7(address), - |mut connection: I2cConnection| connection.read_bytes_raw(buffer.iter_mut()), + |mut connection: I2cConnection| connection.read_bytes_raw(buffer.iter_mut()), ) } } -impl<'a> embedded_hal::blocking::i2c::Write for I2C<'a> { +impl embedded_hal::blocking::i2c::Write for I2C { type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.connect( Address::bits_7(address), - |mut connection: I2cConnection| connection.write_bytes(bytes.iter().map(|b| *b)), + |mut connection: I2cConnection| connection.write_bytes(bytes.iter().map(|b| *b)), ) } } -impl<'a> embedded_hal::blocking::i2c::WriteRead for I2C<'a> { +impl embedded_hal::blocking::i2c::WriteRead for I2C { type Error = Error; fn write_read( @@ -417,7 +425,7 @@ impl<'a> embedded_hal::blocking::i2c::WriteRead for I2C<'a> { ) -> Result<(), Self::Error> { self.connect( Address::bits_7(address), - |mut connection: I2cConnection| { + |mut connection: I2cConnection| { connection.write_bytes(bytes.iter().map(|b| *b))?; connection.read_bytes_raw(buffer.iter_mut()) }, @@ -426,12 +434,7 @@ impl<'a> embedded_hal::blocking::i2c::WriteRead for I2C<'a> { } /// Initialize the I2C bus and return an `I2C` type. -/// -/// The IC2 type assumes that it has ownership of the I2C buffer. Therefore it is unsafe to access -/// the passed RegisterBlock as long as the I2C lives. (This function should take a -/// `&mut RegisterBlock`, but this is not possible due to the API that svd2rust generates. See -/// [stm32f7-discovery#72](https://github.com/embed-rs/stm32f7-discovery/issues/72) for more info. -pub fn init<'a>(i2c: &'a RegisterBlock, rcc: &mut RCC) -> I2C<'a> { +pub fn init(i2c: I, rcc: &mut RCC) -> I2C { // enable clocks rcc.apb1enr.modify(|_, w| w.i2c3en().enabled()); diff --git a/src/init/mod.rs b/src/init/mod.rs index 9c974598..3939ee2d 100644 --- a/src/init/mod.rs +++ b/src/init/mod.rs @@ -1,9 +1,9 @@ //! Provides various hardware initialization functions. -use crate::i2c::{self, I2C}; +use crate::i2c::{self, I2C, I2cTrait}; use crate::lcd::{self, Lcd}; use crate::system_clock; -use stm32f7::stm32f7x6::{i2c1, FLASH, FMC, LTDC, PWR, RCC, SAI2, SYST}; +use stm32f7::stm32f7x6::{self as device, i2c1, FLASH, FMC, LTDC, PWR, RCC, SAI2, SYST}; pub use self::pins::init as pins; @@ -298,7 +298,7 @@ pub fn init_lcd<'a>(ltdc: &'a mut LTDC, rcc: &mut RCC) -> Lcd<'a> { /// Initializes the I2C3 bus. /// /// This function is equivalent to [`i2c::init`](crate::i2c::init). -pub fn init_i2c_3<'a>(i2c: &'a i2c1::RegisterBlock, rcc: &mut RCC) -> I2C<'a> { +pub fn init_i2c_3(i2c: device::I2C3, rcc: &mut RCC) -> I2C { i2c::init(i2c, rcc) } @@ -525,7 +525,7 @@ const WM8994_ADDRESS: i2c::Address = i2c::Address::bits_7(0b0011010); /// Initializes the WM8994 audio controller. /// /// Required for audio input. -pub fn init_wm8994(i2c_3: &mut i2c::I2C) -> Result<(), i2c::Error> { +pub fn init_wm8994(i2c_3: &mut i2c::I2C) -> Result<(), i2c::Error> { i2c_3.connect::(WM8994_ADDRESS, |mut conn| { // read and check device family ID assert_eq!(conn.read(0).ok(), Some(0x8994)); diff --git a/src/touch.rs b/src/touch.rs index a8fcc420..43b19b75 100644 --- a/src/touch.rs +++ b/src/touch.rs @@ -2,6 +2,7 @@ use crate::i2c::{self, I2C}; use arrayvec::ArrayVec; +use stm32f7::stm32f7x6 as device; const FT5336_ADDRESS: i2c::Address = i2c::Address::bits_7(0b0111000); const FT5336_FAMILY_ID_REGISTER: u8 = 0xA8; @@ -11,7 +12,7 @@ const FT5336_STATUS_REGISTER: u8 = 0x02; const FT5336_DATA_REGISTERS: [u8; 5] = [0x03, 0x09, 0x0F, 0x15, 0x1B]; /// Checks the whether the device familiy ID register contains the expected value. -pub fn check_family_id(i2c_3: &mut I2C) -> Result<(), i2c::Error> { +pub fn check_family_id(i2c_3: &mut I2C) -> Result<(), i2c::Error> { i2c_3.connect::(FT5336_ADDRESS, |mut conn| { // read and check device family ID assert_eq!(conn.read(FT5336_FAMILY_ID_REGISTER).ok(), Some(0x51)); @@ -27,7 +28,7 @@ pub struct Touch { } /// Returns a list of active touch points. -pub fn touches(i2c_3: &mut I2C) -> Result, i2c::Error> { +pub fn touches(i2c_3: &mut I2C) -> Result, i2c::Error> { let mut touches = ArrayVec::new(); i2c_3.connect::(FT5336_ADDRESS, |mut conn| { let status = conn.read(FT5336_STATUS_REGISTER)?;