aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-03-25 20:33:47 +0100
committerDario Nieuwenhuis <[email protected]>2025-03-25 20:49:09 +0100
commitf007b53db3b850e1186f9cde26160951b14ba2e7 (patch)
tree0a28649725ba7f9a37984bf62e121050aee322d5
parent17cce79807ff978270b96ba081a4ee2ed5604dcd (diff)
stm32/dac: dedup pin and DMA traits, demacrofify.
-rw-r--r--embassy-stm32/build.rs17
-rw-r--r--embassy-stm32/src/dac/mod.rs216
2 files changed, 113 insertions, 120 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index eb0437bc2..8ca79eadf 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1151,6 +1151,8 @@ fn main() {
1151 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)), 1151 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
1152 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)), 1152 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
1153 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)), 1153 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
1154 (("dac", "OUT1"), quote!(crate::dac::DacPin<Ch1>)),
1155 (("dac", "OUT2"), quote!(crate::dac::DacPin<Ch2>)),
1154 ].into(); 1156 ].into();
1155 1157
1156 for p in METADATA.peripherals { 1158 for p in METADATA.peripherals {
@@ -1250,17 +1252,6 @@ fn main() {
1250 } 1252 }
1251 } 1253 }
1252 1254
1253 // DAC is special
1254 if regs.kind == "dac" {
1255 let peri = format_ident!("{}", p.name);
1256 let pin_name = format_ident!("{}", pin.pin);
1257 let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap();
1258
1259 g.extend(quote! {
1260 impl_dac_pin!( #peri, #pin_name, #ch);
1261 })
1262 }
1263
1264 if regs.kind == "spdifrx" { 1255 if regs.kind == "spdifrx" {
1265 let peri = format_ident!("{}", p.name); 1256 let peri = format_ident!("{}", p.name);
1266 let pin_name = format_ident!("{}", pin.pin); 1257 let pin_name = format_ident!("{}", pin.pin);
@@ -1304,8 +1295,8 @@ fn main() {
1304 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 1295 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
1305 (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)), 1296 (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)),
1306 (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)), 1297 (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)),
1307 (("dac", "CH1"), quote!(crate::dac::DacDma1)), 1298 (("dac", "CH1"), quote!(crate::dac::Dma<Ch1>)),
1308 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1299 (("dac", "CH2"), quote!(crate::dac::Dma<Ch2>)),
1309 (("timer", "UP"), quote!(crate::timer::UpDma)), 1300 (("timer", "UP"), quote!(crate::timer::UpDma)),
1310 (("hash", "IN"), quote!(crate::hash::Dma)), 1301 (("hash", "IN"), quote!(crate::hash::Dma)),
1311 (("cryp", "IN"), quote!(crate::cryp::DmaIn)), 1302 (("cryp", "IN"), quote!(crate::cryp::DmaIn)),
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 8bba5ded0..4406f2960 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -100,20 +100,18 @@ pub enum ValueArray<'a> {
100/// 100///
101/// If you want to use both channels, either together or independently, 101/// If you want to use both channels, either together or independently,
102/// create a [`Dac`] first and use it to access each channel. 102/// create a [`Dac`] first and use it to access each channel.
103pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { 103pub struct DacChannel<'d, T: Instance, C: Channel, DMA = NoDma> {
104 phantom: PhantomData<&'d mut T>, 104 phantom: PhantomData<&'d mut (T, C)>,
105 #[allow(unused)] 105 #[allow(unused)]
106 dma: PeripheralRef<'d, DMA>, 106 dma: PeripheralRef<'d, DMA>,
107} 107}
108 108
109/// DAC channel 1 type alias. 109/// DAC channel 1 type alias.
110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; 110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch1, DMA>;
111/// DAC channel 2 type alias. 111/// DAC channel 2 type alias.
112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; 112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch2, DMA>;
113
114impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
115 const IDX: usize = (N - 1) as usize;
116 113
114impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
117 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. 115 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
118 /// 116 ///
119 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. 117 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
@@ -127,7 +125,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
127 pub fn new( 125 pub fn new(
128 _peri: impl Peripheral<P = T> + 'd, 126 _peri: impl Peripheral<P = T> + 'd,
129 dma: impl Peripheral<P = DMA> + 'd, 127 dma: impl Peripheral<P = DMA> + 'd,
130 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd, 128 pin: impl Peripheral<P = impl DacPin<T, C> + crate::gpio::Pin> + 'd,
131 ) -> Self { 129 ) -> Self {
132 into_ref!(dma, pin); 130 into_ref!(dma, pin);
133 pin.set_as_analog(); 131 pin.set_as_analog();
@@ -173,7 +171,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
173 pub fn set_enable(&mut self, on: bool) { 171 pub fn set_enable(&mut self, on: bool) {
174 critical_section::with(|_| { 172 critical_section::with(|_| {
175 T::regs().cr().modify(|reg| { 173 T::regs().cr().modify(|reg| {
176 reg.set_en(Self::IDX, on); 174 reg.set_en(C::IDX, on);
177 }); 175 });
178 }); 176 });
179 } 177 }
@@ -194,8 +192,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
194 pub fn set_trigger(&mut self, source: TriggerSel) { 192 pub fn set_trigger(&mut self, source: TriggerSel) {
195 critical_section::with(|_| { 193 critical_section::with(|_| {
196 T::regs().cr().modify(|reg| { 194 T::regs().cr().modify(|reg| {
197 reg.set_en(Self::IDX, false); 195 reg.set_en(C::IDX, false);
198 reg.set_tsel(Self::IDX, source as u8); 196 reg.set_tsel(C::IDX, source as u8);
199 }); 197 });
200 }); 198 });
201 } 199 }
@@ -204,7 +202,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
204 pub fn set_triggering(&mut self, on: bool) { 202 pub fn set_triggering(&mut self, on: bool) {
205 critical_section::with(|_| { 203 critical_section::with(|_| {
206 T::regs().cr().modify(|reg| { 204 T::regs().cr().modify(|reg| {
207 reg.set_ten(Self::IDX, on); 205 reg.set_ten(C::IDX, on);
208 }); 206 });
209 }); 207 });
210 } 208 }
@@ -212,7 +210,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
212 /// Software trigger this channel. 210 /// Software trigger this channel.
213 pub fn trigger(&mut self) { 211 pub fn trigger(&mut self) {
214 T::regs().swtrigr().write(|reg| { 212 T::regs().swtrigr().write(|reg| {
215 reg.set_swtrig(Self::IDX, true); 213 reg.set_swtrig(C::IDX, true);
216 }); 214 });
217 } 215 }
218 216
@@ -223,10 +221,10 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
223 pub fn set_mode(&mut self, mode: Mode) { 221 pub fn set_mode(&mut self, mode: Mode) {
224 critical_section::with(|_| { 222 critical_section::with(|_| {
225 T::regs().cr().modify(|reg| { 223 T::regs().cr().modify(|reg| {
226 reg.set_en(Self::IDX, false); 224 reg.set_en(C::IDX, false);
227 }); 225 });
228 T::regs().mcr().modify(|reg| { 226 T::regs().mcr().modify(|reg| {
229 reg.set_mode(Self::IDX, mode.mode()); 227 reg.set_mode(C::IDX, mode.mode());
230 }); 228 });
231 }); 229 });
232 } 230 }
@@ -237,15 +235,15 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
237 /// it will be output after the next trigger. 235 /// it will be output after the next trigger.
238 pub fn set(&mut self, value: Value) { 236 pub fn set(&mut self, value: Value) {
239 match value { 237 match value {
240 Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)), 238 Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)),
241 Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)), 239 Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)),
242 Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)), 240 Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)),
243 } 241 }
244 } 242 }
245 243
246 /// Read the current output value of the DAC. 244 /// Read the current output value of the DAC.
247 pub fn read(&self) -> u16 { 245 pub fn read(&self) -> u16 {
248 T::regs().dor(Self::IDX).read().dor() 246 T::regs().dor(C::IDX).read().dor()
249 } 247 }
250 248
251 /// Set HFSEL as appropriate for the current peripheral clock frequency. 249 /// Set HFSEL as appropriate for the current peripheral clock frequency.
@@ -277,84 +275,75 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
277 }); 275 });
278 } 276 }
279 } 277 }
280}
281 278
282macro_rules! impl_dma_methods { 279 /// Write `data` to this channel via DMA.
283 ($n:literal, $trait:ident) => { 280 ///
284 impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA> 281 /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
285 where 282 /// flag can be set. This configures a circular DMA transfer that continually outputs
286 DMA: $trait<T>, 283 /// `data`. Note that for performance reasons in circular mode the transfer-complete
287 { 284 /// interrupt is disabled.
288 /// Write `data` to this channel via DMA. 285 #[cfg(not(gpdma))]
289 /// 286 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool)
290 /// To prevent delays or glitches when outputing a periodic waveform, the `circular` 287 where
291 /// flag can be set. This configures a circular DMA transfer that continually outputs 288 DMA: Dma<T, C>,
292 /// `data`. Note that for performance reasons in circular mode the transfer-complete 289 {
293 /// interrupt is disabled. 290 // Enable DAC and DMA
294 #[cfg(not(gpdma))] 291 T::regs().cr().modify(|w| {
295 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { 292 w.set_en(C::IDX, true);
296 // Enable DAC and DMA 293 w.set_dmaen(C::IDX, true);
297 T::regs().cr().modify(|w| { 294 });
298 w.set_en(Self::IDX, true);
299 w.set_dmaen(Self::IDX, true);
300 });
301 295
302 let tx_request = self.dma.request(); 296 let tx_request = self.dma.request();
303 let dma_channel = &mut self.dma; 297 let dma_channel = &mut self.dma;
304 298
305 let tx_options = crate::dma::TransferOptions { 299 let tx_options = crate::dma::TransferOptions {
306 circular, 300 circular,
307 half_transfer_ir: false, 301 half_transfer_ir: false,
308 complete_transfer_ir: !circular, 302 complete_transfer_ir: !circular,
309 ..Default::default() 303 ..Default::default()
310 }; 304 };
311 305
312 // Initiate the correct type of DMA transfer depending on what data is passed 306 // Initiate the correct type of DMA transfer depending on what data is passed
313 let tx_f = match data { 307 let tx_f = match data {
314 ValueArray::Bit8(buf) => unsafe { 308 ValueArray::Bit8(buf) => unsafe {
315 crate::dma::Transfer::new_write( 309 crate::dma::Transfer::new_write(
316 dma_channel, 310 dma_channel,
317 tx_request, 311 tx_request,
318 buf, 312 buf,
319 T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8, 313 T::regs().dhr8r(C::IDX).as_ptr() as *mut u8,
320 tx_options, 314 tx_options,
321 ) 315 )
322 }, 316 },
323 ValueArray::Bit12Left(buf) => unsafe { 317 ValueArray::Bit12Left(buf) => unsafe {
324 crate::dma::Transfer::new_write( 318 crate::dma::Transfer::new_write(
325 dma_channel, 319 dma_channel,
326 tx_request, 320 tx_request,
327 buf, 321 buf,
328 T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16, 322 T::regs().dhr12l(C::IDX).as_ptr() as *mut u16,
329 tx_options, 323 tx_options,
330 ) 324 )
331 }, 325 },
332 ValueArray::Bit12Right(buf) => unsafe { 326 ValueArray::Bit12Right(buf) => unsafe {
333 crate::dma::Transfer::new_write( 327 crate::dma::Transfer::new_write(
334 dma_channel, 328 dma_channel,
335 tx_request, 329 tx_request,
336 buf, 330 buf,
337 T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16, 331 T::regs().dhr12r(C::IDX).as_ptr() as *mut u16,
338 tx_options, 332 tx_options,
339 ) 333 )
340 }, 334 },
341 }; 335 };
342
343 tx_f.await;
344
345 T::regs().cr().modify(|w| {
346 w.set_en(Self::IDX, false);
347 w.set_dmaen(Self::IDX, false);
348 });
349 }
350 }
351 };
352}
353 336
354impl_dma_methods!(1, DacDma1); 337 tx_f.await;
355impl_dma_methods!(2, DacDma2);
356 338
357impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { 339 T::regs().cr().modify(|w| {
340 w.set_en(C::IDX, false);
341 w.set_dmaen(C::IDX, false);
342 });
343 }
344}
345
346impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> {
358 fn drop(&mut self) { 347 fn drop(&mut self) {
359 rcc::disable::<T>(); 348 rcc::disable::<T>();
360 } 349 }
@@ -371,8 +360,8 @@ impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
371/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); 360/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split();
372/// ``` 361/// ```
373pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { 362pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> {
374 ch1: DacChannel<'d, T, 1, DMACh1>, 363 ch1: DacChannel<'d, T, Ch1, DMACh1>,
375 ch2: DacChannel<'d, T, 2, DMACh2>, 364 ch2: DacChannel<'d, T, Ch2, DMACh2>,
376} 365}
377 366
378impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { 367impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
@@ -392,8 +381,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
392 _peri: impl Peripheral<P = T> + 'd, 381 _peri: impl Peripheral<P = T> + 'd,
393 dma_ch1: impl Peripheral<P = DMACh1> + 'd, 382 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
394 dma_ch2: impl Peripheral<P = DMACh2> + 'd, 383 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
395 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd, 384 pin_ch1: impl Peripheral<P = impl DacPin<T, Ch1> + crate::gpio::Pin> + 'd,
396 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd, 385 pin_ch2: impl Peripheral<P = impl DacPin<T, Ch2> + crate::gpio::Pin> + 'd,
397 ) -> Self { 386 ) -> Self {
398 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); 387 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
399 pin_ch1.set_as_analog(); 388 pin_ch1.set_as_analog();
@@ -514,11 +503,30 @@ trait SealedInstance {
514/// DAC instance. 503/// DAC instance.
515#[allow(private_bounds)] 504#[allow(private_bounds)]
516pub trait Instance: SealedInstance + RccPeripheral + 'static {} 505pub trait Instance: SealedInstance + RccPeripheral + 'static {}
517dma_trait!(DacDma1, Instance);
518dma_trait!(DacDma2, Instance);
519 506
520/// Marks a pin that can be used with the DAC 507/// Channel 1 marker type.
521pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} 508pub enum Ch1 {}
509/// Channel 2 marker type.
510pub enum Ch2 {}
511
512trait SealedChannel {
513 const IDX: usize;
514}
515/// DAC channel trait.
516#[allow(private_bounds)]
517pub trait Channel: SealedChannel {}
518
519impl SealedChannel for Ch1 {
520 const IDX: usize = 0;
521}
522impl SealedChannel for Ch2 {
523 const IDX: usize = 1;
524}
525impl Channel for Ch1 {}
526impl Channel for Ch2 {}
527
528dma_trait!(Dma, Instance, Channel);
529pin_trait!(DacPin, Instance, Channel);
522 530
523foreach_peripheral!( 531foreach_peripheral!(
524 (dac, $inst:ident) => { 532 (dac, $inst:ident) => {
@@ -531,9 +539,3 @@ foreach_peripheral!(
531 impl crate::dac::Instance for peripherals::$inst {} 539 impl crate::dac::Instance for peripherals::$inst {}
532 }; 540 };
533); 541);
534
535macro_rules! impl_dac_pin {
536 ($inst:ident, $pin:ident, $ch:expr) => {
537 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
538 };
539}