Wire up DMA with USART v1.
This commit is contained in:
		| @@ -1,6 +1,6 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
|  |  | ||||||
| //#[cfg_attr(dma_v1, path = "v1.rs")] | #[cfg_attr(dma_v1, path = "v1.rs")] | ||||||
| #[cfg_attr(dma_v2, path = "v2.rs")] | #[cfg_attr(dma_v2, path = "v2.rs")] | ||||||
| mod _version; | mod _version; | ||||||
|  |  | ||||||
| @@ -19,4 +19,12 @@ pub trait WriteDma<T> { | |||||||
|         T: 'a; |         T: 'a; | ||||||
| } | } | ||||||
|  |  | ||||||
| pub trait ReadDma {} | pub trait ReadDma<T> { | ||||||
|  |     type ReadDmaFuture<'a>: Future<Output = ()> + 'a | ||||||
|  |     where | ||||||
|  |         Self: 'a; | ||||||
|  |  | ||||||
|  |     fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> | ||||||
|  |     where | ||||||
|  |         T: 'a; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -39,6 +39,52 @@ impl State { | |||||||
|  |  | ||||||
| static STATE: State = State::new(); | static STATE: State = State::new(); | ||||||
|  |  | ||||||
|  | #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled | ||||||
|  | pub(crate) async unsafe fn transfer_p2m( | ||||||
|  |     ch: &mut impl Channel, | ||||||
|  |     ch_func: u8, | ||||||
|  |     src: *const u8, | ||||||
|  |     dst: &mut [u8], | ||||||
|  | ) { | ||||||
|  |     let n = ch.num(); | ||||||
|  |     let c = ch.regs(); | ||||||
|  |  | ||||||
|  |     // ndtr is max 16 bits. | ||||||
|  |     assert!(dst.len() <= 0xFFFF); | ||||||
|  |  | ||||||
|  |     // Reset status | ||||||
|  |     STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Relaxed); | ||||||
|  |  | ||||||
|  |     unsafe { | ||||||
|  |         c.par().write_value(src as _); | ||||||
|  |         c.m0ar().write_value(dst.as_ptr() as _); | ||||||
|  |         c.ndtr().write_value(regs::Ndtr(dst.len() as _)); | ||||||
|  |         c.cr().write(|w| { | ||||||
|  |             w.set_dir(vals::Dir::PERIPHERALTOMEMORY); | ||||||
|  |             w.set_msize(vals::Size::BITS8); | ||||||
|  |             w.set_psize(vals::Size::BITS8); | ||||||
|  |             w.set_minc(vals::Inc::INCREMENTED); | ||||||
|  |             w.set_pinc(vals::Inc::FIXED); | ||||||
|  |             w.set_chsel(ch_func); | ||||||
|  |             w.set_teie(true); | ||||||
|  |             w.set_tcie(true); | ||||||
|  |             w.set_en(true); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let res = poll_fn(|cx| { | ||||||
|  |         STATE.ch_wakers[n].register(cx.waker()); | ||||||
|  |         match STATE.ch_status[n].load(Ordering::Relaxed) { | ||||||
|  |             CH_STATUS_NONE => Poll::Pending, | ||||||
|  |             x => Poll::Ready(x), | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     .await; | ||||||
|  |  | ||||||
|  |     // TODO handle error | ||||||
|  |     assert!(res == CH_STATUS_COMPLETED); | ||||||
|  | } | ||||||
|  |  | ||||||
| #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled | #[allow(unused)] // Used by usart/v1.rs which may or may not be enabled | ||||||
| pub(crate) async unsafe fn transfer_m2p( | pub(crate) async unsafe fn transfer_m2p( | ||||||
|     ch: &mut impl Channel, |     ch: &mut impl Channel, | ||||||
| @@ -75,7 +121,10 @@ pub(crate) async unsafe fn transfer_m2p( | |||||||
|     let res = poll_fn(|cx| { |     let res = poll_fn(|cx| { | ||||||
|         STATE.ch_wakers[n].register(cx.waker()); |         STATE.ch_wakers[n].register(cx.waker()); | ||||||
|         match STATE.ch_status[n].load(Ordering::Relaxed) { |         match STATE.ch_status[n].load(Ordering::Relaxed) { | ||||||
|             CH_STATUS_NONE => Poll::Pending, |             CH_STATUS_NONE => { | ||||||
|  |                 let left = c.ndtr().read().ndt(); | ||||||
|  |                 Poll::Pending | ||||||
|  |             } | ||||||
|             x => Poll::Ready(x), |             x => Poll::Ready(x), | ||||||
|         } |         } | ||||||
|     }) |     }) | ||||||
| @@ -137,14 +186,14 @@ pub(crate) mod sealed { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub trait PeripheralChannel<PERI>: Channel { |     pub trait PeripheralChannel<PERI, OP>: Channel { | ||||||
|         fn request(&self) -> u8; |         fn request(&self) -> u8; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub trait Dma: sealed::Dma + Sized {} | pub trait Dma: sealed::Dma + Sized {} | ||||||
| pub trait Channel: sealed::Channel + Sized {} | pub trait Channel: sealed::Channel + Sized {} | ||||||
| pub trait PeripheralChannel<PERI>: sealed::PeripheralChannel<PERI> + Sized {} | pub trait PeripheralChannel<PERI, OP>: sealed::PeripheralChannel<PERI, OP> + Sized {} | ||||||
|  |  | ||||||
| macro_rules! impl_dma { | macro_rules! impl_dma { | ||||||
|     ($peri:ident, $num:expr) => { |     ($peri:ident, $num:expr) => { | ||||||
| @@ -180,7 +229,7 @@ macro_rules! impl_dma_channel { | |||||||
|  |  | ||||||
|         impl<T> WriteDma<T> for peripherals::$channel_peri |         impl<T> WriteDma<T> for peripherals::$channel_peri | ||||||
|         where |         where | ||||||
|             Self: sealed::PeripheralChannel<T>, |             Self: sealed::PeripheralChannel<T, M2P>, | ||||||
|             T: 'static, |             T: 'static, | ||||||
|         { |         { | ||||||
|             type WriteDmaFuture<'a> = impl Future<Output = ()>; |             type WriteDmaFuture<'a> = impl Future<Output = ()>; | ||||||
| @@ -189,10 +238,30 @@ macro_rules! impl_dma_channel { | |||||||
|             where |             where | ||||||
|                 T: 'a, |                 T: 'a, | ||||||
|             { |             { | ||||||
|                 let request = sealed::PeripheralChannel::<T>::request(self); |                 let request = sealed::PeripheralChannel::<T, M2P>::request(self); | ||||||
|                 unsafe { transfer_m2p(self, request, buf, dst) } |                 unsafe { transfer_m2p(self, request, buf, dst) } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         impl<T> ReadDma<T> for peripherals::$channel_peri | ||||||
|  |         where | ||||||
|  |             Self: sealed::PeripheralChannel<T, P2M>, | ||||||
|  |             T: 'static, | ||||||
|  |         { | ||||||
|  |             type ReadDmaFuture<'a> = impl Future<Output = ()>; | ||||||
|  |  | ||||||
|  |             fn transfer<'a>( | ||||||
|  |                 &'a mut self, | ||||||
|  |                 src: *const u8, | ||||||
|  |                 buf: &'a mut [u8], | ||||||
|  |             ) -> Self::ReadDmaFuture<'a> | ||||||
|  |             where | ||||||
|  |                 T: 'a, | ||||||
|  |             { | ||||||
|  |                 let request = sealed::PeripheralChannel::<T, P2M>::request(self); | ||||||
|  |                 unsafe { transfer_p2m(self, request, src, buf) } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -217,12 +286,16 @@ peripherals! { | |||||||
|  |  | ||||||
| interrupts! { | interrupts! { | ||||||
|     (DMA, $irq:ident) => { |     (DMA, $irq:ident) => { | ||||||
|  |         #[crate::interrupt] | ||||||
|         unsafe fn $irq () { |         unsafe fn $irq () { | ||||||
|             on_irq() |             on_irq() | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub struct P2M; | ||||||
|  | pub struct M2P; | ||||||
|  |  | ||||||
| #[cfg(usart)] | #[cfg(usart)] | ||||||
| use crate::usart; | use crate::usart; | ||||||
| peripheral_dma_channels! { | peripheral_dma_channels! { | ||||||
| @@ -230,25 +303,25 @@ peripheral_dma_channels! { | |||||||
|         impl usart::RxDma<peripherals::$peri> for peripherals::$channel_peri { } |         impl usart::RxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||||||
|         impl usart::sealed::RxDma<peripherals::$peri> for peripherals::$channel_peri { } |         impl usart::sealed::RxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||||||
|  |  | ||||||
|         impl sealed::PeripheralChannel<peripherals::$peri> for peripherals::$channel_peri { |         impl sealed::PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri { | ||||||
|             fn request(&self) -> u8 { |             fn request(&self) -> u8 { | ||||||
|                 $event_num |                 $event_num | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         impl PeripheralChannel<peripherals::$peri> for peripherals::$channel_peri { } |         impl PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri { } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { |     ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => { | ||||||
|         impl usart::TxDma<peripherals::$peri> for peripherals::$channel_peri { } |         impl usart::TxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||||||
|         impl usart::sealed::TxDma<peripherals::$peri> for peripherals::$channel_peri { } |         impl usart::sealed::TxDma<peripherals::$peri> for peripherals::$channel_peri { } | ||||||
|  |  | ||||||
|         impl sealed::PeripheralChannel<peripherals::$peri> for peripherals::$channel_peri { |         impl sealed::PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri { | ||||||
|             fn request(&self) -> u8 { |             fn request(&self) -> u8 { | ||||||
|                 $event_num |                 $event_num | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         impl PeripheralChannel<peripherals::$peri> for peripherals::$channel_peri { } |         impl PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri { } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -132,7 +132,7 @@ impl RccExt for RCC { | |||||||
|             ClockSrc::HSI16 => { |             ClockSrc::HSI16 => { | ||||||
|                 // Enable HSI16 |                 // Enable HSI16 | ||||||
|                 unsafe { |                 unsafe { | ||||||
|                     rcc.cr().write(|w| w.set_hsion(true)); |                     rcc.cr().modify(|w| w.set_hsion(true)); | ||||||
|                     while !rcc.cr().read().hsirdy() {} |                     while !rcc.cr().read().hsirdy() {} | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| @@ -141,7 +141,7 @@ impl RccExt for RCC { | |||||||
|             ClockSrc::HSE(freq) => { |             ClockSrc::HSE(freq) => { | ||||||
|                 // Enable HSE |                 // Enable HSE | ||||||
|                 unsafe { |                 unsafe { | ||||||
|                     rcc.cr().write(|w| w.set_hseon(true)); |                     rcc.cr().modify(|w| w.set_hseon(true)); | ||||||
|                     while !rcc.cr().read().hserdy() {} |                     while !rcc.cr().read().hserdy() {} | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,13 +1,14 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
|  |  | ||||||
| #[cfg_attr(usart_v1, path = "v1.rs")] | #[cfg_attr(usart_v1, path = "v1.rs")] | ||||||
| //#[cfg_attr(usart_v2, path = "v2.rs")] | #[cfg_attr(usart_v2, path = "v2.rs")] | ||||||
| mod _version; | mod _version; | ||||||
| use crate::peripherals; | use crate::peripherals; | ||||||
| pub use _version::*; | pub use _version::*; | ||||||
|  |  | ||||||
| use crate::gpio::Pin; | use crate::gpio::Pin; | ||||||
| use crate::pac::usart::Usart; | use crate::pac::usart::Usart; | ||||||
|  | use crate::rcc::RccPeripheral; | ||||||
|  |  | ||||||
| /// Serial error | /// Serial error | ||||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||||
| @@ -51,7 +52,7 @@ pub(crate) mod sealed { | |||||||
|     pub trait TxDma<T: Instance>: WriteDma<T> {} |     pub trait TxDma<T: Instance>: WriteDma<T> {} | ||||||
| } | } | ||||||
|  |  | ||||||
| pub trait Instance: sealed::Instance {} | pub trait Instance: sealed::Instance + RccPeripheral {} | ||||||
| pub trait RxPin<T: Instance>: sealed::RxPin<T> {} | pub trait RxPin<T: Instance>: sealed::RxPin<T> {} | ||||||
| pub trait TxPin<T: Instance>: sealed::TxPin<T> {} | pub trait TxPin<T: Instance>: sealed::TxPin<T> {} | ||||||
| pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} | pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} | ||||||
|   | |||||||
| @@ -63,14 +63,17 @@ impl<'d, T: Instance> Uart<'d, T> { | |||||||
|         rx: impl Unborrow<Target = impl RxPin<T>>, |         rx: impl Unborrow<Target = impl RxPin<T>>, | ||||||
|         tx: impl Unborrow<Target = impl TxPin<T>>, |         tx: impl Unborrow<Target = impl TxPin<T>>, | ||||||
|         config: Config, |         config: Config, | ||||||
|         pclk_freq: u32, |         //pclk_freq: u32, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         unborrow!(inner, rx, tx); |         unborrow!(inner, rx, tx); | ||||||
|  |  | ||||||
|  |         let pclk_freq = T::frequency(); | ||||||
|  |         //let pclk_freq = 16_000_000; | ||||||
|  |  | ||||||
|         // TODO: enable in RCC |         // TODO: enable in RCC | ||||||
|  |  | ||||||
|         // TODO: better calculation, including error checking and OVER8 if possible. |         // TODO: better calculation, including error checking and OVER8 if possible. | ||||||
|         let div = (pclk_freq + (config.baudrate / 2)) / config.baudrate; |         let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; | ||||||
|  |  | ||||||
|         let r = inner.regs(); |         let r = inner.regs(); | ||||||
|  |  | ||||||
| @@ -108,25 +111,15 @@ impl<'d, T: Instance> Uart<'d, T> { | |||||||
|         ch: &mut impl TxDma<T>, |         ch: &mut impl TxDma<T>, | ||||||
|         buffer: &[u8], |         buffer: &[u8], | ||||||
|     ) -> Result<(), Error> { |     ) -> Result<(), Error> { | ||||||
|  |         unsafe { | ||||||
|  |             self.inner.regs().cr3().modify(|reg| { | ||||||
|  |                 reg.set_dmat(true); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|         let r = self.inner.regs(); |         let r = self.inner.regs(); | ||||||
|         let dst = r.dr().ptr() as *mut u8; |         let dst = r.dr().ptr() as *mut u8; | ||||||
|         ch.transfer(buffer, dst).await; |         ch.transfer(buffer, dst).await; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|         /* |  | ||||||
|         let ch_func = 4; // USART3_TX |  | ||||||
|  |  | ||||||
|         unsafe { |  | ||||||
|             r.cr3().write(|w| { |  | ||||||
|                 w.set_dmat(true); |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             let dst = r.dr().ptr() as *mut u8; |  | ||||||
|  |  | ||||||
|             crate::dma::transfer_m2p(ch, ch_func, buffer, dst).await; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|          */ |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |     pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user