Browse Source

Merge branch 'master' into stm32f070-support

features/pwm
Jesse Braham 4 years ago
parent
commit
16bd62ea2b
  1. 4
      Cargo.toml
  2. 178
      src/i2c.rs
  3. 360
      src/serial.rs
  4. 190
      src/spi.rs
  5. 11
      src/timers.rs

4
Cargo.toml

@ -51,8 +51,8 @@ stm32f042 = ["stm32f0/stm32f0x2"]
stm32f030 = ["stm32f0/stm32f0x0"]
stm32f030x4 = ["stm32f030x6"]
stm32f030x6 = ["stm32f030"]
stm32f030x8 = ["stm32f030", "stm32f0/stm32f0x0"]
stm32f030xc = ["stm32f030", "stm32f0/stm32f0x0"]
stm32f030x8 = ["stm32f030"]
stm32f030xc = ["stm32f030"]
stm32f070 = ["stm32f0/stm32f0x0"]
stm32f070x6 = ["stm32f070"]
stm32f070xb = ["stm32f070"]

178
src/i2c.rs

@ -1,41 +1,83 @@
#[cfg(feature = "stm32f042")]
use crate::stm32::{I2C1, RCC};
use core::ops::Deref;
use crate::stm32;
use embedded_hal::blocking::i2c::{Write, WriteRead};
use core::cmp;
#[cfg(feature = "stm32f042")]
use crate::gpio::gpioa::{PA10, PA11, PA12, PA9};
#[cfg(feature = "stm32f042")]
use crate::gpio::gpiob::{PB10, PB11, PB13, PB14, PB6, PB7, PB8, PB9};
#[cfg(feature = "stm32f042")]
use crate::gpio::gpiof::{PF0, PF1};
#[cfg(feature = "stm32f042")]
use crate::gpio::{Alternate, AF1, AF4, AF5};
use crate::gpio::*;
use crate::time::{KiloHertz, U32Ext};
use core::cmp;
/// I2C abstraction
pub struct I2c<I2C, PINS> {
pub struct I2c<I2C, SCLPIN, SDAPIN> {
i2c: I2C,
pins: PINS,
pins: (SCLPIN, SDAPIN),
}
pub trait Pins<I2c> {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PA9<Alternate<AF4>>, PA10<Alternate<AF4>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PA11<Alternate<AF5>>, PA12<Alternate<AF5>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PB6<Alternate<AF1>>, PB7<Alternate<AF1>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PB8<Alternate<AF1>>, PB9<Alternate<AF1>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PB10<Alternate<AF1>>, PB11<Alternate<AF1>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PB13<Alternate<AF5>>, PB14<Alternate<AF5>>) {}
#[cfg(feature = "stm32f042")]
impl Pins<I2C1> for (PF1<Alternate<AF1>>, PF0<Alternate<AF1>>) {}
pub trait SclPin<I2C> {}
pub trait SdaPin<I2C> {}
macro_rules! i2c_pins {
($($I2C:ident => {
scl => [$($scl:ty),+ $(,)*],
sda => [$($sda:ty),+ $(,)*],
})+) => {
$(
$(
impl SclPin<stm32::$I2C> for $scl {}
)+
$(
impl SdaPin<stm32::$I2C> for $sda {}
)+
)+
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
i2c_pins! {
I2C1 => {
scl => [gpioa::PA11<Alternate<AF5>>, gpiob::PB6<Alternate<AF1>>, gpiob::PB8<Alternate<AF1>>],
sda => [gpioa::PA12<Alternate<AF5>>, gpiob::PB7<Alternate<AF1>>, gpiob::PB9<Alternate<AF1>>],
}
}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x6",
feature = "stm32f030xc"
))]
i2c_pins! {
I2C1 => {
scl => [gpioa::PA9<Alternate<AF4>>],
sda => [gpioa::PA10<Alternate<AF4>>],
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030x6"))]
i2c_pins! {
I2C1 => {
scl => [gpiob::PB10<Alternate<AF1>>],
sda => [gpiob::PB11<Alternate<AF1>>],
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030xc"))]
i2c_pins! {
I2C1 => {
scl => [gpiob::PB13<Alternate<AF5>>, gpiof::PF1<Alternate<AF1>>],
sda => [gpiob::PB14<Alternate<AF5>>, gpiof::PF0<Alternate<AF1>>],
}
}
#[cfg(any(feature = "stm32f030x8", feature = "stm32f030xc"))]
i2c_pins! {
I2C2 => {
scl => [gpiob::PB10<Alternate<AF1>>],
sda => [gpiob::PB11<Alternate<AF1>>],
}
}
#[cfg(feature = "stm32f030xc")]
i2c_pins! {
I2C2 => {
scl => [gpiob::PB13<Alternate<AF5>>],
sda => [gpiob::PB14<Alternate<AF5>>],
}
}
#[derive(Debug)]
pub enum Error {
@ -43,24 +85,50 @@ pub enum Error {
NACK,
}
#[cfg(feature = "stm32f042")]
impl<PINS> I2c<I2C1, PINS> {
pub fn i2c1(i2c: I2C1, pins: PINS, speed: KiloHertz) -> Self
where
PINS: Pins<I2C1>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
/* Enable clock for I2C1 */
rcc.apb1enr.modify(|_, w| w.i2c1en().set_bit());
/* Reset I2C1 */
rcc.apb1rstr.modify(|_, w| w.i2c1rst().set_bit());
rcc.apb1rstr.modify(|_, w| w.i2c1rst().clear_bit());
macro_rules! i2c {
($($I2C:ident: ($i2c:ident, $i2cXen:ident, $i2cXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
$(
use crate::stm32::$I2C;
impl<SCLPIN, SDAPIN> I2c<$I2C, SCLPIN, SDAPIN> {
pub fn $i2c(i2c: $I2C, pins: (SCLPIN, SDAPIN), speed: KiloHertz) -> Self
where
SCLPIN: SclPin<$I2C>,
SDAPIN: SdaPin<$I2C>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*stm32::RCC::ptr()) };
/* Enable clock for I2C */
rcc.$apbenr.modify(|_, w| w.$i2cXen().set_bit());
/* Reset I2C */
rcc.$apbrstr.modify(|_, w| w.$i2cXrst().set_bit());
rcc.$apbrstr.modify(|_, w| w.$i2cXrst().clear_bit());
I2c { i2c, pins }.i2c_init(speed)
}
}
)+
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
i2c! {
I2C1: (i2c1, i2c1en, i2c1rst, apb1enr, apb1rstr),
}
#[cfg(any(feature = "stm32f030xc", feature = "stm32f030xc"))]
i2c! {
I2C2: (i2c2, i2c2en, i2c2rst, apb1enr, apb1rstr),
}
// It's s needed for the impls, but rustc doesn't recognize that
#[allow(dead_code)]
type I2cRegisterBlock = stm32::i2c1::RegisterBlock;
impl<I2C, SCLPIN, SDAPIN> I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
fn i2c_init(self: Self, speed: KiloHertz) -> Self {
/* Make sure the I2C unit is disabled so we can configure it */
i2c.cr1.modify(|_, w| w.pe().clear_bit());
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());
// Calculate settings for I2C speed modes
let presc;
@ -88,7 +156,7 @@ impl<PINS> I2c<I2C1, PINS> {
}
/* Enable I2C signal generator, and configure I2C for 400KHz full speed */
i2c.timingr.write(|w| {
self.i2c.timingr.write(|w| {
w.presc()
.bits(presc)
.scldel()
@ -102,12 +170,12 @@ impl<PINS> I2c<I2C1, PINS> {
});
/* Enable the I2C processing */
i2c.cr1.modify(|_, w| w.pe().set_bit());
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
I2c { i2c, pins }
self
}
pub fn release(self) -> (I2C1, PINS) {
pub fn release(self) -> (I2C, (SCLPIN, SDAPIN)) {
(self.i2c, self.pins)
}
@ -136,8 +204,10 @@ impl<PINS> I2c<I2C1, PINS> {
}
}
#[cfg(feature = "stm32f042")]
impl<PINS> WriteRead for I2c<I2C1, PINS> {
impl<I2C, SCLPIN, SDAPIN> WriteRead for I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
type Error = Error;
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
@ -214,8 +284,10 @@ impl<PINS> WriteRead for I2c<I2C1, PINS> {
}
}
#[cfg(feature = "stm32f042")]
impl<PINS> Write for I2c<I2C1, PINS> {
impl<I2C, SCLPIN, SDAPIN> Write for I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {

360
src/serial.rs

@ -1,5 +1,30 @@
//! API for the integrated USART ports
//!
//! This only implements the usual asynchronous bidirectional 8-bit transfers, everything else is missing
//!
//! # Example
//! Serial Echo
//! ``` no_run
//! use stm32f0xx_hal as hal;
//!
//! use crate::hal::stm32;
//! use crate::hal::prelude::*;
//! use crate::hal::serial::Serial;
//! use nb::block;
//!
//! let mut p = stm32::Peripherals::take().unwrap();
//!
//! let mut led = gpioa.pa1.into_push_pull_pull_output();
//! let rcc = p.RCC.constrain().cfgr.freeze();
//! let mut timer = Timer::tim1(p.TIM1, Hertz(1), clocks);
//! loop {
//! led.toggle();
//! block!(timer.wait()).ok();
//! }
//! ```
use core::fmt::{Result, Write};
use core::marker::PhantomData;
use core::ops::Deref;
use core::ptr;
use embedded_hal::prelude::*;
@ -7,7 +32,7 @@ use nb::block;
use void::Void;
#[cfg(any(feature = "stm32f042", feature = "stm32f030", feature = "stm32f070"))]
use crate::stm32::{RCC, USART1, USART2};
use crate::stm32;
use crate::gpio::*;
use crate::rcc::Clocks;
@ -36,113 +61,158 @@ pub enum Error {
_Extensible,
}
pub trait Pins<USART> {}
#[cfg(any(feature = "stm32f030", feature = "stm32f042", feature = "stm32f070"))]
impl Pins<USART1> for (gpioa::PA9<Alternate<AF1>>, gpioa::PA10<Alternate<AF1>>) {}
#[cfg(any(feature = "stm32f030", feature = "stm32f042", feature = "stm32f070"))]
impl Pins<USART1> for (gpiob::PB6<Alternate<AF0>>, gpiob::PB7<Alternate<AF0>>) {}
#[cfg(any(feature = "stm32f030", feature = "stm32f042", feature = "stm32f070"))]
impl Pins<USART1> for (gpioa::PA9<Alternate<AF1>>, gpiob::PB7<Alternate<AF0>>) {}
#[cfg(any(feature = "stm32f030", feature = "stm32f042", feature = "stm32f070"))]
impl Pins<USART1> for (gpiob::PB6<Alternate<AF0>>, gpioa::PA10<Alternate<AF1>>) {}
pub trait TxPin<USART> {}
pub trait RxPin<USART> {}
macro_rules! usart_pins {
($($USART:ident => {
tx => [$($tx:ty),+ $(,)*],
rx => [$($rx:ty),+ $(,)*],
})+) => {
$(
$(
impl TxPin<stm32::$USART> for $tx {}
)+
$(
impl RxPin<stm32::$USART> for $rx {}
)+
)+
}
}
#[cfg(any(feature = "stm32f030", feature = "stm32f042"))]
usart_pins! {
USART1 => {
tx => [gpioa::PA9<Alternate<AF1>>, gpiob::PB6<Alternate<AF0>>],
rx => [gpioa::PA10<Alternate<AF1>>, gpiob::PB6<Alternate<AF0>>],
}
}
#[cfg(feature = "stm32f030x6")]
impl Pins<USART1> for (gpioa::PA2<Alternate<AF1>>, gpioa::PA3<Alternate<AF1>>) {}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030xc",
))]
impl Pins<USART2> for (gpioa::PA2<Alternate<AF1>>, gpioa::PA3<Alternate<AF1>>) {}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030xc",
feature = "stm32f070",
))]
impl Pins<USART2> for (gpioa::PA2<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>) {}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030xc",
feature = "stm32f070",
))]
impl Pins<USART2> for (gpioa::PA14<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>) {}
usart_pins! {
USART1 => {
tx => [gpioa::PA2<Alternate<AF1>>, gpioa::PA14<Alternate<AF1>>],
rx => [gpioa::PA3<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>],
}
}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030xc",
feature = "stm32f070",
))]
impl Pins<USART2> for (gpioa::PA14<Alternate<AF1>>, gpioa::PA3<Alternate<AF1>>) {}
usart_pins! {
USART2 => {
tx => [gpioa::PA2<Alternate<AF1>>, gpioa::PA14<Alternate<AF1>>],
rx => [gpioa::PA3<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>],
}
}
#[cfg(feature = "stm32f030xc")]
usart_pins! {
USART3 => {
// According to the datasheet PB10 is both tx and rx, but in stm32cubemx it's only tx
tx => [gpiob::PB10<Alternate<AF4>>, gpioc::PC4<Alternate<AF1>>, gpioc::PC10<Alternate<AF1>>],
rx => [gpiob::PB11<Alternate<AF4>>, gpioc::PC5<Alternate<AF1>>, gpioc::PC11<Alternate<AF1>>],
}
USART4 => {
tx => [gpioa::PA0<Alternate<AF4>>, gpioc::PC10<Alternate<AF0>>],
rx => [gpioa::PA1<Alternate<AF4>>, gpioc::PC11<Alternate<AF0>>],
}
USART5 => {
tx => [gpiob::PB3<Alternate<AF4>>, gpioc::PC12<Alternate<AF2>>],
rx => [gpiob::PB4<Alternate<AF4>>, gpiod::PD2<Alternate<AF2>>],
}
USART6 => {
tx => [gpioa::PA4<Alternate<AF5>>, gpioc::PC0<Alternate<AF2>>],
rx => [gpioa::PA5<Alternate<AF5>>, gpioc::PC1<Alternate<AF2>>],
}
}
/// Serial abstraction
pub struct Serial<USART, PINS> {
pub struct Serial<USART, TXPIN, RXPIN> {
usart: USART,
pins: PINS,
pins: (TXPIN, RXPIN),
}
/// Serial receiver
pub struct Rx<USART> {
_usart: PhantomData<USART>,
// This is ok, because the USART types only contains PhantomData
usart: *const USART,
}
/// Serial transmitter
pub struct Tx<USART> {
_usart: PhantomData<USART>,
// This is ok, because the USART types only contains PhantomData
usart: *const USART,
}
/// USART1
#[cfg(any(feature = "stm32f042", feature = "stm32f030", feature = "stm32f070"))]
impl<PINS> Serial<USART1, PINS> {
pub fn usart1(usart: USART1, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
where
PINS: Pins<USART1>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
/* Enable clock for USART */
rcc.apb2enr.modify(|_, w| w.usart1en().set_bit());
// Calculate correct baudrate divisor on the fly
let brr = clocks.pclk().0 / baud_rate.0;
usart.brr.write(|w| unsafe { w.bits(brr) });
/* Reset other registers to disable advanced USART features */
usart.cr2.reset();
usart.cr3.reset();
/* Enable transmission and receiving */
usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
Serial { usart, pins }
macro_rules! usart {
($($USART:ident: ($usart:ident, $usartXen:ident, $apbenr:ident),)+) => {
$(
use crate::stm32::$USART;
impl<TXPIN, RXPIN> Serial<$USART, TXPIN, RXPIN> {
/// Creates a new serial instance
pub fn $usart(usart: $USART, pins: (TXPIN, RXPIN), baud_rate: Bps, clocks: Clocks) -> Self
where
TXPIN: TxPin<$USART>,
RXPIN: RxPin<$USART>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*stm32::RCC::ptr()) };
/* Enable clock for USART */
rcc.$apbenr.modify(|_, w| w.$usartXen().set_bit());
// Calculate correct baudrate divisor on the fly
let brr = clocks.pclk().0 / baud_rate.0;
usart.brr.write(|w| unsafe { w.bits(brr) });
/* Reset other registers to disable advanced USART features */
usart.cr2.reset();
usart.cr3.reset();
/* Enable transmission and receiving */
usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
Serial { usart, pins }
}
}
)+
}
}
pub fn split(self) -> (Tx<USART1>, Rx<USART1>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
pub fn release(self) -> (USART1, PINS) {
(self.usart, self.pins)
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
usart! {
USART1: (usart1, usart1en, apb2enr),
}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030xc"
))]
usart! {
USART2: (usart2, usart2en, apb1enr),
}
#[cfg(any(feature = "stm32f030xc"))]
usart! {
USART3: (usart3, usart3en, apb1enr),
USART4: (usart4, usart4en, apb1enr),
USART5: (usart5, usart5en, apb1enr),
USART6: (usart6, usart6en, apb2enr),
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030", feature = "stm32f070"))]
impl embedded_hal::serial::Read<u8> for Rx<USART1> {
// It's s needed for the impls, but rustc doesn't recognize that
#[allow(dead_code)]
type SerialRegisterBlock = stm32::usart1::RegisterBlock;
impl<USART> embedded_hal::serial::Read<u8> for Rx<USART>
where
USART: Deref<Target = SerialRegisterBlock>,
{
type Error = Error;
/// Tries to read a byte from the uart
fn read(&mut self) -> nb::Result<u8, Error> {
// NOTE(unsafe) atomic read with no side effects
let isr = unsafe { (*USART1::ptr()).isr.read() };
let isr = unsafe { (*self.usart).isr.read() };
Err(if isr.pe().bit_is_set() {
nb::Error::Other(Error::Parity)
@ -154,20 +224,23 @@ impl embedded_hal::serial::Read<u8> for Rx<USART1> {
nb::Error::Other(Error::Overrun)
} else if isr.rxne().bit_is_set() {
// NOTE(read_volatile) see `write_volatile` below
return Ok(unsafe { ptr::read_volatile(&(*USART1::ptr()).rdr as *const _ as *const _) });
return Ok(unsafe { ptr::read_volatile(&(*self.usart).rdr as *const _ as *const _) });
} else {
nb::Error::WouldBlock
})
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030", feature = "stm32f070"))]
impl embedded_hal::serial::Write<u8> for Tx<USART1> {
impl<USART> embedded_hal::serial::Write<u8> for Tx<USART>
where
USART: Deref<Target = SerialRegisterBlock>,
{
type Error = Void;
/// Ensures that none of the previously written words are still buffered
fn flush(&mut self) -> nb::Result<(), Self::Error> {
// NOTE(unsafe) atomic read with no side effects
let isr = unsafe { (*USART1::ptr()).isr.read() };
let isr = unsafe { (*self.usart).isr.read() };
if isr.tc().bit_is_set() {
Ok(())
@ -176,14 +249,16 @@ impl embedded_hal::serial::Write<u8> for Tx<USART1> {
}
}
/// Tries to write a byte to the uart
/// Fails if the transmit buffer is full
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
// NOTE(unsafe) atomic read with no side effects
let isr = unsafe { (*USART1::ptr()).isr.read() };
let isr = unsafe { (*self.usart).isr.read() };
if isr.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(&(*USART1::ptr()).tdr as *const _ as *mut _, byte) }
unsafe { ptr::write_volatile(&(*self.usart).tdr as *const _ as *mut _, byte) }
Ok(())
} else {
Err(nb::Error::WouldBlock)
@ -191,118 +266,27 @@ impl embedded_hal::serial::Write<u8> for Tx<USART1> {
}
}
/// USART2
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030x8",
feature = "stm32f070",
))]
impl<PINS> Serial<USART2, PINS> {
pub fn usart2(usart: USART2, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
where
PINS: Pins<USART2>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
/* Enable clock for USART */
rcc.apb1enr.modify(|_, w| w.usart2en().set_bit());
// Calculate correct baudrate divisor on the fly
let brr = clocks.pclk().0 / baud_rate.0;
usart.brr.write(|w| unsafe { w.bits(brr) });
/* Reset other registers to disable advanced USART features */
usart.cr2.reset();
usart.cr3.reset();
/* Enable transmission and receiving */
usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
Serial { usart, pins }
}
pub fn split(self) -> (Tx<USART2>, Rx<USART2>) {
impl<USART, TXPIN, RXPIN> Serial<USART, TXPIN, RXPIN>
where
USART: Deref<Target = SerialRegisterBlock>,
{
/// Splits the UART Peripheral in a Tx and an Rx part
/// This is required for sending/receiving
pub fn split(self) -> (Tx<USART>, Rx<USART>) {
(
Tx {
_usart: PhantomData,
usart: &self.usart as *const _,
},
Rx {
_usart: PhantomData,
usart: &self.usart as *const _,
},
)
}
pub fn release(self) -> (USART2, PINS) {
pub fn release(self) -> (USART, (TXPIN, RXPIN)) {
(self.usart, self.pins)
}
}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030x8",
feature = "stm32f070",
))]
impl embedded_hal::serial::Read<u8> for Rx<USART2> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
// NOTE(unsafe) atomic read with no side effects
let isr = unsafe { (*USART2::ptr()).isr.read() };
Err(if isr.pe().bit_is_set() {
nb::Error::Other(Error::Parity)
} else if isr.fe().bit_is_set() {
nb::Error::Other(Error::Framing)
} else if isr.nf().bit_is_set() {
nb::Error::Other(Error::Noise)
} else if isr.ore().bit_is_set() {
nb::Error::Other(Error::Overrun)
} else if isr.rxne().bit_is_set() {
// NOTE(read_volatile) see `write_volatile` below
return Ok(unsafe { ptr::read_volatile(&(*USART2::ptr()).rdr as *const _ as *const _) });
} else {
nb::Error::WouldBlock
})
}
}
#[cfg(any(
feature = "stm32f042",
feature = "stm32f030x8",
feature = "stm32f030x8",
feature = "stm32f070",
))]
impl embedded_hal::serial::Write<u8> for Tx<USART2> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
// NOTE(unsafe) atomic read with no side effects
let isr = unsafe { (*USART2::ptr()).isr.read() };
if isr.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 isr = unsafe { (*USART2::ptr()).isr.read() };
if isr.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(&(*USART2::ptr()).tdr as *const _ as *mut _, byte) }
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<USART> Write for Tx<USART>
where
Tx<USART>: embedded_hal::serial::Write<u8>,

