aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json1
-rw-r--r--embassy-nrf-examples/Cargo.toml6
-rw-r--r--embassy-nrf-examples/src/bin/qspi.rs25
-rw-r--r--embassy-nrf/Cargo.toml1
-rw-r--r--embassy-nrf/src/qspi.rs270
-rw-r--r--embassy/src/flash.rs8
6 files changed, 192 insertions, 119 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8915126a4..19efb1373 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,6 +6,7 @@
6 "rust-analyzer.checkOnSave.allTargets": false, 6 "rust-analyzer.checkOnSave.allTargets": false,
7 "rust-analyzer.procMacro.enable": true, 7 "rust-analyzer.procMacro.enable": true,
8 "rust-analyzer.cargo.loadOutDirsFromCheck": true, 8 "rust-analyzer.cargo.loadOutDirsFromCheck": true,
9 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
9 "files.watcherExclude": { 10 "files.watcherExclude": {
10 "**/.git/objects/**": true, 11 "**/.git/objects/**": true,
11 "**/.git/subtree-cache/**": true, 12 "**/.git/subtree-cache/**": true,
diff --git a/embassy-nrf-examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml
index 364fd8a51..b7e4c340c 100644
--- a/embassy-nrf-examples/Cargo.toml
+++ b/embassy-nrf-examples/Cargo.toml
@@ -17,13 +17,13 @@ defmt-error = []
17 17
18 18
19[dependencies] 19[dependencies]
20embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } 20embassy = { version = "0.1.0", path = "../embassy", features = ["defmt"] }
21embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } 21embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "52840"] }
22 22
23defmt = "0.2.0" 23defmt = "0.2.0"
24defmt-rtt = "0.2.0" 24defmt-rtt = "0.2.0"
25 25
26cortex-m = "0.7.1" 26cortex-m = { version = "0.7.1", features = ["inline-asm"] }
27cortex-m-rt = "0.6.13" 27cortex-m-rt = "0.6.13"
28embedded-hal = { version = "0.2.4" } 28embedded-hal = { version = "0.2.4" }
29panic-probe = "0.1.0" 29panic-probe = "0.1.0"
diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs
index 850681d7c..790dedc91 100644
--- a/embassy-nrf-examples/src/bin/qspi.rs
+++ b/embassy-nrf-examples/src/bin/qspi.rs
@@ -8,6 +8,7 @@ use example_common::*;
8 8
9use cortex_m_rt::entry; 9use cortex_m_rt::entry;
10use defmt::{assert_eq, panic}; 10use defmt::{assert_eq, panic};
11use futures::pin_mut;
11use nrf52840_hal::gpio; 12use nrf52840_hal::gpio;
12 13
13use embassy::executor::{task, Executor}; 14use embassy::executor::{task, Executor};
@@ -69,22 +70,32 @@ async fn run() {
69 }; 70 };
70 71
71 let irq = interrupt::take!(QSPI); 72 let irq = interrupt::take!(QSPI);
72 let mut q = qspi::Qspi::new(p.QSPI, irq, config); 73 let q = qspi::Qspi::new(p.QSPI, irq, config);
74 pin_mut!(q);
73 75
74 let mut id = [1; 3]; 76 let mut id = [1; 3];
75 q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); 77 q.as_mut()
78 .custom_instruction(0x9F, &[], &mut id)
79 .await
80 .unwrap();
76 info!("id: {}", id); 81 info!("id: {}", id);
77 82
78 // Read status register 83 // Read status register
79 let mut status = [0; 1]; 84 let mut status = [0; 1];
80 q.custom_instruction(0x05, &[], &mut status).await.unwrap(); 85 q.as_mut()
86 .custom_instruction(0x05, &[], &mut status)
87 .await
88 .unwrap();
81 89
82 info!("status: {:?}", status[0]); 90 info!("status: {:?}", status[0]);
83 91
84 if status[0] & 0x40 == 0 { 92 if status[0] & 0x40 == 0 {
85 status[0] |= 0x40; 93 status[0] |= 0x40;
86 94
87 q.custom_instruction(0x01, &status, &mut []).await.unwrap(); 95 q.as_mut()
96 .custom_instruction(0x01, &status, &mut [])
97 .await
98 .unwrap();
88 99
89 info!("enabled quad in status"); 100 info!("enabled quad in status");
90 } 101 }
@@ -95,19 +106,19 @@ async fn run() {
95 106
96 for i in 0..8 { 107 for i in 0..8 {
97 info!("page {:?}: erasing... ", i); 108 info!("page {:?}: erasing... ", i);
98 q.erase(i * PAGE_SIZE).await.unwrap(); 109 q.as_mut().erase(i * PAGE_SIZE).await.unwrap();
99 110
100 for j in 0..PAGE_SIZE { 111 for j in 0..PAGE_SIZE {
101 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); 112 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
102 } 113 }
103 114
104 info!("programming..."); 115 info!("programming...");
105 q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); 116 q.as_mut().write(i * PAGE_SIZE, &buf.0).await.unwrap();
106 } 117 }
107 118
108 for i in 0..8 { 119 for i in 0..8 {
109 info!("page {:?}: reading... ", i); 120 info!("page {:?}: reading... ", i);
110 q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); 121 q.as_mut().read(i * PAGE_SIZE, &mut buf.0).await.unwrap();
111 122
112 info!("verifying..."); 123 info!("verifying...");
113 for j in 0..PAGE_SIZE { 124 for j in 0..PAGE_SIZE {
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index ddd2dc31a..6324792fc 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -27,6 +27,7 @@ cortex-m-rt = "0.6.13"
27cortex-m = "0.7.1" 27cortex-m = "0.7.1"
28embedded-hal = { version = "0.2.4" } 28embedded-hal = { version = "0.2.4" }
29embedded-dma = { version = "0.1.2" } 29embedded-dma = { version = "0.1.2" }
30futures = { version = "0.3.5", default-features = false }
30 31
31nrf52810-pac = { version = "0.9.0", optional = true } 32nrf52810-pac = { version = "0.9.0", optional = true }
32nrf52811-pac = { version = "0.9.1", optional = true } 33nrf52811-pac = { version = "0.9.1", optional = true }
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 300b32ad5..c238a6c82 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -1,6 +1,9 @@
1use crate::fmt::{assert, assert_eq, *};
2use core::future::Future; 1use core::future::Future;
2use core::pin::Pin;
3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll;
3 5
6use crate::fmt::{assert, assert_eq, *};
4use crate::hal::gpio::{Output, Pin as GpioPin, Port as GpioPort, PushPull}; 7use crate::hal::gpio::{Output, Pin as GpioPin, Port as GpioPort, PushPull};
5use crate::interrupt::{self, Interrupt}; 8use crate::interrupt::{self, Interrupt};
6use crate::pac::QSPI; 9use crate::pac::QSPI;
@@ -9,6 +12,7 @@ pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode;
9pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize; 12pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize;
10pub use crate::pac::qspi::ifconfig0::READOC_A as ReadOpcode; 13pub use crate::pac::qspi::ifconfig0::READOC_A as ReadOpcode;
11pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; 14pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
15use crate::util::peripheral::{PeripheralMutex, PeripheralState};
12 16
13// TODO 17// TODO
14// - config: 18// - config:
@@ -21,7 +25,8 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
21// - set gpio in high drive 25// - set gpio in high drive
22 26
23use embassy::flash::{Error, Flash}; 27use embassy::flash::{Error, Flash};
24use embassy::util::{DropBomb, Signal}; 28use embassy::util::{DropBomb, WakerRegistration};
29use futures::future::poll_fn;
25 30
26pub struct Pins { 31pub struct Pins {
27 pub sck: GpioPin<Output<PushPull>>, 32 pub sck: GpioPin<Output<PushPull>>,
@@ -46,8 +51,13 @@ pub struct Config {
46 pub deep_power_down: Option<DeepPowerDownConfig>, 51 pub deep_power_down: Option<DeepPowerDownConfig>,
47} 52}
48 53
49pub struct Qspi { 54struct State {
50 inner: QSPI, 55 inner: QSPI,
56 waker: WakerRegistration,
57}
58
59pub struct Qspi {
60 inner: PeripheralMutex<State>,
51} 61}
52 62
53fn port_bit(port: GpioPort) -> bool { 63fn port_bit(port: GpioPort) -> bool {
@@ -142,32 +152,34 @@ impl Qspi {
142 while qspi.events_ready.read().bits() == 0 {} 152 while qspi.events_ready.read().bits() == 0 {}
143 qspi.events_ready.reset(); 153 qspi.events_ready.reset();
144 154
145 // Enable READY interrupt 155 Self {
146 SIGNAL.reset(); 156 inner: PeripheralMutex::new(
147 qspi.intenset.write(|w| w.ready().set()); 157 State {
148 158 inner: qspi,
149 irq.set_handler(irq_handler); 159 waker: WakerRegistration::new(),
150 irq.unpend(); 160 },
151 irq.enable(); 161 irq,
152 162 ),
153 Self { inner: qspi } 163 }
154 } 164 }
155 165
156 pub fn sleep(&mut self) { 166 pub fn sleep(self: Pin<&mut Self>) {
157 info!("flash: sleeping"); 167 self.inner().with(|s, _| {
158 info!("flash: state = {:?}", self.inner.status.read().bits()); 168 info!("flash: sleeping");
159 self.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); 169 info!("flash: state = {:?}", s.inner.status.read().bits());
160 info!("flash: state = {:?}", self.inner.status.read().bits()); 170 s.inner.ifconfig1.modify(|_, w| w.dpmen().enter());
161 cortex_m::asm::delay(1000000); 171 info!("flash: state = {:?}", s.inner.status.read().bits());
162 info!("flash: state = {:?}", self.inner.status.read().bits()); 172 cortex_m::asm::delay(1000000);
163 173 info!("flash: state = {:?}", s.inner.status.read().bits());
164 self.inner 174
165 .tasks_deactivate 175 s.inner
166 .write(|w| w.tasks_deactivate().set_bit()); 176 .tasks_deactivate
177 .write(|w| w.tasks_deactivate().set_bit());
178 });
167 } 179 }
168 180
169 pub async fn custom_instruction<'a>( 181 pub async fn custom_instruction<'a>(
170 &'a mut self, 182 mut self: Pin<&'a mut Self>,
171 opcode: u8, 183 opcode: u8,
172 req: &'a [u8], 184 req: &'a [u8],
173 resp: &'a mut [u8], 185 resp: &'a mut [u8],
@@ -193,40 +205,68 @@ impl Qspi {
193 205
194 let len = core::cmp::max(req.len(), resp.len()) as u8; 206 let len = core::cmp::max(req.len(), resp.len()) as u8;
195 207
196 self.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); 208 self.as_mut().inner().with(|s, _| {
197 self.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); 209 s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
198 self.inner.events_ready.reset(); 210 s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
199 self.inner.cinstrconf.write(|w| { 211
200 let w = unsafe { w.opcode().bits(opcode) }; 212 s.inner.events_ready.reset();
201 let w = unsafe { w.length().bits(len + 1) }; 213 s.inner.intenset.write(|w| w.ready().set());
202 let w = w.lio2().bit(true); 214
203 let w = w.lio3().bit(true); 215 s.inner.cinstrconf.write(|w| {
204 let w = w.wipwait().bit(true); 216 let w = unsafe { w.opcode().bits(opcode) };
205 let w = w.wren().bit(true); 217 let w = unsafe { w.length().bits(len + 1) };
206 let w = w.lfen().bit(false); 218 let w = w.lio2().bit(true);
207 let w = w.lfstop().bit(false); 219 let w = w.lio3().bit(true);
208 w 220 let w = w.wipwait().bit(true);
221 let w = w.wren().bit(true);
222 let w = w.lfen().bit(false);
223 let w = w.lfstop().bit(false);
224 w
225 });
209 }); 226 });
210 227
211 SIGNAL.wait().await; 228 self.as_mut().wait_ready().await;
212 229
213 let dat0 = self.inner.cinstrdat0.read().bits(); 230 self.as_mut().inner().with(|s, _| {
214 let dat1 = self.inner.cinstrdat1.read().bits(); 231 let dat0 = s.inner.cinstrdat0.read().bits();
215 for i in 0..4 { 232 let dat1 = s.inner.cinstrdat1.read().bits();
216 if i < resp.len() { 233 for i in 0..4 {
217 resp[i] = (dat0 >> (i * 8)) as u8; 234 if i < resp.len() {
235 resp[i] = (dat0 >> (i * 8)) as u8;
236 }
218 } 237 }
219 } 238 for i in 0..4 {
220 for i in 0..4 { 239 if i + 4 < resp.len() {
221 if i + 4 < resp.len() { 240 resp[i] = (dat1 >> (i * 8)) as u8;
222 resp[i] = (dat1 >> (i * 8)) as u8; 241 }
223 } 242 }
224 } 243 });
225 244
226 bomb.defuse(); 245 bomb.defuse();
227 246
228 Ok(()) 247 Ok(())
229 } 248 }
249
250 fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State>> {
251 unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
252 }
253
254 pub fn free(self: Pin<&mut Self>) -> (QSPI, interrupt::QSPI) {
255 let (state, irq) = self.inner().free();
256 (state.inner, irq)
257 }
258
259 fn wait_ready<'a>(mut self: Pin<&'a mut Self>) -> impl Future<Output = ()> + 'a {
260 poll_fn(move |cx| {
261 self.as_mut().inner().with(|s, irq| {
262 if s.inner.events_ready.read().bits() != 0 {
263 return Poll::Ready(());
264 }
265 s.waker.register(cx.waker());
266 Poll::Pending
267 })
268 })
269 }
230} 270}
231 271
232impl Flash for Qspi { 272impl Flash for Qspi {
@@ -234,7 +274,11 @@ impl Flash for Qspi {
234 type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; 274 type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
235 type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; 275 type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
236 276
237 fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> { 277 fn read<'a>(
278 mut self: Pin<&'a mut Self>,
279 address: usize,
280 data: &'a mut [u8],
281 ) -> Self::ReadFuture<'a> {
238 async move { 282 async move {
239 let bomb = DropBomb::new(); 283 let bomb = DropBomb::new();
240 284
@@ -242,25 +286,28 @@ impl Flash for Qspi {
242 assert_eq!(data.len() as u32 % 4, 0); 286 assert_eq!(data.len() as u32 % 4, 0);
243 assert_eq!(address as u32 % 4, 0); 287 assert_eq!(address as u32 % 4, 0);
244 288
245 self.inner 289 self.as_mut().inner().with(|s, _| {
246 .read 290 s.inner
247 .src 291 .read
248 .write(|w| unsafe { w.src().bits(address as u32) }); 292 .src
249 self.inner 293 .write(|w| unsafe { w.src().bits(address as u32) });
250 .read 294 s.inner
251 .dst 295 .read
252 .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); 296 .dst
253 self.inner 297 .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
254 .read 298 s.inner
255 .cnt 299 .read
256 .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); 300 .cnt
257 301 .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
258 self.inner.events_ready.reset(); 302
259 self.inner 303 s.inner.events_ready.reset();
260 .tasks_readstart 304 s.inner.intenset.write(|w| w.ready().set());
261 .write(|w| w.tasks_readstart().bit(true)); 305 s.inner
262 306 .tasks_readstart
263 SIGNAL.wait().await; 307 .write(|w| w.tasks_readstart().bit(true));
308 });
309
310 self.as_mut().wait_ready().await;
264 311
265 bomb.defuse(); 312 bomb.defuse();
266 313
@@ -268,7 +315,11 @@ impl Flash for Qspi {
268 } 315 }
269 } 316 }
270 317
271 fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> { 318 fn write<'a>(
319 mut self: Pin<&'a mut Self>,
320 address: usize,
321 data: &'a [u8],
322 ) -> Self::WriteFuture<'a> {
272 async move { 323 async move {
273 let bomb = DropBomb::new(); 324 let bomb = DropBomb::new();
274 325
@@ -276,25 +327,28 @@ impl Flash for Qspi {
276 assert_eq!(data.len() as u32 % 4, 0); 327 assert_eq!(data.len() as u32 % 4, 0);
277 assert_eq!(address as u32 % 4, 0); 328 assert_eq!(address as u32 % 4, 0);
278 329
279 self.inner 330 self.as_mut().inner().with(|s, _| {
280 .write 331 s.inner
281 .src 332 .write
282 .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); 333 .src
283 self.inner 334 .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
284 .write 335 s.inner
285 .dst 336 .write
286 .write(|w| unsafe { w.dst().bits(address as u32) }); 337 .dst
287 self.inner 338 .write(|w| unsafe { w.dst().bits(address as u32) });
288 .write 339 s.inner
289 .cnt 340 .write
290 .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); 341 .cnt
291 342 .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
292 self.inner.events_ready.reset(); 343
293 self.inner 344 s.inner.events_ready.reset();
294 .tasks_writestart 345 s.inner.intenset.write(|w| w.ready().set());
295 .write(|w| w.tasks_writestart().bit(true)); 346 s.inner
296 347 .tasks_writestart
297 SIGNAL.wait().await; 348 .write(|w| w.tasks_writestart().bit(true));
349 });
350
351 self.as_mut().wait_ready().await;
298 352
299 bomb.defuse(); 353 bomb.defuse();
300 354
@@ -302,23 +356,27 @@ impl Flash for Qspi {
302 } 356 }
303 } 357 }
304 358
305 fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> { 359 fn erase<'a>(mut self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a> {
306 async move { 360 async move {
307 let bomb = DropBomb::new(); 361 let bomb = DropBomb::new();
308 362
309 assert_eq!(address as u32 % 4096, 0); 363 assert_eq!(address as u32 % 4096, 0);
310 364
311 self.inner 365 self.as_mut().inner().with(|s, _| {
312 .erase 366 s.inner
313 .ptr 367 .erase
314 .write(|w| unsafe { w.ptr().bits(address as u32) }); 368 .ptr
315 self.inner.erase.len.write(|w| w.len()._4kb()); 369 .write(|w| unsafe { w.ptr().bits(address as u32) });
316 self.inner.events_ready.reset(); 370 s.inner.erase.len.write(|w| w.len()._4kb());
317 self.inner 371
318 .tasks_erasestart 372 s.inner.events_ready.reset();
319 .write(|w| w.tasks_erasestart().bit(true)); 373 s.inner.intenset.write(|w| w.ready().set());
374 s.inner
375 .tasks_erasestart
376 .write(|w| w.tasks_erasestart().bit(true));
377 });
320 378
321 SIGNAL.wait().await; 379 self.as_mut().wait_ready().await;
322 380
323 bomb.defuse(); 381 bomb.defuse();
324 382
@@ -343,13 +401,13 @@ impl Flash for Qspi {
343 } 401 }
344} 402}
345 403
346static SIGNAL: Signal<()> = Signal::new(); 404impl PeripheralState for State {
405 type Interrupt = interrupt::QSPI;
347 406
348unsafe fn irq_handler(_ctx: *mut ()) { 407 fn on_interrupt(&mut self) {
349 let p = crate::pac::Peripherals::steal().QSPI; 408 if self.inner.events_ready.read().bits() != 0 {
350 if p.events_ready.read().events_ready().bit_is_set() { 409 self.inner.intenclr.write(|w| w.ready().clear());
351 p.events_ready.reset(); 410 self.waker.wake()
352 info!("qspi ready"); 411 }
353 SIGNAL.signal(());
354 } 412 }
355} 413}
diff --git a/embassy/src/flash.rs b/embassy/src/flash.rs
index 5866fdf05..145cc7684 100644
--- a/embassy/src/flash.rs
+++ b/embassy/src/flash.rs
@@ -1,4 +1,5 @@
1use core::future::Future; 1use core::future::Future;
2use core::pin::Pin;
2 3
3#[derive(Copy, Clone, Debug, Eq, PartialEq)] 4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -18,18 +19,19 @@ pub trait Flash {
18 /// 19 ///
19 /// address must be a multiple of self.read_size(). 20 /// address must be a multiple of self.read_size().
20 /// buf.len() must be a multiple of self.read_size(). 21 /// buf.len() must be a multiple of self.read_size().
21 fn read<'a>(&'a mut self, address: usize, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; 22 fn read<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a mut [u8])
23 -> Self::ReadFuture<'a>;
22 24
23 /// Writes data to the flash device. 25 /// Writes data to the flash device.
24 /// 26 ///
25 /// address must be a multiple of self.write_size(). 27 /// address must be a multiple of self.write_size().
26 /// buf.len() must be a multiple of self.write_size(). 28 /// buf.len() must be a multiple of self.write_size().
27 fn write<'a>(&'a mut self, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>; 29 fn write<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>;
28 30
29 /// Erases a single page from the flash device. 31 /// Erases a single page from the flash device.
30 /// 32 ///
31 /// address must be a multiple of self.erase_size(). 33 /// address must be a multiple of self.erase_size().
32 fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a>; 34 fn erase<'a>(self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a>;
33 35
34 /// Returns the total size, in bytes. 36 /// Returns the total size, in bytes.
35 /// This is not guaranteed to be a power of 2. 37 /// This is not guaranteed to be a power of 2.