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

[#80] Baudrate type implementation #88

Merged
merged 2 commits into from
Nov 7, 2020
Merged
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
111 changes: 104 additions & 7 deletions avr-hal-generic/src/serial.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,105 @@
//! Serial Implementations

use core::cmp::Ordering;

// Clock is needed because the calculations needs to take core clock into account
#[derive(Debug, Clone, Copy)]
Rahix marked this conversation as resolved.
Show resolved Hide resolved
pub struct Baudrate<CLOCK> {
pub ubrr: u16,
pub u2x: bool,
pub _clock: ::core::marker::PhantomData<CLOCK>,
}

impl<CLOCK: crate::clock::Clock> PartialEq for Baudrate<CLOCK> {
fn eq(&self, other: &Self) -> bool {
self.compare_value() == other.compare_value()
}
}

impl<CLOCK: crate::clock::Clock> Eq for Baudrate<CLOCK> {}

impl<CLOCK: crate::clock::Clock> PartialOrd for Baudrate<CLOCK> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.compare_value().cmp(&other.compare_value()))
}
}

impl<CLOCK: crate::clock::Clock> Ord for Baudrate<CLOCK> {
fn cmp(&self, other: &Self) -> Ordering {
other.compare_value().cmp(&self.compare_value())
}
}

impl<CLOCK: crate::clock::Clock> From<u32> for Baudrate<CLOCK> {
fn from(baud: u32) -> Self {
Baudrate::new(baud)
}
}

impl<CLOCK: crate::clock::Clock> Baudrate<CLOCK> {
pub fn new(baud: u32) -> Baudrate<CLOCK> {
let mut ubrr = (CLOCK::FREQ / 4 / baud - 1) / 2;
let mut u2x = true;
debug_assert!(ubrr <= u16::MAX as u32);
if ubrr > 4095 {
u2x = false;
ubrr = (CLOCK::FREQ / 8 / baud - 1) / 2;
}

Baudrate {
ubrr: ubrr as u16,
u2x: u2x,
_clock: ::core::marker::PhantomData,
}
}

pub fn with_exact(u2x: bool, ubrr: u16) -> Baudrate<CLOCK> {
Baudrate {
ubrr, u2x, _clock: ::core::marker::PhantomData,
}
}

fn compare_value(&self) -> u32 {
if self.u2x {
return 8 * (self.ubrr as u32 + 1);
} else {
return 16 * (self.ubrr as u32 + 1);
};
}
}

pub trait BaudrateExt {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK>;
}

impl BaudrateExt for u32 {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK> {
Baudrate::new(self)
}
}

pub trait BaudrateArduinoExt {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK>;
}

impl BaudrateArduinoExt for u32 {
fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK> {
let br = Baudrate::new(self);

// hardcoded exception for 57600 for compatibility with the bootloader
// shipped with the Duemilanove and previous boards and the firmware
// on the 8U2 on the Uno and Mega 2560.
//
// https://github.com/arduino/ArduinoCore-avr/blob/3055c1efa3c6980c864f661e6c8cc5d5ac773af4/cores/arduino/HardwareSerial.cpp#L123-L132
if CLOCK::FREQ == 16_000_000 && br.ubrr == 34 && br.u2x {
// (CLOCK::FREQ / 8 / 57600 - 1) / 2 == 16
Baudrate::with_exact(false, 16)
} else {
br
}
}
}

