123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- use core::marker::PhantomData;
- use core::ptr;
- use core::sync::atomic::{self, Ordering};
- use cast::u16;
- use hal;
- use nb;
- use stm32::{USART1, USART2, USART3};
- use void::Void;
- use afio::MAPR;
- use dma::{dma1, CircBuffer, Static, Transfer, R, W};
- use gpio::gpioa::{PA10, PA2, PA3, PA9};
- use gpio::gpiob::{PB10, PB11, PB6, PB7};
- use gpio::{Alternate, Floating, Input, PushPull};
- use rcc::{APB1, APB2, Clocks};
- use time::Bps;
- /// Interrupt event
- pub enum Event {
- /// New data has been received
- Rxne,
- /// New data can be sent
- Txe,
- }
- /// Serial error
- #[derive(Debug)]
- pub enum Error {
- /// Framing error
- Framing,
- /// Noise error
- Noise,
- /// RX buffer overrun
- Overrun,
- /// Parity check error
- Parity,
- #[doc(hidden)]
- _Extensible,
- }
- pub trait Pins<USART> {
- const REMAP: u8;
- }
- impl Pins<USART1> for (PA9<Alternate<PushPull>>, PA10<Input<Floating>>) {
- const REMAP: u8 = 0;
- }
- impl Pins<USART1> for (PB6<Alternate<PushPull>>, PB7<Input<Floating>>) {
- const REMAP: u8 = 1;
- }
- impl Pins<USART2> for (PA2<Alternate<PushPull>>, PA3<Input<Floating>>) {
- const REMAP: u8 = 0;
- }
- // impl Pins<USART2> for (PD5<Alternate<PushPull>>, PD6<Input<Floating>>) {
- // const REMAP: u8 = 0;
- // }
- impl Pins<USART3> for (PB10<Alternate<PushPull>>, PB11<Input<Floating>>) {
- const REMAP: u8 = 0;
- }
- // impl Pins<USART3> for (PC10<Alternate<PushPull>>, PC11<Input<Floating>>) {
- // const REMAP: u8 = 1;
- // }
- // impl Pins<USART3> for (PD8<Alternate<PushPull>>, PD9<Input<Floating>>) {
- // const REMAP: u8 = 0b11;
- // }
- /// Serial abstraction
- pub struct Serial<USART, PINS> {
- usart: USART,
- pins: PINS,
- }
- /// Serial receiver
- pub struct Rx<USART> {
- _usart: PhantomData<USART>,
- }
- /// Serial transmitter
- pub struct Tx<USART> {
- _usart: PhantomData<USART>,
- }
- macro_rules! hal {
- ($(
- $USARTX:ident: (
- $usartX:ident,
- $usartXen:ident,
- $usartXrst:ident,
- $usartX_remap:ident,
- $bit:ident,
- $closure:expr,
- $APB:ident
- ),
- )+) => {
- $(
- impl<PINS> Serial<$USARTX, PINS> {
- pub fn $usartX(
- usart: $USARTX,
- pins: PINS,
- mapr: &mut MAPR,
- baud_rate: Bps,
- clocks: Clocks,
- apb: &mut $APB,
- ) -> Self
- where
- PINS: Pins<$USARTX>,
- {
- // enable and reset $USARTX
- apb.enr().modify(|_, w| w.$usartXen().set_bit());
- apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
- apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
- #[allow(unused_unsafe)]
- mapr.mapr()
- .modify(|_, w| unsafe{
- w.$usartX_remap().$bit(($closure)(PINS::REMAP))
- });
- // enable DMA transfers
- usart.cr3.write(|w| w.dmat().set_bit().dmar().set_bit());
- let brr = clocks.pclk2().0 / baud_rate.0;
- assert!(brr >= 16, "impossible baud rate");
- usart.brr.write(|w| unsafe { w.bits(brr) });
- // UE: enable USART
- // RE: enable receiver
- // TE: enable transceiver
- usart
- .cr1
- .write(|w| w.ue().set_bit().re().set_bit().te().set_bit());
- Serial { usart, pins }
- }
- pub fn listen(&mut self, event: Event) {
- match event {
- Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().set_bit()),
- Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().set_bit()),
- }
- }
- pub fn unlisten(&mut self, event: Event) {
- match event {
- Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
- Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().clear_bit()),
- }
- }
- pub fn release(self) -> ($USARTX, PINS) {
- (self.usart, self.pins)
- }
- pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
- (
- Tx {
- _usart: PhantomData,
- },
- Rx {
- _usart: PhantomData,
- },
- )
- }
- }
- impl hal::serial::Read<u8> for Rx<$USARTX> {
- type Error = Error;
- fn read(&mut self) -> nb::Result<u8, Error> {
- // NOTE(unsafe) atomic read with no side effects
- let sr = unsafe { (*$USARTX::ptr()).sr.read() };
- // Check for any errors
- let err = if sr.pe().bit_is_set() {
- Some(Error::Parity)
- } else if sr.fe().bit_is_set() {
- Some(Error::Framing)
- } else if sr.ne().bit_is_set() {
- Some(Error::Noise)
- } else if sr.ore().bit_is_set() {
- Some(Error::Overrun)
- } else {
- None
- };
- if let Some(err) = err {
- // Some error occured. In order to clear that error flag, you have to
- // do a read from the sr register followed by a read from the dr
- // register
- // NOTE(read_volatile) see `write_volatile` below
- unsafe {
- ptr::read_volatile(&(*$USARTX::ptr()).sr as *const _ as *const _);
- ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _);
- }
- Err(nb::Error::Other(err))
- } else {
- // Check if a byte is available
- if sr.rxne().bit_is_set() {
- // Read the received byte
- // NOTE(read_volatile) see `write_volatile` below
- Ok(unsafe {
- ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _)
- })
- } else {
- Err(nb::Error::WouldBlock)
- }
- }
- }
- }
- impl<B> ReadDma<B> for Rx<$USARTX> where B: AsMut<[u8]> {
- fn circ_read(self, mut chan: Self::Dma, buffer: &'static mut [B; 2],
- ) -> CircBuffer<B, Self::Dma>
- {
- {
- let buffer = buffer[0].as_mut();
- chan.cmar().write(|w| unsafe {
- w.ma().bits(buffer.as_ptr() as usize as u32)
- });
- chan.cndtr().write(|w| unsafe{
- w.ndt().bits(u16(buffer.len() * 2).unwrap())
- });
- chan.cpar().write(|w| unsafe {
- w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
- });
- // TODO can we weaken this compiler barrier?
- // NOTE(compiler_fence) operations on `buffer` should not be reordered after
- // the next statement, which starts the DMA transfer
- atomic::compiler_fence(Ordering::SeqCst);
- chan.ccr().modify(|_, w| {
- w.mem2mem()
- .clear_bit()
- .pl()
- .medium()
- .msize()
- .bit8()
- .psize()
- .bit8()
- .minc()
- .set_bit()
- .pinc()
- .clear_bit()
- .circ()
- .set_bit()
- .dir()
- .clear_bit()
- .en()
- .set_bit()
- });
- }
- CircBuffer::new(buffer, chan)
- }
- fn read_exact(self, mut chan: Self::Dma, buffer: &'static mut B,
- ) -> Transfer<W, &'static mut B, Self::Dma, Self>
- {
- {
- let buffer = buffer.as_mut();
- chan.cmar().write(|w| unsafe {
- w.ma().bits(buffer.as_ptr() as usize as u32)
- });
- chan.cndtr().write(|w| unsafe{
- w.ndt().bits(u16(buffer.len()).unwrap())
- });
- chan.cpar().write(|w| unsafe {
- w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
- });
- // TODO can we weaken this compiler barrier?
- // NOTE(compiler_fence) operations on `buffer` should not be reordered after
- // the next statement, which starts the DMA transfer
- atomic::compiler_fence(Ordering::SeqCst);
- chan.ccr().modify(|_, w| {
- w.mem2mem()
- .clear_bit()
- .pl()
- .medium()
- .msize()
- .bit8()
- .psize()
- .bit8()
- .minc()
- .set_bit()
- .pinc()
- .clear_bit()
- .circ()
- .clear_bit()
- .dir()
- .clear_bit()
- .en()
- .set_bit()
- });
- }
- Transfer::w(buffer, chan, self)
- }
- }
- impl<A, B> WriteDma<A, B> for Tx<$USARTX> where A: AsRef<[u8]>, B: Static<A> {
- fn write_all(self, mut chan: Self::Dma, buffer: B
- ) -> Transfer<R, B, Self::Dma, Self>
- {
- {
- let buffer = buffer.borrow().as_ref();
- chan.cmar().write(|w| unsafe {
- w.ma().bits(buffer.as_ptr() as usize as u32)
- });
- chan.cndtr().write(|w| unsafe{
- w.ndt().bits(u16(buffer.len()).unwrap())
- });
- chan.cpar().write(|w| unsafe {
- w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
- });
- // TODO can we weaken this compiler barrier?
- // NOTE(compiler_fence) operations on `buffer` should not be reordered after
- // the next statement, which starts the DMA transfer
- atomic::compiler_fence(Ordering::SeqCst);
- chan.ccr().modify(|_, w| {
- w.mem2mem()
- .clear_bit()
- .pl()
- .medium()
- .msize()
- .bit8()
- .psize()
- .bit8()
- .minc()
- .set_bit()
- .pinc()
- .clear_bit()
- .circ()
- .clear_bit()
- .dir()
- .set_bit()
- .en()
- .set_bit()
- });
- }
- Transfer::r(buffer, chan, self)
- }
- }
- impl hal::serial::Write<u8> for Tx<$USARTX> {
- type Error = Void;
- fn flush(&mut self) -> nb::Result<(), Self::Error> {
- // NOTE(unsafe) atomic read with no side effects
- let sr = unsafe { (*$USARTX::ptr()).sr.read() };
- if sr.tc().bit_is_set() {
- Ok(())
- } else {
- Err(nb::Error::WouldBlock)
- }
- }
- fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
- // NOTE(unsafe) atomic read with no side effects
- let sr = unsafe { (*$USARTX::ptr()).sr.read() };
- if sr.txe().bit_is_set() {
- // NOTE(unsafe) atomic write to stateless register
- // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
- unsafe {
- ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
- }
- Ok(())
- } else {
- Err(nb::Error::WouldBlock)
- }
- }
- }
- )+
- }
- }
- hal! {
- USART1: (
- usart1,
- usart1en,
- usart1rst,
- usart1_remap,
- bit,
- |remap| remap == 1,
- APB2
- ),
- USART2: (
- usart2,
- usart2en,
- usart2rst,
- usart2_remap,
- bit,
- |remap| remap == 1,
- APB1
- ),
- USART3: (
- usart3,
- usart3en,
- usart3rst,
- usart3_remap,
- bits,
- |remap| remap,
- APB1
- ),
- }
- use dma::DmaChannel;
- impl DmaChannel for Rx<USART1> {
- type Dma = dma1::C5;
- }
- impl DmaChannel for Tx<USART1> {
- type Dma = dma1::C4;
- }
- impl DmaChannel for Rx<USART2> {
- type Dma = dma1::C6;
- }
- impl DmaChannel for Tx<USART2> {
- type Dma = dma1::C7;
- }
- impl DmaChannel for Rx<USART3> {
- type Dma = dma1::C3;
- }
- impl DmaChannel for Tx<USART3> {
- type Dma = dma1::C2;
- }
- pub trait ReadDma<B>: DmaChannel
- where
- B: AsMut<[u8]>,
- Self: core::marker::Sized,
- {
- fn circ_read(self, chan: Self::Dma, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::Dma>;
- fn read_exact(
- self,
- chan: Self::Dma,
- buffer: &'static mut B,
- ) -> Transfer<W, &'static mut B, Self::Dma, Self>;
- }
- pub trait WriteDma<A, B>: DmaChannel
- where
- A: AsRef<[u8]>,
- B: Static<A>,
- Self: core::marker::Sized,
- {
- fn write_all(self, chan: Self::Dma, buffer: B) -> Transfer<R, B, Self::Dma, Self>;
- }
|