Skip to content

Commit

Permalink
Store singleton directly in I2C type to take ownership
Browse files Browse the repository at this point in the history
Make the I2C type generic over a new I2cTrait so that all I2C busses are suppored.
  • Loading branch information
phil-opp authored and oli-obk committed Jan 25, 2019
1 parent 6650509 commit 09a7513
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 32 deletions.
6 changes: 3 additions & 3 deletions src/bin/async-await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -340,7 +340,7 @@ where
F: Framebuffer,
{
touch_int_stream: S,
i2c_3_mutex: Arc<FutureMutex<I2C<'static>>>,
i2c_3_mutex: Arc<FutureMutex<I2C<device::I2C3>>>,
layer_mutex: Arc<FutureMutex<Layer<F>>>,
}

Expand Down
4 changes: 2 additions & 2 deletions src/bin/polling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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();

Expand Down
45 changes: 24 additions & 21 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Target = i2c1::RegisterBlock> {

}

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: I2cTrait>(I);

/// Errors that can happen while accessing the I2C bus.
#[derive(Debug)]
Expand Down Expand Up @@ -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<I>,
device_address: Address,
register_type: PhantomData<T>,
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -213,15 +221,15 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> {
}
}

impl<'a> I2C<'a> {
impl<I: I2cTrait> I2C<I> {
/// 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
/// bus. The connection is active until the closure `f` returns.
pub fn connect<T, F>(&mut self, device_address: Address, f: F) -> Result<(), Error>
where
T: RegisterType,
F: FnOnce(I2cConnection<T>) -> Result<(), Error>,
F: FnOnce(I2cConnection<I, T>) -> Result<(), Error>,
{
{
let conn = I2cConnection {
Expand Down Expand Up @@ -384,29 +392,29 @@ impl<'a> I2C<'a> {
}
}

impl<'a> embedded_hal::blocking::i2c::Read for I2C<'a> {
impl<I: I2cTrait> embedded_hal::blocking::i2c::Read for I2C<I> {
type Error = Error;

fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.connect(
Address::bits_7(address),
|mut connection: I2cConnection<u8>| connection.read_bytes_raw(buffer.iter_mut()),
|mut connection: I2cConnection<I, u8>| connection.read_bytes_raw(buffer.iter_mut()),
)
}
}

impl<'a> embedded_hal::blocking::i2c::Write for I2C<'a> {
impl<I: I2cTrait> embedded_hal::blocking::i2c::Write for I2C<I> {
type Error = Error;

fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.connect(
Address::bits_7(address),
|mut connection: I2cConnection<u8>| connection.write_bytes(bytes.iter().map(|b| *b)),
|mut connection: I2cConnection<I, u8>| connection.write_bytes(bytes.iter().map(|b| *b)),
)
}
}

impl<'a> embedded_hal::blocking::i2c::WriteRead for I2C<'a> {
impl<I: I2cTrait> embedded_hal::blocking::i2c::WriteRead for I2C<I> {
type Error = Error;

fn write_read(
Expand All @@ -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<u8>| {
|mut connection: I2cConnection<I, u8>| {
connection.write_bytes(bytes.iter().map(|b| *b))?;
connection.read_bytes_raw(buffer.iter_mut())
},
Expand All @@ -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<I: I2cTrait>(i2c: I, rcc: &mut RCC) -> I2C<I> {
// enable clocks
rcc.apb1enr.modify(|_, w| w.i2c3en().enabled());

Expand Down
8 changes: 4 additions & 4 deletions src/init/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<device::I2C3> {
i2c::init(i2c, rcc)
}

Expand Down Expand Up @@ -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<device::I2C3>) -> Result<(), i2c::Error> {
i2c_3.connect::<u16, _>(WM8994_ADDRESS, |mut conn| {
// read and check device family ID
assert_eq!(conn.read(0).ok(), Some(0x8994));
Expand Down
5 changes: 3 additions & 2 deletions src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<device::I2C3>) -> Result<(), i2c::Error> {
i2c_3.connect::<u8, _>(FT5336_ADDRESS, |mut conn| {
// read and check device family ID
assert_eq!(conn.read(FT5336_FAMILY_ID_REGISTER).ok(), Some(0x51));
Expand All @@ -27,7 +28,7 @@ pub struct Touch {
}

/// Returns a list of active touch points.
pub fn touches(i2c_3: &mut I2C) -> Result<ArrayVec<[Touch; 5]>, i2c::Error> {
pub fn touches(i2c_3: &mut I2C<device::I2C3>) -> Result<ArrayVec<[Touch; 5]>, i2c::Error> {
let mut touches = ArrayVec::new();
i2c_3.connect::<u8, _>(FT5336_ADDRESS, |mut conn| {
let status = conn.read(FT5336_STATUS_REGISTER)?;
Expand Down

0 comments on commit 09a7513

Please sign in to comment.