Merge pull request #282 from bobmcwhirter/dmamux_thales
BDMA + DMAMUX + H7 with major help from @thalesfragoso
This commit is contained in:
		| @@ -1,69 +1,413 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| #[cfg_attr(bdma_v1, path = "v1.rs")] | ||||
| #[cfg_attr(bdma_v2, path = "v2.rs")] | ||||
| mod _version; | ||||
| use core::future::Future; | ||||
| use core::task::Poll; | ||||
|  | ||||
| #[allow(unused)] | ||||
| pub use _version::*; | ||||
| use atomic_polyfill::{AtomicU8, Ordering}; | ||||
| use embassy::interrupt::{Interrupt, InterruptExt}; | ||||
| use embassy::util::{AtomicWaker, OnDrop}; | ||||
| use futures::future::poll_fn; | ||||
|  | ||||
| use crate::dma_traits::{ReadDma, WriteDma}; | ||||
| use crate::interrupt; | ||||
| use crate::pac; | ||||
| use crate::peripherals; | ||||
| use crate::pac::bdma::vals; | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
| const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; | ||||
| const CH_STATUS_NONE: u8 = 0; | ||||
| const CH_STATUS_COMPLETED: u8 = 1; | ||||
| const CH_STATUS_ERROR: u8 = 2; | ||||
|  | ||||
|     pub trait Channel { | ||||
|         fn num(&self) -> u8; | ||||
| struct State { | ||||
|     ch_wakers: [AtomicWaker; CH_COUNT], | ||||
|     ch_status: [AtomicU8; CH_COUNT], | ||||
| } | ||||
|  | ||||
|         fn dma_num(&self) -> u8 { | ||||
|             self.num() / 8 | ||||
|         } | ||||
|         fn ch_num(&self) -> u8 { | ||||
|             self.num() % 8 | ||||
|         } | ||||
|         fn regs(&self) -> pac::dma::Dma { | ||||
|             pac::DMA(self.num() as _) | ||||
| impl State { | ||||
|     const fn new() -> Self { | ||||
|         const AW: AtomicWaker = AtomicWaker::new(); | ||||
|         const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); | ||||
|         Self { | ||||
|             ch_wakers: [AW; CH_COUNT], | ||||
|             ch_status: [AU; CH_COUNT], | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static STATE: State = State::new(); | ||||
|  | ||||
| #[allow(unused)] | ||||
| pub(crate) async unsafe fn transfer_p2m( | ||||
|     regs: pac::bdma::Ch, | ||||
|     state_number: u8, | ||||
|     src: *const u8, | ||||
|     dst: &mut [u8], | ||||
|     #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||||
|     #[cfg(dmamux)] dmamux_ch_num: u8, | ||||
|     #[cfg(dmamux)] request: u8, | ||||
| ) { | ||||
|     // ndtr is max 16 bits. | ||||
|     assert!(dst.len() <= 0xFFFF); | ||||
|  | ||||
|     // Reset status | ||||
|     // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||||
|     STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||||
|  | ||||
|     let on_drop = OnDrop::new(|| unsafe { | ||||
|         regs.cr().modify(|w| { | ||||
|             w.set_tcie(false); | ||||
|             w.set_teie(false); | ||||
|             w.set_en(false); | ||||
|         }); | ||||
|         while regs.cr().read().en() {} | ||||
|     }); | ||||
|  | ||||
|     #[cfg(dmamux)] | ||||
|     crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||||
|  | ||||
|     regs.par().write_value(src as u32); | ||||
|     regs.mar().write_value(dst.as_mut_ptr() as u32); | ||||
|     regs.ndtr().write(|w| w.set_ndt(dst.len() as u16)); | ||||
|     regs.cr().write(|w| { | ||||
|         w.set_psize(vals::Size::BITS8); | ||||
|         w.set_msize(vals::Size::BITS8); | ||||
|         w.set_minc(vals::Inc::ENABLED); | ||||
|         w.set_teie(true); | ||||
|         w.set_tcie(true); | ||||
|         w.set_en(true); | ||||
|     }); | ||||
|  | ||||
|     let res = poll_fn(|cx| { | ||||
|         STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||||
|         match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { | ||||
|             CH_STATUS_NONE => Poll::Pending, | ||||
|             x => Poll::Ready(x), | ||||
|         } | ||||
|     }) | ||||
|     .await; | ||||
|  | ||||
|     // TODO handle error | ||||
|     assert!(res == CH_STATUS_COMPLETED); | ||||
| } | ||||
|  | ||||
| #[allow(unused)] | ||||
| pub(crate) async unsafe fn transfer_m2p( | ||||
|     regs: pac::bdma::Ch, | ||||
|     state_number: u8, | ||||
|     src: &[u8], | ||||
|     dst: *mut u8, | ||||
|     #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||||
|     #[cfg(dmamux)] dmamux_ch_num: u8, | ||||
|     #[cfg(dmamux)] request: u8, | ||||
| ) { | ||||
|     // ndtr is max 16 bits. | ||||
|     assert!(src.len() <= 0xFFFF); | ||||
|  | ||||
|     // Reset status | ||||
|     // Generate a DMB here to flush the store buffer (M7) before enabling the DMA | ||||
|     STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); | ||||
|  | ||||
|     let on_drop = OnDrop::new(|| unsafe { | ||||
|         regs.cr().modify(|w| { | ||||
|             w.set_tcie(false); | ||||
|             w.set_teie(false); | ||||
|             w.set_en(false); | ||||
|         }); | ||||
|         while regs.cr().read().en() {} | ||||
|     }); | ||||
|  | ||||
|     #[cfg(dmamux)] | ||||
|     crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||||
|  | ||||
|     regs.par().write_value(dst as u32); | ||||
|     regs.mar().write_value(src.as_ptr() as u32); | ||||
|     regs.ndtr().write(|w| w.set_ndt(src.len() as u16)); | ||||
|     regs.cr().write(|w| { | ||||
|         w.set_psize(vals::Size::BITS8); | ||||
|         w.set_msize(vals::Size::BITS8); | ||||
|         w.set_minc(vals::Inc::ENABLED); | ||||
|         w.set_dir(vals::Dir::FROMMEMORY); | ||||
|         w.set_teie(true); | ||||
|         w.set_tcie(true); | ||||
|         w.set_en(true); | ||||
|     }); | ||||
|  | ||||
|     let res = poll_fn(|cx| { | ||||
|         STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||||
|         match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { | ||||
|             CH_STATUS_NONE => Poll::Pending, | ||||
|             x => Poll::Ready(x), | ||||
|         } | ||||
|     }) | ||||
|     .await; | ||||
|  | ||||
|     // TODO handle error | ||||
|     assert!(res == CH_STATUS_COMPLETED); | ||||
| } | ||||
|  | ||||
| unsafe fn on_irq() { | ||||
|     pac::peripherals! { | ||||
|         (bdma, $dma:ident) => { | ||||
|                 let isr = pac::$dma.isr().read(); | ||||
|                 pac::$dma.ifcr().write_value(isr); | ||||
|                 let dman = <crate::peripherals::$dma as sealed::Dma>::NUM as usize; | ||||
|  | ||||
|                 for chn in 0..crate::pac::dma_channels_count!($dma) { | ||||
|                     let n = dman * 8 + chn; | ||||
|                     if isr.teif(chn) { | ||||
|                         STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); | ||||
|                         STATE.ch_wakers[n].wake(); | ||||
|                     } else if isr.tcif(chn) { | ||||
|                         STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); | ||||
|                         STATE.ch_wakers[n].wake(); | ||||
|                     } | ||||
|                 } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| use crate::rcc::sealed::RccPeripheral; | ||||
|  | ||||
| /// safety: must be called only once | ||||
| pub(crate) unsafe fn init() { | ||||
|     pac::interrupts! { | ||||
|         (DMA, $irq:ident) => { | ||||
|             crate::interrupt::$irq::steal().enable(); | ||||
|         }; | ||||
|     } | ||||
|     pac::peripherals! { | ||||
|         (bdma, $peri:ident) => { | ||||
|             crate::peripherals::$peri::enable(); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub trait Dma { | ||||
|         const NUM: u8; | ||||
|     } | ||||
|  | ||||
|     pub trait Channel { | ||||
|         const CH_NUM: u8; | ||||
|         const STATE_NUM: u8; | ||||
|         const DMA_REGS: pac::bdma::Dma; | ||||
|  | ||||
|         fn regs(&self) -> pac::bdma::Ch { | ||||
|             Self::DMA_REGS.ch(Self::CH_NUM as usize) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Dma: sealed::Dma + Sized {} | ||||
| pub trait Channel: sealed::Channel + Sized {} | ||||
|  | ||||
| macro_rules! impl_dma { | ||||
|     ($peri:ident) => { | ||||
|         impl Dma for crate::peripherals::$peri {} | ||||
|         impl sealed::Dma for crate::peripherals::$peri { | ||||
|             const NUM: u8 = dma_num!($peri); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_dma_channel { | ||||
|     ($channel_peri:ident, $dma_num:expr, $ch_num:expr) => { | ||||
|         impl Channel for peripherals::$channel_peri {} | ||||
|         impl sealed::Channel for peripherals::$channel_peri { | ||||
|             #[inline] | ||||
|             fn num(&self) -> u8 { | ||||
|                 $dma_num * 8 + $ch_num | ||||
|     ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => { | ||||
|         impl Channel for crate::peripherals::$channel_peri {} | ||||
|         impl sealed::Channel for crate::peripherals::$channel_peri { | ||||
|             const CH_NUM: u8 = $ch_num; | ||||
|             const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num; | ||||
|             const DMA_REGS: pac::bdma::Dma = crate::pac::$dma_peri; | ||||
|  | ||||
|             //#[inline] | ||||
|             //fn dma_regs() -> pac::bdma::Dma { | ||||
|             //crate::pac::$dma_peri | ||||
|             //} | ||||
|  | ||||
|             //fn state_num(&self) -> usize { | ||||
|             //(dma_num!($dma_peri) * 8) + $ch_num | ||||
|             //} | ||||
|         } | ||||
|  | ||||
|         #[cfg(not(dmamux))] | ||||
|         impl<T> WriteDma<T> for crate::peripherals::$channel_peri | ||||
|         where | ||||
|             T: 'static, | ||||
|         { | ||||
|             type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||||
|  | ||||
|             fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||||
|             where | ||||
|                 T: 'a, | ||||
|             { | ||||
|                 use sealed::Channel as _Channel; | ||||
|  | ||||
|                 let state_num = Self::STATE_NUM; | ||||
|                 let regs = self.regs(); | ||||
|  | ||||
|                 unsafe { transfer_m2p(regs, state_num, buf, dst) } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #[cfg(dmamux)] | ||||
|         impl<T> WriteDma<T> for crate::peripherals::$channel_peri | ||||
|         where | ||||
|             Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::M2P>, | ||||
|             T: 'static, | ||||
|         { | ||||
|             type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||||
|  | ||||
|             fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||||
|             where | ||||
|                 T: 'a, | ||||
|             { | ||||
|                 use sealed::Channel as _Channel; | ||||
|  | ||||
|                 let state_num = Self::STATE_NUM; | ||||
|                 let regs = self.regs(); | ||||
|  | ||||
|                 use crate::dmamux::sealed::Channel as MuxChannel; | ||||
|                 use crate::dmamux::sealed::PeripheralChannel; | ||||
|                 let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS; | ||||
|                 let dmamux_ch_num = | ||||
|                     <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM; | ||||
|                 let request = <crate::peripherals::$channel_peri as PeripheralChannel< | ||||
|                     T, | ||||
|                     crate::dmamux::M2P, | ||||
|                 >>::REQUEST; | ||||
|                 unsafe { | ||||
|                     transfer_m2p( | ||||
|                         regs, | ||||
|                         state_num, | ||||
|                         buf, | ||||
|                         dst, | ||||
|                         dmamux_regs, | ||||
|                         dmamux_ch_num, | ||||
|                         request, | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #[cfg(not(dmamux))] | ||||
|         impl<T> ReadDma<T> for crate::peripherals::$channel_peri | ||||
|         where | ||||
|             T: 'static, | ||||
|         { | ||||
|             type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||||
|  | ||||
|             fn transfer<'a>( | ||||
|                 &'a mut self, | ||||
|                 src: *const u8, | ||||
|                 buf: &'a mut [u8], | ||||
|             ) -> Self::ReadDmaFuture<'a> | ||||
|             where | ||||
|                 T: 'a, | ||||
|             { | ||||
|                 use sealed::Channel as _Channel; | ||||
|  | ||||
|                 let state_num = Self::STATE_NUM; | ||||
|                 let regs = self.regs(); | ||||
|                 unsafe { transfer_p2m(regs, state_num, src, buf) } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #[cfg(dmamux)] | ||||
|         impl<T> ReadDma<T> for crate::peripherals::$channel_peri | ||||
|         where | ||||
|             Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::P2M>, | ||||
|             T: 'static, | ||||
|         { | ||||
|             type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||||
|  | ||||
|             fn transfer<'a>( | ||||
|                 &'a mut self, | ||||
|                 src: *const u8, | ||||
|                 buf: &'a mut [u8], | ||||
|             ) -> Self::ReadDmaFuture<'a> | ||||
|             where | ||||
|                 T: 'a, | ||||
|             { | ||||
|                 use sealed::Channel as _Channel; | ||||
|  | ||||
|                 let state_num = Self::STATE_NUM; | ||||
|                 let regs = self.regs(); | ||||
|  | ||||
|                 use crate::dmamux::sealed::Channel as MuxChannel; | ||||
|                 use crate::dmamux::sealed::PeripheralChannel; | ||||
|                 let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS; | ||||
|                 let dmamux_ch_num = | ||||
|                     <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM; | ||||
|                 let request = <crate::peripherals::$channel_peri as PeripheralChannel< | ||||
|                     T, | ||||
|                     crate::dmamux::P2M, | ||||
|                 >>::REQUEST; | ||||
|                 unsafe { | ||||
|                     transfer_p2m( | ||||
|                         regs, | ||||
|                         state_num, | ||||
|                         src, | ||||
|                         buf, | ||||
|                         dmamux_regs, | ||||
|                         dmamux_ch_num, | ||||
|                         request, | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /* | ||||
| crate::pac::peripherals!( | ||||
|     (dma,DMA1) => { | ||||
|         impl_dma_channel!(DMA1_CH0, 0, 0); | ||||
|         impl_dma_channel!(DMA1_CH1, 0, 1); | ||||
|         impl_dma_channel!(DMA1_CH2, 0, 2); | ||||
|         impl_dma_channel!(DMA1_CH3, 0, 3); | ||||
|         impl_dma_channel!(DMA1_CH4, 0, 4); | ||||
|         impl_dma_channel!(DMA1_CH5, 0, 5); | ||||
|         impl_dma_channel!(DMA1_CH6, 0, 6); | ||||
|         impl_dma_channel!(DMA1_CH7, 0, 7); | ||||
| macro_rules! dma_num { | ||||
|     (DMA1) => { | ||||
|         0 | ||||
|     }; | ||||
|     (DMA2) => { | ||||
|         1 | ||||
|     }; | ||||
|     (BDMA) => { | ||||
|         0 | ||||
|     }; | ||||
| } | ||||
| pac::peripherals! { | ||||
|     (bdma, $peri:ident) => { | ||||
|         impl_dma!($peri); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pac::bdma_channels! { | ||||
|     ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||||
|         impl_dma_channel!($channel_peri, $dma_peri, $channel_num); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pac::interrupts! { | ||||
|     (DMA, $irq:ident) => { | ||||
|         #[crate::interrupt] | ||||
|         unsafe fn $irq () { | ||||
|             on_irq() | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[cfg(usart)] | ||||
| use crate::usart; | ||||
|  | ||||
| pac::peripherals! { | ||||
|     (usart, $peri:ident) => { | ||||
|         impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {} | ||||
|         impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {} | ||||
|  | ||||
|         impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {} | ||||
|         impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {} | ||||
|     }; | ||||
|  | ||||
|     (dma,DMA2) => { | ||||
|         impl_dma_channel!(DMA2_CH0, 1, 0); | ||||
|         impl_dma_channel!(DMA2_CH1, 1, 1); | ||||
|         impl_dma_channel!(DMA2_CH2, 1, 2); | ||||
|         impl_dma_channel!(DMA2_CH3, 1, 3); | ||||
|         impl_dma_channel!(DMA2_CH4, 1, 4); | ||||
|         impl_dma_channel!(DMA2_CH5, 1, 5); | ||||
|         impl_dma_channel!(DMA2_CH6, 1, 6); | ||||
|         impl_dma_channel!(DMA2_CH7, 1, 7); | ||||
|     (uart, $peri:ident) => { | ||||
|         impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {} | ||||
|         impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {} | ||||
|  | ||||
|         impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {} | ||||
|         impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {} | ||||
|     }; | ||||
| ); | ||||
|  */ | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| #[cfg(dma)] | ||||
| #[cfg_attr(dma_v1, path = "v1.rs")] | ||||
| #[cfg_attr(dma_v2, path = "v2.rs")] | ||||
| mod _version; | ||||
| @@ -8,25 +7,3 @@ mod _version; | ||||
| #[cfg(dma)] | ||||
| #[allow(unused)] | ||||
| pub use _version::*; | ||||
|  | ||||
| use core::future::Future; | ||||
|  | ||||
| pub trait WriteDma<T> { | ||||
|     type WriteDmaFuture<'a>: Future<Output = ()> + 'a | ||||
|     where | ||||
|         Self: 'a; | ||||
|  | ||||
|     fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||||
|     where | ||||
|         T: 'a; | ||||
| } | ||||
|  | ||||
| pub trait ReadDma<T> { | ||||
|     type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||||
|     where | ||||
|         Self: 'a; | ||||
|  | ||||
|     fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||||
|     where | ||||
|         T: 'a; | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| use core::task::Poll; | ||||
|  | ||||
| use crate::dma_traits::{ReadDma, WriteDma}; | ||||
| use atomic_polyfill::{AtomicU8, Ordering}; | ||||
| use core::future::Future; | ||||
| use embassy::interrupt::{Interrupt, InterruptExt}; | ||||
| use embassy::util::AtomicWaker; | ||||
| use futures::future::poll_fn; | ||||
|  | ||||
| use super::*; | ||||
| use crate::interrupt; | ||||
| use crate::pac; | ||||
| use crate::pac::dma::{regs, vals}; | ||||
|   | ||||
							
								
								
									
										21
									
								
								embassy-stm32/src/dma_traits.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								embassy-stm32/src/dma_traits.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| use core::future::Future; | ||||
|  | ||||
| pub trait WriteDma<T> { | ||||
|     type WriteDmaFuture<'a>: Future<Output = ()> + 'a | ||||
|     where | ||||
|         Self: 'a; | ||||
|  | ||||
|     fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> | ||||
|     where | ||||
|         T: 'a; | ||||
| } | ||||
|  | ||||
| pub trait ReadDma<T> { | ||||
|     type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||||
|     where | ||||
|         Self: 'a; | ||||
|  | ||||
|     fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||||
|     where | ||||
|         T: 'a; | ||||
| } | ||||
							
								
								
									
										137
									
								
								embassy-stm32/src/dmamux/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								embassy-stm32/src/dmamux/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use crate::pac; | ||||
| use crate::pac::bdma_channels; | ||||
| use crate::pac::dma_requests; | ||||
| use crate::pac::peripherals; | ||||
| use crate::peripherals; | ||||
|  | ||||
| pub(crate) unsafe fn configure_dmamux( | ||||
|     dmamux_regs: pac::dmamux::Dmamux, | ||||
|     dmamux_ch_num: u8, | ||||
|     request: u8, | ||||
| ) { | ||||
|     let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _); | ||||
|     ch_mux_regs.write(|reg| { | ||||
|         reg.set_nbreq(0); | ||||
|         reg.set_dmareq_id(request); | ||||
|     }); | ||||
|  | ||||
|     ch_mux_regs.modify(|reg| { | ||||
|         reg.set_ege(true); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub trait Channel { | ||||
|         const DMAMUX_CH_NUM: u8; | ||||
|         const DMAMUX_REGS: pac::dmamux::Dmamux; | ||||
|     } | ||||
|  | ||||
|     pub trait PeripheralChannel<PERI, OP>: Channel { | ||||
|         const REQUEST: u8; | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Channel: sealed::Channel {} | ||||
| pub trait PeripheralChannel<PERI, OP>: sealed::Channel {} | ||||
|  | ||||
| pub struct P2M; | ||||
| pub struct M2P; | ||||
|  | ||||
| macro_rules! dma_num { | ||||
|     (DMA1) => { | ||||
|         0 | ||||
|     }; | ||||
|     (DMA2) => { | ||||
|         1 | ||||
|     }; | ||||
|     (BDMA) => { | ||||
|         0 | ||||
|     }; | ||||
| } | ||||
|  | ||||
| macro_rules! dmamux_peri { | ||||
|     (DMA1) => { | ||||
|         crate::pac::DMAMUX1 | ||||
|     }; | ||||
|     (DMA2) => { | ||||
|         crate::pac::DMAMUX1 | ||||
|     }; | ||||
|     (BDMA) => { | ||||
|         crate::pac::DMAMUX1 | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[allow(unused)] | ||||
| macro_rules! impl_dma_channel { | ||||
|     ($channel_peri:ident, $channel_num:expr, $dma_peri: ident) => { | ||||
|         impl Channel for peripherals::$channel_peri {} | ||||
|         impl sealed::Channel for peripherals::$channel_peri { | ||||
|             const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; | ||||
|             const DMAMUX_REGS: pac::dmamux::Dmamux = dmamux_peri!($dma_peri); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| peripherals! { | ||||
|     (bdma, $peri:ident) => { | ||||
|         bdma_channels! { | ||||
|             ($channel_peri:ident, $peri, $channel_num:expr) => { | ||||
|                 impl_dma_channel!($channel_peri, $channel_num, $peri); | ||||
|             }; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[allow(unused)] | ||||
| macro_rules! impl_peripheral_channel { | ||||
|     ($channel_peri:ident, $direction:ident, $peri:ident, $request:expr) => { | ||||
|         impl sealed::PeripheralChannel<peripherals::$peri, $direction> | ||||
|             for peripherals::$channel_peri | ||||
|         { | ||||
|             const REQUEST: u8 = $request; | ||||
|         } | ||||
|  | ||||
|         impl PeripheralChannel<peripherals::$peri, $direction> for peripherals::$channel_peri {} | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[allow(unused)] | ||||
| macro_rules! impl_usart_dma_requests { | ||||
|     ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||||
|         dma_requests! { | ||||
|             (usart, $peri:ident, RX, $request:expr) => { | ||||
|                 impl_peripheral_channel!($channel_peri, P2M, $peri, $request); | ||||
|             }; | ||||
|  | ||||
|             (usart, $peri:ident, TX, $request:expr) => { | ||||
|                 impl_peripheral_channel!($channel_peri, M2P, $peri, $request); | ||||
|             }; | ||||
|  | ||||
|             (uart, $peri:ident, RX, $request:expr) => { | ||||
|                 impl_peripheral_channel!($channel_peri, P2M, $peri, $request); | ||||
|             }; | ||||
|  | ||||
|             (uart, $peri:ident, TX, $request:expr) => { | ||||
|                 impl_peripheral_channel!($channel_peri, M2P, $peri, $request); | ||||
|             }; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[allow(unused)] | ||||
| #[cfg(usart)] | ||||
| use crate::usart; | ||||
|  | ||||
| bdma_channels! { | ||||
|     ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { | ||||
|         #[cfg(usart)] | ||||
|         impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /// safety: must be called only once | ||||
| pub(crate) unsafe fn init() {} | ||||
| @@ -20,14 +20,21 @@ pub mod gpio; | ||||
| pub mod rcc; | ||||
|  | ||||
| // Sometimes-present hardware | ||||
| #[cfg(any(dma, bdma, dmamux))] | ||||
| pub mod dma_traits; | ||||
|  | ||||
| #[cfg(adc)] | ||||
| pub mod adc; | ||||
| #[cfg(bdma)] | ||||
| pub mod bdma; | ||||
| #[cfg(timer)] | ||||
| pub mod clock; | ||||
| #[cfg(dac)] | ||||
| pub mod dac; | ||||
| #[cfg(any(dma, dmamux))] | ||||
| #[cfg(dma)] | ||||
| pub mod dma; | ||||
| #[cfg(dmamux)] | ||||
| pub mod dmamux; | ||||
| #[cfg(all(eth, feature = "net"))] | ||||
| pub mod eth; | ||||
| #[cfg(exti)] | ||||
| @@ -86,8 +93,13 @@ pub fn init(config: Config) -> Peripherals { | ||||
|     unsafe { | ||||
|         #[cfg(dma)] | ||||
|         dma::init(); | ||||
|         #[cfg(bdma)] | ||||
|         bdma::init(); | ||||
|         #[cfg(dmamux)] | ||||
|         dmamux::init(); | ||||
|         #[cfg(exti)] | ||||
|         exti::init(); | ||||
|  | ||||
|         rcc::init(config.rcc); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -532,6 +532,7 @@ pub unsafe fn init(config: Config) { | ||||
|         ahb1: core_clocks.hclk, | ||||
|         ahb2: core_clocks.hclk, | ||||
|         ahb3: core_clocks.hclk, | ||||
|         ahb4: core_clocks.hclk, | ||||
|         apb1: core_clocks.pclk1, | ||||
|         apb2: core_clocks.pclk2, | ||||
|         apb4: core_clocks.pclk4, | ||||
|   | ||||
| @@ -170,7 +170,7 @@ impl<'d> Rcc<'d> { | ||||
|     pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { | ||||
|         // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU | ||||
|         unsafe { | ||||
|             pac::RCC.ahbenr().modify(|w| w.set_dmaen(enable_dma)); | ||||
|             pac::RCC.ahbenr().modify(|w| w.set_dma1en(enable_dma)); | ||||
|  | ||||
|             pac::DBGMCU.cr().modify(|w| { | ||||
|                 w.set_dbg_sleep(true); | ||||
|   | ||||
| @@ -26,6 +26,9 @@ pub struct Clocks { | ||||
|     #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))] | ||||
|     pub ahb3: Hertz, | ||||
|  | ||||
|     #[cfg(any(rcc_h7))] | ||||
|     pub ahb4: Hertz, | ||||
|  | ||||
|     #[cfg(any(rcc_h7))] | ||||
|     pub apb4: Hertz, | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,6 @@ use crate::peripherals; | ||||
| pub use _version::*; | ||||
|  | ||||
| use crate::gpio::Pin; | ||||
| use crate::pac::usart::Usart; | ||||
| use crate::rcc::RccPeripheral; | ||||
|  | ||||
| #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||||
| @@ -58,6 +57,7 @@ impl Default for Config { | ||||
|  | ||||
| /// Serial error | ||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||
| #[non_exhaustive] | ||||
| pub enum Error { | ||||
|     /// Framing error | ||||
| @@ -73,11 +73,11 @@ pub enum Error { | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     #[cfg(any(dma, dmamux))] | ||||
|     use crate::dma::WriteDma; | ||||
|     #[cfg(any(dma, bdma, dmamux))] | ||||
|     use crate::dma_traits::WriteDma; | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs(&self) -> Usart; | ||||
|         fn regs(&self) -> crate::pac::usart::Usart; | ||||
|     } | ||||
|     pub trait RxPin<T: Instance>: Pin { | ||||
|         fn af_num(&self) -> u8; | ||||
| @@ -95,10 +95,10 @@ pub(crate) mod sealed { | ||||
|         fn af_num(&self) -> u8; | ||||
|     } | ||||
|  | ||||
|     #[cfg(any(dma, dmamux))] | ||||
|     #[cfg(any(bdma, dma, dmamux))] | ||||
|     pub trait RxDma<T: Instance> {} | ||||
|  | ||||
|     #[cfg(any(dma, dmamux))] | ||||
|     #[cfg(any(bdma, dma, dmamux))] | ||||
|     pub trait TxDma<T: Instance>: WriteDma<T> {} | ||||
| } | ||||
|  | ||||
| @@ -109,10 +109,10 @@ pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} | ||||
| pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} | ||||
| pub trait CkPin<T: Instance>: sealed::CkPin<T> {} | ||||
|  | ||||
| #[cfg(any(dma, dmamux))] | ||||
| #[cfg(any(bdma, dma, dmamux))] | ||||
| pub trait RxDma<T: Instance>: sealed::RxDma<T> {} | ||||
|  | ||||
| #[cfg(any(dma, dmamux))] | ||||
| #[cfg(any(bdma, dma, dmamux))] | ||||
| pub trait TxDma<T: Instance>: sealed::TxDma<T> {} | ||||
|  | ||||
| crate::pac::peripherals!( | ||||
|   | ||||
| @@ -1 +1,119 @@ | ||||
| use core::marker::PhantomData; | ||||
|  | ||||
| use embassy::util::Unborrow; | ||||
| use embassy_extras::unborrow; | ||||
|  | ||||
| use crate::pac::usart::vals; | ||||
|  | ||||
| use super::*; | ||||
|  | ||||
| pub struct Uart<'d, T: Instance> { | ||||
|     inner: T, | ||||
|     phantom: PhantomData<&'d mut T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Uart<'d, T> { | ||||
|     pub fn new( | ||||
|         inner: impl Unborrow<Target = T>, | ||||
|         rx: impl Unborrow<Target = impl RxPin<T>>, | ||||
|         tx: impl Unborrow<Target = impl TxPin<T>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         unborrow!(inner, rx, tx); | ||||
|  | ||||
|         T::enable(); | ||||
|         let pclk_freq = T::frequency(); | ||||
|  | ||||
|         // TODO: better calculation, including error checking and OVER8 if possible. | ||||
|         let div = pclk_freq.0 / config.baudrate; | ||||
|  | ||||
|         let r = inner.regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num()); | ||||
|             tx.set_as_af(tx.af_num()); | ||||
|  | ||||
|             r.cr2().write(|_w| {}); | ||||
|             r.cr3().write(|_w| {}); | ||||
|  | ||||
|             r.brr().write(|w| w.set_brr(div as u16)); | ||||
|             r.cr1().write(|w| { | ||||
|                 w.set_ue(true); | ||||
|                 w.set_te(true); | ||||
|                 w.set_re(true); | ||||
|                 w.set_m0(vals::M0::BIT8); | ||||
|                 w.set_m1(vals::M1::M0); | ||||
|                 w.set_pce(config.parity != Parity::ParityNone); | ||||
|                 w.set_ps(match config.parity { | ||||
|                     Parity::ParityOdd => vals::Ps::ODD, | ||||
|                     Parity::ParityEven => vals::Ps::EVEN, | ||||
|                     _ => vals::Ps::EVEN, | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         Self { | ||||
|             inner, | ||||
|             phantom: PhantomData, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(bdma)] | ||||
|     pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             self.inner.regs().cr3().modify(|reg| { | ||||
|                 reg.set_dmat(true); | ||||
|             }); | ||||
|         } | ||||
|         let r = self.inner.regs(); | ||||
|         let dst = r.tdr().ptr() as *mut u8; | ||||
|         ch.transfer(buffer, dst).await; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             let r = self.inner.regs(); | ||||
|             for b in buffer { | ||||
|                 loop { | ||||
|                     let sr = r.isr().read(); | ||||
|                     if sr.pe() { | ||||
|                         r.rdr().read(); | ||||
|                         return Err(Error::Parity); | ||||
|                     } else if sr.fe() { | ||||
|                         r.rdr().read(); | ||||
|                         return Err(Error::Framing); | ||||
|                     } else if sr.ore() { | ||||
|                         r.rdr().read(); | ||||
|                         return Err(Error::Overrun); | ||||
|                     } else if sr.rxne() { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 *b = r.rdr().read().0 as u8; | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> { | ||||
|     type Error = Error; | ||||
|     fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||||
|         unsafe { | ||||
|             let r = self.inner.regs(); | ||||
|             for &b in buffer { | ||||
|                 while !r.isr().read().txe() {} | ||||
|                 r.tdr().write(|w| w.set_dr(b as u16)); | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn bflush(&mut self) -> Result<(), Self::Error> { | ||||
|         unsafe { | ||||
|             let r = self.inner.regs(); | ||||
|             while !r.isr().read().tc() {} | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -57,7 +57,7 @@ impl<'d, T: Instance> Uart<'d, T> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(dma)] | ||||
|     #[cfg(any(dma, dmamux))] | ||||
|     pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             self.inner.regs().cr3().modify(|reg| { | ||||
|   | ||||
| @@ -82,10 +82,6 @@ fn main() -> ! { | ||||
|         w.syscfgen().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|     //pp.RCC.apb1enr.modify(|_, w| { | ||||
|     //w.usart3en().enabled(); | ||||
|     //w | ||||
|     //}); | ||||
|  | ||||
|     unsafe { embassy::time::set_clock(&ZeroClock) }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										96
									
								
								examples/stm32l4/src/bin/usart_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								examples/stm32l4/src/bin/usart_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(trait_alias)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use core::fmt::Write; | ||||
| use cortex_m_rt::entry; | ||||
| use embassy::executor::Executor; | ||||
| use embassy::time::Clock; | ||||
| use embassy::util::Forever; | ||||
| use embassy_stm32::usart::{Config, Uart}; | ||||
| use example_common::*; | ||||
| use heapless::String; | ||||
| use stm32l4::stm32l4x5 as pac; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn main_task() { | ||||
|     let mut p = embassy_stm32::init(Default::default()); | ||||
|  | ||||
|     let config = Config::default(); | ||||
|     let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, config); | ||||
|  | ||||
|     for n in 0u32.. { | ||||
|         let mut s: String<128> = String::new(); | ||||
|         core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | ||||
|  | ||||
|         usart | ||||
|             .write_dma(&mut p.DMA1_3, s.as_bytes()) | ||||
|             .await | ||||
|             .unwrap(); | ||||
|         info!("wrote DMA"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct ZeroClock; | ||||
|  | ||||
| impl Clock for ZeroClock { | ||||
|     fn now(&self) -> u64 { | ||||
|         0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let pp = pac::Peripherals::take().unwrap(); | ||||
|  | ||||
|     pp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbg_sleep().set_bit(); | ||||
|         w.dbg_standby().set_bit(); | ||||
|         w.dbg_stop().set_bit() | ||||
|     }); | ||||
|  | ||||
|     pp.RCC.ahb1enr.modify(|_, w| { | ||||
|         unsafe { | ||||
|             w.bits( 0x07 ); | ||||
|         } | ||||
|         w | ||||
|         //w.dmamuxen().set_bit(); | ||||
|         //w.dma1en().set_bit(); | ||||
|         //w.dma2en().set_bit(); | ||||
|         //w | ||||
|     }); | ||||
|  | ||||
|     pp.RCC.ahb2enr.modify(|_, w| { | ||||
|         w.gpioaen().set_bit(); | ||||
|         w.gpioben().set_bit(); | ||||
|         w.gpiocen().set_bit(); | ||||
|         w.gpioden().set_bit(); | ||||
|         w.gpioeen().set_bit(); | ||||
|         w.gpiofen().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|     pp.RCC.apb2enr.modify(|_, w| { | ||||
|         w.syscfgen().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     unsafe { embassy::time::set_clock(&ZeroClock) }; | ||||
|  | ||||
|     let executor = EXECUTOR.put(Executor::new()); | ||||
|  | ||||
|     executor.run(|spawner| { | ||||
|         unwrap!(spawner.spawn(main_task())); | ||||
|     }) | ||||
| } | ||||
 Submodule stm32-data updated: 409ed5502c...bc74a98017
									
								
							| @@ -141,6 +141,21 @@ macro_rules! peripheral_count {{ | ||||
|     write!(out, " }}\n").unwrap(); | ||||
| } | ||||
|  | ||||
| fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) { | ||||
|     write!(out, | ||||
|            "#[macro_export] | ||||
| macro_rules! dma_channels_count {{ | ||||
|     ").unwrap(); | ||||
|     for (name, count) in data { | ||||
|         write!(out, | ||||
|                "({}) => ({});\n", | ||||
|                name, count, | ||||
|         ).unwrap(); | ||||
|     } | ||||
|     write!(out, | ||||
|            " }}\n").unwrap(); | ||||
| } | ||||
|  | ||||
| fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { | ||||
|     write!( | ||||
|         out, | ||||
| @@ -252,9 +267,11 @@ pub fn gen(options: Options) { | ||||
|         let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut bdma_channels_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut dma_requests_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); | ||||
|         let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); | ||||
|         let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); | ||||
|  | ||||
|         let dma_base = core | ||||
|             .peripherals | ||||
| @@ -266,14 +283,6 @@ pub fn gen(options: Options) { | ||||
|         let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; | ||||
|         let gpio_stride = 0x400; | ||||
|  | ||||
|         for (id, channel_info) in &core.dma_channels { | ||||
|             let mut row = Vec::new(); | ||||
|             row.push(id.clone()); | ||||
|             row.push(channel_info.dma.clone()); | ||||
|             row.push(channel_info.channel.to_string()); | ||||
|             dma_channels_table.push(row); | ||||
|         } | ||||
|  | ||||
|         let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); | ||||
|  | ||||
|         for (name, p) in &core.peripherals { | ||||
| @@ -295,6 +304,11 @@ pub fn gen(options: Options) { | ||||
|             if let Some(block) = &p.block { | ||||
|                 let bi = BlockInfo::parse(block); | ||||
|  | ||||
|                 peripheral_counts.insert( | ||||
|                     bi.module.clone(), | ||||
|                     peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), | ||||
|                 ); | ||||
|  | ||||
|                 for pin in &p.pins { | ||||
|                     let mut row = Vec::new(); | ||||
|                     row.push(name.clone()); | ||||
| @@ -421,14 +435,16 @@ pub fn gen(options: Options) { | ||||
|                                     clock.to_ascii_lowercase() | ||||
|                                 }; | ||||
|  | ||||
|                                 peripheral_rcc_table.push(vec![ | ||||
|                                     name.clone(), | ||||
|                                     clock, | ||||
|                                     enable_reg.to_ascii_lowercase(), | ||||
|                                     reset_reg.to_ascii_lowercase(), | ||||
|                                     format!("set_{}", enable_field.to_ascii_lowercase()), | ||||
|                                     format!("set_{}", reset_field.to_ascii_lowercase()), | ||||
|                                 ]); | ||||
|                                 if !name.starts_with("GPIO") { | ||||
|                                     peripheral_rcc_table.push(vec![ | ||||
|                                         name.clone(), | ||||
|                                         clock, | ||||
|                                         enable_reg.to_ascii_lowercase(), | ||||
|                                         reset_reg.to_ascii_lowercase(), | ||||
|                                         format!("set_{}", enable_field.to_ascii_lowercase()), | ||||
|                                         format!("set_{}", reset_field.to_ascii_lowercase()), | ||||
|                                     ]); | ||||
|                                 } | ||||
|                             } | ||||
|                             (None, Some(_)) => { | ||||
|                                 print!("Unable to find enable register for {}", name) | ||||
| @@ -447,6 +463,30 @@ pub fn gen(options: Options) { | ||||
|             dev.peripherals.push(ir_peri); | ||||
|         } | ||||
|  | ||||
|         for (id, channel_info) in &core.dma_channels { | ||||
|             let mut row = Vec::new(); | ||||
|             let dma_peri = core.peripherals.get(&channel_info.dma); | ||||
|             row.push(id.clone()); | ||||
|             row.push(channel_info.dma.clone()); | ||||
|             row.push(channel_info.channel.to_string()); | ||||
|             if let Some(dma_peri) = dma_peri { | ||||
|                 if let Some(ref block) = dma_peri.block { | ||||
|                     let bi = BlockInfo::parse(block); | ||||
|                     if bi.module == "bdma" { | ||||
|                         bdma_channels_table.push(row); | ||||
|                     } else { | ||||
|                         dma_channels_table.push(row); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             let dma_peri_name = channel_info.dma.clone(); | ||||
|             dma_channel_counts.insert( | ||||
|                 dma_peri_name.clone(), | ||||
|                 dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1), | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         for (name, &num) in &core.interrupts { | ||||
|             dev.interrupts.push(ir::Interrupt { | ||||
|                 name: name.clone(), | ||||
| @@ -493,8 +533,10 @@ pub fn gen(options: Options) { | ||||
|         ); | ||||
|         make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); | ||||
|         make_table(&mut extra, "dma_channels", &dma_channels_table); | ||||
|         make_table(&mut extra, "bdma_channels", &bdma_channels_table); | ||||
|         make_table(&mut extra, "dma_requests", &dma_requests_table); | ||||
|         make_peripheral_counts(&mut extra, &peripheral_counts); | ||||
|         make_dma_channel_counts(&mut extra, &dma_channel_counts); | ||||
|  | ||||
|         for (module, version) in peripheral_versions { | ||||
|             all_peripheral_versions.insert((module.clone(), version.clone())); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user