commit
						282f00e705
					
				
							
								
								
									
										116
									
								
								embassy-nrf-examples/src/bin/spim.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								embassy-nrf-examples/src/bin/spim.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  | 
 | ||||||
|  | #[path = "../example_common.rs"] | ||||||
|  | mod example_common; | ||||||
|  | use example_common::*; | ||||||
|  | 
 | ||||||
|  | use cortex_m_rt::entry; | ||||||
|  | use defmt::panic; | ||||||
|  | use embassy::executor::{task, Executor}; | ||||||
|  | use embassy::util::Forever; | ||||||
|  | use embedded_hal::digital::v2::*; | ||||||
|  | use futures::pin_mut; | ||||||
|  | use nrf52840_hal::clocks; | ||||||
|  | use nrf52840_hal::gpio; | ||||||
|  | 
 | ||||||
|  | use embassy_nrf::{interrupt, pac, rtc, spim}; | ||||||
|  | 
 | ||||||
|  | #[task] | ||||||
|  | async fn run() { | ||||||
|  |     info!("running!"); | ||||||
|  | 
 | ||||||
|  |     let p = unsafe { embassy_nrf::pac::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 { | ||||||
|  |         pins, | ||||||
|  |         frequency: spim::Frequency::M16, | ||||||
|  |         mode: spim::MODE_0, | ||||||
|  |         orc: 0x00, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let mut ncs = p0.p0_31.into_push_pull_output(gpio::Level::High); | ||||||
|  |     let spim = spim::Spim::new(p.SPIM3, interrupt::take!(SPIM3), config); | ||||||
|  |     pin_mut!(spim); | ||||||
|  | 
 | ||||||
|  |     // Example on how to talk to an ENC28J60 chip
 | ||||||
|  | 
 | ||||||
|  |     // softreset
 | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_low().unwrap(); | ||||||
|  |     cortex_m::asm::delay(5); | ||||||
|  |     let tx = [0xFF]; | ||||||
|  |     unwrap!(spim.as_mut().send_receive(&tx, &mut []).await); | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_high().unwrap(); | ||||||
|  | 
 | ||||||
|  |     cortex_m::asm::delay(100000); | ||||||
|  | 
 | ||||||
|  |     let mut rx = [0; 2]; | ||||||
|  | 
 | ||||||
|  |     // read ESTAT
 | ||||||
|  |     cortex_m::asm::delay(5000); | ||||||
|  |     ncs.set_low().unwrap(); | ||||||
|  |     cortex_m::asm::delay(5000); | ||||||
|  |     let tx = [0b000_11101, 0]; | ||||||
|  |     unwrap!(spim.as_mut().send_receive(&tx, &mut rx).await); | ||||||
|  |     cortex_m::asm::delay(5000); | ||||||
|  |     ncs.set_high().unwrap(); | ||||||
|  |     info!("estat: {=[?]}", rx); | ||||||
|  | 
 | ||||||
|  |     // Switch to bank 3
 | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_low().unwrap(); | ||||||
|  |     cortex_m::asm::delay(5); | ||||||
|  |     let tx = [0b100_11111, 0b11]; | ||||||
|  |     unwrap!(spim.as_mut().send_receive(&tx, &mut rx).await); | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_high().unwrap(); | ||||||
|  | 
 | ||||||
|  |     // read EREVID
 | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_low().unwrap(); | ||||||
|  |     cortex_m::asm::delay(5); | ||||||
|  |     let tx = [0b000_10010, 0]; | ||||||
|  |     unwrap!(spim.as_mut().send_receive(&tx, &mut rx).await); | ||||||
|  |     cortex_m::asm::delay(10); | ||||||
|  |     ncs.set_high().unwrap(); | ||||||
|  | 
 | ||||||
|  |     info!("erevid: {=[?]}", rx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); | ||||||
|  | static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); | ||||||
|  | static EXECUTOR: Forever<Executor> = Forever::new(); | ||||||
|  | 
 | ||||||
|  | #[entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | ||||||
|  | 
 | ||||||
|  |     clocks::Clocks::new(p.CLOCK) | ||||||
|  |         .enable_ext_hfosc() | ||||||
|  |         .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) | ||||||
|  |         .start_lfclk(); | ||||||
|  | 
 | ||||||
|  |     let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); | ||||||
|  |     rtc.start(); | ||||||
|  | 
 | ||||||
|  |     unsafe { embassy::time::set_clock(rtc) }; | ||||||
|  | 
 | ||||||
|  |     let alarm = ALARM.put(rtc.alarm0()); | ||||||
|  |     let executor = EXECUTOR.put(Executor::new()); | ||||||
|  |     executor.set_alarm(alarm); | ||||||
|  | 
 | ||||||
