diff options
| author | kbleeke <[email protected]> | 2023-02-19 16:31:33 +0100 |
|---|---|---|
| committer | kbleeke <[email protected]> | 2023-03-19 16:57:54 +0100 |
| commit | d57fe0de867cfc6510f0192fab488355d9ae8586 (patch) | |
| tree | 08a59192f1dbba10000759cb2d473178beefda00 | |
| parent | e33b99e9ec9902d6f93582530fd9cfe38953ce69 (diff) | |
Custom Bus Trait to support PIO
| -rw-r--r-- | examples/rpi-pico-w/build.rs | 34 | ||||
| -rw-r--r-- | examples/rpi-pico-w/src/main.rs | 11 | ||||
| -rw-r--r-- | src/bus.rs | 100 | ||||
| -rw-r--r-- | src/lib.rs | 8 |
4 files changed, 104 insertions, 49 deletions
diff --git a/examples/rpi-pico-w/build.rs b/examples/rpi-pico-w/build.rs index 3f915f931..d4c3ec89d 100644 --- a/examples/rpi-pico-w/build.rs +++ b/examples/rpi-pico-w/build.rs | |||
| @@ -14,23 +14,23 @@ use std::io::Write; | |||
| 14 | use std::path::PathBuf; | 14 | use std::path::PathBuf; |
| 15 | 15 | ||
| 16 | fn main() { | 16 | fn main() { |
| 17 | // Put `memory.x` in our output directory and ensure it's | 17 | // // Put `memory.x` in our output directory and ensure it's |
| 18 | // on the linker search path. | 18 | // // on the linker search path. |
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | 19 | // let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| 20 | File::create(out.join("memory.x")) | 20 | // File::create(out.join("memory.x")) |
| 21 | .unwrap() | 21 | // .unwrap() |
| 22 | .write_all(include_bytes!("memory.x")) | 22 | // .write_all(include_bytes!("memory.x")) |
| 23 | .unwrap(); | 23 | // .unwrap(); |
| 24 | println!("cargo:rustc-link-search={}", out.display()); | 24 | // println!("cargo:rustc-link-search={}", out.display()); |
| 25 | 25 | ||
| 26 | // By default, Cargo will re-run a build script whenever | 26 | // // By default, Cargo will re-run a build script whenever |
| 27 | // any file in the project changes. By specifying `memory.x` | 27 | // // any file in the project changes. By specifying `memory.x` |
| 28 | // here, we ensure the build script is only re-run when | 28 | // // here, we ensure the build script is only re-run when |
| 29 | // `memory.x` is changed. | 29 | // // `memory.x` is changed. |
| 30 | println!("cargo:rerun-if-changed=memory.x"); | 30 | // println!("cargo:rerun-if-changed=memory.x"); |
| 31 | 31 | ||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | 32 | // println!("cargo:rustc-link-arg-bins=--nmagic"); |
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | 33 | // println!("cargo:rustc-link-arg-bins=-Tlink.x"); |
| 34 | println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); | 34 | // println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); |
| 35 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | 35 | // println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); |
| 36 | } | 36 | } |
diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index c706e121d..f768af193 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs | |||
| @@ -161,6 +161,17 @@ impl ErrorType for MySpi { | |||
| 161 | type Error = Infallible; | 161 | type Error = Infallible; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | impl cyw43::SpiBusCyw43<u32> for MySpi { | ||
| 165 | async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> { | ||
| 166 | self.write(write).await | ||
| 167 | } | ||
| 168 | |||
| 169 | async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> { | ||
| 170 | self.write(write).await?; | ||
| 171 | self.read(read).await | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 164 | impl SpiBusFlush for MySpi { | 175 | impl SpiBusFlush for MySpi { |
| 165 | async fn flush(&mut self) -> Result<(), Self::Error> { | 176 | async fn flush(&mut self) -> Result<(), Self::Error> { |
| 166 | Ok(()) | 177 | Ok(()) |
diff --git a/src/bus.rs b/src/bus.rs index f64c0abba..1c8bb9893 100644 --- a/src/bus.rs +++ b/src/bus.rs | |||
| @@ -2,10 +2,23 @@ use core::slice; | |||
| 2 | 2 | ||
| 3 | use embassy_time::{Duration, Timer}; | 3 | use embassy_time::{Duration, Timer}; |
| 4 | use embedded_hal_1::digital::OutputPin; | 4 | use embedded_hal_1::digital::OutputPin; |
| 5 | use embedded_hal_1::spi::ErrorType; | ||
| 5 | use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice}; | 6 | use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice}; |
| 6 | 7 | ||
| 7 | use crate::consts::*; | 8 | use crate::consts::*; |
| 8 | 9 | ||
| 10 | /// Custom Spi Trait that _only_ supports the bus operation of the cyw43 | ||
| 11 | pub trait SpiBusCyw43<Word: 'static + Copy>: ErrorType { | ||
| 12 | /// Issues a write command on the bus | ||
| 13 | /// Frist 32 bits of `word` are expected to be a cmd word | ||
| 14 | async fn cmd_write<'a>(&'a mut self, write: &'a [Word]) -> Result<(), Self::Error>; | ||
| 15 | |||
| 16 | /// Issues a read command on the bus | ||
| 17 | /// `write` is expected to be a 32 bit cmd word | ||
| 18 | /// `read` will contain the response of the device | ||
| 19 | async fn cmd_read<'a>(&'a mut self, write: &'a [Word], read: &'a mut [Word]) -> Result<(), Self::Error>; | ||
| 20 | } | ||
| 21 | |||
| 9 | pub(crate) struct Bus<PWR, SPI> { | 22 | pub(crate) struct Bus<PWR, SPI> { |
| 10 | backplane_window: u32, | 23 | backplane_window: u32, |
| 11 | pwr: PWR, | 24 | pwr: PWR, |
| @@ -16,7 +29,7 @@ impl<PWR, SPI> Bus<PWR, SPI> | |||
| 16 | where | 29 | where |
| 17 | PWR: OutputPin, | 30 | PWR: OutputPin, |
| 18 | SPI: SpiDevice, | 31 | SPI: SpiDevice, |
| 19 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | 32 | SPI::Bus: SpiBusCyw43<u32>, |
| 20 | { | 33 | { |
| 21 | pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { | 34 | pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { |
| 22 | Self { | 35 | Self { |
| @@ -52,8 +65,9 @@ where | |||
| 52 | let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); | 65 | let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); |
| 53 | let len_in_u32 = (len_in_u8 as usize + 3) / 4; | 66 | let len_in_u32 = (len_in_u8 as usize + 3) / 4; |
| 54 | transaction!(&mut self.spi, |bus| async { | 67 | transaction!(&mut self.spi, |bus| async { |
| 55 | bus.write(&[cmd]).await?; | 68 | // bus.write(&[cmd]).await?; |
| 56 | bus.read(&mut buf[..len_in_u32]).await?; | 69 | // bus.read(&mut buf[..len_in_u32]).await?; |
| 70 | bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len_in_u32]).await?; | ||
| 57 | Ok(()) | 71 | Ok(()) |
| 58 | }) | 72 | }) |
| 59 | .await | 73 | .await |
| @@ -62,9 +76,16 @@ where | |||
| 62 | 76 | ||
| 63 | pub async fn wlan_write(&mut self, buf: &[u32]) { | 77 | pub async fn wlan_write(&mut self, buf: &[u32]) { |
| 64 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); | 78 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); |
| 79 | //TODO try to remove copy? | ||
| 80 | let mut cmd_buf = [0_u32; 513]; | ||
| 81 | cmd_buf[0] = cmd; | ||
| 82 | cmd_buf[1..][..buf.len()].copy_from_slice(buf); | ||
| 83 | |||
| 65 | transaction!(&mut self.spi, |bus| async { | 84 | transaction!(&mut self.spi, |bus| async { |
| 66 | bus.write(&[cmd]).await?; | 85 | // bus.write(&[cmd]).await?; |
| 67 | bus.write(buf).await?; | 86 | // bus.write(buf).await?; |
| 87 | |||
| 88 | bus.cmd_write(&cmd_buf).await?; | ||
| 68 | Ok(()) | 89 | Ok(()) |
| 69 | }) | 90 | }) |
| 70 | .await | 91 | .await |
| @@ -79,7 +100,7 @@ where | |||
| 79 | // To simplify, enforce 4-align for now. | 100 | // To simplify, enforce 4-align for now. |
| 80 | assert!(addr % 4 == 0); | 101 | assert!(addr % 4 == 0); |
| 81 | 102 | ||
| 82 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; | 103 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; |
| 83 | 104 | ||
| 84 | while !data.is_empty() { | 105 | while !data.is_empty() { |
| 85 | // Ensure transfer doesn't cross a window boundary. | 106 | // Ensure transfer doesn't cross a window boundary. |
| @@ -93,20 +114,23 @@ where | |||
| 93 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); | 114 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); |
| 94 | 115 | ||
| 95 | transaction!(&mut self.spi, |bus| async { | 116 | transaction!(&mut self.spi, |bus| async { |
| 96 | bus.write(&[cmd]).await?; | 117 | // bus.write(&[cmd]).await?; |
| 118 | |||
| 119 | // // 4-byte response delay. | ||
| 120 | // let mut junk = [0; 1]; | ||
| 121 | // bus.read(&mut junk).await?; | ||
| 97 | 122 | ||
| 98 | // 4-byte response delay. | 123 | // // Read data |
| 99 | let mut junk = [0; 1]; | 124 | // bus.read(&mut buf[..(len + 3) / 4]).await?; |
| 100 | bus.read(&mut junk).await?; | ||
| 101 | 125 | ||
| 102 | // Read data | 126 | bus.cmd_read(slice::from_ref(&cmd), &mut buf[..(len + 3) / 4 + 1]) |
| 103 | bus.read(&mut buf[..(len + 3) / 4]).await?; | 127 | .await?; |
| 104 | Ok(()) | 128 | Ok(()) |
| 105 | }) | 129 | }) |
| 106 | .await | 130 | .await |
| 107 | .unwrap(); | 131 | .unwrap(); |
| 108 | 132 | ||
| 109 | data[..len].copy_from_slice(&slice8_mut(&mut buf)[..len]); | 133 | data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); |
| 110 | 134 | ||
| 111 | // Advance ptr. | 135 | // Advance ptr. |
| 112 | addr += len as u32; | 136 | addr += len as u32; |
| @@ -121,7 +145,7 @@ where | |||
| 121 | // To simplify, enforce 4-align for now. | 145 | // To simplify, enforce 4-align for now. |
| 122 | assert!(addr % 4 == 0); | 146 | assert!(addr % 4 == 0); |
| 123 | 147 | ||
| 124 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; | 148 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; |
| 125 | 149 | ||
| 126 | while !data.is_empty() { | 150 | while !data.is_empty() { |
| 127 | // Ensure transfer doesn't cross a window boundary. | 151 | // Ensure transfer doesn't cross a window boundary. |
| @@ -129,15 +153,19 @@ where | |||
| 129 | let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; | 153 | let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; |
| 130 | 154 | ||
| 131 | let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); | 155 | let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); |
| 132 | slice8_mut(&mut buf)[..len].copy_from_slice(&data[..len]); | 156 | slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]); |
| 133 | 157 | ||
| 134 | self.backplane_set_window(addr).await; | 158 | self.backplane_set_window(addr).await; |
| 135 | 159 | ||
| 136 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); | 160 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); |
| 161 | buf[0] = cmd; | ||
| 137 | 162 | ||
| 138 | transaction!(&mut self.spi, |bus| async { | 163 | transaction!(&mut self.spi, |bus| async { |
| 139 | bus.write(&[cmd]).await?; | 164 | // bus.write(&[cmd]).await?; |
| 140 | bus.write(&buf[..(len + 3) / 4]).await?; | 165 | // bus.write(&buf[..(len + 3) / 4]).await?; |
| 166 | |||
| 167 | bus.cmd_write(&buf[..(len + 3) / 4 + 1]).await?; | ||
| 168 | |||
| 141 | Ok(()) | 169 | Ok(()) |
| 142 | }) | 170 | }) |
| 143 | .await | 171 | .await |
| @@ -253,28 +281,36 @@ where | |||
| 253 | 281 | ||
| 254 | async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { | 282 | async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { |
| 255 | let cmd = cmd_word(READ, INC_ADDR, func, addr, len); | 283 | let cmd = cmd_word(READ, INC_ADDR, func, addr, len); |
| 256 | let mut buf = [0; 1]; | 284 | let mut buf = [0; 2]; |
| 285 | let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; | ||
| 257 | 286 | ||
| 258 | transaction!(&mut self.spi, |bus| async { | 287 | transaction!(&mut self.spi, |bus| async { |
| 259 | bus.write(&[cmd]).await?; | 288 | // bus.write(&[cmd]).await?; |
| 260 | if func == FUNC_BACKPLANE { | 289 | // if func == FUNC_BACKPLANE { |
| 261 | // 4-byte response delay. | 290 | // // 4-byte response delay. |
| 262 | bus.read(&mut buf).await?; | 291 | // bus.read(&mut buf).await?; |
| 263 | } | 292 | // } |
| 264 | bus.read(&mut buf).await?; | 293 | // bus.read(&mut buf).await?; |
| 294 | |||
| 295 | bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len]).await?; | ||
| 265 | Ok(()) | 296 | Ok(()) |
| 266 | }) | 297 | }) |
| 267 | .await | 298 | .await |
| 268 | .unwrap(); | 299 | .unwrap(); |
| 269 | 300 | ||
| 270 | buf[0] | 301 | if func == FUNC_BACKPLANE { |
| 302 | buf[1] | ||
| 303 | } else { | ||
| 304 | buf[0] | ||
| 305 | } | ||
| 271 | } | 306 | } |
| 272 | 307 | ||
| 273 | async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { | 308 | async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { |
| 274 | let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); | 309 | let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); |
| 275 | 310 | ||
| 276 | transaction!(&mut self.spi, |bus| async { | 311 | transaction!(&mut self.spi, |bus| async { |
| 277 | bus.write(&[cmd, val]).await?; | 312 | // bus.write(&[cmd, val]).await?; |
| 313 | bus.cmd_write(&[cmd, val]).await?; | ||
| 278 | Ok(()) | 314 | Ok(()) |
| 279 | }) | 315 | }) |
| 280 | .await | 316 | .await |
| @@ -283,11 +319,14 @@ where | |||
| 283 | 319 | ||
| 284 | async fn read32_swapped(&mut self, addr: u32) -> u32 { | 320 | async fn read32_swapped(&mut self, addr: u32) -> u32 { |
| 285 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); | 321 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); |
| 322 | let cmd = swap16(cmd); | ||
| 286 | let mut buf = [0; 1]; | 323 | let mut buf = [0; 1]; |
| 287 | 324 | ||
| 288 | transaction!(&mut self.spi, |bus| async { | 325 | transaction!(&mut self.spi, |bus| async { |
| 289 | bus.write(&[swap16(cmd)]).await?; | 326 | // bus.write(&[swap16(cmd)]).await?; |
| 290 | bus.read(&mut buf).await?; | 327 | // bus.read(&mut buf).await?; |
| 328 | |||
| 329 | bus.cmd_read(slice::from_ref(&cmd), &mut buf).await?; | ||
| 291 | Ok(()) | 330 | Ok(()) |
| 292 | }) | 331 | }) |
| 293 | .await | 332 | .await |
| @@ -298,9 +337,12 @@ where | |||
| 298 | 337 | ||
| 299 | async fn write32_swapped(&mut self, addr: u32, val: u32) { | 338 | async fn write32_swapped(&mut self, addr: u32, val: u32) { |
| 300 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); | 339 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); |
| 340 | let buf = [swap16(cmd), swap16(val)]; | ||
| 301 | 341 | ||
| 302 | transaction!(&mut self.spi, |bus| async { | 342 | transaction!(&mut self.spi, |bus| async { |
| 303 | bus.write(&[swap16(cmd), swap16(val)]).await?; | 343 | // bus.write(&[swap16(cmd), swap16(val)]).await?; |
| 344 | |||
| 345 | bus.cmd_write(&buf).await?; | ||
| 304 | Ok(()) | 346 | Ok(()) |
| 305 | }) | 347 | }) |
| 306 | .await | 348 | .await |
diff --git a/src/lib.rs b/src/lib.rs index 5733506ac..7bf3992cd 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait, concat_bytes)] | 3 | #![allow(incomplete_features)] |
| 4 | #![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] | ||
| 4 | #![deny(unused_must_use)] | 5 | #![deny(unused_must_use)] |
| 5 | 6 | ||
| 6 | // This mod MUST go first, so that the others see its macros. | 7 | // This mod MUST go first, so that the others see its macros. |
| @@ -24,6 +25,7 @@ use embedded_hal_1::digital::OutputPin; | |||
| 24 | use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice}; | 25 | use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice}; |
| 25 | 26 | ||
| 26 | use crate::bus::Bus; | 27 | use crate::bus::Bus; |
| 28 | pub use crate::bus::SpiBusCyw43; | ||
| 27 | use crate::consts::*; | 29 | use crate::consts::*; |
| 28 | use crate::events::Event; | 30 | use crate::events::Event; |
| 29 | use crate::structs::*; | 31 | use crate::structs::*; |
| @@ -512,7 +514,7 @@ pub async fn new<'a, PWR, SPI>( | |||
| 512 | where | 514 | where |
| 513 | PWR: OutputPin, | 515 | PWR: OutputPin, |
| 514 | SPI: SpiDevice, | 516 | SPI: SpiDevice, |
| 515 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | 517 | SPI::Bus: SpiBusCyw43<u32>, |
| 516 | { | 518 | { |
| 517 | let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); | 519 | let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); |
| 518 | let state_ch = ch_runner.state_runner(); | 520 | let state_ch = ch_runner.state_runner(); |
| @@ -551,7 +553,7 @@ impl<'a, PWR, SPI> Runner<'a, PWR, SPI> | |||
| 551 | where | 553 | where |
| 552 | PWR: OutputPin, | 554 | PWR: OutputPin, |
| 553 | SPI: SpiDevice, | 555 | SPI: SpiDevice, |
| 554 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | 556 | SPI::Bus: SpiBusCyw43<u32>, |
| 555 | { | 557 | { |
| 556 | async fn init(&mut self, firmware: &[u8]) { | 558 | async fn init(&mut self, firmware: &[u8]) { |
| 557 | self.bus.init().await; | 559 | self.bus.init().await; |
