diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4e37c94f..058d5012 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -28,6 +28,7 @@ stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt" vcell = { version = "0.1.3", optional = true } cfg-if = "1.0.0" +paste = "1.0.5" [build-dependencies] stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false } diff --git a/embassy-stm32/gen.py b/embassy-stm32/gen.py index 386c5ce1..01c77871 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 00000000..e85ade5d --- /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 773cdc8b..a8a22ce8 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,67 +1,22 @@ #![macro_use] -#[cfg_attr(dma_v1, path = "v1.rs")] +//#[cfg_attr(dma_v1, path = "v1.rs")] #[cfg_attr(dma_v2, path = "v2.rs")] 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 {} - -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 - } - } - }; -} - -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); - }; -); +pub trait ReadDma {} diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index e7bd6913..6c6bbde2 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; @@ -41,9 +46,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); @@ -82,106 +86,169 @@ pub(crate) async unsafe fn transfer_m2p( } 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::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(); + } } } - } + }; } } -#[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) } + } + } + }; +} + +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) => { + unsafe fn $irq () { + on_irq() + } + }; +} + +#[cfg(usart)] +use crate::usart; +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/lib.rs b/embassy-stm32/src/lib.rs index 9ba7bbe4..813c58cd 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -22,6 +22,8 @@ pub mod rcc; // Sometimes-present hardware #[cfg(adc)] pub mod adc; +#[cfg(bdma)] +pub mod bdma; #[cfg(timer)] pub mod clock; #[cfg(dac)] diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index adf48c32..24793b6b 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,7 +1,7 @@ #![macro_use] #[cfg_attr(usart_v1, path = "v1.rs")] -#[cfg_attr(usart_v2, path = "v2.rs")] +//#[cfg_attr(usart_v2, path = "v2.rs")] mod _version; use crate::peripherals; pub use _version::*; @@ -25,6 +25,7 @@ pub enum Error { pub(crate) mod sealed { use super::*; + use crate::dma::WriteDma; pub trait Instance { fn regs(&self) -> Usart; @@ -44,7 +45,12 @@ pub(crate) mod sealed { pub trait CkPin: Pin { fn af_num(&self) -> u8; } + + pub trait RxDma {} + + pub trait TxDma: WriteDma {} } + pub trait Instance: sealed::Instance {} pub trait RxPin: sealed::RxPin {} pub trait TxPin: sealed::TxPin {} @@ -52,6 +58,9 @@ pub trait CtsPin: sealed::CtsPin {} pub trait RtsPin: sealed::RtsPin {} pub trait CkPin: sealed::CkPin {} +pub trait RxDma: sealed::RxDma {} +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 1ec1f5b3..a721e89a 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -104,11 +104,16 @@ impl<'d, T: Instance> Uart<'d, T> { #[cfg(dma_v2)] pub async fn write_dma( &mut self, - ch: &mut impl crate::dma::Channel, + //ch: &mut impl crate::dma::Channel, + ch: &mut impl TxDma, buffer: &[u8], ) -> Result<(), Error> { - let ch_func = 4; // USART3_TX let r = self.inner.regs(); + let dst = r.dr().ptr() as *mut u8; + ch.transfer(buffer, dst).await; + Ok(()) + /* + let ch_func = 4; // USART3_TX unsafe { r.cr3().write(|w| { @@ -121,6 +126,7 @@ impl<'d, T: Instance> Uart<'d, T> { } Ok(()) + */ } pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { diff --git a/stm32-metapac/Cargo.toml b/stm32-metapac/Cargo.toml index bed772c8..79f1c374 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 408865e3..00e122e9 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -48,7 +48,7 @@ pub struct Peripheral { #[serde(default)] pub pins: Vec, #[serde(default)] - pub dma_channels: HashMap>, + pub dma_channels: HashMap>, #[serde(default)] pub dma_requests: HashMap, } @@ -66,6 +66,12 @@ pub struct DmaChannel { 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, @@ -121,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, @@ -234,6 +255,7 @@ pub fn gen(options: Options) { 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 @@ -248,12 +270,20 @@ pub fn gen(options: Options) { 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.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, @@ -291,12 +321,15 @@ pub fn gen(options: Options) { 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(bi.module.clone()); + row.push(bi.block.clone()); row.push(event.clone()); - row.push( channel.clone() ); - row.push( core.dma_channels[channel].dma.clone() ); - row.push( core.dma_channels[channel].channel.to_string() ); + 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); } } @@ -421,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); @@ -429,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 @@ -450,6 +490,7 @@ 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, "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()));