|  |     executor.run(|spawner| { | ||||||
|  |         unwrap!(spawner.spawn(run())); | ||||||
|  |     }); | ||||||
|  | } | ||||||
| @ -49,6 +49,45 @@ pub use nrf52833_hal as hal; | |||||||
| #[cfg(feature = "52840")] | #[cfg(feature = "52840")] | ||||||
| pub use nrf52840_hal as hal; | pub use nrf52840_hal as hal; | ||||||
| 
 | 
 | ||||||
|  | /// Length of Nordic EasyDMA differs for MCUs
 | ||||||
|  | #[cfg(any(
 | ||||||
|  |     feature = "52810", | ||||||
|  |     feature = "52811", | ||||||
|  |     feature = "52832", | ||||||
|  |     feature = "51" | ||||||
|  | ))] | ||||||
|  | pub mod target_constants { | ||||||
|  |     // NRF52832 8 bits1..0xFF
 | ||||||
|  |     pub const EASY_DMA_SIZE: usize = 255; | ||||||
|  |     // Easy DMA can only read from data ram
 | ||||||
|  |     pub const SRAM_LOWER: usize = 0x2000_0000; | ||||||
|  |     pub const SRAM_UPPER: usize = 0x3000_0000; | ||||||
|  | } | ||||||
|  | #[cfg(any(feature = "52840", feature = "52833", feature = "9160"))] | ||||||
|  | pub mod target_constants { | ||||||
|  |     // NRF52840 and NRF9160 16 bits 1..0xFFFF
 | ||||||
|  |     pub const EASY_DMA_SIZE: usize = 65535; | ||||||
|  |     // Limits for Easy DMA - it can only read from data ram
 | ||||||
|  |     pub const SRAM_LOWER: usize = 0x2000_0000; | ||||||
|  |     pub const SRAM_UPPER: usize = 0x3000_0000; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Does this slice reside entirely within RAM?
 | ||||||
|  | pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { | ||||||
|  |     let ptr = slice.as_ptr() as usize; | ||||||
|  |     ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Return an error if slice is not in RAM.
 | ||||||
|  | #[cfg(not(feature = "51"))] | ||||||
|  | pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> { | ||||||
|  |     if slice.len() == 0 || slice_in_ram(slice) { | ||||||
|  |         Ok(()) | ||||||
|  |     } else { | ||||||
|  |         Err(err) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // This mod MUST go first, so that the others see its macros.
 | // This mod MUST go first, so that the others see its macros.
 | ||||||
| pub(crate) mod fmt; | pub(crate) mod fmt; | ||||||
| pub(crate) mod util; | pub(crate) mod util; | ||||||
| @ -59,4 +98,5 @@ pub mod interrupt; | |||||||
| #[cfg(feature = "52840")] | #[cfg(feature = "52840")] | ||||||
| pub mod qspi; | pub mod qspi; | ||||||
| pub mod rtc; | pub mod rtc; | ||||||
|  | pub mod spim; | ||||||
| pub mod uarte; | pub mod uarte; | ||||||
|  | |||||||
							
								
								
									
										272
									
								
								embassy-nrf/src/spim.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								embassy-nrf/src/spim.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,272 @@ | |||||||
|  | use core::future::Future; | ||||||
|  | use core::pin::Pin; | ||||||
|  | use core::sync::atomic::{compiler_fence, Ordering}; | ||||||
|  | use core::task::Poll; | ||||||
|  | use embassy::util::WakerRegistration; | ||||||
|  | use futures::future::poll_fn; | ||||||
|  | 
 | ||||||
|  | use crate::hal::gpio::Port as GpioPort; | ||||||
|  | use crate::interrupt::{self, Interrupt}; | ||||||
|  | use crate::util::peripheral::{PeripheralMutex, PeripheralState}; | ||||||
|  | use crate::{pac, slice_in_ram_or}; | ||||||
|  | 
 | ||||||
|  | pub use crate::hal::spim::{ | ||||||
|  |     Frequency, Mode, Phase, Pins, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||||
|  | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
|  | #[non_exhaustive] | ||||||
|  | pub enum Error { | ||||||
|  |     TxBufferTooLong, | ||||||
|  |     RxBufferTooLong, | ||||||
|  |     /// EasyDMA can only read from data memory, read only buffers in flash will fail.
 | ||||||
|  |     DMABufferNotInDataMemory, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct State<T: Instance> { | ||||||
|  |     spim: T, | ||||||
|  |     waker: WakerRegistration, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Spim<T: Instance> { | ||||||
|  |     inner: PeripheralMutex<State<T>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  | fn port_bit(port: GpioPort) -> bool { | ||||||
|  |     match port { | ||||||
|  |         GpioPort::Port0 => false, | ||||||
|  |         GpioPort::Port1 => true, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Config { | ||||||
|  |     pub pins: Pins, | ||||||
|  |     pub frequency: Frequency, | ||||||
|  |     pub mode: Mode, | ||||||
|  |     pub orc: u8, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Instance> Spim<T> { | ||||||
|  |     pub fn new(mut spim: T, irq: T::Interrupt, config: Config) -> Self { | ||||||
|  |         let r = spim.regs(); | ||||||
|  | 
 | ||||||
|  |         // Select pins.
 | ||||||
|  |         r.psel.sck.write(|w| { | ||||||
|  |             let w = unsafe { w.pin().bits(config.pins.sck.pin()) }; | ||||||
|  |             #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  |             let w = w.port().bit(port_bit(config.pins.sck.port())); | ||||||
|  |             w.connect().connected() | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         match config.pins.mosi { | ||||||
|  |             Some(mosi) => r.psel.mosi.write(|w| { | ||||||
|  |                 let w = unsafe { w.pin().bits(mosi.pin()) }; | ||||||
|  |                 #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  |                 let w = w.port().bit(port_bit(mosi.port())); | ||||||
|  |                 w.connect().connected() | ||||||
|  |             }), | ||||||
|  |             None => r.psel.mosi.write(|w| w.connect().disconnected()), | ||||||
|  |         } | ||||||
|  |         match config.pins.miso { | ||||||
|  |             Some(miso) => r.psel.miso.write(|w| { | ||||||
|  |                 let w = unsafe { w.pin().bits(miso.pin()) }; | ||||||
|  |                 #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  |                 let w = w.port().bit(port_bit(miso.port())); | ||||||
|  |                 w.connect().connected() | ||||||
|  |             }), | ||||||
|  |             None => r.psel.miso.write(|w| w.connect().disconnected()), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Enable SPIM instance.
 | ||||||
|  |         r.enable.write(|w| w.enable().enabled()); | ||||||
|  | 
 | ||||||
|  |         // Configure mode.
 | ||||||
|  |         let mode = config.mode; | ||||||
|  |         r.config.write(|w| { | ||||||
|  |             // Can't match on `mode` due to embedded-hal, see https://github.com/rust-embedded/embedded-hal/pull/126
 | ||||||
|  |             if mode == MODE_0 { | ||||||
|  |                 w.order().msb_first(); | ||||||
|  |                 w.cpol().active_high(); | ||||||
|  |                 w.cpha().leading(); | ||||||
|  |             } else if mode == MODE_1 { | ||||||
|  |                 w.order().msb_first(); | ||||||
|  |                 w.cpol().active_high(); | ||||||
|  |                 w.cpha().trailing(); | ||||||
|  |             } else if mode == MODE_2 { | ||||||
|  |                 w.order().msb_first(); | ||||||
|  |                 w.cpol().active_low(); | ||||||
|  |                 w.cpha().leading(); | ||||||
|  |             } else { | ||||||
|  |                 w.order().msb_first(); | ||||||
|  |                 w.cpol().active_low(); | ||||||
|  |                 w.cpha().trailing(); | ||||||
|  |             } | ||||||
|  |             w | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // Configure frequency.
 | ||||||
|  |         let frequency = config.frequency; | ||||||
|  |         r.frequency.write(|w| w.frequency().variant(frequency)); | ||||||
|  | 
 | ||||||
|  |         // Set over-read character
 | ||||||
|  |         let orc = config.orc; | ||||||
|  |         r.orc.write(|w| | ||||||
|  |             // The ORC field is 8 bits long, so any u8 is a valid value to write.
 | ||||||
|  |             unsafe { w.orc().bits(orc) }); | ||||||
|  | 
 | ||||||
|  |         // Disable all events interrupts
 | ||||||
|  |         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||||
|  | 
 | ||||||
|  |         Self { | ||||||
|  |             inner: PeripheralMutex::new( | ||||||
|  |                 State { | ||||||
|  |                     spim, | ||||||
|  |                     waker: WakerRegistration::new(), | ||||||
|  |                 }, | ||||||
|  |                 irq, | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<T>>> { | ||||||
|  |         unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn free(self: Pin<&mut Self>) -> (T, T::Interrupt) { | ||||||
|  |         let (state, irq) = self.inner().free(); | ||||||
|  |         (state.spim, irq) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn send_receive<'a>( | ||||||
|  |         mut self: Pin<&'a mut Self>, | ||||||
|  |         tx: &'a [u8], | ||||||
|  |         rx: &'a mut [u8], | ||||||
|  |     ) -> impl Future<Output = Result<(), Error>> + 'a { | ||||||
|  |         async move { | ||||||
|  |             slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; | ||||||
|  |             slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; | ||||||
|  | 
 | ||||||
|  |             self.as_mut().inner().with(|s, _irq| { | ||||||
|  |                 // Conservative compiler fence to prevent optimizations that do not
 | ||||||
|  |                 // take in to account actions by DMA. The fence has been placed here,
 | ||||||
|  |                 // before any DMA action has started.
 | ||||||
|  |                 compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |                 let r = s.spim.regs(); | ||||||
|  | 
 | ||||||
|  |                 // Set up the DMA write.
 | ||||||
|  |                 r.txd | ||||||
|  |                     .ptr | ||||||
|  |                     .write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) }); | ||||||
|  |                 r.txd | ||||||
|  |                     .maxcnt | ||||||
|  |                     .write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); | ||||||
|  | 
 | ||||||
|  |                 // Set up the DMA read.
 | ||||||
|  |                 r.rxd | ||||||
|  |                     .ptr | ||||||
|  |                     .write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) }); | ||||||
|  |                 r.rxd | ||||||
|  |                     .maxcnt | ||||||
|  |                     .write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); | ||||||
|  | 
 | ||||||
|  |                 // Reset and enable the event
 | ||||||
|  |                 r.events_end.reset(); | ||||||
|  |                 r.intenset.write(|w| w.end().set()); | ||||||
|  | 
 | ||||||
|  |                 // Start SPI transaction.
 | ||||||
|  |                 r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||||
|  | 
 | ||||||
|  |                 // Conservative compiler fence to prevent optimizations that do not
 | ||||||
|  |                 // take in to account actions by DMA. The fence has been placed here,
 | ||||||
|  |                 // after all possible DMA actions have completed.
 | ||||||
|  |                 compiler_fence(Ordering::SeqCst); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             // Wait for 'end' event.
 | ||||||
|  |             poll_fn(|cx| { | ||||||
|  |                 self.as_mut().inner().with(|s, _irq| { | ||||||
|  |                     let r = s.spim.regs(); | ||||||
|  |                     if r.events_end.read().bits() != 0 { | ||||||
|  |                         return Poll::Ready(()); | ||||||
|  |                     } | ||||||
|  |                     s.waker.register(cx.waker()); | ||||||
|  |                     Poll::Pending | ||||||
|  |                 }) | ||||||
|  |             }) | ||||||
|  |             .await; | ||||||
|  | 
 | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<U: Instance> PeripheralState for State<U> { | ||||||
|  |     type Interrupt = U::Interrupt; | ||||||
|  |     fn on_interrupt(&mut self) { | ||||||
|  |         if self.spim.regs().events_end.read().bits() != 0 { | ||||||
|  |             self.spim.regs().intenclr.write(|w| w.end().clear()); | ||||||
|  |             self.waker.wake() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | mod sealed { | ||||||
|  |     pub trait Instance {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait Instance: sealed::Instance { | ||||||
|  |     type Interrupt: Interrupt; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl sealed::Instance for pac::SPIM0 {} | ||||||
|  | impl Instance for pac::SPIM0 { | ||||||
|  |     #[cfg(feature = "52810")] | ||||||
|  |     type Interrupt = interrupt::SPIM0_SPIS0_SPI0; | ||||||
|  |     #[cfg(not(feature = "52810"))] | ||||||
|  |     type Interrupt = interrupt::SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock { | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||||
|  | impl sealed::Instance for pac::SPIM1 {} | ||||||
|  | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||||
|  | impl Instance for pac::SPIM1 { | ||||||
|  |     type Interrupt = interrupt::SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock { | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||||
|  | impl sealed::Instance for pac::SPIM2 {} | ||||||
|  | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||||
|  | impl Instance for pac::SPIM2 { | ||||||
|  |     type Interrupt = interrupt::SPIM2_SPIS2_SPI2; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock { | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  | impl sealed::Instance for pac::SPIM3 {} | ||||||
|  | #[cfg(any(feature = "52833", feature = "52840"))] | ||||||
|  | impl Instance for pac::SPIM3 { | ||||||
|  |     type Interrupt = interrupt::SPIM3; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock { | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: sealed::Instance> sealed::Instance for &mut T {} | ||||||
|  | impl<T: Instance> Instance for &mut T { | ||||||
|  |     type Interrupt = T::Interrupt; | ||||||
|  |     fn regs(&mut self) -> &pac::spim0::RegisterBlock { | ||||||
|  |         T::regs(*self) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user