fix issues when DAC2 present, add additional options to DMA (NOT YET WORKING with STM32H7A3ZI)
This commit is contained in:
parent
8cafaa1f3c
commit
e7bc84dda8
@ -699,8 +699,8 @@ fn main() {
|
|||||||
// SDMMCv1 uses the same channel for both directions, so just implement for RX
|
// SDMMCv1 uses the same channel for both directions, so just implement for RX
|
||||||
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
|
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
|
||||||
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
|
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
|
||||||
(("dac", "CH1"), quote!(crate::dac::Dma)),
|
(("dac", "CH1"), quote!(crate::dac::DmaCh1)),
|
||||||
(("dac", "CH2"), quote!(crate::dac::Dma)),
|
(("dac", "CH2"), quote!(crate::dac::DmaCh2)),
|
||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -171,13 +171,6 @@ pub trait DacChannel<T: Instance, Tx> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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
|
/// Hold two DAC channels
|
||||||
@ -244,6 +237,81 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
|
|||||||
});
|
});
|
||||||
Ok(())
|
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> {
|
impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
|
||||||
@ -279,6 +347,81 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
|
|||||||
});
|
});
|
||||||
Ok(())
|
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> {
|
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> {
|
impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
|
||||||
const CHANNEL: Channel = Channel::Ch1;
|
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> {
|
impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
|
||||||
const CHANNEL: Channel = Channel::Ch2;
|
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 {
|
pub(crate) mod sealed {
|
||||||
@ -470,7 +506,8 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
|
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
|
/// Marks a pin that can be used with the DAC
|
||||||
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||||
|
@ -29,6 +29,12 @@ pub struct TransferOptions {
|
|||||||
pub flow_ctrl: FlowControl,
|
pub flow_ctrl: FlowControl,
|
||||||
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
|
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
|
||||||
pub fifo_threshold: Option<FifoThreshold>,
|
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 {
|
impl Default for TransferOptions {
|
||||||
@ -38,6 +44,9 @@ impl Default for TransferOptions {
|
|||||||
mburst: Burst::Single,
|
mburst: Burst::Single,
|
||||||
flow_ctrl: FlowControl::Dma,
|
flow_ctrl: FlowControl::Dma,
|
||||||
fifo_threshold: None,
|
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_pinc(vals::Inc::FIXED);
|
||||||
w.set_teie(true);
|
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)]
|
#[cfg(dma_v1)]
|
||||||
w.set_trbuff(true);
|
w.set_trbuff(true);
|
||||||
|
|
||||||
#[cfg(dma_v2)]
|
#[cfg(dma_v2)]
|
||||||
w.set_chsel(_request);
|
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_pburst(options.pburst.into());
|
||||||
w.set_mburst(options.mburst.into());
|
w.set_mburst(options.mburst.into());
|
||||||
w.set_pfctrl(options.flow_ctrl.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 {
|
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());
|
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
|
/// Gets the total remaining transfers for the channel
|
||||||
|
Loading…
x
Reference in New Issue
Block a user