Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make peripheral constructors fallible (fixes #276) #331

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ rustc-args = ["--cfg", "docsrs"]

[dependencies]
cfg-if = "1.0.0"
cortex-m = "0.7.4"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
defmt = { version = ">=0.2.3, <0.4.0", optional = true }
embedded-dma = "0.2.0"
Expand Down
3 changes: 2 additions & 1 deletion examples/i2c_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ fn main() -> ! {
100.kHz().try_into().unwrap(),
clocks,
&mut rcc.apb1,
);
)
.unwrap();

hprintln!("Start i2c scanning...").expect("Error using hprintln.");
hprintln!().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion examples/serial_dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() -> ! {
.pa10
.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh),
);
let serial = Serial::new(dp.USART1, pins, 9600.Bd(), clocks, &mut rcc.apb2);
let serial = Serial::new(dp.USART1, pins, 9600.Bd(), clocks, &mut rcc.apb2).unwrap();
let (tx, rx) = serial.split();

let dma1 = dp.DMA1.split(&mut rcc.ahb);
Expand Down
2 changes: 1 addition & 1 deletion examples/serial_echo_rtic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ mod app {
);
pins.1.internal_pull_up(&mut gpioa.pupdr, true);
let mut serial: SerialType =
Serial::new(cx.device.USART1, pins, 19200.Bd(), clocks, &mut rcc.apb2);
Serial::new(cx.device.USART1, pins, 19200.Bd(), clocks, &mut rcc.apb2).unwrap();
serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Toggle::On);

rprintln!("post init");
Expand Down
24 changes: 16 additions & 8 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ use cfg_if::cfg_if;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
/// Configuration
Config,
/// Arbitration loss
Arbitration,
/// Bus error
Expand Down Expand Up @@ -117,13 +119,15 @@ impl<I2C, SCL, SDA> I2c<I2C, (SCL, SDA)> {
freq: Hertz,
clocks: Clocks,
bus: &mut <I2C as rcc::RccBus>::Bus,
) -> Self
) -> Result<Self, Error>
where
I2C: Instance,
SCL: SclPin<I2C>,
SDA: SdaPin<I2C>,
{
crate::assert!(freq.integer() <= 1_000_000);
if freq.integer() > 1_000_000 {
return Err(Error::Config);
}

I2C::enable(bus);
I2C::reset(bus);
Expand Down Expand Up @@ -175,11 +179,15 @@ impl<I2C, SCL, SDA> I2c<I2C, (SCL, SDA)> {
(presc, scll, sclh, sdadel, scldel)
};

crate::assert!(presc < 16);
crate::assert!(scldel < 16);
crate::assert!(sdadel < 16);
let sclh = crate::unwrap!(u8::try_from(sclh).ok());
let scll = crate::unwrap!(u8::try_from(scll).ok());
if presc >= 16 || scldel >= 16 || sdadel >= 16 {
return Err(Error::Config);
}
let Ok(sclh) = u8::try_from(sclh) else {
return Err(Error::Config);
};
let Ok(scll) = u8::try_from(scll) else {
return Err(Error::Config);
};

// Configure for "fast mode" (400 KHz)
// NOTE(write): writes all non-reserved bits.
Expand All @@ -199,7 +207,7 @@ impl<I2C, SCL, SDA> I2c<I2C, (SCL, SDA)> {
// Enable the peripheral
i2c.cr1.modify(|_, w| w.pe().set_bit());

Self { i2c, pins }
Ok(Self { i2c, pins })
}

/// Get access to the underlying register block.
Expand Down
12 changes: 8 additions & 4 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ mod split {

pub use split::{Rx, Tx};

use self::config::InvalidBaudrate;

impl<Usart, Tx, Rx> Serial<Usart, (Tx, Rx)>
where
Usart: Instance,
Expand All @@ -464,7 +466,7 @@ where
config: Config,
clocks: Clocks,
apb: &mut <Usart as rcc::RccBus>::Bus,
) -> Self
) -> Result<Self, InvalidBaudrate>
where
Usart: Instance,
Tx: TxPin<Usart>,
Expand All @@ -483,7 +485,9 @@ where
usart.cr1.modify(|_, w| w.ue().disabled());

let brr = Usart::clock(&clocks).integer() / config.baudrate.integer();
crate::assert!(brr >= 16, "impossible baud rate");
if brr < 16 {
return Err(InvalidBaudrate);
}
usart.brr.write(|w| w.brr().bits(brr as u16));

// We currently support only eight data bits as supporting a full-blown
Expand All @@ -510,7 +514,7 @@ where
// Finally enable the configured UART.
usart.cr1.modify(|_, w| w.ue().enabled());

