diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-07-17 08:32:31 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-07-17 08:32:31 +0200 |
| commit | 59953b5b5e4935747a7f5c9699702d29ca248a2e (patch) | |
| tree | b832ade1a4f07ecddc01f04290bb400115712510 | |
| parent | 69fb1b5418a4fb355d48b3b4357d0cd7562b5c4d (diff) | |
| parent | d7176da37c372d8a57283af540f4fecb532540aa (diff) | |
Merge pull request #295 from embassy-rs/all_dma
stm32: impl dma for all chips
24 files changed, 818 insertions, 1046 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index ceb87ad53..a5a656637 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json | |||
| @@ -1,12 +1,17 @@ | |||
| 1 | { | 1 | { |
| 2 | "editor.formatOnSave": true, | 2 | "editor.formatOnSave": true, |
| 3 | "rust-analyzer.assist.importEnforceGranularity": true, | ||
| 4 | "rust-analyzer.assist.importGranularity": "module", | ||
| 3 | "rust-analyzer.checkOnSave.allFeatures": false, | 5 | "rust-analyzer.checkOnSave.allFeatures": false, |
| 4 | "rust-analyzer.checkOnSave.allTargets": false, | 6 | "rust-analyzer.checkOnSave.allTargets": false, |
| 7 | "rust-analyzer.cargo.noDefaultFeatures": true, | ||
| 8 | "rust-analyzer.checkOnSave.noDefaultFeatures": true, | ||
| 5 | "rust-analyzer.cargo.target": "thumbv7em-none-eabi", | 9 | "rust-analyzer.cargo.target": "thumbv7em-none-eabi", |
| 6 | "rust-analyzer.cargo.features": [ | 10 | "rust-analyzer.cargo.features": [ |
| 7 | // These are needed to prevent embassy-net from failing to build | 11 | // These are needed to prevent embassy-net from failing to build |
| 8 | "embassy-net/medium-ethernet", | 12 | "embassy-net/medium-ethernet", |
| 9 | "embassy-net/tcp" | 13 | "embassy-net/tcp", |
| 14 | "embassy-net/pool-16", | ||
| 10 | ], | 15 | ], |
| 11 | "rust-analyzer.procMacro.enable": true, | 16 | "rust-analyzer.procMacro.enable": true, |
| 12 | "rust-analyzer.cargo.runBuildScripts": true, | 17 | "rust-analyzer.cargo.runBuildScripts": true, |
diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs deleted file mode 100644 index f57358f68..000000000 --- a/embassy-stm32/src/bdma/mod.rs +++ /dev/null | |||
| @@ -1,413 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use core::future::Future; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 7 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 8 | use embassy::util::{AtomicWaker, OnDrop}; | ||
| 9 | use futures::future::poll_fn; | ||
| 10 | |||
| 11 | use crate::dma_traits::{ReadDma, WriteDma}; | ||
| 12 | use crate::interrupt; | ||
| 13 | use crate::pac; | ||
| 14 | use crate::pac::bdma::vals; | ||
| 15 | |||
| 16 | const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; | ||
| 17 | const CH_STATUS_NONE: u8 = 0; | ||
| 18 | const CH_STATUS_COMPLETED: u8 = 1; | ||
| 19 | const CH_STATUS_ERROR: u8 = 2; | ||
| 20 | |||
| 21 | struct State { | ||
| 22 | ch_wakers: [AtomicWaker; CH_COUNT], | ||
| 23 | ch_status: [AtomicU8; CH_COUNT], | ||
| 24 | } | ||
| 25 | |||
| 26 | impl State { | ||
| 27 | const fn new() -> Self { | ||
| 28 | const AW: AtomicWaker = AtomicWaker::new(); | ||
| 29 | const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); | ||
| 30 | Self { | ||
| 31 | ch_wakers: [AW; CH_COUNT], | ||
| 32 | ch_status: [AU; CH_COUNT], | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | static STATE: State = State::new(); | ||
| 38 | |||
| 39 | #[allow(unused)] | ||
| 40 | pub(crate) async unsafe fn transfer_p2m( | ||
| 41 | regs: pac::bdma::Ch, | ||
| 42 | state_number: u8, | ||
| 43 | src: *const u8, | ||
| 44 | dst: &mut [u8], | ||
| 45 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 46 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 47 | #[cfg(dmamux)] request: u8, | ||
| 48 | ) { | ||
| 49 | // ndtr is max 16 bits. | ||
| 50 | assert!(dst.len() <= 0xFFFF); | ||
| 51 | |||
| 52 | // Reset status | ||
| 53 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 54 | STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||
| 55 | |||
| 56 | let on_drop = OnDrop::new(|| unsafe { | ||
| 57 | regs.cr().modify(|w| { | ||
| 58 | w.set_tcie(false); | ||
| 59 | w.set_teie(false); | ||
| 60 | w.set_en(false); | ||
| 61 | }); | ||
| 62 | while regs.cr().read().en() {} | ||
| 63 | }); | ||
| 64 | |||
| 65 | #[cfg(dmamux)] | ||
| 66 | crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 67 | |||
| 68 | regs.par().write_value(src as u32); | ||
| 69 | regs.mar().write_value(dst.as_mut_ptr() as u32); | ||
| 70 | regs.ndtr().write(|w| w.set_ndt(dst.len() as u16)); | ||
| 71 | regs.cr().write(|w| { | ||
| 72 | w.set_psize(vals::Size::BITS8); | ||
| 73 | w.set_msize(vals::Size::BITS8); | ||
| 74 | w.set_minc(vals::Inc::ENABLED); | ||
| 75 | w.set_teie(true); | ||
| 76 | w.set_tcie(true); | ||
| 77 | w.set_en(true); | ||
| 78 | }); | ||
| 79 | |||
| 80 | let res = poll_fn(|cx| { | ||
| 81 | STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||
| 82 | match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { | ||
| 83 | CH_STATUS_NONE => Poll::Pending, | ||
| 84 | x => Poll::Ready(x), | ||
| 85 | } | ||
| 86 | }) | ||
| 87 | .await; | ||
| 88 | |||
| 89 | // TODO handle error | ||
| 90 | assert!(res == CH_STATUS_COMPLETED); | ||
| 91 | } | ||
| 92 | |||
| 93 | #[allow(unused)] | ||
| 94 | pub(crate) async unsafe fn transfer_m2p( | ||
| 95 | regs: pac::bdma::Ch, | ||
| 96 | state_number: u8, | ||
| 97 | src: &[u8], | ||
| 98 | dst: *mut u8, | ||
| 99 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 100 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 101 | #[cfg(dmamux)] request: u8, | ||
| 102 | ) { | ||
| 103 | // ndtr is max 16 bits. | ||
| 104 | assert!(src.len() <= 0xFFFF); | ||
| 105 | |||
| 106 | // Reset status | ||
| 107 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 108 | STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||
| 109 | |||
| 110 | let on_drop = OnDrop::new(|| unsafe { | ||
| 111 | regs.cr().modify(|w| { | ||
| 112 | w.set_tcie(false); | ||
| 113 | w.set_teie(false); | ||
| 114 | w.set_en(false); | ||
| 115 | }); | ||
| 116 | while regs.cr().read().en() {} | ||
| 117 | }); | ||
| 118 | |||
| 119 | #[cfg(dmamux)] | ||
| 120 | crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 121 | |||
| 122 | regs.par().write_value(dst as u32); | ||
| 123 | regs.mar().write_value(src.as_ptr() as u32); | ||
| 124 | regs.ndtr().write(|w| w.set_ndt(src.len() as u16)); | ||
| 125 | regs.cr().write(|w| { | ||
| 126 | w.set_psize(vals::Size::BITS8); | ||
| 127 | w.set_msize(vals::Size::BITS8); | ||
| 128 | w.set_minc(vals::Inc::ENABLED); | ||
| 129 | w.set_dir(vals::Dir::FROMMEMORY); | ||
| 130 | w.set_teie(true); | ||
| 131 | w.set_tcie(true); | ||
| 132 | w.set_en(true); | ||
| 133 | }); | ||
| 134 | |||
| 135 | let res = poll_fn(|cx| { | ||
| 136 | STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||
| 137 | match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { | ||
| 138 | CH_STATUS_NONE => Poll::Pending, | ||
| 139 | x => Poll::Ready(x), | ||
| 140 | } | ||
| 141 | }) | ||
| 142 | .await; | ||
| 143 | |||
| 144 | // TODO handle error | ||
| 145 | assert!(res == CH_STATUS_COMPLETED); | ||
| 146 | } | ||
| 147 | |||
| 148 | unsafe fn on_irq() { | ||
| 149 | pac::peripherals! { | ||
| 150 | (bdma, $dma:ident) => { | ||
| 151 | let isr = pac::$dma.isr().read(); | ||
| 152 | pac::$dma.ifcr().write_value(isr); | ||
| 153 | let dman = <crate::peripherals::$dma as sealed::Dma>::NUM as usize; | ||
| 154 | |||
| 155 | for chn in 0..crate::pac::dma_channels_count!($dma) { | ||
| 156 | let n = dman * 8 + chn; | ||
| 157 | if isr.teif(chn) { | ||
| 158 | STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); | ||
| 159 | STATE.ch_wakers[n].wake(); | ||
| 160 | } else if isr.tcif(chn) { | ||
| 161 | STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); | ||
| 162 | STATE.ch_wakers[n].wake(); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | }; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | use crate::rcc::sealed::RccPeripheral; | ||
| 170 | |||
| 171 | /// safety: must be called only once | ||
| 172 | pub(crate) unsafe fn init() { | ||
| 173 | pac::interrupts! { | ||
| 174 | (DMA, $irq:ident) => { | ||
| 175 | crate::interrupt::$irq::steal().enable(); | ||
| 176 | }; | ||
| 177 | } | ||
| 178 | pac::peripherals! { | ||
| 179 | (bdma, $peri:ident) => { | ||
| 180 | <crate::peripherals::$peri as RccPeripheral>::enable(); | ||
| 181 | }; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | pub(crate) mod sealed { | ||
| 186 | use super::*; | ||
| 187 | |||
| 188 | pub trait Dma { | ||
| 189 | const NUM: u8; | ||
| 190 | } | ||
| 191 | |||
| 192 | pub trait Channel { | ||
| 193 | const CH_NUM: u8; | ||
| 194 | const STATE_NUM: u8; | ||
| 195 | const DMA_REGS: pac::bdma::Dma; | ||
| 196 | |||
| 197 | fn regs(&self) -> pac::bdma::Ch { | ||
| 198 | Self::DMA_REGS.ch(Self::CH_NUM as usize) | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | pub trait Dma: sealed::Dma + Sized {} | ||
| 204 | pub trait Channel: sealed::Channel + Sized {} | ||
| 205 | |||
| 206 | macro_rules! impl_dma { | ||
| 207 | ($peri:ident) => { | ||
| 208 | impl Dma for crate::peripherals::$peri {} | ||
| 209 | impl sealed::Dma for crate::peripherals::$peri { | ||
| 210 | const NUM: u8 = dma_num!($peri); | ||
| 211 | } | ||
| 212 | }; | ||
| 213 | } | ||
| 214 | |||
| 215 | macro_rules! impl_dma_channel { | ||
| 216 | ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => { | ||
| 217 | impl Channel for crate::peripherals::$channel_peri {} | ||
| 218 | impl sealed::Channel for crate::peripherals::$channel_peri { | ||
| 219 | const CH_NUM: u8 = $ch_num; | ||
| 220 | const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num; | ||
| 221 | const DMA_REGS: pac::bdma::Dma = crate::pac::$dma_peri; | ||
| 222 | |||
| 223 | //#[inline] | ||
| 224 | //fn dma_regs() -> pac::bdma::Dma { | ||
| 225 | //crate::pac::$dma_peri | ||
| 226 | //} | ||
| 227 | |||
| 228 | //fn state_num(&self) -> usize { | ||
| 229 | //(dma_num!($dma_peri) * 8) + $ch_num | ||
| 230 | //} | ||
| 231 | } | ||
| 232 | |||
| 233 | #[cfg(not(dmamux))] | ||
| 234 | impl<T> WriteDma<T> for crate::peripherals::$channel_peri | ||
| 235 | where | ||
| 236 | T: 'static, | ||
| 237 | { | ||
| 238 | type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||
| 239 | |||
| 240 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 241 | where | ||
| 242 | T: 'a, | ||
| 243 | { | ||
| 244 | use sealed::Channel as _Channel; | ||
| 245 | |||
| 246 | let state_num = Self::STATE_NUM; | ||
| 247 | let regs = self.regs(); | ||
| 248 | |||
| 249 | unsafe { transfer_m2p(regs, state_num, buf, dst) } | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | #[cfg(dmamux)] | ||
| 254 | impl<T> WriteDma<T> for crate::peripherals::$channel_peri | ||
| 255 | where | ||
| 256 | Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::M2P>, | ||
| 257 | T: 'static, | ||
| 258 | { | ||
| 259 | type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||
| 260 | |||
| 261 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 262 | where | ||
| 263 | T: 'a, | ||
| 264 | { | ||
| 265 | use sealed::Channel as _Channel; | ||
| 266 | |||
| 267 | let state_num = Self::STATE_NUM; | ||
| 268 | let regs = self.regs(); | ||
| 269 | |||
| 270 | use crate::dmamux::sealed::Channel as MuxChannel; | ||
| 271 | use crate::dmamux::sealed::PeripheralChannel; | ||
| 272 | let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS; | ||
| 273 | let dmamux_ch_num = | ||
| 274 | <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM; | ||
| 275 | let request = <crate::peripherals::$channel_peri as PeripheralChannel< | ||
| 276 | T, | ||
| 277 | crate::dmamux::M2P, | ||
| 278 | >>::REQUEST; | ||
| 279 | unsafe { | ||
| 280 | transfer_m2p( | ||
| 281 | regs, | ||
| 282 | state_num, | ||
| 283 | buf, | ||
| 284 | dst, | ||
| 285 | dmamux_regs, | ||
| 286 | dmamux_ch_num, | ||
| 287 | request, | ||
| 288 | ) | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | #[cfg(not(dmamux))] | ||
| 294 | impl<T> ReadDma<T> for crate::peripherals::$channel_peri | ||
| 295 | where | ||
| 296 | T: 'static, | ||
| 297 | { | ||
| 298 | type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||
| 299 | |||
| 300 | fn transfer<'a>( | ||
| 301 | &'a mut self, | ||
| 302 | src: *const u8, | ||
| 303 | buf: &'a mut [u8], | ||
| 304 | ) -> Self::ReadDmaFuture<'a> | ||
| 305 | where | ||
| 306 | T: 'a, | ||
| 307 | { | ||
| 308 | use sealed::Channel as _Channel; | ||
| 309 | |||
| 310 | let state_num = Self::STATE_NUM; | ||
| 311 | let regs = self.regs(); | ||
| 312 | unsafe { transfer_p2m(regs, state_num, src, buf) } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | #[cfg(dmamux)] | ||
| 317 | impl<T> ReadDma<T> for crate::peripherals::$channel_peri | ||
| 318 | where | ||
| 319 | Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::P2M>, | ||
| 320 | T: 'static, | ||
| 321 | { | ||
| 322 | type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||
| 323 | |||
| 324 | fn transfer<'a>( | ||
| 325 | &'a mut self, | ||
| 326 | src: *const u8, | ||
| 327 | buf: &'a mut [u8], | ||
| 328 | ) -> Self::ReadDmaFuture<'a> | ||
| 329 | where | ||
| 330 | T: 'a, | ||
| 331 | { | ||
| 332 | use sealed::Channel as _Channel; | ||
| 333 | |||
| 334 | let state_num = Self::STATE_NUM; | ||
| 335 | let regs = self.regs(); | ||
| 336 | |||
| 337 | use crate::dmamux::sealed::Channel as MuxChannel; | ||
| 338 | use crate::dmamux::sealed::PeripheralChannel; | ||
| 339 | let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS; | ||
| 340 | let dmamux_ch_num = | ||
| 341 | <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM; | ||
| 342 | let request = <crate::peripherals::$channel_peri as PeripheralChannel< | ||
| 343 | T, | ||
| 344 | crate::dmamux::P2M, | ||
| 345 | >>::REQUEST; | ||
| 346 | unsafe { | ||
| 347 | transfer_p2m( | ||
| 348 | regs, | ||
| 349 | state_num, | ||
| 350 | src, | ||
| 351 | buf, | ||
| 352 | dmamux_regs, | ||
| 353 | dmamux_ch_num, | ||
| 354 | request, | ||
| 355 | ) | ||
| 356 | } | ||
| 357 | } | ||
| 358 | } | ||
| 359 | }; | ||
| 360 | } | ||
| 361 | |||
| 362 | macro_rules! dma_num { | ||
| 363 | (DMA1) => { | ||
| 364 | 0 | ||
| 365 | }; | ||
| 366 | (DMA2) => { | ||
| 367 | 1 | ||
| 368 | }; | ||
| 369 | (BDMA) => { | ||
| 370 | 0 | ||
| 371 | }; | ||
| 372 | } | ||
| 373 | pac::peripherals! { | ||
| 374 | (bdma, $peri:ident) => { | ||
| 375 | impl_dma!($peri); | ||
| 376 | }; | ||
| 377 | } | ||
| 378 | |||
| 379 | pac::bdma_channels! { | ||
| 380 | ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||
| 381 | impl_dma_channel!($channel_peri, $dma_peri, $channel_num); | ||
| 382 | }; | ||
| 383 | } | ||
| 384 | |||
| 385 | pac::interrupts! { | ||
| 386 | (DMA, $irq:ident) => { | ||
| 387 | #[crate::interrupt] | ||
| 388 | unsafe fn $irq () { | ||
| 389 | on_irq() | ||
| 390 | } | ||
| 391 | }; | ||
| 392 | } | ||
| 393 | |||
| 394 | #[cfg(usart)] | ||
| 395 | use crate::usart; | ||
| 396 | |||
| 397 | pac::peripherals! { | ||
| 398 | (usart, $peri:ident) => { | ||
| 399 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {} | ||
| 400 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {} | ||
| 401 | |||
| 402 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {} | ||
| 403 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {} | ||
| 404 | }; | ||
| 405 | |||
| 406 | (uart, $peri:ident) => { | ||
| 407 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {} | ||
| 408 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {} | ||
| 409 | |||
| 410 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {} | ||
| 411 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {} | ||
| 412 | }; | ||
| 413 | } | ||
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs new file mode 100644 index 000000000..4c26a9501 --- /dev/null +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -0,0 +1,219 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use core::future::Future; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 7 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 8 | use embassy::util::{AtomicWaker, OnDrop}; | ||
| 9 | use futures::future::poll_fn; | ||
| 10 | |||
| 11 | use crate::dma::{Channel, Request}; | ||
| 12 | use crate::interrupt; | ||
| 13 | use crate::pac; | ||
| 14 | use crate::pac::bdma::vals; | ||
| 15 | use crate::rcc::sealed::RccPeripheral; | ||
| 16 | |||
| 17 | const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; | ||
| 18 | const CH_STATUS_NONE: u8 = 0; | ||
| 19 | const CH_STATUS_COMPLETED: u8 = 1; | ||
| 20 | const CH_STATUS_ERROR: u8 = 2; | ||
| 21 | |||
| 22 | struct State { | ||
| 23 | ch_wakers: [AtomicWaker; CH_COUNT], | ||
| 24 | ch_status: [AtomicU8; CH_COUNT], | ||
| 25 | } | ||
| 26 | |||
| 27 | impl State { | ||
| 28 | const fn new() -> Self { | ||
| 29 | const AW: AtomicWaker = AtomicWaker::new(); | ||
| 30 | const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); | ||
| 31 | Self { | ||
| 32 | ch_wakers: [AW; CH_COUNT], | ||
| 33 | ch_status: [AU; CH_COUNT], | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | static STATE: State = State::new(); | ||
| 39 | |||
| 40 | #[allow(unused)] | ||
| 41 | pub(crate) async unsafe fn do_transfer( | ||
| 42 | dma: pac::bdma::Dma, | ||
| 43 | channel_number: u8, | ||
| 44 | state_number: u8, | ||
| 45 | request: Request, | ||
| 46 | dir: vals::Dir, | ||
| 47 | peri_addr: *const u8, | ||
| 48 | mem_addr: *mut u8, | ||
| 49 | mem_len: usize, | ||
| 50 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 51 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 52 | ) { | ||
| 53 | // ndtr is max 16 bits. | ||
| 54 | assert!(mem_len <= 0xFFFF); | ||
| 55 | |||
| 56 | let ch = dma.ch(channel_number as _); | ||
| 57 | |||
| 58 | // Reset status | ||
| 59 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 60 | STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||
| 61 | |||
| 62 | let on_drop = OnDrop::new(|| unsafe { | ||
| 63 | ch.cr().modify(|w| { | ||
| 64 | w.set_tcie(false); | ||
| 65 | w.set_teie(false); | ||
| 66 | w.set_en(false); | ||
| 67 | }); | ||
| 68 | while ch.cr().read().en() {} | ||
| 69 | }); | ||
| 70 | |||
| 71 | #[cfg(dmamux)] | ||
| 72 | super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 73 | |||
| 74 | #[cfg(bdma_v2)] | ||
| 75 | critical_section::with(|_| { | ||
| 76 | dma.cselr() | ||
| 77 | .modify(|w| w.set_cs(channel_number as _, request)) | ||
| 78 | }); | ||
| 79 | |||
| 80 | ch.par().write_value(peri_addr as u32); | ||
| 81 | ch.mar().write_value(mem_addr as u32); | ||
| 82 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); | ||
| 83 | ch.cr().write(|w| { | ||
| 84 | w.set_psize(vals::Size::BITS8); | ||
| 85 | w.set_msize(vals::Size::BITS8); | ||
| 86 | w.set_minc(vals::Inc::ENABLED); | ||
| 87 | w.set_dir(dir); | ||
| 88 | w.set_teie(true); | ||
| 89 | w.set_tcie(true); | ||
| 90 | w.set_en(true); | ||
| 91 | }); | ||
| 92 | |||
| 93 | let res = poll_fn(|cx| { | ||
| 94 | STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||
| 95 | match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { | ||
| 96 | CH_STATUS_NONE => Poll::Pending, | ||
| 97 | x => Poll::Ready(x), | ||
| 98 | } | ||
| 99 | }) | ||
| 100 | .await; | ||
| 101 | |||
| 102 | // TODO handle error | ||
| 103 | assert!(res == CH_STATUS_COMPLETED); | ||
| 104 | } | ||
| 105 | |||
| 106 | macro_rules! dma_num { | ||
| 107 | (DMA1) => { | ||
| 108 | 0 | ||
| 109 | }; | ||
| 110 | (DMA2) => { | ||
| 111 | 1 | ||
| 112 | }; | ||
| 113 | (BDMA) => { | ||
| 114 | 0 | ||
| 115 | }; | ||
| 116 | } | ||
| 117 | |||
| 118 | unsafe fn on_irq() { | ||
| 119 | pac::peripherals! { | ||
| 120 | (bdma, $dma:ident) => { | ||
| 121 | let isr = pac::$dma.isr().read(); | ||
| 122 | pac::$dma.ifcr().write_value(isr); | ||
| 123 | let dman = dma_num!($dma); | ||
| 124 | |||
| 125 | for chn in 0..crate::pac::dma_channels_count!($dma) { | ||
| 126 | let n = dman * 8 + chn; | ||
| 127 | if isr.teif(chn) { | ||
| 128 | STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); | ||
| 129 | STATE.ch_wakers[n].wake(); | ||
| 130 | } else if isr.tcif(chn) { | ||
| 131 | STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); | ||
| 132 | STATE.ch_wakers[n].wake(); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | }; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /// safety: must be called only once | ||
| 140 | pub(crate) unsafe fn init() { | ||
| 141 | pac::interrupts! { | ||
| 142 | (BDMA, $irq:ident) => { | ||
| 143 | crate::interrupt::$irq::steal().enable(); | ||
| 144 | }; | ||
| 145 | } | ||
| 146 | pac::peripherals! { | ||
| 147 | (bdma, $peri:ident) => { | ||
| 148 | crate::peripherals::$peri::enable(); | ||
| 149 | }; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | pac::dma_channels! { | ||
| 154 | ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => { | ||
| 155 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} | ||
| 156 | impl Channel for crate::peripherals::$channel_peri | ||
| 157 | { | ||
| 158 | type ReadFuture<'a> = impl Future<Output = ()>; | ||
| 159 | type WriteFuture<'a> = impl Future<Output = ()>; | ||
| 160 | |||
| 161 | fn read<'a>( | ||
| 162 | &'a mut self, | ||
| 163 | request: Request, | ||
| 164 | src: *mut u8, | ||
| 165 | buf: &'a mut [u8], | ||
| 166 | ) -> Self::ReadFuture<'a> { | ||
| 167 | unsafe { | ||
| 168 | do_transfer( | ||
| 169 | crate::pac::$dma_peri, | ||
| 170 | $channel_num, | ||
| 171 | (dma_num!($dma_peri) * 8) + $channel_num, | ||
| 172 | request, | ||
| 173 | vals::Dir::FROMPERIPHERAL, | ||
| 174 | src, | ||
| 175 | buf.as_mut_ptr(), | ||
| 176 | buf.len(), | ||
| 177 | #[cfg(dmamux)] | ||
| 178 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 179 | #[cfg(dmamux)] | ||
| 180 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 181 | ) | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | fn write<'a>( | ||
| 186 | &'a mut self, | ||
| 187 | request: Request, | ||
| 188 | buf: &'a [u8], | ||
| 189 | dst: *mut u8, | ||
| 190 | ) -> Self::WriteFuture<'a> { | ||
| 191 | unsafe { | ||
| 192 | do_transfer( | ||
| 193 | crate::pac::$dma_peri, | ||
| 194 | $channel_num, | ||
| 195 | (dma_num!($dma_peri) * 8) + $channel_num, | ||
| 196 | request, | ||
| 197 | vals::Dir::FROMMEMORY, | ||
| 198 | dst, | ||
| 199 | buf.as_ptr() as *mut u8, | ||
| 200 | buf.len(), | ||
| 201 | #[cfg(dmamux)] | ||
| 202 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 203 | #[cfg(dmamux)] | ||
| 204 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 205 | ) | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | }; | ||
| 210 | } | ||
| 211 | |||
| 212 | pac::interrupts! { | ||
| 213 | (BDMA, $irq:ident) => { | ||
| 214 | #[crate::interrupt] | ||
| 215 | unsafe fn $irq () { | ||
| 216 | on_irq() | ||
| 217 | } | ||
| 218 | }; | ||
| 219 | } | ||
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs new file mode 100644 index 000000000..591279ef8 --- /dev/null +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | use core::task::Poll; | ||
| 2 | |||
| 3 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 4 | use core::future::Future; | ||
| 5 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 6 | use embassy::util::{AtomicWaker, OnDrop}; | ||
| 7 | use futures::future::poll_fn; | ||
| 8 | |||
| 9 | use crate::interrupt; | ||
| 10 | use crate::pac; | ||
| 11 | use crate::pac::dma::{regs, vals}; | ||
| 12 | use crate::rcc::sealed::RccPeripheral; | ||
| 13 | |||
| 14 | use super::{Channel, Request}; | ||
| 15 | |||
| 16 | const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; | ||
| 17 | const CH_STATUS_NONE: u8 = 0; | ||
| 18 | const CH_STATUS_COMPLETED: u8 = 1; | ||
| 19 | const CH_STATUS_ERROR: u8 = 2; | ||
| 20 | |||
| 21 | struct State { | ||
| 22 | ch_wakers: [AtomicWaker; CH_COUNT], | ||
| 23 | ch_status: [AtomicU8; CH_COUNT], | ||
| 24 | } | ||
| 25 | |||
| 26 | impl State { | ||
| 27 | const fn new() -> Self { | ||
| 28 | const AW: AtomicWaker = AtomicWaker::new(); | ||
| 29 | const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); | ||
| 30 | Self { | ||
| 31 | ch_wakers: [AW; CH_COUNT], | ||
| 32 | ch_status: [AU; CH_COUNT], | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | static STATE: State = State::new(); | ||
| 38 | |||
| 39 | //async unsafe fn do_transfer(ch: &mut impl Channel, ch_func: u8, src: *const u8, dst: &mut [u8]) { | ||
| 40 | |||
| 41 | #[allow(unused)] | ||
| 42 | pub(crate) async unsafe fn do_transfer( | ||
| 43 | dma: pac::dma::Dma, | ||
| 44 | channel_number: u8, | ||
| 45 | state_number: u8, | ||
| 46 | request: Request, | ||
| 47 | dir: vals::Dir, | ||
| 48 | peri_addr: *const u8, | ||
| 49 | mem_addr: *mut u8, | ||
| 50 | mem_len: usize, | ||
| 51 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 52 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 53 | ) { | ||
| 54 | // ndtr is max 16 bits. | ||
| 55 | assert!(mem_len <= 0xFFFF); | ||
| 56 | |||
| 57 | // Reset status | ||
| 58 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 59 | STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||
| 60 | |||
| 61 | let ch = dma.st(channel_number as _); | ||
| 62 | |||
| 63 | let on_drop = OnDrop::new(|| unsafe { | ||
| 64 | ch.cr().modify(|w| { | ||
| 65 | w.set_tcie(false); | ||
| 66 | w.set_teie(false); | ||
| 67 | w.set_en(false); | ||
| 68 | }); | ||
| 69 | while ch.cr().read().en() {} | ||
| 70 | }); | ||
| 71 | |||
| 72 | #[cfg(dmamux)] | ||
| 73 | super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 74 | |||
| 75 | unsafe { | ||
| 76 | ch.par().write_value(peri_addr as u32); | ||
| 77 | ch.m0ar().write_value(mem_addr as u32); | ||
| 78 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); | ||
| 79 | ch.cr().write(|w| { | ||
| 80 | w.set_dir(dir); | ||
| 81 | w.set_msize(vals::Size::BITS8); | ||
| 82 | w.set_psize(vals::Size::BITS8); | ||
| 83 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 84 | w.set_pinc(vals::Inc::FIXED); | ||
| 85 | w.set_teie(true); | ||
| 86 | w.set_tcie(true); | ||
| 87 | #[cfg(dma_v1)] | ||
| 88 | w.set_trbuff(true); | ||
| 89 | w.set_en(true); | ||
| 90 | |||
| 91 | #[cfg(dma_v2)] | ||
| 92 | w.set_chsel(request); | ||
| 93 | }); | ||
| 94 | } | ||
| 95 | |||
| 96 | let res = poll_fn(|cx| { | ||
| 97 | let n = channel_number as usize; | ||
| 98 | STATE.ch_wakers[n].register(cx.waker()); | ||
| 99 | match STATE.ch_status[n].load(Ordering::Acquire) { | ||
| 100 | CH_STATUS_NONE => Poll::Pending, | ||
| 101 | x => Poll::Ready(x), | ||
| 102 | } | ||
| 103 | }) | ||
| 104 | .await; | ||
| 105 | |||
| 106 | // TODO handle error | ||
| 107 | assert!(res == CH_STATUS_COMPLETED); | ||
| 108 | } | ||
| 109 | |||
| 110 | macro_rules! dma_num { | ||
| 111 | (DMA1) => { | ||
| 112 | 0 | ||
| 113 | }; | ||
| 114 | (DMA2) => { | ||
| 115 | 1 | ||
| 116 | }; | ||
| 117 | } | ||
| 118 | |||
| 119 | unsafe fn on_irq() { | ||
| 120 | pac::peripherals! { | ||
| 121 | (dma, $dma:ident) => { | ||
| 122 | for isrn in 0..2 { | ||
| 123 | let isr = pac::$dma.isr(isrn).read(); | ||
| 124 | pac::$dma.ifcr(isrn).write_value(isr); | ||
| 125 | let dman = dma_num!($dma); | ||
| 126 | |||
| 127 | for chn in 0..4 { | ||
| 128 | let n = dman * 8 + isrn * 4 + chn; | ||
| 129 | if isr.teif(chn) { | ||
| 130 | STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); | ||
| 131 | STATE.ch_wakers[n].wake(); | ||
| 132 | } else if isr.tcif(chn) { | ||
| 133 | STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); | ||
| 134 | STATE.ch_wakers[n].wake(); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | }; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | /// safety: must be called only once | ||
| 143 | pub(crate) unsafe fn init() { | ||
| 144 | pac::interrupts! { | ||
| 145 | (DMA, $irq:ident) => { | ||
| 146 | interrupt::$irq::steal().enable(); | ||
| 147 | }; | ||
| 148 | } | ||
| 149 | pac::peripherals! { | ||
| 150 | (dma, $peri:ident) => { | ||
| 151 | crate::peripherals::$peri::enable(); | ||
| 152 | }; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | pac::dma_channels! { | ||
| 157 | ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { | ||
| 158 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} | ||
| 159 | impl Channel for crate::peripherals::$channel_peri | ||
| 160 | { | ||
| 161 | type ReadFuture<'a> = impl Future<Output = ()>; | ||
| 162 | type WriteFuture<'a> = impl Future<Output = ()>; | ||
| 163 | |||
| 164 | fn read<'a>( | ||
| 165 | &'a mut self, | ||
| 166 | request: Request, | ||
| 167 | src: *mut u8, | ||
| 168 | buf: &'a mut [u8], | ||
| 169 | ) -> Self::ReadFuture<'a> { | ||
| 170 | unsafe { | ||
| 171 | do_transfer( | ||
| 172 | crate::pac::$dma_peri, | ||
| 173 | $channel_num, | ||
| 174 | (dma_num!($dma_peri) * 8) + $channel_num, | ||
| 175 | request, | ||
| 176 | vals::Dir::PERIPHERALTOMEMORY, | ||
| 177 | src, | ||
| 178 | buf.as_mut_ptr(), | ||
| 179 | buf.len(), | ||
| 180 | #[cfg(dmamux)] | ||
| 181 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 182 | #[cfg(dmamux)] | ||
| 183 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 184 | ) | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | fn write<'a>( | ||
| 189 | &'a mut self, | ||
| 190 | request: Request, | ||
| 191 | buf: &'a [u8], | ||
| 192 | dst: *mut u8, | ||
| 193 | ) -> Self::WriteFuture<'a> { | ||
| 194 | unsafe { | ||
| 195 | do_transfer( | ||
| 196 | crate::pac::$dma_peri, | ||
| 197 | $channel_num, | ||
| 198 | (dma_num!($dma_peri) * 8) + $channel_num, | ||
| 199 | request, | ||
| 200 | vals::Dir::MEMORYTOPERIPHERAL, | ||
| 201 | dst, | ||
| 202 | buf.as_ptr() as *mut u8, | ||
| 203 | buf.len(), | ||
| 204 | #[cfg(dmamux)] | ||
| 205 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 206 | #[cfg(dmamux)] | ||
| 207 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 208 | ) | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | }; | ||
| 213 | } | ||
| 214 | |||
| 215 | pac::interrupts! { | ||
| 216 | (DMA, $irq:ident) => { | ||
| 217 | #[crate::interrupt] | ||
| 218 | unsafe fn $irq () { | ||
| 219 | on_irq() | ||
| 220 | } | ||
| 221 | }; | ||
| 222 | } | ||
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs new file mode 100644 index 000000000..718859a44 --- /dev/null +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use crate::pac; | ||
| 4 | use crate::peripherals; | ||
| 5 | |||
| 6 | pub(crate) unsafe fn configure_dmamux( | ||
| 7 | dmamux_regs: pac::dmamux::Dmamux, | ||
| 8 | dmamux_ch_num: u8, | ||
| 9 | request: u8, | ||
| 10 | ) { | ||
| 11 | let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _); | ||
| 12 | ch_mux_regs.write(|reg| { | ||
| 13 | reg.set_nbreq(0); | ||
| 14 | reg.set_dmareq_id(request); | ||
| 15 | }); | ||
| 16 | |||
| 17 | ch_mux_regs.modify(|reg| { | ||
| 18 | reg.set_ege(true); | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | pub(crate) mod sealed { | ||
| 23 | use super::*; | ||
| 24 | pub trait MuxChannel { | ||
| 25 | const DMAMUX_CH_NUM: u8; | ||
| 26 | const DMAMUX_REGS: pac::dmamux::Dmamux; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | pub struct DMAMUX1; | ||
| 31 | #[cfg(rcc_h7)] | ||
| 32 | pub struct DMAMUX2; | ||
| 33 | |||
| 34 | pub trait MuxChannel: sealed::MuxChannel + super::Channel { | ||
| 35 | type Mux; | ||
| 36 | } | ||
| 37 | |||
| 38 | pac::dma_channels! { | ||
| 39 | ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { | ||
| 40 | impl sealed::MuxChannel for peripherals::$channel_peri { | ||
| 41 | const DMAMUX_CH_NUM: u8 = $dmamux_channel; | ||
| 42 | const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux; | ||
| 43 | } | ||
| 44 | impl MuxChannel for peripherals::$channel_peri { | ||
| 45 | type Mux = $dmamux; | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | } | ||
| 49 | |||
| 50 | /// safety: must be called only once | ||
| 51 | pub(crate) unsafe fn init() {} | ||
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index ed080cd16..fbf82b87b 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -1,9 +1,65 @@ | |||
| 1 | #![macro_use] | 1 | #[cfg(bdma)] |
| 2 | mod bdma; | ||
| 3 | #[cfg(dma)] | ||
| 4 | mod dma; | ||
| 5 | #[cfg(dmamux)] | ||
| 6 | mod dmamux; | ||
| 2 | 7 | ||
| 3 | #[cfg_attr(dma_v1, path = "v1.rs")] | 8 | #[cfg(dmamux)] |
| 4 | #[cfg_attr(dma_v2, path = "v2.rs")] | 9 | pub use dmamux::*; |
| 5 | mod _version; | ||
| 6 | 10 | ||
| 7 | #[cfg(dma)] | 11 | use core::future::Future; |
| 8 | #[allow(unused)] | 12 | use embassy::util::Unborrow; |
| 9 | pub use _version::*; | 13 | |
| 14 | #[cfg(any(bdma_v2, dma_v2, dmamux))] | ||
| 15 | pub type Request = u8; | ||
| 16 | #[cfg(not(any(bdma_v2, dma_v2, dmamux)))] | ||
| 17 | pub type Request = (); | ||
| 18 | |||
| 19 | pub(crate) mod sealed { | ||
| 20 | pub trait Channel {} | ||
| 21 | } | ||
| 22 | |||
| 23 | pub trait Channel: sealed::Channel { | ||
| 24 | type ReadFuture<'a>: Future<Output = ()> + 'a | ||
| 25 | where | ||
| 26 | Self: 'a; | ||
| 27 | |||
| 28 | type WriteFuture<'a>: Future<Output = ()> + 'a | ||
| 29 | where | ||
| 30 | Self: 'a; | ||
| 31 | |||
| 32 | fn read<'a>( | ||
| 33 | &'a mut self, | ||
| 34 | request: Request, | ||
| 35 | src: *mut u8, | ||
| 36 | buf: &'a mut [u8], | ||
| 37 | ) -> Self::ReadFuture<'a>; | ||
| 38 | |||
| 39 | fn write<'a>( | ||
| 40 | &'a mut self, | ||
| 41 | request: Request, | ||
| 42 | buf: &'a [u8], | ||
| 43 | dst: *mut u8, | ||
| 44 | ) -> Self::WriteFuture<'a>; | ||
| 45 | } | ||
| 46 | |||
| 47 | pub struct NoDma; | ||
| 48 | |||
| 49 | unsafe impl Unborrow for NoDma { | ||
| 50 | type Target = NoDma; | ||
| 51 | |||
| 52 | unsafe fn unborrow(self) -> Self::Target { | ||
| 53 | self | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | // safety: must be called only once at startup | ||
| 58 | pub(crate) unsafe fn init() { | ||
| 59 | #[cfg(bdma)] | ||
| 60 | bdma::init(); | ||
| 61 | #[cfg(dma)] | ||
| 62 | dma::init(); | ||
| 63 | #[cfg(dmamux)] | ||
| 64 | dmamux::init(); | ||
| 65 | } | ||
diff --git a/embassy-stm32/src/dma/v1.rs b/embassy-stm32/src/dma/v1.rs deleted file mode 100644 index 4544108e5..000000000 --- a/embassy-stm32/src/dma/v1.rs +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | /// safety: must be called only once | ||
| 2 | pub(crate) unsafe fn init() {} | ||
diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs deleted file mode 100644 index df3b922ff..000000000 --- a/embassy-stm32/src/dma/v2.rs +++ /dev/null | |||
| @@ -1,331 +0,0 @@ | |||
| 1 | use core::task::Poll; | ||
| 2 | |||
| 3 | use crate::dma_traits::{ReadDma, WriteDma}; | ||
| 4 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 5 | use core::future::Future; | ||
| 6 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 7 | use embassy::util::AtomicWaker; | ||
| 8 | use futures::future::poll_fn; | ||
| 9 | |||
| 10 | use crate::interrupt; | ||
| 11 | use crate::pac; | ||
| 12 | use crate::pac::dma::{regs, vals}; | ||
| 13 | |||
| 14 | use crate::pac::dma_channels; | ||
| 15 | use crate::pac::interrupts; | ||
| 16 | use crate::pac::peripheral_count; | ||
| 17 | use crate::pac::peripheral_dma_channels; | ||
| 18 | use crate::pac::peripherals; | ||
| 19 | use crate::peripherals; | ||
| 20 | |||
| 21 | const CH_COUNT: usize = peripheral_count!(DMA) * 8; | ||
| 22 | const CH_STATUS_NONE: u8 = 0; | ||
| 23 | const CH_STATUS_COMPLETED: u8 = 1; | ||
| 24 | const CH_STATUS_ERROR: u8 = 2; | ||
| 25 | |||
| 26 | struct State { | ||
| 27 | ch_wakers: [AtomicWaker; CH_COUNT], | ||
| 28 | ch_status: [AtomicU8; CH_COUNT], | ||
| 29 | } | ||
| 30 | |||
| 31 | impl State { | ||
| 32 | const fn new() -> Self { | ||
| 33 | const AW: AtomicWaker = AtomicWaker::new(); | ||
| 34 | const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); | ||
| 35 | Self { | ||
| 36 | ch_wakers: [AW; CH_COUNT], | ||
| 37 | ch_status: [AU; CH_COUNT], | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | static STATE: State = State::new(); | ||
| 43 | |||
| 44 | #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled | ||
| 45 | pub(crate) async unsafe fn transfer_p2m( | ||
| 46 | ch: &mut impl Channel, | ||
| 47 | ch_func: u8, | ||
| 48 | src: *const u8, | ||
| 49 | dst: &mut [u8], | ||
| 50 | ) { | ||
| 51 | let n = ch.num(); | ||
| 52 | let c = ch.regs(); | ||
| 53 | |||
| 54 | // ndtr is max 16 bits. | ||
| 55 | assert!(dst.len() <= 0xFFFF); | ||
| 56 | |||
| 57 | // Reset status | ||
| 58 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 59 | STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release); | ||
| 60 | |||
| 61 | unsafe { | ||
| 62 | c.par().write_value(src as _); | ||
| 63 | c.m0ar().write_value(dst.as_ptr() as _); | ||
| 64 | c.ndtr().write_value(regs::Ndtr(dst.len() as _)); | ||
| 65 | c.cr().write(|w| { | ||
| 66 | w.set_dir(vals::Dir::PERIPHERALTOMEMORY); | ||
| 67 | w.set_msize(vals::Size::BITS8); | ||
| 68 | w.set_psize(vals::Size::BITS8); | ||
| 69 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 70 | w.set_pinc(vals::Inc::FIXED); | ||
| 71 | w.set_chsel(ch_func); | ||
| 72 | w.set_teie(true); | ||
| 73 | w.set_tcie(true); | ||
| 74 | w.set_en(true); | ||
| 75 | }); | ||
| 76 | } | ||
| 77 | |||
| 78 | let res = poll_fn(|cx| { | ||
| 79 | STATE.ch_wakers[n].register(cx.waker()); | ||
| 80 | match STATE.ch_status[n].load(Ordering::Acquire) { | ||
| 81 | CH_STATUS_NONE => Poll::Pending, | ||
| 82 | x => Poll::Ready(x), | ||
| 83 | } | ||
| 84 | }) | ||
| 85 | .await; | ||
| 86 | |||
| 87 | // TODO handle error | ||
| 88 | assert!(res == CH_STATUS_COMPLETED); | ||
| 89 | } | ||
| 90 | |||
| 91 | #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled | ||
| 92 | pub(crate) async unsafe fn transfer_m2p( | ||
| 93 | ch: &mut impl Channel, | ||
| 94 | ch_func: u8, | ||
| 95 | src: &[u8], | ||
| 96 | dst: *mut u8, | ||
| 97 | ) { | ||
| 98 | let n = ch.num(); | ||
| 99 | let c = ch.regs(); | ||
| 100 | |||
| 101 | // ndtr is max 16 bits. | ||
| 102 | assert!(src.len() <= 0xFFFF); | ||
| 103 | |||
| 104 | // Reset status | ||
| 105 | // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||
| 106 | STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release); | ||
| 107 | |||
| 108 | unsafe { | ||
| 109 | c.par().write_value(dst as _); | ||
| 110 | c.m0ar().write_value(src.as_ptr() as _); | ||
| 111 | c.ndtr().write_value(regs::Ndtr(src.len() as _)); | ||
| 112 | c.cr().write(|w| { | ||
| 113 | w.set_dir(vals::Dir::MEMORYTOPERIPHERAL); | ||
| 114 | w.set_msize(vals::Size::BITS8); | ||
| 115 | w.set_psize(vals::Size::BITS8); | ||
| 116 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 117 | w.set_pinc(vals::Inc::FIXED); | ||
| 118 | w.set_chsel(ch_func); | ||
| 119 | w.set_teie(true); | ||
| 120 | w.set_tcie(true); | ||
| 121 | w.set_en(true); | ||
| 122 | }); | ||
| 123 | } | ||
| 124 | |||
| 125 | let res = poll_fn(|cx| { | ||
| 126 | STATE.ch_wakers[n].register(cx.waker()); | ||
| 127 | match STATE.ch_status[n].load(Ordering::Acquire) { | ||
| 128 | CH_STATUS_NONE => { | ||
| 129 | let left = c.ndtr().read().ndt(); | ||
| 130 | Poll::Pending | ||
| 131 | } | ||
| 132 | x => Poll::Ready(x), | ||
| 133 | } | ||
| 134 | }) | ||
| 135 | .await; | ||
| 136 | |||
| 137 | // TODO handle error | ||
| 138 | assert!(res == CH_STATUS_COMPLETED); | ||
| 139 | } | ||
| 140 | |||
| 141 | unsafe fn on_irq() { | ||
| 142 | peripherals! { | ||
| 143 | (dma, $dma:ident) => { | ||
| 144 | for isrn in 0..2 { | ||
| 145 | let isr = pac::$dma.isr(isrn).read(); | ||
| 146 | pac::$dma.ifcr(isrn).write_value(isr); | ||
| 147 | let dman = <peripherals::$dma as sealed::Dma>::num() as usize; | ||
| 148 | |||
| 149 | for chn in 0..4 { | ||
| 150 | let n = dman * 8 + isrn * 4 + chn; | ||
| 151 | if isr.teif(chn) { | ||
| 152 | STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); | ||
| 153 | STATE.ch_wakers[n].wake(); | ||
| 154 | } else if isr.tcif(chn) { | ||
| 155 | STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); | ||
| 156 | STATE.ch_wakers[n].wake(); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | }; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | /// safety: must be called only once | ||
| 165 | pub(crate) unsafe fn init() { | ||
| 166 | interrupts! { | ||
| 167 | (DMA, $irq:ident) => { | ||
| 168 | interrupt::$irq::steal().enable(); | ||
| 169 | }; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | pub(crate) mod sealed { | ||
| 174 | use super::*; | ||
| 175 | |||
| 176 | pub trait Dma { | ||
| 177 | fn num() -> u8; | ||
| 178 | fn regs() -> &'static pac::dma::Dma; | ||
| 179 | } | ||
| 180 | |||
| 181 | pub trait Channel { | ||
| 182 | fn dma_regs() -> &'static pac::dma::Dma; | ||
| 183 | |||
| 184 | fn num(&self) -> usize; | ||
| 185 | |||
| 186 | fn ch_num(&self) -> u8; | ||
| 187 | |||
| 188 | fn regs(&self) -> pac::dma::St { | ||
| 189 | Self::dma_regs().st(self.ch_num() as _) | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | pub trait PeripheralChannel<PERI, OP>: Channel { | ||
| 194 | fn request(&self) -> u8; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | pub trait Dma: sealed::Dma + Sized {} | ||
| 199 | pub trait Channel: sealed::Channel + Sized {} | ||
| 200 | pub trait PeripheralChannel<PERI, OP>: sealed::PeripheralChannel<PERI, OP> + Sized {} | ||
| 201 | |||
| 202 | macro_rules! impl_dma { | ||
| 203 | ($peri:ident, $num:expr) => { | ||
| 204 | impl Dma for peripherals::$peri {} | ||
| 205 | impl sealed::Dma for peripherals::$peri { | ||
| 206 | fn num() -> u8 { | ||
| 207 | $num | ||
| 208 | } | ||
| 209 | fn regs() -> &'static pac::dma::Dma { | ||
| 210 | &pac::$peri | ||
| 211 | } | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | } | ||
| 215 | |||
| 216 | macro_rules! impl_dma_channel { | ||
| 217 | ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { | ||
| 218 | impl Channel for peripherals::$channel_peri {} | ||
| 219 | impl sealed::Channel for peripherals::$channel_peri { | ||
| 220 | #[inline] | ||
| 221 | fn dma_regs() -> &'static pac::dma::Dma { | ||
| 222 | &crate::pac::$dma_peri | ||
| 223 | } | ||
| 224 | |||
| 225 | fn num(&self) -> usize { | ||
| 226 | ($dma_num * 8) + $ch_num | ||
| 227 | } | ||
| 228 | |||
| 229 | fn ch_num(&self) -> u8 { | ||
| 230 | $ch_num | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | impl<T> WriteDma<T> for peripherals::$channel_peri | ||
| 235 | where | ||
| 236 | Self: sealed::PeripheralChannel<T, M2P>, | ||
| 237 | T: 'static, | ||
| 238 | { | ||
| 239 | type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||
| 240 | |||
| 241 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 242 | where | ||
| 243 | T: 'a, | ||
| 244 | { | ||
| 245 | let request = sealed::PeripheralChannel::<T, M2P>::request(self); | ||
| 246 | unsafe { transfer_m2p(self, request, buf, dst) } | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | impl<T> ReadDma<T> for peripherals::$channel_peri | ||
| 251 | where | ||
| 252 | Self: sealed::PeripheralChannel<T, P2M>, | ||
| 253 | T: 'static, | ||
| 254 | { | ||
| 255 | type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||
| 256 | |||
| 257 | fn transfer<'a>( | ||
| 258 | &'a mut self, | ||
| 259 | src: *const u8, | ||
| 260 | buf: &'a mut [u8], | ||
| 261 | ) -> Self::ReadDmaFuture<'a> | ||
| 262 | where | ||
| 263 | T: 'a, | ||
| 264 | { | ||
| 265 | let request = sealed::PeripheralChannel::<T, P2M>::request(self); | ||
| 266 | unsafe { transfer_p2m(self, request, src, buf) } | ||
| 267 | } | ||
| 268 | } | ||
| 269 | }; | ||
| 270 | } | ||
| 271 | |||
| 272 | peripherals! { | ||
| 273 | (dma, DMA1) => { | ||
| 274 | impl_dma!(DMA1, 0); | ||
| 275 | dma_channels! { | ||
| 276 | ($channel_peri:ident, DMA1, $channel_num:expr) => { | ||
| 277 | impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); | ||
| 278 | }; | ||
| 279 | } | ||
| 280 | }; | ||
| 281 | (dma, DMA2) => { | ||
| 282 | impl_dma!(DMA2, 1); | ||
| 283 | dma_channels! { | ||
| 284 | ($channel_peri:ident, DMA2, $channel_num:expr) => { | ||
| 285 | impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); | ||
| 286 | }; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | } | ||
| 290 | |||
| 291 | interrupts! { | ||
| 292 | (DMA, $irq:ident) => { | ||
| 293 | #[crate::interrupt] | ||
| 294 | unsafe fn $irq () { | ||
| 295 | on_irq() | ||
| 296 | } | ||
| 297 | }; | ||
| 298 | } | ||
| 299 | |||
| 300 | pub struct P2M; | ||
| 301 | pub struct M2P; | ||
| 302 | |||
| 303 | #[cfg(usart)] | ||
| 304 | use crate::usart; | ||
| 305 | peripheral_dma_channels! { | ||
| 306 | ($peri:ident, usart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { | ||
| 307 | impl usart::RxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||
| 308 | impl usart::sealed::RxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||
| 309 | |||
| 310 | impl sealed::PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri { | ||
| 311 | fn request(&self) -> u8 { | ||
| 312 | $event_num | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | impl PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri { } | ||
| 317 | }; | ||
| 318 | |||
| 319 | ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { | ||
| 320 | impl usart::TxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||
| 321 | impl usart::sealed::TxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||
| 322 | |||
| 323 | impl sealed::PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri { | ||
| 324 | fn request(&self) -> u8 { | ||
| 325 | $event_num | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | impl PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri { } | ||
| 330 | }; | ||
| 331 | } | ||
diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs deleted file mode 100644 index 6733d911a..000000000 --- a/embassy-stm32/src/dma_traits.rs +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use embassy::util::Unborrow; | ||
| 3 | |||
| 4 | pub trait WriteDma<T> { | ||
| 5 | type WriteDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 6 | where | ||
| 7 | Self: 'a; | ||
| 8 | |||
| 9 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 10 | where | ||
| 11 | T: 'a; | ||
| 12 | } | ||
| 13 | |||
| 14 | pub trait ReadDma<T> { | ||
| 15 | type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 16 | where | ||
| 17 | Self: 'a; | ||
| 18 | |||
| 19 | fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||
| 20 | where | ||
| 21 | T: 'a; | ||
| 22 | } | ||
| 23 | |||
| 24 | pub struct NoDma; | ||
| 25 | |||
| 26 | unsafe impl Unborrow for NoDma { | ||
| 27 | type Target = NoDma; | ||
| 28 | |||
| 29 | unsafe fn unborrow(self) -> Self::Target { | ||
| 30 | self | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs deleted file mode 100644 index ecea0b290..000000000 --- a/embassy-stm32/src/dmamux/mod.rs +++ /dev/null | |||
| @@ -1,137 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use crate::pac; | ||
| 4 | use crate::pac::bdma_channels; | ||
| 5 | use crate::pac::dma_requests; | ||
| 6 | use crate::pac::peripherals; | ||
| 7 | use crate::peripherals; | ||
| 8 | |||
| 9 | pub(crate) unsafe fn configure_dmamux( | ||
| 10 | dmamux_regs: pac::dmamux::Dmamux, | ||
| 11 | dmamux_ch_num: u8, | ||
| 12 | request: u8, | ||
| 13 | ) { | ||
| 14 | let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _); | ||
| 15 | ch_mux_regs.write(|reg| { | ||
| 16 | reg.set_nbreq(0); | ||
| 17 | reg.set_dmareq_id(request); | ||
| 18 | }); | ||
| 19 | |||
| 20 | ch_mux_regs.modify(|reg| { | ||
| 21 | reg.set_ege(true); | ||
| 22 | }); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub(crate) mod sealed { | ||
| 26 | use super::*; | ||
| 27 | |||
| 28 | pub trait Channel { | ||
| 29 | const DMAMUX_CH_NUM: u8; | ||
| 30 | const DMAMUX_REGS: pac::dmamux::Dmamux; | ||
| 31 | } | ||
| 32 | |||
| 33 | pub trait PeripheralChannel<PERI, OP>: Channel { | ||
| 34 | const REQUEST: u8; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | pub trait Channel: sealed::Channel {} | ||
| 39 | pub trait PeripheralChannel<PERI, OP>: sealed::Channel {} | ||
| 40 | |||
| 41 | pub struct P2M; | ||
| 42 | pub struct M2P; | ||
| 43 | |||
| 44 | macro_rules! dma_num { | ||
| 45 | (DMA1) => { | ||
| 46 | 0 | ||
| 47 | }; | ||
| 48 | (DMA2) => { | ||
| 49 | 1 | ||
| 50 | }; | ||
| 51 | (BDMA) => { | ||
| 52 | 0 | ||
| 53 | }; | ||
| 54 | } | ||
| 55 | |||
| 56 | macro_rules! dmamux_peri { | ||
| 57 | (DMA1) => { | ||
| 58 | crate::pac::DMAMUX1 | ||
| 59 | }; | ||
| 60 | (DMA2) => { | ||
| 61 | crate::pac::DMAMUX1 | ||
| 62 | }; | ||
| 63 | (BDMA) => { | ||
| 64 | crate::pac::DMAMUX1 | ||
| 65 | }; | ||
| 66 | } | ||
| 67 | |||
| 68 | #[allow(unused)] | ||
| 69 | macro_rules! impl_dma_channel { | ||
| 70 | ($channel_peri:ident, $channel_num:expr, $dma_peri: ident) => { | ||
| 71 | impl Channel for peripherals::$channel_peri {} | ||
| 72 | impl sealed::Channel for peripherals::$channel_peri { | ||
| 73 | const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; | ||
| 74 | const DMAMUX_REGS: pac::dmamux::Dmamux = dmamux_peri!($dma_peri); | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | } | ||
| 78 | |||
| 79 | peripherals! { | ||
| 80 | (bdma, $peri:ident) => { | ||
| 81 | bdma_channels! { | ||
| 82 | ($channel_peri:ident, $peri, $channel_num:expr) => { | ||
| 83 | impl_dma_channel!($channel_peri, $channel_num, $peri); | ||
| 84 | }; | ||
| 85 | } | ||
| 86 | }; | ||
| 87 | } | ||
| 88 | |||
| 89 | #[allow(unused)] | ||
| 90 | macro_rules! impl_peripheral_channel { | ||
| 91 | ($channel_peri:ident, $direction:ident, $peri:ident, $request:expr) => { | ||
| 92 | impl sealed::PeripheralChannel<peripherals::$peri, $direction> | ||
| 93 | for peripherals::$channel_peri | ||
| 94 | { | ||
| 95 | const REQUEST: u8 = $request; | ||
| 96 | } | ||
| 97 | |||
| 98 | impl PeripheralChannel<peripherals::$peri, $direction> for peripherals::$channel_peri {} | ||
| 99 | }; | ||
| 100 | } | ||
| 101 | |||
| 102 | #[allow(unused)] | ||
| 103 | macro_rules! impl_usart_dma_requests { | ||
| 104 | ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||
| 105 | dma_requests! { | ||
| 106 | (usart, $peri:ident, RX, $request:expr) => { | ||
| 107 | impl_peripheral_channel!($channel_peri, P2M, $peri, $request); | ||
| 108 | }; | ||
| 109 | |||
| 110 | (usart, $peri:ident, TX, $request:expr) => { | ||
| 111 | impl_peripheral_channel!($channel_peri, M2P, $peri, $request); | ||
| 112 | }; | ||
| 113 | |||
| 114 | (uart, $peri:ident, RX, $request:expr) => { | ||
| 115 | impl_peripheral_channel!($channel_peri, P2M, $peri, $request); | ||
| 116 | }; | ||
| 117 | |||
| 118 | (uart, $peri:ident, TX, $request:expr) => { | ||
| 119 | impl_peripheral_channel!($channel_peri, M2P, $peri, $request); | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | }; | ||
| 123 | } | ||
| 124 | |||
| 125 | #[allow(unused)] | ||
| 126 | #[cfg(usart)] | ||
| 127 | use crate::usart; | ||
| 128 | |||
| 129 | bdma_channels! { | ||
| 130 | ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||
| 131 | #[cfg(usart)] | ||
| 132 | impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); | ||
| 133 | }; | ||
| 134 | } | ||
| 135 | |||
| 136 | /// safety: must be called only once | ||
| 137 | pub(crate) unsafe fn init() {} | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 22999a69e..c10310e2d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -19,25 +19,18 @@ pub mod interrupt; | |||
| 19 | pub mod time; | 19 | pub mod time; |
| 20 | 20 | ||
| 21 | // Always-present hardware | 21 | // Always-present hardware |
| 22 | pub mod dma; | ||
| 22 | pub mod gpio; | 23 | pub mod gpio; |
| 23 | pub mod rcc; | 24 | pub mod rcc; |
| 24 | 25 | ||
| 25 | // Sometimes-present hardware | 26 | // Sometimes-present hardware |
| 26 | #[cfg(any(dma, bdma, dmamux))] | ||
| 27 | pub mod dma_traits; | ||
| 28 | 27 | ||
| 29 | #[cfg(adc)] | 28 | #[cfg(adc)] |
| 30 | pub mod adc; | 29 | pub mod adc; |
| 31 | #[cfg(bdma)] | ||
| 32 | pub mod bdma; | ||
| 33 | #[cfg(timer)] | 30 | #[cfg(timer)] |
| 34 | pub mod clock; | 31 | pub mod clock; |
| 35 | #[cfg(dac)] | 32 | #[cfg(dac)] |
| 36 | pub mod dac; | 33 | pub mod dac; |
| 37 | #[cfg(dma)] | ||
| 38 | pub mod dma; | ||
| 39 | #[cfg(dmamux)] | ||
| 40 | pub mod dmamux; | ||
| 41 | #[cfg(all(eth, feature = "net"))] | 34 | #[cfg(all(eth, feature = "net"))] |
| 42 | pub mod eth; | 35 | pub mod eth; |
| 43 | #[cfg(exti)] | 36 | #[cfg(exti)] |
| @@ -94,12 +87,7 @@ pub fn init(config: Config) -> Peripherals { | |||
| 94 | let p = Peripherals::take(); | 87 | let p = Peripherals::take(); |
| 95 | 88 | ||
| 96 | unsafe { | 89 | unsafe { |
| 97 | #[cfg(dma)] | ||
| 98 | dma::init(); | 90 | dma::init(); |
| 99 | #[cfg(bdma)] | ||
| 100 | bdma::init(); | ||
| 101 | #[cfg(dmamux)] | ||
| 102 | dmamux::init(); | ||
| 103 | #[cfg(exti)] | 91 | #[cfg(exti)] |
| 104 | exti::init(); | 92 | exti::init(); |
| 105 | 93 | ||
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c3ac8bc59..9df00d3a8 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | #[cfg_attr(usart_v1, path = "v1.rs")] | 3 | #[cfg_attr(usart_v1, path = "v1.rs")] |
| 4 | #[cfg_attr(usart_v2, path = "v2.rs")] | 4 | #[cfg_attr(usart_v2, path = "v2.rs")] |
| 5 | mod _version; | 5 | mod _version; |
| 6 | use crate::peripherals; | 6 | use crate::{dma, peripherals}; |
| 7 | pub use _version::*; | 7 | pub use _version::*; |
| 8 | 8 | ||
| 9 | use crate::gpio::Pin; | 9 | use crate::gpio::Pin; |
| @@ -72,9 +72,6 @@ pub enum Error { | |||
| 72 | pub(crate) mod sealed { | 72 | pub(crate) mod sealed { |
| 73 | use super::*; | 73 | use super::*; |
| 74 | 74 | ||
| 75 | #[cfg(any(dma, bdma, dmamux))] | ||
| 76 | use crate::dma_traits::WriteDma; | ||
| 77 | |||
| 78 | pub trait Instance { | 75 | pub trait Instance { |
| 79 | fn regs(&self) -> crate::pac::usart::Usart; | 76 | fn regs(&self) -> crate::pac::usart::Usart; |
| 80 | } | 77 | } |
| @@ -94,11 +91,13 @@ pub(crate) mod sealed { | |||
| 94 | fn af_num(&self) -> u8; | 91 | fn af_num(&self) -> u8; |
| 95 | } | 92 | } |
| 96 | 93 | ||
| 97 | #[cfg(any(bdma, dma, dmamux))] | 94 | pub trait RxDma<T: Instance> { |
| 98 | pub trait RxDma<T: Instance> {} | 95 | fn request(&self) -> dma::Request; |
| 96 | } | ||
| 99 | 97 | ||
| 100 | #[cfg(any(bdma, dma, dmamux))] | 98 | pub trait TxDma<T: Instance> { |
| 101 | pub trait TxDma<T: Instance>: WriteDma<T> {} | 99 | fn request(&self) -> dma::Request; |
| 100 | } | ||
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | pub trait Instance: sealed::Instance + RccPeripheral {} | 103 | pub trait Instance: sealed::Instance + RccPeripheral {} |
| @@ -107,12 +106,8 @@ pub trait TxPin<T: Instance>: sealed::TxPin<T> {} | |||
| 107 | pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} | 106 | pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} |
| 108 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} | 107 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} |
| 109 | pub trait CkPin<T: Instance>: sealed::CkPin<T> {} | 108 | pub trait CkPin<T: Instance>: sealed::CkPin<T> {} |
| 110 | 109 | pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {} | |
| 111 | #[cfg(any(bdma, dma, dmamux))] | 110 | pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {} |
| 112 | pub trait RxDma<T: Instance>: sealed::RxDma<T> {} | ||
| 113 | |||
| 114 | #[cfg(any(bdma, dma, dmamux))] | ||
| 115 | pub trait TxDma<T: Instance>: sealed::TxDma<T> {} | ||
| 116 | 111 | ||
| 117 | crate::pac::peripherals!( | 112 | crate::pac::peripherals!( |
| 118 | (usart, $inst:ident) => { | 113 | (usart, $inst:ident) => { |
| @@ -141,46 +136,78 @@ macro_rules! impl_pin { | |||
| 141 | crate::pac::peripheral_pins!( | 136 | crate::pac::peripheral_pins!( |
| 142 | 137 | ||
| 143 | // USART | 138 | // USART |
| 144 | |||
| 145 | ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => { | 139 | ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => { |
| 146 | impl_pin!($inst, $pin, TxPin, $af); | 140 | impl_pin!($inst, $pin, TxPin, $af); |
| 147 | }; | 141 | }; |
| 148 | |||
| 149 | ($inst:ident, usart, USART, $pin:ident, RX, $af:expr) => { | 142 | ($inst:ident, usart, USART, $pin:ident, RX, $af:expr) => { |
| 150 | impl_pin!($inst, $pin, RxPin, $af); | 143 | impl_pin!($inst, $pin, RxPin, $af); |
| 151 | }; | 144 | }; |
| 152 | |||
| 153 | ($inst:ident, usart, USART, $pin:ident, CTS, $af:expr) => { | 145 | ($inst:ident, usart, USART, $pin:ident, CTS, $af:expr) => { |
| 154 | impl_pin!($inst, $pin, CtsPin, $af); | 146 | impl_pin!($inst, $pin, CtsPin, $af); |
| 155 | }; | 147 | }; |
| 156 | |||
| 157 | ($inst:ident, usart, USART, $pin:ident, RTS, $af:expr) => { | 148 | ($inst:ident, usart, USART, $pin:ident, RTS, $af:expr) => { |
| 158 | impl_pin!($inst, $pin, RtsPin, $af); | 149 | impl_pin!($inst, $pin, RtsPin, $af); |
| 159 | }; | 150 | }; |
| 160 | |||
| 161 | ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => { | 151 | ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => { |
| 162 | impl_pin!($inst, $pin, CkPin, $af); | 152 | impl_pin!($inst, $pin, CkPin, $af); |
| 163 | }; | 153 | }; |
| 164 | 154 | ||
| 165 | // UART | 155 | // UART |
| 166 | |||
| 167 | ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => { | 156 | ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => { |
| 168 | impl_pin!($inst, $pin, TxPin, $af); | 157 | impl_pin!($inst, $pin, TxPin, $af); |
| 169 | }; | 158 | }; |
| 170 | |||
| 171 | ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => { | 159 | ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => { |
| 172 | impl_pin!($inst, $pin, RxPin, $af); | 160 | impl_pin!($inst, $pin, RxPin, $af); |
| 173 | }; | 161 | }; |
| 174 | |||
| 175 | ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => { | 162 | ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => { |
| 176 | impl_pin!($inst, $pin, CtsPin, $af); | 163 | impl_pin!($inst, $pin, CtsPin, $af); |
| 177 | }; | 164 | }; |
| 178 | |||
| 179 | ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => { | 165 | ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => { |
| 180 | impl_pin!($inst, $pin, RtsPin, $af); | 166 | impl_pin!($inst, $pin, RtsPin, $af); |
| 181 | }; | 167 | }; |
| 182 | |||
| 183 | ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => { | 168 | ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => { |
| 184 | impl_pin!($inst, $pin, CkPin, $af); | 169 | impl_pin!($inst, $pin, CkPin, $af); |
| 185 | }; | 170 | }; |
| 186 | ); | 171 | ); |
| 172 | |||
| 173 | macro_rules! impl_dma { | ||
| 174 | ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { | ||
| 175 | impl<T> sealed::$signal<peripherals::$inst> for T | ||
| 176 | where | ||
| 177 | T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | ||
| 178 | { | ||
| 179 | fn request(&self) -> dma::Request { | ||
| 180 | $request | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | impl<T> $signal<peripherals::$inst> for T where | ||
| 185 | T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux> | ||
| 186 | { | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => { | ||
| 190 | impl sealed::$signal<peripherals::$inst> for peripherals::$channel { | ||
| 191 | fn request(&self) -> dma::Request { | ||
| 192 | $request | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | impl $signal<peripherals::$inst> for peripherals::$channel {} | ||
| 197 | }; | ||
| 198 | } | ||
| 199 | |||
| 200 | crate::pac::peripheral_dma_channels! { | ||
| 201 | ($peri:ident, usart, $kind:ident, RX, $channel:tt, $request:expr) => { | ||
| 202 | impl_dma!($peri, $channel, RxDma, $request); | ||
| 203 | }; | ||
| 204 | ($peri:ident, usart, $kind:ident, TX, $channel:tt, $request:expr) => { | ||
| 205 | impl_dma!($peri, $channel, TxDma, $request); | ||
| 206 | }; | ||
| 207 | ($peri:ident, uart, $kind:ident, RX, $channel:tt, $request:expr) => { | ||
| 208 | impl_dma!($peri, $channel, RxDma, $request); | ||
| 209 | }; | ||
| 210 | ($peri:ident, uart, $kind:ident, TX, $channel:tt, $request:expr) => { | ||
| 211 | impl_dma!($peri, $channel, TxDma, $request); | ||
| 212 | }; | ||
| 213 | } | ||
diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 169938952..0f39c364b 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs | |||
| @@ -1,25 +1,31 @@ | |||
| 1 | use core::future::Future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | |||
| 3 | use embassy::util::Unborrow; | 3 | use embassy::util::Unborrow; |
| 4 | use embassy_extras::unborrow; | 4 | use embassy_extras::unborrow; |
| 5 | 5 | use futures::TryFutureExt; | |
| 6 | use crate::pac::usart::{regs, vals}; | ||
| 7 | 6 | ||
| 8 | use super::*; | 7 | use super::*; |
| 8 | use crate::dma::NoDma; | ||
| 9 | use crate::pac::usart::{regs, vals}; | ||
| 9 | 10 | ||
| 10 | pub struct Uart<'d, T: Instance> { | 11 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { |
| 11 | inner: T, | 12 | inner: T, |
| 12 | phantom: PhantomData<&'d mut T>, | 13 | phantom: PhantomData<&'d mut T>, |
| 14 | tx_dma: TxDma, | ||
| 15 | #[allow(dead_code)] | ||
| 16 | rx_dma: RxDma, | ||
| 13 | } | 17 | } |
| 14 | 18 | ||
| 15 | impl<'d, T: Instance> Uart<'d, T> { | 19 | impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { |
| 16 | pub fn new( | 20 | pub fn new( |
| 17 | inner: impl Unborrow<Target = T>, | 21 | inner: impl Unborrow<Target = T>, |
| 18 | rx: impl Unborrow<Target = impl RxPin<T>>, | 22 | rx: impl Unborrow<Target = impl RxPin<T>>, |
| 19 | tx: impl Unborrow<Target = impl TxPin<T>>, | 23 | tx: impl Unborrow<Target = impl TxPin<T>>, |
| 24 | tx_dma: impl Unborrow<Target = TxDma>, | ||
| 25 | rx_dma: impl Unborrow<Target = RxDma>, | ||
| 20 | config: Config, | 26 | config: Config, |
| 21 | ) -> Self { | 27 | ) -> Self { |
| 22 | unborrow!(inner, rx, tx); | 28 | unborrow!(inner, rx, tx, tx_dma, rx_dma); |
| 23 | 29 | ||
| 24 | T::enable(); | 30 | T::enable(); |
| 25 | let pclk_freq = T::frequency(); | 31 | let pclk_freq = T::frequency(); |
| @@ -53,11 +59,16 @@ impl<'d, T: Instance> Uart<'d, T> { | |||
| 53 | Self { | 59 | Self { |
| 54 | inner, | 60 | inner, |
| 55 | phantom: PhantomData, | 61 | phantom: PhantomData, |
| 62 | tx_dma, | ||
| 63 | rx_dma, | ||
| 56 | } | 64 | } |
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | #[cfg(dma)] | 67 | async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> |
| 60 | pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { | 68 | where |
| 69 | TxDma: crate::usart::TxDma<T>, | ||
| 70 | { | ||
| 71 | let ch = &mut self.tx_dma; | ||
| 61 | unsafe { | 72 | unsafe { |
| 62 | self.inner.regs().cr3().modify(|reg| { | 73 | self.inner.regs().cr3().modify(|reg| { |
| 63 | reg.set_dmat(true); | 74 | reg.set_dmat(true); |
| @@ -65,7 +76,7 @@ impl<'d, T: Instance> Uart<'d, T> { | |||
| 65 | } | 76 | } |
| 66 | let r = self.inner.regs(); | 77 | let r = self.inner.regs(); |
| 67 | let dst = r.dr().ptr() as *mut u8; | 78 | let dst = r.dr().ptr() as *mut u8; |
| 68 | ch.transfer(buffer, dst).await; | 79 | ch.write(ch.request(), buffer, dst).await; |
| 69 | Ok(()) | 80 | Ok(()) |
| 70 | } | 81 | } |
| 71 | 82 | ||
| @@ -98,7 +109,9 @@ impl<'d, T: Instance> Uart<'d, T> { | |||
| 98 | } | 109 | } |
| 99 | } | 110 | } |
| 100 | 111 | ||
| 101 | impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> { | 112 | impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8> |
| 113 | for Uart<'d, T, NoDma, RxDma> | ||
| 114 | { | ||
| 102 | type Error = Error; | 115 | type Error = Error; |
| 103 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 116 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 104 | unsafe { | 117 | unsafe { |
| @@ -118,3 +131,15 @@ impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> | |||
| 118 | Ok(()) | 131 | Ok(()) |
| 119 | } | 132 | } |
| 120 | } | 133 | } |
| 134 | |||
| 135 | // rustfmt::skip because intellij removes the 'where' claus on the associated type. | ||
| 136 | #[rustfmt::skip] | ||
| 137 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> | ||
| 138 | where TxDma: crate::usart::TxDma<T> | ||
| 139 | { | ||
| 140 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>>; | ||
| 141 | |||
| 142 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 143 | self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) | ||
| 144 | } | ||
| 145 | } | ||
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index b958c0a0c..8a4d63b20 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs | |||
| @@ -1,21 +1,18 @@ | |||
| 1 | use core::future::Future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | |||
| 3 | use embassy::util::Unborrow; | 3 | use embassy::util::Unborrow; |
| 4 | use embassy_extras::unborrow; | 4 | use embassy_extras::unborrow; |
| 5 | |||
| 6 | use crate::pac::usart::{regs, vals}; | ||
| 7 | |||
| 8 | use super::*; | ||
| 9 | use core::future::Future; | ||
| 10 | use futures::TryFutureExt; | 5 | use futures::TryFutureExt; |
| 11 | 6 | ||
| 12 | use crate::dma_traits::NoDma; | 7 | use super::*; |
| 8 | use crate::dma::NoDma; | ||
| 9 | use crate::pac::usart::{regs, vals}; | ||
| 13 | 10 | ||
| 14 | #[allow(dead_code)] | ||
| 15 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { | 11 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { |
| 16 | inner: T, | 12 | inner: T, |
| 17 | phantom: PhantomData<&'d mut T>, | 13 | phantom: PhantomData<&'d mut T>, |
| 18 | tx_dma: TxDma, | 14 | tx_dma: TxDma, |
| 15 | #[allow(dead_code)] | ||
| 19 | rx_dma: RxDma, | 16 | rx_dma: RxDma, |
| 20 | } | 17 | } |
| 21 | 18 | ||
| @@ -83,7 +80,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 83 | } | 80 | } |
| 84 | let r = self.inner.regs(); | 81 | let r = self.inner.regs(); |
| 85 | let dst = r.tdr().ptr() as *mut u8; | 82 | let dst = r.tdr().ptr() as *mut u8; |
| 86 | ch.transfer(buffer, dst).await; | 83 | ch.write(ch.request(), buffer, dst).await; |
| 87 | Ok(()) | 84 | Ok(()) |
| 88 | } | 85 | } |
| 89 | 86 | ||
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index dda0ee4ed..aa48ceed5 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs | |||
| @@ -61,7 +61,7 @@ fn main() -> ! { | |||
| 61 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | 61 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); |
| 62 | 62 | ||
| 63 | loop { | 63 | loop { |
| 64 | let mut buf = [0x0A; 4]; | 64 | let mut buf = [0x0Au8; 4]; |
| 65 | unwrap!(cs.set_low()); | 65 | unwrap!(cs.set_low()); |
| 66 | unwrap!(spi.transfer(&mut buf)); | 66 | unwrap!(spi.transfer(&mut buf)); |
| 67 | unwrap!(cs.set_high()); | 67 | unwrap!(cs.set_high()); |
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 42f154b05..31525036a 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs | |||
| @@ -12,6 +12,7 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write; | |||
| 12 | use embassy::executor::Executor; | 12 | use embassy::executor::Executor; |
| 13 | use embassy::time::Clock; | 13 | use embassy::time::Clock; |
| 14 | use embassy::util::Forever; | 14 | use embassy::util::Forever; |
| 15 | use embassy_stm32::dma::NoDma; | ||
| 15 | use embassy_stm32::usart::{Config, Uart}; | 16 | use embassy_stm32::usart::{Config, Uart}; |
| 16 | use example_common::*; | 17 | use example_common::*; |
| 17 | 18 | ||
| @@ -23,7 +24,7 @@ async fn main_task() { | |||
| 23 | let p = embassy_stm32::init(Default::default()); | 24 | let p = embassy_stm32::init(Default::default()); |
| 24 | 25 | ||
| 25 | let config = Config::default(); | 26 | let config = Config::default(); |
| 26 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); | 27 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); |
| 27 | 28 | ||
| 28 | usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); | 29 | usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); |
| 29 | info!("wrote Hello, starting echo"); | 30 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index 66ca6242b..b578aebca 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs | |||
| @@ -13,26 +13,25 @@ use cortex_m_rt::entry; | |||
| 13 | use embassy::executor::Executor; | 13 | use embassy::executor::Executor; |
| 14 | use embassy::time::Clock; | 14 | use embassy::time::Clock; |
| 15 | use embassy::util::Forever; | 15 | use embassy::util::Forever; |
| 16 | use embassy_stm32::dma::NoDma; | ||
| 16 | use embassy_stm32::usart::{Config, Uart}; | 17 | use embassy_stm32::usart::{Config, Uart}; |
| 18 | use embassy_traits::uart::Write as _; | ||
| 17 | use example_common::*; | 19 | use example_common::*; |
| 18 | use heapless::String; | 20 | use heapless::String; |
| 19 | use stm32f4::stm32f429 as pac; | 21 | use stm32f4::stm32f429 as pac; |
| 20 | 22 | ||
| 21 | #[embassy::task] | 23 | #[embassy::task] |
| 22 | async fn main_task() { | 24 | async fn main_task() { |
| 23 | let mut p = embassy_stm32::init(Default::default()); | 25 | let p = embassy_stm32::init(Default::default()); |
| 24 | 26 | ||
| 25 | let config = Config::default(); | 27 | let config = Config::default(); |
| 26 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); | 28 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); |
| 27 | 29 | ||
| 28 | for n in 0u32.. { | 30 | for n in 0u32.. { |
| 29 | let mut s: String<128> = String::new(); | 31 | let mut s: String<128> = String::new(); |
| 30 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | 32 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); |
| 31 | 33 | ||
| 32 | usart | 34 | usart.write(s.as_bytes()).await.unwrap(); |
| 33 | .write_dma(&mut p.DMA1_3, s.as_bytes()) | ||
| 34 | .await | ||
| 35 | .unwrap(); | ||
| 36 | info!("wrote DMA"); | 35 | info!("wrote DMA"); |
| 37 | } | 36 | } |
| 38 | } | 37 | } |
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index d8e60158b..143f94491 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | |||
| 2 | #![no_std] | 1 | #![no_std] |
| 3 | #![no_main] | 2 | #![no_main] |
| 4 | #![feature(trait_alias)] | 3 | #![feature(trait_alias)] |
| @@ -13,12 +12,12 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write; | |||
| 13 | use embassy::executor::Executor; | 12 | use embassy::executor::Executor; |
| 14 | use embassy::time::Clock; | 13 | use embassy::time::Clock; |
| 15 | use embassy::util::Forever; | 14 | use embassy::util::Forever; |
| 15 | use embassy_stm32::dma::NoDma; | ||
| 16 | use embassy_stm32::usart::{Config, Uart}; | 16 | use embassy_stm32::usart::{Config, Uart}; |
| 17 | use embassy_stm32::dma_traits::NoDma; | ||
| 18 | use example_common::*; | 17 | use example_common::*; |
| 19 | 18 | ||
| 20 | use stm32h7xx_hal as hal; | ||
| 21 | use hal::prelude::*; | 19 | use hal::prelude::*; |
| 20 | use stm32h7xx_hal as hal; | ||
| 22 | 21 | ||
| 23 | use cortex_m_rt::entry; | 22 | use cortex_m_rt::entry; |
| 24 | use stm32h7::stm32h743 as pac; | 23 | use stm32h7::stm32h743 as pac; |
| @@ -60,8 +59,7 @@ fn main() -> ! { | |||
| 60 | 59 | ||
| 61 | let rcc = pp.RCC.constrain(); | 60 | let rcc = pp.RCC.constrain(); |
| 62 | 61 | ||
| 63 | rcc | 62 | rcc.sys_ck(96.mhz()) |
| 64 | .sys_ck(96.mhz()) | ||
| 65 | .pclk1(48.mhz()) | 63 | .pclk1(48.mhz()) |
| 66 | .pclk2(48.mhz()) | 64 | .pclk2(48.mhz()) |
| 67 | .pclk3(48.mhz()) | 65 | .pclk3(48.mhz()) |
| @@ -89,7 +87,6 @@ fn main() -> ! { | |||
| 89 | w | 87 | w |
| 90 | }); | 88 | }); |
| 91 | 89 | ||
| 92 | |||
| 93 | unsafe { embassy::time::set_clock(&ZeroClock) }; | 90 | unsafe { embassy::time::set_clock(&ZeroClock) }; |
| 94 | 91 | ||
| 95 | let executor = EXECUTOR.put(Executor::new()); | 92 | let executor = EXECUTOR.put(Executor::new()); |
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs new file mode 100644 index 000000000..0073d5c66 --- /dev/null +++ b/examples/stm32h7/src/bin/usart_dma.rs | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(trait_alias)] | ||
| 4 | #![feature(min_type_alias_impl_trait)] | ||
| 5 | #![feature(impl_trait_in_bindings)] | ||
| 6 | #![feature(type_alias_impl_trait)] | ||
| 7 | #![allow(incomplete_features)] | ||
| 8 | |||
| 9 | #[path = "../example_common.rs"] | ||
| 10 | mod example_common; | ||
| 11 | use core::fmt::Write; | ||
| 12 | use embassy::executor::Executor; | ||
| 13 | use embassy::time::Clock; | ||
| 14 | use embassy::util::Forever; | ||
| 15 | use embassy_stm32::dma::NoDma; | ||
| 16 | use embassy_stm32::usart::{Config, Uart}; | ||
| 17 | use example_common::*; | ||
| 18 | use embassy_traits::uart::Write as _Write; | ||
| 19 | |||
| 20 | use hal::prelude::*; | ||
| 21 | use stm32h7xx_hal as hal; | ||
| 22 | |||
| 23 | use cortex_m_rt::entry; | ||
| 24 | use stm32h7::stm32h743 as pac; | ||
| 25 | use heapless::String; | ||
| 26 | |||
| 27 | #[embassy::task] | ||
| 28 | async fn main_task() { | ||
| 29 | let p = embassy_stm32::init(Default::default()); | ||
| 30 | |||
| 31 | let config = Config::default(); | ||
| 32 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); | ||
| 33 | |||
| 34 | for n in 0u32.. { | ||
| 35 | let mut s: String<128> = String::new(); | ||
| 36 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 37 | |||
| 38 | usart.write(s.as_bytes()).await.ok(); | ||
| 39 | |||
| 40 | info!("wrote DMA"); | ||
| 41 | } | ||
| 42 | |||
| 43 | } | ||
| 44 | |||
| 45 | struct ZeroClock; | ||
| 46 | |||
| 47 | impl Clock for ZeroClock { | ||
| 48 | fn now(&self) -> u64 { | ||
| 49 | 0 | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 54 | |||
| 55 | #[entry] | ||
| 56 | fn main() -> ! { | ||
| 57 | info!("Hello World!"); | ||
| 58 | |||
| 59 | let pp = pac::Peripherals::take().unwrap(); | ||
| 60 | |||
| 61 | let pwrcfg = pp.PWR.constrain().freeze(); | ||
| 62 | |||
| 63 | let rcc = pp.RCC.constrain(); | ||
| 64 | |||
| 65 | rcc.sys_ck(96.mhz()) | ||
| 66 | .pclk1(48.mhz()) | ||
| 67 | .pclk2(48.mhz()) | ||
| 68 | .pclk3(48.mhz()) | ||
| 69 | .pclk4(48.mhz()) | ||
| 70 | .pll1_q_ck(48.mhz()) | ||
| 71 | .freeze(pwrcfg, &pp.SYSCFG); | ||
| 72 | |||
| 73 | let pp = unsafe { pac::Peripherals::steal() }; | ||
| 74 | |||
| 75 | pp.DBGMCU.cr.modify(|_, w| { | ||
| 76 | w.dbgsleep_d1().set_bit(); | ||
| 77 | w.dbgstby_d1().set_bit(); | ||
| 78 | w.dbgstop_d1().set_bit(); | ||
| 79 | w.d1dbgcken().set_bit(); | ||
| 80 | w | ||
| 81 | }); | ||
| 82 | |||
| 83 | pp.RCC.ahb4enr.modify(|_, w| { | ||
| 84 | w.gpioaen().set_bit(); | ||
| 85 | w.gpioben().set_bit(); | ||
| 86 | w.gpiocen().set_bit(); | ||
| 87 | w.gpioden().set_bit(); | ||
| 88 | w.gpioeen().set_bit(); | ||
| 89 | w.gpiofen().set_bit(); | ||
| 90 | w | ||
| 91 | }); | ||
| 92 | |||
| 93 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 94 | |||
| 95 | let executor = EXECUTOR.put(Executor::new()); | ||
| 96 | |||
| 97 | executor.run(|spawner| { | ||
| 98 | unwrap!(spawner.spawn(main_task())); | ||
| 99 | }) | ||
| 100 | } | ||
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 45ccfcebc..7cac01fd4 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs | |||
| @@ -57,7 +57,7 @@ fn main() -> ! { | |||
| 57 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | 57 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); |
| 58 | 58 | ||
| 59 | loop { | 59 | loop { |
| 60 | let mut buf = [0x0A; 4]; | 60 | let mut buf = [0x0Au8; 4]; |
| 61 | unwrap!(cs.set_low()); | 61 | unwrap!(cs.set_low()); |
| 62 | unwrap!(spi.transfer(&mut buf)); | 62 | unwrap!(spi.transfer(&mut buf)); |
| 63 | unwrap!(cs.set_high()); | 63 | unwrap!(cs.set_high()); |
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index e9a44f151..f572b1eff 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs | |||
| @@ -13,7 +13,7 @@ use cortex_m_rt::entry; | |||
| 13 | use embassy::executor::Executor; | 13 | use embassy::executor::Executor; |
| 14 | use embassy::time::Clock; | 14 | use embassy::time::Clock; |
| 15 | use embassy::util::Forever; | 15 | use embassy::util::Forever; |
| 16 | use embassy_stm32::dma_traits::NoDma; | 16 | use embassy_stm32::dma::NoDma; |
| 17 | use embassy_stm32::pac; | 17 | use embassy_stm32::pac; |
| 18 | use embassy_stm32::usart::{Config, Uart}; | 18 | use embassy_stm32::usart::{Config, Uart}; |
| 19 | use example_common::*; | 19 | use example_common::*; |
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 1eadd3ad4..e325e3da3 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs | |||
| @@ -13,7 +13,7 @@ use cortex_m_rt::entry; | |||
| 13 | use embassy::executor::Executor; | 13 | use embassy::executor::Executor; |
| 14 | use embassy::time::Clock; | 14 | use embassy::time::Clock; |
| 15 | use embassy::util::Forever; | 15 | use embassy::util::Forever; |
| 16 | use embassy_stm32::dma_traits::NoDma; | 16 | use embassy_stm32::dma::NoDma; |
| 17 | use embassy_stm32::pac; | 17 | use embassy_stm32::pac; |
| 18 | use embassy_stm32::usart::{Config, Uart}; | 18 | use embassy_stm32::usart::{Config, Uart}; |
| 19 | use embassy_traits::uart::Write as _; | 19 | use embassy_traits::uart::Write as _; |
| @@ -25,7 +25,7 @@ async fn main_task() { | |||
| 25 | let p = embassy_stm32::init(Default::default()); | 25 | let p = embassy_stm32::init(Default::default()); |
| 26 | 26 | ||
| 27 | let config = Config::default(); | 27 | let config = Config::default(); |
| 28 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_3, NoDma, config); | 28 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); |
| 29 | 29 | ||
| 30 | for n in 0u32.. { | 30 | for n in 0u32.. { |
| 31 | let mut s: String<128> = String::new(); | 31 | let mut s: String<128> = String::new(); |
diff --git a/stm32-data b/stm32-data | |||
| Subproject 32ca79020ec7523fe4c3fcfc02006cb1ea637a1 | Subproject 8702a3a3bb83a59515dab2cf9f75952fa6edae8 | ||
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index a9ee88002..fee991111 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs | |||
| @@ -49,8 +49,6 @@ pub struct Peripheral { | |||
| 49 | pub pins: Vec<Pin>, | 49 | pub pins: Vec<Pin>, |
| 50 | #[serde(default)] | 50 | #[serde(default)] |
| 51 | pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, | 51 | pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, |
| 52 | #[serde(default)] | ||
| 53 | pub dma_requests: HashMap<String, u32>, | ||
| 54 | } | 52 | } |
| 55 | 53 | ||
| 56 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] | 54 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] |
| @@ -64,11 +62,14 @@ pub struct Pin { | |||
| 64 | pub struct DmaChannel { | 62 | pub struct DmaChannel { |
| 65 | pub dma: String, | 63 | pub dma: String, |
| 66 | pub channel: u32, | 64 | pub channel: u32, |
| 65 | pub dmamux: Option<String>, | ||
| 66 | pub dmamux_channel: Option<u32>, | ||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] | 69 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] |
| 70 | pub struct PeripheralDmaChannel { | 70 | pub struct PeripheralDmaChannel { |
| 71 | pub channel: String, | 71 | pub channel: Option<String>, |
| 72 | pub dmamux: Option<String>, | ||
| 72 | pub request: Option<u32>, | 73 | pub request: Option<u32>, |
| 73 | } | 74 | } |
| 74 | 75 | ||
| @@ -266,24 +267,18 @@ pub fn gen(options: Options) { | |||
| 266 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); | 267 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); |
| 267 | let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); | 268 | let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); |
| 268 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | 269 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 269 | let mut bdma_channels_table: Vec<Vec<String>> = Vec::new(); | ||
| 270 | let mut dma_requests_table: Vec<Vec<String>> = Vec::new(); | ||
| 271 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); | 270 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 272 | let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); | 271 | let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); |
| 273 | let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); | 272 | let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); |
| 274 | 273 | ||
| 275 | let dma_base = core | ||
| 276 | .peripherals | ||
| 277 | .get(&"DMA".to_string()) | ||
| 278 | .unwrap_or_else(|| core.peripherals.get(&"DMA1".to_string()).unwrap()) | ||
| 279 | .address; | ||
| 280 | let dma_stride = 0x400; | ||
| 281 | |||
| 282 | let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; | 274 | let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; |
| 283 | let gpio_stride = 0x400; | 275 | let gpio_stride = 0x400; |
| 284 | 276 | ||
| 285 | let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); | 277 | let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); |
| 286 | 278 | ||
| 279 | let mut has_bdma = false; | ||
| 280 | let mut has_dma = false; | ||
| 281 | |||
| 287 | for (name, p) in &core.peripherals { | 282 | for (name, p) in &core.peripherals { |
| 288 | let captures = number_suffix_re.captures(&name).unwrap(); | 283 | let captures = number_suffix_re.captures(&name).unwrap(); |
| 289 | let root_peri_name = captures.get(1).unwrap().as_str().to_string(); | 284 | let root_peri_name = captures.get(1).unwrap().as_str().to_string(); |
| @@ -303,6 +298,12 @@ pub fn gen(options: Options) { | |||
| 303 | if let Some(block) = &p.block { | 298 | if let Some(block) = &p.block { |
| 304 | let bi = BlockInfo::parse(block); | 299 | let bi = BlockInfo::parse(block); |
| 305 | 300 | ||
| 301 | if bi.module == "bdma" { | ||
| 302 | has_bdma = true | ||
| 303 | } else if bi.module == "dma" { | ||
| 304 | has_dma = true | ||
| 305 | } | ||
| 306 | |||
| 306 | peripheral_counts.insert( | 307 | peripheral_counts.insert( |
| 307 | bi.module.clone(), | 308 | bi.module.clone(), |
| 308 | peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), | 309 | peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), |
| @@ -321,27 +322,24 @@ pub fn gen(options: Options) { | |||
| 321 | peripheral_pins_table.push(row); | 322 | peripheral_pins_table.push(row); |
| 322 | } | 323 | } |
| 323 | 324 | ||
| 324 | for dma_request in &p.dma_requests { | 325 | for (request, dma_channels) in &p.dma_channels { |
| 325 | let mut row = Vec::new(); | ||
| 326 | row.push(bi.module.clone()); | ||
| 327 | row.push(name.clone()); | ||
| 328 | row.push(dma_request.0.clone()); | ||
| 329 | row.push(dma_request.1.to_string()); | ||
| 330 | dma_requests_table.push(row); | ||
| 331 | } | ||
| 332 | |||
| 333 | for (event, dma_channels) in &p.dma_channels { | ||
| 334 | for channel in dma_channels.iter() { | 326 | for channel in dma_channels.iter() { |
| 335 | let mut row = Vec::new(); | 327 | let mut row = Vec::new(); |
| 336 | row.push(name.clone()); | 328 | row.push(name.clone()); |
| 337 | row.push(bi.module.clone()); | 329 | row.push(bi.module.clone()); |
| 338 | row.push(bi.block.clone()); | 330 | row.push(bi.block.clone()); |
| 339 | row.push(event.clone()); | 331 | row.push(request.clone()); |
| 340 | row.push(channel.channel.clone()); | 332 | if let Some(channel) = &channel.channel { |
| 341 | row.push(core.dma_channels[&channel.channel].dma.clone()); | 333 | row.push(format!("{{channel: {}}}", channel)); |
| 342 | row.push(core.dma_channels[&channel.channel].channel.to_string()); | 334 | } else if let Some(dmamux) = &channel.dmamux { |
| 335 | row.push(format!("{{dmamux: {}}}", dmamux)); | ||
| 336 | } else { | ||
| 337 | unreachable!(); | ||
| 338 | } | ||
| 343 | if let Some(request) = channel.request { | 339 | if let Some(request) = channel.request { |
| 344 | row.push(request.to_string()); | 340 | row.push(request.to_string()); |
| 341 | } else { | ||
| 342 | row.push("()".to_string()); | ||
| 345 | } | 343 | } |
| 346 | peripheral_dma_channels_table.push(row); | 344 | peripheral_dma_channels_table.push(row); |
| 347 | } | 345 | } |
| @@ -381,15 +379,6 @@ pub fn gen(options: Options) { | |||
| 381 | ]); | 379 | ]); |
| 382 | } | 380 | } |
| 383 | } | 381 | } |
| 384 | "dma" => { | ||
| 385 | let dma_num = if name == "DMA" { | ||
| 386 | 0 | ||
| 387 | } else { | ||
| 388 | let dma_letter = name.chars().skip(3).next().unwrap(); | ||
| 389 | dma_letter as u32 - '1' as u32 | ||
| 390 | }; | ||
| 391 | assert_eq!(p.address, dma_base + dma_stride * dma_num); | ||
| 392 | } | ||
| 393 | _ => {} | 382 | _ => {} |
| 394 | } | 383 | } |
| 395 | 384 | ||
| @@ -489,21 +478,25 @@ pub fn gen(options: Options) { | |||
| 489 | 478 | ||
| 490 | for (id, channel_info) in &core.dma_channels { | 479 | for (id, channel_info) in &core.dma_channels { |
| 491 | let mut row = Vec::new(); | 480 | let mut row = Vec::new(); |
| 492 | let dma_peri = core.peripherals.get(&channel_info.dma); | 481 | let dma_peri = core.peripherals.get(&channel_info.dma).unwrap(); |
| 482 | let bi = BlockInfo::parse(dma_peri.block.as_ref().unwrap()); | ||
| 483 | |||
| 493 | row.push(id.clone()); | 484 | row.push(id.clone()); |
| 494 | row.push(channel_info.dma.clone()); | 485 | row.push(channel_info.dma.clone()); |
| 486 | row.push(bi.module.clone()); | ||
| 495 | row.push(channel_info.channel.to_string()); | 487 | row.push(channel_info.channel.to_string()); |
| 496 | if let Some(dma_peri) = dma_peri { | 488 | if let Some(dmamux) = &channel_info.dmamux { |
| 497 | if let Some(ref block) = dma_peri.block { | 489 | let dmamux_channel = channel_info.dmamux_channel.unwrap(); |
| 498 | let bi = BlockInfo::parse(block); | 490 | row.push(format!( |
| 499 | if bi.module == "bdma" { | 491 | "{{dmamux: {}, dmamux_channel: {}}}", |
| 500 | bdma_channels_table.push(row); | 492 | dmamux, dmamux_channel |
| 501 | } else { | 493 | )); |
| 502 | dma_channels_table.push(row); | 494 | } else { |
| 503 | } | 495 | row.push("{}".to_string()); |
| 504 | } | ||
| 505 | } | 496 | } |
| 506 | 497 | ||
| 498 | dma_channels_table.push(row); | ||
| 499 | |||
| 507 | let dma_peri_name = channel_info.dma.clone(); | 500 | let dma_peri_name = channel_info.dma.clone(); |
| 508 | dma_channel_counts.insert( | 501 | dma_channel_counts.insert( |
| 509 | dma_peri_name.clone(), | 502 | dma_peri_name.clone(), |
| @@ -522,8 +515,17 @@ pub fn gen(options: Options) { | |||
| 522 | 515 | ||
| 523 | interrupt_table.push(vec![name.clone()]); | 516 | interrupt_table.push(vec![name.clone()]); |
| 524 | 517 | ||
| 525 | if name.starts_with("DMA") || name.contains("_DMA") { | 518 | if name.starts_with("DMA1_") || name.starts_with("DMA2_") || name.contains("_DMA") { |
| 526 | interrupt_table.push(vec!["DMA".to_string(), name.clone()]); | 519 | if has_dma { |
| 520 | interrupt_table.push(vec!["DMA".to_string(), name.clone()]); | ||
| 521 | } else if has_bdma { | ||
| 522 | interrupt_table.push(vec!["BDMA".to_string(), name.clone()]); | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | if name.starts_with("BDMA_") || name.starts_with("BDMA1_") || name.starts_with("BDMA2_") | ||
| 527 | { | ||
| 528 | interrupt_table.push(vec!["BDMA".to_string(), name.clone()]); | ||
| 527 | } | 529 | } |
| 528 | 530 | ||
| 529 | if name.contains("EXTI") { | 531 | if name.contains("EXTI") { |
| @@ -557,8 +559,6 @@ pub fn gen(options: Options) { | |||
| 557 | ); | 559 | ); |
| 558 | make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); | 560 | make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); |
| 559 | make_table(&mut extra, "dma_channels", &dma_channels_table); | 561 | make_table(&mut extra, "dma_channels", &dma_channels_table); |
| 560 | make_table(&mut extra, "bdma_channels", &bdma_channels_table); | ||
| 561 | make_table(&mut extra, "dma_requests", &dma_requests_table); | ||
| 562 | make_peripheral_counts(&mut extra, &peripheral_counts); | 562 | make_peripheral_counts(&mut extra, &peripheral_counts); |
| 563 | make_dma_channel_counts(&mut extra, &dma_channel_counts); | 563 | make_dma_channel_counts(&mut extra, &dma_channel_counts); |
| 564 | 564 | ||
