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

Add atmega328pb as a extension to atmega328p #96

Merged
merged 1 commit into from
Oct 29, 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
2 changes: 1 addition & 1 deletion boards/arduino-uno/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ rt = ["atmega328p-hal/rt"]
arduino-nano = ["atmega328p-hal/adc-pins"]

[dependencies]
atmega328p-hal = { path = "../../chips/atmega328p-hal/" }
atmega328p-hal = { path = "../../chips/atmega328p-hal/", features = ["atmega328p"] }
avr-hal-generic = { path = "../../avr-hal-generic/" }

[dev-dependencies]
Expand Down
4 changes: 3 additions & 1 deletion chips/atmega328p-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ edition = "2018"
rt = ["avr-device/rt"]
# Package exposes the ADC6 and ADC7 pins (only 32TQFP, 32MLF, 32UFBGA)
adc-pins = []
device-selected = []
atmega328p = ["avr-device/atmega328p", "device-selected"]
atmega328pb = ["avr-device/atmega328pb", "device-selected"]

[dependencies]
avr-hal-generic = { path = "../../avr-hal-generic/" }

[dependencies.avr-device]
version = "0.2.2"
features = ["atmega328p"]
154 changes: 152 additions & 2 deletions chips/atmega328p-hal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
#![no_std]

#[cfg(not(feature = "device-selected"))]
compile_error!(
"This crate requires you to specify your target chip as a feature.

Please select one of the following

* atmega328p
* atmega328pb
"
);


/// Reexport of `atmega328p` from `avr-device`
#[cfg(feature = "atmega328p")]
pub use avr_device::atmega328p as pac;
/// Reexport of `atmega328pb` from `avr-device`
#[cfg(feature = "atmega328pb")]
pub use avr_device::atmega328pb as pac;

/// See [`avr_device::entry`](https://docs.rs/avr-device/latest/avr_device/attr.entry.html).
#[cfg(feature = "rt")]
Expand All @@ -10,17 +26,22 @@ pub use avr_device::entry;
pub use avr_hal_generic::clock;
pub use avr_hal_generic::delay;

#[cfg(feature = "device-selected")]
pub mod port;

#[cfg(feature = "device-selected")]
pub mod adc;
#[cfg(feature = "device-selected")]
pub mod pwm;
#[cfg(feature = "device-selected")]
pub mod wdt;

#[cfg(feature = "device-selected")]
pub mod prelude {
pub use avr_hal_generic::prelude::*;
pub use crate::port::PortExt as _;
}

#[cfg(feature = "atmega328p")]
/// I2C Bus
pub mod i2c {
use crate::port::portc;
Expand Down Expand Up @@ -53,6 +74,66 @@ pub mod i2c {
}
}

#[cfg(feature = "atmega328pb")]
/// I2C Bus
pub mod i2c {
use crate::port::{portc, porte};
pub use avr_hal_generic::i2c::*;

avr_hal_generic::impl_twi_i2c! {
/// I2C based on ATmega328P's TWI peripheral
pub struct I2c0 {
peripheral: crate::pac::TWI0,
pins: {
sda: portc::PC4,
scl: portc::PC5,
},
registers: {
control: twcr {
enable: twen,
ack: twea,
int: twint,
start: twsta,
stop: twsto,
},
status: twsr {
prescaler: twps,
status: tws,
},
bitrate: twbr,
data: twdr,
},
}
}

avr_hal_generic::impl_twi_i2c! {
/// I2C based on ATmega328P's TWI peripheral
pub struct I2c1 {
peripheral: crate::pac::TWI1,
pins: {
sda: porte::PE0,
scl: porte::PE1,
},
registers: {
control: twcr {
enable: twen,
ack: twea,
int: twint,
start: twsta,
stop: twsto,
},
status: twsr {
prescaler: twps,
status: tws,
},
bitrate: twbr,
data: twdr,
},
}
}
}

