Skip to content

Commit

Permalink
Baudrate type implementation #88
Browse files Browse the repository at this point in the history
  • Loading branch information
explicite committed Nov 6, 2020
1 parent 7337cd7 commit 64c152f
Show file tree
Hide file tree
Showing 78 changed files with 1,011 additions and 466 deletions.
106 changes: 106 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

**Note**: As this project is still very early in its lifecycle, we don't have
proper releases yet. Instead, the CHANGELOG will document changes over time so
people already using the crates have a reference what is changing upstream.

## [2020-10-26 - 2020-11-01][2020-44]
### Changed
- In HAL crates, the `avr-hal-generic` crate is no longer renamed to `avr-hal`
as this will just lead to confusion and problems down the line ([#89]).
- In HAL crates, the peripheral access crate (submodule of `avr-device`) is
imported as `pac` everywhere instead of using the actual device name. This
will make it easier to support multiple devices in a single HAL in the future
([#89]).
- The reexported modules in board crates were cleaned up: The HAL crate is now
reexported as `hal` and the PAC crates as `pac` ([#89]).

[#89]: https://github.com/Rahix/avr-hal/pull/89


## [2020-10-12 - 2020-10-18][2020-42]
### Added
- The runner scripts now have better suport for MacOS out of the box ([#87]).

[#87]: https://github.com/Rahix/avr-hal/pull/87


## [2020-10-05 - 2020-10-11][2020-41]
### Added
- Added a script for automatically synchronizing target specs with upstream
([#84]).

### Changed
- Moved all target specs (like `avr-atmega32u4.json`) to a single directory
named `avr-specs/` ([#82]).
- Updated various settings in all target specs for better compatibility and
general cleanup ([#85]).

### Fixed
- Fixed a number of issues in the `sparkfun-pro-micro` board crate ([#74]).

[#74]: https://github.com/Rahix/avr-hal/pull/74
[#82]: https://github.com/Rahix/avr-hal/pull/82
[#84]: https://github.com/Rahix/avr-hal/pull/84
[#85]: https://github.com/Rahix/avr-hal/pull/85


## [2020-09-14 - 2020-09-20][2020-38]
### Changed
- The `Pins::new()` for `arduino-leonardo` now also consumes the `PORTF`
peripheral and exposes its pins as `a0` - `a5` ([#73]).

### Fixed
- Fixed a nightly regression which broke our target specs ([#72]).

[#73]: https://github.com/Rahix/avr-hal/pull/73
[#72]: https://github.com/Rahix/avr-hal/pull/72


## [2020-09-07 - 2020-09-13][2020-37]
### Added
- Added support for Arduino Nano (in `arduino-uno` board crate) ([#69]).
- Added support for `ADC6` and `ADC7` pins in `atmega328p-hal` ([#69]).

### Fixed
- Reduced the overhead from `delay_us(u32)` ([#68]).

[#68]: https://github.com/Rahix/avr-hal/pull/68
[#69]: https://github.com/Rahix/avr-hal/pull/69


## [2020-08-31 - 2020-09-06][2020-36]
### Added
- Support for Sparkfun's Pro Micro board ([#62]).
- SPI driver now implements the `blocking::spi::{Transfer, Write}` traits
([#66]).

### Fixed
- Fixed not resetting `U2X` bit in `USART` driver which leads to wrong baudrates
in some situations (reported in [#67], fixed in [`7caed3a995e2`]).
- Fixed I2C/TWI driver not resetting all bits during initialization
([`3116e9ad5441`]).

[#62]: https://github.com/Rahix/avr-hal/pull/62
[#66]: https://github.com/Rahix/avr-hal/pull/66
[#67]: https://github.com/Rahix/avr-hal/pull/67
[`7caed3a995e2`]: https://github.com/Rahix/avr-hal/commit/7caed3a995e22f107b87e69f53679b0b4a3eb758
[`3116e9ad5441`]: https://github.com/Rahix/avr-hal/commit/3116e9ad544120fffd55c60fcca58b51e61f934b


## 2019-05-11 - 2020-08-31
Please look at the git log for changes before this point :)




[2020-44]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-10-25%7D...master@%7B2020-11-01%7D
[2020-42]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-10-11%7D...master@%7B2020-10-18%7D
[2020-41]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-10-04%7D...master@%7B2020-10-11%7D
[2020-38]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-09-13%7D...master@%7B2020-09-20%7D
[2020-37]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-09-06%7D...master@%7B2020-09-13%7D
[2020-36]: https://github.com/Rahix/avr-hal/compare/master@%7B2020-08-30%7D...master@%7B2020-09-06%7D
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ avr-hal [![Build Status](https://travis-ci.com/Rahix/avr-hal.svg?branch=master)]
## Quickstart
You need nightly rust for compiling rust code for AVR. Go into `./boards/arduino-leonardo` (or the directory for whatever board you want), and run the following commands:
```bash
cd boards/arduino-leonardo

# Now you are ready to build your first avr blink example!
cargo +nightly build --example leonardo-blink

Expand Down Expand Up @@ -54,6 +56,11 @@ This is a step-by-step guide for creating a new project targeting Arduino Leonar

[dependencies.arduino-leonardo]
git = "https://github.com/Rahix/avr-hal"
rev = "<insert latest git-commit hash here>"
# ^- Pin the dependency to a specific version. You should use the latest
# commit hash from the avr-hal master branch. You can find it here:
#
# https://github.com/Rahix/avr-hal/commits/master

# Configure the build for minimal size
[profile.dev]
Expand All @@ -68,6 +75,7 @@ This is a step-by-step guide for creating a new project targeting Arduino Leonar
lto = true
opt-level = "s"
```
**Note**: If you at some point want to update to a newer version of `avr-hal`, you just need to put a later commit hash into the `rev =` field. For any breaking changes which might require you to fix something in your code, read the [CHANGELOG](https://github.com/Rahix/avr-hal/blob/master/CHANGELOG.md).
6. Start your project with this basic template:
```rust
#![no_std]
Expand Down
2 changes: 1 addition & 1 deletion avr-hal-generic/src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ macro_rules! impl_adc {
use $crate::hal::adc::{Channel, OneShot};
use $crate::nb;
use $crate::port::mode::Analog;
pub use avr_hal::adc::*;
pub use $crate::adc::*;

pub struct $Adc {
peripheral: $ADC,
Expand Down
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)]
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>,
) -> $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) });
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
37 changes: 25 additions & 12 deletions avr-hal-generic/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,6 @@ macro_rules! impl_spi {
}
}
) => {
type SCLK = $sclkmod::$SCLK<$crate::port::mode::Output>;
type MOSI = $mosimod::$MOSI<$crate::port::mode::Output>;
type MISO<InputMode> = $misomod::$MISO<$crate::port::mode::Input<InputMode>>;

/// Behavior for a SPI interface.
///
/// Stores the SPI peripheral for register access. In addition, it takes
Expand All @@ -90,9 +86,9 @@ macro_rules! impl_spi {
$(#[$spi_attr])*
pub struct $Spi<MisoInputMode: $crate::port::mode::InputMode> {
peripheral: $SPI,
sclk: SCLK,
mosi: MOSI,
miso: MISO<MisoInputMode>,
sclk: $sclkmod::$SCLK<$crate::port::mode::Output>,
mosi: $mosimod::$MOSI<$crate::port::mode::Output>,
miso: $misomod::$MISO<$crate::port::mode::Input<MisoInputMode>>,
settings: Settings,
is_write_in_progress: bool,
}
Expand All @@ -104,8 +100,14 @@ macro_rules! impl_spi {
/// The pins are not actually used directly, but they are moved into the struct in
/// order to enforce that they are in the correct mode, and cannot be used by anyone
/// else while SPI is active.
pub fn new(peripheral: $SPI, sclk: SCLK, mosi: MOSI, miso: MISO<$crate::port::mode::PullUp>, settings: Settings) -> Self {
let spi = Spi {
pub fn new(
peripheral: $SPI,
sclk: $sclkmod::$SCLK<$crate::port::mode::Output>,
mosi: $mosimod::$MOSI<$crate::port::mode::Output>,
miso: $misomod::$MISO<$crate::port::mode::Input<$crate::port::mode::PullUp>>,
settings: Settings
) -> Self {
let spi = $Spi {
peripheral,
sclk,
mosi,
Expand All @@ -125,8 +127,14 @@ macro_rules! impl_spi {
/// The pins are not actually used directly, but they are moved into the struct in
/// order to enforce that they are in the correct mode, and cannot be used by anyone
/// else while SPI is active.
pub fn with_external_pullup(peripheral: $SPI, sclk: SCLK, mosi: MOSI, miso: MISO<$crate::port::mode::Floating>, settings: Settings) -> Self {
let spi = Spi {
pub fn with_external_pullup(
peripheral: $SPI,
sclk: $sclkmod::$SCLK<$crate::port::mode::Output>,
mosi: $mosimod::$MOSI<$crate::port::mode::Output>,
miso: $misomod::$MISO<$crate::port::mode::Input<$crate::port::mode::Floating>>,
settings: Settings
) -> Self {
let spi = $Spi {
peripheral,
sclk,
mosi,
Expand All @@ -143,7 +151,12 @@ macro_rules! impl_spi {
/// Disable the SPI device and release ownership of the peripheral
/// and pins. Instance can no-longer be used after this is
/// invoked.
pub fn release(self) -> ($SPI, SCLK, MOSI, MISO<MisoInputMode>) {
pub fn release(self) -> (
$SPI,
$sclkmod::$SCLK<$crate::port::mode::Output>,
$mosimod::$MOSI<$crate::port::mode::Output>,
$misomod::$MISO<$crate::port::mode::Input<MisoInputMode>>,
) {
self.peripheral.spcr.write(|w| {
w.spe().clear_bit()
});
Expand Down
4 changes: 2 additions & 2 deletions avr-hal-generic/src/wdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ macro_rules! impl_wdt {
// 2. Within the next four clock cycles, write the WDE and Watchdog prescaler
// bits (WDP) as desired, but with the WDCE bit cleared. This must be done in
// one operation.
avr_hal::avr_device::interrupt::free(|_| {
$crate::avr_device::interrupt::free(|_| {
// Reset the watchdog timer
self.feed();
// Enable watchdog configuration mode
Expand Down Expand Up @@ -116,7 +116,7 @@ macro_rules! impl_wdt {
// previous value of the WDE bit.
// 2. Within the next four clock cycles, clear the WDE and WDCE bits.
// This must be done in one operation.
avr_hal::avr_device::interrupt::free(|_| {
$crate::avr_device::interrupt::free(|_| {
// Reset the watchdog timer
self.feed();
// Enable watchdog configuration mode
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
Loading

0 comments on commit 64c152f

Please sign in to comment.