implement mwe of a DMA write() method for DAC
This commit is contained in:
parent
ec36225f8a
commit
f5d084552d
@ -699,6 +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", "CH2"), quote!(crate::dac::Dma)),
|
||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
|
use crate::dma::{slice_ptr_parts, word, Transfer};
|
||||||
use crate::pac::dac;
|
use crate::pac::dac;
|
||||||
use crate::rcc::RccPeripheral;
|
use crate::rcc::RccPeripheral;
|
||||||
use crate::{peripherals, Peripheral};
|
use crate::{peripherals, Peripheral};
|
||||||
@ -97,39 +98,58 @@ pub enum Value {
|
|||||||
Bit12(u16, Alignment),
|
Bit12(u16, Alignment),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Dac<'d, T: Instance> {
|
pub struct Dac<'d, T: Instance, Tx> {
|
||||||
channels: u8,
|
channels: u8,
|
||||||
|
txdma: PeripheralRef<'d, Tx>,
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Dac<'d, T> {
|
impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
|
||||||
pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self {
|
pub fn new_1ch(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
txdma: impl Peripheral<P = Tx> + 'd,
|
||||||
|
_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
|
||||||
|
) -> Self {
|
||||||
into_ref!(peri);
|
into_ref!(peri);
|
||||||
Self::new_inner(peri, 1)
|
Self::new_inner(peri, 1, txdma)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_2ch(
|
pub fn new_2ch(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
txdma: impl Peripheral<P = Tx> + 'd,
|
||||||
_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
|
_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
|
||||||
_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
|
_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri);
|
into_ref!(peri);
|
||||||
Self::new_inner(peri, 2)
|
Self::new_inner(peri, 2, txdma)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
|
fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral<P = Tx> + 'd) -> Self {
|
||||||
|
into_ref!(txdma);
|
||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
T::regs().mcr().modify(|reg| {
|
||||||
|
for ch in 0..channels {
|
||||||
|
reg.set_mode(ch as usize, 0);
|
||||||
|
reg.set_mode(ch as usize, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
for ch in 0..channels {
|
for ch in 0..channels {
|
||||||
reg.set_en(ch as usize, true);
|
reg.set_en(ch as usize, true);
|
||||||
|
reg.set_ten(ch as usize, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { channels, _peri: peri }
|
Self {
|
||||||
|
channels,
|
||||||
|
txdma,
|
||||||
|
_peri: peri,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the channel is configured
|
/// Check the channel is configured
|
||||||
@ -215,6 +235,47 @@ impl<'d, T: Instance> Dac<'d, T> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: Allow an array of Value instead of only u16, right-aligned
|
||||||
|
pub async fn write(&mut self, data: &[u16]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
Tx: Dma<T>,
|
||||||
|
{
|
||||||
|
// TODO: Make this a parameter or get it from the struct or so...
|
||||||
|
const CHANNEL: usize = 0;
|
||||||
|
|
||||||
|
//debug!("Starting DAC");
|
||||||
|
unsafe {
|
||||||
|
T::regs().cr().modify(|w| {
|
||||||
|
w.set_en(CHANNEL, true);
|
||||||
|
w.set_dmaen(CHANNEL, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx_request = self.txdma.request();
|
||||||
|
|
||||||
|
// Use the 12 bit right-aligned register for now. TODO: distinguish values
|
||||||
|
let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16;
|
||||||
|
|
||||||
|
let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
|
||||||
|
|
||||||
|
//debug!("Awaiting tx_f");
|
||||||
|
|
||||||
|
tx_f.await;
|
||||||
|
|
||||||
|
// finish dma
|
||||||
|
unsafe {
|
||||||
|
// 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 {
|
||||||
@ -224,6 +285,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
|
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
|
||||||
|
dma_trait!(Dma, Instance);
|
||||||
|
|
||||||
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user