190
src/spi.rs

@ -1,11 +1,17 @@
use core::ops::Deref;
use core::ptr;
use nb;
pub use embedded_hal::spi::{Mode, Phase, Polarity};
#[cfg(feature = "stm32f042")]
use crate::stm32::{RCC, SPI1};
use crate::stm32;
// TODO Put this inside the macro
// Currently that causes a compiler panic
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
use crate::stm32::SPI1;
#[cfg(any(feature = "stm32f030x8", feature = "stm32f030xc"))]
use crate::stm32::SPI2;
use crate::gpio::*;
use crate::rcc::Clocks;
@ -25,49 +31,124 @@ pub enum Error {
}
/// SPI abstraction
pub struct Spi<SPI, PINS> {
pub struct Spi<SPI, SCKPIN, MISOPIN, MOSIPIN> {
spi: SPI,
pins: PINS,
pins: (SCKPIN, MISOPIN, MOSIPIN),
}
pub trait Pins<Spi> {}
#[cfg(feature = "stm32f042")]
impl Pins<SPI1>
for (
gpioa::PA5<Alternate<AF0>>,
gpioa::PA6<Alternate<AF0>>,
gpioa::PA7<Alternate<AF0>>,
)
{}
#[cfg(feature = "stm32f042")]
impl Pins<SPI1>
for (
gpiob::PB3<Alternate<AF0>>,
gpiob::PB4<Alternate<AF0>>,
gpiob::PB5<Alternate<AF0>>,
)
{}
#[cfg(feature = "stm32f042")]
impl<PINS> Spi<SPI1, PINS> {
pub fn spi1<F>(spi: SPI1, pins: PINS, mode: Mode, speed: F, clocks: Clocks) -> Self
where
PINS: Pins<SPI1>,
F: Into<Hertz>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
pub trait SckPin<SPI> {}
pub trait MisoPin<SPI> {}
pub trait MosiPin<SPI> {}
macro_rules! spi_pins {
($($SPI:ident => {
sck => [$($sck:ty),+ $(,)*],
miso => [$($miso:ty),+ $(,)*],
mosi => [$($mosi:ty),+ $(,)*],
})+) => {
$(
$(
impl SckPin<stm32::$SPI> for $sck {}
)+
$(
impl MisoPin<stm32::$SPI> for $miso {}
)+
$(
impl MosiPin<stm32::$SPI> for $mosi {}
)+
)+
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
spi_pins! {
SPI1 => {
sck => [gpioa::PA5<Alternate<AF0>>, gpiob::PB3<Alternate<AF0>>],
miso => [gpioa::PA6<Alternate<AF0>>, gpiob::PB4<Alternate<AF0>>],
mosi => [gpioa::PA7<Alternate<AF0>>, gpiob::PB5<Alternate<AF0>>],
}
}
#[cfg(feature = "stm32f030x6")]
spi_pins! {
SPI1 => {
sck => [gpiob::PB13<Alternate<AF0>>],
miso => [gpiob::PB14<Alternate<AF0>>],
mosi => [gpiob::PB15<Alternate<AF0>>],
}
}
#[cfg(any(feature = "stm32f030x8", feature = "stm32f030xc"))]
spi_pins! {
SPI2 => {
sck => [gpiob::PB13<Alternate<AF0>>],
miso => [gpiob::PB14<Alternate<AF0>>],
mosi => [gpiob::PB15<Alternate<AF0>>],
}
}
#[cfg(feature = "stm32f030xc")]
spi_pins! {
SPI2 => {
sck => [gpiob::PB10<Alternate<AF5>>],
miso => [gpioc::PC2<Alternate<AF1>>],
mosi => [gpioc::PC3<Alternate<AF1>>],
}
}
macro_rules! spi {
($($SPI:ident: ($spi:ident, $spiXen:ident, $spiXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
$(
impl<SCKPIN, MISOPIN, MOSIPIN> Spi<$SPI, SCKPIN, MISOPIN, MOSIPIN> {
pub fn $spi<F>(
spi: $SPI,
pins: (SCKPIN, MISOPIN, MOSIPIN),
mode: Mode,
speed: F,
clocks: Clocks,
) -> Self
where
SCKPIN: SckPin<$SPI>,
MISOPIN: MisoPin<$SPI>,
MOSIPIN: MosiPin<$SPI>,
F: Into<Hertz>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*stm32::RCC::ptr()) };
/* Enable clock for SPI1 */
rcc.apb2enr.modify(|_, w| w.spi1en().set_bit());
/* Enable clock for SPI */
rcc.$apbenr.modify(|_, w| w.$spiXen().set_bit());
/* Reset SPI */
rcc.$apbrstr.modify(|_, w| w.$spiXrst().set_bit());
rcc.$apbrstr.modify(|_, w| w.$spiXrst().clear_bit());
Spi { spi, pins }.spi_init(mode, speed, clocks)
}
}
)+
}
}
#[cfg(any(feature = "stm32f042", feature = "stm32f030"))]
spi! {
SPI1: (spi1, spi1en, spi1rst, apb2enr, apb2rstr),
}
#[cfg(any(feature = "stm32f030x8", feature = "stm32f030xc"))]
spi! {
SPI2: (spi2, spi2en, spi2rst, apb1enr, apb1rstr),
}
/* Reset SPI1 */
rcc.apb2rstr.modify(|_, w| w.spi1rst().set_bit());
rcc.apb2rstr.modify(|_, w| w.spi1rst().clear_bit());
// It's s needed for the impls, but rustc doesn't recognize that
#[allow(dead_code)]
type SpiRegisterBlock = stm32::spi1::RegisterBlock;
impl<SPI, SCKPIN, MISOPIN, MOSIPIN> Spi<SPI, SCKPIN, MISOPIN, MOSIPIN>
where
SPI: Deref<Target = SpiRegisterBlock>,
{
fn spi_init<F>(self: Self, mode: Mode, speed: F, clocks: Clocks) -> Self
where
F: Into<Hertz>,
{
/* Make sure the SPI unit is disabled so we can configure it */
spi.cr1.modify(|_, w| w.spe().clear_bit());
self.spi.cr1.modify(|_, w| w.spe().clear_bit());
// FRXTH: 8-bit threshold on RX FIFO
// DS: 8-bit data size
@ -75,7 +156,8 @@ impl<PINS> Spi<SPI1, PINS> {
//
// NOTE(unsafe): DS reserved bit patterns are 0b0000, 0b0001, and 0b0010. 0b0111 is valid
// (reference manual, pp 804)
spi.cr2
self.spi
.cr2
.write(|w| unsafe { w.frxth().set_bit().ds().bits(0b0111).ssoe().clear_bit() });
let br = match clocks.pclk().0 / speed.into().0 {
@ -97,7 +179,7 @@ impl<PINS> Spi<SPI1, PINS> {
// dff: 8 bit frames
// bidimode: 2-line unidirectional
// spe: enable the SPI bus
spi.cr1.write(|w| unsafe {
self.spi.cr1.write(|w| unsafe {
w.cpha()
.bit(mode.phase == Phase::CaptureOnSecondTransition)
.cpol()
@ -120,16 +202,18 @@ impl<PINS> Spi<SPI1, PINS> {
.set_bit()
});
Spi { spi, pins }
self
}
pub fn release(self) -> (SPI1, PINS) {
pub fn release(self) -> (SPI, (SCKPIN, MISOPIN, MOSIPIN)) {
(self.spi, self.pins)
}
}
#[cfg(feature = "stm32f042")]
impl<PINS> ::embedded_hal::spi::FullDuplex<u8> for Spi<SPI1, PINS> {
impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::spi::FullDuplex<u8>
for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN>
where
SPI: Deref<Target = SpiRegisterBlock>,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
@ -169,7 +253,15 @@ impl<PINS> ::embedded_hal::spi::FullDuplex<u8> for Spi<SPI1, PINS> {
}
}
#[cfg(feature = "stm32f042")]
impl<PINS> ::embedded_hal::blocking::spi::transfer::Default<u8> for Spi<SPI1, PINS> {}
#[cfg(feature = "stm32f042")]
impl<PINS> ::embedded_hal::blocking::spi::write::Default<u8> for Spi<SPI1, PINS> {}
impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::transfer::Default<u8>
for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN>
where
SPI: Deref<Target = SpiRegisterBlock>,
{
}
impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::write::Default<u8>
for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN>
where
SPI: Deref<Target = SpiRegisterBlock>,
{
}

11
src/timers.rs

@ -24,10 +24,7 @@
//! }
//! ```
#[cfg(any(feature = "stm32f030", feature = "stm32f070"))]
use crate::stm32::{RCC, TIM1, TIM14, TIM15, TIM16, TIM17, TIM3, TIM6, TIM7};
#[cfg(feature = "stm32f042")]
use crate::stm32::{RCC, TIM1, TIM14, TIM16, TIM17, TIM2, TIM3};
use crate::stm32;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;
@ -111,6 +108,7 @@ impl Periodic for Timer<SYST> {}
macro_rules! timers {
($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
$(
use crate::stm32::$TIM;
impl Timer<$TIM> {
// XXX(why not name this `new`?) bummer: constructors need to have different names
// even if the `$TIM` are non overlapping (compare to the `free` function below
@ -121,7 +119,7 @@ macro_rules! timers {
T: Into<Hertz>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
let rcc = unsafe { &(*stm32::RCC::ptr()) };
// enable and reset peripheral to a clean slate state
rcc.$apbenr.modify(|_, w| w.$timXen().set_bit());
@ -159,8 +157,7 @@ macro_rules! timers {
/// Releases the TIM peripheral
pub fn release(self) -> $TIM {
use crate::stm32::RCC;
let rcc = unsafe { &(*RCC::ptr()) };
let rcc = unsafe { &(*stm32::RCC::ptr()) };
// Pause counter
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
// Disable timer

Loading…
Cancel
Save