Skip to content

Commit

Permalink
Try implementing async I2C (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbeaurivage committed Oct 26, 2023
1 parent d2fb295 commit cec7f64
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 41 deletions.
1 change: 1 addition & 0 deletions boards/feather_m0/.cargo/config
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ rustflags = [
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x"
]

[target.thumbv6m-none-eabi]
Expand Down
8 changes: 8 additions & 0 deletions boards/feather_m0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ git = "https://github.com/datdenkikniet/cortex-m-interrupt.git"

[dev-dependencies]
cortex-m-rtic = "1.1.3"
fugit = "0.3.6"
cortex-m = "0.7"
usbd-serial = "0.1"
cortex-m-semihosting = "0.3"
Expand All @@ -53,6 +54,9 @@ nom = { version = "5", default-features = false }
heapless = "0.7"
panic-halt = "0.2"
panic-semihosting = "0.5"
defmt = "0.3"
defmt-rtt = "0.3"
panic-probe = "0.3"

[features]
# ask the HAL to enable atsamd21g support
Expand Down Expand Up @@ -154,5 +158,9 @@ required-features = ["dma"]
name = "async_timer"
required-features = ["atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"]

[[example]]
name = "async_i2c"
required-features = ["atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"]

[patch.crates-io]
cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic.git", branch = "async-2022" }
95 changes: 95 additions & 0 deletions boards/feather_m0/examples/async_i2c.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

use panic_probe as _;
use defmt_rtt as _;

#[rtic::app(device = bsp::pac, dispatchers = [I2S])]
mod app {
use bsp::{hal, pac, pin_alias};
use feather_m0 as bsp;
use hal::{
prelude::*,
clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController},
ehal::digital::v2::ToggleableOutputPin,
rtc::{Count32Mode, Rtc},
sercom::i2c::{self,Config, I2cFuture},
};
use fugit::MillisDuration;

#[monotonic(binds = RTC, default = true)]
type Monotonic = Rtc<Count32Mode>;

#[shared]
struct Shared {}

#[local]
struct Local {
i2c: I2cFuture<Config<bsp::I2cPads>, bsp::pac::Interrupt>,
red_led: bsp::RedLed,
}

#[init]
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
let mut peripherals = cx.device;
let _core = cx.core;

let mut clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.PM,
&mut peripherals.SYSCTRL,
&mut peripherals.NVMCTRL,
);
let pins = bsp::Pins::new(peripherals.PORT);
let red_led: bsp::RedLed = pin_alias!(pins.red_led).into();

// Take SDA and SCL
let (sda, scl) = (pins.sda, pins.scl);

let sercom3_irq = cortex_m_interrupt::take_nvic_interrupt!(pac::Interrupt::SERCOM3, 2);
// tc4_irq.set_priority(2);

enable_internal_32kosc(&mut peripherals.SYSCTRL);
let timer_clock = clocks
.configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false)
.unwrap();
clocks.configure_standby(ClockGenId::GCLK2, true);

// Setup RTC monotonic
let rtc_clock = clocks.rtc(&timer_clock).unwrap();
let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM);

let gclk0 = clocks.gclk0();
let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap();
let pads = i2c::Pads::new(sda, scl);
let i2c = i2c::Config::new(&peripherals.PM, peripherals.SERCOM3, pads, sercom3_clock.freq())
.baud(100.khz())
.enable().into_async(sercom3_irq);


async_task::spawn().ok();

(Shared {}, Local { i2c, red_led }, init::Monotonics(rtc))
}