#[cfg(feature = "atmega328p")]
pub mod spi {
//! Implementation of the Rust Embedded-HAL SPI FullDuplex trait for AVR.
//!
Expand Down Expand Up @@ -93,9 +174,63 @@ pub mod spi {
}
}

#[cfg(feature = "atmega328pb")]
pub mod spi {
//! Implementation of the Rust Embedded-HAL SPI FullDuplex trait for AVR.
//!
//! The interface can be instantiated with the `new` method, and used directly
//! or passed into a driver. Example usage:
//!
//! ```
//! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode
//! // create SPI interface
//! let mut spi = Spi0::new(
//! dp.SPI,// SPI peripheral
//! pins.d13.into_output(&mut pins.ddr),// SCLK
//! pins.d11.into_output(&mut pins.ddr),// MOSI output pin
//! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin
//! Settings::default(),
//! );
//!
//! // Send a byte
//! let sent = 0b10101010;
//! spi.send(sent).unwrap();
//! let response = spi.read().unwrap();
//! ```
//! In the example above, all of the settings are left at the default. You can
//! also instantiate a Settings object with the other options available.

use crate::port::{portb, portc, porte};
pub use avr_hal_generic::spi::*;

avr_hal_generic::impl_spi! {
pub struct Spi0 {
peripheral: crate::pac::SPI0,
pins: {
sclk: portb::PB5,
mosi: portb::PB3,
miso: portb::PB4,
}
}
}

avr_hal_generic::impl_spi! {
pub struct Spi1 {
peripheral: crate::pac::SPI1,
pins: {
sclk: portc::PC1,
mosi: porte::PE3,
miso: portc::PC0,
}
}
}
}

/// Serial interface using USART
#[cfg(feature = "device-selected")]
pub mod usart {
jkristell marked this conversation as resolved.
Show resolved Hide resolved
use crate::port::portd;
#[allow(unused_imports)]
use crate::port::{portb, portd};
pub use avr_hal_generic::serial::*;

avr_hal_generic::impl_usart! {
Expand All @@ -111,4 +246,19 @@ pub mod usart {
register_suffix: 0,
}
}

#[cfg(feature = "atmega328pb")]
avr_hal_generic::impl_usart! {
/// Serial interface based on ATmega328PB's USART0 peripheral
///
/// Maximum baudrate seems to be 57600
pub struct Usart1 {
peripheral: crate::pac::USART1,
pins: {
rx: portb::PB4,
tx: portb::PB3,
},
register_suffix: 1,
}
}
}
30 changes: 30 additions & 0 deletions chips/atmega328p-hal/src/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub trait PortExt {
fn split(self) -> Self::Parts;
}

#[cfg(feature = "atmega328p")]
avr_hal_generic::impl_generic_pin! {
pub enum Pin {
B(crate::pac::PORTB, portb, pinb, ddrb),
Expand All @@ -20,6 +21,17 @@ avr_hal_generic::impl_generic_pin! {
}
}

#[cfg(feature = "atmega328pb")]
avr_hal_generic::impl_generic_pin! {
pub enum Pin {
B(crate::pac::PORTB, portb, pinb, ddrb),
C(crate::pac::PORTC, portc, pinc, ddrc),
D(crate::pac::PORTD, portd, pind, ddrd),
E(crate::pac::PORTE, porte, pine, ddre),
}
}


avr_hal_generic::impl_port! {
pub mod portb {
#[port_ext]
Expand Down Expand Up @@ -85,3 +97,21 @@ avr_hal_generic::impl_port! {
}
}

#[cfg(feature = "atmega328pb")]
avr_hal_generic::impl_port! {
pub mod porte {
#[port_ext]
use super::PortExt;

#[generic_pin]
use Pin::E;

impl PortExt for crate::pac::PORTE {
regs: (pine, ddre, porte),
pe0: (PE0, 0),
pe1: (PE1, 1),
pe2: (PE2, 2),
pe3: (PE3, 3),
}
}
}
104 changes: 104 additions & 0 deletions chips/atmega328p-hal/src/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,107 @@ avr_hal_generic::impl_pwm! {
},
}
}

