aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Alsér <[email protected]>2022-11-05 00:15:43 +0100
committerHenrik Alsér <[email protected]>2022-11-05 00:15:43 +0100
commit1920e90dcdbebc1e2f86001f1491a9f28eb0f0f3 (patch)
tree5cb6408c92df3b3bf09d4271e800caef85620579
parentb99533607ceed225dd12ae73aaa9a0d969a7365e (diff)
embassy-nrf: Add SPIS module
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs2
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs2
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs4
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs1
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs5
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/spis.rs516
-rw-r--r--examples/nrf/src/bin/spis.rs25
13 files changed, 575 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index dec31a84c..11a6840c8 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -131,6 +131,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
131 131
132impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); 132impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
133 133
134impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0);
135
134impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 136impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
135 137
136impl_timer!(TIMER0, TIMER0, TIMER0); 138impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index e57a4a383..3614cd229 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -137,6 +137,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
137 137
138impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); 138impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
139 139
140impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0);
141
140impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 142impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
141 143
142impl_pwm!(PWM0, PWM0, PWM0); 144impl_pwm!(PWM0, PWM0, PWM0);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 918404cf1..dc4a8660e 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -138,6 +138,9 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
138impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 138impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
139impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); 139impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1);
140 140
141impl_spis!(TWISPI0, SPIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
142impl_spis!(SPI1, SPIS1, SPIM1_SPIS1_SPI1);
143
141impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 144impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
142 145
143impl_pwm!(PWM0, PWM0, PWM0); 146impl_pwm!(PWM0, PWM0, PWM0);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index dba033b0f..7668920bd 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -136,6 +136,9 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
136impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 136impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
137impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 137impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
138 138
139impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
140impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
141
139impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 142impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
140impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 143impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
141 144
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 81e66c193..851643b55 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -146,6 +146,10 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
146impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 146impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
147impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 147impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
148 148
149impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
150impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
151impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
152
149impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 153impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
150impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 154impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
151 155
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 92499e3c9..5342ba8c2 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -174,6 +174,10 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
174impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 174impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
175impl_spim!(SPI3, SPIM3, SPIM3); 175impl_spim!(SPI3, SPIM3, SPIM3);
176 176
177impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
178impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
179impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
180
177impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 181impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
178impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 182impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
179 183
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 4beadfba8..a330aef8b 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -177,6 +177,10 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
177impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 177impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
178impl_spim!(SPI3, SPIM3, SPIM3); 178impl_spim!(SPI3, SPIM3, SPIM3);
179 179
180impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
183
180impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 184impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 185impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182 186
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 7845d4a8e..1c027ec02 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -361,6 +361,11 @@ impl_spim!(UARTETWISPI1, SPIM1, SERIAL1);
361impl_spim!(UARTETWISPI2, SPIM2, SERIAL2); 361impl_spim!(UARTETWISPI2, SPIM2, SERIAL2);
362impl_spim!(UARTETWISPI3, SPIM3, SERIAL3); 362impl_spim!(UARTETWISPI3, SPIM3, SERIAL3);
363 363
364impl_spis!(UARTETWISPI0, SPIS0, SERIAL0);
365impl_spis!(UARTETWISPI1, SPIS1, SERIAL1);
366impl_spis!(UARTETWISPI2, SPIS2, SERIAL2);
367impl_spis!(UARTETWISPI3, SPIS3, SERIAL3);
368
364impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); 369impl_twim!(UARTETWISPI0, TWIM0, SERIAL0);
365impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); 370impl_twim!(UARTETWISPI1, TWIM1, SERIAL1);
366impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); 371impl_twim!(UARTETWISPI2, TWIM2, SERIAL2);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index ae136e09d..3bcd44fcb 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -238,6 +238,7 @@ embassy_hal_common::peripherals! {
238 238
239impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); 239impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0);
240impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); 240impl_spim!(UARTETWISPI0, SPIM0, SERIAL0);
241impl_spis!(UARTETWISPI0, SPIS0, SERIAL0);
241impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); 242impl_twim!(UARTETWISPI0, TWIM0, SERIAL0);
242 243
243impl_timer!(TIMER0, TIMER0, TIMER0); 244impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index b5a53ed80..0dfa112fe 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -275,6 +275,11 @@ impl_spim!(UARTETWISPI1, SPIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
275impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 275impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
276impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 276impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
277 277
278impl_spis!(UARTETWISPI0, SPIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
279impl_spis!(UARTETWISPI1, SPIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
280impl_spis!(UARTETWISPI2, SPIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
281impl_spis!(UARTETWISPI3, SPIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
282
278impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); 283impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
279impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); 284impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
280impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 285impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index bc70fc2f6..587e19be5 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -96,6 +96,7 @@ pub mod rng;
96#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] 96#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
97pub mod saadc; 97pub mod saadc;
98pub mod spim; 98pub mod spim;
99pub mod spis;
99#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 100#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
100pub mod temp; 101pub mod temp;
101pub mod timer; 102pub mod timer;
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
new file mode 100644
index 000000000..32c0b6f93
--- /dev/null
+++ b/embassy-nrf/src/spis.rs
@@ -0,0 +1,516 @@
1#![macro_use]
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_embedded_hal::SetConfig;
8use embassy_hal_common::{into_ref, PeripheralRef};
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
10
11use crate::chip::FORCE_COPY_BUFFER_SIZE;
12use crate::gpio::sealed::Pin as _;
13use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
14use crate::interrupt::{Interrupt, InterruptExt};
15use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
16use crate::{pac, Peripheral};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20#[non_exhaustive]
21pub enum Error {
22 TxBufferTooLong,
23 RxBufferTooLong,
24 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
25 DMABufferNotInDataMemory,
26}
27
28/// Interface for the SPIS peripheral using EasyDMA to offload the transmission and reception workload.
29///
30/// For more details about EasyDMA, consult the module documentation.
31pub struct Spis<'d, T: Instance> {
32 _p: PeripheralRef<'d, T>,
33}
34
35#[non_exhaustive]
36pub struct Config {
37 pub mode: Mode,
38 pub orc: u8,
39 pub def: u8,
40 pub auto_acquire: bool,
41}
42
43impl Default for Config {
44 fn default() -> Self {
45 Self {
46 mode: MODE_0,
47 orc: 0x00,
48 def: 0x00,
49 auto_acquire: true,
50 }
51 }
52}
53
54impl<'d, T: Instance> Spis<'d, T> {
55 pub fn new(
56 spis: impl Peripheral<P = T> + 'd,
57 irq: impl Peripheral<P = T::Interrupt> + 'd,
58 cs: impl Peripheral<P = impl GpioPin> + 'd,
59 sck: impl Peripheral<P = impl GpioPin> + 'd,
60 miso: impl Peripheral<P = impl GpioPin> + 'd,
61 mosi: impl Peripheral<P = impl GpioPin> + 'd,
62 config: Config,
63 ) -> Self {
64 into_ref!(cs, sck, miso, mosi);
65 Self::new_inner(
66 spis,
67 irq,
68 cs.map_into(),
69 sck.map_into(),
70 Some(miso.map_into()),
71 Some(mosi.map_into()),
72 config,
73 )
74 }
75
76 pub fn new_txonly(
77 spis: impl Peripheral<P = T> + 'd,
78 irq: impl Peripheral<P = T::Interrupt> + 'd,
79 cs: impl Peripheral<P = impl GpioPin> + 'd,
80 sck: impl Peripheral<P = impl GpioPin> + 'd,
81 mosi: impl Peripheral<P = impl GpioPin> + 'd,
82 config: Config,
83 ) -> Self {
84 into_ref!(cs, sck, mosi);
85 Self::new_inner(spis, irq, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config)
86 }
87
88 pub fn new_rxonly(
89 spis: impl Peripheral<P = T> + 'd,
90 irq: impl Peripheral<P = T::Interrupt> + 'd,
91 cs: impl Peripheral<P = impl GpioPin> + 'd,
92 sck: impl Peripheral<P = impl GpioPin> + 'd,
93 miso: impl Peripheral<P = impl GpioPin> + 'd,
94 config: Config,
95 ) -> Self {
96 into_ref!(cs, sck, miso);
97 Self::new_inner(spis, irq, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config)
98 }
99
100 fn new_inner(
101 spis: impl Peripheral<P = T> + 'd,
102 irq: impl Peripheral<P = T::Interrupt> + 'd,
103 cs: PeripheralRef<'d, AnyPin>,
104 sck: PeripheralRef<'d, AnyPin>,
105 miso: Option<PeripheralRef<'d, AnyPin>>,
106 mosi: Option<PeripheralRef<'d, AnyPin>>,
107 config: Config,
108 ) -> Self {
109 into_ref!(cs, spis, irq);
110
111 let r = T::regs();
112
113 // Configure pins
114 sck.conf().write(|w| w.input().connect().drive().h0h1());
115 cs.conf().write(|w| w.input().connect().drive().h0h1());
116 if let Some(mosi) = &mosi {
117 mosi.conf().write(|w| w.input().connect().drive().h0h1());
118 }
119 if let Some(miso) = &miso {
120 miso.conf().write(|w| w.dir().output().drive().h0h1());
121 }
122
123 match config.mode.polarity {
124 Polarity::IdleHigh => {
125 sck.set_high();
126 if let Some(mosi) = &mosi {
127 mosi.set_high();
128 }
129 }
130 Polarity::IdleLow => {
131 sck.set_low();
132 if let Some(mosi) = &mosi {
133 mosi.set_low();
134 }
135 }
136 }
137
138 if config.auto_acquire {
139 r.shorts.write(|w| w.end_acquire().bit(true));
140 }
141
142 // Select pins.
143 r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
144 r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) });
145 r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) });
146 r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) });
147
148 // Enable SPIS instance.
149 r.enable.write(|w| w.enable().enabled());
150
151 // Configure mode.
152 let mode = config.mode;
153 r.config.write(|w| {
154 match mode {
155 MODE_0 => {
156 w.order().msb_first();
157 w.cpol().active_high();
158 w.cpha().leading();
159 }
160 MODE_1 => {
161 w.order().msb_first();
162 w.cpol().active_high();
163 w.cpha().trailing();
164 }
165 MODE_2 => {
166 w.order().msb_first();
167 w.cpol().active_low();
168 w.cpha().leading();
169 }
170 MODE_3 => {
171 w.order().msb_first();
172 w.cpol().active_low();
173 w.cpha().trailing();
174 }
175 }
176
177 w
178 });
179
180 // Set over-read character
181 let orc = config.orc;
182 r.orc.write(|w| unsafe { w.orc().bits(orc) });
183
184 // Set default character
185 let def = config.def;
186 r.def.write(|w| unsafe { w.def().bits(def) });
187
188 // Disable all events interrupts
189 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
190
191 irq.set_handler(Self::on_interrupt);
192 irq.unpend();
193 irq.enable();
194
195 Self { _p: spis }
196 }
197
198 fn on_interrupt(_: *mut ()) {
199 let r = T::regs();
200 let s = T::state();
201
202 if r.events_end.read().bits() != 0 {
203 s.end_waker.wake();
204 r.intenclr.write(|w| w.end().clear());
205 }
206
207 if r.events_acquired.read().bits() != 0 {
208 s.acquire_waker.wake();
209 r.intenclr.write(|w| w.acquired().clear());
210 }
211 }
212
213 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
214 slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
215 // NOTE: RAM slice check for rx is not necessary, as a mutable
216 // slice can only be built from data located in RAM.
217
218 compiler_fence(Ordering::SeqCst);
219
220 let r = T::regs();
221
222 // Set up the DMA write.
223 let (ptr, len) = slice_ptr_parts(tx);
224 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
225 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
226
227 // Set up the DMA read.
228 let (ptr, len) = slice_ptr_parts_mut(rx);
229 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
230 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
231
232 // Reset and enable the end event
233 r.events_end.reset();
234 r.intenset.write(|w| w.end().set());
235
236 // Release the semaphore
237 r.tasks_release.write(|w| unsafe { w.bits(1) });
238
239 Ok(())
240 }
241
242 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
243 self.prepare(rx, tx)?;
244 let r = T::regs();
245
246 // Wait for 'end' event.
247 while r.events_end.read().bits() == 0 {}
248
249 let n_rx = r.rxd.amount.read().bits() as usize;
250 let n_tx = r.txd.amount.read().bits() as usize;
251
252 compiler_fence(Ordering::SeqCst);
253
254 Ok((n_rx, n_tx))
255 }
256
257 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
258 match self.blocking_inner_from_ram(rx, tx) {
259 Ok(n) => Ok(n),
260 Err(Error::DMABufferNotInDataMemory) => {
261 trace!("Copying SPIS tx buffer into RAM for DMA");
262 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
263 tx_ram_buf.copy_from_slice(tx);
264 self.blocking_inner_from_ram(rx, tx_ram_buf)
265 }
266 Err(error) => Err(error),
267 }
268 }
269
270 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
271 let r = T::regs();
272 let s = T::state();
273
274 if r.semstat.read().bits() != 1 {
275 // Reset and enable the acquire event
276 r.events_acquired.reset();
277 r.intenset.write(|w| w.acquired().set());
278
279 // Requests acquiring the SPIS semaphore
280 r.tasks_acquire.write(|w| unsafe { w.bits(1) });
281
282 // Wait for 'acquire' event.
283 poll_fn(|cx| {
284 s.acquire_waker.register(cx.waker());
285 if r.events_acquired.read().bits() != 0 {
286 return Poll::Ready(());
287 }
288 Poll::Pending
289 })
290 .await;
291 }
292
293 self.prepare(rx, tx)?;
294
295 // Wait for 'end' event.
296 poll_fn(|cx| {
297 s.end_waker.register(cx.waker());
298 if r.events_end.read().bits() != 0 {
299 return Poll::Ready(());
300 }
301
302 Poll::Pending
303 })
304 .await;
305
306 let n_rx = r.rxd.amount.read().bits() as usize;
307 let n_tx = r.txd.amount.read().bits() as usize;
308
309 compiler_fence(Ordering::SeqCst);
310
311 Ok((n_rx, n_tx))
312 }
313
314 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
315 match self.async_inner_from_ram(rx, tx).await {
316 Ok(n) => Ok(n),
317 Err(Error::DMABufferNotInDataMemory) => {
318 trace!("Copying SPIS tx buffer into RAM for DMA");
319 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
320 tx_ram_buf.copy_from_slice(tx);
321 self.async_inner_from_ram(rx, tx_ram_buf).await
322 }
323 Err(error) => Err(error),
324 }
325 }
326
327 /// Reads data from the SPI bus without sending anything. Blocks until the buffer has been filled.
328 /// Returns number of bytes read
329 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
330 self.blocking_inner(data, &[]).map(|n| n.0)
331 }
332
333 /// Simultaneously sends and receives data. Blocks until the transmission is completed.
334 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
335 /// Returns number of bytes transferred `(n_rx, n_tx)`
336 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
337 self.blocking_inner(read, write)
338 }
339
340 /// Same as [`blocking_transfer`](Spis::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
341 /// Returns number of bytes transferred `(n_rx, n_tx)`
342 pub fn blocking_transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
343 self.blocking_inner(read, write)
344 }
345
346 /// Simultaneously sends and receives data.
347 /// Places the received data into the same buffer and blocks until the transmission is completed.
348 /// Returns number of bytes transferred
349 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> {
350 self.blocking_inner_from_ram(data, data).map(|n| n.0)
351 }
352
353 /// Sends data, discarding any received data. Blocks until the transmission is completed.
354 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
355 /// Returns number of bytes written
356 pub fn blocking_write(&mut self, data: &[u8]) -> Result<usize, Error> {
357 self.blocking_inner(&mut [], data).map(|n| n.1)
358 }
359
360 /// Same as [`blocking_write`](Spis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
361 /// Returns number of bytes written
362 pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> {
363 self.blocking_inner(&mut [], data).map(|n| n.1)
364 }
365
366 /// Reads data from the SPI bus without sending anything.
367 /// Returns number of bytes read
368 pub async fn read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
369 self.async_inner(data, &[]).await.map(|n| n.0)
370 }
371
372 /// Simultaneously sends and receives data.
373 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
374 /// Returns number of bytes transferred `(n_rx, n_tx)`
375 pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
376 self.async_inner(read, write).await
377 }
378
379 /// Same as [`transfer`](Spis::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
380 /// Returns number of bytes transferred `(n_rx, n_tx)`
381 pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
382 self.async_inner_from_ram(read, write).await
383 }
384
385 /// Simultaneously sends and receives data. Places the received data into the same buffer.
386 /// Returns number of bytes transferred
387 pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> {
388 self.async_inner_from_ram(data, data).await.map(|n| n.0)
389 }
390
391 /// Sends data, discarding any received data.
392 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
393 /// Returns number of bytes written
394 pub async fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
395 self.async_inner(&mut [], data).await.map(|n| n.1)
396 }
397
398 /// Same as [`write`](Spis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
399 /// Returns number of bytes written
400 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> {
401 self.async_inner_from_ram(&mut [], data).await.map(|n| n.1)
402 }
403}
404
405impl<'d, T: Instance> Drop for Spis<'d, T> {
406 fn drop(&mut self) {
407 trace!("spis drop");
408
409 // Disable
410 let r = T::regs();
411 r.enable.write(|w| w.enable().disabled());
412
413 gpio::deconfigure_pin(r.psel.sck.read().bits());
414 gpio::deconfigure_pin(r.psel.csn.read().bits());
415 gpio::deconfigure_pin(r.psel.miso.read().bits());
416 gpio::deconfigure_pin(r.psel.mosi.read().bits());
417
418 trace!("spis drop: done");
419 }
420}
421
422pub(crate) mod sealed {
423 use embassy_sync::waitqueue::AtomicWaker;
424
425 use super::*;
426
427 pub struct State {
428 pub end_waker: AtomicWaker,
429 pub acquire_waker: AtomicWaker,
430 }
431
432 impl State {
433 pub const fn new() -> Self {
434 Self {
435 end_waker: AtomicWaker::new(),
436 acquire_waker: AtomicWaker::new(),
437 }
438 }
439 }
440
441 pub trait Instance {
442 fn regs() -> &'static pac::spis0::RegisterBlock;
443 fn state() -> &'static State;
444 }
445}
446
447pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
448 type Interrupt: Interrupt;
449}
450
451macro_rules! impl_spis {
452 ($type:ident, $pac_type:ident, $irq:ident) => {
453 impl crate::spis::sealed::Instance for peripherals::$type {
454 fn regs() -> &'static pac::spis0::RegisterBlock {
455 unsafe { &*pac::$pac_type::ptr() }
456 }
457 fn state() -> &'static crate::spis::sealed::State {
458 static STATE: crate::spis::sealed::State = crate::spis::sealed::State::new();
459 &STATE
460 }
461 }
462 impl crate::spis::Instance for peripherals::$type {
463 type Interrupt = crate::interrupt::$irq;
464 }
465 };
466}
467
468// ====================
469
470impl<'d, T: Instance> SetConfig for Spis<'d, T> {
471 type Config = Config;
472 fn set_config(&mut self, config: &Self::Config) {
473 let r = T::regs();
474 // Configure mode.
475 let mode = config.mode;
476 r.config.write(|w| {
477 match mode {
478 MODE_0 => {
479 w.order().msb_first();
480 w.cpol().active_high();
481 w.cpha().leading();
482 }
483 MODE_1 => {
484 w.order().msb_first();
485 w.cpol().active_high();
486 w.cpha().trailing();
487 }
488 MODE_2 => {
489 w.order().msb_first();
490 w.cpol().active_low();
491 w.cpha().leading();
492 }
493 MODE_3 => {
494 w.order().msb_first();
495 w.cpol().active_low();
496 w.cpha().trailing();
497 }
498 }
499
500 w
501 });
502
503 // Set over-read character
504 let orc = config.orc;
505 r.orc.write(|w| unsafe { w.orc().bits(orc) });
506
507 // Set default character
508 let def = config.def;
509 r.def.write(|w| unsafe { w.def().bits(def) });
510
511 // Set auto acquire
512 let auto_acquire = config.auto_acquire;
513 r.shorts.write(|w| w.end_acquire().bit(auto_acquire));
514
515 }
516}
diff --git a/examples/nrf/src/bin/spis.rs b/examples/nrf/src/bin/spis.rs
new file mode 100644
index 000000000..181e08404
--- /dev/null
+++ b/examples/nrf/src/bin/spis.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::spis::{self, Config};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Running!");
15
16 let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
17 let mut spis = spis::Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
18
19 loop {
20 let mut buf = [0_u8; 64];
21 if let Ok(n) = spis.read(&mut buf).await {
22 info!("RX: {:?}", buf[..n]);
23 }
24 }
25}