2023-01-31 23:48:33 +00:00
//! Serial Peripheral Instance in master mode (SPIM) driver.
2021-05-11 01:04:59 +00:00
#![ macro_use ]
2022-09-22 14:42:49 +00:00
use core ::future ::poll_fn ;
2023-03-05 21:00:52 +00:00
use core ::marker ::PhantomData ;
2021-01-18 13:22:55 +00:00
use core ::sync ::atomic ::{ compiler_fence , Ordering } ;
use core ::task ::Poll ;
2022-06-12 20:15:44 +00:00
2022-07-08 13:47:47 +00:00
use embassy_embedded_hal ::SetConfig ;
2023-07-28 11:23:22 +00:00
use embassy_hal_internal ::{ into_ref , PeripheralRef } ;
2022-06-12 20:15:44 +00:00
pub use embedded_hal_02 ::spi ::{ Mode , Phase , Polarity , MODE_0 , MODE_1 , MODE_2 , MODE_3 } ;
2024-01-27 04:38:03 +00:00
pub use pac ::spim0 ::config ::ORDER_A as BitOrder ;
2022-06-12 20:15:44 +00:00
pub use pac ::spim0 ::frequency ::FREQUENCY_A as Frequency ;
2021-01-18 13:22:55 +00:00
2024-02-08 19:43:05 +00:00
use crate ::chip ::{ EASY_DMA_SIZE , FORCE_COPY_BUFFER_SIZE } ;
2021-03-27 02:20:58 +00:00
use crate ::gpio ::sealed ::Pin as _ ;
2024-02-20 01:46:25 +00:00
use crate ::gpio ::{ self , convert_drive , AnyPin , OutputDrive , Pin as GpioPin , PselBits } ;
2023-06-08 14:08:40 +00:00
use crate ::interrupt ::typelevel ::Interrupt ;
2024-02-15 10:34:51 +00:00
use crate ::util ::{ slice_in_ram_or , slice_ptr_len , slice_ptr_parts , slice_ptr_parts_mut } ;
2023-06-08 14:08:40 +00:00
use crate ::{ interrupt , pac , Peripheral } ;
2021-01-18 13:22:55 +00:00
2023-01-31 23:48:33 +00:00
/// SPIM error
2021-01-18 13:22:55 +00:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
#[ cfg_attr(feature = " defmt " , derive(defmt::Format)) ]
#[ non_exhaustive ]
pub enum Error {
/// EasyDMA can only read from data memory, read only buffers in flash will fail.
2023-01-31 23:48:33 +00:00
BufferNotInRAM ,
2021-01-18 13:22:55 +00:00
}
2023-01-31 23:48:33 +00:00
/// SPIM configuration.
2021-05-11 01:04:59 +00:00
#[ non_exhaustive ]
2021-01-18 13:22:55 +00:00
pub struct Config {
2023-01-31 23:48:33 +00:00
/// Frequency
2021-01-18 13:22:55 +00:00
pub frequency : Frequency ,
2023-01-31 23:48:33 +00:00
/// SPI mode
2021-01-18 13:22:55 +00:00
pub mode : Mode ,
2023-01-31 23:48:33 +00:00
2024-01-27 04:38:03 +00:00
/// Bit order
pub bit_order : BitOrder ,
2023-01-31 23:48:33 +00:00
/// Overread character.
///
/// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer,
/// this byte will be transmitted in the MOSI line for the left-over bytes.
2021-01-18 13:22:55 +00:00
pub orc : u8 ,
2024-02-16 06:33:23 +00:00
2024-02-20 01:46:25 +00:00
/// Drive strength for the SCK line.
pub sck_drive : OutputDrive ,
2024-02-16 06:33:23 +00:00
2024-02-20 01:46:25 +00:00
/// Drive strength for the MOSI line.
pub mosi_drive : OutputDrive ,
2024-02-16 06:33:23 +00:00
2024-02-20 01:46:25 +00:00
/// Drive strength for the MISO line.
pub miso_drive : OutputDrive ,
2021-01-18 13:22:55 +00:00
}
2021-05-11 01:04:59 +00:00
impl Default for Config {
fn default ( ) -> Self {
Self {
frequency : Frequency ::M1 ,
mode : MODE_0 ,
2024-01-27 04:38:03 +00:00
bit_order : BitOrder ::MSB_FIRST ,
2021-05-11 01:04:59 +00:00
orc : 0x00 ,
2024-02-20 01:46:25 +00:00
sck_drive : OutputDrive ::HighDrive ,
mosi_drive : OutputDrive ::HighDrive ,
miso_drive : OutputDrive ::HighDrive ,
2021-05-11 01:04:59 +00:00
}
}
}
2023-03-05 21:00:52 +00:00
/// Interrupt handler.
pub struct InterruptHandler < T : Instance > {
_phantom : PhantomData < T > ,
}
2023-06-08 14:08:40 +00:00
impl < T : Instance > interrupt ::typelevel ::Handler < T ::Interrupt > for InterruptHandler < T > {
2023-03-05 21:00:52 +00:00
unsafe fn on_interrupt ( ) {
let r = T ::regs ( ) ;
let s = T ::state ( ) ;
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2024-02-15 10:34:51 +00:00
{
// Ideally we should call this only during the first chunk transfer,
// but so far calling this every time doesn't seem to be causing any issues.
if r . events_started . read ( ) . bits ( ) ! = 0 {
s . waker . wake ( ) ;
r . intenclr . write ( | w | w . started ( ) . clear ( ) ) ;
}
2023-09-06 20:15:33 +00:00
}
2023-03-05 21:00:52 +00:00
if r . events_end . read ( ) . bits ( ) ! = 0 {
2023-09-22 13:12:57 +00:00
s . waker . wake ( ) ;
2023-03-05 21:00:52 +00:00
r . intenclr . write ( | w | w . end ( ) . clear ( ) ) ;
}
}
}
/// SPIM driver.
pub struct Spim < ' d , T : Instance > {
_p : PeripheralRef < ' d , T > ,
}
2021-03-19 03:08:44 +00:00
impl < ' d , T : Instance > Spim < ' d , T > {
2023-01-31 23:48:33 +00:00
/// Create a new SPIM driver.
2021-03-19 03:08:44 +00:00
pub fn new (
2022-07-23 12:00:19 +00:00
spim : impl Peripheral < P = T > + ' d ,
2023-06-08 14:08:40 +00:00
_irq : impl interrupt ::typelevel ::Binding < T ::Interrupt , InterruptHandler < T > > + ' d ,
2022-07-23 12:00:19 +00:00
sck : impl Peripheral < P = impl GpioPin > + ' d ,
miso : impl Peripheral < P = impl GpioPin > + ' d ,
mosi : impl Peripheral < P = impl GpioPin > + ' d ,
2022-02-12 00:04:01 +00:00
config : Config ,
) -> Self {
2022-07-23 12:27:45 +00:00
into_ref! ( sck , miso , mosi ) ;
Self ::new_inner (
spim ,
2024-01-03 13:55:09 +00:00
Some ( sck . map_into ( ) ) ,
2022-07-23 12:27:45 +00:00
Some ( miso . map_into ( ) ) ,
Some ( mosi . map_into ( ) ) ,
config ,
)
2022-02-12 00:04:01 +00:00
}
2023-01-31 23:48:33 +00:00
/// Create a new SPIM driver, capable of TX only (MOSI only).
2022-02-12 00:04:01 +00:00
pub fn new_txonly (
2022-07-23 12:00:19 +00:00
spim : impl Peripheral < P = T > + ' d ,
2023-06-08 14:08:40 +00:00
_irq : impl interrupt ::typelevel ::Binding < T ::Interrupt , InterruptHandler < T > > + ' d ,
2022-07-23 12:00:19 +00:00
sck : impl Peripheral < P = impl GpioPin > + ' d ,
mosi : impl Peripheral < P = impl GpioPin > + ' d ,
2022-02-12 00:04:01 +00:00
config : Config ,
) -> Self {
2022-07-23 12:27:45 +00:00
into_ref! ( sck , mosi ) ;
2024-01-03 13:55:09 +00:00
Self ::new_inner ( spim , Some ( sck . map_into ( ) ) , None , Some ( mosi . map_into ( ) ) , config )
2022-02-12 00:04:01 +00:00
}
2023-01-31 23:48:33 +00:00
/// Create a new SPIM driver, capable of RX only (MISO only).
2022-02-12 00:04:01 +00:00
pub fn new_rxonly (
2022-07-23 12:00:19 +00:00
spim : impl Peripheral < P = T > + ' d ,
2023-06-08 14:08:40 +00:00
_irq : impl interrupt ::typelevel ::Binding < T ::Interrupt , InterruptHandler < T > > + ' d ,
2022-07-23 12:00:19 +00:00
sck : impl Peripheral < P = impl GpioPin > + ' d ,
miso : impl Peripheral < P = impl GpioPin > + ' d ,
2022-02-12 00:04:01 +00:00
config : Config ,
) -> Self {
2022-07-23 12:27:45 +00:00
into_ref! ( sck , miso ) ;
2024-01-03 13:55:09 +00:00
Self ::new_inner ( spim , Some ( sck . map_into ( ) ) , Some ( miso . map_into ( ) ) , None , config )
}
/// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin.
pub fn new_txonly_nosck (
spim : impl Peripheral < P = T > + ' d ,
_irq : impl interrupt ::typelevel ::Binding < T ::Interrupt , InterruptHandler < T > > + ' d ,
mosi : impl Peripheral < P = impl GpioPin > + ' d ,
config : Config ,
) -> Self {
into_ref! ( mosi ) ;
Self ::new_inner ( spim , None , None , Some ( mosi . map_into ( ) ) , config )
2022-02-12 00:04:01 +00:00
}
fn new_inner (
2022-07-23 13:13:47 +00:00
spim : impl Peripheral < P = T > + ' d ,
2024-01-03 13:55:09 +00:00
sck : Option < PeripheralRef < ' d , AnyPin > > ,
2022-07-23 12:00:19 +00:00
miso : Option < PeripheralRef < ' d , AnyPin > > ,
mosi : Option < PeripheralRef < ' d , AnyPin > > ,
2021-03-19 03:08:44 +00:00
config : Config ,
) -> Self {
2023-03-05 21:00:52 +00:00
into_ref! ( spim ) ;
2021-03-19 03:08:44 +00:00
2021-04-14 14:37:10 +00:00
let r = T ::regs ( ) ;
2021-01-18 13:22:55 +00:00
2021-03-19 03:08:44 +00:00
// Configure pins
2024-01-03 13:55:09 +00:00
if let Some ( sck ) = & sck {
2024-02-20 01:46:25 +00:00
sck . conf ( )
. write ( | w | w . dir ( ) . output ( ) . drive ( ) . variant ( convert_drive ( config . sck_drive ) ) ) ;
2024-01-03 13:55:09 +00:00
}
2022-02-12 00:04:01 +00:00
if let Some ( mosi ) = & mosi {
2024-02-20 01:46:25 +00:00
mosi . conf ( )
. write ( | w | w . dir ( ) . output ( ) . drive ( ) . variant ( convert_drive ( config . mosi_drive ) ) ) ;
2021-03-27 02:20:58 +00:00
}
2022-02-12 00:04:01 +00:00
if let Some ( miso ) = & miso {
2024-02-20 01:46:25 +00:00
miso . conf ( )
. write ( | w | w . input ( ) . connect ( ) . drive ( ) . variant ( convert_drive ( config . miso_drive ) ) ) ;
2021-03-27 02:20:58 +00:00
}
2021-03-19 03:08:44 +00:00
match config . mode . polarity {
Polarity ::IdleHigh = > {
2024-01-03 14:05:30 +00:00
if let Some ( sck ) = & sck {
sck . set_high ( ) ;
}
2022-02-12 00:04:01 +00:00
if let Some ( mosi ) = & mosi {
2021-03-27 02:20:58 +00:00
mosi . set_high ( ) ;
}
2021-03-19 03:08:44 +00:00
}
Polarity ::IdleLow = > {
2024-01-03 14:05:30 +00:00
if let Some ( sck ) = & sck {
sck . set_low ( ) ;
}
2022-02-12 00:04:01 +00:00
if let Some ( mosi ) = & mosi {
2021-03-27 02:20:58 +00:00
mosi . set_low ( ) ;
}
2021-03-19 03:08:44 +00:00
}
}
2021-01-18 13:22:55 +00:00
// Select pins.
2021-03-21 19:52:20 +00:00
r . psel . sck . write ( | w | unsafe { w . bits ( sck . psel_bits ( ) ) } ) ;
r . psel . mosi . write ( | w | unsafe { w . bits ( mosi . psel_bits ( ) ) } ) ;
r . psel . miso . write ( | w | unsafe { w . bits ( miso . psel_bits ( ) ) } ) ;
2021-01-18 13:22:55 +00:00
// Enable SPIM instance.
r . enable . write ( | w | w . enable ( ) . enabled ( ) ) ;
2023-09-06 13:44:02 +00:00
let mut spim = Self { _p : spim } ;
2021-01-18 13:22:55 +00:00
2023-09-06 13:44:02 +00:00
// Apply runtime peripheral configuration
2023-10-01 14:37:42 +00:00
Self ::set_config ( & mut spim , & config ) . unwrap ( ) ;
2021-01-18 13:22:55 +00:00
// Disable all events interrupts
r . intenclr . write ( | w | unsafe { w . bits ( 0xFFFF_FFFF ) } ) ;
2023-06-01 00:22:46 +00:00
T ::Interrupt ::unpend ( ) ;
unsafe { T ::Interrupt ::enable ( ) } ;
2021-04-14 14:37:10 +00:00
2023-09-06 13:44:02 +00:00
spim
2021-01-18 13:22:55 +00:00
}
2021-04-14 14:37:10 +00:00
2024-02-15 10:34:51 +00:00
fn prepare_dma_transfer ( & mut self , rx : * mut [ u8 ] , tx : * const [ u8 ] , offset : usize , length : usize ) {
2022-01-13 18:27:10 +00:00
compiler_fence ( Ordering ::SeqCst ) ;
let r = T ::regs ( ) ;
2024-02-15 10:34:51 +00:00
fn xfer_params ( ptr : u32 , total : usize , offset : usize , length : usize ) -> ( u32 , usize ) {
if total > offset {
( ptr . wrapping_add ( offset as _ ) , core ::cmp ::min ( total - offset , length ) )
} else {
( ptr , 0 )
}
2024-02-08 19:43:05 +00:00
}
2022-01-13 18:27:10 +00:00
// Set up the DMA read.
2024-02-15 10:34:51 +00:00
let ( ptr , len ) = slice_ptr_parts_mut ( rx ) ;
let ( rx_ptr , rx_len ) = xfer_params ( ptr as _ , len as _ , offset , length ) ;
r . rxd . ptr . write ( | w | unsafe { w . ptr ( ) . bits ( rx_ptr ) } ) ;
2023-09-06 20:15:33 +00:00
r . rxd . maxcnt . write ( | w | unsafe { w . maxcnt ( ) . bits ( rx_len as _ ) } ) ;
2024-02-15 10:34:51 +00:00
// Set up the DMA write.
let ( ptr , len ) = slice_ptr_parts ( tx ) ;
let ( tx_ptr , tx_len ) = xfer_params ( ptr as _ , len as _ , offset , length ) ;
r . txd . ptr . write ( | w | unsafe { w . ptr ( ) . bits ( tx_ptr ) } ) ;
r . txd . maxcnt . write ( | w | unsafe { w . maxcnt ( ) . bits ( tx_len as _ ) } ) ;
/*
trace! ( " XFER: offset: {}, length: {} " , offset , length ) ;
trace! ( " RX(len: {}, ptr: {=u32:02x}) " , rx_len , rx_ptr as u32 ) ;
trace! ( " TX(len: {}, ptr: {=u32:02x}) " , tx_len , tx_ptr as u32 ) ;
* /
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2024-02-15 10:34:51 +00:00
if offset = = 0 {
2023-09-06 20:15:33 +00:00
let s = T ::state ( ) ;
r . events_started . reset ( ) ;
// Set rx/tx buffer lengths to 0...
r . txd . maxcnt . reset ( ) ;
r . rxd . maxcnt . reset ( ) ;
// ...and keep track of original buffer lengths...
s . tx . store ( tx_len as _ , Ordering ::Relaxed ) ;
s . rx . store ( rx_len as _ , Ordering ::Relaxed ) ;
// ...signalling the start of the fake transfer.
r . intenset . write ( | w | w . started ( ) . bit ( true ) ) ;
}
2022-01-13 18:27:10 +00:00
// 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 ) } ) ;
}
2024-02-15 10:34:51 +00:00
fn blocking_inner_from_ram_chunk ( & mut self , rx : * mut [ u8 ] , tx : * const [ u8 ] , offset : usize , length : usize ) {
self . prepare_dma_transfer ( rx , tx , offset , length ) ;
2022-01-13 18:27:10 +00:00
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2024-02-15 10:34:51 +00:00
if offset = = 0 {
while self . nrf52832_dma_workaround_status ( ) . is_pending ( ) { }
}
2023-09-22 13:12:57 +00:00
2022-01-13 18:27:10 +00:00
// Wait for 'end' event.
while T ::regs ( ) . events_end . read ( ) . bits ( ) = = 0 { }
compiler_fence ( Ordering ::SeqCst ) ;
2024-02-15 10:34:51 +00:00
}
2022-01-13 18:27:10 +00:00
2024-02-15 10:34:51 +00:00
fn blocking_inner_from_ram ( & mut self , rx : * mut [ u8 ] , tx : * const [ u8 ] ) -> Result < ( ) , Error > {
slice_in_ram_or ( tx , Error ::BufferNotInRAM ) ? ;
// NOTE: RAM slice check for rx is not necessary, as a mutable
// slice can only be built from data located in RAM.
let xfer_len = core ::cmp ::max ( slice_ptr_len ( rx ) , slice_ptr_len ( tx ) ) ;
for offset in ( 0 .. xfer_len ) . step_by ( EASY_DMA_SIZE ) {
let length = core ::cmp ::min ( xfer_len - offset , EASY_DMA_SIZE ) ;
self . blocking_inner_from_ram_chunk ( rx , tx , offset , length ) ;
}
2022-01-13 18:27:10 +00:00
Ok ( ( ) )
}
2022-02-23 21:51:59 +00:00
fn blocking_inner ( & mut self , rx : & mut [ u8 ] , tx : & [ u8 ] ) -> Result < ( ) , Error > {
match self . blocking_inner_from_ram ( rx , tx ) {
Ok ( _ ) = > Ok ( ( ) ) ,
2023-01-31 23:48:33 +00:00
Err ( Error ::BufferNotInRAM ) = > {
2022-02-23 22:27:12 +00:00
trace! ( " Copying SPIM tx buffer into RAM for DMA " ) ;
2022-03-02 21:48:58 +00:00
let tx_ram_buf = & mut [ 0 ; FORCE_COPY_BUFFER_SIZE ] [ .. tx . len ( ) ] ;
tx_ram_buf . copy_from_slice ( tx ) ;
self . blocking_inner_from_ram ( rx , tx_ram_buf )
2022-02-23 21:51:59 +00:00
}
}
}
2024-02-15 10:34:51 +00:00
async fn async_inner_from_ram_chunk ( & mut self , rx : * mut [ u8 ] , tx : * const [ u8 ] , offset : usize , length : usize ) {
self . prepare_dma_transfer ( rx , tx , offset , length ) ;
2022-01-13 18:27:10 +00:00
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2024-02-15 10:34:51 +00:00
if offset = = 0 {
poll_fn ( | cx | {
let s = T ::state ( ) ;
2023-09-22 13:12:57 +00:00
2024-02-15 10:34:51 +00:00
s . waker . register ( cx . waker ( ) ) ;
2023-09-22 13:12:57 +00:00
2024-02-15 10:34:51 +00:00
self . nrf52832_dma_workaround_status ( )
} )
. await ;
}
2023-09-22 13:12:57 +00:00
2022-01-13 18:27:10 +00:00
// Wait for 'end' event.
poll_fn ( | cx | {
2023-09-22 13:12:57 +00:00
T ::state ( ) . waker . register ( cx . waker ( ) ) ;
2022-01-13 18:27:10 +00:00
if T ::regs ( ) . events_end . read ( ) . bits ( ) ! = 0 {
return Poll ::Ready ( ( ) ) ;
}
Poll ::Pending
} )
. await ;
compiler_fence ( Ordering ::SeqCst ) ;
2024-02-15 10:34:51 +00:00
}
async fn async_inner_from_ram ( & mut self , rx : * mut [ u8 ] , tx : * const [ u8 ] ) -> Result < ( ) , Error > {
slice_in_ram_or ( tx , Error ::BufferNotInRAM ) ? ;
// NOTE: RAM slice check for rx is not necessary, as a mutable
// slice can only be built from data located in RAM.
2022-01-13 18:27:10 +00:00
2024-02-15 10:34:51 +00:00
let xfer_len = core ::cmp ::max ( slice_ptr_len ( rx ) , slice_ptr_len ( tx ) ) ;
for offset in ( 0 .. xfer_len ) . step_by ( EASY_DMA_SIZE ) {
let length = core ::cmp ::min ( xfer_len - offset , EASY_DMA_SIZE ) ;
self . async_inner_from_ram_chunk ( rx , tx , offset , length ) . await ;
}
2022-01-13 18:27:10 +00:00
Ok ( ( ) )
}
2022-01-13 19:00:33 +00:00
2022-02-23 21:51:59 +00:00
async fn async_inner ( & mut self , rx : & mut [ u8 ] , tx : & [ u8 ] ) -> Result < ( ) , Error > {
match self . async_inner_from_ram ( rx , tx ) . await {
Ok ( _ ) = > Ok ( ( ) ) ,
2023-01-31 23:48:33 +00:00
Err ( Error ::BufferNotInRAM ) = > {
2022-02-23 22:27:12 +00:00
trace! ( " Copying SPIM tx buffer into RAM for DMA " ) ;
2022-03-02 21:48:58 +00:00
let tx_ram_buf = & mut [ 0 ; FORCE_COPY_BUFFER_SIZE ] [ .. tx . len ( ) ] ;
tx_ram_buf . copy_from_slice ( tx ) ;
self . async_inner_from_ram ( rx , tx_ram_buf ) . await
2022-02-23 21:51:59 +00:00
}
}
}
/// Reads data from the SPI bus without sending anything. Blocks until the buffer has been filled.
2022-01-13 19:00:33 +00:00
pub fn blocking_read ( & mut self , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
self . blocking_inner ( data , & [ ] )
}
2022-02-23 21:51:59 +00:00
/// Simultaneously sends and receives data. Blocks until the transmission is completed.
/// If necessary, the write buffer will be copied into RAM (see struct description for detail).
2022-01-13 19:00:33 +00:00
pub fn blocking_transfer ( & mut self , read : & mut [ u8 ] , write : & [ u8 ] ) -> Result < ( ) , Error > {
self . blocking_inner ( read , write )
}
2022-03-08 15:42:46 +00:00
/// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
2022-06-12 20:15:44 +00:00
pub fn blocking_transfer_from_ram ( & mut self , read : & mut [ u8 ] , write : & [ u8 ] ) -> Result < ( ) , Error > {
2022-02-23 21:51:59 +00:00
self . blocking_inner ( read , write )
}
/// Simultaneously sends and receives data.
/// Places the received data into the same buffer and blocks until the transmission is completed.
2022-01-13 19:00:33 +00:00
pub fn blocking_transfer_in_place ( & mut self , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
2022-02-23 21:51:59 +00:00
self . blocking_inner_from_ram ( data , data )
2022-01-13 19:00:33 +00:00
}
2022-02-23 21:51:59 +00:00
/// Sends data, discarding any received data. Blocks until the transmission is completed.
/// If necessary, the write buffer will be copied into RAM (see struct description for detail).
2022-01-13 19:00:33 +00:00
pub fn blocking_write ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
self . blocking_inner ( & mut [ ] , data )
}
2022-03-08 15:42:46 +00:00
/// Same as [`blocking_write`](Spim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
2022-02-23 21:51:59 +00:00
pub fn blocking_write_from_ram ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
self . blocking_inner ( & mut [ ] , data )
}
/// Reads data from the SPI bus without sending anything.
2022-01-13 19:00:33 +00:00
pub async fn read ( & mut self , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
self . async_inner ( data , & [ ] ) . await
}
2022-02-23 21:51:59 +00:00
/// Simultaneously sends and receives data.
/// If necessary, the write buffer will be copied into RAM (see struct description for detail).
2022-01-13 19:00:33 +00:00
pub async fn transfer ( & mut self , read : & mut [ u8 ] , write : & [ u8 ] ) -> Result < ( ) , Error > {
self . async_inner ( read , write ) . await
}
2022-03-08 15:42:46 +00:00
/// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
2022-02-23 21:51:59 +00:00
pub async fn transfer_from_ram ( & mut self , read : & mut [ u8 ] , write : & [ u8 ] ) -> Result < ( ) , Error > {
self . async_inner_from_ram ( read , write ) . await
}
/// Simultaneously sends and receives data. Places the received data into the same buffer.
2022-01-13 19:00:33 +00:00
pub async fn transfer_in_place ( & mut self , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
2022-02-23 21:51:59 +00:00
self . async_inner_from_ram ( data , data ) . await
2022-01-13 19:00:33 +00:00
}
2022-02-23 21:51:59 +00:00
/// Sends data, discarding any received data.
/// If necessary, the write buffer will be copied into RAM (see struct description for detail).
2022-01-13 19:00:33 +00:00
pub async fn write ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
self . async_inner ( & mut [ ] , data ) . await
}
2022-02-23 21:51:59 +00:00
2022-03-08 15:42:46 +00:00
/// Same as [`write`](Spim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
2022-02-23 21:51:59 +00:00
pub async fn write_from_ram ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
self . async_inner_from_ram ( & mut [ ] , data ) . await
}
2023-09-22 13:12:57 +00:00
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-22 13:12:57 +00:00
fn nrf52832_dma_workaround_status ( & mut self ) -> Poll < ( ) > {
let r = T ::regs ( ) ;
if r . events_started . read ( ) . bits ( ) ! = 0 {
let s = T ::state ( ) ;
// Handle the first "fake" transmission
r . events_started . reset ( ) ;
r . events_end . reset ( ) ;
// Update DMA registers with correct rx/tx buffer sizes
r . rxd
. maxcnt
. write ( | w | unsafe { w . maxcnt ( ) . bits ( s . rx . load ( Ordering ::Relaxed ) ) } ) ;
r . txd
. maxcnt
. write ( | w | unsafe { w . maxcnt ( ) . bits ( s . tx . load ( Ordering ::Relaxed ) ) } ) ;
r . intenset . write ( | w | w . end ( ) . set ( ) ) ;
// ... and start actual, hopefully glitch-free transmission
r . tasks_start . write ( | w | unsafe { w . bits ( 1 ) } ) ;
return Poll ::Ready ( ( ) ) ;
}
Poll ::Pending
}
2021-03-18 00:27:30 +00:00
}
2021-05-26 16:22:44 +00:00
impl < ' d , T : Instance > Drop for Spim < ' d , T > {
fn drop ( & mut self ) {
2021-12-23 12:43:14 +00:00
trace! ( " spim drop " ) ;
2021-05-26 16:22:44 +00:00
// TODO check for abort, wait for xxxstopped
// disable!
let r = T ::regs ( ) ;
r . enable . write ( | w | w . enable ( ) . disabled ( ) ) ;
gpio ::deconfigure_pin ( r . psel . sck . read ( ) . bits ( ) ) ;
gpio ::deconfigure_pin ( r . psel . miso . read ( ) . bits ( ) ) ;
gpio ::deconfigure_pin ( r . psel . mosi . read ( ) . bits ( ) ) ;
2023-08-10 20:18:26 +00:00
// Disable all events interrupts
T ::Interrupt ::disable ( ) ;
2021-12-23 12:43:14 +00:00
trace! ( " spim drop: done " ) ;
2021-05-26 16:22:44 +00:00
}
}
2021-05-11 01:04:59 +00:00
pub ( crate ) mod sealed {
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-06 20:15:33 +00:00
use core ::sync ::atomic ::AtomicU8 ;
2022-08-22 19:46:09 +00:00
use embassy_sync ::waitqueue ::AtomicWaker ;
2021-09-10 23:53:53 +00:00
2021-03-18 19:56:10 +00:00
use super ::* ;
2021-04-14 14:37:10 +00:00
pub struct State {
2023-09-22 13:12:57 +00:00
pub waker : AtomicWaker ,
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-06 20:15:33 +00:00
pub rx : AtomicU8 ,
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-06 20:15:33 +00:00
pub tx : AtomicU8 ,
2021-04-14 14:37:10 +00:00
}
impl State {
pub const fn new ( ) -> Self {
Self {
2023-09-22 13:12:57 +00:00
waker : AtomicWaker ::new ( ) ,
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-06 20:15:33 +00:00
rx : AtomicU8 ::new ( 0 ) ,
2023-09-22 14:30:09 +00:00
#[ cfg(feature = " _nrf52832_anomaly_109 " ) ]
2023-09-06 20:15:33 +00:00
tx : AtomicU8 ::new ( 0 ) ,
2021-04-14 14:37:10 +00:00
}
}
}
2021-03-18 19:56:10 +00:00
pub trait Instance {
2021-04-14 14:37:10 +00:00
fn regs ( ) -> & 'static pac ::spim0 ::RegisterBlock ;
fn state ( ) -> & 'static State ;
2021-03-18 19:56:10 +00:00
}
2021-01-18 13:22:55 +00:00
}
2023-01-31 23:48:33 +00:00
/// SPIM peripheral instance
2022-07-23 12:00:19 +00:00
pub trait Instance : Peripheral < P = Self > + sealed ::Instance + 'static {
2023-01-31 23:48:33 +00:00
/// Interrupt for this peripheral.
2023-06-08 14:08:40 +00:00
type Interrupt : interrupt ::typelevel ::Interrupt ;
2021-01-18 13:22:55 +00:00
}
2021-05-11 01:04:59 +00:00
macro_rules ! impl_spim {
( $type :ident , $pac_type :ident , $irq :ident ) = > {
impl crate ::spim ::sealed ::Instance for peripherals ::$type {
2021-04-14 14:37:10 +00:00
fn regs ( ) -> & 'static pac ::spim0 ::RegisterBlock {
2021-05-11 01:04:59 +00:00
unsafe { & * pac ::$pac_type ::ptr ( ) }
2021-03-18 19:56:10 +00:00
}
2021-05-11 01:04:59 +00:00
fn state ( ) -> & 'static crate ::spim ::sealed ::State {
static STATE : crate ::spim ::sealed ::State = crate ::spim ::sealed ::State ::new ( ) ;
2021-04-14 14:37:10 +00:00
& STATE
}
2021-03-18 19:56:10 +00:00
}
2021-05-11 01:04:59 +00:00
impl crate ::spim ::Instance for peripherals ::$type {
2023-06-08 14:08:40 +00:00
type Interrupt = crate ::interrupt ::typelevel ::$irq ;
2021-03-18 19:56:10 +00:00
}
} ;
2021-01-18 13:22:55 +00:00
}
2022-01-13 22:56:25 +00:00
// ====================
mod eh02 {
use super ::* ;
impl < ' d , T : Instance > embedded_hal_02 ::blocking ::spi ::Transfer < u8 > for Spim < ' d , T > {
type Error = Error ;
fn transfer < ' w > ( & mut self , words : & ' w mut [ u8 ] ) -> Result < & ' w [ u8 ] , Self ::Error > {
self . blocking_transfer_in_place ( words ) ? ;
Ok ( words )
}
}
impl < ' d , T : Instance > embedded_hal_02 ::blocking ::spi ::Write < u8 > for Spim < ' d , T > {
type Error = Error ;
fn write ( & mut self , words : & [ u8 ] ) -> Result < ( ) , Self ::Error > {
self . blocking_write ( words )
}
}
}
2023-11-29 16:23:48 +00:00
impl embedded_hal_1 ::spi ::Error for Error {
fn kind ( & self ) -> embedded_hal_1 ::spi ::ErrorKind {
match * self {
Self ::BufferNotInRAM = > embedded_hal_1 ::spi ::ErrorKind ::Other ,
2022-01-13 22:56:25 +00:00
}
}
2023-11-29 16:23:48 +00:00
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
impl < ' d , T : Instance > embedded_hal_1 ::spi ::ErrorType for Spim < ' d , T > {
type Error = Error ;
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
impl < ' d , T : Instance > embedded_hal_1 ::spi ::SpiBus < u8 > for Spim < ' d , T > {
fn flush ( & mut self ) -> Result < ( ) , Self ::Error > {
Ok ( ( ) )
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
fn read ( & mut self , words : & mut [ u8 ] ) -> Result < ( ) , Self ::Error > {
self . blocking_transfer ( words , & [ ] )
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
fn write ( & mut self , words : & [ u8 ] ) -> Result < ( ) , Self ::Error > {
self . blocking_write ( words )
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
fn transfer ( & mut self , read : & mut [ u8 ] , write : & [ u8 ] ) -> Result < ( ) , Self ::Error > {
self . blocking_transfer ( read , write )
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
fn transfer_in_place ( & mut self , words : & mut [ u8 ] ) -> Result < ( ) , Self ::Error > {
self . blocking_transfer_in_place ( words )
2022-01-13 22:56:25 +00:00
}
2022-02-11 23:24:04 +00:00
}
2023-11-29 16:23:48 +00:00
impl < ' d , T : Instance > embedded_hal_async ::spi ::SpiBus < u8 > for Spim < ' d , T > {
async fn flush ( & mut self ) -> Result < ( ) , Error > {
Ok ( ( ) )
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
async fn read ( & mut self , words : & mut [ u8 ] ) -> Result < ( ) , Error > {
self . read ( words ) . await
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
async fn write ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
self . write ( data ) . await
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
async fn transfer ( & mut self , rx : & mut [ u8 ] , tx : & [ u8 ] ) -> Result < ( ) , Error > {
self . transfer ( rx , tx ) . await
}
2022-01-13 22:56:25 +00:00
2023-11-29 16:23:48 +00:00
async fn transfer_in_place ( & mut self , words : & mut [ u8 ] ) -> Result < ( ) , Error > {
self . transfer_in_place ( words ) . await
2022-01-13 22:56:25 +00:00
}
}
2022-07-08 13:47:47 +00:00
2022-07-08 22:00:55 +00:00
impl < ' d , T : Instance > SetConfig for Spim < ' d , T > {
type Config = Config ;
2023-10-01 14:37:42 +00:00
type ConfigError = ( ) ;
fn set_config ( & mut self , config : & Self ::Config ) -> Result < ( ) , Self ::ConfigError > {
2022-07-08 13:47:47 +00:00
let r = T ::regs ( ) ;
// Configure mode.
let mode = config . mode ;
r . config . write ( | w | {
match mode {
MODE_0 = > {
2024-01-27 04:38:03 +00:00
w . order ( ) . variant ( config . bit_order ) ;
2022-07-08 13:47:47 +00:00
w . cpol ( ) . active_high ( ) ;
w . cpha ( ) . leading ( ) ;
}
MODE_1 = > {
2024-01-27 04:38:03 +00:00
w . order ( ) . variant ( config . bit_order ) ;
2022-07-08 13:47:47 +00:00
w . cpol ( ) . active_high ( ) ;
w . cpha ( ) . trailing ( ) ;
}
MODE_2 = > {
2024-01-27 04:38:03 +00:00
w . order ( ) . variant ( config . bit_order ) ;
2022-07-08 13:47:47 +00:00
w . cpol ( ) . active_low ( ) ;
w . cpha ( ) . leading ( ) ;
}
MODE_3 = > {
2024-01-27 04:38:03 +00:00
w . order ( ) . variant ( config . bit_order ) ;
2022-07-08 13:47:47 +00:00
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 | unsafe { w . orc ( ) . bits ( orc ) } ) ;
2023-10-01 14:37:42 +00:00
Ok ( ( ) )
2022-07-08 13:47:47 +00:00
}
}