diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-04-26 23:57:26 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-27 01:16:14 +0200 |
| commit | 009bb8e4e1b7afbe9d9d7d89135f8d4dd3c4e808 (patch) | |
| tree | d734f3e82f9fb3c22b7517a70e1f47969624d248 | |
| parent | a39d796c3de9c96ea4df6b9da525cb0d5ef60fc0 (diff) | |
stm32: add stm32u5 GPDMA, SPIv4 support, add HIL tests.
| -rwxr-xr-x | ci.sh | 1 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 16 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma.rs | 293 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 87 | ||||
| -rw-r--r-- | embassy-stm32/src/traits.rs | 14 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/blinky.rs | 29 | ||||
| m--------- | stm32-data | 0 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/data.rs | 1 | ||||
| -rw-r--r-- | stm32-metapac/src/metadata.rs | 1 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 13 | ||||
| -rw-r--r-- | tests/stm32/src/bin/gpio.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi.rs | 12 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi_dma.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_dma.rs | 2 |
16 files changed, 446 insertions, 58 deletions
| @@ -88,6 +88,7 @@ cargo batch \ | |||
| 88 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \ | 88 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \ |
| 89 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ | 89 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ |
| 90 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ | 90 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ |
| 91 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ | ||
| 91 | 92 | ||
| 92 | 93 | ||
| 93 | function run_elf { | 94 | function run_elf { |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 9125155c5..aa3e64131 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -109,7 +109,7 @@ fn main() { | |||
| 109 | 109 | ||
| 110 | for p in METADATA.peripherals { | 110 | for p in METADATA.peripherals { |
| 111 | if let Some(r) = &p.registers { | 111 | if let Some(r) = &p.registers { |
| 112 | if r.kind == "dma" || r.kind == "bdma" { | 112 | if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" { |
| 113 | if p.name == "BDMA1" { | 113 | if p.name == "BDMA1" { |
| 114 | // BDMA1 in H7 doesn't use DMAMUX, which breaks | 114 | // BDMA1 in H7 doesn't use DMAMUX, which breaks |
| 115 | continue; | 115 | continue; |
| @@ -214,7 +214,7 @@ fn main() { | |||
| 214 | // ======== | 214 | // ======== |
| 215 | // Generate fns to enable GPIO, DMA in RCC | 215 | // Generate fns to enable GPIO, DMA in RCC |
| 216 | 216 | ||
| 217 | for kind in ["dma", "bdma", "dmamux", "gpio"] { | 217 | for kind in ["dma", "bdma", "dmamux", "gpdma", "gpio"] { |
| 218 | let mut gg = TokenStream::new(); | 218 | let mut gg = TokenStream::new(); |
| 219 | 219 | ||
| 220 | for p in METADATA.peripherals { | 220 | for p in METADATA.peripherals { |
| @@ -528,11 +528,17 @@ fn main() { | |||
| 528 | let peri = format_ident!("{}", p.name); | 528 | let peri = format_ident!("{}", p.name); |
| 529 | 529 | ||
| 530 | let channel = if let Some(channel) = &ch.channel { | 530 | let channel = if let Some(channel) = &ch.channel { |
| 531 | // Chip with DMA/BDMA, without DMAMUX | ||
| 531 | let channel = format_ident!("{}", channel); | 532 | let channel = format_ident!("{}", channel); |
| 532 | quote!({channel: #channel}) | 533 | quote!({channel: #channel}) |
| 533 | } else if let Some(dmamux) = &ch.dmamux { | 534 | } else if let Some(dmamux) = &ch.dmamux { |
| 535 | // Chip with DMAMUX | ||
| 534 | let dmamux = format_ident!("{}", dmamux); | 536 | let dmamux = format_ident!("{}", dmamux); |
| 535 | quote!({dmamux: #dmamux}) | 537 | quote!({dmamux: #dmamux}) |
| 538 | } else if let Some(dma) = &ch.dma { | ||
| 539 | // Chip with GPDMA | ||
| 540 | let dma = format_ident!("{}", dma); | ||
| 541 | quote!({dma: #dma}) | ||
| 536 | } else { | 542 | } else { |
| 537 | unreachable!(); | 543 | unreachable!(); |
| 538 | }; | 544 | }; |
| @@ -606,6 +612,7 @@ fn main() { | |||
| 606 | 612 | ||
| 607 | let mut dma_channel_count: usize = 0; | 613 | let mut dma_channel_count: usize = 0; |
| 608 | let mut bdma_channel_count: usize = 0; | 614 | let mut bdma_channel_count: usize = 0; |
| 615 | let mut gpdma_channel_count: usize = 0; | ||
| 609 | 616 | ||
| 610 | for ch in METADATA.dma_channels { | 617 | for ch in METADATA.dma_channels { |
| 611 | let mut row = Vec::new(); | 618 | let mut row = Vec::new(); |
| @@ -626,6 +633,10 @@ fn main() { | |||
| 626 | num = bdma_channel_count; | 633 | num = bdma_channel_count; |
| 627 | bdma_channel_count += 1; | 634 | bdma_channel_count += 1; |
| 628 | } | 635 | } |
| 636 | "gpdma" => { | ||
| 637 | num = gpdma_channel_count; | ||
| 638 | gpdma_channel_count += 1; | ||
| 639 | } | ||
| 629 | _ => panic!("bad dma channel kind {}", bi.kind), | 640 | _ => panic!("bad dma channel kind {}", bi.kind), |
| 630 | } | 641 | } |
| 631 | 642 | ||
| @@ -650,6 +661,7 @@ fn main() { | |||
| 650 | g.extend(quote! { | 661 | g.extend(quote! { |
| 651 | pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count; | 662 | pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count; |
| 652 | pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count; | 663 | pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count; |
| 664 | pub(crate) const GPDMA_CHANNEL_COUNT: usize = #gpdma_channel_count; | ||
| 653 | }); | 665 | }); |
| 654 | 666 | ||
| 655 | for irq in METADATA.interrupts { | 667 | for irq in METADATA.interrupts { |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs new file mode 100644 index 000000000..0cb986b32 --- /dev/null +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | use core::sync::atomic::{fence, Ordering}; | ||
| 2 | use core::task::Waker; | ||
| 3 | |||
| 4 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 5 | use embassy::waitqueue::AtomicWaker; | ||
| 6 | |||
| 7 | use crate::_generated::GPDMA_CHANNEL_COUNT; | ||
| 8 | use crate::interrupt; | ||
| 9 | use crate::pac; | ||
| 10 | use crate::pac::gpdma::{vals, Gpdma}; | ||
| 11 | |||
| 12 | use super::{Request, TransferOptions, Word, WordSize}; | ||
| 13 | |||
| 14 | impl From<WordSize> for vals::ChTr1Dw { | ||
| 15 | fn from(raw: WordSize) -> Self { | ||
| 16 | match raw { | ||
| 17 | WordSize::OneByte => Self::BYTE, | ||
| 18 | WordSize::TwoBytes => Self::HALFWORD, | ||
| 19 | WordSize::FourBytes => Self::WORD, | ||
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | struct ChannelState { | ||
| 25 | waker: AtomicWaker, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl ChannelState { | ||
| 29 | const fn new() -> Self { | ||
| 30 | Self { | ||
| 31 | waker: AtomicWaker::new(), | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | struct State { | ||
| 37 | channels: [ChannelState; GPDMA_CHANNEL_COUNT], | ||
| 38 | } | ||
| 39 | |||
| 40 | impl State { | ||
| 41 | const fn new() -> Self { | ||
| 42 | const CH: ChannelState = ChannelState::new(); | ||
| 43 | Self { | ||
| 44 | channels: [CH; GPDMA_CHANNEL_COUNT], | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | static STATE: State = State::new(); | ||
| 50 | |||
| 51 | /// safety: must be called only once | ||
| 52 | pub(crate) unsafe fn init() { | ||
| 53 | foreach_interrupt! { | ||
| 54 | ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { | ||
| 55 | interrupt::$irq::steal().enable(); | ||
| 56 | }; | ||
| 57 | } | ||
| 58 | crate::_generated::init_gpdma(); | ||
| 59 | } | ||
| 60 | |||
| 61 | foreach_dma_channel! { | ||
| 62 | ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { | ||
| 63 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { | ||
| 64 | unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { | ||
| 65 | let (ptr, len) = super::slice_ptr_parts(buf); | ||
| 66 | low_level_api::start_transfer( | ||
| 67 | pac::$dma_peri, | ||
| 68 | $channel_num, | ||
| 69 | request, | ||
| 70 | low_level_api::Dir::MemoryToPeripheral, | ||
| 71 | reg_addr as *const u32, | ||
| 72 | ptr as *mut u32, | ||
| 73 | len, | ||
| 74 | true, | ||
| 75 | W::bits(), | ||
| 76 | options, | ||
| 77 | ) | ||
| 78 | } | ||
| 79 | |||
| 80 | unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) { | ||
| 81 | let buf = [repeated]; | ||
| 82 | low_level_api::start_transfer( | ||
| 83 | pac::$dma_peri, | ||
| 84 | $channel_num, | ||
| 85 | request, | ||
| 86 | low_level_api::Dir::MemoryToPeripheral, | ||
| 87 | reg_addr as *const u32, | ||
| 88 | buf.as_ptr() as *mut u32, | ||
| 89 | count, | ||
| 90 | false, | ||
| 91 | W::bits(), | ||
| 92 | options, | ||
| 93 | ) | ||
| 94 | } | ||
| 95 | |||
| 96 | unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { | ||
| 97 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 98 | low_level_api::start_transfer( | ||
| 99 | pac::$dma_peri, | ||
| 100 | $channel_num, | ||
| 101 | request, | ||
| 102 | low_level_api::Dir::PeripheralToMemory, | ||
| 103 | reg_addr as *const u32, | ||
| 104 | ptr as *mut u32, | ||
| 105 | len, | ||
| 106 | true, | ||
| 107 | W::bits(), | ||
| 108 | options, | ||
| 109 | ); | ||
| 110 | } | ||
| 111 | |||
| 112 | unsafe fn start_double_buffered_read<W: Word>( | ||
| 113 | &mut self, | ||
| 114 | _request: Request, | ||
| 115 | _reg_addr: *const W, | ||
| 116 | _buffer0: *mut W, | ||
| 117 | _buffer1: *mut W, | ||
| 118 | _buffer_len: usize, | ||
| 119 | _options: TransferOptions, | ||
| 120 | ) { | ||
| 121 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | ||
| 122 | } | ||
| 123 | |||
| 124 | unsafe fn set_buffer0<W: Word>(&mut self, _buffer: *mut W) { | ||
| 125 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | ||
| 126 | } | ||
| 127 | |||
| 128 | unsafe fn set_buffer1<W: Word>(&mut self, _buffer: *mut W) { | ||
| 129 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | ||
| 130 | } | ||
| 131 | |||
| 132 | unsafe fn is_buffer0_accessible(&mut self) -> bool { | ||
| 133 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | ||
| 134 | } | ||
| 135 | |||
| 136 | fn request_stop(&mut self) { | ||
| 137 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} | ||
| 138 | } | ||
| 139 | |||
| 140 | fn is_running(&self) -> bool { | ||
| 141 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} | ||
| 142 | } | ||
| 143 | |||
| 144 | fn remaining_transfers(&mut self) -> u16 { | ||
| 145 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | ||
| 146 | } | ||
| 147 | |||
| 148 | fn set_waker(&mut self, waker: &Waker) { | ||
| 149 | unsafe {low_level_api::set_waker($index, waker )} | ||
| 150 | } | ||
| 151 | |||
| 152 | fn on_irq() { | ||
| 153 | unsafe { | ||
| 154 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } | ||
| 159 | }; | ||
| 160 | } | ||
| 161 | |||
| 162 | mod low_level_api { | ||
| 163 | use super::*; | ||
| 164 | |||
| 165 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 166 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 167 | pub enum Dir { | ||
| 168 | MemoryToPeripheral, | ||
| 169 | PeripheralToMemory, | ||
| 170 | } | ||
| 171 | |||
| 172 | pub unsafe fn start_transfer( | ||
| 173 | dma: Gpdma, | ||
| 174 | channel_number: u8, | ||
| 175 | request: Request, | ||
| 176 | dir: Dir, | ||
| 177 | peri_addr: *const u32, | ||
| 178 | mem_addr: *mut u32, | ||
| 179 | mem_len: usize, | ||
| 180 | incr_mem: bool, | ||
| 181 | data_size: WordSize, | ||
| 182 | _options: TransferOptions, | ||
| 183 | ) { | ||
| 184 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 185 | fence(Ordering::SeqCst); | ||
| 186 | |||
| 187 | let ch = dma.ch(channel_number as _); | ||
| 188 | ch.llr().write(|_| {}); // no linked list | ||
| 189 | ch.tr1().write(|w| { | ||
| 190 | w.set_sdw(data_size.into()); | ||
| 191 | w.set_ddw(data_size.into()); | ||
| 192 | w.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem); | ||
| 193 | w.set_dinc(dir == Dir::PeripheralToMemory && incr_mem); | ||
| 194 | }); | ||
| 195 | ch.tr2().write(|w| { | ||
| 196 | w.set_dreq(match dir { | ||
| 197 | Dir::MemoryToPeripheral => vals::ChTr2Dreq::DESTINATIONPERIPHERAL, | ||
| 198 | Dir::PeripheralToMemory => vals::ChTr2Dreq::SOURCEPERIPHERAL, | ||
| 199 | }); | ||
| 200 | w.set_reqsel(request); | ||
| 201 | }); | ||
| 202 | ch.br1().write(|w| { | ||
| 203 | // BNDT is specified as bytes, not as number of transfers. | ||
| 204 | w.set_bndt((mem_len * data_size.bytes()) as u16) | ||
| 205 | }); | ||
| 206 | |||
| 207 | match dir { | ||
| 208 | Dir::MemoryToPeripheral => { | ||
| 209 | ch.sar().write_value(mem_addr as _); | ||
| 210 | ch.dar().write_value(peri_addr as _); | ||
| 211 | } | ||
| 212 | Dir::PeripheralToMemory => { | ||
| 213 | ch.sar().write_value(peri_addr as _); | ||
| 214 | ch.dar().write_value(mem_addr as _); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | ch.cr().write(|w| { | ||
| 219 | // Enable interrupts | ||
| 220 | w.set_tcie(true); | ||
| 221 | w.set_useie(true); | ||
| 222 | w.set_dteie(true); | ||
| 223 | w.set_suspie(true); | ||
| 224 | |||
| 225 | // Start it | ||
| 226 | w.set_en(true); | ||
| 227 | }); | ||
| 228 | } | ||
| 229 | |||
| 230 | /// Stops the DMA channel. | ||
| 231 | pub unsafe fn request_stop(dma: Gpdma, channel_number: u8) { | ||
| 232 | // get a handle on the channel itself | ||
| 233 | let ch = dma.ch(channel_number as _); | ||
| 234 | |||
| 235 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||
| 236 | ch.cr().write(|w| { | ||
| 237 | w.set_tcie(true); | ||
| 238 | w.set_useie(true); | ||
| 239 | w.set_dteie(true); | ||
| 240 | w.set_suspie(true); | ||
| 241 | }); | ||
| 242 | |||
| 243 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 244 | fence(Ordering::SeqCst); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Gets the running status of the channel | ||
| 248 | pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool { | ||
| 249 | let ch = dma.ch(ch as _); | ||
| 250 | !ch.sr().read().idlef() | ||
| 251 | } | ||
| 252 | |||
| 253 | /// Gets the total remaining transfers for the channel | ||
| 254 | /// Note: this will be zero for transfers that completed without cancellation. | ||
| 255 | pub unsafe fn get_remaining_transfers(dma: Gpdma, ch: u8) -> u16 { | ||
| 256 | // get a handle on the channel itself | ||
| 257 | let ch = dma.ch(ch as _); | ||
| 258 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 259 | ch.br1().read().bndt() | ||
| 260 | } | ||
| 261 | |||
| 262 | /// Sets the waker for the specified DMA channel | ||
| 263 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | ||
| 264 | STATE.channels[state_number].waker.register(waker); | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | ||
| 268 | pub unsafe fn on_irq_inner(dma: Gpdma, channel_num: u8, state_index: u8) { | ||
| 269 | let channel_num = channel_num as usize; | ||
| 270 | let state_index = state_index as usize; | ||
| 271 | |||
| 272 | let ch = dma.ch(channel_num); | ||
| 273 | let sr = ch.sr().read(); | ||
| 274 | |||
| 275 | if sr.dtef() { | ||
| 276 | panic!( | ||
| 277 | "DMA: data transfer error on DMA@{:08x} channel {}", | ||
| 278 | dma.0 as u32, channel_num | ||
| 279 | ); | ||
| 280 | } | ||
| 281 | if sr.usef() { | ||
| 282 | panic!( | ||
| 283 | "DMA: user settings error on DMA@{:08x} channel {}", | ||
| 284 | dma.0 as u32, channel_num | ||
| 285 | ); | ||
| 286 | } | ||
| 287 | |||
| 288 | if sr.suspf() || sr.tcf() { | ||
| 289 | ch.cr().write(|w| w.set_reset(true)); | ||
| 290 | STATE.channels[state_index].waker.wake(); | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } | ||
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index f96ccbf6e..c19f7b3c7 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -4,6 +4,8 @@ pub(crate) mod bdma; | |||
| 4 | pub(crate) mod dma; | 4 | pub(crate) mod dma; |
| 5 | #[cfg(dmamux)] | 5 | #[cfg(dmamux)] |
| 6 | mod dmamux; | 6 | mod dmamux; |
| 7 | #[cfg(gpdma)] | ||
| 8 | mod gpdma; | ||
| 7 | 9 | ||
| 8 | #[cfg(dmamux)] | 10 | #[cfg(dmamux)] |
| 9 | pub use dmamux::*; | 11 | pub use dmamux::*; |
| @@ -24,9 +26,9 @@ pub mod low_level { | |||
| 24 | 26 | ||
| 25 | pub(crate) use transfers::*; | 27 | pub(crate) use transfers::*; |
| 26 | 28 | ||
| 27 | #[cfg(any(bdma_v2, dma_v2, dmamux))] | 29 | #[cfg(any(bdma_v2, dma_v2, dmamux, gpdma))] |
| 28 | pub type Request = u8; | 30 | pub type Request = u8; |
| 29 | #[cfg(not(any(bdma_v2, dma_v2, dmamux)))] | 31 | #[cfg(not(any(bdma_v2, dma_v2, dmamux, gpdma)))] |
| 30 | pub type Request = (); | 32 | pub type Request = (); |
| 31 | 33 | ||
| 32 | pub(crate) mod sealed { | 34 | pub(crate) mod sealed { |
| @@ -118,11 +120,24 @@ pub(crate) mod sealed { | |||
| 118 | } | 120 | } |
| 119 | } | 121 | } |
| 120 | 122 | ||
| 123 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 124 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 121 | pub enum WordSize { | 125 | pub enum WordSize { |
| 122 | OneByte, | 126 | OneByte, |
| 123 | TwoBytes, | 127 | TwoBytes, |
| 124 | FourBytes, | 128 | FourBytes, |
| 125 | } | 129 | } |
| 130 | |||
| 131 | impl WordSize { | ||
| 132 | pub fn bytes(&self) -> usize { | ||
| 133 | match self { | ||
| 134 | Self::OneByte => 1, | ||
| 135 | Self::TwoBytes => 2, | ||
| 136 | Self::FourBytes => 4, | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 126 | pub trait Word: sealed::Word { | 141 | pub trait Word: sealed::Word { |
| 127 | fn bits() -> WordSize; | 142 | fn bits() -> WordSize; |
| 128 | } | 143 | } |
| @@ -148,7 +163,8 @@ impl Word for u32 { | |||
| 148 | } | 163 | } |
| 149 | } | 164 | } |
| 150 | 165 | ||
| 151 | #[derive(Debug, PartialEq)] | 166 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 167 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 152 | pub enum Burst { | 168 | pub enum Burst { |
| 153 | /// Single transfer | 169 | /// Single transfer |
| 154 | Single, | 170 | Single, |
| @@ -160,7 +176,8 @@ pub enum Burst { | |||
| 160 | Incr16, | 176 | Incr16, |
| 161 | } | 177 | } |
| 162 | 178 | ||
| 163 | #[derive(Debug, PartialEq)] | 179 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 180 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 164 | pub enum FlowControl { | 181 | pub enum FlowControl { |
| 165 | /// Flow control by DMA | 182 | /// Flow control by DMA |
| 166 | Dma, | 183 | Dma, |
| @@ -168,6 +185,8 @@ pub enum FlowControl { | |||
| 168 | Peripheral, | 185 | Peripheral, |
| 169 | } | 186 | } |
| 170 | 187 | ||
| 188 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 189 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 171 | pub struct TransferOptions { | 190 | pub struct TransferOptions { |
| 172 | /// Peripheral burst transfer configuration | 191 | /// Peripheral burst transfer configuration |
| 173 | pub pburst: Burst, | 192 | pub pburst: Burst, |
| @@ -299,6 +318,8 @@ pub(crate) unsafe fn init() { | |||
| 299 | dma::init(); | 318 | dma::init(); |
| 300 | #[cfg(dmamux)] | 319 | #[cfg(dmamux)] |
| 301 | dmamux::init(); | 320 | dmamux::init(); |
| 321 | #[cfg(gpdma)] | ||
| 322 | gpdma::init(); | ||
| 302 | } | 323 | } |
| 303 | 324 | ||
| 304 | // TODO: replace transmutes with core::ptr::metadata once it's stable | 325 | // TODO: replace transmutes with core::ptr::metadata once it's stable |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index ea0c496db..23240ad82 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -100,13 +100,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 100 | unborrow!(sck, mosi, miso); | 100 | unborrow!(sck, mosi, miso); |
| 101 | unsafe { | 101 | unsafe { |
| 102 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 102 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 103 | #[cfg(any(spi_v2, spi_v3))] | 103 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 104 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 104 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 105 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | 105 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); |
| 106 | #[cfg(any(spi_v2, spi_v3))] | 106 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 107 | mosi.set_speed(crate::gpio::Speed::VeryHigh); | 107 | mosi.set_speed(crate::gpio::Speed::VeryHigh); |
| 108 | miso.set_as_af(miso.af_num(), AFType::Input); | 108 | miso.set_as_af(miso.af_num(), AFType::Input); |
| 109 | #[cfg(any(spi_v2, spi_v3))] | 109 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 110 | miso.set_speed(crate::gpio::Speed::VeryHigh); | 110 | miso.set_speed(crate::gpio::Speed::VeryHigh); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| @@ -137,10 +137,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 137 | unborrow!(sck, miso); | 137 | unborrow!(sck, miso); |
| 138 | unsafe { | 138 | unsafe { |
| 139 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 139 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 140 | #[cfg(any(spi_v2, spi_v3))] | 140 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 141 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 141 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 142 | miso.set_as_af(miso.af_num(), AFType::Input); | 142 | miso.set_as_af(miso.af_num(), AFType::Input); |
| 143 | #[cfg(any(spi_v2, spi_v3))] | 143 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 144 | miso.set_speed(crate::gpio::Speed::VeryHigh); | 144 | miso.set_speed(crate::gpio::Speed::VeryHigh); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| @@ -171,10 +171,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 171 | unborrow!(sck, mosi); | 171 | unborrow!(sck, mosi); |
| 172 | unsafe { | 172 | unsafe { |
| 173 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 173 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 174 | #[cfg(any(spi_v2, spi_v3))] | 174 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 175 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 175 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 176 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | 176 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); |
| 177 | #[cfg(any(spi_v2, spi_v3))] | 177 | #[cfg(any(spi_v2, spi_v3, spi_v4))] |
| 178 | mosi.set_speed(crate::gpio::Speed::VeryHigh); | 178 | mosi.set_speed(crate::gpio::Speed::VeryHigh); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| @@ -260,7 +260,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 260 | w.set_spe(true); | 260 | w.set_spe(true); |
| 261 | }); | 261 | }); |
| 262 | } | 262 | } |
| 263 | #[cfg(spi_v3)] | 263 | #[cfg(any(spi_v3, spi_v4))] |
| 264 | unsafe { | 264 | unsafe { |
| 265 | T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); | 265 | T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); |
| 266 | T::REGS.cfg2().modify(|w| { | 266 | T::REGS.cfg2().modify(|w| { |
| @@ -285,7 +285,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 285 | }); | 285 | }); |
| 286 | T::REGS.cr2().modify(|w| { | 286 | T::REGS.cr2().modify(|w| { |
| 287 | w.set_tsize(0); | 287 | w.set_tsize(0); |
| 288 | w.set_tser(0); | ||
| 289 | }); | 288 | }); |
| 290 | T::REGS.cr1().modify(|w| { | 289 | T::REGS.cr1().modify(|w| { |
| 291 | w.set_ssi(false); | 290 | w.set_ssi(false); |
| @@ -320,7 +319,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 320 | }); | 319 | }); |
| 321 | } | 320 | } |
| 322 | 321 | ||
| 323 | #[cfg(spi_v3)] | 322 | #[cfg(any(spi_v3, spi_v4))] |
| 324 | unsafe { | 323 | unsafe { |
| 325 | T::REGS.cfg2().modify(|w| { | 324 | T::REGS.cfg2().modify(|w| { |
| 326 | w.set_cpha(cpha); | 325 | w.set_cpha(cpha); |
| @@ -333,7 +332,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 333 | pub fn get_current_config(&self) -> Config { | 332 | pub fn get_current_config(&self) -> Config { |
| 334 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 333 | #[cfg(any(spi_v1, spi_f1, spi_v2))] |
| 335 | let cfg = unsafe { T::REGS.cr1().read() }; | 334 | let cfg = unsafe { T::REGS.cr1().read() }; |
| 336 | #[cfg(spi_v3)] | 335 | #[cfg(any(spi_v3, spi_v4))] |
| 337 | let cfg = unsafe { T::REGS.cfg2().read() }; | 336 | let cfg = unsafe { T::REGS.cfg2().read() }; |
| 338 | let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { | 337 | let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { |
| 339 | Polarity::IdleLow | 338 | Polarity::IdleLow |
| @@ -386,7 +385,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 386 | w.set_spe(true); | 385 | w.set_spe(true); |
| 387 | }); | 386 | }); |
| 388 | } | 387 | } |
| 389 | #[cfg(spi_v3)] | 388 | #[cfg(any(spi_v3, spi_v4))] |
| 390 | unsafe { | 389 | unsafe { |
| 391 | T::REGS.cr1().modify(|w| { | 390 | T::REGS.cr1().modify(|w| { |
| 392 | w.set_csusp(true); | 391 | w.set_csusp(true); |
| @@ -435,7 +434,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 435 | T::REGS.cr1().modify(|w| { | 434 | T::REGS.cr1().modify(|w| { |
| 436 | w.set_spe(true); | 435 | w.set_spe(true); |
| 437 | }); | 436 | }); |
| 438 | #[cfg(spi_v3)] | 437 | #[cfg(any(spi_v3, spi_v4))] |
| 439 | T::REGS.cr1().modify(|w| { | 438 | T::REGS.cr1().modify(|w| { |
| 440 | w.set_cstart(true); | 439 | w.set_cstart(true); |
| 441 | }); | 440 | }); |
| @@ -466,7 +465,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 466 | } | 465 | } |
| 467 | 466 | ||
| 468 | // SPIv3 clears rxfifo on SPE=0 | 467 | // SPIv3 clears rxfifo on SPE=0 |
| 469 | #[cfg(not(spi_v3))] | 468 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 470 | flush_rx_fifo(T::REGS); | 469 | flush_rx_fifo(T::REGS); |
| 471 | 470 | ||
| 472 | let clock_byte_count = data.len(); | 471 | let clock_byte_count = data.len(); |
| @@ -495,7 +494,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 495 | T::REGS.cr1().modify(|w| { | 494 | T::REGS.cr1().modify(|w| { |
| 496 | w.set_spe(true); | 495 | w.set_spe(true); |
| 497 | }); | 496 | }); |
| 498 | #[cfg(spi_v3)] | 497 | #[cfg(any(spi_v3, spi_v4))] |
| 499 | T::REGS.cr1().modify(|w| { | 498 | T::REGS.cr1().modify(|w| { |
| 500 | w.set_cstart(true); | 499 | w.set_cstart(true); |
| 501 | }); | 500 | }); |
| @@ -533,7 +532,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 533 | } | 532 | } |
| 534 | 533 | ||
| 535 | // SPIv3 clears rxfifo on SPE=0 | 534 | // SPIv3 clears rxfifo on SPE=0 |
| 536 | #[cfg(not(spi_v3))] | 535 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 537 | flush_rx_fifo(T::REGS); | 536 | flush_rx_fifo(T::REGS); |
| 538 | 537 | ||
| 539 | let rx_request = self.rxdma.request(); | 538 | let rx_request = self.rxdma.request(); |
| @@ -557,7 +556,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 557 | T::REGS.cr1().modify(|w| { | 556 | T::REGS.cr1().modify(|w| { |
| 558 | w.set_spe(true); | 557 | w.set_spe(true); |
| 559 | }); | 558 | }); |
| 560 | #[cfg(spi_v3)] | 559 | #[cfg(any(spi_v3, spi_v4))] |
| 561 | T::REGS.cr1().modify(|w| { | 560 | T::REGS.cr1().modify(|w| { |
| 562 | w.set_cstart(true); | 561 | w.set_cstart(true); |
| 563 | }); | 562 | }); |
| @@ -642,9 +641,9 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | |||
| 642 | } | 641 | } |
| 643 | } | 642 | } |
| 644 | 643 | ||
| 645 | #[cfg(not(spi_v3))] | 644 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 646 | use vals::Br; | 645 | use vals::Br; |
| 647 | #[cfg(spi_v3)] | 646 | #[cfg(any(spi_v3, spi_v4))] |
| 648 | use vals::Mbr as Br; | 647 | use vals::Mbr as Br; |
| 649 | 648 | ||
| 650 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { | 649 | fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { |
| @@ -670,17 +669,17 @@ trait RegsExt { | |||
| 670 | 669 | ||
| 671 | impl RegsExt for Regs { | 670 | impl RegsExt for Regs { |
| 672 | fn tx_ptr<W>(&self) -> *mut W { | 671 | fn tx_ptr<W>(&self) -> *mut W { |
| 673 | #[cfg(not(spi_v3))] | 672 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 674 | let dr = self.dr(); | 673 | let dr = self.dr(); |
| 675 | #[cfg(spi_v3)] | 674 | #[cfg(any(spi_v3, spi_v4))] |
| 676 | let dr = self.txdr(); | 675 | let dr = self.txdr(); |
| 677 | dr.ptr() as *mut W | 676 | dr.ptr() as *mut W |
| 678 | } | 677 | } |
| 679 | 678 | ||
| 680 | fn rx_ptr<W>(&self) -> *mut W { | 679 | fn rx_ptr<W>(&self) -> *mut W { |
| 681 | #[cfg(not(spi_v3))] | 680 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 682 | let dr = self.dr(); | 681 | let dr = self.dr(); |
| 683 | #[cfg(spi_v3)] | 682 | #[cfg(any(spi_v3, spi_v4))] |
| 684 | let dr = self.rxdr(); | 683 | let dr = self.rxdr(); |
| 685 | dr.ptr() as *mut W | 684 | dr.ptr() as *mut W |
| 686 | } | 685 | } |
| @@ -690,22 +689,22 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { | |||
| 690 | if sr.ovr() { | 689 | if sr.ovr() { |
| 691 | return Err(Error::Overrun); | 690 | return Err(Error::Overrun); |
| 692 | } | 691 | } |
| 693 | #[cfg(not(any(spi_f1, spi_v3)))] | 692 | #[cfg(not(any(spi_f1, spi_v3, spi_v4)))] |
| 694 | if sr.fre() { | 693 | if sr.fre() { |
| 695 | return Err(Error::Framing); | 694 | return Err(Error::Framing); |
| 696 | } | 695 | } |
| 697 | #[cfg(spi_v3)] | 696 | #[cfg(any(spi_v3, spi_v4))] |
| 698 | if sr.tifre() { | 697 | if sr.tifre() { |
| 699 | return Err(Error::Framing); | 698 | return Err(Error::Framing); |
| 700 | } | 699 | } |
| 701 | if sr.modf() { | 700 | if sr.modf() { |
| 702 | return Err(Error::ModeFault); | 701 | return Err(Error::ModeFault); |
| 703 | } | 702 | } |
| 704 | #[cfg(not(spi_v3))] | 703 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 705 | if sr.crcerr() { | 704 | if sr.crcerr() { |
| 706 | return Err(Error::Crc); | 705 | return Err(Error::Crc); |
| 707 | } | 706 | } |
| 708 | #[cfg(spi_v3)] | 707 | #[cfg(any(spi_v3, spi_v4))] |
| 709 | if sr.crce() { | 708 | if sr.crce() { |
| 710 | return Err(Error::Crc); | 709 | return Err(Error::Crc); |
| 711 | } | 710 | } |
| @@ -719,11 +718,11 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | |||
| 719 | 718 | ||
| 720 | check_error_flags(sr)?; | 719 | check_error_flags(sr)?; |
| 721 | 720 | ||
| 722 | #[cfg(not(spi_v3))] | 721 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 723 | if sr.txe() { | 722 | if sr.txe() { |
| 724 | return Ok(()); | 723 | return Ok(()); |
| 725 | } | 724 | } |
| 726 | #[cfg(spi_v3)] | 725 | #[cfg(any(spi_v3, spi_v4))] |
| 727 | if sr.txp() { | 726 | if sr.txp() { |
| 728 | return Ok(()); | 727 | return Ok(()); |
| 729 | } | 728 | } |
| @@ -736,11 +735,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 736 | 735 | ||
| 737 | check_error_flags(sr)?; | 736 | check_error_flags(sr)?; |
| 738 | 737 | ||
| 739 | #[cfg(not(spi_v3))] | 738 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 740 | if sr.rxne() { | 739 | if sr.rxne() { |
| 741 | return Ok(()); | 740 | return Ok(()); |
| 742 | } | 741 | } |
| 743 | #[cfg(spi_v3)] | 742 | #[cfg(any(spi_v3, spi_v4))] |
| 744 | if sr.rxp() { | 743 | if sr.rxp() { |
| 745 | return Ok(()); | 744 | return Ok(()); |
| 746 | } | 745 | } |
| @@ -749,11 +748,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 749 | 748 | ||
| 750 | fn flush_rx_fifo(regs: Regs) { | 749 | fn flush_rx_fifo(regs: Regs) { |
| 751 | unsafe { | 750 | unsafe { |
| 752 | #[cfg(not(spi_v3))] | 751 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 753 | while regs.sr().read().rxne() { | 752 | while regs.sr().read().rxne() { |
| 754 | let _ = regs.dr().read(); | 753 | let _ = regs.dr().read(); |
| 755 | } | 754 | } |
| 756 | #[cfg(spi_v3)] | 755 | #[cfg(any(spi_v3, spi_v4))] |
| 757 | while regs.sr().read().rxp() { | 756 | while regs.sr().read().rxp() { |
| 758 | let _ = regs.rxdr().read(); | 757 | let _ = regs.rxdr().read(); |
| 759 | } | 758 | } |
| @@ -762,11 +761,11 @@ fn flush_rx_fifo(regs: Regs) { | |||
| 762 | 761 | ||
| 763 | fn set_txdmaen(regs: Regs, val: bool) { | 762 | fn set_txdmaen(regs: Regs, val: bool) { |
| 764 | unsafe { | 763 | unsafe { |
| 765 | #[cfg(not(spi_v3))] | 764 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 766 | regs.cr2().modify(|reg| { | 765 | regs.cr2().modify(|reg| { |
| 767 | reg.set_txdmaen(val); | 766 | reg.set_txdmaen(val); |
| 768 | }); | 767 | }); |
| 769 | #[cfg(spi_v3)] | 768 | #[cfg(any(spi_v3, spi_v4))] |
| 770 | regs.cfg1().modify(|reg| { | 769 | regs.cfg1().modify(|reg| { |
| 771 | reg.set_txdmaen(val); | 770 | reg.set_txdmaen(val); |
| 772 | }); | 771 | }); |
| @@ -775,11 +774,11 @@ fn set_txdmaen(regs: Regs, val: bool) { | |||
| 775 | 774 | ||
| 776 | fn set_rxdmaen(regs: Regs, val: bool) { | 775 | fn set_rxdmaen(regs: Regs, val: bool) { |
| 777 | unsafe { | 776 | unsafe { |
| 778 | #[cfg(not(spi_v3))] | 777 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 779 | regs.cr2().modify(|reg| { | 778 | regs.cr2().modify(|reg| { |
| 780 | reg.set_rxdmaen(val); | 779 | reg.set_rxdmaen(val); |
| 781 | }); | 780 | }); |
| 782 | #[cfg(spi_v3)] | 781 | #[cfg(any(spi_v3, spi_v4))] |
| 783 | regs.cfg1().modify(|reg| { | 782 | regs.cfg1().modify(|reg| { |
| 784 | reg.set_rxdmaen(val); | 783 | reg.set_rxdmaen(val); |
| 785 | }); | 784 | }); |
| @@ -791,21 +790,21 @@ fn finish_dma(regs: Regs) { | |||
| 791 | #[cfg(spi_v2)] | 790 | #[cfg(spi_v2)] |
| 792 | while regs.sr().read().ftlvl() > 0 {} | 791 | while regs.sr().read().ftlvl() > 0 {} |
| 793 | 792 | ||
| 794 | #[cfg(spi_v3)] | 793 | #[cfg(any(spi_v3, spi_v4))] |
| 795 | while !regs.sr().read().txc() {} | 794 | while !regs.sr().read().txc() {} |
| 796 | #[cfg(not(spi_v3))] | 795 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 797 | while regs.sr().read().bsy() {} | 796 | while regs.sr().read().bsy() {} |
| 798 | 797 | ||
| 799 | regs.cr1().modify(|w| { | 798 | regs.cr1().modify(|w| { |
| 800 | w.set_spe(false); | 799 | w.set_spe(false); |
| 801 | }); | 800 | }); |
| 802 | 801 | ||
| 803 | #[cfg(not(spi_v3))] | 802 | #[cfg(not(any(spi_v3, spi_v4)))] |
| 804 | regs.cr2().modify(|reg| { | 803 | regs.cr2().modify(|reg| { |
| 805 | reg.set_txdmaen(false); | 804 | reg.set_txdmaen(false); |
| 806 | reg.set_rxdmaen(false); | 805 | reg.set_rxdmaen(false); |
| 807 | }); | 806 | }); |
| 808 | #[cfg(spi_v3)] | 807 | #[cfg(any(spi_v3, spi_v4))] |
| 809 | regs.cfg1().modify(|reg| { | 808 | regs.cfg1().modify(|reg| { |
| 810 | reg.set_txdmaen(false); | 809 | reg.set_txdmaen(false); |
| 811 | reg.set_rxdmaen(false); | 810 | reg.set_rxdmaen(false); |
| @@ -819,7 +818,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { | |||
| 819 | unsafe { | 818 | unsafe { |
| 820 | ptr::write_volatile(regs.tx_ptr(), tx_word); | 819 | ptr::write_volatile(regs.tx_ptr(), tx_word); |
| 821 | 820 | ||
| 822 | #[cfg(spi_v3)] | 821 | #[cfg(any(spi_v3, spi_v4))] |
| 823 | regs.cr1().modify(|reg| reg.set_cstart(true)); | 822 | regs.cr1().modify(|reg| reg.set_cstart(true)); |
| 824 | } | 823 | } |
| 825 | 824 | ||
| @@ -1018,7 +1017,7 @@ pub(crate) mod sealed { | |||
| 1018 | } | 1017 | } |
| 1019 | } | 1018 | } |
| 1020 | 1019 | ||
| 1021 | #[cfg(spi_v3)] | 1020 | #[cfg(any(spi_v3, spi_v4))] |
| 1022 | pub fn dsize(&self) -> u8 { | 1021 | pub fn dsize(&self) -> u8 { |
| 1023 | match self { | 1022 | match self { |
| 1024 | WordSize::EightBit => 0b0111, | 1023 | WordSize::EightBit => 0b0111, |
| @@ -1026,7 +1025,7 @@ pub(crate) mod sealed { | |||
| 1026 | } | 1025 | } |
| 1027 | } | 1026 | } |
| 1028 | 1027 | ||
| 1029 | #[cfg(spi_v3)] | 1028 | #[cfg(any(spi_v3, spi_v4))] |
| 1030 | pub fn _frxth(&self) -> vals::Fthlv { | 1029 | pub fn _frxth(&self) -> vals::Fthlv { |
| 1031 | match self { | 1030 | match self { |
| 1032 | WordSize::EightBit => vals::Fthlv::ONEFRAME, | 1031 | WordSize::EightBit => vals::Fthlv::ONEFRAME, |
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index c733f4226..45cc4e725 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs | |||
| @@ -42,7 +42,19 @@ macro_rules! dma_trait_impl { | |||
| 42 | } | 42 | } |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | // No DMAMUX | 45 | // DMAMUX |
| 46 | (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { | ||
| 47 | impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T | ||
| 48 | where | ||
| 49 | T: crate::dma::Channel, | ||
| 50 | { | ||
| 51 | fn request(&self) -> crate::dma::Request { | ||
| 52 | $request | ||
| 53 | } | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | |||
| 57 | // DMA/GPDMA, without DMAMUX | ||
| 46 | (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { | 58 | (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { |
| 47 | impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { | 59 | impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { |
| 48 | fn request(&self) -> crate::dma::Request { | 60 | fn request(&self) -> crate::dma::Request { |
diff --git a/examples/stm32u5/src/bin/blinky.rs b/examples/stm32u5/src/bin/blinky.rs new file mode 100644 index 000000000..e1bcccf58 --- /dev/null +++ b/examples/stm32u5/src/bin/blinky.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use defmt_rtt as _; | ||
| 7 | use embassy::executor::Spawner; | ||
| 8 | use embassy::time::{Duration, Timer}; | ||
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 10 | use embassy_stm32::Peripherals; | ||
| 11 | // global logger | ||
| 12 | use panic_probe as _; | ||
| 13 | |||
| 14 | #[embassy::main] | ||
| 15 | async fn main(_spawner: Spawner, p: Peripherals) -> ! { | ||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | let mut led = Output::new(p.PH7, Level::Low, Speed::Medium); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | defmt::info!("on!"); | ||
| 22 | led.set_low(); | ||
| 23 | Timer::after(Duration::from_millis(200)).await; | ||
| 24 | |||
| 25 | defmt::info!("off!"); | ||
| 26 | led.set_high(); | ||
| 27 | Timer::after(Duration::from_millis(200)).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject 8fb98d74620ab71fb9d0be2d800c427e0b77c46 | Subproject 472ee98e8fdb11312392e47b16568c9d02fe654 | ||
diff --git a/stm32-metapac-gen/src/data.rs b/stm32-metapac-gen/src/data.rs index 24f0bcf0d..a74c60ac0 100644 --- a/stm32-metapac-gen/src/data.rs +++ b/stm32-metapac-gen/src/data.rs | |||
| @@ -104,6 +104,7 @@ pub struct PeripheralDmaChannel { | |||
| 104 | pub signal: String, | 104 | pub signal: String, |
| 105 | pub channel: Option<String>, | 105 | pub channel: Option<String>, |
| 106 | pub dmamux: Option<String>, | 106 | pub dmamux: Option<String>, |
| 107 | pub dma: Option<String>, | ||
| 107 | pub request: Option<u32>, | 108 | pub request: Option<u32>, |
| 108 | } | 109 | } |
| 109 | 110 | ||
diff --git a/stm32-metapac/src/metadata.rs b/stm32-metapac/src/metadata.rs index 150aa5956..23b759f6c 100644 --- a/stm32-metapac/src/metadata.rs +++ b/stm32-metapac/src/metadata.rs | |||
| @@ -93,5 +93,6 @@ pub struct PeripheralDmaChannel { | |||
| 93 | pub signal: &'static str, | 93 | pub signal: &'static str, |
| 94 | pub channel: Option<&'static str>, | 94 | pub channel: Option<&'static str>, |
| 95 | pub dmamux: Option<&'static str>, | 95 | pub dmamux: Option<&'static str>, |
| 96 | pub dma: Option<&'static str>, | ||
| 96 | pub request: Option<u32>, | 97 | pub request: Option<u32>, |
| 97 | } | 98 | } |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 260ac223b..9bd087618 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -6,12 +6,13 @@ version = "0.1.0" | |||
| 6 | resolver = "2" | 6 | resolver = "2" |
| 7 | 7 | ||
| 8 | [features] | 8 | [features] |
| 9 | stm32f103c8 = ["embassy-stm32/stm32f103c8"] | 9 | stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill |
| 10 | stm32f429zi = ["embassy-stm32/stm32f429zi"] | 10 | stm32f429zi = ["embassy-stm32/stm32f429zi"] # Nucleo |
| 11 | stm32g071rb = ["embassy-stm32/stm32g071rb"] | 11 | stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo |
| 12 | stm32g491re = ["embassy-stm32/stm32g491re"] | 12 | stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo |
| 13 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] | 13 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo |
| 14 | stm32wb55rg = ["embassy-stm32/stm32wb55rg"] | 14 | stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo |
| 15 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board | ||
| 15 | 16 | ||
| 16 | [dependencies] | 17 | [dependencies] |
| 17 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } | 18 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } |
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index 41c10d45f..c7991953f 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs | |||
| @@ -28,6 +28,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 28 | let (mut a, mut b) = (p.PA3, p.PA2); | 28 | let (mut a, mut b) = (p.PA3, p.PA2); |
| 29 | #[cfg(feature = "stm32h755zi")] | 29 | #[cfg(feature = "stm32h755zi")] |
| 30 | let (mut a, mut b) = (p.PB6, p.PB7); | 30 | let (mut a, mut b) = (p.PB6, p.PB7); |
| 31 | #[cfg(feature = "stm32u585ai")] | ||
| 32 | let (mut a, mut b) = (p.PD9, p.PD8); | ||
| 31 | 33 | ||
| 32 | // Test initial output | 34 | // Test initial output |
| 33 | { | 35 | { |
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index b079472d5..049ba1e9f 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs | |||
| @@ -16,10 +16,20 @@ use example_common::*; | |||
| 16 | async fn main(_spawner: Spawner, p: Peripherals) { | 16 | async fn main(_spawner: Spawner, p: Peripherals) { |
| 17 | info!("Hello World!"); | 17 | info!("Hello World!"); |
| 18 | 18 | ||
| 19 | #[cfg(not(feature = "stm32h755zi"))] | 19 | #[cfg(feature = "stm32f103c8")] |
| 20 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); | ||
| 21 | #[cfg(feature = "stm32f429zi")] | ||
| 20 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); | 22 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); |
| 21 | #[cfg(feature = "stm32h755zi")] | 23 | #[cfg(feature = "stm32h755zi")] |
| 22 | let (sck, mosi, miso) = (p.PA5, p.PB5, p.PA6); | 24 | let (sck, mosi, miso) = (p.PA5, p.PB5, p.PA6); |
| 25 | #[cfg(feature = "stm32g491re")] | ||
| 26 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); | ||
| 27 | #[cfg(feature = "stm32g071rb")] | ||
| 28 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); | ||
| 29 | #[cfg(feature = "stm32wb55rg")] | ||
| 30 | let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); | ||
| 31 | #[cfg(feature = "stm32u585ai")] | ||
| 32 | let (sck, mosi, miso) = (p.PE13, p.PE15, p.PE14); | ||
| 23 | 33 | ||
| 24 | let mut spi = Spi::new( | 34 | let mut spi = Spi::new( |
| 25 | p.SPI1, | 35 | p.SPI1, |
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index f4f1994c0..64337886b 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs | |||
| @@ -27,6 +27,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 27 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); | 27 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); |
| 28 | #[cfg(feature = "stm32wb55rg")] | 28 | #[cfg(feature = "stm32wb55rg")] |
| 29 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); | 29 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); |
| 30 | #[cfg(feature = "stm32u585ai")] | ||
| 31 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); | ||
| 30 | 32 | ||
| 31 | let mut spi = Spi::new( | 33 | let mut spi = Spi::new( |
| 32 | p.SPI1, | 34 | p.SPI1, |
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 87a593ca5..c3468290e 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs | |||
| @@ -35,6 +35,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 35 | let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); // TODO this is wrong | 35 | let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); // TODO this is wrong |
| 36 | #[cfg(feature = "stm32h755zi")] | 36 | #[cfg(feature = "stm32h755zi")] |
| 37 | let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); | 37 | let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); |
| 38 | #[cfg(feature = "stm32u585ai")] | ||
| 39 | let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); | ||
| 38 | 40 | ||
| 39 | let config = Config::default(); | 41 | let config = Config::default(); |
| 40 | let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); | 42 | let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 2565409e6..9946f4a56 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -34,6 +34,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 34 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH1, p.DMA1_CH2); // TODO this is wrong | 34 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH1, p.DMA1_CH2); // TODO this is wrong |
| 35 | #[cfg(feature = "stm32h755zi")] | 35 | #[cfg(feature = "stm32h755zi")] |
| 36 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 36 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); |
| 37 | #[cfg(feature = "stm32u585ai")] | ||
| 38 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); | ||
| 37 | 39 | ||
| 38 | let config = Config::default(); | 40 | let config = Config::default(); |
| 39 | let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); | 41 | let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); |
