diff options
| author | Bob McWhirter <[email protected]> | 2021-07-13 13:33:38 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-07-13 13:33:38 -0400 |
| commit | b6eb5dcf2f0f06527a7ed677f44cb0528c6b182e (patch) | |
| tree | a3851981c44ca0e9fd5e34c6b97935a142c3b832 | |
| parent | 8f28d6b4b1e74b3b3b64fd3a28ce1ea9072b7cbb (diff) | |
| parent | 6e0e83cfd907c504c8d2ce05a7304b49565361ff (diff) | |
Merge pull request #282 from bobmcwhirter/dmamux_thales
BDMA + DMAMUX + H7 with major help from @thalesfragoso
| -rw-r--r-- | embassy-stm32/src/bdma/mod.rs | 430 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/v2.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/dma_traits.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/dmamux/mod.rs | 137 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 14 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l0/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 16 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v2.rs | 118 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v3.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usart.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usart_dma.rs | 96 | ||||
| m--------- | stm32-data | 0 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/lib.rs | 74 |
16 files changed, 846 insertions, 98 deletions
diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index e85ade5df..39e8bec3b 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs | |||
| @@ -1,69 +1,413 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg_attr(bdma_v1, path = "v1.rs")] | 3 | use core::future::Future; |
| 4 | #[cfg_attr(bdma_v2, path = "v2.rs")] | 4 | use core::task::Poll; |
| 5 | mod _version; | ||
| 6 | 5 | ||
| 7 | #[allow(unused)] | 6 | use atomic_polyfill::{AtomicU8, Ordering}; |
| 8 | pub use _version::*; | 7 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 8 | use embassy::util::{AtomicWaker, OnDrop}; | ||
| 9 | use futures::future::poll_fn; | ||
| 9 | 10 | ||
| 11 | use crate::dma_traits::{ReadDma, WriteDma}; | ||
| 12 | use crate::interrupt; | ||
| 10 | use crate::pac; | 13 | use crate::pac; |
| 11 | use crate::peripherals; | 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::enable(); | ||
| 181 | }; | ||
| 182 | } | ||
| 183 | } | ||
| 12 | 184 | ||
| 13 | pub(crate) mod sealed { | 185 | pub(crate) mod sealed { |
| 14 | use super::*; | 186 | use super::*; |
| 15 | 187 | ||
| 188 | pub trait Dma { | ||
| 189 | const NUM: u8; | ||
| 190 | } | ||
| 191 | |||
| 16 | pub trait Channel { | 192 | pub trait Channel { |
| 17 | fn num(&self) -> u8; | 193 | const CH_NUM: u8; |
| 194 | const STATE_NUM: u8; | ||
| 195 | const DMA_REGS: pac::bdma::Dma; | ||
| 18 | 196 | ||
| 19 | fn dma_num(&self) -> u8 { | 197 | fn regs(&self) -> pac::bdma::Ch { |
| 20 | self.num() / 8 | 198 | Self::DMA_REGS.ch(Self::CH_NUM as usize) |
| 21 | } | ||
| 22 | fn ch_num(&self) -> u8 { | ||
| 23 | self.num() % 8 | ||
| 24 | } | ||
| 25 | fn regs(&self) -> pac::dma::Dma { | ||
| 26 | pac::DMA(self.num() as _) | ||
| 27 | } | 199 | } |
| 28 | } | 200 | } |
| 29 | } | 201 | } |
| 30 | 202 | ||
| 203 | pub trait Dma: sealed::Dma + Sized {} | ||
| 31 | pub trait Channel: sealed::Channel + Sized {} | 204 | pub trait Channel: sealed::Channel + Sized {} |
| 32 | 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 | |||
| 33 | macro_rules! impl_dma_channel { | 215 | macro_rules! impl_dma_channel { |
| 34 | ($channel_peri:ident, $dma_num:expr, $ch_num:expr) => { | 216 | ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => { |
| 35 | impl Channel for peripherals::$channel_peri {} | 217 | impl Channel for crate::peripherals::$channel_peri {} |
| 36 | impl sealed::Channel for peripherals::$channel_peri { | 218 | impl sealed::Channel for crate::peripherals::$channel_peri { |
| 37 | #[inline] | 219 | const CH_NUM: u8 = $ch_num; |
| 38 | fn num(&self) -> u8 { | 220 | const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num; |
| 39 | $dma_num * 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 | } | ||
| 40 | } | 357 | } |
| 41 | } | 358 | } |
| 42 | }; | 359 | }; |
| 43 | } | 360 | } |
| 44 | 361 | ||
| 45 | /* | 362 | macro_rules! dma_num { |
| 46 | crate::pac::peripherals!( | 363 | (DMA1) => { |
| 47 | (dma,DMA1) => { | 364 | 0 |
| 48 | impl_dma_channel!(DMA1_CH0, 0, 0); | 365 | }; |
| 49 | impl_dma_channel!(DMA1_CH1, 0, 1); | 366 | (DMA2) => { |
| 50 | impl_dma_channel!(DMA1_CH2, 0, 2); | 367 | 1 |
| 51 | impl_dma_channel!(DMA1_CH3, 0, 3); | 368 | }; |
| 52 | impl_dma_channel!(DMA1_CH4, 0, 4); | 369 | (BDMA) => { |
| 53 | impl_dma_channel!(DMA1_CH5, 0, 5); | 370 | 0 |
| 54 | impl_dma_channel!(DMA1_CH6, 0, 6); | 371 | }; |
| 55 | impl_dma_channel!(DMA1_CH7, 0, 7); | 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 {} | ||
| 56 | }; | 404 | }; |
| 57 | 405 | ||
| 58 | (dma,DMA2) => { | 406 | (uart, $peri:ident) => { |
| 59 | impl_dma_channel!(DMA2_CH0, 1, 0); | 407 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {} |
| 60 | impl_dma_channel!(DMA2_CH1, 1, 1); | 408 | impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {} |
| 61 | impl_dma_channel!(DMA2_CH2, 1, 2); | 409 | |
| 62 | impl_dma_channel!(DMA2_CH3, 1, 3); | 410 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {} |
| 63 | impl_dma_channel!(DMA2_CH4, 1, 4); | 411 | impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {} |
| 64 | impl_dma_channel!(DMA2_CH5, 1, 5); | ||
| 65 | impl_dma_channel!(DMA2_CH6, 1, 6); | ||
| 66 | impl_dma_channel!(DMA2_CH7, 1, 7); | ||
| 67 | }; | 412 | }; |
| 68 | ); | 413 | } |
| 69 | */ | ||
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 466cfa033..ed080cd16 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg(dma)] | ||
| 4 | #[cfg_attr(dma_v1, path = "v1.rs")] | 3 | #[cfg_attr(dma_v1, path = "v1.rs")] |
| 5 | #[cfg_attr(dma_v2, path = "v2.rs")] | 4 | #[cfg_attr(dma_v2, path = "v2.rs")] |
| 6 | mod _version; | 5 | mod _version; |
| @@ -8,25 +7,3 @@ mod _version; | |||
| 8 | #[cfg(dma)] | 7 | #[cfg(dma)] |
| 9 | #[allow(unused)] | 8 | #[allow(unused)] |
| 10 | pub use _version::*; | 9 | pub use _version::*; |
| 11 | |||
| 12 | use core::future::Future; | ||
| 13 | |||
| 14 | pub trait WriteDma<T> { | ||
| 15 | type WriteDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 16 | where | ||
| 17 | Self: 'a; | ||
| 18 | |||
| 19 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 20 | where | ||
| 21 | T: 'a; | ||
| 22 | } | ||
| 23 | |||
| 24 | pub trait ReadDma<T> { | ||
| 25 | type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 26 | where | ||
| 27 | Self: 'a; | ||
| 28 | |||
| 29 | fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||
| 30 | where | ||
| 31 | T: 'a; | ||
| 32 | } | ||
diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index e7cd24710..df3b922ff 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | use core::task::Poll; | 1 | use core::task::Poll; |
| 2 | 2 | ||
| 3 | use crate::dma_traits::{ReadDma, WriteDma}; | ||
| 3 | use atomic_polyfill::{AtomicU8, Ordering}; | 4 | use atomic_polyfill::{AtomicU8, Ordering}; |
| 5 | use core::future::Future; | ||
| 4 | use embassy::interrupt::{Interrupt, InterruptExt}; | 6 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 5 | use embassy::util::AtomicWaker; | 7 | use embassy::util::AtomicWaker; |
| 6 | use futures::future::poll_fn; | 8 | use futures::future::poll_fn; |
| 7 | 9 | ||
| 8 | use super::*; | ||
| 9 | use crate::interrupt; | 10 | use crate::interrupt; |
| 10 | use crate::pac; | 11 | use crate::pac; |
| 11 | use crate::pac::dma::{regs, vals}; | 12 | use crate::pac::dma::{regs, vals}; |
diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs new file mode 100644 index 000000000..8f1a9f40e --- /dev/null +++ b/embassy-stm32/src/dma_traits.rs | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | |||
| 3 | pub trait WriteDma<T> { | ||
| 4 | type WriteDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 5 | where | ||
| 6 | Self: 'a; | ||
| 7 | |||
| 8 | fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||
| 9 | where | ||
| 10 | T: 'a; | ||
| 11 | } | ||
| 12 | |||
| 13 | pub trait ReadDma<T> { | ||
| 14 | type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||
| 15 | where | ||
| 16 | Self: 'a; | ||
| 17 | |||
| 18 | fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||
| 19 | where | ||
| 20 | T: 'a; | ||
| 21 | } | ||
diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs new file mode 100644 index 000000000..ecea0b290 --- /dev/null +++ b/embassy-stm32/src/dmamux/mod.rs | |||
| @@ -0,0 +1,137 @@ | |||
| 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 76a6ecd88..4b2826ae8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -20,14 +20,21 @@ pub mod gpio; | |||
| 20 | pub mod rcc; | 20 | pub mod rcc; |
| 21 | 21 | ||
| 22 | // Sometimes-present hardware | 22 | // Sometimes-present hardware |
| 23 | #[cfg(any(dma, bdma, dmamux))] | ||
| 24 | pub mod dma_traits; | ||
| 25 | |||
| 23 | #[cfg(adc)] | 26 | #[cfg(adc)] |
| 24 | pub mod adc; | 27 | pub mod adc; |
| 28 | #[cfg(bdma)] | ||
| 29 | pub mod bdma; | ||
| 25 | #[cfg(timer)] | 30 | #[cfg(timer)] |
| 26 | pub mod clock; | 31 | pub mod clock; |
| 27 | #[cfg(dac)] | 32 | #[cfg(dac)] |
| 28 | pub mod dac; | 33 | pub mod dac; |
| 29 | #[cfg(any(dma, dmamux))] | 34 | #[cfg(dma)] |
| 30 | pub mod dma; | 35 | pub mod dma; |
| 36 | #[cfg(dmamux)] | ||
| 37 | pub mod dmamux; | ||
| 31 | #[cfg(all(eth, feature = "net"))] | 38 | #[cfg(all(eth, feature = "net"))] |
| 32 | pub mod eth; | 39 | pub mod eth; |
| 33 | #[cfg(exti)] | 40 | #[cfg(exti)] |
| @@ -86,8 +93,13 @@ pub fn init(config: Config) -> Peripherals { | |||
| 86 | unsafe { | 93 | unsafe { |
| 87 | #[cfg(dma)] | 94 | #[cfg(dma)] |
| 88 | dma::init(); | 95 | dma::init(); |
| 96 | #[cfg(bdma)] | ||
| 97 | bdma::init(); | ||
| 98 | #[cfg(dmamux)] | ||
| 99 | dmamux::init(); | ||
| 89 | #[cfg(exti)] | 100 | #[cfg(exti)] |
| 90 | exti::init(); | 101 | exti::init(); |
| 102 | |||
| 91 | rcc::init(config.rcc); | 103 | rcc::init(config.rcc); |
| 92 | } | 104 | } |
| 93 | 105 | ||
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs index 309902335..5ec531820 100644 --- a/embassy-stm32/src/rcc/h7/mod.rs +++ b/embassy-stm32/src/rcc/h7/mod.rs | |||
| @@ -532,6 +532,7 @@ pub unsafe fn init(config: Config) { | |||
| 532 | ahb1: core_clocks.hclk, | 532 | ahb1: core_clocks.hclk, |
| 533 | ahb2: core_clocks.hclk, | 533 | ahb2: core_clocks.hclk, |
| 534 | ahb3: core_clocks.hclk, | 534 | ahb3: core_clocks.hclk, |
| 535 | ahb4: core_clocks.hclk, | ||
| 535 | apb1: core_clocks.pclk1, | 536 | apb1: core_clocks.pclk1, |
| 536 | apb2: core_clocks.pclk2, | 537 | apb2: core_clocks.pclk2, |
| 537 | apb4: core_clocks.pclk4, | 538 | apb4: core_clocks.pclk4, |
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs index 0b11e708f..6107d5f55 100644 --- a/embassy-stm32/src/rcc/l0/mod.rs +++ b/embassy-stm32/src/rcc/l0/mod.rs | |||
| @@ -170,7 +170,7 @@ impl<'d> Rcc<'d> { | |||
| 170 | pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { | 170 | pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { |
| 171 | // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU | 171 | // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU |
| 172 | unsafe { | 172 | unsafe { |
| 173 | pac::RCC.ahbenr().modify(|w| w.set_dmaen(enable_dma)); | 173 | pac::RCC.ahbenr().modify(|w| w.set_dma1en(enable_dma)); |
| 174 | 174 | ||
| 175 | pac::DBGMCU.cr().modify(|w| { | 175 | pac::DBGMCU.cr().modify(|w| { |
| 176 | w.set_dbg_sleep(true); | 176 | w.set_dbg_sleep(true); |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c7d1ae615..b7b692f15 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -27,6 +27,9 @@ pub struct Clocks { | |||
| 27 | pub ahb3: Hertz, | 27 | pub ahb3: Hertz, |
| 28 | 28 | ||
| 29 | #[cfg(any(rcc_h7))] | 29 | #[cfg(any(rcc_h7))] |
| 30 | pub ahb4: Hertz, | ||
| 31 | |||
| 32 | #[cfg(any(rcc_h7))] | ||
| 30 | pub apb4: Hertz, | 33 | pub apb4: Hertz, |
| 31 | } | 34 | } |
| 32 | 35 | ||
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2fa758ecc..ddaed5bb9 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -8,7 +8,6 @@ use crate::peripherals; | |||
| 8 | pub use _version::*; | 8 | pub use _version::*; |
| 9 | 9 | ||
| 10 | use crate::gpio::Pin; | 10 | use crate::gpio::Pin; |
| 11 | use crate::pac::usart::Usart; | ||
| 12 | use crate::rcc::RccPeripheral; | 11 | use crate::rcc::RccPeripheral; |
| 13 | 12 | ||
| 14 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 13 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| @@ -58,6 +57,7 @@ impl Default for Config { | |||
| 58 | 57 | ||
| 59 | /// Serial error | 58 | /// Serial error |
| 60 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | 59 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
| 60 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 61 | #[non_exhaustive] | 61 | #[non_exhaustive] |
| 62 | pub enum Error { | 62 | pub enum Error { |
| 63 | /// Framing error | 63 | /// Framing error |
| @@ -73,11 +73,11 @@ pub enum Error { | |||
| 73 | pub(crate) mod sealed { | 73 | pub(crate) mod sealed { |
| 74 | use super::*; | 74 | use super::*; |
| 75 | 75 | ||
| 76 | #[cfg(any(dma, dmamux))] | 76 | #[cfg(any(dma, bdma, dmamux))] |
| 77 | use crate::dma::WriteDma; | 77 | use crate::dma_traits::WriteDma; |
| 78 | 78 | ||
| 79 | pub trait Instance { | 79 | pub trait Instance { |
| 80 | fn regs(&self) -> Usart; | 80 | fn regs(&self) -> crate::pac::usart::Usart; |
| 81 | } | 81 | } |
| 82 | pub trait RxPin<T: Instance>: Pin { | 82 | pub trait RxPin<T: Instance>: Pin { |
| 83 | fn af_num(&self) -> u8; | 83 | fn af_num(&self) -> u8; |
| @@ -95,10 +95,10 @@ pub(crate) mod sealed { | |||
| 95 | fn af_num(&self) -> u8; | 95 | fn af_num(&self) -> u8; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | #[cfg(any(dma, dmamux))] | 98 | #[cfg(any(bdma, dma, dmamux))] |
| 99 | pub trait RxDma<T: Instance> {} | 99 | pub trait RxDma<T: Instance> {} |
| 100 | 100 | ||
| 101 | #[cfg(any(dma, dmamux))] | 101 | #[cfg(any(bdma, dma, dmamux))] |
| 102 | pub trait TxDma<T: Instance>: WriteDma<T> {} | 102 | pub trait TxDma<T: Instance>: WriteDma<T> {} |
| 103 | } | 103 | } |
| 104 | 104 | ||
| @@ -109,10 +109,10 @@ pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} | |||
| 109 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} | 109 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} |
| 110 | pub trait CkPin<T: Instance>: sealed::CkPin<T> {} | 110 | pub trait CkPin<T: Instance>: sealed::CkPin<T> {} |
| 111 | 111 | ||
| 112 | #[cfg(any(dma, dmamux))] | 112 | #[cfg(any(bdma, dma, dmamux))] |
| 113 | pub trait RxDma<T: Instance>: sealed::RxDma<T> {} | 113 | pub trait RxDma<T: Instance>: sealed::RxDma<T> {} |
| 114 | 114 | ||
| 115 | #[cfg(any(dma, dmamux))] | 115 | #[cfg(any(bdma, dma, dmamux))] |
| 116 | pub trait TxDma<T: Instance>: sealed::TxDma<T> {} | 116 | pub trait TxDma<T: Instance>: sealed::TxDma<T> {} |
| 117 | 117 | ||
| 118 | crate::pac::peripherals!( | 118 | crate::pac::peripherals!( |
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 8b1378917..22041b4aa 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs | |||
| @@ -1 +1,119 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 1 | 2 | ||
| 3 | use embassy::util::Unborrow; | ||
| 4 | use embassy_extras::unborrow; | ||
| 5 | |||
| 6 | use crate::pac::usart::vals; | ||
| 7 | |||
| 8 | use super::*; | ||
| 9 | |||
| 10 | pub struct Uart<'d, T: Instance> { | ||
| 11 | inner: T, | ||
| 12 | phantom: PhantomData<&'d mut T>, | ||
| 13 | } | ||
| 14 | |||
| 15 | impl<'d, T: Instance> Uart<'d, T> { | ||
| 16 | pub fn new( | ||
| 17 | inner: impl Unborrow<Target = T>, | ||
| 18 | rx: impl Unborrow<Target = impl RxPin<T>>, | ||
| 19 | tx: impl Unborrow<Target = impl TxPin<T>>, | ||
| 20 | config: Config, | ||
| 21 | ) -> Self { | ||
| 22 | unborrow!(inner, rx, tx); | ||
| 23 | |||
| 24 | T::enable(); | ||
| 25 | let pclk_freq = T::frequency(); | ||
| 26 | |||
| 27 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 28 | let div = pclk_freq.0 / config.baudrate; | ||
| 29 | |||
| 30 | let r = inner.regs(); | ||
| 31 | |||
| 32 | unsafe { | ||
| 33 | rx.set_as_af(rx.af_num()); | ||
| 34 | tx.set_as_af(tx.af_num()); | ||
| 35 | |||
| 36 | r.cr2().write(|_w| {}); | ||
| 37 | r.cr3().write(|_w| {}); | ||
| 38 | |||
| 39 | r.brr().write(|w| w.set_brr(div as u16)); | ||
| 40 | r.cr1().write(|w| { | ||
| 41 | w.set_ue(true); | ||
| 42 | w.set_te(true); | ||
| 43 | w.set_re(true); | ||
| 44 | w.set_m0(vals::M0::BIT8); | ||
| 45 | w.set_m1(vals::M1::M0); | ||
| 46 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 47 | w.set_ps(match config.parity { | ||
| 48 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 49 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 50 | _ => vals::Ps::EVEN, | ||
| 51 | }); | ||
| 52 | }); | ||
| 53 | } | ||
| 54 | |||
| 55 | Self { | ||
| 56 | inner, | ||
| 57 | phantom: PhantomData, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg(bdma)] | ||
| 62 | pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { | ||
| 63 | unsafe { | ||
| 64 | self.inner.regs().cr3().modify(|reg| { | ||
| 65 | reg.set_dmat(true); | ||
| 66 | }); | ||
| 67 | } | ||
| 68 | let r = self.inner.regs(); | ||
| 69 | let dst = r.tdr().ptr() as *mut u8; | ||
| 70 | ch.transfer(buffer, dst).await; | ||
| 71 | Ok(()) | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 75 | unsafe { | ||
| 76 | let r = self.inner.regs(); | ||
| 77 | for b in buffer { | ||
| 78 | loop { | ||
| 79 | let sr = r.isr().read(); | ||
| 80 | if sr.pe() { | ||
| 81 | r.rdr().read(); | ||
| 82 | return Err(Error::Parity); | ||
| 83 | } else if sr.fe() { | ||
| 84 | r.rdr().read(); | ||
| 85 | return Err(Error::Framing); | ||
| 86 | } else if sr.ore() { | ||
| 87 | r.rdr().read(); | ||
| 88 | return Err(Error::Overrun); | ||
| 89 | } else if sr.rxne() { | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | *b = r.rdr().read().0 as u8; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | Ok(()) | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> { | ||
| 101 | type Error = Error; | ||
| 102 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 103 | unsafe { | ||
| 104 | let r = self.inner.regs(); | ||
| 105 | for &b in buffer { | ||
| 106 | while !r.isr().read().txe() {} | ||
| 107 | r.tdr().write(|w| w.set_dr(b as u16)); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | Ok(()) | ||
| 111 | } | ||
| 112 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 113 | unsafe { | ||
| 114 | let r = self.inner.regs(); | ||
| 115 | while !r.isr().read().tc() {} | ||
| 116 | } | ||
| 117 | Ok(()) | ||
| 118 | } | ||
| 119 | } | ||
diff --git a/embassy-stm32/src/usart/v3.rs b/embassy-stm32/src/usart/v3.rs index 1e9051443..0071c597a 100644 --- a/embassy-stm32/src/usart/v3.rs +++ b/embassy-stm32/src/usart/v3.rs | |||
| @@ -57,7 +57,7 @@ impl<'d, T: Instance> Uart<'d, T> { | |||
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | #[cfg(dma)] | 60 | #[cfg(any(dma, dmamux))] |
| 61 | pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { | 61 | pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { |
| 62 | unsafe { | 62 | unsafe { |
| 63 | self.inner.regs().cr3().modify(|reg| { | 63 | self.inner.regs().cr3().modify(|reg| { |
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 5b6d9eaa1..0b14eeb59 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs | |||
| @@ -82,10 +82,6 @@ fn main() -> ! { | |||
| 82 | w.syscfgen().set_bit(); | 82 | w.syscfgen().set_bit(); |
| 83 | w | 83 | w |
| 84 | }); | 84 | }); |
| 85 | //pp.RCC.apb1enr.modify(|_, w| { | ||
| 86 | //w.usart3en().enabled(); | ||
| 87 | //w | ||
| 88 | //}); | ||
| 89 | 85 | ||
| 90 | unsafe { embassy::time::set_clock(&ZeroClock) }; | 86 | unsafe { embassy::time::set_clock(&ZeroClock) }; |
| 91 | 87 | ||
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs new file mode 100644 index 000000000..cc630e0df --- /dev/null +++ b/examples/stm32l4/src/bin/usart_dma.rs | |||
| @@ -0,0 +1,96 @@ | |||
| 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 cortex_m_rt::entry; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use embassy_stm32::usart::{Config, Uart}; | ||
| 17 | use example_common::*; | ||
| 18 | use heapless::String; | ||
| 19 | use stm32l4::stm32l4x5 as pac; | ||
| 20 | |||
| 21 | #[embassy::task] | ||
| 22 | async fn main_task() { | ||
| 23 | let mut p = embassy_stm32::init(Default::default()); | ||
| 24 | |||
| 25 | let config = Config::default(); | ||
| 26 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, config); | ||
| 27 | |||
| 28 | for n in 0u32.. { | ||
| 29 | let mut s: String<128> = String::new(); | ||
| 30 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 31 | |||
| 32 | usart | ||
| 33 | .write_dma(&mut p.DMA1_3, s.as_bytes()) | ||
| 34 | .await | ||
| 35 | .unwrap(); | ||
| 36 | info!("wrote DMA"); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | struct ZeroClock; | ||
| 41 | |||
| 42 | impl Clock for ZeroClock { | ||
| 43 | fn now(&self) -> u64 { | ||
| 44 | 0 | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 49 | |||
| 50 | #[entry] | ||
| 51 | fn main() -> ! { | ||
| 52 | info!("Hello World!"); | ||
| 53 | |||
| 54 | let pp = pac::Peripherals::take().unwrap(); | ||
| 55 | |||
| 56 | pp.DBGMCU.cr.modify(|_, w| { | ||
| 57 | w.dbg_sleep().set_bit(); | ||
| 58 | w.dbg_standby().set_bit(); | ||
| 59 | w.dbg_stop().set_bit() | ||
| 60 | }); | ||
| 61 | |||
| 62 | pp.RCC.ahb1enr.modify(|_, w| { | ||
| 63 | unsafe { | ||
| 64 | w.bits( 0x07 ); | ||
| 65 | } | ||
| 66 | w | ||
| 67 | //w.dmamuxen().set_bit(); | ||
| 68 | //w.dma1en().set_bit(); | ||
| 69 | //w.dma2en().set_bit(); | ||
| 70 | //w | ||
| 71 | }); | ||
| 72 | |||
| 73 | pp.RCC.ahb2enr.modify(|_, w| { | ||
| 74 | w.gpioaen().set_bit(); | ||
| 75 | w.gpioben().set_bit(); | ||
| 76 | w.gpiocen().set_bit(); | ||
| 77 | w.gpioden().set_bit(); | ||
| 78 | w.gpioeen().set_bit(); | ||
| 79 | w.gpiofen().set_bit(); | ||
| 80 | w | ||
| 81 | }); | ||
| 82 | |||
| 83 | pp.RCC.apb2enr.modify(|_, w| { | ||
| 84 | w.syscfgen().set_bit(); | ||
| 85 | w | ||
| 86 | }); | ||
| 87 | |||
| 88 | |||
| 89 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 90 | |||
| 91 | let executor = EXECUTOR.put(Executor::new()); | ||
| 92 | |||
| 93 | executor.run(|spawner| { | ||
| 94 | unwrap!(spawner.spawn(main_task())); | ||
| 95 | }) | ||
| 96 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject 409ed5502c254e462f3e31b0ea5ddee95f818a7 | Subproject bc74a98017800aad50dd1448a24e3f54eaec8eb | ||
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 978f70b92..37254f6f0 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs | |||
| @@ -141,6 +141,21 @@ macro_rules! peripheral_count {{ | |||
| 141 | write!(out, " }}\n").unwrap(); | 141 | write!(out, " }}\n").unwrap(); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) { | ||
| 145 | write!(out, | ||
| 146 | "#[macro_export] | ||
| 147 | macro_rules! dma_channels_count {{ | ||
| 148 | ").unwrap(); | ||
| 149 | for (name, count) in data { | ||
| 150 | write!(out, | ||
| 151 | "({}) => ({});\n", | ||
| 152 | name, count, | ||
| 153 | ).unwrap(); | ||
| 154 | } | ||
| 155 | write!(out, | ||
| 156 | " }}\n").unwrap(); | ||
| 157 | } | ||
| 158 | |||
| 144 | fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { | 159 | fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { |
| 145 | write!( | 160 | write!( |
| 146 | out, | 161 | out, |
| @@ -252,9 +267,11 @@ pub fn gen(options: Options) { | |||
| 252 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); | 267 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); |
| 253 | let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); | 268 | let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); |
| 254 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | 269 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 270 | let mut bdma_channels_table: Vec<Vec<String>> = Vec::new(); | ||
| 255 | let mut dma_requests_table: Vec<Vec<String>> = Vec::new(); | 271 | let mut dma_requests_table: Vec<Vec<String>> = Vec::new(); |
| 256 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); | 272 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 257 | let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); | 273 | let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); |
| 274 | let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); | ||
| 258 | 275 | ||
| 259 | let dma_base = core | 276 | let dma_base = core |
| 260 | .peripherals | 277 | .peripherals |
| @@ -266,14 +283,6 @@ pub fn gen(options: Options) { | |||
| 266 | let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; | 283 | let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; |
| 267 | let gpio_stride = 0x400; | 284 | let gpio_stride = 0x400; |
| 268 | 285 | ||
| 269 | for (id, channel_info) in &core.dma_channels { | ||
| 270 | let mut row = Vec::new(); | ||
| 271 | row.push(id.clone()); | ||
| 272 | row.push(channel_info.dma.clone()); | ||
| 273 | row.push(channel_info.channel.to_string()); | ||
| 274 | dma_channels_table.push(row); | ||
| 275 | } | ||
| 276 | |||
| 277 | let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); | 286 | let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); |
| 278 | 287 | ||
| 279 | for (name, p) in &core.peripherals { | 288 | for (name, p) in &core.peripherals { |
| @@ -295,6 +304,11 @@ pub fn gen(options: Options) { | |||
| 295 | if let Some(block) = &p.block { | 304 | if let Some(block) = &p.block { |
| 296 | let bi = BlockInfo::parse(block); | 305 | let bi = BlockInfo::parse(block); |
| 297 | 306 | ||
| 307 | peripheral_counts.insert( | ||
| 308 | bi.module.clone(), | ||
| 309 | peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), | ||
| 310 | ); | ||
| 311 | |||
| 298 | for pin in &p.pins { | 312 | for pin in &p.pins { |
| 299 | let mut row = Vec::new(); | 313 | let mut row = Vec::new(); |
| 300 | row.push(name.clone()); | 314 | row.push(name.clone()); |
| @@ -421,14 +435,16 @@ pub fn gen(options: Options) { | |||
| 421 | clock.to_ascii_lowercase() | 435 | clock.to_ascii_lowercase() |
| 422 | }; | 436 | }; |
| 423 | 437 | ||
| 424 | peripheral_rcc_table.push(vec![ | 438 | if !name.starts_with("GPIO") { |
| 425 | name.clone(), | 439 | peripheral_rcc_table.push(vec![ |
| 426 | clock, | 440 | name.clone(), |
| 427 | enable_reg.to_ascii_lowercase(), | 441 | clock, |
| 428 | reset_reg.to_ascii_lowercase(), | 442 | enable_reg.to_ascii_lowercase(), |
| 429 | format!("set_{}", enable_field.to_ascii_lowercase()), | 443 | reset_reg.to_ascii_lowercase(), |
| 430 | format!("set_{}", reset_field.to_ascii_lowercase()), | 444 | format!("set_{}", enable_field.to_ascii_lowercase()), |
| 431 | ]); | 445 | format!("set_{}", reset_field.to_ascii_lowercase()), |
| 446 | ]); | ||
| 447 | } | ||
| 432 | } | 448 | } |
| 433 | (None, Some(_)) => { | 449 | (None, Some(_)) => { |
| 434 | print!("Unable to find enable register for {}", name) | 450 | print!("Unable to find enable register for {}", name) |
| @@ -447,6 +463,30 @@ pub fn gen(options: Options) { | |||
| 447 | dev.peripherals.push(ir_peri); | 463 | dev.peripherals.push(ir_peri); |
| 448 | } | 464 | } |
| 449 | 465 | ||
| 466 | for (id, channel_info) in &core.dma_channels { | ||
| 467 | let mut row = Vec::new(); | ||
| 468 | let dma_peri = core.peripherals.get(&channel_info.dma); | ||
| 469 | row.push(id.clone()); | ||
| 470 | row.push(channel_info.dma.clone()); | ||
| 471 | row.push(channel_info.channel.to_string()); | ||
| 472 | if let Some(dma_peri) = dma_peri { | ||
| 473 | if let Some(ref block) = dma_peri.block { | ||
| 474 | let bi = BlockInfo::parse(block); | ||
| 475 | if bi.module == "bdma" { | ||
| 476 | bdma_channels_table.push(row); | ||
| 477 | } else { | ||
| 478 | dma_channels_table.push(row); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | let dma_peri_name = channel_info.dma.clone(); | ||
| 484 | dma_channel_counts.insert( | ||
| 485 | dma_peri_name.clone(), | ||
| 486 | dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1), | ||
| 487 | ); | ||
| 488 | } | ||
| 489 | |||
| 450 | for (name, &num) in &core.interrupts { | 490 | for (name, &num) in &core.interrupts { |
| 451 | dev.interrupts.push(ir::Interrupt { | 491 | dev.interrupts.push(ir::Interrupt { |
| 452 | name: name.clone(), | 492 | name: name.clone(), |
| @@ -493,8 +533,10 @@ pub fn gen(options: Options) { | |||
| 493 | ); | 533 | ); |
| 494 | make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); | 534 | make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); |
| 495 | make_table(&mut extra, "dma_channels", &dma_channels_table); | 535 | make_table(&mut extra, "dma_channels", &dma_channels_table); |
| 536 | make_table(&mut extra, "bdma_channels", &bdma_channels_table); | ||
| 496 | make_table(&mut extra, "dma_requests", &dma_requests_table); | 537 | make_table(&mut extra, "dma_requests", &dma_requests_table); |
| 497 | make_peripheral_counts(&mut extra, &peripheral_counts); | 538 | make_peripheral_counts(&mut extra, &peripheral_counts); |
| 539 | make_dma_channel_counts(&mut extra, &dma_channel_counts); | ||
| 498 | 540 | ||
| 499 | for (module, version) in peripheral_versions { | 541 | for (module, version) in peripheral_versions { |
| 500 | all_peripheral_versions.insert((module.clone(), version.clone())); | 542 | all_peripheral_versions.insert((module.clone(), version.clone())); |
