diff --git a/Cargo.toml b/Cargo.toml index 3f05cd245a76a3775517771851218e64a122b3e5..a3beb7788358341d2f20dbb122474c61a8cd7ee1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,19 @@ name = "f3" repository = "https://github.com/japaric/f3" version = "0.5.0" +[dependencies] +static-ref = "0.2.0" + [dependencies.cast] default-features = false -version = "0.2.0" +version = "0.2.2" + +[dependencies.embedded-hal] +git = "https://github.com/japaric/embedded-hal" +rev = "7d904f515d15fd5fe7ea34e18820ea83e2651fa2" + +[dependencies.nb] +git = "https://github.com/japaric/nb" [dependencies.stm32f30x] features = ["rt"] diff --git a/examples/loopback.rs b/examples/loopback.rs index a9417b0efdb3066ee7e596165a993cf6c2fe4d79..bb345e03d26b4e505090d7fcb082431c87f13970 100644 --- a/examples/loopback.rs +++ b/examples/loopback.rs @@ -7,11 +7,14 @@ extern crate cortex_m_rtfm as rtfm; extern crate f3; -use f3::serial::Serial; +use f3::prelude::*; +use f3::Serial; +use f3::serial::Event; +use f3::time::Hertz; use rtfm::{app, Threshold}; // CONFIGURATION -const BAUD_RATE: u32 = 115_200; // bits per second +const BAUD_RATE: Hertz = Hertz(115_200); // TASKS & RESOURCES app! { @@ -27,9 +30,10 @@ app! { // INITIALIZATION PHASE fn init(p: init::Peripherals) { - let serial = Serial(&p.USART1); + let serial = Serial(p.USART1); - serial.init(&p.GPIOA, &p.RCC, BAUD_RATE); + serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC); + serial.listen(Event::Rxne); } // IDLE LOOP @@ -43,7 +47,7 @@ fn idle() -> ! { // TASKS // Send back the received byte fn loopback(_t: &mut Threshold, r: USART1_EXTI25::Resources) { - let serial = Serial(&r.USART1); + let serial = Serial(&**r.USART1); let byte = serial.read().unwrap(); serial.write(byte).unwrap(); diff --git a/src/dma.rs b/src/dma.rs new file mode 100644 index 0000000000000000000000000000000000000000..a207f03c00b5b919ea1eed5602058cb5173084a8 --- /dev/null +++ b/src/dma.rs @@ -0,0 +1,259 @@ +//! Direct Memory Access (DMA) + +use core::cell::{Cell, UnsafeCell}; +use core::marker::PhantomData; +use core::ops; + +use nb; +use stm32f30x::DMA1; + +/// DMA error +#[derive(Debug)] +pub enum Error { + /// DMA channel in use + InUse, + /// Previous data got overwritten before it could be read because it was + /// not accessed in a timely fashion + Overrun, + /// Transfer error + Transfer, +} + +/// Channel 2 of DMA1 +pub struct Dma1Channel2 { + _0: (), +} + +/// Channel 4 of DMA1 +pub struct Dma1Channel4 { + _0: (), +} + +/// Channel 5 of DMA1 +pub struct Dma1Channel5 { + _0: (), +} + +/// Buffer to be used with a certain DMA `CHANNEL` +// NOTE(packed) workaround for rust-lang/rust#41315 +#[repr(packed)] +pub struct Buffer<T, CHANNEL> { + data: UnsafeCell<T>, + flag: Cell<BorrowFlag>, + state: Cell<State>, + _marker: PhantomData<CHANNEL>, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum State { + // A new `Buffer` starts in this state. We set it to zero to place this + // buffer in the .bss section + Unlocked = 0, + + Locked, + MutLocked, +} + +type BorrowFlag = usize; + +const UNUSED: BorrowFlag = 0; +const WRITING: BorrowFlag = !0; + +/// Wraps a borrowed reference to a value in a `Buffer` +pub struct Ref<'a, T> +where + T: 'a, +{ + data: &'a T, + flag: &'a Cell<BorrowFlag>, +} + +impl<'a, T> ops::Deref for Ref<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + self.data + } +} + +impl<'a, T> Drop for Ref<'a, T> { + fn drop(&mut self) { + self.flag.set(self.flag.get() - 1); + } +} + +/// A wrapper type for a mutably borrowed value from a `Buffer`` +pub struct RefMut<'a, T> +where + T: 'a, +{ + data: &'a mut T, + flag: &'a Cell<BorrowFlag>, +} + +impl<'a, T> ops::Deref for RefMut<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + self.data + } +} + +impl<'a, T> ops::DerefMut for RefMut<'a, T> { + fn deref_mut(&mut self) -> &mut T { + self.data + } +} + +impl<'a, T> Drop for RefMut<'a, T> { + fn drop(&mut self) { + self.flag.set(UNUSED); + } +} + +impl<T, CHANNEL> Buffer<T, CHANNEL> { + /// Creates a new buffer + pub const fn new(data: T) -> Self { + Buffer { + _marker: PhantomData, + data: UnsafeCell::new(data), + flag: Cell::new(0), + state: Cell::new(State::Unlocked), + } + } + + /// Immutably borrows the wrapped value. + /// + /// The borrow lasts until the returned `Ref` exits scope. Multiple + /// immutable borrows can be taken out at the same time. + /// + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. + pub fn borrow(&self) -> Ref<T> { + assert_ne!(self.flag.get(), WRITING); + + self.flag.set(self.flag.get() + 1); + + Ref { + data: unsafe { &*self.data.get() }, + flag: &self.flag, + } + } + + /// Mutably borrows the wrapped value. + /// + /// The borrow lasts until the returned `RefMut` exits scope. The value + /// cannot be borrowed while this borrow is active. + /// + /// # Panics + /// + /// Panics if the value is currently borrowed. + pub fn borrow_mut(&self) -> RefMut<T> { + assert_eq!(self.flag.get(), UNUSED); + + self.flag.set(WRITING); + + RefMut { + data: unsafe { &mut *self.data.get() }, + flag: &self.flag, + } + } + + pub(crate) fn lock(&self) -> &T { + assert_eq!(self.state.get(), State::Unlocked); + assert_ne!(self.flag.get(), WRITING); + + self.flag.set(self.flag.get() + 1); + self.state.set(State::Locked); + + unsafe { &*self.data.get() } + } + + pub(crate) fn lock_mut(&self) -> &mut T { + assert_eq!(self.state.get(), State::Unlocked); + assert_eq!(self.flag.get(), UNUSED); + + self.flag.set(WRITING); + self.state.set(State::MutLocked); + + unsafe { &mut *self.data.get() } + } + + unsafe fn unlock(&self, state: State) { + match state { + State::Locked => self.flag.set(self.flag.get() - 1), + State::MutLocked => self.flag.set(UNUSED), + _ => { /* unreachable!() */ } + } + + self.state.set(State::Unlocked); + } +} + +// FIXME these `release` methods probably want some of sort of barrier +impl<T> Buffer<T, Dma1Channel2> { + /// Waits until the DMA releases this buffer + pub fn release(&self, dma1: &DMA1) -> nb::Result<(), Error> { + let state = self.state.get(); + + if state == State::Unlocked { + return Ok(()); + } + + if dma1.isr.read().teif2().bit_is_set() { + Err(nb::Error::Other(Error::Transfer)) + } else if dma1.isr.read().tcif2().bit_is_set() { + unsafe { self.unlock(state) } + dma1.ifcr.write(|w| w.ctcif2().set_bit()); + dma1.ccr2.modify(|_, w| w.en().clear_bit()); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } +} + +impl<T> Buffer<T, Dma1Channel4> { + /// Waits until the DMA releases this buffer + pub fn release(&self, dma1: &DMA1) -> nb::Result<(), Error> { + let state = self.state.get(); + + if state == State::Unlocked { + return Ok(()); + } + + if dma1.isr.read().teif4().bit_is_set() { + Err(nb::Error::Other(Error::Transfer)) + } else if dma1.isr.read().tcif4().bit_is_set() { + unsafe { self.unlock(state) } + dma1.ifcr.write(|w| w.ctcif4().set_bit()); + dma1.ccr4.modify(|_, w| w.en().clear_bit()); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } +} + +impl<T> Buffer<T, Dma1Channel5> { + /// Waits until the DMA releases this buffer + pub fn release(&self, dma1: &DMA1) -> nb::Result<(), Error> { + let state = self.state.get(); + + if state == State::Unlocked { + return Ok(()); + } + + if dma1.isr.read().teif5().bit_is_set() { + Err(nb::Error::Other(Error::Transfer)) + } else if dma1.isr.read().tcif5().bit_is_set() { + unsafe { self.unlock(state) } + dma1.ifcr.write(|w| w.ctcif5().set_bit()); + dma1.ccr5.modify(|_, w| w.en().clear_bit()); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } +} diff --git a/src/frequency.rs b/src/frequency.rs index ebb4f9b240e9e2b0aa3816dc8b981746e4bf544b..ce5eb546e826c89aafce968d20b0a56649d7eb42 100644 --- a/src/frequency.rs +++ b/src/frequency.rs @@ -1,3 +1,86 @@ -// pub const AHB: u32 = 8_000_000; -pub const APB1: u32 = 8_000_000; -pub const APB2: u32 = 8_000_000; +//! Definition of bus frequency details for f3. + +macro_rules! frequency { + ($FREQUENCY:expr) => { + use time::*; + + /// Frequency + pub const FREQUENCY: u32 = $FREQUENCY; + + /// Unit of time + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] + pub struct Ticks(pub u32); + + impl Ticks { + /// Applies the function `f` to the inner value + pub fn map<F>(self, f: F) -> Self + where F: FnOnce(u32) -> u32, + { + Ticks(f(self.0)) + } + } + + impl From<Ticks> for Microseconds { + fn from(ticks: Ticks) -> Self { + Microseconds(ticks.0 / (FREQUENCY / 1_000_000)) + } + } + + impl From<Ticks> for Milliseconds { + fn from(ticks: Ticks) -> Self { + Milliseconds(ticks.0 / (FREQUENCY / 1_000)) + } + } + + impl From<Ticks> for Seconds { + fn from(ticks: Ticks) -> Self { + Seconds(ticks.0 / FREQUENCY) + } + } + + impl From<IHertz> for Ticks { + fn from(ihz: IHertz) -> Ticks { + Ticks(FREQUENCY / ihz.0) + } + } + + impl From<Microseconds> for Ticks { + fn from(us: Microseconds) -> Ticks { + Ticks(us.0 * (FREQUENCY / 1_000_000)) + } + } + + impl From<Milliseconds> for Ticks { + fn from(ms: Milliseconds) -> Ticks { + Ticks(ms.0 * (FREQUENCY / 1_000)) + } + } + + impl From<Seconds> for Ticks { + fn from(s: Seconds) -> Ticks { + Ticks(s.0 * FREQUENCY) + } + } + + impl Into<u32> for Ticks { + fn into(self) -> u32 { + self.0 + } + } + } +} + +/// Advance High-performance Bus (AHB) +pub mod ahb { + frequency!(8_000_000); +} + +/// Advance Peripheral Bus 1 (APB1) +pub mod apb1 { + frequency!(8_000_000); +} + +/// Advance Peripheral Bus 2 (APB2) +pub mod apb2 { + frequency!(8_000_000); +} diff --git a/src/lib.rs b/src/lib.rs index 9b0c42c77fb836bec681a025747fdfed5065aceb..eda4eeea5bb5bbf598e987c7f7d261c0c5d4ebda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,16 +17,31 @@ #![deny(missing_docs)] #![deny(warnings)] +#![feature(const_fn)] +#![feature(get_type_id)] +#![feature(never_type)] +#![feature(unsize)] #![no_std] extern crate cast; +extern crate embedded_hal as hal; +extern crate nb; +extern crate static_ref; + pub extern crate stm32f30x; // For documentation only pub mod examples; +pub mod dma; pub mod led; pub mod serial; pub mod timer; +pub mod time; + +pub mod frequency; +use frequency::*; + +pub use hal::prelude; +pub use serial::Serial; -mod frequency; diff --git a/src/serial.rs b/src/serial.rs index 62dd09d8c33bd504735600413288937c3c94b5d3..2f292af6b3306046303c22ad9711b4a07f887c9a 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1,117 +1,398 @@ //! Serial interface //! -//! - TX - PA9 -//! - RX - PA10 +//! You can use the `Serial` interface with these USART instances +//! +//! # USART1 +//! +//! - TX = PA9 +//! - RX = PA10 +//! - Interrupt = USART1 +use core::any::{Any, TypeId}; +use core::marker::Unsize; +use core::ops::Deref; use core::ptr; -use cast::{u16, u8}; -use stm32f30x::{USART1, GPIOA, RCC}; +use cast::u16; +use hal; +use nb; +use static_ref::Static; +use stm32f30x::{gpioa, DMA1, USART1, usart1, GPIOA, + RCC}; -use frequency; +use dma::{self, Buffer, Dma1Channel4, Dma1Channel5}; /// Specialized `Result` type -pub type Result<T> = ::core::result::Result<T, Error>; +pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>; + +/// IMPLEMENTATION DETAIL +pub unsafe trait Usart: Deref<Target = usart1::RegisterBlock> { + /// IMPLEMENTATION DETAIL + type GPIO: Deref<Target = gpioa::RegisterBlock>; + /// IMPLEMENTATION DETAIL + type Ticks: Into<u32>; +} + +unsafe impl Usart for USART1 { + type GPIO = GPIOA; + type Ticks = ::apb2::Ticks; +} /// An error #[derive(Debug)] pub enum Error { + /// De-synchronization, excessive noise or a break character detected + Framing, + /// Noise detected in the received frame + Noise, + /// RX buffer overrun + Overrun, #[doc(hidden)] _Extensible, } +/// Interrupt event +pub enum Event { + /// RX buffer Not Empty (new data available) + Rxne, + /// Transmission Complete + Tc, + /// TX buffer Empty (more data can be send) + Txe, +} + /// Serial interface /// /// # Interrupts /// -/// - `Usart1Exti25` - RXNE (RX buffer not empty) -pub struct Serial<'a>(pub &'a USART1); +/// - RXNE +pub struct Serial<'a, U>(pub &'a U) +where + U: Any + Usart; + +impl<'a, U> Clone for Serial<'a, U> +where + U: Any + Usart, +{ + fn clone(&self) -> Self { + *self + } +} -impl<'a> Serial<'a> { +impl<'a, U> Copy for Serial<'a, U> +where + U: Any + Usart, +{ +} + +impl<'a, U> Serial<'a, U> +where + U: Any + Usart, +{ /// Initializes the serial interface with a baud rate of `baut_rate` bits /// per second - pub fn init(&self, gpioa: &GPIOA, rcc: &RCC, baud_rate: u32) { - let usart1 = self.0; + /// + /// The serial interface will be configured to use 8 bits of data, 1 stop + /// bit, no hardware control and to omit parity checking + pub fn init<B>( + &self, + baud_rate: B, + dma1: Option<&DMA1>, + gpio: &U::GPIO, + rcc: &RCC, + ) where + B: Into<U::Ticks>, + { + self._init(baud_rate.into(), dma1, gpio, rcc) + } + + fn _init( + &self, + baud_rate: U::Ticks, + dma1: Option<&DMA1>, + gpio: &U::GPIO, + rcc: &RCC, + ) { + let usart = self.0; + + // power up peripherals + if dma1.is_some() { + rcc.ahbenr.modify(|_, w| w.dmaen().enabled()); + } + if usart.get_type_id() == TypeId::of::<USART1>() { + rcc.apb2enr.modify(|_, w| { + w.usart1en().enabled() + }); + } + + rcc.ahbenr.modify(|_, w| w.iopaen().set_bit()); + + if usart.get_type_id() == TypeId::of::<USART1>() { + // PA9. = TX, PA10 = RX + gpio.afrh.modify(|_, w| { + unsafe { + w.afrh9().bits(7).afrh10().bits(7) + } + }); + gpio.moder.modify(|_, w| { + w.moder9().alternate() + .moder10().alternate() + }); + } + + if let Some(dma1) = dma1 { + if usart.get_type_id() == TypeId::of::<USART1>() { + // TX DMA transfer + // mem2mem: Memory to memory mode disabled + // pl: Medium priority + // msize: Memory size = 8 bits + // psize: Peripheral size = 8 bits + // minc: Memory increment mode enabled + // pinc: Peripheral increment mode disabled + // circ: Circular mode disabled + // dir: Transfer from memory to peripheral + // tceie: Transfer complete interrupt enabled + // en: Disabled + dma1.ccr4.write(|w| unsafe { + w.mem2mem() + .clear_bit() + .pl() + .bits(0b01) + .msize() + .bits(0b00) + .psize() + .bits(0b00) + .minc() + .set_bit() + .circ() + .clear_bit() + .pinc() + .clear_bit() + .dir() + .set_bit() + .tcie() + .set_bit() + .en() + .clear_bit() + }); + + // RX DMA transfer + // mem2mem: Memory to memory mode disabled + // pl: Medium priority + // msize: Memory size = 8 bits + // psize: Peripheral size = 8 bits + // minc: Memory increment mode enabled + // pinc: Peripheral increment mode disabled + // circ: Circular mode disabled + // dir: Transfer from peripheral to memory + // tceie: Transfer complete interrupt enabled + // en: Disabled + dma1.ccr5.write(|w| unsafe { + w.mem2mem() + .clear_bit() + .pl() + .bits(0b01) + .msize() + .bits(0b00) + .psize() + .bits(0b00) + .minc() + .set_bit() + .circ() + .clear_bit() + .pinc() + .clear_bit() + .dir() + .clear_bit() + .tcie() + .set_bit() + .en() + .clear_bit() + }); + } + } - // Power up the peripherals - rcc.apb2enr.modify(|_, w| w.usart1en().enabled()); - rcc.ahbenr.modify(|_, w| w.iopaen().enabled()); - - // Configure PA9 as TX and PA10 as RX - gpioa - .afrh - .modify(|_, w| unsafe { w.afrh9().bits(7).afrh10().bits(7) }); - gpioa - .moder - .modify(|_, w| w.moder9().alternate().moder10().alternate()); - - // 8 data bits, 0 stop bits - usart1.cr2.write(|w| unsafe { w.stop().bits(0b00) }); - - // Disable hardware flow control - usart1 - .cr3 - .write(|w| w.rtse().clear_bit().ctse().clear_bit()); - - // set baud rate - let brr = u16(frequency::APB2 / baud_rate).unwrap(); - let fraction = u8(brr & 0b1111).unwrap(); - let mantissa = brr >> 4; - usart1.brr.write(|w| unsafe { - w.div_fraction() - .bits(fraction) - .div_mantissa() - .bits(mantissa) + // 8N1 + usart.cr2.write(|w| unsafe { w.stop().bits(0b00) }); + + // baud rate + let brr = baud_rate.into(); + assert!(brr >= 16, "impossible baud rate"); + usart.brr.write(|w| unsafe { w.bits(brr) }); + + // disable hardware flow control + // enable DMA TX and RX transfers + usart.cr3.write(|w| { + w.rtse() + .clear_bit() + .ctse() + .clear_bit() + .dmat() + .set_bit() + .dmar() + .set_bit() }); - // enable peripheral, transmitter, receiver - // enable RXNE event - usart1.cr1.write(|w| { + // enable TX, RX; disable parity checking + usart.cr1.write(|w| { w.ue() .set_bit() .re() .set_bit() .te() .set_bit() - .pce() + .m() .clear_bit() .over8() .clear_bit() + .pce() + .clear_bit() .rxneie() - .set_bit() + .clear_bit() }); } - /// Reads a byte from the RX buffer - /// - /// Returns `None` if the buffer is empty - pub fn read(&self) -> Result<u8> { + /// Starts listening for an interrupt `event` + pub fn listen(&self, event: Event) { + let usart = self.0; + + match event { + Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().set_bit()), + Event::Tc => usart.cr1.modify(|_, w| w.tcie().set_bit()), + Event::Txe => usart.cr1.modify(|_, w| w.txeie().set_bit()), + } + } + + /// Stops listening for an interrupt `event` + pub fn unlisten(&self, event: Event) { + let usart = self.0; + + match event { + Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().clear_bit()), + Event::Tc => usart.cr1.modify(|_, w| w.tcie().clear_bit()), + Event::Txe => usart.cr1.modify(|_, w| w.txeie().clear_bit()), + } + } +} + +impl<'a, U> hal::serial::Read<u8> for Serial<'a, U> +where + U: Any + Usart, +{ + type Error = Error; + + fn read(&self) -> Result<u8> { let usart1 = self.0; + let sr = usart1.isr.read(); - if usart1.isr.read().rxne().bit_is_set() { + if sr.ore().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else if sr.nf().bit_is_set() { + Err(nb::Error::Other(Error::Noise)) + } else if sr.fe().bit_is_set() { + Err(nb::Error::Other(Error::Framing)) + } else if sr.rxne().bit_is_set() { // NOTE(read_volatile) the register is 9 bits big but we'll only // work with the first 8 bits Ok(unsafe { ptr::read_volatile(&usart1.rdr as *const _ as *const u8) }) } else { - Err(Error::_Extensible) + Err(nb::Error::WouldBlock) } } +} - /// Writes byte into the TX buffer - /// - /// Returns `Err` if the buffer is already full - pub fn write(&self, byte: u8) -> Result<()> { +impl<'a, U> hal::serial::Write<u8> for Serial<'a, U> +where + U: Any + Usart, +{ + type Error = Error; + + fn write(&self, byte: u8) -> Result<()> { let usart1 = self.0; + let sr = usart1.isr.read(); - if usart1.isr.read().txe().bit_is_set() { + if sr.ore().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else if sr.nf().bit_is_set() { + Err(nb::Error::Other(Error::Noise)) + } else if sr.fe().bit_is_set() { + Err(nb::Error::Other(Error::Framing)) + } else if sr.txe().bit_is_set() { + // NOTE(write_volatile) see NOTE in the `read` method unsafe { ptr::write_volatile(&usart1.tdr as *const _ as *mut u8, byte) } Ok(()) } else { - Err(Error::_Extensible) + Err(nb::Error::WouldBlock) } } } + +impl<'a> Serial<'a, USART1> { + /// Starts a DMA transfer to receive serial data into a `buffer` + /// + /// This will mutably lock the `buffer` preventing borrowing its contents + /// The `buffer` can be `release`d after the DMA transfer finishes + // TODO support circular mode + half transfer interrupt as a double + // buffering mode + pub fn read_exact<B>( + &self, + dma1: &DMA1, + buffer: &Static<Buffer<B, Dma1Channel5>>, + ) -> ::core::result::Result<(), dma::Error> + where + B: Unsize<[u8]>, + { + let usart1 = self.0; + + if dma1.ccr5.read().en().bit_is_set() { + return Err(dma::Error::InUse); + } + + let buffer: &mut [u8] = buffer.lock_mut(); + + dma1.cndtr5 + .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) }); + dma1.cpar5 + .write(|w| unsafe { w.bits(&usart1.rdr as *const _ as u32) }); + dma1.cmar5 + .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); + dma1.ccr5.modify(|_, w| w.en().set_bit()); + + Ok(()) + } + + /// Starts a DMA transfer to send `buffer` through this serial port + /// + /// This will immutably lock the `buffer` preventing mutably borrowing its + /// contents. The `buffer` can be `release`d after the DMA transfer finishes + pub fn write_all<B>( + &self, + dma1: &DMA1, + buffer: &Static<Buffer<B, Dma1Channel4>>, + ) -> ::core::result::Result<(), dma::Error> + where + B: Unsize<[u8]>, + { + let usart1 = self.0; + + if dma1.ccr4.read().en().bit_is_set() { + return Err(dma::Error::InUse); + } + + let buffer: &[u8] = buffer.lock(); + + dma1.cndtr4 + .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) }); + dma1.cpar4 + .write(|w| unsafe { w.bits(&usart1.tdr as *const _ as u32) }); + dma1.cmar4 + .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); + dma1.ccr4.modify(|_, w| w.en().set_bit()); + + Ok(()) + } +} diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000000000000000000000000000000000000..3922a718896a763b4f82205ba985939198affac5 --- /dev/null +++ b/src/time.rs @@ -0,0 +1,93 @@ + +//! Units of time + +macro_rules! map { + ($Self:ident) => { + impl $Self { + /// Applies the function `f` to inner value + pub fn map<F>(self, f: F) -> $Self + where + F: FnOnce(u32) -> u32 + { + $Self(f(self.0)) + } + } + } +} + +/// `Hz^-1` +#[derive(Clone, Copy, Debug)] +pub struct IHertz(pub u32); + +impl IHertz { + /// Invert this quantity + pub fn invert(self) -> Hertz { + Hertz(self.0) + } +} + +map!(IHertz); + +/// `Hz` +#[derive(Clone, Copy, Debug)] +pub struct Hertz(pub u32); + +impl Hertz { + /// Invert this quantity + pub fn invert(self) -> IHertz { + IHertz(self.0) + } +} + +map!(Hertz); + +/// `us` +#[derive(Clone, Copy, Debug)] +pub struct Microseconds(pub u32); + +map!(Microseconds); + +/// `ms` +#[derive(Clone, Copy, Debug)] +pub struct Milliseconds(pub u32); + +map!(Milliseconds); + +/// `s` +#[derive(Clone, Copy, Debug)] +pub struct Seconds(pub u32); + +map!(Seconds); + +/// `u32` extension trait +pub trait U32Ext { + /// Wrap in `Hz` + fn hz(self) -> Hertz; + + /// Wrap in `Milliseconds` + fn ms(self) -> Milliseconds; + + /// Wrap in `Seconds` + fn s(self) -> Seconds; + + /// Wrap in `Microseconds` + fn us(self) -> Microseconds; +} + +impl U32Ext for u32 { + fn hz(self) -> Hertz { + Hertz(self) + } + + fn ms(self) -> Milliseconds { + Milliseconds(self) + } + + fn s(self) -> Seconds { + Seconds(self) + } + + fn us(self) -> Microseconds { + Microseconds(self) + } +} diff --git a/src/timer.rs b/src/timer.rs index bffc2f5e26bc18790a2c18e1ed832e87edc0eac6..41d41300e65266a2ba9ae33e85703cdc1bcdd5c1 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -5,8 +5,6 @@ use core::u16; use cast::{u16, u32}; use stm32f30x::{RCC, TIM7}; -use frequency; - /// Specialized `Result` type pub type Result<T> = ::core::result::Result<T, Error>; @@ -32,7 +30,7 @@ impl<'a> Timer<'a> { // Power up peripherals rcc.apb1enr.modify(|_, w| w.tim7en().enabled()); - let ratio = frequency::APB1 / frequency; + let ratio = ::apb1::FREQUENCY / frequency; let psc = u16((ratio - 1) / u32(u16::MAX)).unwrap(); tim7.psc.write(|w| w.psc().bits(psc)); let arr = u16(ratio / u32(psc + 1)).unwrap();