diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-03-21 19:56:57 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-03-21 19:56:57 +0100 |
| commit | 33cbc22236634753340392adadd943acb31bd5e2 (patch) | |
| tree | 87b4e1ab2b4ec5e46790d4533bd31270cff74e55 /src | |
| parent | 0e946dfb203dcf1ca3f165ffb06f3f58d4eaa119 (diff) | |
| parent | 359b1c7fdb246c125e0b835eb58283a8a9a6a946 (diff) | |
Merge pull request #39 from kbleeke/pio
Use PIO for SPI communication in Pico W example
Diffstat (limited to 'src')
| -rw-r--r-- | src/bus.rs | 141 | ||||
| -rw-r--r-- | src/lib.rs | 11 |
2 files changed, 71 insertions, 81 deletions
diff --git a/src/bus.rs b/src/bus.rs index f64c0abba..f77b890df 100644 --- a/src/bus.rs +++ b/src/bus.rs | |||
| @@ -2,10 +2,25 @@ 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_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice}; | 5 | use futures::FutureExt; |
| 6 | 6 | ||
| 7 | use crate::consts::*; | 7 | use crate::consts::*; |
| 8 | 8 | ||
| 9 | /// Custom Spi Trait that _only_ supports the bus operation of the cyw43 | ||
| 10 | /// Implementors are expected to hold the CS pin low during an operation. | ||
| 11 | pub trait SpiBusCyw43 { | ||
| 12 | /// Issues a write command on the bus | ||
| 13 | /// First 32 bits of `word` are expected to be a cmd word | ||
| 14 | async fn cmd_write(&mut self, write: &[u32]); | ||
| 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 | /// Backplane reads have a response delay that produces one extra unspecified word at the beginning of `read`. | ||
| 20 | /// Callers that want to read `n` word from the backplane, have to provide a slice that is `n+1` words long. | ||
| 21 | async fn cmd_read(&mut self, write: u32, read: &mut [u32]); | ||
| 22 | } | ||
| 23 | |||
| 9 | pub(crate) struct Bus<PWR, SPI> { | 24 | pub(crate) struct Bus<PWR, SPI> { |
| 10 | backplane_window: u32, | 25 | backplane_window: u32, |
| 11 | pwr: PWR, | 26 | pwr: PWR, |
| @@ -15,8 +30,7 @@ pub(crate) struct Bus<PWR, SPI> { | |||
| 15 | impl<PWR, SPI> Bus<PWR, SPI> | 30 | impl<PWR, SPI> Bus<PWR, SPI> |
| 16 | where | 31 | where |
| 17 | PWR: OutputPin, | 32 | PWR: OutputPin, |
| 18 | SPI: SpiDevice, | 33 | SPI: SpiBusCyw43, |
| 19 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | ||
| 20 | { | 34 | { |
| 21 | pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { | 35 | pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { |
| 22 | Self { | 36 | Self { |
| @@ -33,42 +47,50 @@ where | |||
| 33 | self.pwr.set_high().unwrap(); | 47 | self.pwr.set_high().unwrap(); |
| 34 | Timer::after(Duration::from_millis(250)).await; | 48 | Timer::after(Duration::from_millis(250)).await; |
| 35 | 49 | ||
| 36 | while self.read32_swapped(REG_BUS_TEST_RO).await != FEEDBEAD {} | 50 | while self |
| 51 | .read32_swapped(REG_BUS_TEST_RO) | ||
| 52 | .inspect(|v| defmt::trace!("{:#x}", v)) | ||
| 53 | .await | ||
| 54 | != FEEDBEAD | ||
| 55 | {} | ||
| 37 | 56 | ||
| 38 | self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; | 57 | self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; |
| 39 | let val = self.read32_swapped(REG_BUS_TEST_RW).await; | 58 | let val = self.read32_swapped(REG_BUS_TEST_RW).await; |
| 59 | defmt::trace!("{:#x}", val); | ||
| 40 | assert_eq!(val, TEST_PATTERN); | 60 | assert_eq!(val, TEST_PATTERN); |
| 41 | 61 | ||
| 62 | let val = self.read32_swapped(REG_BUS_CTRL).await; | ||
| 63 | defmt::trace!("{:#010b}", (val & 0xff)); | ||
| 64 | |||
| 42 | // 32-bit word length, little endian (which is the default endianess). | 65 | // 32-bit word length, little endian (which is the default endianess). |
| 43 | self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await; | 66 | self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await; |
| 44 | 67 | ||
| 68 | let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; | ||
| 69 | defmt::trace!("{:#b}", val); | ||
| 70 | |||
| 45 | let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; | 71 | let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; |
| 72 | defmt::trace!("{:#x}", val); | ||
| 46 | assert_eq!(val, FEEDBEAD); | 73 | assert_eq!(val, FEEDBEAD); |
| 47 | let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; | 74 | let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; |
| 75 | defmt::trace!("{:#x}", val); | ||
| 48 | assert_eq!(val, TEST_PATTERN); | 76 | assert_eq!(val, TEST_PATTERN); |
| 49 | } | 77 | } |
| 50 | 78 | ||
| 51 | pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { | 79 | pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { |
| 52 | let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); | 80 | 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; | 81 | let len_in_u32 = (len_in_u8 as usize + 3) / 4; |
| 54 | transaction!(&mut self.spi, |bus| async { | 82 | |
| 55 | bus.write(&[cmd]).await?; | 83 | self.spi.cmd_read(cmd, &mut buf[..len_in_u32]).await; |
| 56 | bus.read(&mut buf[..len_in_u32]).await?; | ||
| 57 | Ok(()) | ||
| 58 | }) | ||
| 59 | .await | ||
| 60 | .unwrap(); | ||
| 61 | } | 84 | } |
| 62 | 85 | ||
| 63 | pub async fn wlan_write(&mut self, buf: &[u32]) { | 86 | 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); | 87 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); |
| 65 | transaction!(&mut self.spi, |bus| async { | 88 | //TODO try to remove copy? |
| 66 | bus.write(&[cmd]).await?; | 89 | let mut cmd_buf = [0_u32; 513]; |
| 67 | bus.write(buf).await?; | 90 | cmd_buf[0] = cmd; |
| 68 | Ok(()) | 91 | cmd_buf[1..][..buf.len()].copy_from_slice(buf); |
| 69 | }) | 92 | |
| 70 | .await | 93 | self.spi.cmd_write(&cmd_buf).await; |
| 71 | .unwrap(); | ||
| 72 | } | 94 | } |
| 73 | 95 | ||
| 74 | #[allow(unused)] | 96 | #[allow(unused)] |
| @@ -79,7 +101,8 @@ where | |||
| 79 | // To simplify, enforce 4-align for now. | 101 | // To simplify, enforce 4-align for now. |
| 80 | assert!(addr % 4 == 0); | 102 | assert!(addr % 4 == 0); |
| 81 | 103 | ||
| 82 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; | 104 | // Backplane read buffer has one extra word for the response delay. |
| 105 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; | ||
| 83 | 106 | ||
| 84 | while !data.is_empty() { | 107 | while !data.is_empty() { |
| 85 | // Ensure transfer doesn't cross a window boundary. | 108 | // Ensure transfer doesn't cross a window boundary. |
| @@ -92,21 +115,11 @@ where | |||
| 92 | 115 | ||
| 93 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); | 116 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); |
| 94 | 117 | ||
| 95 | transaction!(&mut self.spi, |bus| async { | 118 | // round `buf` to word boundary, add one extra word for the response delay |
| 96 | bus.write(&[cmd]).await?; | 119 | self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await; |
| 97 | 120 | ||
| 98 | // 4-byte response delay. | 121 | // when writing out the data, we skip the response-delay byte |
| 99 | let mut junk = [0; 1]; | 122 | data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); |
| 100 | bus.read(&mut junk).await?; | ||
| 101 | |||
| 102 | // Read data | ||
| 103 | bus.read(&mut buf[..(len + 3) / 4]).await?; | ||
| 104 | Ok(()) | ||
| 105 | }) | ||
| 106 | .await | ||
| 107 | .unwrap(); | ||
| 108 | |||
| 109 | data[..len].copy_from_slice(&slice8_mut(&mut buf)[..len]); | ||
| 110 | 123 | ||
| 111 | // Advance ptr. | 124 | // Advance ptr. |
| 112 | addr += len as u32; | 125 | addr += len as u32; |
| @@ -121,7 +134,7 @@ where | |||
| 121 | // To simplify, enforce 4-align for now. | 134 | // To simplify, enforce 4-align for now. |
| 122 | assert!(addr % 4 == 0); | 135 | assert!(addr % 4 == 0); |
| 123 | 136 | ||
| 124 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; | 137 | let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; |
| 125 | 138 | ||
| 126 | while !data.is_empty() { | 139 | while !data.is_empty() { |
| 127 | // Ensure transfer doesn't cross a window boundary. | 140 | // Ensure transfer doesn't cross a window boundary. |
| @@ -129,19 +142,14 @@ where | |||
| 129 | let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; | 142 | let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; |
| 130 | 143 | ||
| 131 | let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); | 144 | let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); |
| 132 | slice8_mut(&mut buf)[..len].copy_from_slice(&data[..len]); | 145 | slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]); |
| 133 | 146 | ||
| 134 | self.backplane_set_window(addr).await; | 147 | self.backplane_set_window(addr).await; |
| 135 | 148 | ||
| 136 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); | 149 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); |
| 150 | buf[0] = cmd; | ||
| 137 | 151 | ||
| 138 | transaction!(&mut self.spi, |bus| async { | 152 | self.spi.cmd_write(&buf[..(len + 3) / 4 + 1]).await; |
| 139 | bus.write(&[cmd]).await?; | ||
| 140 | bus.write(&buf[..(len + 3) / 4]).await?; | ||
| 141 | Ok(()) | ||
| 142 | }) | ||
| 143 | .await | ||
| 144 | .unwrap(); | ||
| 145 | 153 | ||
| 146 | // Advance ptr. | 154 | // Advance ptr. |
| 147 | addr += len as u32; | 155 | addr += len as u32; |
| @@ -253,58 +261,41 @@ where | |||
| 253 | 261 | ||
| 254 | async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { | 262 | async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { |
| 255 | let cmd = cmd_word(READ, INC_ADDR, func, addr, len); | 263 | let cmd = cmd_word(READ, INC_ADDR, func, addr, len); |
| 256 | let mut buf = [0; 1]; | 264 | let mut buf = [0; 2]; |
| 265 | // if we are reading from the backplane, we need an extra word for the response delay | ||
| 266 | let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; | ||
| 267 | |||
| 268 | self.spi.cmd_read(cmd, &mut buf[..len]).await; | ||
| 257 | 269 | ||
| 258 | transaction!(&mut self.spi, |bus| async { | 270 | // if we read from the backplane, the result is in the second word, after the response delay |
| 259 | bus.write(&[cmd]).await?; | 271 | if func == FUNC_BACKPLANE { |
| 260 | if func == FUNC_BACKPLANE { | 272 | buf[1] |
| 261 | // 4-byte response delay. | 273 | } else { |
| 262 | bus.read(&mut buf).await?; | 274 | buf[0] |
| 263 | } | 275 | } |
| 264 | bus.read(&mut buf).await?; | ||
| 265 | Ok(()) | ||
| 266 | }) | ||
| 267 | .await | ||
| 268 | .unwrap(); | ||
| 269 | |||
| 270 | buf[0] | ||
| 271 | } | 276 | } |
| 272 | 277 | ||
| 273 | async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { | 278 | async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { |
| 274 | let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); | 279 | let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); |
| 275 | 280 | ||
| 276 | transaction!(&mut self.spi, |bus| async { | 281 | self.spi.cmd_write(&[cmd, val]).await; |
| 277 | bus.write(&[cmd, val]).await?; | ||
| 278 | Ok(()) | ||
| 279 | }) | ||
| 280 | .await | ||
| 281 | .unwrap(); | ||
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | async fn read32_swapped(&mut self, addr: u32) -> u32 { | 284 | async fn read32_swapped(&mut self, addr: u32) -> u32 { |
| 285 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); | 285 | let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); |
| 286 | let cmd = swap16(cmd); | ||
| 286 | let mut buf = [0; 1]; | 287 | let mut buf = [0; 1]; |
| 287 | 288 | ||
| 288 | transaction!(&mut self.spi, |bus| async { | 289 | self.spi.cmd_read(cmd, &mut buf).await; |
| 289 | bus.write(&[swap16(cmd)]).await?; | ||
| 290 | bus.read(&mut buf).await?; | ||
| 291 | Ok(()) | ||
| 292 | }) | ||
| 293 | .await | ||
| 294 | .unwrap(); | ||
| 295 | 290 | ||
| 296 | swap16(buf[0]) | 291 | swap16(buf[0]) |
| 297 | } | 292 | } |
| 298 | 293 | ||
| 299 | async fn write32_swapped(&mut self, addr: u32, val: u32) { | 294 | async fn write32_swapped(&mut self, addr: u32, val: u32) { |
| 300 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); | 295 | let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); |
| 296 | let buf = [swap16(cmd), swap16(val)]; | ||
| 301 | 297 | ||
| 302 | transaction!(&mut self.spi, |bus| async { | 298 | self.spi.cmd_write(&buf).await; |
| 303 | bus.write(&[swap16(cmd), swap16(val)]).await?; | ||
| 304 | Ok(()) | ||
| 305 | }) | ||
| 306 | .await | ||
| 307 | .unwrap(); | ||
| 308 | } | 299 | } |
| 309 | } | 300 | } |
| 310 | 301 | ||
diff --git a/src/lib.rs b/src/lib.rs index c58ac8e7d..1b7d603d7 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. |
| @@ -22,10 +23,10 @@ use embassy_net_driver_channel as ch; | |||
| 22 | use embassy_sync::pubsub::PubSubBehavior; | 23 | use embassy_sync::pubsub::PubSubBehavior; |
| 23 | use embassy_time::{block_for, Duration, Timer}; | 24 | use embassy_time::{block_for, Duration, Timer}; |
| 24 | use embedded_hal_1::digital::OutputPin; | 25 | use embedded_hal_1::digital::OutputPin; |
| 25 | use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice}; | ||
| 26 | use events::EventQueue; | 26 | use events::EventQueue; |
| 27 | 27 | ||
| 28 | use crate::bus::Bus; | 28 | use crate::bus::Bus; |
| 29 | pub use crate::bus::SpiBusCyw43; | ||
| 29 | use crate::consts::*; | 30 | use crate::consts::*; |
| 30 | use crate::events::{Event, EventStatus}; | 31 | use crate::events::{Event, EventStatus}; |
| 31 | use crate::structs::*; | 32 | use crate::structs::*; |
| @@ -533,8 +534,7 @@ pub async fn new<'a, PWR, SPI>( | |||
| 533 | ) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) | 534 | ) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) |
| 534 | where | 535 | where |
| 535 | PWR: OutputPin, | 536 | PWR: OutputPin, |
| 536 | SPI: SpiDevice, | 537 | SPI: SpiBusCyw43, |
| 537 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | ||
| 538 | { | 538 | { |
| 539 | let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); | 539 | let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); |
| 540 | let state_ch = ch_runner.state_runner(); | 540 | let state_ch = ch_runner.state_runner(); |
| @@ -575,8 +575,7 @@ where | |||
| 575 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> | 575 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> |
| 576 | where | 576 | where |
| 577 | PWR: OutputPin, | 577 | PWR: OutputPin, |
| 578 | SPI: SpiDevice, | 578 | SPI: SpiBusCyw43, |
| 579 | SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>, | ||
| 580 | { | 579 | { |
| 581 | async fn init(&mut self, firmware: &[u8]) { | 580 | async fn init(&mut self, firmware: &[u8]) { |
| 582 | self.bus.init().await; | 581 | self.bus.init().await; |