/// Implement serial traits for a USART peripheral
#[macro_export]
macro_rules! impl_usart {
Expand Down Expand Up @@ -40,7 +140,7 @@ macro_rules! impl_usart {
p: $USART,
rx: $rxmod::$RX<$crate::port::mode::Input<RX_MODE>>,
tx: $txmod::$TX<$crate::port::mode::Output>,
baud: u32,
baud: Baudrate<CLOCK>,
Rahix marked this conversation as resolved.
Show resolved Hide resolved
) -> $Usart<CLOCK, RX_MODE> {
let mut usart = $Usart {
p,
Expand All @@ -52,12 +152,9 @@ macro_rules! impl_usart {
usart
}

fn initialize(&mut self, baud: u32) {
// Value for baudrate register must be calculated based on clock frequency.
let brr = CLOCK::FREQ / (16 * baud) - 1;
self.p.[<ubrr $n>].write(|w| unsafe { w.bits(brr as u16) });

self.p.[<ucsr $n a>].reset();
fn initialize(&mut self, baud: Baudrate<CLOCK>) {
self.p.[<ubrr $n>].write(|w| unsafe { w.bits(baud.ubrr) });
Rahix marked this conversation as resolved.
Show resolved Hide resolved
self.p.[<ucsr $n a>].write(|w| w.[<u2x $n>]().bit(baud.u2x));

// Enable receiver and transmitter but leave interrupts disabled.
self.p.[<ucsr $n b>].write(|w| w
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-diecimila/examples/diecimila-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
5 changes: 4 additions & 1 deletion boards/arduino-diecimila/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ mod pins;
pub use crate::pac::Peripherals;
pub use crate::pins::*;
pub use crate::hal::adc;
pub use crate::hal::prelude;
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal::usart::BaudrateArduinoExt as _;
}
pub use crate::hal::pwm;
pub use crate::hal::spi;

Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-leonardo/examples/leonardo-adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Reading analog inputs ...\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-leonardo/examples/leonardo-i2cdetect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);
let mut i2c = arduino_leonardo::I2c::new(
dp.TWI,
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-leonardo/examples/leonardo-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-leonardo/examples/leonardo-serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-leonardo/examples/leonardo-spi-feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

pins.led_rx.into_output(&mut pins.ddr); // SS must be set to output mode.
Expand Down
8 changes: 6 additions & 2 deletions boards/arduino-leonardo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ pub use crate::pac::Peripherals;
mod pins;
pub use crate::pins::*;

pub use crate::hal::prelude;
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal::usart::BaudrateExt as _;
}
pub use crate::hal::usart;

/// Busy-Delay
///
Expand Down Expand Up @@ -187,7 +191,7 @@ pub mod pwm {
/// dp.USART1,
/// pins.d0,
/// pins.d1.into_output(&mut pins.ddr),
/// 57600,
/// 57600.into_baudrate(),
/// );
///
/// ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-mega2560/examples/mega2560-adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Reading analog inputs ...\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-mega2560/examples/mega2560-i2cdetect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);
let mut i2c = arduino_mega2560::I2c::new(
dp.TWI,
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-mega2560/examples/mega2560-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from MEGA2560!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-mega2560/examples/mega2560-serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-mega2560/examples/mega2560-spi-feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

pins.d53.into_output(&mut pins.ddr); // SS must be set to output mode.
Expand Down
5 changes: 4 additions & 1 deletion boards/arduino-mega2560/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ pub use crate::pac::Peripherals;
mod pins;
pub use crate::pins::*;

pub use crate::hal::prelude;
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal::usart::BaudrateExt as _;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need to check whether this is affected by the special implementation. @couchand, maybe you can give a try of this PR at 57600 baud?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In worst case I think will be able to test this in next week.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For mega2560 same results. I will check now Uno rev3 for same baunds

baund UBRR tested
300 767 ok
600 383 ok
1200 191 ok
2400 95 ok
4800 47 ok
9600 23 ok
14400 15 failed
19200 11 ok
28800 7 failed
38400 5 ok
57600 3 ok
76800 2 failed
115200 1 ok

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is with the BaudrateExt trait, right? So it seems 57600 and 115200 are working fine with the default implementation which means we don't need to switch for this board!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Looks like works fine. I'm able to test today uno rev3 too. Then I will need to reupload bootloader for mega2560...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't have any objections, I'm content with the results you provided and would go ahead with merging your PR now. Thank you so much for you work here! You were a lot more thorough than most people would be which I appreciate a lot. :)

}

pub use crate::hal::spi;
pub use crate::hal::adc;
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() -> ! {
let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);

let mut serial =
arduino_uno::Serial::new(dp.USART0, pins.d0, pins.d1.into_output(&mut pins.ddr), 9600);
arduino_uno::Serial::new(dp.USART0, pins.d0, pins.d1.into_output(&mut pins.ddr), 9600.into_baudrate());

let mut adc = adc::Adc::new(dp.ADC, Default::default());

Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-hc-sr04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

let timer1 = dp.TC1;
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-i2cdetect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);
let mut i2c = arduino_uno::I2c::new(
dp.TWI,
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/arduino-uno/examples/uno-spi-feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() -> ! {
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

pins.d10.into_output(&mut pins.ddr); // SS must be set to output mode.
Expand Down
7 changes: 5 additions & 2 deletions boards/arduino-uno/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ pub use crate::pac::Peripherals;
mod pins;
pub use crate::pins::*;

pub use crate::hal::prelude;
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal::usart::BaudrateArduinoExt as _;
}

/// Busy-Delay
///
Expand Down Expand Up @@ -192,7 +195,7 @@ pub mod pwm {
/// dp.USART0,
/// pins.d0,
/// pins.d1.into_output(&mut pins.ddr),
/// 57600,
/// 57600.into_baudrate(),
/// );
///
/// ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/bigavr6/examples/bigavr6-i2cdetect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);
let mut i2c = bigavr6::I2c::new(
dp.TWI,
Expand Down
2 changes: 1 addition & 1 deletion boards/bigavr6/examples/bigavr6-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from BIGAVR6!\r").void_unwrap();
Expand Down
2 changes: 1 addition & 1 deletion boards/bigavr6/examples/bigavr6-serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() -> ! {
dp.USART0,
porte.pe0,
porte.pe1.into_output(&mut porte.ddr),
57600,
57600.into_baudrate(),
);

// The following would also work, but needs +600% more bytes
Expand Down
5 changes: 4 additions & 1 deletion boards/bigavr6/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ pub use crate::hal::pac;
pub use crate::hal::entry;

pub use crate::pac::Peripherals;
pub use crate::hal::prelude;
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal::usart::BaudrateExt as _;
}

pub type Delay = crate::hal::delay::Delay<hal::clock::MHz16>;
pub type Serial<IMODE> = crate::hal::usart::Usart0<hal::clock::MHz16, IMODE>;
Expand Down
2 changes: 1 addition & 1 deletion boards/sparkfun-pro-micro/examples/pro-micro-adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() -> ! {
dp.USART1,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Reading analog inputs ...\r").void_unwrap();
Expand Down
Loading