diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-09-01 13:52:47 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-09-01 13:52:47 +0000 |
| commit | 835b69456d6a270e6d5c869da46c0df30fe54254 (patch) | |
| tree | 1633bef46e753c6023c79dac1aa6ba817614e4bb | |
| parent | 838f3065ea1ecc68f4db8ceb2fea0026df4f6ff8 (diff) | |
| parent | efe456ab1414a19a4e0469a6bb7686a04029a44b (diff) | |
Merge #933
933: embassy-rp: Add async SPI r=Dirbaio a=kalkyl
Co-authored-by: Henrik Alsér <[email protected]>
Co-authored-by: Henrik Alsér <[email protected]>
| -rw-r--r-- | embassy-rp/src/dma.rs | 6 | ||||
| -rw-r--r-- | embassy-rp/src/spi.rs | 333 | ||||
| -rw-r--r-- | examples/rp/src/bin/spi.rs | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/spi_async.rs | 29 | ||||
| -rw-r--r-- | examples/rp/src/bin/spi_display.rs | 5 | ||||
| -rw-r--r-- | tests/rp/src/bin/spi.rs | 28 | ||||
| -rw-r--r-- | tests/rp/src/bin/spi_async.rs | 28 |
7 files changed, 373 insertions, 58 deletions
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 75d7492e0..acf338225 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -40,10 +40,10 @@ pub(crate) unsafe fn init() { | |||
| 40 | pub unsafe fn read<'a, C: Channel, W: Word>( | 40 | pub unsafe fn read<'a, C: Channel, W: Word>( |
| 41 | ch: impl Peripheral<P = C> + 'a, | 41 | ch: impl Peripheral<P = C> + 'a, |
| 42 | from: *const W, | 42 | from: *const W, |
| 43 | to: &mut [W], | 43 | to: *mut [W], |
| 44 | dreq: u8, | 44 | dreq: u8, |
| 45 | ) -> Transfer<'a, C> { | 45 | ) -> Transfer<'a, C> { |
| 46 | let (to_ptr, len) = crate::dma::slice_ptr_parts_mut(to); | 46 | let (to_ptr, len) = crate::dma::slice_ptr_parts(to); |
| 47 | copy_inner( | 47 | copy_inner( |
| 48 | ch, | 48 | ch, |
| 49 | from as *const u32, | 49 | from as *const u32, |
| @@ -58,7 +58,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>( | |||
| 58 | 58 | ||
| 59 | pub unsafe fn write<'a, C: Channel, W: Word>( | 59 | pub unsafe fn write<'a, C: Channel, W: Word>( |
| 60 | ch: impl Peripheral<P = C> + 'a, | 60 | ch: impl Peripheral<P = C> + 'a, |
| 61 | from: &[W], | 61 | from: *const [W], |
| 62 | to: *mut W, | 62 | to: *mut W, |
| 63 | dreq: u8, | 63 | dreq: u8, |
| 64 | ) -> Transfer<'a, C> { | 64 | ) -> Transfer<'a, C> { |
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index d0261598e..74f0b04de 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 1 | use embassy_embedded_hal::SetConfig; | 3 | use embassy_embedded_hal::SetConfig; |
| 2 | use embassy_hal_common::{into_ref, PeripheralRef}; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 3 | pub use embedded_hal_02::spi::{Phase, Polarity}; | 5 | pub use embedded_hal_02::spi::{Phase, Polarity}; |
| 6 | use futures::future::join; | ||
| 4 | 7 | ||
| 8 | use crate::dma::{AnyChannel, Channel}; | ||
| 5 | use crate::gpio::sealed::Pin as _; | 9 | use crate::gpio::sealed::Pin as _; |
| 6 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 10 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 7 | use crate::{pac, peripherals, Peripheral}; | 11 | use crate::{pac, peripherals, Peripheral}; |
| @@ -30,8 +34,11 @@ impl Default for Config { | |||
| 30 | } | 34 | } |
| 31 | } | 35 | } |
| 32 | 36 | ||
| 33 | pub struct Spi<'d, T: Instance> { | 37 | pub struct Spi<'d, T: Instance, M: Mode> { |
| 34 | inner: PeripheralRef<'d, T>, | 38 | inner: PeripheralRef<'d, T>, |
| 39 | tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 40 | rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 41 | phantom: PhantomData<(&'d mut T, M)>, | ||
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | fn div_roundup(a: u32, b: u32) -> u32 { | 44 | fn div_roundup(a: u32, b: u32) -> u32 { |
| @@ -57,51 +64,15 @@ fn calc_prescs(freq: u32) -> (u8, u8) { | |||
| 57 | ((presc * 2) as u8, (postdiv - 1) as u8) | 64 | ((presc * 2) as u8, (postdiv - 1) as u8) |
| 58 | } | 65 | } |
| 59 | 66 | ||
| 60 | impl<'d, T: Instance> Spi<'d, T> { | 67 | impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { |
| 61 | pub fn new( | ||
| 62 | inner: impl Peripheral<P = T> + 'd, | ||
| 63 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 64 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 65 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 66 | config: Config, | ||
| 67 | ) -> Self { | ||
| 68 | into_ref!(clk, mosi, miso); | ||
| 69 | Self::new_inner( | ||
| 70 | inner, | ||
| 71 | Some(clk.map_into()), | ||
| 72 | Some(mosi.map_into()), | ||
| 73 | Some(miso.map_into()), | ||
| 74 | None, | ||
| 75 | config, | ||
| 76 | ) | ||
| 77 | } | ||
| 78 | |||
| 79 | pub fn new_txonly( | ||
| 80 | inner: impl Peripheral<P = T> + 'd, | ||
| 81 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 82 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 83 | config: Config, | ||
| 84 | ) -> Self { | ||
| 85 | into_ref!(clk, mosi); | ||
| 86 | Self::new_inner(inner, Some(clk.map_into()), Some(mosi.map_into()), None, None, config) | ||
| 87 | } | ||
| 88 | |||
| 89 | pub fn new_rxonly( | ||
| 90 | inner: impl Peripheral<P = T> + 'd, | ||
| 91 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 92 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 93 | config: Config, | ||
| 94 | ) -> Self { | ||
| 95 | into_ref!(clk, miso); | ||
| 96 | Self::new_inner(inner, Some(clk.map_into()), None, Some(miso.map_into()), None, config) | ||
| 97 | } | ||
| 98 | |||
| 99 | fn new_inner( | 68 | fn new_inner( |
| 100 | inner: impl Peripheral<P = T> + 'd, | 69 | inner: impl Peripheral<P = T> + 'd, |
| 101 | clk: Option<PeripheralRef<'d, AnyPin>>, | 70 | clk: Option<PeripheralRef<'d, AnyPin>>, |
| 102 | mosi: Option<PeripheralRef<'d, AnyPin>>, | 71 | mosi: Option<PeripheralRef<'d, AnyPin>>, |
| 103 | miso: Option<PeripheralRef<'d, AnyPin>>, | 72 | miso: Option<PeripheralRef<'d, AnyPin>>, |
| 104 | cs: Option<PeripheralRef<'d, AnyPin>>, | 73 | cs: Option<PeripheralRef<'d, AnyPin>>, |
| 74 | tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 75 | rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 105 | config: Config, | 76 | config: Config, |
| 106 | ) -> Self { | 77 | ) -> Self { |
| 107 | into_ref!(inner); | 78 | into_ref!(inner); |
| @@ -134,7 +105,12 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 134 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 105 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 135 | } | 106 | } |
| 136 | } | 107 | } |
| 137 | Self { inner } | 108 | Self { |
| 109 | inner, | ||
| 110 | tx_dma, | ||
| 111 | rx_dma, | ||
| 112 | phantom: PhantomData, | ||
| 113 | } | ||
| 138 | } | 114 | } |
| 139 | 115 | ||
| 140 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { | 116 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { |
| @@ -225,19 +201,214 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 225 | } | 201 | } |
| 226 | } | 202 | } |
| 227 | 203 | ||
| 204 | impl<'d, T: Instance> Spi<'d, T, Blocking> { | ||
| 205 | pub fn new_blocking( | ||
| 206 | inner: impl Peripheral<P = T> + 'd, | ||
| 207 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 208 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 209 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 210 | config: Config, | ||
| 211 | ) -> Self { | ||
| 212 | into_ref!(clk, mosi, miso); | ||
| 213 | Self::new_inner( | ||
| 214 | inner, | ||
| 215 | Some(clk.map_into()), | ||
| 216 | Some(mosi.map_into()), | ||
| 217 | Some(miso.map_into()), | ||
| 218 | None, | ||
| 219 | None, | ||
| 220 | None, | ||
| 221 | config, | ||
| 222 | ) | ||
| 223 | } | ||
| 224 | |||
| 225 | pub fn new_blocking_txonly( | ||
| 226 | inner: impl Peripheral<P = T> + 'd, | ||
| 227 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 228 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 229 | config: Config, | ||
| 230 | ) -> Self { | ||
| 231 | into_ref!(clk, mosi); | ||
| 232 | Self::new_inner( | ||
| 233 | inner, | ||
| 234 | Some(clk.map_into()), | ||
| 235 | Some(mosi.map_into()), | ||
| 236 | None, | ||
| 237 | None, | ||
| 238 | None, | ||
| 239 | None, | ||
| 240 | config, | ||
| 241 | ) | ||
| 242 | } | ||
| 243 | |||
| 244 | pub fn new_blocking_rxonly( | ||
| 245 | inner: impl Peripheral<P = T> + 'd, | ||
| 246 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 247 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 248 | config: Config, | ||
| 249 | ) -> Self { | ||
| 250 | into_ref!(clk, miso); | ||
| 251 | Self::new_inner( | ||
| 252 | inner, | ||
| 253 | Some(clk.map_into()), | ||
| 254 | None, | ||
| 255 | Some(miso.map_into()), | ||
| 256 | None, | ||
| 257 | None, | ||
| 258 | None, | ||
| 259 | config, | ||
| 260 | ) | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | impl<'d, T: Instance> Spi<'d, T, Async> { | ||
| 265 | pub fn new( | ||
| 266 | inner: impl Peripheral<P = T> + 'd, | ||
| 267 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 268 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 269 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 270 | tx_dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 271 | rx_dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 272 | config: Config, | ||
| 273 | ) -> Self { | ||
| 274 | into_ref!(tx_dma, rx_dma, clk, mosi, miso); | ||
| 275 | Self::new_inner( | ||
| 276 | inner, | ||
| 277 | Some(clk.map_into()), | ||
| 278 | Some(mosi.map_into()), | ||
| 279 | Some(miso.map_into()), | ||
| 280 | None, | ||
| 281 | Some(tx_dma.map_into()), | ||
| 282 | Some(rx_dma.map_into()), | ||
| 283 | config, | ||
| 284 | ) | ||
| 285 | } | ||
| 286 | |||
| 287 | pub fn new_txonly( | ||
| 288 | inner: impl Peripheral<P = T> + 'd, | ||
| 289 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 290 | mosi: impl Peripheral<P = impl MosiPin<T> + 'd> + 'd, | ||
| 291 | tx_dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 292 | config: Config, | ||
| 293 | ) -> Self { | ||
| 294 | into_ref!(tx_dma, clk, mosi); | ||
| 295 | Self::new_inner( | ||
| 296 | inner, | ||
| 297 | Some(clk.map_into()), | ||
| 298 | Some(mosi.map_into()), | ||
| 299 | None, | ||
| 300 | None, | ||
| 301 | Some(tx_dma.map_into()), | ||
| 302 | None, | ||
| 303 | config, | ||
| 304 | ) | ||
| 305 | } | ||
| 306 | |||
| 307 | pub fn new_rxonly( | ||
| 308 | inner: impl Peripheral<P = T> + 'd, | ||
| 309 | clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, | ||
| 310 | miso: impl Peripheral<P = impl MisoPin<T> + 'd> + 'd, | ||
| 311 | rx_dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 312 | config: Config, | ||
| 313 | ) -> Self { | ||
| 314 | into_ref!(rx_dma, clk, miso); | ||
| 315 | Self::new_inner( | ||
| 316 | inner, | ||
| 317 | Some(clk.map_into()), | ||
| 318 | None, | ||
| 319 | Some(miso.map_into()), | ||
| 320 | None, | ||
| 321 | None, | ||
| 322 | Some(rx_dma.map_into()), | ||
| 323 | config, | ||
| 324 | ) | ||
| 325 | } | ||
| 326 | |||
| 327 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 328 | let ch = self.tx_dma.as_mut().unwrap(); | ||
| 329 | let transfer = unsafe { | ||
| 330 | self.inner.regs().dmacr().modify(|reg| { | ||
| 331 | reg.set_txdmae(true); | ||
| 332 | }); | ||
| 333 | // If we don't assign future to a variable, the data register pointer | ||
| 334 | // is held across an await and makes the future non-Send. | ||
| 335 | crate::dma::write(ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | ||
| 336 | }; | ||
| 337 | transfer.await; | ||
| 338 | Ok(()) | ||
| 339 | } | ||
| 340 | |||
| 341 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 342 | let ch = self.rx_dma.as_mut().unwrap(); | ||
| 343 | let transfer = unsafe { | ||
| 344 | self.inner.regs().dmacr().modify(|reg| { | ||
| 345 | reg.set_rxdmae(true); | ||
| 346 | }); | ||
| 347 | // If we don't assign future to a variable, the data register pointer | ||
| 348 | // is held across an await and makes the future non-Send. | ||
| 349 | crate::dma::read(ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) | ||
| 350 | }; | ||
| 351 | transfer.await; | ||
| 352 | Ok(()) | ||
| 353 | } | ||
| 354 | |||
| 355 | pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> { | ||
| 356 | self.transfer_inner(rx_buffer, tx_buffer).await | ||
| 357 | } | ||
| 358 | |||
| 359 | pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { | ||
| 360 | self.transfer_inner(words, words).await | ||
| 361 | } | ||
| 362 | |||
| 363 | async fn transfer_inner(&mut self, rx_ptr: *mut [u8], tx_ptr: *const [u8]) -> Result<(), Error> { | ||
| 364 | let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); | ||
| 365 | let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); | ||
| 366 | assert_eq!(from_len, to_len); | ||
| 367 | let tx_ch = self.tx_dma.as_mut().unwrap(); | ||
| 368 | let tx_transfer = unsafe { | ||
| 369 | self.inner.regs().dmacr().modify(|reg| { | ||
| 370 | reg.set_txdmae(true); | ||
| 371 | }); | ||
| 372 | // If we don't assign future to a variable, the data register pointer | ||
| 373 | // is held across an await and makes the future non-Send. | ||
| 374 | crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | ||
| 375 | }; | ||
| 376 | let rx_ch = self.rx_dma.as_mut().unwrap(); | ||
| 377 | let rx_transfer = unsafe { | ||
| 378 | self.inner.regs().dmacr().modify(|reg| { | ||
| 379 | reg.set_rxdmae(true); | ||
| 380 | }); | ||
| 381 | // If we don't assign future to a variable, the data register pointer | ||
| 382 | // is held across an await and makes the future non-Send. | ||
| 383 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) | ||
| 384 | }; | ||
| 385 | join(tx_transfer, rx_transfer).await; | ||
| 386 | Ok(()) | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 228 | mod sealed { | 390 | mod sealed { |
| 229 | use super::*; | 391 | use super::*; |
| 230 | 392 | ||
| 393 | pub trait Mode {} | ||
| 394 | |||
| 231 | pub trait Instance { | 395 | pub trait Instance { |
| 396 | const TX_DREQ: u8; | ||
| 397 | const RX_DREQ: u8; | ||
| 398 | |||
| 232 | fn regs(&self) -> pac::spi::Spi; | 399 | fn regs(&self) -> pac::spi::Spi; |
| 233 | } | 400 | } |
| 234 | } | 401 | } |
| 235 | 402 | ||
| 403 | pub trait Mode: sealed::Mode {} | ||
| 236 | pub trait Instance: sealed::Instance {} | 404 | pub trait Instance: sealed::Instance {} |
| 237 | 405 | ||
| 238 | macro_rules! impl_instance { | 406 | macro_rules! impl_instance { |
| 239 | ($type:ident, $irq:ident) => { | 407 | ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { |
| 240 | impl sealed::Instance for peripherals::$type { | 408 | impl sealed::Instance for peripherals::$type { |
| 409 | const TX_DREQ: u8 = $tx_dreq; | ||
| 410 | const RX_DREQ: u8 = $rx_dreq; | ||
| 411 | |||
| 241 | fn regs(&self) -> pac::spi::Spi { | 412 | fn regs(&self) -> pac::spi::Spi { |
| 242 | pac::$type | 413 | pac::$type |
| 243 | } | 414 | } |
| @@ -246,8 +417,8 @@ macro_rules! impl_instance { | |||
| 246 | }; | 417 | }; |
| 247 | } | 418 | } |
| 248 | 419 | ||
| 249 | impl_instance!(SPI0, Spi0); | 420 | impl_instance!(SPI0, Spi0, 16, 17); |
| 250 | impl_instance!(SPI1, Spi1); | 421 | impl_instance!(SPI1, Spi1, 18, 19); |
| 251 | 422 | ||
| 252 | pub trait ClkPin<T: Instance>: GpioPin {} | 423 | pub trait ClkPin<T: Instance>: GpioPin {} |
| 253 | pub trait CsPin<T: Instance>: GpioPin {} | 424 | pub trait CsPin<T: Instance>: GpioPin {} |
| @@ -281,12 +452,25 @@ impl_pin!(PIN_17, SPI0, CsPin); | |||
| 281 | impl_pin!(PIN_18, SPI0, ClkPin); | 452 | impl_pin!(PIN_18, SPI0, ClkPin); |
| 282 | impl_pin!(PIN_19, SPI0, MosiPin); | 453 | impl_pin!(PIN_19, SPI0, MosiPin); |
| 283 | 454 | ||
| 455 | macro_rules! impl_mode { | ||
| 456 | ($name:ident) => { | ||
| 457 | impl sealed::Mode for $name {} | ||
| 458 | impl Mode for $name {} | ||
| 459 | }; | ||
| 460 | } | ||
| 461 | |||
| 462 | pub struct Blocking; | ||
| 463 | pub struct Async; | ||
| 464 | |||
| 465 | impl_mode!(Blocking); | ||
| 466 | impl_mode!(Async); | ||
| 467 | |||
| 284 | // ==================== | 468 | // ==================== |
| 285 | 469 | ||
| 286 | mod eh02 { | 470 | mod eh02 { |
| 287 | use super::*; | 471 | use super::*; |
| 288 | 472 | ||
| 289 | impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, T> { | 473 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, T, M> { |
| 290 | type Error = Error; | 474 | type Error = Error; |
| 291 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { | 475 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { |
| 292 | self.blocking_transfer_in_place(words)?; | 476 | self.blocking_transfer_in_place(words)?; |
| @@ -294,7 +478,7 @@ mod eh02 { | |||
| 294 | } | 478 | } |
| 295 | } | 479 | } |
| 296 | 480 | ||
| 297 | impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, T> { | 481 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, T, M> { |
| 298 | type Error = Error; | 482 | type Error = Error; |
| 299 | 483 | ||
| 300 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { | 484 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { |
| @@ -313,29 +497,29 @@ mod eh1 { | |||
| 313 | } | 497 | } |
| 314 | } | 498 | } |
| 315 | 499 | ||
| 316 | impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spi<'d, T> { | 500 | impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> { |
| 317 | type Error = Error; | 501 | type Error = Error; |
| 318 | } | 502 | } |
| 319 | 503 | ||
| 320 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusFlush for Spi<'d, T> { | 504 | impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusFlush for Spi<'d, T, M> { |
| 321 | fn flush(&mut self) -> Result<(), Self::Error> { | 505 | fn flush(&mut self) -> Result<(), Self::Error> { |
| 322 | Ok(()) | 506 | Ok(()) |
| 323 | } | 507 | } |
| 324 | } | 508 | } |
| 325 | 509 | ||
| 326 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusRead<u8> for Spi<'d, T> { | 510 | impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusRead<u8> for Spi<'d, T, M> { |
| 327 | fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { | 511 | fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { |
| 328 | self.blocking_transfer(words, &[]) | 512 | self.blocking_transfer(words, &[]) |
| 329 | } | 513 | } |
| 330 | } | 514 | } |
| 331 | 515 | ||
| 332 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusWrite<u8> for Spi<'d, T> { | 516 | impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusWrite<u8> for Spi<'d, T, M> { |
| 333 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { | 517 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { |
| 334 | self.blocking_write(words) | 518 | self.blocking_write(words) |
| 335 | } | 519 | } |
| 336 | } | 520 | } |
| 337 | 521 | ||
| 338 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBus<u8> for Spi<'d, T> { | 522 | impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBus<u8> for Spi<'d, T, M> { |
| 339 | fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { | 523 | fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { |
| 340 | self.blocking_transfer(read, write) | 524 | self.blocking_transfer(read, write) |
| 341 | } | 525 | } |
| @@ -346,7 +530,52 @@ mod eh1 { | |||
| 346 | } | 530 | } |
| 347 | } | 531 | } |
| 348 | 532 | ||
| 349 | impl<'d, T: Instance> SetConfig for Spi<'d, T> { | 533 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] |
| 534 | mod eha { | ||
| 535 | use core::future::Future; | ||
| 536 | |||
| 537 | use super::*; | ||
| 538 | |||
| 539 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Async> { | ||
| 540 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 541 | |||
| 542 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 543 | async { Ok(()) } | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spi<'d, T, Async> { | ||
| 548 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 549 | |||
| 550 | fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 551 | self.write(data) | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spi<'d, T, Async> { | ||
| 556 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 557 | |||
| 558 | fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 559 | self.read(data) | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> { | ||
| 564 | type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 565 | |||
| 566 | fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> { | ||
| 567 | self.transfer(rx, tx) | ||
| 568 | } | ||
| 569 | |||
| 570 | type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 571 | |||
| 572 | fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> { | ||
| 573 | self.transfer_in_place(words) | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> { | ||
| 350 | type Config = Config; | 579 | type Config = Config; |
| 351 | fn set_config(&mut self, config: &Self::Config) { | 580 | fn set_config(&mut self, config: &Self::Config) { |
| 352 | let p = self.inner.regs(); | 581 | let p = self.inner.regs(); |
diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs index 88003ee17..a830a17a2 100644 --- a/examples/rp/src/bin/spi.rs +++ b/examples/rp/src/bin/spi.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | // create SPI | 24 | // create SPI |
| 25 | let mut config = spi::Config::default(); | 25 | let mut config = spi::Config::default(); |
| 26 | config.frequency = 2_000_000; | 26 | config.frequency = 2_000_000; |
| 27 | let mut spi = Spi::new(p.SPI1, clk, mosi, miso, config); | 27 | let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); |
| 28 | 28 | ||
| 29 | // Configure CS | 29 | // Configure CS |
| 30 | let mut cs = Output::new(touch_cs, Level::Low); | 30 | let mut cs = Output::new(touch_cs, Level::Low); |
diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs new file mode 100644 index 000000000..671a9caaf --- /dev/null +++ b/examples/rp/src/bin/spi_async.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::spi::{Config, Spi}; | ||
| 8 | use embassy_time::{Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let p = embassy_rp::init(Default::default()); | ||
| 14 | info!("Hello World!"); | ||
| 15 | |||
| 16 | let miso = p.PIN_12; | ||
| 17 | let mosi = p.PIN_11; | ||
| 18 | let clk = p.PIN_10; | ||
| 19 | |||
| 20 | let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); | ||
| 21 | |||
| 22 | loop { | ||
| 23 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 24 | let mut rx_buf = [0_u8; 6]; | ||
| 25 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 26 | info!("{:?}", rx_buf); | ||
| 27 | Timer::after(Duration::from_secs(1)).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index f0e54d87f..23cd4355e 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs | |||
| @@ -8,7 +8,7 @@ use defmt::*; | |||
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_rp::gpio::{Level, Output}; | 9 | use embassy_rp::gpio::{Level, Output}; |
| 10 | use embassy_rp::spi; | 10 | use embassy_rp::spi; |
| 11 | use embassy_rp::spi::Spi; | 11 | use embassy_rp::spi::{Blocking, Spi}; |
| 12 | use embassy_time::Delay; | 12 | use embassy_time::Delay; |
| 13 | use embedded_graphics::image::{Image, ImageRawLE}; | 13 | use embedded_graphics::image::{Image, ImageRawLE}; |
| 14 | use embedded_graphics::mono_font::ascii::FONT_10X20; | 14 | use embedded_graphics::mono_font::ascii::FONT_10X20; |
| @@ -48,7 +48,8 @@ async fn main(_spawner: Spawner) { | |||
| 48 | config.phase = spi::Phase::CaptureOnSecondTransition; | 48 | config.phase = spi::Phase::CaptureOnSecondTransition; |
| 49 | config.polarity = spi::Polarity::IdleHigh; | 49 | config.polarity = spi::Polarity::IdleHigh; |
| 50 | 50 | ||
| 51 | let spi_bus = RefCell::new(Spi::new(p.SPI1, clk, mosi, miso, config)); | 51 | let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); |
| 52 | let spi_bus = RefCell::new(spi); | ||
| 52 | 53 | ||
| 53 | let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); | 54 | let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); |
| 54 | let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); | 55 | let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); |
diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs new file mode 100644 index 000000000..478d62ee0 --- /dev/null +++ b/tests/rp/src/bin/spi.rs | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::spi::{Config, Spi}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_rp::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let clk = p.PIN_2; | ||
| 16 | let mosi = p.PIN_3; | ||
| 17 | let miso = p.PIN_4; | ||
| 18 | |||
| 19 | let mut spi = Spi::new_blocking(p.SPI0, clk, mosi, miso, Config::default()); | ||
| 20 | |||
| 21 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 22 | let mut rx_buf = [0_u8; 6]; | ||
| 23 | spi.blocking_transfer(&mut rx_buf, &tx_buf).unwrap(); | ||
| 24 | assert_eq!(rx_buf, tx_buf); | ||
| 25 | |||
| 26 | info!("Test OK"); | ||
| 27 | cortex_m::asm::bkpt(); | ||
| 28 | } | ||
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs new file mode 100644 index 000000000..6c85ef60a --- /dev/null +++ b/tests/rp/src/bin/spi_async.rs | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::spi::{Config, Spi}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_rp::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let clk = p.PIN_2; | ||
| 16 | let mosi = p.PIN_3; | ||
| 17 | let miso = p.PIN_4; | ||
| 18 | |||
| 19 | let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); | ||
| 20 | |||
| 21 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 22 | let mut rx_buf = [0_u8; 6]; | ||
| 23 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 24 | assert_eq!(rx_buf, tx_buf); | ||
| 25 | |||
| 26 | info!("Test OK"); | ||
| 27 | cortex_m::asm::bkpt(); | ||
| 28 | } | ||
