fix issues when DAC2 present, add additional options to DMA (NOT YET WORKING with STM32H7A3ZI)
This commit is contained in:
		| @@ -699,8 +699,8 @@ fn main() { | ||||
|         // SDMMCv1 uses the same channel for both directions, so just implement for RX | ||||
|         (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), | ||||
|         (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), | ||||
|         (("dac", "CH1"), quote!(crate::dac::Dma)), | ||||
|         (("dac", "CH2"), quote!(crate::dac::Dma)), | ||||
|         (("dac", "CH1"), quote!(crate::dac::DmaCh1)), | ||||
|         (("dac", "CH2"), quote!(crate::dac::DmaCh2)), | ||||
|     ] | ||||
|     .into(); | ||||
|  | ||||
|   | ||||
| @@ -171,13 +171,6 @@ pub trait DacChannel<T: Instance, Tx> { | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Write `data` to the DAC channel via DMA. | ||||
|     /// | ||||
|     /// `circular` sets the DMA to circular mode. | ||||
|     async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> | ||||
|     where | ||||
|         Tx: Dma<T>; | ||||
| } | ||||
|  | ||||
| /// Hold two DAC channels | ||||
| @@ -244,6 +237,81 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Write `data` to the DAC CH1 via DMA. | ||||
|     /// | ||||
|     /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. | ||||
|     /// This will configure a circular DMA transfer that periodically outputs the `data`. | ||||
|     /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. | ||||
|     /// | ||||
|     /// **Important:** Channel 1 has to be configured for the DAC instance! | ||||
|     pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> | ||||
|     where | ||||
|         Tx: DmaCh1<T>, | ||||
|     { | ||||
|         let channel = Channel::Ch1.index(); | ||||
|         debug!("Writing to channel {}", channel); | ||||
|  | ||||
|         // Enable DAC and DMA | ||||
|         T::regs().cr().modify(|w| { | ||||
|             w.set_en(channel, true); | ||||
|             w.set_dmaen(channel, true); | ||||
|         }); | ||||
|  | ||||
|         let tx_request = self.dma.request(); | ||||
|         let dma_channel = &self.dma; | ||||
|  | ||||
|         let tx_options = TransferOptions { | ||||
|             circular, | ||||
|             half_transfer_ir: false, | ||||
|             complete_transfer_ir: !circular, | ||||
|             ..Default::default() | ||||
|         }; | ||||
|  | ||||
|         // Initiate the correct type of DMA transfer depending on what data is passed | ||||
|         let tx_f = match data { | ||||
|             ValueArray::Bit8(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr8r(channel).as_ptr() as *mut u8, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|             ValueArray::Bit12Left(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr12l(channel).as_ptr() as *mut u16, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|             ValueArray::Bit12Right(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr12r(channel).as_ptr() as *mut u16, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|         }; | ||||
|  | ||||
|         tx_f.await; | ||||
|  | ||||
|         // finish dma | ||||
|         // TODO: Do we need to check any status registers here? | ||||
|         T::regs().cr().modify(|w| { | ||||
|             // Disable the DAC peripheral | ||||
|             w.set_en(channel, false); | ||||
|             // Disable the DMA. TODO: Is this necessary? | ||||
|             w.set_dmaen(channel, false); | ||||
|         }); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { | ||||
| @@ -279,6 +347,81 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Write `data` to the DAC CH2 via DMA. | ||||
|     /// | ||||
|     /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. | ||||
|     /// This will configure a circular DMA transfer that periodically outputs the `data`. | ||||
|     /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. | ||||
|     /// | ||||
|     /// **Important:** Channel 2 has to be configured for the DAC instance! | ||||
|     pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> | ||||
|     where | ||||
|         Tx: DmaCh2<T>, | ||||
|     { | ||||
|         let channel = Channel::Ch2.index(); | ||||
|         debug!("Writing to channel {}", channel); | ||||
|  | ||||
|         // Enable DAC and DMA | ||||
|         T::regs().cr().modify(|w| { | ||||
|             w.set_en(channel, true); | ||||
|             w.set_dmaen(channel, true); | ||||
|         }); | ||||
|  | ||||
|         let tx_request = self.dma.request(); | ||||
|         let dma_channel = &self.dma; | ||||
|  | ||||
|         let tx_options = TransferOptions { | ||||
|             circular, | ||||
|             half_transfer_ir: false, | ||||
|             complete_transfer_ir: !circular, | ||||
|             ..Default::default() | ||||
|         }; | ||||
|  | ||||
|         // Initiate the correct type of DMA transfer depending on what data is passed | ||||
|         let tx_f = match data { | ||||
|             ValueArray::Bit8(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr8r(channel).as_ptr() as *mut u8, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|             ValueArray::Bit12Left(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr12l(channel).as_ptr() as *mut u16, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|             ValueArray::Bit12Right(buf) => unsafe { | ||||
|                 Transfer::new_write( | ||||
|                     dma_channel, | ||||
|                     tx_request, | ||||
|                     buf, | ||||
|                     T::regs().dhr12r(channel).as_ptr() as *mut u16, | ||||
|                     tx_options, | ||||
|                 ) | ||||
|             }, | ||||
|         }; | ||||
|  | ||||
|         tx_f.await; | ||||
|  | ||||
|         // finish dma | ||||
|         // TODO: Do we need to check any status registers here? | ||||
|         T::regs().cr().modify(|w| { | ||||
|             // Disable the DAC peripheral | ||||
|             w.set_en(channel, false); | ||||
|             // Disable the DMA. TODO: Is this necessary? | ||||
|             w.set_dmaen(channel, false); | ||||
|         }); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { | ||||
| @@ -350,117 +493,10 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { | ||||
|  | ||||
| impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> { | ||||
|     const CHANNEL: Channel = Channel::Ch1; | ||||
|  | ||||
|     /// Write `data` to the DAC CH1 via DMA. | ||||
|     /// | ||||
|     /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. | ||||
|     /// This will configure a circular DMA transfer that periodically outputs the `data`. | ||||
|     /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. | ||||
|     /// | ||||
|     /// **Important:** Channel 1 has to be configured for the DAC instance! | ||||
|     async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> | ||||
|     where | ||||
|         Tx: Dma<T>, | ||||
|     { | ||||
|         write_inner(Self::CHANNEL, &self.dma, data, circular).await | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> { | ||||
|     const CHANNEL: Channel = Channel::Ch2; | ||||
|  | ||||
|     /// Write `data` to the DAC CH2 via DMA. | ||||
|     /// | ||||
|     /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. | ||||
|     /// This will configure a circular DMA transfer that periodically outputs the `data`. | ||||
|     /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. | ||||
|     /// | ||||
|     /// **Important:** Channel 2 has to be configured for the DAC instance! | ||||
|     async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> | ||||
|     where | ||||
|         Tx: Dma<T>, | ||||
|     { | ||||
|         write_inner(Self::CHANNEL, &self.dma, data, circular).await | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Shared utility function to perform the actual DMA config and write. | ||||
| async fn write_inner<T: Instance, Tx>( | ||||
|     ch: Channel, | ||||
|     dma: &PeripheralRef<'_, Tx>, | ||||
|     data: ValueArray<'_>, | ||||
|     circular: bool, | ||||
| ) -> Result<(), Error> | ||||
| where | ||||
|     Tx: Dma<T>, | ||||
| { | ||||
|     let channel = ch.index(); | ||||
|     debug!("Writing to channel {}", channel); | ||||
|  | ||||
|     // Enable DAC and DMA | ||||
|     T::regs().cr().modify(|w| { | ||||
|         w.set_en(channel, true); | ||||
|         w.set_dmaen(channel, true); | ||||
|     }); | ||||
|  | ||||
|     let tx_request = dma.request(); | ||||
|     let dma_channel = dma; | ||||
|  | ||||
|     // Initiate the correct type of DMA transfer depending on what data is passed | ||||
|     let tx_f = match data { | ||||
|         ValueArray::Bit8(buf) => unsafe { | ||||
|             Transfer::new_write( | ||||
|                 dma_channel, | ||||
|                 tx_request, | ||||
|                 buf, | ||||
|                 T::regs().dhr8r(channel).as_ptr() as *mut u8, | ||||
|                 TransferOptions { | ||||
|                     circular, | ||||
|                     half_transfer_ir: false, | ||||
|                     complete_transfer_ir: !circular, | ||||
|                 }, | ||||
|             ) | ||||
|         }, | ||||
|         ValueArray::Bit12Left(buf) => unsafe { | ||||
|             Transfer::new_write( | ||||
|                 dma_channel, | ||||
|                 tx_request, | ||||
|                 buf, | ||||
|                 T::regs().dhr12l(channel).as_ptr() as *mut u16, | ||||
|                 TransferOptions { | ||||
|                     circular, | ||||
|                     half_transfer_ir: false, | ||||
|                     complete_transfer_ir: !circular, | ||||
|                 }, | ||||
|             ) | ||||
|         }, | ||||
|         ValueArray::Bit12Right(buf) => unsafe { | ||||
|             Transfer::new_write( | ||||
|                 dma_channel, | ||||
|                 tx_request, | ||||
|                 buf, | ||||
|                 T::regs().dhr12r(channel).as_ptr() as *mut u16, | ||||
|                 TransferOptions { | ||||
|                     circular, | ||||
|                     half_transfer_ir: false, | ||||
|                     complete_transfer_ir: !circular, | ||||
|                 }, | ||||
|             ) | ||||
|         }, | ||||
|     }; | ||||
|  | ||||
|     tx_f.await; | ||||
|  | ||||
|     // finish dma | ||||
|     // TODO: Do we need to check any status registers here? | ||||
|     T::regs().cr().modify(|w| { | ||||
|         // Disable the DAC peripheral | ||||
|         w.set_en(channel, false); | ||||
|         // Disable the DMA. TODO: Is this necessary? | ||||
|         w.set_dmaen(channel, false); | ||||
|     }); | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
| @@ -470,7 +506,8 @@ pub(crate) mod sealed { | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | ||||
| dma_trait!(Dma, Instance); | ||||
| dma_trait!(DmaCh1, Instance); | ||||
| dma_trait!(DmaCh2, Instance); | ||||
|  | ||||
| /// Marks a pin that can be used with the DAC | ||||
| pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | ||||
|   | ||||
| @@ -29,6 +29,12 @@ pub struct TransferOptions { | ||||
|     pub flow_ctrl: FlowControl, | ||||
|     /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. | ||||
|     pub fifo_threshold: Option<FifoThreshold>, | ||||
|     /// Enable circular DMA | ||||
|     pub circular: bool, | ||||
|     /// Enable half transfer interrupt | ||||
|     pub half_transfer_ir: bool, | ||||
|     /// Enable transfer complete interrupt | ||||
|     pub complete_transfer_ir: bool, | ||||
| } | ||||
|  | ||||
| impl Default for TransferOptions { | ||||
| @@ -38,6 +44,9 @@ impl Default for TransferOptions { | ||||
|             mburst: Burst::Single, | ||||
|             flow_ctrl: FlowControl::Dma, | ||||
|             fifo_threshold: None, | ||||
|             circular: false, | ||||
|             half_transfer_ir: false, | ||||
|             complete_transfer_ir: true, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -366,13 +375,20 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|             }); | ||||
|             w.set_pinc(vals::Inc::FIXED); | ||||
|             w.set_teie(true); | ||||
|             w.set_tcie(true); | ||||
|             w.set_tcie(options.complete_transfer_ir); | ||||
|             w.set_htie(options.half_transfer_ir); | ||||
|             #[cfg(dma_v1)] | ||||
|             w.set_trbuff(true); | ||||
|  | ||||
|             #[cfg(dma_v2)] | ||||
|             w.set_chsel(_request); | ||||
|  | ||||
|             if options.circular { | ||||
|                 w.set_circ(vals::Circ::ENABLED); | ||||
|                 debug!("Setting circular mode"); | ||||
|             } else { | ||||
|                 w.set_circ(vals::Circ::DISABLED); | ||||
|             } | ||||
|             w.set_pburst(options.pburst.into()); | ||||
|             w.set_mburst(options.mburst.into()); | ||||
|             w.set_pfctrl(options.flow_ctrl.into()); | ||||
| @@ -404,8 +420,14 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         //let ch = self.channel.regs().st(self.channel.num()); | ||||
|         //ch.cr().read().en() | ||||
|  | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         ch.cr().read().en() | ||||
|         let en = ch.cr().read().en(); | ||||
|         let circular = ch.cr().read().circ() == vals::Circ::ENABLED; | ||||
|         let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; | ||||
|         en && (circular || !tcif) | ||||
|     } | ||||
|  | ||||
|     /// Gets the total remaining transfers for the channel | ||||
|   | ||||
		Reference in New Issue
	
	Block a user