#[task(local = [i2c, red_led])]
async fn async_task(cx: async_task::Context) {
let i2c = cx.local.i2c;
let red_led = cx.local.red_led;

loop {
defmt::info!("Sending 1 byte to I2C...");
// This test is based on the BMP388 barometer. Feel free to use any I2C peripheral
// you have on hand.
i2c.write(0x76, &[0x00]).await.unwrap();

let mut buffer = [0x00; 1];
defmt::info!("Reading 1 byte from I2C...");
i2c.read(0x76, &mut buffer).await.unwrap();
defmt::info!("Chip ID is: {:#x}", buffer[0]);
red_led.toggle().unwrap();
crate::app::monotonics::delay(MillisDuration::<u32>::from_ticks(500).convert()).await;
}
}
}
2 changes: 1 addition & 1 deletion boards/feather_m0/examples/async_timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ mod app {
// configure a clock for the TC4 and TC5 peripherals
let tc45 = &clocks.tc4_tc5(&timer_clock).unwrap();

// instantiate a timer objec for the TC3 peripheral
// instantiate a timer object for the TC4 peripheral
let timer = TimerCounter::tc4_(tc45, peripherals.TC4, &mut peripherals.PM);
let timer = timer.into_async(tc4_irq);
async_task::spawn().ok();
Expand Down
10 changes: 1 addition & 9 deletions hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ atsame54n = {version = "0.13.0", path = "../pac/atsame54n", optional = true}
atsame54p = {version = "0.13.0", path = "../pac/atsame54p", optional = true}

[dependencies.embedded-hal-async]
version = "0.1.0-alph"
package = "embedded-hal"
version = "0.1.0-alpha.2"
optional = true

[dependencies.critical-section]
Expand All @@ -105,12 +104,6 @@ optional = true
version = "0.1"
optional = true
git = "https://github.com/embassy-rs/embassy.git"
# path = "../../../rust-projects/embassy/embassy-sync"

[dependencies.futures]
version = "0.3.21"
optional = true
default-features = false

[dependencies.cortex-m-interrupt]
version = "0.1"
Expand Down Expand Up @@ -214,7 +207,6 @@ usb = ["usb-device"]
use_rtt = ["jlink_rtt"]
async = [
"cortex-m-interrupt",
"futures",
"critical-section",
"unproven",
"embassy-sync",
Expand Down
32 changes: 16 additions & 16 deletions hal/src/async_hal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
//! Async APIs
#[cfg(feature = "samd11")]
#[path = "irqs_samd11.rs"]
mod irqs;
// #[cfg(feature = "samd11")]
// #[path = "irqs_samd11.rs"]
// mod irqs;

#[cfg(feature = "samd21")]
#[path = "irqs_samd21.rs"]
mod irqs;
// #[cfg(feature = "samd21")]
// #[path = "irqs_samd21.rs"]
// mod irqs;

#[cfg(feature = "samd51")]
#[path = "irqs_thumbv7em.rs"]
mod irqs;
// #[cfg(feature = "samd51")]
// #[path = "irqs_thumbv7em.rs"]
// mod irqs;

pub mod interrupt {
pub use super::irqs::*;
pub use cortex_m::interrupt::{CriticalSection, Mutex};
pub use embassy::interrupt::{declare, take, Interrupt};
// pub mod interrupt {
// pub use super::irqs::*;
// pub use cortex_m::interrupt::{CriticalSection, Mutex};
// pub use embassy::interrupt::{declare, take, Interrupt};

// TODO Priority2 seems to only be true for thumbv6m chips
pub use embassy_hal_common::interrupt::Priority2 as Priority;
}
// // TODO Priority2 seems to only be true for thumbv6m chips
// pub use embassy_hal_common::interrupt::Priority2 as Priority;
// }

pub mod timer;
2 changes: 1 addition & 1 deletion hal/src/async_hal/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ where
#[inline]
pub fn into_async<I, N>(mut self, irq: I) -> AsyncTimer<T, N>
where
I: NvicInterruptHandle<InterruptNumber = N>,
I: NvicInterruptHandle<N>,
N: InterruptNumber,
{
let irq_number = irq.number();
Expand Down
6 changes: 6 additions & 0 deletions hal/src/sercom/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ pub use config::*;

mod impl_ehal;

#[cfg(feature = "async")]
mod async_api;

#[cfg(feature = "async")]
pub use async_api::*;

/// Word size for an I2C message
pub type Word = u8;

Expand Down
Loading

0 comments on commit cec7f64

Please sign in to comment.