diff --git a/embassy-stm32/gen.py b/embassy-stm32/gen.py index 386c5ce17..01c778716 100644 --- a/embassy-stm32/gen.py +++ b/embassy-stm32/gen.py @@ -73,13 +73,16 @@ with open(output_file, 'w') as f: pins.add(pin) singletons.append(pin) - if block_mod == 'dma': - custom_singletons = True - for ch_num in range(8): - channel = f'{name}_CH{ch_num}' - singletons.append(channel) + # if block_mod == 'dma': + # custom_singletons = True + # for ch_num in range(8): + # channel = f'{name}_CH{ch_num}' + # singletons.append(channel) if not custom_singletons: singletons.append(name) + for (channel_id, defn) in core['dma_channels'].items(): + singletons.append( channel_id ) + f.write(f"embassy_extras::peripherals!({','.join(singletons)});") diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs new file mode 100644 index 000000000..e85ade5df --- /dev/null +++ b/embassy-stm32/src/bdma/mod.rs @@ -0,0 +1,69 @@ +#![macro_use] + +#[cfg_attr(bdma_v1, path = "v1.rs")] +#[cfg_attr(bdma_v2, path = "v2.rs")] +mod _version; + +#[allow(unused)] +pub use _version::*; + +use crate::pac; +use crate::peripherals; + +pub(crate) mod sealed { + use super::*; + + pub trait Channel { + fn num(&self) -> u8; + + 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 _) + } + } +} + +pub trait Channel: sealed::Channel + Sized {} + +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 + } + } + }; +} + +/* +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); + }; + + (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); + }; +); + */ diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 773cdc8b8..371741ffd 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -7,61 +7,24 @@ mod _version; #[allow(unused)] pub use _version::*; -use crate::pac; -use crate::peripherals; +use core::future::Future; -pub(crate) mod sealed { - use super::*; +pub trait WriteDma { + type WriteDmaFuture<'a>: Future + 'a + where + Self: 'a; - pub trait Channel { - fn num(&self) -> u8; - - 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 _) - } - } + fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> + where + T: 'a; } -pub trait Channel: sealed::Channel + Sized {} +pub trait ReadDma { + type ReadDmaFuture<'a>: Future + 'a + where + Self: 'a; -macro_rules! impl_dma_channel { - ($type:ident, $dma_num:expr, $ch_num:expr) => { - impl Channel for peripherals::$type {} - impl sealed::Channel for peripherals::$type { - #[inline] - fn num(&self) -> u8 { - $dma_num * 8 + $ch_num - } - } - }; + fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> + where + T: 'a; } - -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); - }; - - (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); - }; -); diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index e7bd69130..93b3cb869 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs @@ -9,9 +9,14 @@ use crate::interrupt; use crate::pac; use crate::pac::dma::{regs, vals}; -const DMAS: [pac::dma::Dma; 2] = [pac::DMA1, pac::DMA2]; +use crate::pac::dma_channels; +use crate::pac::interrupts; +use crate::pac::peripheral_count; +use crate::pac::peripheral_dma_channels; +use crate::pac::peripherals; +use crate::peripherals; -const CH_COUNT: usize = 16; +const CH_COUNT: usize = peripheral_count!(DMA) * 8; const CH_STATUS_NONE: u8 = 0; const CH_STATUS_COMPLETED: u8 = 1; const CH_STATUS_ERROR: u8 = 2; @@ -34,6 +39,52 @@ impl State { static STATE: State = State::new(); +#[allow(unused)] // Used by usart/v1.rs which may or may not be enabled +pub(crate) async unsafe fn transfer_p2m( + ch: &mut impl Channel, + ch_func: u8, + src: *const u8, + dst: &mut [u8], +) { + let n = ch.num(); + let c = ch.regs(); + + // ndtr is max 16 bits. + assert!(dst.len() <= 0xFFFF); + + // Reset status + STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Relaxed); + + unsafe { + c.par().write_value(src as _); + c.m0ar().write_value(dst.as_ptr() as _); + c.ndtr().write_value(regs::Ndtr(dst.len() as _)); + c.cr().write(|w| { + w.set_dir(vals::Dir::PERIPHERALTOMEMORY); + w.set_msize(vals::Size::BITS8); + w.set_psize(vals::Size::BITS8); + w.set_minc(vals::Inc::INCREMENTED); + w.set_pinc(vals::Inc::FIXED); + w.set_chsel(ch_func); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + } + + let res = poll_fn(|cx| { + STATE.ch_wakers[n].register(cx.waker()); + match STATE.ch_status[n].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled pub(crate) async unsafe fn transfer_m2p( ch: &mut impl Channel, @@ -41,9 +92,8 @@ pub(crate) async unsafe fn transfer_m2p( src: &[u8], dst: *mut u8, ) { - let n = ch.num() as usize; - let r = ch.regs(); - let c = r.st(ch.ch_num() as _); + let n = ch.num(); + let c = ch.regs(); // ndtr is max 16 bits. assert!(src.len() <= 0xFFFF); @@ -55,6 +105,7 @@ pub(crate) async unsafe fn transfer_m2p( c.par().write_value(dst as _); c.m0ar().write_value(src.as_ptr() as _); c.ndtr().write_value(regs::Ndtr(src.len() as _)); + compiler_fence(Ordering::AcqRel); c.cr().write(|w| { w.set_dir(vals::Dir::MEMORYTOPERIPHERAL); w.set_msize(vals::Size::BITS8); @@ -70,118 +121,211 @@ pub(crate) async unsafe fn transfer_m2p( let res = poll_fn(|cx| { STATE.ch_wakers[n].register(cx.waker()); - match STATE.ch_status[n].load(Ordering::Relaxed) { - CH_STATUS_NONE => Poll::Pending, + match STATE.ch_status[n].load(Ordering::Acquire) { + CH_STATUS_NONE => { + let left = c.ndtr().read().ndt(); + Poll::Pending + } x => Poll::Ready(x), } }) .await; + compiler_fence(Ordering::AcqRel); + // TODO handle error assert!(res == CH_STATUS_COMPLETED); } unsafe fn on_irq() { - for (dman, &dma) in DMAS.iter().enumerate() { - for isrn in 0..2 { - let isr = dma.isr(isrn).read(); - dma.ifcr(isrn).write_value(isr); + peripherals! { + (dma, $dma:ident) => { + for isrn in 0..2 { + let isr = pac::$dma.isr(isrn).read(); + pac::$dma.ifcr(isrn).write_value(isr); + let dman = ::num() as usize; - for chn in 0..4 { - let n = dman * 8 + isrn * 4 + 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(); + for chn in 0..4 { + let n = dman * 8 + isrn * 4 + chn; + if isr.teif(chn) { + STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Release); + STATE.ch_wakers[n].wake(); + } else if isr.tcif(chn) { + STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Release); + STATE.ch_wakers[n].wake(); + } } } - } + }; } } -#[interrupt] -unsafe fn DMA1_STREAM0() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM1() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM2() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM3() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM4() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM5() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM6() { - on_irq() -} -#[interrupt] -unsafe fn DMA1_STREAM7() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM0() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM1() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM2() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM3() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM4() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM5() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM6() { - on_irq() -} -#[interrupt] -unsafe fn DMA2_STREAM7() { - on_irq() -} - /// safety: must be called only once pub(crate) unsafe fn init() { - interrupt::DMA1_STREAM0::steal().enable(); - interrupt::DMA1_STREAM1::steal().enable(); - interrupt::DMA1_STREAM2::steal().enable(); - interrupt::DMA1_STREAM3::steal().enable(); - interrupt::DMA1_STREAM4::steal().enable(); - interrupt::DMA1_STREAM5::steal().enable(); - interrupt::DMA1_STREAM6::steal().enable(); - interrupt::DMA1_STREAM7::steal().enable(); - interrupt::DMA2_STREAM0::steal().enable(); - interrupt::DMA2_STREAM1::steal().enable(); - interrupt::DMA2_STREAM2::steal().enable(); - interrupt::DMA2_STREAM3::steal().enable(); - interrupt::DMA2_STREAM4::steal().enable(); - interrupt::DMA2_STREAM5::steal().enable(); - interrupt::DMA2_STREAM6::steal().enable(); - interrupt::DMA2_STREAM7::steal().enable(); + interrupts! { + (DMA, $irq:ident) => { + interrupt::$irq::steal().enable(); + }; + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Dma { + fn num() -> u8; + fn regs() -> &'static pac::dma::Dma; + } + + pub trait Channel { + fn dma_regs() -> &'static pac::dma::Dma; + + fn num(&self) -> usize; + + fn ch_num(&self) -> u8; + + fn regs(&self) -> pac::dma::St { + Self::dma_regs().st(self.ch_num() as _) + } + } + + pub trait PeripheralChannel: Channel { + fn request(&self) -> u8; + } +} + +pub trait Dma: sealed::Dma + Sized {} +pub trait Channel: sealed::Channel + Sized {} +pub trait PeripheralChannel: sealed::PeripheralChannel + Sized {} + +macro_rules! impl_dma { + ($peri:ident, $num:expr) => { + impl Dma for peripherals::$peri {} + impl sealed::Dma for peripherals::$peri { + fn num() -> u8 { + $num + } + fn regs() -> &'static pac::dma::Dma { + &pac::$peri + } + } + }; +} + +macro_rules! impl_dma_channel { + ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { + impl Channel for peripherals::$channel_peri {} + impl sealed::Channel for peripherals::$channel_peri { + #[inline] + fn dma_regs() -> &'static pac::dma::Dma { + &crate::pac::$dma_peri + } + + fn num(&self) -> usize { + ($dma_num * 8) + $ch_num + } + + fn ch_num(&self) -> u8 { + $ch_num + } + } + + impl WriteDma for peripherals::$channel_peri + where + Self: sealed::PeripheralChannel, + T: 'static, + { + type WriteDmaFuture<'a> = impl Future; + + fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> + where + T: 'a, + { + let request = sealed::PeripheralChannel::::request(self); + unsafe { transfer_m2p(self, request, buf, dst) } + } + } + + impl ReadDma for peripherals::$channel_peri + where + Self: sealed::PeripheralChannel, + T: 'static, + { + type ReadDmaFuture<'a> = impl Future; + + fn transfer<'a>( + &'a mut self, + src: *const u8, + buf: &'a mut [u8], + ) -> Self::ReadDmaFuture<'a> + where + T: 'a, + { + let request = sealed::PeripheralChannel::::request(self); + unsafe { transfer_p2m(self, request, src, buf) } + } + } + }; +} + +peripherals! { + (dma, DMA1) => { + impl_dma!(DMA1, 0); + dma_channels! { + ($channel_peri:ident, DMA1, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); + }; + } + }; + (dma, DMA2) => { + impl_dma!(DMA2, 1); + dma_channels! { + ($channel_peri:ident, DMA2, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); + }; + } + }; +} + +interrupts! { + (DMA, $irq:ident) => { + #[crate::interrupt] + unsafe fn $irq () { + on_irq() + } + }; +} + +pub struct P2M; +pub struct M2P; + +#[cfg(usart)] +use crate::usart; +use atomic_polyfill::compiler_fence; +peripheral_dma_channels! { + ($peri:ident, usart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { + impl usart::RxDma for peripherals::$channel_peri { } + impl usart::sealed::RxDma for peripherals::$channel_peri { } + + impl sealed::PeripheralChannel for peripherals::$channel_peri { + fn request(&self) -> u8 { + $event_num + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + }; + + ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { + impl usart::TxDma for peripherals::$channel_peri { } + impl usart::sealed::TxDma for peripherals::$channel_peri { } + + impl sealed::PeripheralChannel for peripherals::$channel_peri { + fn request(&self) -> u8 { + $event_num + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + }; } diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4/mod.rs index 4b17bdf40..6000192b9 100644 --- a/embassy-stm32/src/rcc/f4/mod.rs +++ b/embassy-stm32/src/rcc/f4/mod.rs @@ -132,7 +132,7 @@ impl RccExt for RCC { ClockSrc::HSI16 => { // Enable HSI16 unsafe { - rcc.cr().write(|w| w.set_hsion(true)); + rcc.cr().modify(|w| w.set_hsion(true)); while !rcc.cr().read().hsirdy() {} } @@ -141,7 +141,7 @@ impl RccExt for RCC { ClockSrc::HSE(freq) => { // Enable HSE unsafe { - rcc.cr().write(|w| w.set_hseon(true)); + rcc.cr().modify(|w| w.set_hseon(true)); while !rcc.cr().read().hserdy() {} } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index adf48c326..a75793f84 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -8,6 +8,7 @@ pub use _version::*; use crate::gpio::Pin; use crate::pac::usart::Usart; +use crate::rcc::RccPeripheral; /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] @@ -26,6 +27,9 @@ pub enum Error { pub(crate) mod sealed { use super::*; + #[cfg(dma)] + use crate::dma::WriteDma; + pub trait Instance { fn regs(&self) -> Usart; } @@ -44,14 +48,26 @@ pub(crate) mod sealed { pub trait CkPin: Pin { fn af_num(&self) -> u8; } + + #[cfg(dma)] + pub trait RxDma {} + + #[cfg(dma)] + pub trait TxDma: WriteDma {} } -pub trait Instance: sealed::Instance {} + +pub trait Instance: sealed::Instance + RccPeripheral {} pub trait RxPin: sealed::RxPin {} pub trait TxPin: sealed::TxPin {} pub trait CtsPin: sealed::CtsPin {} pub trait RtsPin: sealed::RtsPin {} pub trait CkPin: sealed::CkPin {} +#[cfg(dma)] +pub trait RxDma: sealed::RxDma {} +#[cfg(dma)] +pub trait TxDma: sealed::TxDma {} + crate::pac::peripherals!( (usart, $inst:ident) => { impl sealed::Instance for peripherals::$inst { diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 1ec1f5b30..6c5a12441 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -63,14 +63,14 @@ impl<'d, T: Instance> Uart<'d, T> { rx: impl Unborrow>, tx: impl Unborrow>, config: Config, - pclk_freq: u32, ) -> Self { unborrow!(inner, rx, tx); - // TODO: enable in RCC + T::enable(); + let pclk_freq = T::frequency(); // TODO: better calculation, including error checking and OVER8 if possible. - let div = (pclk_freq + (config.baudrate / 2)) / config.baudrate; + let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; let r = inner.regs(); @@ -101,25 +101,16 @@ impl<'d, T: Instance> Uart<'d, T> { } } - #[cfg(dma_v2)] - pub async fn write_dma( - &mut self, - ch: &mut impl crate::dma::Channel, - buffer: &[u8], - ) -> Result<(), Error> { - let ch_func = 4; // USART3_TX - let r = self.inner.regs(); - + #[cfg(dma)] + pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { unsafe { - r.cr3().write(|w| { - w.set_dmat(true); + self.inner.regs().cr3().modify(|reg| { + reg.set_dmat(true); }); - - let dst = r.dr().ptr() as *mut u8; - - crate::dma::transfer_m2p(ch, ch_func, buffer, dst).await; } - + let r = self.inner.regs(); + let dst = r.dr().ptr() as *mut u8; + ch.transfer(buffer, dst).await; Ok(()) } diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index f7b66f86b..42f154b05 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -23,7 +23,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index fae05b607..66ca6242b 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -23,14 +23,14 @@ async fn main_task() { let mut p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, 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_CH3, s.as_bytes()) + .write_dma(&mut p.DMA1_3, s.as_bytes()) .await .unwrap(); info!("wrote DMA"); diff --git a/stm32-data b/stm32-data index eb76ee900..9856b1117 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit eb76ee900ac67b51497196572250323e82666b4c +Subproject commit 9856b11172ae27ffa60d339ac271d2d06c190756 diff --git a/stm32-metapac/Cargo.toml b/stm32-metapac/Cargo.toml index bed772c81..79f1c3746 100644 --- a/stm32-metapac/Cargo.toml +++ b/stm32-metapac/Cargo.toml @@ -12,6 +12,7 @@ cortex-m-rt = { version = "0.6.8", optional = true } # These are removed when generating the pre-generated crate using the tool at gen/. [build-dependencies] stm32-metapac-gen = { path = "./gen" } +regex = "1.5.4" # END BUILD DEPENDENCIES [features] diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index 9e7add452..a552c8cea 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -27,6 +27,7 @@ pub struct Core { pub name: String, pub peripherals: HashMap, pub interrupts: HashMap, + pub dma_channels: HashMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -46,6 +47,10 @@ pub struct Peripheral { pub clock: Option, #[serde(default)] pub pins: Vec, + #[serde(default)] + pub dma_channels: HashMap>, + #[serde(default)] + pub dma_requests: HashMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -55,6 +60,18 @@ pub struct Pin { pub af: Option, } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] +pub struct DmaChannel { + pub dma: String, + pub channel: u32, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] +pub struct PeripheralDmaChannel { + pub channel: String, + pub request: Option, +} + struct BlockInfo { /// usart_v1/USART -> usart module: String, @@ -110,6 +127,21 @@ fn find_reg_for_field<'c>( }) } +fn make_peripheral_counts(out: &mut String, data: &HashMap) { + write!(out, + "#[macro_export] +macro_rules! peripheral_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>) { write!( out, @@ -123,7 +155,7 @@ macro_rules! {} {{ ", name, name ) - .unwrap(); + .unwrap(); for row in data { write!(out, " __{}_inner!(({}));\n", name, row.join(",")).unwrap(); @@ -134,7 +166,7 @@ macro_rules! {} {{ " }}; }}" ) - .unwrap(); + .unwrap(); } pub struct Options { @@ -220,6 +252,10 @@ pub fn gen(options: Options) { let mut peripherals_table: Vec> = Vec::new(); let mut peripheral_pins_table: Vec> = Vec::new(); let mut peripheral_rcc_table: Vec> = Vec::new(); + let mut dma_channels_table: Vec> = Vec::new(); + let mut dma_requests_table: Vec> = Vec::new(); + let mut peripheral_dma_channels_table: Vec> = Vec::new(); + let mut peripheral_counts: HashMap = HashMap::new(); let dma_base = core .peripherals @@ -231,7 +267,23 @@ 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 { + let captures = number_suffix_re.captures(&name).unwrap(); + let root_peri_name = captures.get(1).unwrap().as_str().to_string(); + peripheral_counts.insert( + root_peri_name.clone(), + peripheral_counts.get(&root_peri_name).map_or(1, |v| v + 1), + ); let mut ir_peri = ir::Peripheral { name: name.clone(), array: None, @@ -257,13 +309,38 @@ pub fn gen(options: Options) { peripheral_pins_table.push(row); } + for dma_request in &p.dma_requests { + let mut row = Vec::new(); + row.push(name.clone()); + row.push(dma_request.0.clone()); + row.push(dma_request.1.to_string()); + dma_requests_table.push(row); + } + + for (event, dma_channels) in &p.dma_channels { + for channel in dma_channels.iter() { + let mut row = Vec::new(); + row.push(name.clone()); + row.push(bi.module.clone()); + row.push(bi.block.clone()); + row.push(event.clone()); + row.push(channel.channel.clone()); + row.push(core.dma_channels[&channel.channel].dma.clone()); + row.push(core.dma_channels[&channel.channel].channel.to_string()); + if let Some(request) = channel.request { + row.push(request.to_string()); + } + peripheral_dma_channels_table.push(row); + } + } + let mut peripheral_row = Vec::new(); peripheral_row.push(bi.module.clone()); peripheral_row.push(name.clone()); peripherals_table.push(peripheral_row); if let Some(old_version) = - peripheral_versions.insert(bi.module.clone(), bi.version.clone()) + peripheral_versions.insert(bi.module.clone(), bi.version.clone()) { if old_version != bi.version { panic!( @@ -354,13 +431,13 @@ pub fn gen(options: Options) { ]); } (None, Some(_)) => { - println!("Unable to find enable register for {}", name) + print!("Unable to find enable register for {}", name) } (Some(_), None) => { - println!("Unable to find reset register for {}", name) + print!("Unable to find reset register for {}", name) } (None, None) => { - println!("Unable to find enable and reset register for {}", name) + print!("Unable to find enable and reset register for {}", name) } } } @@ -377,7 +454,17 @@ pub fn gen(options: Options) { value: num, }); - interrupt_table.push(vec![name.to_ascii_uppercase()]); + let name = name.to_ascii_uppercase(); + + interrupt_table.push(vec![name.clone()]); + + if name.starts_with("DMA") || name.contains("_DMA") { + interrupt_table.push(vec!["DMA".to_string(), name.clone()]); + } + + if name.contains("EXTI") { + interrupt_table.push(vec!["EXTI".to_string(), name.clone()]); + } } ir.devices.insert("".to_string(), dev); @@ -385,11 +472,8 @@ pub fn gen(options: Options) { let mut extra = format!( "pub fn GPIO(n: usize) -> gpio::Gpio {{ gpio::Gpio(({} + {}*n) as _) - }} - pub fn DMA(n: usize) -> dma::Dma {{ - dma::Dma(({} + {}*n) as _) }}", - gpio_base, gpio_stride, dma_base, dma_stride, + gpio_base, gpio_stride, ); let peripheral_version_table = peripheral_versions @@ -402,7 +486,11 @@ pub fn gen(options: Options) { make_table(&mut extra, "peripherals", &peripherals_table); make_table(&mut extra, "peripheral_versions", &peripheral_version_table); make_table(&mut extra, "peripheral_pins", &peripheral_pins_table); + make_table(&mut extra, "peripheral_dma_channels", &peripheral_dma_channels_table); make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); + make_table(&mut extra, "dma_channels", &dma_channels_table); + make_table(&mut extra, "dma_requests", &dma_requests_table); + make_peripheral_counts(&mut extra, &peripheral_counts); for (module, version) in peripheral_versions { all_peripheral_versions.insert((module.clone(), version.clone())); @@ -411,7 +499,7 @@ pub fn gen(options: Options) { "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n", module, version, module ) - .unwrap(); + .unwrap(); } // Cleanups! @@ -449,7 +537,7 @@ pub fn gen(options: Options) { "PROVIDE({} = DefaultHandler);\n", name.to_ascii_uppercase() ) - .unwrap(); + .unwrap(); } File::create(chip_dir.join("device.x")) @@ -477,7 +565,7 @@ pub fn gen(options: Options) { transform::NameKind::Enum => format!("vals::{}", s), _ => s.to_string(), }) - .unwrap(); + .unwrap(); transform::sort::Sort {}.run(&mut ir).unwrap(); transform::Sanitize {}.run(&mut ir).unwrap(); @@ -488,7 +576,7 @@ pub fn gen(options: Options) { .join("src/peripherals") .join(format!("{}_{}.rs", module, version)), ) - .unwrap(); + .unwrap(); let data = items.to_string().replace("] ", "]\n"); // Remove inner attributes like #![no_std] @@ -511,14 +599,14 @@ pub fn gen(options: Options) { "#[cfg_attr(feature=\"{}_{}\", path = \"chips/{}_{}/pac.rs\")]", x, c, x, c ) - .unwrap(); + .unwrap(); } else { write!( &mut paths, "#[cfg_attr(feature=\"{}\", path = \"chips/{}/pac.rs\")]", x, x ) - .unwrap(); + .unwrap(); } } let mut contents: Vec = Vec::new(); @@ -541,7 +629,7 @@ pub fn gen(options: Options) { out_dir.join("src").join("common.rs"), generate::COMMON_MODULE, ) - .unwrap(); + .unwrap(); // Generate Cargo.toml const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES";