nrf: add owned Peripherals struct, migrate gpio and spim
This commit is contained in:
parent
d9aaa0edf8
commit
fcf6a63b5c
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
mod example_common;
|
mod example_common;
|
||||||
|
use embassy_nrf::gpio::{Level, Output};
|
||||||
|
use embassy_nrf::peripherals::Peripherals;
|
||||||
use embassy_traits::spi::FullDuplex;
|
use embassy_traits::spi::FullDuplex;
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
@ -16,7 +18,6 @@ use embassy::util::Forever;
|
|||||||
use embedded_hal::digital::v2::*;
|
use embedded_hal::digital::v2::*;
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
use nrf52840_hal::clocks;
|
use nrf52840_hal::clocks;
|
||||||
use nrf52840_hal::gpio;
|
|
||||||
|
|
||||||
use embassy_nrf::{interrupt, pac, rtc, spim};
|
use embassy_nrf::{interrupt, pac, rtc, spim};
|
||||||
|
|
||||||
@ -24,25 +25,20 @@ use embassy_nrf::{interrupt, pac, rtc, spim};
|
|||||||
async fn run() {
|
async fn run() {
|
||||||
info!("running!");
|
info!("running!");
|
||||||
|
|
||||||
let p = unsafe { embassy_nrf::pac::Peripherals::steal() };
|
let mut p = unsafe { Peripherals::steal() };
|
||||||
let p0 = gpio::p0::Parts::new(p.P0);
|
|
||||||
|
|
||||||
let pins = spim::Pins {
|
|
||||||
sck: p0.p0_29.into_push_pull_output(gpio::Level::Low).degrade(),
|
|
||||||
miso: Some(p0.p0_28.into_floating_input().degrade()),
|
|
||||||
mosi: Some(p0.p0_30.into_push_pull_output(gpio::Level::Low).degrade()),
|
|
||||||
};
|
|
||||||
let config = spim::Config {
|
let config = spim::Config {
|
||||||
pins,
|
|
||||||
frequency: spim::Frequency::M16,
|
frequency: spim::Frequency::M16,
|
||||||
mode: spim::MODE_0,
|
mode: spim::MODE_0,
|
||||||
orc: 0x00,
|
orc: 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ncs = p0.p0_31.into_push_pull_output(gpio::Level::High);
|
let mut irq = interrupt::take!(SPIM3);
|
||||||
let spim = spim::Spim::new(p.SPIM3, interrupt::take!(SPIM3), config);
|
let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config);
|
||||||
pin_mut!(spim);
|
pin_mut!(spim);
|
||||||
|
|
||||||
|
let mut ncs = Output::new(p.p0_31, Level::High);
|
||||||
|
|
||||||
// Example on how to talk to an ENC28J60 chip
|
// Example on how to talk to an ENC28J60 chip
|
||||||
|
|
||||||
// softreset
|
// softreset
|
||||||
|
307
embassy-nrf/src/gpio.rs
Normal file
307
embassy-nrf/src/gpio.rs
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
use core::convert::Infallible;
|
||||||
|
use core::hint::unreachable_unchecked;
|
||||||
|
|
||||||
|
use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin};
|
||||||
|
|
||||||
|
use crate::pac;
|
||||||
|
use crate::pac::p0 as gpio;
|
||||||
|
use crate::peripherals;
|
||||||
|
|
||||||
|
/// Represents a digital input or output level.
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub enum Level {
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a pull setting for an input.
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub enum Pull {
|
||||||
|
None,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A GPIO port with up to 32 pins.
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub enum Port {
|
||||||
|
/// Port 0, available on all nRF52 and nRF51 MCUs.
|
||||||
|
Port0,
|
||||||
|
|
||||||
|
/// Port 1, only available on some nRF52 MCUs.
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
Port1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Input<T: Pin> {
|
||||||
|
pin: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> Input<T> {
|
||||||
|
pub fn new(pin: T, pull: Pull) -> Self {
|
||||||
|
pin.conf().write(|w| {
|
||||||
|
w.dir().input();
|
||||||
|
w.input().connect();
|
||||||
|
match pull {
|
||||||
|
Pull::None => {
|
||||||
|
w.pull().disabled();
|
||||||
|
}
|
||||||
|
Pull::Up => {
|
||||||
|
w.pull().pullup();
|
||||||
|
}
|
||||||
|
Pull::Down => {
|
||||||
|
w.pull().pulldown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.drive().s0s1();
|
||||||
|
w.sense().disabled();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { pin }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> Drop for Input<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.pin.conf().reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> InputPin for Input<T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.is_low().map(|v| !v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Output<T: Pin> {
|
||||||
|
pin: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> Output<T> {
|
||||||
|
// TODO opendrain
|
||||||
|
pub fn new(pin: T, initial_output: Level) -> Self {
|
||||||
|
pin.conf().write(|w| {
|
||||||
|
w.dir().output();
|
||||||
|
w.input().disconnect();
|
||||||
|
w.pull().disabled();
|
||||||
|
w.drive().s0s1();
|
||||||
|
w.sense().disabled();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { pin }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> Drop for Output<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.pin.conf().reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> OutputPin for Output<T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
/// Set the output as high.
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
unsafe {
|
||||||
|
self.pin
|
||||||
|
.block()
|
||||||
|
.outset
|
||||||
|
.write(|w| w.bits(1u32 << self.pin.pin()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the output as low.
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
unsafe {
|
||||||
|
self.pin
|
||||||
|
.block()
|
||||||
|
.outclr
|
||||||
|
.write(|w| w.bits(1u32 << self.pin.pin()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pin> StatefulOutputPin for Output<T> {
|
||||||
|
/// Is the output pin set as high?
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.is_set_low().map(|v| !v)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the output pin set as low?
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod sealed {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait Pin {
|
||||||
|
fn pin_port(&self) -> u8;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn _pin(&self) -> u8 {
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
{
|
||||||
|
self.pin_port() % 32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "52833", feature = "52840")))]
|
||||||
|
{
|
||||||
|
self.pin_port()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block(&self) -> &gpio::RegisterBlock {
|
||||||
|
unsafe {
|
||||||
|
match self.pin_port() / 32 {
|
||||||
|
0 => &*pac::P0::ptr(),
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
1 => &*pac::P1::ptr(),
|
||||||
|
_ => unreachable_unchecked(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn conf(&self) -> &gpio::PIN_CNF {
|
||||||
|
&self.block().pin_cnf[self._pin() as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the output as high.
|
||||||
|
fn set_high(&self) {
|
||||||
|
unsafe {
|
||||||
|
self.block().outset.write(|w| w.bits(1u32 << self._pin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the output as low.
|
||||||
|
fn set_low(&self) {
|
||||||
|
unsafe {
|
||||||
|
self.block().outclr.write(|w| w.bits(1u32 << self._pin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Pin: sealed::Pin + Sized {
|
||||||
|
#[inline]
|
||||||
|
fn pin(&self) -> u8 {
|
||||||
|
self._pin()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn port(&self) -> Port {
|
||||||
|
match self.pin_port() / 32 {
|
||||||
|
1 => Port::Port0,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
1 => Port::Port1,
|
||||||
|
_ => unsafe { unreachable_unchecked() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn psel_bits(&self) -> u32 {
|
||||||
|
self.pin_port() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn degrade(self) -> AnyPin {
|
||||||
|
AnyPin {
|
||||||
|
pin_port: self.pin_port(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AnyPin {
|
||||||
|
pin_port: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyPin {
|
||||||
|
pub unsafe fn from_psel_bits(psel_bits: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
pin_port: psel_bits as u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pin for AnyPin {}
|
||||||
|
impl sealed::Pin for AnyPin {
|
||||||
|
fn pin_port(&self) -> u8 {
|
||||||
|
self.pin_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_impl {
|
||||||
|
($type:ident, $port_num:expr, $pin_num:expr) => {
|
||||||
|
impl Pin for peripherals::$type {}
|
||||||
|
impl sealed::Pin for peripherals::$type {
|
||||||
|
fn pin_port(&self) -> u8 {
|
||||||
|
$port_num * 32 + $pin_num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
make_impl!(P0_00, 0, 0);
|
||||||
|
make_impl!(P0_01, 0, 1);
|
||||||
|
make_impl!(P0_02, 0, 2);
|
||||||
|
make_impl!(P0_03, 0, 3);
|
||||||
|
make_impl!(P0_04, 0, 4);
|
||||||
|
make_impl!(P0_05, 0, 5);
|
||||||
|
make_impl!(P0_06, 0, 6);
|
||||||
|
make_impl!(P0_07, 0, 7);
|
||||||
|
make_impl!(P0_08, 0, 8);
|
||||||
|
make_impl!(P0_09, 0, 9);
|
||||||
|
make_impl!(P0_10, 0, 10);
|
||||||
|
make_impl!(P0_11, 0, 11);
|
||||||
|
make_impl!(P0_12, 0, 12);
|
||||||
|
make_impl!(P0_13, 0, 13);
|
||||||
|
make_impl!(P0_14, 0, 14);
|
||||||
|
make_impl!(P0_15, 0, 15);
|
||||||
|
make_impl!(P0_16, 0, 16);
|
||||||
|
make_impl!(P0_17, 0, 17);
|
||||||
|
make_impl!(P0_18, 0, 18);
|
||||||
|
make_impl!(P0_19, 0, 19);
|
||||||
|
make_impl!(P0_20, 0, 20);
|
||||||
|
make_impl!(P0_21, 0, 21);
|
||||||
|
make_impl!(P0_22, 0, 22);
|
||||||
|
make_impl!(P0_23, 0, 23);
|
||||||
|
make_impl!(P0_24, 0, 24);
|
||||||
|
make_impl!(P0_25, 0, 25);
|
||||||
|
make_impl!(P0_26, 0, 26);
|
||||||
|
make_impl!(P0_27, 0, 27);
|
||||||
|
make_impl!(P0_28, 0, 28);
|
||||||
|
make_impl!(P0_29, 0, 29);
|
||||||
|
make_impl!(P0_30, 0, 30);
|
||||||
|
make_impl!(P0_31, 0, 31);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
mod _p1 {
|
||||||
|
use super::*;
|
||||||
|
make_impl!(P1_00, 1, 0);
|
||||||
|
make_impl!(P1_01, 1, 1);
|
||||||
|
make_impl!(P1_02, 1, 2);
|
||||||
|
make_impl!(P1_03, 1, 3);
|
||||||
|
make_impl!(P1_04, 1, 4);
|
||||||
|
make_impl!(P1_05, 1, 5);
|
||||||
|
make_impl!(P1_06, 1, 6);
|
||||||
|
make_impl!(P1_07, 1, 7);
|
||||||
|
make_impl!(P1_08, 1, 8);
|
||||||
|
make_impl!(P1_09, 1, 9);
|
||||||
|
make_impl!(P1_10, 1, 10);
|
||||||
|
make_impl!(P1_11, 1, 11);
|
||||||
|
make_impl!(P1_12, 1, 12);
|
||||||
|
make_impl!(P1_13, 1, 13);
|
||||||
|
make_impl!(P1_14, 1, 14);
|
||||||
|
make_impl!(P1_15, 1, 15);
|
||||||
|
}
|
@ -94,8 +94,10 @@ pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> {
|
|||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
|
||||||
pub mod buffered_uarte;
|
pub mod buffered_uarte;
|
||||||
|
pub mod gpio;
|
||||||
pub mod gpiote;
|
pub mod gpiote;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
pub mod peripherals;
|
||||||
#[cfg(feature = "52840")]
|
#[cfg(feature = "52840")]
|
||||||
pub mod qspi;
|
pub mod qspi;
|
||||||
pub mod rtc;
|
pub mod rtc;
|
||||||
|
144
embassy-nrf/src/peripherals.rs
Normal file
144
embassy-nrf/src/peripherals.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use embassy::util::PeripheralBorrow;
|
||||||
|
|
||||||
|
macro_rules! peripherals {
|
||||||
|
($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => {
|
||||||
|
$(
|
||||||
|
$(#[$cfg])?
|
||||||
|
pub struct $type { _private: () }
|
||||||
|
|
||||||
|
$(#[$cfg])?
|
||||||
|
impl PeripheralBorrow for $type {
|
||||||
|
type Target = $type;
|
||||||
|
unsafe fn unborrow(self) -> $type {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(#[$cfg])?
|
||||||
|
impl PeripheralBorrow for &mut $type {
|
||||||
|
type Target = $type;
|
||||||
|
unsafe fn unborrow(self) -> $type {
|
||||||
|
::core::ptr::read(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
pub struct Peripherals {
|
||||||
|
$(
|
||||||
|
$(#[$cfg])?
|
||||||
|
pub $name: $type,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Peripherals {
|
||||||
|
pub unsafe fn steal() -> Self {
|
||||||
|
Self {
|
||||||
|
$(
|
||||||
|
$(#[$cfg])?
|
||||||
|
$name: $type { _private: () },
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
peripherals! {
|
||||||
|
// RTC
|
||||||
|
rtc0: RTC0,
|
||||||
|
rtc1: RTC1,
|
||||||
|
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
|
||||||
|
rtc2: RTC2,
|
||||||
|
|
||||||
|
// QSPI
|
||||||
|
#[cfg(feature = "52840")]
|
||||||
|
qspi: QSPI,
|
||||||
|
|
||||||
|
// UARTE
|
||||||
|
uarte0: UARTE0,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
|
||||||
|
uarte1: UARTE1,
|
||||||
|
|
||||||
|
// SPIM
|
||||||
|
// TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS.
|
||||||
|
// When they're all implemented, they should be only one peripheral here.
|
||||||
|
spim0: SPIM0,
|
||||||
|
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
|
||||||
|
spim1: SPIM1,
|
||||||
|
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
|
||||||
|
spim2: SPIM2,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
spim3: SPIM3,
|
||||||
|
|
||||||
|
// GPIOTE
|
||||||
|
gpiote: GPIOTE,
|
||||||
|
|
||||||
|
// GPIO port 0
|
||||||
|
p0_00: P0_00,
|
||||||
|
p0_01: P0_01,
|
||||||
|
p0_02: P0_02,
|
||||||
|
p0_03: P0_03,
|
||||||
|
p0_04: P0_04,
|
||||||
|
p0_05: P0_05,
|
||||||
|
p0_06: P0_06,
|
||||||
|
p0_07: P0_07,
|
||||||
|
p0_08: P0_08,
|
||||||
|
p0_09: P0_09,
|
||||||
|
p0_10: P0_10,
|
||||||
|
p0_11: P0_11,
|
||||||
|
p0_12: P0_12,
|
||||||
|
p0_13: P0_13,
|
||||||
|
p0_14: P0_14,
|
||||||
|
p0_15: P0_15,
|
||||||
|
p0_16: P0_16,
|
||||||
|
p0_17: P0_17,
|
||||||
|
p0_18: P0_18,
|
||||||
|
p0_19: P0_19,
|
||||||
|
p0_20: P0_20,
|
||||||
|
p0_21: P0_21,
|
||||||
|
p0_22: P0_22,
|
||||||
|
p0_23: P0_23,
|
||||||
|
p0_24: P0_24,
|
||||||
|
p0_25: P0_25,
|
||||||
|
p0_26: P0_26,
|
||||||
|
p0_27: P0_27,
|
||||||
|
p0_28: P0_28,
|
||||||
|
p0_29: P0_29,
|
||||||
|
p0_30: P0_30,
|
||||||
|
p0_31: P0_31,
|
||||||
|
|
||||||
|
// GPIO port 1
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_00: P1_00,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_01: P1_01,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_02: P1_02,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_03: P1_03,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_04: P1_04,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_05: P1_05,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_06: P1_06,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_07: P1_07,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_08: P1_08,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_09: P1_09,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_10: P1_10,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_11: P1_11,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_12: P1_12,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_13: P1_13,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_14: P1_14,
|
||||||
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
|
p1_15: P1_15,
|
||||||
|
}
|
@ -1,19 +1,20 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
use embassy::traits;
|
use embassy::traits;
|
||||||
use embassy::util::WakerRegistration;
|
use embassy::util::{PeripheralBorrow, WakerRegistration};
|
||||||
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
|
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use traits::spi::FullDuplex;
|
use traits::spi::FullDuplex;
|
||||||
|
|
||||||
|
use crate::gpio::Pin as GpioPin;
|
||||||
use crate::interrupt::{self, Interrupt};
|
use crate::interrupt::{self, Interrupt};
|
||||||
use crate::{pac, slice_in_ram_or};
|
use crate::{pac, peripherals, slice_in_ram_or};
|
||||||
|
|
||||||
pub use crate::hal::spim::{
|
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||||
Frequency, Mode, Phase, Pins, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
|
pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -30,41 +31,63 @@ struct State<T: Instance> {
|
|||||||
waker: WakerRegistration,
|
waker: WakerRegistration,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Spim<T: Instance> {
|
pub struct Spim<'d, T: Instance> {
|
||||||
inner: PeripheralMutex<State<T>>,
|
inner: PeripheralMutex<State<T>>,
|
||||||
|
phantom: PhantomData<&'d mut T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub pins: Pins,
|
|
||||||
pub frequency: Frequency,
|
pub frequency: Frequency,
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
pub orc: u8,
|
pub orc: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> Spim<T> {
|
impl<'d, T: Instance> Spim<'d, T> {
|
||||||
pub fn new(mut spim: T, irq: T::Interrupt, config: Config) -> Self {
|
pub fn new(
|
||||||
|
spim: impl PeripheralBorrow<Target = T> + 'd,
|
||||||
|
irq: impl PeripheralBorrow<Target = T::Interrupt> + 'd,
|
||||||
|
sck: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
|
||||||
|
miso: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
|
||||||
|
mosi: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
let mut spim = unsafe { spim.unborrow() };
|
||||||
|
let irq = unsafe { irq.unborrow() };
|
||||||
|
let sck = unsafe { sck.unborrow() };
|
||||||
|
let miso = unsafe { miso.unborrow() };
|
||||||
|
let mosi = unsafe { mosi.unborrow() };
|
||||||
|
|
||||||
let r = spim.regs();
|
let r = spim.regs();
|
||||||
|
|
||||||
|
// Configure pins
|
||||||
|
sck.conf().write(|w| w.dir().output());
|
||||||
|
mosi.conf().write(|w| w.dir().output());
|
||||||
|
miso.conf().write(|w| w.input().connect());
|
||||||
|
|
||||||
|
match config.mode.polarity {
|
||||||
|
Polarity::IdleHigh => {
|
||||||
|
sck.set_high();
|
||||||
|
mosi.set_high();
|
||||||
|
}
|
||||||
|
Polarity::IdleLow => {
|
||||||
|
sck.set_low();
|
||||||
|
mosi.set_low();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Select pins.
|
// Select pins.
|
||||||
r.psel.sck.write(|w| {
|
r.psel.sck.write(|w| {
|
||||||
unsafe { w.bits(config.pins.sck.psel_bits()) };
|
unsafe { w.bits(sck.psel_bits()) };
|
||||||
w.connect().connected()
|
w.connect().connected()
|
||||||
});
|
});
|
||||||
|
r.psel.mosi.write(|w| {
|
||||||
match config.pins.mosi {
|
|
||||||
Some(mosi) => r.psel.mosi.write(|w| {
|
|
||||||
unsafe { w.bits(mosi.psel_bits()) };
|
unsafe { w.bits(mosi.psel_bits()) };
|
||||||
w.connect().connected()
|
w.connect().connected()
|
||||||
}),
|
});
|
||||||
None => r.psel.mosi.write(|w| w.connect().disconnected()),
|
r.psel.miso.write(|w| {
|
||||||
}
|
|
||||||
match config.pins.miso {
|
|
||||||
Some(miso) => r.psel.miso.write(|w| {
|
|
||||||
unsafe { w.bits(miso.psel_bits()) };
|
unsafe { w.bits(miso.psel_bits()) };
|
||||||
w.connect().connected()
|
w.connect().connected()
|
||||||
}),
|
});
|
||||||
None => r.psel.miso.write(|w| w.connect().disconnected()),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable SPIM instance.
|
// Enable SPIM instance.
|
||||||
r.enable.write(|w| w.enable().enabled());
|
r.enable.write(|w| w.enable().enabled());
|
||||||
@ -114,6 +137,7 @@ impl<T: Instance> Spim<T> {
|
|||||||
},
|
},
|
||||||
irq,
|
irq,
|
||||||
),
|
),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +146,7 @@ impl<T: Instance> Spim<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> FullDuplex<u8> for Spim<T> {
|
impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
@ -222,19 +246,19 @@ mod sealed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: sealed::Instance {
|
pub trait Instance: sealed::Instance + 'static {
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! make_impl {
|
macro_rules! make_impl {
|
||||||
($SPIMx:ident, $IRQ:ident) => {
|
($type:ident, $irq:ident) => {
|
||||||
impl sealed::Instance for pac::$SPIMx {
|
impl sealed::Instance for peripherals::$type {
|
||||||
fn regs(&mut self) -> &pac::spim0::RegisterBlock {
|
fn regs(&mut self) -> &pac::spim0::RegisterBlock {
|
||||||
self
|
unsafe { &*pac::$type::ptr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Instance for pac::$SPIMx {
|
impl Instance for peripherals::$type {
|
||||||
type Interrupt = interrupt::$IRQ;
|
type Interrupt = interrupt::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user