#[cfg(feature = "atmega328pb")]
avr_hal_generic::impl_pwm! {
/// Use `TC3` for PWM (pins `PD0`, `PD2`)
///
/// # Example
/// ```
/// let mut portd = dp.PORTD.split();
/// let mut timer3 = Timer3Pwm::new(dp.TC3, pwm::Prescaler::Prescale64);
///
/// let mut pb1 = portd.pd1.into_output(&mut portd.ddr).into_pwm(&mut timer3);
/// let mut pb2 = portd.pd2.into_output(&mut portd.ddr).into_pwm(&mut timer3);
///
/// pd1.set_duty(128);
/// pd1.enable();
/// ```
pub struct Timer3Pwm {
timer: crate::pac::TC3,
init: |tim, prescaler| {
tim.tccr3a.modify(|_, w| w.wgm3().bits(0b01));
tim.tccr3b.modify(|_, w| {
//TODO: Figure out if svdtool can mark this as safe (as for Tc1)
unsafe { w.wgm3().bits(0b01) };
match prescaler {
Prescaler::Direct => w.cs3().direct(),
Prescaler::Prescale8 => w.cs3().prescale_8(),
Prescaler::Prescale64 => w.cs3().prescale_64(),
Prescaler::Prescale256 => w.cs3().prescale_256(),
Prescaler::Prescale1024 => w.cs3().prescale_1024(),
}
});
},
pins: {
portd::PD0: {
ocr: ocr3a,
into_pwm: |tim| if enable {
tim.tccr3a.modify(|_, w| w.com3a().match_clear());
} else {
tim.tccr3a.modify(|_, w| w.com3a().disconnected());
},
},
portd::PD2: {
ocr: ocr3b,
into_pwm3: |tim| if enable {
tim.tccr3a.modify(|_, w| w.com3b().match_clear());
} else {
tim.tccr3a.modify(|_, w| w.com3b().disconnected());
},
},
},
}
}

#[cfg(feature = "atmega328pb")]
avr_hal_generic::impl_pwm! {
/// Use `TC4` for PWM (pins `PD1`, `PD2`)
///
/// # Example
/// ```
/// let mut portd = dp.PORTD.split();
/// let mut timer4 = Timer4Pwm::new(dp.TC4, pwm::Prescaler::Prescale64);
///
/// let mut pd1 = portd.pd1.into_output(&mut portd.ddr).into_pwm(&mut timer4);
/// let mut pd2 = portd.pd2.into_output(&mut portd.ddr).into_pwm(&mut timer4);
///
/// pd1.set_duty(128);
/// pd1.enable();
/// ```
pub struct Timer4Pwm {
timer: crate::pac::TC4,
init: |tim, prescaler| {
tim.tccr4a.modify(|_, w| w.wgm4().bits(0b01));
tim.tccr4b.modify(|_, w| {
//TODO: Figure out if svdtool can mark this as safe (as for Tc1)
unsafe { w.wgm4().bits(0b01) };
match prescaler {
Prescaler::Direct => w.cs4().direct(),
Prescaler::Prescale8 => w.cs4().prescale_8(),
Prescaler::Prescale64 => w.cs4().prescale_64(),
Prescaler::Prescale256 => w.cs4().prescale_256(),
Prescaler::Prescale1024 => w.cs4().prescale_1024(),
}
});
},
pins: {
portd::PD1: {
ocr: ocr4a,
into_pwm: |tim| if enable {
tim.tccr4a.modify(|_, w| w.com4a().match_clear());
} else {
tim.tccr4a.modify(|_, w| w.com4a().disconnected());
},
},
portd::PD2: {
ocr: ocr4b,
into_pwm4: |tim| if enable {
tim.tccr4a.modify(|_, w| w.com4b().match_clear());
} else {
tim.tccr4a.modify(|_, w| w.com4b().disconnected());
},
},
},
}
}