Self { usart, pins }
Ok(Self { usart, pins })
}

/// Get access to the underlying register block.
Expand Down Expand Up @@ -544,7 +548,7 @@ where
/// ```
/// let dp = pac::Peripherals::take().unwrap();
///
/// (tx, rx) = Serial::new(dp.USART1, ...).split();
/// (tx, rx) = Serial::new(dp.USART1, ...).unwrap().split();
///
/// // Do something with tx and rx
///
Expand Down
4 changes: 4 additions & 0 deletions src/serial/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ impl Config {
}
}

/// Invalid baud rate.
#[derive(Debug)]
pub struct InvalidBaudrate;

impl Default for Config {
/// Creates a new configuration with typically used parameters: 115,200
/// Baud 8N1.
Expand Down
56 changes: 34 additions & 22 deletions testsuite/tests/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const TEST_MSG: [u8; 8] = [0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xaa, 0xbb];

fn test_test_msg_loopback(state: &mut State, config: impl Into<Config>) {
let (usart, pins) = unwrap!(state.serial1.take()).free();
let mut serial = Serial::new(usart, pins, config, state.clocks, &mut state.apb2);
let mut serial = Serial::new(usart, pins, config, state.clocks, &mut state.apb2).unwrap();

for i in &TEST_MSG {
unwrap!(nb::block!(serial.write(*i)));
Expand All @@ -75,7 +75,7 @@ fn trigger_event<Usart, Pins>(
let mut events = EnumSet::new();
events.insert(event);
// Clear events, so that previously triggered events do not fire
// the now configured interupt imediatly.
// the now configured interrupt immediately.
serial.clear_events();
serial.configure_interrupts(events);
// Check that the interrupt has not been run, since the configuration
Expand Down Expand Up @@ -153,26 +153,33 @@ mod tests {
9600.Bd(),
clocks,
&mut rcc.apb2,
);
)
.unwrap();

unsafe { cortex_m::peripheral::NVIC::unmask(serial1.interrupt()) }

super::State {
serial1: Some(serial1),
serial_slow: Some(Serial::new(
dp.USART2,
(cs_pair_1.0, cs_pair_2.1),
BAUD_SLOW,
clocks,
&mut rcc.apb1,
)),
serial_fast: Some(Serial::new(
dp.USART3,
(cs_pair_2.0, cs_pair_1.1),
BAUD_FAST,
clocks,
&mut rcc.apb1,
)),
serial_slow: Some(
Serial::new(
dp.USART2,
(cs_pair_1.0, cs_pair_2.1),
BAUD_SLOW,
clocks,
&mut rcc.apb1,
)
.unwrap(),
),
serial_fast: Some(
Serial::new(
dp.USART3,
(cs_pair_2.0, cs_pair_1.1),
BAUD_FAST,
clocks,
&mut rcc.apb1,
)
.unwrap(),
),
clocks,
apb1: rcc.apb1,
apb2: rcc.apb2,
Expand All @@ -195,7 +202,8 @@ mod tests {
#[test]
fn test_overrun(state: &mut super::State) {
let (usart, pins) = unwrap!(state.serial1.take()).free();
let mut serial = Serial::new(usart, pins, 115200.Bd(), state.clocks, &mut state.apb2);
let mut serial =
Serial::new(usart, pins, 115200.Bd(), state.clocks, &mut state.apb2).unwrap();
// Provoke an overrun
unwrap!(serial.bwrite_all(&TEST_MSG));

Expand Down Expand Up @@ -296,7 +304,8 @@ mod tests {
config_even,
state.clocks,
&mut state.apb1,
);
)
.unwrap();
let (usart_odd, pins_odd) = unwrap!(state.serial_fast.take()).free();
let config_odd = Config::default().parity(Parity::Odd);
let mut serial_odd = Serial::new(
Expand All @@ -305,7 +314,8 @@ mod tests {
config_odd,
state.clocks,
&mut state.apb1,
);
)
.unwrap();

// Transmit data with wrong parity in both directions.
unwrap!(nb::block!(serial_even.write(b'x')));
Expand All @@ -326,15 +336,17 @@ mod tests {
BAUD_SLOW,
state.clocks,
&mut state.apb1,
);
)
.unwrap();
let (usart_fast, pins_fast) = serial_odd.free();
let serial_fast = Serial::new(
usart_fast,
pins_fast,
BAUD_FAST,
state.clocks,
&mut state.apb1,
);
)
.unwrap();
state.serial_slow = Some(serial_slow);
state.serial_fast = Some(serial_fast);
}
Expand Down