From 42bd207484527f40d3f105b9925e2cecffd1a7f8 Mon Sep 17 00:00:00 2001 From: Iris Artin Date: Wed, 20 Nov 2024 23:10:35 -0500 Subject: [PATCH 1/4] Refactor attiny-hal for opt-out deprecated globals --- .github/workflows/ci.yml | 5 + avr-hal-generic/src/simple_pwm.rs | 2 +- mcu/attiny-hal/Cargo.toml | 69 +++++--- mcu/attiny-hal/src/adc.rs | 209 ------------------------- mcu/attiny-hal/src/attiny167.rs | 92 +++++++++++ mcu/attiny-hal/src/attiny2313.rs | 40 +++++ mcu/attiny-hal/src/attiny84.rs | 120 ++++++++++++++ mcu/attiny-hal/src/attiny85.rs | 162 +++++++++++++++++++ mcu/attiny-hal/src/attiny88.rs | 134 ++++++++++++++++ mcu/attiny-hal/src/eeprom.rs | 56 ------- mcu/attiny-hal/src/globals.rs | 93 +++++++++++ mcu/attiny-hal/src/impl/adc.rs | 149 ++++++++++++++++++ mcu/attiny-hal/src/impl/eeprom.rs | 48 ++++++ mcu/attiny-hal/src/impl/mod.rs | 23 +++ mcu/attiny-hal/src/impl/port.rs | 31 ++++ mcu/attiny-hal/src/impl/simple_pwm.rs | 15 ++ mcu/attiny-hal/src/impl/spi.rs | 65 ++++++++ mcu/attiny-hal/src/impl/wdt.rs | 34 ++++ mcu/attiny-hal/src/lib.rs | 128 +++------------ mcu/attiny-hal/src/port.rs | 62 -------- mcu/attiny-hal/src/simple_pwm.rs | 217 -------------------------- mcu/attiny-hal/src/spi.rs | 72 --------- mcu/attiny-hal/src/wdt.rs | 44 ------ 23 files changed, 1086 insertions(+), 784 deletions(-) delete mode 100644 mcu/attiny-hal/src/adc.rs create mode 100644 mcu/attiny-hal/src/attiny167.rs create mode 100644 mcu/attiny-hal/src/attiny2313.rs create mode 100644 mcu/attiny-hal/src/attiny84.rs create mode 100644 mcu/attiny-hal/src/attiny85.rs create mode 100644 mcu/attiny-hal/src/attiny88.rs delete mode 100644 mcu/attiny-hal/src/eeprom.rs create mode 100644 mcu/attiny-hal/src/globals.rs create mode 100644 mcu/attiny-hal/src/impl/adc.rs create mode 100644 mcu/attiny-hal/src/impl/eeprom.rs create mode 100644 mcu/attiny-hal/src/impl/mod.rs create mode 100644 mcu/attiny-hal/src/impl/port.rs create mode 100644 mcu/attiny-hal/src/impl/simple_pwm.rs create mode 100644 mcu/attiny-hal/src/impl/spi.rs create mode 100644 mcu/attiny-hal/src/impl/wdt.rs delete mode 100644 mcu/attiny-hal/src/port.rs delete mode 100644 mcu/attiny-hal/src/simple_pwm.rs delete mode 100644 mcu/attiny-hal/src/spi.rs delete mode 100644 mcu/attiny-hal/src/wdt.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 507335a20c..63fc8e6511 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,11 @@ jobs: - name: Test-compile HAL crate for an MCU if: "${{ matrix.m.type == 'mcu' }}" run: cd "mcu/${{ matrix.m.crate }}" && cargo build --features "${{ matrix.m.name }}" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" + - name: Test-compile HAL crate for an MCU (no deprecated globals) + if: "${{ matrix.m.crate == 'attiny-hal' }}" + run: >- + cd "mcu/${{ matrix.m.crate }}" && + cargo build --features "${{ matrix.m.name }}-no-deprecated-globals" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" ravedude: name: "ravedude" diff --git a/avr-hal-generic/src/simple_pwm.rs b/avr-hal-generic/src/simple_pwm.rs index 93b4081bf5..4952e3e925 100644 --- a/avr-hal-generic/src/simple_pwm.rs +++ b/avr-hal-generic/src/simple_pwm.rs @@ -123,7 +123,7 @@ macro_rules! impl_simple_pwm { timer: $TIMER:ty, init: |$init_timer:ident, $prescaler:ident| $init_block:block, pins: {$( - $PXi:ident: { + $PXi:ty: { ocr: $ocr:ident, $into_pwm:ident: |$pin_timer:ident| if enable $pin_enable_block:block else $pin_disable_block:block, diff --git a/mcu/attiny-hal/Cargo.toml b/mcu/attiny-hal/Cargo.toml index 4e11377dcb..561e90da07 100644 --- a/mcu/attiny-hal/Cargo.toml +++ b/mcu/attiny-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "attiny-hal" -version = "0.1.0" +version = "0.2.0" authors = ["Rahix "] edition = "2021" @@ -12,33 +12,66 @@ categories = ["no-std", "embedded", "hardware-support"] [features] rt = ["avr-device/rt"] -device-selected = [] -attiny84 = ["avr-device/attiny84", "device-selected"] -attiny85 = ["avr-device/attiny85", "device-selected"] -attiny88 = ["avr-device/attiny88", "device-selected"] -attiny167 = ["avr-device/attiny167", "device-selected"] -attiny2313 = ["avr-device/attiny2313", "device-selected"] + +# MCU-specific targets. Due to use of deprecated globals, only one MCU can be selected at a time +# In attiny-hal 0.30 the defaults will change to no deprecated globals +attiny84 = ["attiny84-deprecated-globals"] +attiny85 = ["attiny85-deprecated-globals"] +attiny88 = ["attiny88-deprecated-globals"] +attiny167 = ["attiny167-deprecated-globals"] +attiny2313 = ["attiny2313-deprecated-globals"] + +# MCU-specific targets with deprecated globals. This is the default in attiny-hal <0.3.0 +attiny84-deprecated-globals = ["_mcu-attiny84", "deprecated-globals"] +attiny85-deprecated-globals = ["_mcu-attiny85", "deprecated-globals"] +attiny88-deprecated-globals = ["_mcu-attiny88", "deprecated-globals"] +attiny167-deprecated-globals = ["_mcu-attiny167", "deprecated-globals"] +attiny2313-deprecated-globals = ["_mcu-attiny2313", "deprecated-globals"] + +# MCU-specific targets without deprecated globals. This will be the default in attiny-hal 0.3.0 +attiny84-no-deprecated-globals = ["_mcu-attiny84"] +attiny85-no-deprecated-globals = ["_mcu-attiny85"] +attiny88-no-deprecated-globals = ["_mcu-attiny88"] +attiny167-no-deprecated-globals = ["_mcu-attiny167"] +attiny2313-no-deprecated-globals = ["_mcu-attiny2313"] critical-section-impl = ["avr-device/critical-section-impl"] -# Allow certain downstream crates to overwrite the device selection error by themselves. -disable-device-selection-error = [] +default = [] + +docsrs = [ + "attiny84-no-deprecated-globals", + "attiny85-no-deprecated-globals", + "attiny88-no-deprecated-globals", + "attiny167-no-deprecated-globals", + "attiny2313-no-deprecated-globals", +] + +# Include soon-to-be-deprecated globals in the crate. Only one MCU can be selected if deprecated globals are enabled +deprecated-globals = [] + +# When using this crate from another lib crate, you can use this feature to turn suppress the chip selection error in favor of your own error +disable-device-selection-error = ["_mcu-selected"] + +# MCU-specific implementation features +# Do not use directly; use either an -deprecated-globals feature or any number of -no-deprecated-globals features +_mcu-attiny84 = ["_mcu-selected", "_peripheral-simple-pwm", "avr-device/attiny84"] +_mcu-attiny85 = ["_mcu-selected", "_peripheral-adc", "_peripheral-simple-pwm", "avr-device/attiny85"] +_mcu-attiny88 = ["_mcu-selected", "_peripheral-adc", "_peripheral-spi", "_peripheral-simple-pwm", "avr-device/attiny88"] +_mcu-attiny167 = ["_mcu-selected", "_peripheral-adc", "_peripheral-spi", "avr-device/attiny167"] +_mcu-attiny2313 = ["_mcu-selected", "avr-device/attiny2313"] + +_mcu-selected = [] +_peripheral-adc = [] +_peripheral-spi = [] +_peripheral-simple-pwm = [] -# We must select a microcontroller to build on docs.rs -docsrs = ["attiny85"] [dependencies] avr-hal-generic = { path = "../../avr-hal-generic/" } [dependencies.avr-device] version = "0.5.4" - -# Because this crate has its own check that at least one device is selected, we -# can safely "circumvent" the check in `avr-device`. -# -# Why would we want that? Otherwise, as `avr-device` is compiled first, its -# error will be shown and ours won't which leads to a degraded user experience -# as the displayed error message does not really tell what needs to be done... features = ["device-selected"] [package.metadata.docs.rs] diff --git a/mcu/attiny-hal/src/adc.rs b/mcu/attiny-hal/src/adc.rs deleted file mode 100644 index 0856312086..0000000000 --- a/mcu/attiny-hal/src/adc.rs +++ /dev/null @@ -1,209 +0,0 @@ -#![allow(non_camel_case_types)] -//! Analog-to-Digital Converter -//! -//! # Example -//! -//! For full source code, please refer to the ATmega ADC example: -//! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) -//! -//! ``` -//! let dp = attiny_hal::Peripherals::take().unwrap(); -//! let pins = attiny_hal::pins!(dp); -//! -//! let mut adc = Adc::new(dp.ADC, Default::default()); -//! -//! let channels: [attiny_hal::adc::Channel; 4] = [ -//! pins.pa0.into_analog_input(&mut adc).into_channel(), -//! pins.pa1.into_analog_input(&mut adc).into_channel(), -//! pins.pa2.into_analog_input(&mut adc).into_channel(), -//! pins.pa3.into_analog_input(&mut adc).into_channel(), -//! ]; -//! -//! for (index, channel) in channels.iter().enumerate() { -//! let value = adc.read_blocking(channel); -//! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); -//! } -//! ``` - -use crate::port; -pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; - -/// Select the voltage reference for the ADC peripheral -/// -/// The internal voltage reference options may not be used if an external reference voltage is -/// being applied to the AREF pin. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum ReferenceVoltage { - /// Voltage applied to AREF pin. - #[cfg(any(feature = "attiny85", feature = "attiny167",))] - Aref, - /// Default reference voltage (default). - AVcc, - /// Internal 1.1V reference. - Internal1_1, - /// Internal 2.56V reference. - #[cfg(any(feature = "attiny85", feature = "attiny167",))] - Internal2_56, -} - -impl Default for ReferenceVoltage { - fn default() -> Self { - Self::AVcc - } -} - -/// Configuration for the ADC peripheral. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub struct AdcSettings { - pub clock_divider: ClockDivider, - pub ref_voltage: ReferenceVoltage, -} - -/// Check the [`avr_hal_generic::adc::Adc`] documentation. -pub type Adc = avr_hal_generic::adc::Adc; - -/// Check the [`avr_hal_generic::adc::Channel`] documentation. -pub type Channel = avr_hal_generic::adc::Channel; - -/// Additional channels -/// -/// Some channels are not directly connected to pins. This module provides types which can be used -/// to access them. -/// -/// # Example -/// ``` -/// let dp = attiny_hal::Peripherals::take().unwrap(); -/// let mut adc = attiny_hal::Adc::new(dp.ADC, Default::default()); -/// -/// let value = adc.read_blocking(&channel::Vbg); -/// ``` -pub mod channel { - #[cfg(feature = "attiny167")] - pub struct AVcc_4; - pub struct Vbg; - pub struct Gnd; - pub struct Temperature; -} - -fn apply_clock(peripheral: &crate::pac::ADC, settings: AdcSettings) { - peripheral.adcsra.write(|w| { - w.aden().set_bit(); - match settings.clock_divider { - ClockDivider::Factor2 => w.adps().prescaler_2(), - ClockDivider::Factor4 => w.adps().prescaler_4(), - ClockDivider::Factor8 => w.adps().prescaler_8(), - ClockDivider::Factor16 => w.adps().prescaler_16(), - ClockDivider::Factor32 => w.adps().prescaler_32(), - ClockDivider::Factor64 => w.adps().prescaler_64(), - ClockDivider::Factor128 => w.adps().prescaler_128(), - } - }); -} - -#[cfg(feature = "attiny85")] -avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.admux.write(|w| match settings.ref_voltage { - ReferenceVoltage::Aref => w.refs().aref(), - ReferenceVoltage::AVcc => w.refs().vcc(), - ReferenceVoltage::Internal1_1 => w.refs().internal().refs2().clear_bit(), - ReferenceVoltage::Internal2_56 => w.refs().internal().refs2().set_bit(), - }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PB5: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PB2: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PB4: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PB3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} - -#[cfg(feature = "attiny88")] -avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.admux.write(|w| match settings.ref_voltage { - ReferenceVoltage::AVcc => w.refs0().avcc(), - ReferenceVoltage::Internal1_1 => w.refs0().internal(), - }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA0: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} - -#[cfg(feature = "attiny167")] -avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.amiscr.write(|w| match settings.ref_voltage { - ReferenceVoltage::Aref => w.arefen().set_bit(), - _ => w.arefen().clear_bit(), - }); - peripheral.admux.write(|w| match settings.ref_voltage { - ReferenceVoltage::Aref => w.refs().avcc(), - ReferenceVoltage::AVcc => w.refs().avcc(), - ReferenceVoltage::Internal1_1 => w.refs().internal_11(), - ReferenceVoltage::Internal2_56 => w.refs().internal_256(), - }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - port::PB5: (crate::pac::adc::admux::MUX_A::ADC8, didr1::adc8d), - port::PB6: (crate::pac::adc::admux::MUX_A::ADC9, didr1::adc9d), - port::PB7: (crate::pac::adc::admux::MUX_A::ADC10, didr1::adc10d), - }, - channels: { - channel::AVcc_4: crate::pac::adc::admux::MUX_A::ADC_AVCC_4, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} diff --git a/mcu/attiny-hal/src/attiny167.rs b/mcu/attiny-hal/src/attiny167.rs new file mode 100644 index 0000000000..3a2b579a5b --- /dev/null +++ b/mcu/attiny-hal/src/attiny167.rs @@ -0,0 +1,92 @@ +pub use avr_device::attiny167 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::attiny167, + references: { + /// Voltage applied to AREF pin. + Aref: |peripheral| { + peripheral.amiscr.write(|w| w.arefen().set_bit()); + peripheral.admux.write(|w| w.refs().avcc()); + }, + /// Default reference voltage (default). + AVcc: |peripheral| { + peripheral.amiscr.write(|w| w.arefen().clear_bit()); + peripheral.admux.write(|w| w.refs().avcc()); + }, + /// Internal 1.1V reference. + Internal1_1: |peripheral| { + peripheral.amiscr.write(|w| w.arefen().clear_bit()); + peripheral.admux.write(|w| w.refs().internal_11()); + }, + /// Internal 2.56V reference. + Internal2_56: |peripheral| { + peripheral.amiscr.write(|w| w.arefen().clear_bit()); + peripheral.admux.write(|w| w.refs().internal_256()); + }, + }, + pins: { + PA0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PA1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PA2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PA3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PA4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PA5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + PA6: (hal::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), + PA7: (hal::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), + PB5: (hal::pac::adc::admux::MUX_A::ADC8, didr1::adc8d), + PB6: (hal::pac::adc::admux::MUX_A::ADC9, didr1::adc9d), + PB7: (hal::pac::adc::admux::MUX_A::ADC10, didr1::adc10d), + }, + channels: { + AVcc_4: hal::pac::adc::admux::MUX_A::ADC_AVCC_4, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, +} + +impl_mod_eeprom! { + hal: crate::attiny167, + capacity: 512, + addr_width: u16, + addr_reg: eear, +} + +impl_mod_port! { + use crate::attiny167 as hal; + + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + } + } + + #[macro_export] + macro_rules! attiny167_pins { + ($p:expr) => { + $crate::attiny167::port::Pins::new($p.PORTA, $p.PORTB) + }; + } + + pub use attiny167_pins as pins; +} + +impl_mod_spi! { + hal: crate::attiny167, + sclk: PA5, + mosi: PA4, + miso: PA2, + cs: PA6, +} + +impl_mod_wdt! { + hal: crate::attiny167, + wdtcsr_name: wdtcr, +} + diff --git a/mcu/attiny-hal/src/attiny2313.rs b/mcu/attiny-hal/src/attiny2313.rs new file mode 100644 index 0000000000..013acd56d2 --- /dev/null +++ b/mcu/attiny-hal/src/attiny2313.rs @@ -0,0 +1,40 @@ +pub use avr_device::attiny2313 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_eeprom! { + hal: crate::attiny2313, + capacity: 128, + addr_width: u8, + addr_reg: eear, +} + +impl_mod_port! { + use crate::attiny2313 as hal; + + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6], + } + } + + #[macro_export] + macro_rules! attiny2313_pins { + ($p:expr) => { + $crate::attiny2313::port::Pins::new($p.PORTA, $p.PORTB, $p.PORTD) + }; + } + + pub use attiny2313_pins as pins; +} + +impl_mod_wdt! { + hal: crate::attiny2313, + wdtcsr_name: wdtcr, +} + diff --git a/mcu/attiny-hal/src/attiny84.rs b/mcu/attiny-hal/src/attiny84.rs new file mode 100644 index 0000000000..51b4c40390 --- /dev/null +++ b/mcu/attiny-hal/src/attiny84.rs @@ -0,0 +1,120 @@ +pub use avr_device::attiny84 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_eeprom! { + hal: crate::attiny84, + capacity: 512, + addr_width: u16, + addr_reg: eear, +} + +impl_mod_port! { + use crate::attiny84 as hal; + + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], + B: hal::pac::PORTB = [0, 1, 2, 3], + } + } + + #[macro_export] + macro_rules! attiny84_pins { + ($p:expr) => { + $crate::attiny84::port::Pins::new($p.PORTA, $p.PORTB) + }; + } + + pub use attiny84_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::attiny84, + impl: { + pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB2`, `PA7`) + pub struct Timer0Pwm { + timer: crate::attiny84::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PB2: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PA7: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PA6`, 'PA5') + pub struct Timer1Pwm { + timer: crate::attiny84::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_, w| w.wgm1().bits(0b01)); + + tim.tccr1b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + }); + }, + pins: { + hal::port::PA6: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_, w| w.com1a().bits(0b10)); + } else { + tim.tccr1a.modify(|_, w| w.com1a().disconnected()); + }, + }, + + hal::port::PA5: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_, w| w.com1b().bits(0b10)); + } else { + tim.tccr1a.modify(|_, w| w.com1b().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_wdt! { + hal: crate::attiny84, + wdtcsr_name: wdtcsr, +} + diff --git a/mcu/attiny-hal/src/attiny85.rs b/mcu/attiny-hal/src/attiny85.rs new file mode 100644 index 0000000000..bc8a8e9d54 --- /dev/null +++ b/mcu/attiny-hal/src/attiny85.rs @@ -0,0 +1,162 @@ +pub use avr_device::attiny85 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::attiny85, + references: { + /// Voltage applied to AREF pin. + Aref: |peripheral| { + peripheral.admux.write(|w| w.refs().aref()) + }, + /// Default reference voltage (default). + AVcc: |peripheral| { + peripheral.admux.write(|w| w.refs().vcc()) + }, + /// Internal 1.1V reference. + Internal1_1: |peripheral| { + peripheral.admux.write(|w| w.refs().internal().refs2().clear_bit()) + }, + /// Internal 2.56V reference. + Internal2_56: |peripheral| { + peripheral.admux.write(|w| w.refs().internal().refs2().set_bit()) + }, + }, + pins: { + PB5: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PB2: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PB4: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PB3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + }, + channels: { + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, +} + +impl_mod_eeprom! { + hal: crate::attiny85, + capacity: 512, + addr_width: u16, + addr_reg: eear, +} + +impl_mod_port! { + use crate::attiny85 as hal; + + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + avr_hal_generic::impl_port_traditional! { + enum Ports { + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5], + } + } + + #[macro_export] + macro_rules! attiny85_pins { + ($p:expr) => { + $crate::attiny85::port::Pins::new($p.PORTB) + }; + } + + pub use attiny85_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::attiny85, + impl: { + pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB0`, `PB1`) + /// + /// # Example + /// ``` + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut d0 = pins.d0.into_output().into_pwm(&mut timer0); + /// let mut d1 = pins.d1.into_output().into_pwm(&mut timer0); + /// + /// d0.set_duty(128); + /// d0.enable(); + /// ``` + pub struct Timer0Pwm { + timer: crate::attiny85::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PB0: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PB1: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB4`) + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer1); + /// + /// d4.set_duty(128); + /// d4.enable(); + /// ``` + pub struct Timer1Pwm { + timer: crate::attiny85::pac::TC1, + init: |tim, prescaler| { + tim.gtccr.modify(|_, w| w.pwm1b().bit(true)); + + tim.tccr1.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + }); + }, + pins: { + hal::port::PB4: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.gtccr.modify(|_, w| w.com1b().bits(0b10)); + } else { + tim.gtccr.modify(|_, w| w.com1b().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_wdt! { + hal: crate::attiny85, + wdtcsr_name: wdtcr, +} + diff --git a/mcu/attiny-hal/src/attiny88.rs b/mcu/attiny-hal/src/attiny88.rs new file mode 100644 index 0000000000..d255dfe2f8 --- /dev/null +++ b/mcu/attiny-hal/src/attiny88.rs @@ -0,0 +1,134 @@ +pub use avr_device::attiny88 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::attiny88, + references: { + /// Default reference voltage (default). + AVcc: |peripheral| { + peripheral.admux.write(|w| w.refs0().avcc()) + }, + /// Internal 1.1V reference. + Internal1_1: |peripheral| { + peripheral.admux.write(|w| w.refs0().internal()) + }, + }, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PC1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PC2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PC3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PC4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PC5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + PA0: (hal::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), + PA1: (hal::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), + }, + channels: { + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, +} + +impl_mod_eeprom! { + hal: crate::attiny88, + capacity: 64, + addr_width: u8, + addr_reg: eearl, +} + +impl_mod_port! { + use crate::attiny88 as hal; + + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + } + } + + #[macro_export] + macro_rules! attiny88_pins { + ($p:expr) => { + $crate::attiny88::port::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use attiny88_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::attiny88, + impl: { + pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB1`, 'PB2') + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); + /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); + /// + /// d9.set_duty(128); + /// d9.enable(); + /// ``` + pub struct Timer1Pwm { + timer: crate::attiny88::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_, w| w.wgm1().bits(0b01)); + + tim.tccr1b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + }); + }, + pins: { + hal::port::PB1: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_, w| w.com1a().bits(0b10)); + } else { + tim.tccr1a.modify(|_, w| w.com1a().disconnected()); + }, + }, + + hal::port::PB2: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_, w| w.com1b().bits(0b10)); + } else { + tim.tccr1a.modify(|_, w| w.com1b().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_spi! { + hal: crate::attiny88, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, +} + +impl_mod_wdt! { + hal: crate::attiny88, + wdtcsr_name: wdtcsr, +} + diff --git a/mcu/attiny-hal/src/eeprom.rs b/mcu/attiny-hal/src/eeprom.rs deleted file mode 100644 index f325215dfb..0000000000 --- a/mcu/attiny-hal/src/eeprom.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! EEPROM -//! -//! # Example -//! -//! For full source code, please refer to the ATmega EEPROM example: -//! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) -//! -//! ``` -//! const BOOT_COUNT_OFFSET: u16 = 0; -//! -//! let dp = attiny_hal::Peripherals::take().unwrap(); -//! let mut eeprom = Eeprom::new(dp.EEPROM); -//! -//! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); -//! boot_count = boot_count.wrapping_add(1); -//! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); -//! -//! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); -//! ``` - -pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; - -pub type Eeprom = avr_hal_generic::eeprom::Eeprom; - -#[cfg(feature = "attiny2313")] -avr_hal_generic::impl_eeprom_attiny! { - hal: crate::Attiny, - peripheral: crate::pac::EEPROM, - capacity: 128, - addr_width: u8, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any(feature = "attiny167", feature = "attiny85"))] -avr_hal_generic::impl_eeprom_attiny! { - hal: crate::Attiny, - peripheral: crate::pac::EEPROM, - capacity: 512, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(feature = "attiny88")] -avr_hal_generic::impl_eeprom_attiny! { - hal: crate::Attiny, - peripheral: crate::pac::EEPROM, - capacity: 64, - addr_width: u8, - set_address: |peripheral, address| { - peripheral.eearl.write(|w| w.bits(address)); - }, -} diff --git a/mcu/attiny-hal/src/globals.rs b/mcu/attiny-hal/src/globals.rs new file mode 100644 index 0000000000..edc24f9c4f --- /dev/null +++ b/mcu/attiny-hal/src/globals.rs @@ -0,0 +1,93 @@ +// Deprecated globals + +#[cfg(all( + // More than one MCU selected -> error + all( + feature = "_mcu-attiny167", + any( + feature = "_mcu-attiny2313", + feature = "_mcu-attiny84", + feature = "_mcu-attiny85", + feature = "_mcu-attiny88", + ) + ), + all( + feature = "_mcu-attiny2313", + any( + feature = "_mcu-attiny167", + feature = "_mcu-attiny84", + feature = "_mcu-attiny85", + feature = "_mcu-attiny88", + ) + ), + all( + feature = "_mcu-attiny84", + any( + feature = "_mcu-attiny167", + feature = "_mcu-attiny2313", + feature = "_mcu-attiny85", + feature = "_mcu-attiny88", + ) + ), + all( + feature = "_mcu-attiny85", + any( + feature = "_mcu-attiny167", + feature = "_mcu-attiny2313", + feature = "_mcu-attiny84", + feature = "_mcu-attiny88", + ) + ), + all( + feature = "_mcu-attiny88", + any( + feature = "_mcu-attiny167", + feature = "_mcu-attiny2313", + feature = "_mcu-attiny84", + feature = "_mcu-attiny85", + ) + ), +))] +compile_error!( + "When using deprecated globals (default in attiny-hal 0.1.x), you cannot target multiple chips. + + To target multiple chips, turn off deprecated globals by using the following features + + * attiny84-no-deprecated-globals instead of attiny84 + * attiny85-no-deprecated-globals instead of attiny85 + * attiny88-no-deprecated-globals instead of attiny88 + * attiny167-no-deprecated-globals instead of attiny167 + * attiny2313-no-deprecated-globals instead of attiny2313 + " +); + +#[cfg(feature = "_mcu-attiny167")] +pub use crate::attiny167 as hal; + +#[cfg(feature = "_mcu-attiny2313")] +pub use crate::attiny2313 as hal; + +#[cfg(feature = "_mcu-attiny84")] +pub use crate::attiny84 as hal; + +#[cfg(feature = "_mcu-attiny85")] +pub use crate::attiny85 as hal; + +#[cfg(feature = "_mcu-attiny88")] +pub use crate::attiny88 as hal; + +pub use hal::{eeprom, pac, port, wdt, Hal as Attiny, pins}; +pub use {eeprom::Eeprom, pac::Peripherals, port::Pins, wdt::Wdt}; + +#[cfg(feature = "_peripheral-simple-pwm")] +pub use hal::simple_pwm; + +#[cfg(feature = "_peripheral-adc")] +pub use crate::adc::Adc; +#[cfg(feature = "_peripheral-adc")] +pub use hal::adc; + +#[cfg(feature = "_peripheral-spi")] +pub use crate::spi::Spi; +#[cfg(feature = "_peripheral-spi")] +pub use hal::spi; diff --git a/mcu/attiny-hal/src/impl/adc.rs b/mcu/attiny-hal/src/impl/adc.rs new file mode 100644 index 0000000000..f244c7cb71 --- /dev/null +++ b/mcu/attiny-hal/src/impl/adc.rs @@ -0,0 +1,149 @@ +macro_rules! impl_mod_adc { + ( + hal: crate::$hal:ident, + references: { + $( + $(#[$reference_meta:meta])* + $reference_name:ident: |$peripheral_var:ident| $apply_reference:block, + )* + }, + pins: { + $($pin_name:ident: ($pin_channel:expr$(, $didr:ident::$didr_method:ident)?),)+ + }, + channels: { + $($channel_name:ident: $channel_mux: expr,)* + }, + ) => { + pub mod adc { + //! Analog-to-Digital Converter + //! + //! # Example + //! + //! For full source code, please refer to the ATmega ADC example: + //! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) + //! + //! ``` + //! let dp = attiny_hal::Peripherals::take().unwrap(); + //! let pins = attiny_hal::pins!(dp); + //! + //! let mut adc = Adc::new(dp.ADC, Default::default()); + //! + //! let channels: [attiny_hal::adc::Channel; 4] = [ + //! pins.pa0.into_analog_input(&mut adc).into_channel(), + //! pins.pa1.into_analog_input(&mut adc).into_channel(), + //! pins.pa2.into_analog_input(&mut adc).into_channel(), + //! pins.pa3.into_analog_input(&mut adc).into_channel(), + //! ]; + //! + //! for (index, channel) in channels.iter().enumerate() { + //! let value = adc.read_blocking(channel); + //! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); + //! } + //! ``` + + use avr_hal_generic::paste::paste; + use crate::$hal as hal; + + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + $( + $(#[$reference_meta])* + $reference_name, + )* + } + + /// Additional channels + /// + /// Some channels are not directly connected to pins. This module provides types which can be used + /// to access them. + /// + /// # Example + /// ``` + /// let dp = attiny_hal::Peripherals::take().unwrap(); + /// let mut adc = attiny_hal::Adc::new(dp.ADC, Default::default()); + /// + /// let value = adc.read_blocking(&channel::Vbg); + /// ``` + #[allow(non_camel_case_types)] + pub mod channel { + $( + pub struct $channel_name; + )* + } + + pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; + + impl Default for ReferenceVoltage { + fn default() -> Self { + Self::AVcc + } + } + + /// Configuration for the ADC peripheral. + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] + pub struct AdcSettings { + pub clock_divider: ClockDivider, + pub ref_voltage: ReferenceVoltage, + } + + /// Check the [`avr_hal_generic::adc::Adc`] documentation. + pub type Adc = + avr_hal_generic::adc::Adc; + + /// Check the [`avr_hal_generic::adc::Channel`] documentation. + pub type Channel = avr_hal_generic::adc::Channel; + + fn apply_clock(peripheral: &crate::$hal::pac::ADC, settings: AdcSettings) { + peripheral.adcsra.write(|w| { + w.aden().set_bit(); + match settings.clock_divider { + ClockDivider::Factor2 => w.adps().prescaler_2(), + ClockDivider::Factor4 => w.adps().prescaler_4(), + ClockDivider::Factor8 => w.adps().prescaler_8(), + ClockDivider::Factor16 => w.adps().prescaler_16(), + ClockDivider::Factor32 => w.adps().prescaler_32(), + ClockDivider::Factor64 => w.adps().prescaler_64(), + ClockDivider::Factor128 => w.adps().prescaler_128(), + } + }); + } + + paste! { + avr_hal_generic::impl_adc! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::ADC, + settings: crate::$hal::adc::AdcSettings, + apply_settings: |peripheral, settings| { + apply_clock(peripheral, settings); + match settings.ref_voltage { + $( + ReferenceVoltage::$reference_name => { + let $peripheral_var = peripheral; + $apply_reference + }, + )* + } + }, + channel_id: crate::$hal::pac::adc::admux::MUX_A, + set_channel: |peripheral, id| { + peripheral.admux.modify(|_, w| w.mux().variant(id)); + }, + pins: { + $(hal::port::[<$pin_name>]: ($pin_channel $(, $didr::$didr_method)?),)* + }, + channels: { + $(channel::$channel_name: $channel_mux,)* + }, + } + } + + } + pub use adc::Adc; + } +} +pub(crate) use impl_mod_adc; diff --git a/mcu/attiny-hal/src/impl/eeprom.rs b/mcu/attiny-hal/src/impl/eeprom.rs new file mode 100644 index 0000000000..c920d4af37 --- /dev/null +++ b/mcu/attiny-hal/src/impl/eeprom.rs @@ -0,0 +1,48 @@ +macro_rules! impl_mod_eeprom { + ( + hal: crate::$hal:ident, + capacity: $capacity:expr, + addr_width: $addr_width:ty, + addr_reg: $addr_reg:ident $(,)? + ) => { + pub mod eeprom { + //! EEPROM + //! + //! # Example + //! + //! For full source code, please refer to the ATmega EEPROM example: + //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) + //! + //! ``` + //! const BOOT_COUNT_OFFSET: u16 = 0; + //! + //! let dp = attiny_hal::Peripherals::take().unwrap(); + //! let mut eeprom = Eeprom::new(dp.EEPROM); + //! + //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); + //! boot_count = boot_count.wrapping_add(1); + //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); + //! + //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); + //! ``` + + pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; + + pub type Eeprom = + avr_hal_generic::eeprom::Eeprom; + + avr_hal_generic::impl_eeprom_attiny! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::EEPROM, + capacity: $capacity, + addr_width: $addr_width, + set_address: |peripheral, address| { + peripheral.$addr_reg.write(|w| w.bits(address)); + }, + } + } + pub use eeprom::Eeprom; + } +} + +pub(crate) use impl_mod_eeprom; diff --git a/mcu/attiny-hal/src/impl/mod.rs b/mcu/attiny-hal/src/impl/mod.rs new file mode 100644 index 0000000000..4328369349 --- /dev/null +++ b/mcu/attiny-hal/src/impl/mod.rs @@ -0,0 +1,23 @@ +#[cfg(feature = "_peripheral-adc")] +mod adc; +#[cfg(feature = "_peripheral-adc")] +pub(crate) use adc::*; + +mod eeprom; +pub(crate) use eeprom::*; + +mod port; +pub(crate) use port::*; + +#[cfg(feature = "_peripheral-simple-pwm")] +mod simple_pwm; +#[cfg(feature = "_peripheral-simple-pwm")] +pub(crate) use simple_pwm::*; + +#[cfg(feature = "_peripheral-spi")] +mod spi; +#[cfg(feature = "_peripheral-spi")] +pub(crate) use spi::*; + +mod wdt; +pub(crate) use wdt::*; diff --git a/mcu/attiny-hal/src/impl/port.rs b/mcu/attiny-hal/src/impl/port.rs new file mode 100644 index 0000000000..207ef4488a --- /dev/null +++ b/mcu/attiny-hal/src/impl/port.rs @@ -0,0 +1,31 @@ +macro_rules! impl_mod_port { + (use crate::$hal:ident as hal; $($mod:item)*) => { + pub mod port { + //! Port + //! + //! # Example + //! + //! For full source code, please refer to the ATmega port example: + //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) + //! + //! ``` + //! let dp = attiny_hal::Peripherals::take().unwrap(); + //! let pins = attiny_hal::pins!(dp); + //! + //! let mut led = pins.pb2.into_output(); + //! + //! loop { + //! led.toggle(); + //! delay_ms(1000); + //! } + //! ``` + + use crate::$hal as hal; + $($mod)* + } + + pub use {pac::Peripherals, port::Pins, port::pins}; + } +} + +pub(crate) use impl_mod_port; diff --git a/mcu/attiny-hal/src/impl/simple_pwm.rs b/mcu/attiny-hal/src/impl/simple_pwm.rs new file mode 100644 index 0000000000..8726812b3e --- /dev/null +++ b/mcu/attiny-hal/src/impl/simple_pwm.rs @@ -0,0 +1,15 @@ +macro_rules! impl_mod_simple_pwm { + ( + hal: crate::$hal:ident, + $(impl: { + $($impl:item)* + },)? + ) => { + pub mod simple_pwm { + use crate::$hal as hal; + $($($impl)*)? + } + } +} + +pub(crate) use impl_mod_simple_pwm; diff --git a/mcu/attiny-hal/src/impl/spi.rs b/mcu/attiny-hal/src/impl/spi.rs new file mode 100644 index 0000000000..f4c69c1462 --- /dev/null +++ b/mcu/attiny-hal/src/impl/spi.rs @@ -0,0 +1,65 @@ +macro_rules! impl_mod_spi { + ( + hal: crate::$hal:ident, + sclk: $sclk:ident, + mosi: $mosi:ident, + miso: $miso:ident, + cs: $cs:ident $(,)? + ) => { + pub mod spi { + //! SPI + //! + //! # Example + //! + //! For full source code, please refer to the ATmega SPI example: + //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) + //! + //! ``` + //! let dp = attiny_hal::Peripherals::take().unwrap(); + //! let pins = attiny_hal::pins!(dp); + //! + //! let (mut spi, mut cs) = spi::Spi::new( + //! dp.SPI, + //! pins.pa4.into_output(), + //! pins.pa6.into_output(), + //! pins.pa5.into_pull_up_input(), + //! pins.pa3.into_output(), + //! spi::Settings::default(), + //! ); + //! + //! let data_out = b"Hello World!"; + //! let mut data_in = [0u8; 12]; + //! + //! cs.set_low().unwrap(); + //! spi.transfer(&mut data_in, data_out).unwrap(); + //! cs.set_high().unwrap(); + //! + //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); + //! ``` + + pub use avr_hal_generic::spi::*; + use crate::$hal as hal; + + pub type Spi = avr_hal_generic::spi::Spi< + crate::$hal::Hal, + crate::$hal::pac::SPI, + hal::port::$sclk, + hal::port::$mosi, + hal::port::$miso, + hal::port::$cs, + >; + + avr_hal_generic::impl_spi! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::SPI, + sclk: hal::port::$sclk, + mosi: hal::port::$mosi, + miso: hal::port::$miso, + cs: hal::port::$cs, + } + } + pub use spi::Spi; + } +} + +pub(crate) use impl_mod_spi; diff --git a/mcu/attiny-hal/src/impl/wdt.rs b/mcu/attiny-hal/src/impl/wdt.rs new file mode 100644 index 0000000000..5790fd7343 --- /dev/null +++ b/mcu/attiny-hal/src/impl/wdt.rs @@ -0,0 +1,34 @@ +macro_rules! impl_mod_wdt { + ( + hal: $($hal:ident)::+, + wdtcsr_name: $wdtcsr_name:ident $(,)? + ) => { + pub mod wdt { + pub use avr_hal_generic::wdt::{Timeout, WdtOps}; + + avr_hal_generic::impl_wdt! { + hal: $($hal)::+::Hal, + peripheral: $($hal)::+::pac::WDT, + mcusr: $($hal)::+::pac::cpu::MCUSR, + wdtcsr_name: $wdtcsr_name, + timeout: |to, w| match to { + Timeout::Ms16 => w.wdpl().cycles_2k_512k(), + Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), + Timeout::Ms64 => w.wdpl().cycles_8k(), + Timeout::Ms125 => w.wdpl().cycles_16k(), + Timeout::Ms250 => w.wdpl().cycles_32k(), + Timeout::Ms500 => w.wdpl().cycles_64k(), + Timeout::Ms1000 => w.wdpl().cycles_128k(), + Timeout::Ms2000 => w.wdpl().cycles_256k(), + Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), + Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), + }, + } + + pub type Wdt = avr_hal_generic::wdt::Wdt<$($hal)::+::Hal, $($hal)::+::pac::WDT>; + } + pub use wdt::Wdt; + }; +} + +pub(crate) use impl_mod_wdt; diff --git a/mcu/attiny-hal/src/lib.rs b/mcu/attiny-hal/src/lib.rs index a8bf1541e0..2160d4695c 100644 --- a/mcu/attiny-hal/src/lib.rs +++ b/mcu/attiny-hal/src/lib.rs @@ -3,28 +3,19 @@ //! `attiny-hal` //! ============= //! Common HAL (hardware abstraction layer) for ATtiny* microcontrollers. -//! -//! **Note**: This version of the documentation was built for -#![cfg_attr(feature = "attiny85", doc = "**ATtiny85**.")] -#![cfg_attr(feature = "attiny88", doc = "**ATtiny88**.")] -#![cfg_attr(feature = "attiny167", doc = "**ATtiny167**.")] -#![cfg_attr(feature = "attiny2313", doc = "**ATtiny2313**.")] -//! This means that only items which are available for this MCU are visible. If you are using -//! a different chip, try building the documentation locally with: -//! -//! ```text -//! cargo doc --features --open -//! ``` +// This crate can be configured in one of two ways: either you specify deprecated-globals and exactly one MCU +// Or you don't specify deprecated globals and at least one MCU #[cfg(all( - not(feature = "device-selected"), + not(feature = "_mcu-selected"), not(feature = "disable-device-selection-error") ))] compile_error!( - "This crate requires you to specify your target chip as a feature. + "You must specify your target chips as a feature. - Please select one of the following + Please select at least one of the following features + * attiny84 * attiny85 * attiny88 * attiny167 @@ -32,101 +23,28 @@ compile_error!( " ); -/// Reexport of `attiny167` from `avr-device` -/// -#[cfg(feature = "attiny167")] -pub use avr_device::attiny167 as pac; -/// Reexport of `attiny2313` from `avr-device` -/// -#[cfg(feature = "attiny2313")] -pub use avr_device::attiny2313 as pac; -/// Reexport of `attiny84` from `avr-device` -/// -#[cfg(feature = "attiny84")] -pub use avr_device::attiny84 as pac; -/// Reexport of `attiny85` from `avr-device` -/// -#[cfg(feature = "attiny85")] -pub use avr_device::attiny85 as pac; -/// Reexport of `attiny88` from `avr-device` -/// -#[cfg(feature = "attiny88")] -pub use avr_device::attiny88 as pac; - /// See [`avr_device::entry`](https://docs.rs/avr-device/latest/avr_device/attr.entry.html). #[cfg(feature = "rt")] pub use avr_device::entry; -#[cfg(feature = "device-selected")] -pub use pac::Peripherals; - pub use avr_hal_generic::clock; pub use avr_hal_generic::delay; pub use avr_hal_generic::prelude; -// ATtiny2313 does not have ADC and will not compile with this module -#[cfg(all(feature = "device-selected", not(feature = "attiny2313")))] -pub mod adc; -#[cfg(all(feature = "device-selected", not(feature = "attiny2313")))] -pub use adc::Adc; - -#[cfg(feature = "device-selected")] -pub mod port; -#[cfg(feature = "device-selected")] -pub use port::Pins; - -#[cfg(feature = "device-selected")] -pub mod simple_pwm; - -#[cfg(feature = "device-selected")] -pub mod wdt; -#[cfg(feature = "device-selected")] -pub use wdt::Wdt; - -#[cfg(feature = "device-selected")] -pub mod eeprom; -#[cfg(feature = "device-selected")] -pub use eeprom::Eeprom; - -#[cfg(feature = "device-selected")] -pub mod spi; -#[cfg(feature = "device-selected")] -pub use spi::Spi; - -pub struct Attiny; - -#[cfg(feature = "attiny84")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB) - }; -} -#[cfg(feature = "attiny85")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTB) - }; -} -#[cfg(feature = "attiny88")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) - }; -} -#[cfg(feature = "attiny167")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB) - }; -} -#[cfg(feature = "attiny2313")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTD) - }; -} +pub(crate) mod r#impl; + +#[cfg(feature = "_mcu-attiny167")] +pub mod attiny167; +#[cfg(feature = "_mcu-attiny2313")] +pub mod attiny2313; +#[cfg(feature = "_mcu-attiny84")] +pub mod attiny84; +#[cfg(feature = "_mcu-attiny85")] +pub mod attiny85; +#[cfg(feature = "_mcu-attiny88")] +pub mod attiny88; + +#[cfg(feature = "deprecated-globals")] +mod globals; +#[cfg(feature = "deprecated-globals")] +pub use globals::*; diff --git a/mcu/attiny-hal/src/port.rs b/mcu/attiny-hal/src/port.rs deleted file mode 100644 index eaa0818ff1..0000000000 --- a/mcu/attiny-hal/src/port.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Port -//! -//! # Example -//! -//! For full source code, please refer to the ATmega port example: -//! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) -//! -//! ``` -//! let dp = attiny_hal::Peripherals::take().unwrap(); -//! let pins = attiny_hal::pins!(dp); -//! -//! let mut led = pins.pb2.into_output(); -//! -//! loop { -//! led.toggle(); -//! delay_ms(1000); -//! } -//! ``` - -pub use avr_hal_generic::port::{mode, PinMode, PinOps}; - -#[cfg(feature = "attiny2313")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6], - } -} - -#[cfg(feature = "attiny167")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - } -} - -#[cfg(feature = "attiny84")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], - B: crate::pac::PORTB = [0, 1, 2, 3], - } -} - -#[cfg(feature = "attiny85")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5], - } -} - -#[cfg(feature = "attiny88")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - } -} diff --git a/mcu/attiny-hal/src/simple_pwm.rs b/mcu/attiny-hal/src/simple_pwm.rs deleted file mode 100644 index f16a89c9c0..0000000000 --- a/mcu/attiny-hal/src/simple_pwm.rs +++ /dev/null @@ -1,217 +0,0 @@ -pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; - -#[cfg(any(feature = "attiny85", feature = "attiny84", feature = "attiny88"))] -use crate::port::*; - -#[cfg(feature = "attiny84")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB2`, `PA7`) - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PB2: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PA7: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "attiny84")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PA6`, 'PA5') - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_, w| w.wgm1().bits(0b01)); - - tim.tccr1b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - }); - }, - pins: { - PA6: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_, w| w.com1a().bits(0b10)); - } else { - tim.tccr1a.modify(|_, w| w.com1a().disconnected()); - }, - }, - - PA5: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_, w| w.com1b().bits(0b10)); - } else { - tim.tccr1a.modify(|_, w| w.com1b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "attiny85")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB0`, `PB1`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut d0 = pins.d0.into_output().into_pwm(&mut timer0); - /// let mut d1 = pins.d1.into_output().into_pwm(&mut timer0); - /// - /// d0.set_duty(128); - /// d0.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PB0: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PB1: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "attiny85")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB4`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer1); - /// - /// d4.set_duty(128); - /// d4.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.gtccr.modify(|_, w| w.pwm1b().bit(true)); - - tim.tccr1.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - }); - }, - pins: { - PB4: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.gtccr.modify(|_, w| w.com1b().bits(0b10)); - } else { - tim.gtccr.modify(|_, w| w.com1b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "attiny88")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB1`, 'PB2') - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); - /// - /// d9.set_duty(128); - /// d9.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_, w| w.wgm1().bits(0b01)); - - tim.tccr1b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - }); - }, - pins: { - PB1: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_, w| w.com1a().bits(0b10)); - } else { - tim.tccr1a.modify(|_, w| w.com1a().disconnected()); - }, - }, - - PB2: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_, w| w.com1b().bits(0b10)); - } else { - tim.tccr1a.modify(|_, w| w.com1b().disconnected()); - }, - }, - }, - } -} diff --git a/mcu/attiny-hal/src/spi.rs b/mcu/attiny-hal/src/spi.rs deleted file mode 100644 index 65ae277263..0000000000 --- a/mcu/attiny-hal/src/spi.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! SPI -//! -//! # Example -//! -//! For full source code, please refer to the ATmega SPI example: -//! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) -//! -//! ``` -//! let dp = attiny_hal::Peripherals::take().unwrap(); -//! let pins = attiny_hal::pins!(dp); -//! -//! let (mut spi, mut cs) = spi::Spi::new( -//! dp.SPI, -//! pins.pa4.into_output(), -//! pins.pa6.into_output(), -//! pins.pa5.into_pull_up_input(), -//! pins.pa3.into_output(), -//! spi::Settings::default(), -//! ); -//! -//! let data_out = b"Hello World!"; -//! let mut data_in = [0u8; 12]; -//! -//! cs.set_low().unwrap(); -//! spi.transfer(&mut data_in, data_out).unwrap(); -//! cs.set_high().unwrap(); -//! -//! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); -//! ``` - - -#[allow(unused_imports)] -use crate::port; -pub use avr_hal_generic::spi::*; - -#[cfg(feature = "attiny88")] -pub type Spi = avr_hal_generic::spi::Spi< - crate::Attiny, - crate::pac::SPI, - port::PB5, - port::PB3, - port::PB4, - port::PB2, ->; -#[cfg(feature = "attiny88")] -avr_hal_generic::impl_spi! { - hal: crate::Attiny, - peripheral: crate::pac::SPI, - sclk: port::PB5, - mosi: port::PB3, - miso: port::PB4, - cs: port::PB2, -} - -#[cfg(feature = "attiny167")] -pub type Spi = avr_hal_generic::spi::Spi< - crate::Attiny, - crate::pac::SPI, - port::PA5, - port::PA4, - port::PA2, - port::PA6, ->; -#[cfg(feature = "attiny167")] -avr_hal_generic::impl_spi! { - hal: crate::Attiny, - peripheral: crate::pac::SPI, - sclk: port::PA5, - mosi: port::PA4, - miso: port::PA2, - cs: port::PA6, -} diff --git a/mcu/attiny-hal/src/wdt.rs b/mcu/attiny-hal/src/wdt.rs deleted file mode 100644 index 1693051483..0000000000 --- a/mcu/attiny-hal/src/wdt.rs +++ /dev/null @@ -1,44 +0,0 @@ -#[allow(unused_imports)] -pub use avr_hal_generic::wdt::{Timeout, WdtOps}; - -pub type Wdt = avr_hal_generic::wdt::Wdt; - -#[cfg(any(feature = "attiny85", feature = "attiny167", feature = "attiny2313"))] -avr_hal_generic::impl_wdt! { - hal: crate::Attiny, - peripheral: crate::pac::WDT, - mcusr: crate::pac::cpu::MCUSR, - wdtcsr_name: wdtcr, - timeout: |to, w| match to { - Timeout::Ms16 => w.wdpl().cycles_2k_512k(), - Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), - Timeout::Ms64 => w.wdpl().cycles_8k(), - Timeout::Ms125 => w.wdpl().cycles_16k(), - Timeout::Ms250 => w.wdpl().cycles_32k(), - Timeout::Ms500 => w.wdpl().cycles_64k(), - Timeout::Ms1000 => w.wdpl().cycles_128k(), - Timeout::Ms2000 => w.wdpl().cycles_256k(), - Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), - Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), - }, -} - -#[cfg(any(feature = "attiny84", feature = "attiny88"))] -avr_hal_generic::impl_wdt! { - hal: crate::Attiny, - peripheral: crate::pac::WDT, - mcusr: crate::pac::cpu::MCUSR, - wdtcsr_name: wdtcsr, - timeout: |to, w| match to { - Timeout::Ms16 => w.wdpl().cycles_2k_512k(), - Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), - Timeout::Ms64 => w.wdpl().cycles_8k(), - Timeout::Ms125 => w.wdpl().cycles_16k(), - Timeout::Ms250 => w.wdpl().cycles_32k(), - Timeout::Ms500 => w.wdpl().cycles_64k(), - Timeout::Ms1000 => w.wdpl().cycles_128k(), - Timeout::Ms2000 => w.wdpl().cycles_256k(), - Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), - Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), - }, -} From 4df103fe9ac5beeb592c7849434318e981d8bf02 Mon Sep 17 00:00:00 2001 From: Iris Artin Date: Sun, 29 Dec 2024 17:33:15 -0500 Subject: [PATCH 2/4] Fixed attiny doctests --- .github/workflows/ci.yml | 5 +++ mcu/attiny-hal/Cargo.toml | 4 ++ mcu/attiny-hal/src/attiny85.rs | 28 +++++++++----- mcu/attiny-hal/src/attiny88.rs | 15 +++++--- mcu/attiny-hal/src/impl/adc.rs | 61 +++++++++++++++++++------------ mcu/attiny-hal/src/impl/eeprom.rs | 9 ++--- mcu/attiny-hal/src/impl/port.rs | 14 +++++-- mcu/attiny-hal/src/impl/spi.rs | 32 +++++++++------- 8 files changed, 109 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63fc8e6511..edbbe64a53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,6 +124,11 @@ jobs: run: >- cd "mcu/${{ matrix.m.crate }}" && cargo build --features "${{ matrix.m.name }}-no-deprecated-globals" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" + - name: Compile doctests for an MCU (no deprecated globals) + if: "${{ matrix.m.crate == 'attiny-hal' }}" + run: >- + cd "mcu/${{ matrix.m.crate }}" && + cargo test --doc --features "${{ matrix.m.name }}-no-deprecated-globals" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" ravedude: name: "ravedude" diff --git a/mcu/attiny-hal/Cargo.toml b/mcu/attiny-hal/Cargo.toml index 561e90da07..c0eea8cf98 100644 --- a/mcu/attiny-hal/Cargo.toml +++ b/mcu/attiny-hal/Cargo.toml @@ -67,6 +67,10 @@ _peripheral-spi = [] _peripheral-simple-pwm = [] +[dev-dependencies] +ufmt = "0.2.0" +embedded-hal = "1.0" + [dependencies] avr-hal-generic = { path = "../../avr-hal-generic/" } diff --git a/mcu/attiny-hal/src/attiny85.rs b/mcu/attiny-hal/src/attiny85.rs index bc8a8e9d54..3d73195b70 100644 --- a/mcu/attiny-hal/src/attiny85.rs +++ b/mcu/attiny-hal/src/attiny85.rs @@ -72,14 +72,19 @@ impl_mod_simple_pwm! { /// Use `TC0` for PWM (pins `PB0`, `PB1`) /// /// # Example - /// ``` + /// ```no_run + /// use attiny_hal::attiny85 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); /// - /// let mut d0 = pins.d0.into_output().into_pwm(&mut timer0); - /// let mut d1 = pins.d1.into_output().into_pwm(&mut timer0); + /// let mut pb0 = pins.pb0.into_output().into_pwm(&mut timer0); + /// let mut pb1 = pins.pb1.into_output().into_pwm(&mut timer0); /// - /// d0.set_duty(128); - /// d0.enable(); + /// pb0.set_duty(128); + /// pb0.enable(); /// ``` pub struct Timer0Pwm { timer: crate::attiny85::pac::TC0, @@ -119,13 +124,18 @@ impl_mod_simple_pwm! { /// Use `TC1` for PWM (pins `PB4`) /// /// # Example - /// ``` + /// ```no_run + /// use attiny_hal::attiny85 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer1); + /// let mut pb4 = pins.pb4.into_output().into_pwm(&mut timer1); /// - /// d4.set_duty(128); - /// d4.enable(); + /// pb4.set_duty(128); + /// pb4.enable(); /// ``` pub struct Timer1Pwm { timer: crate::attiny85::pac::TC1, diff --git a/mcu/attiny-hal/src/attiny88.rs b/mcu/attiny-hal/src/attiny88.rs index d255dfe2f8..7957892177 100644 --- a/mcu/attiny-hal/src/attiny88.rs +++ b/mcu/attiny-hal/src/attiny88.rs @@ -72,14 +72,19 @@ impl_mod_simple_pwm! { /// Use `TC1` for PWM (pins `PB1`, 'PB2') /// /// # Example - /// ``` + /// ```no_run + /// use attiny_hal::attiny88 as hal; + /// use hal::simple_pwm::{Timer1Pwm,Prescaler,IntoPwmPin}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); + /// let mut pb1 = pins.pb1.into_output().into_pwm(&mut timer1); + /// let mut pb2 = pins.pb2.into_output().into_pwm(&mut timer1); /// - /// d9.set_duty(128); - /// d9.enable(); + /// pb1.set_duty(128); + /// pb1.enable(); /// ``` pub struct Timer1Pwm { timer: crate::attiny88::pac::TC1, diff --git a/mcu/attiny-hal/src/impl/adc.rs b/mcu/attiny-hal/src/impl/adc.rs index f244c7cb71..9751b881dc 100644 --- a/mcu/attiny-hal/src/impl/adc.rs +++ b/mcu/attiny-hal/src/impl/adc.rs @@ -17,28 +17,51 @@ macro_rules! impl_mod_adc { pub mod adc { //! Analog-to-Digital Converter //! - //! # Example - //! //! For full source code, please refer to the ATmega ADC example: //! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) //! + //! # Example: Read pins using `analog_read()` + //! + //! ```no_run + #![doc = concat!("use attiny_hal::", stringify!($hal), " as hal;")] + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); + //! + //! type Clock = avr_hal_generic::clock::MHz16; + //! let mut adc = hal::Adc::::new(dp.ADC, Default::default()); + //! + $( + #![doc = paste!{ concat!( + "let ", stringify!([< input_ $pin_name:lower >]), " = pins.", stringify!([< $pin_name:lower >]), ".into_analog_input(&mut adc);\n", + "let ", stringify!([< value_ $pin_name:lower >]), " = ", stringify!([< input_ $pin_name:lower >]), ".analog_read(&mut adc);\n\n" + )}] + )* //! ``` - //! let dp = attiny_hal::Peripherals::take().unwrap(); - //! let pins = attiny_hal::pins!(dp); //! - //! let mut adc = Adc::new(dp.ADC, Default::default()); + //! # Example: Read channels (including pins) using `read_blocking()` + //! + //! ```no_run + #![doc = concat!("use attiny_hal::", stringify!($hal), " as hal;")] //! - //! let channels: [attiny_hal::adc::Channel; 4] = [ - //! pins.pa0.into_analog_input(&mut adc).into_channel(), - //! pins.pa1.into_analog_input(&mut adc).into_channel(), - //! pins.pa2.into_analog_input(&mut adc).into_channel(), - //! pins.pa3.into_analog_input(&mut adc).into_channel(), - //! ]; + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! for (index, channel) in channels.iter().enumerate() { - //! let value = adc.read_blocking(channel); - //! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); - //! } + //! type Clock = avr_hal_generic::clock::MHz16; + //! let mut adc = hal::Adc::::new(dp.ADC, Default::default()); + //! + //! // + $( + #![doc = paste!{ concat!( + "let ", stringify!([< channel_ $pin_name:lower >]), " = pins.", stringify!([< $pin_name:lower >]), ".into_analog_input(&mut adc).into_channel();\n", + "let ", stringify!([< value_ $pin_name:lower >]), " = adc.read_blocking(&", stringify!([< channel_ $pin_name:lower >]), ");\n\n" + ) }] + )* + $( + #![doc = paste!{ concat!( + "let ", stringify!([< value_ $channel_name:lower >]), " = adc.read_blocking(&hal::adc::channel::", stringify!([< $channel_name >]), ");\n\n" + ) }] + )* //! ``` use avr_hal_generic::paste::paste; @@ -61,14 +84,6 @@ macro_rules! impl_mod_adc { /// /// Some channels are not directly connected to pins. This module provides types which can be used /// to access them. - /// - /// # Example - /// ``` - /// let dp = attiny_hal::Peripherals::take().unwrap(); - /// let mut adc = attiny_hal::Adc::new(dp.ADC, Default::default()); - /// - /// let value = adc.read_blocking(&channel::Vbg); - /// ``` #[allow(non_camel_case_types)] pub mod channel { $( diff --git a/mcu/attiny-hal/src/impl/eeprom.rs b/mcu/attiny-hal/src/impl/eeprom.rs index c920d4af37..534a1fef12 100644 --- a/mcu/attiny-hal/src/impl/eeprom.rs +++ b/mcu/attiny-hal/src/impl/eeprom.rs @@ -13,17 +13,16 @@ macro_rules! impl_mod_eeprom { //! For full source code, please refer to the ATmega EEPROM example: //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) //! - //! ``` + //! ```no_run + #![doc = concat!("use attiny_hal::", stringify!($hal), " as hal;")] //! const BOOT_COUNT_OFFSET: u16 = 0; //! - //! let dp = attiny_hal::Peripherals::take().unwrap(); - //! let mut eeprom = Eeprom::new(dp.EEPROM); + //! let dp = hal::Peripherals::take().unwrap(); + //! let mut eeprom = hal::Eeprom::new(dp.EEPROM); //! //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); //! boot_count = boot_count.wrapping_add(1); //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); - //! - //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); //! ``` pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; diff --git a/mcu/attiny-hal/src/impl/port.rs b/mcu/attiny-hal/src/impl/port.rs index 207ef4488a..6d9f110fa5 100644 --- a/mcu/attiny-hal/src/impl/port.rs +++ b/mcu/attiny-hal/src/impl/port.rs @@ -8,15 +8,21 @@ macro_rules! impl_mod_port { //! For full source code, please refer to the ATmega port example: //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) //! - //! ``` - //! let dp = attiny_hal::Peripherals::take().unwrap(); - //! let pins = attiny_hal::pins!(dp); + //! ```no_run + //! use attiny_hal::prelude::*; + #![doc = concat!("use attiny_hal::", stringify!($hal), " as hal;")] + //! + //! type Clock = attiny_hal::clock::MHz8; + //! let mut delay = attiny_hal::delay::Delay::::new(); + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! //! let mut led = pins.pb2.into_output(); //! //! loop { //! led.toggle(); - //! delay_ms(1000); + //! delay.delay_ms(1000u16); //! } //! ``` diff --git a/mcu/attiny-hal/src/impl/spi.rs b/mcu/attiny-hal/src/impl/spi.rs index f4c69c1462..7c3cb52b07 100644 --- a/mcu/attiny-hal/src/impl/spi.rs +++ b/mcu/attiny-hal/src/impl/spi.rs @@ -14,18 +14,25 @@ macro_rules! impl_mod_spi { //! For full source code, please refer to the ATmega SPI example: //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) //! - //! ``` - //! let dp = attiny_hal::Peripherals::take().unwrap(); - //! let pins = attiny_hal::pins!(dp); + //! ```no_run + #![doc = concat!("use attiny_hal::", stringify!($hal), " as hal;")] + //! + //! use embedded_hal::digital::OutputPin; + //! use embedded_hal::spi::SpiBus; + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! let (mut spi, mut cs) = spi::Spi::new( - //! dp.SPI, - //! pins.pa4.into_output(), - //! pins.pa6.into_output(), - //! pins.pa5.into_pull_up_input(), - //! pins.pa3.into_output(), - //! spi::Settings::default(), - //! ); + #![doc = paste!{ concat!( + "let (mut spi, mut cs) = hal::spi::Spi::new(\n", + " dp.SPI,\n", + " pins.", stringify!([< $sclk:lower >]), ".into_output(),\n", + " pins.", stringify!([< $mosi:lower >]), ".into_output(),\n", + " pins.", stringify!([< $miso:lower >]), ".into_pull_up_input(),\n", + " pins.", stringify!([< $cs:lower >]), ".into_output(),\n", + " hal::spi::Settings::default(),\n", + ");\n", + ) }] //! //! let data_out = b"Hello World!"; //! let mut data_in = [0u8; 12]; @@ -33,11 +40,10 @@ macro_rules! impl_mod_spi { //! cs.set_low().unwrap(); //! spi.transfer(&mut data_in, data_out).unwrap(); //! cs.set_high().unwrap(); - //! - //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); //! ``` pub use avr_hal_generic::spi::*; + use avr_hal_generic::paste::paste; use crate::$hal as hal; pub type Spi = avr_hal_generic::spi::Spi< From 7935db6b1e8c81052b229f98645d5ac7cd3a35f3 Mon Sep 17 00:00:00 2001 From: Iris Artin Date: Thu, 21 Nov 2024 20:41:51 -0500 Subject: [PATCH 3/4] Refactor atmega-hal for opt-out deprecated globals --- .github/workflows/ci.yml | 2 +- mcu/atmega-hal/Cargo.toml | 143 ++- mcu/atmega-hal/src/adc.rs | 398 --------- mcu/atmega-hal/src/atmega1280.rs | 130 +++ mcu/atmega-hal/src/atmega1284p.rs | 308 +++++++ mcu/atmega-hal/src/atmega128a.rs | 203 +++++ mcu/atmega-hal/src/atmega164pa.rs | 200 +++++ mcu/atmega-hal/src/atmega168.rs | 101 +++ mcu/atmega-hal/src/atmega2560.rs | 115 +++ mcu/atmega-hal/src/atmega328p.rs | 101 +++ mcu/atmega-hal/src/atmega328pb.rs | 210 +++++ mcu/atmega-hal/src/atmega32a.rs | 99 +++ mcu/atmega-hal/src/atmega32u4.rs | 318 +++++++ mcu/atmega-hal/src/atmega48p.rs | 88 ++ mcu/atmega-hal/src/atmega8.rs | 188 ++++ mcu/atmega-hal/src/eeprom.rs | 109 --- mcu/atmega-hal/src/globals.rs | 271 ++++++ mcu/atmega-hal/src/i2c.rs | 139 --- mcu/atmega-hal/src/impl/adc.rs | 229 +++++ mcu/atmega-hal/src/impl/eeprom.rs | 50 ++ mcu/atmega-hal/src/impl/i2c.rs | 58 ++ mcu/atmega-hal/src/impl/mod.rs | 25 + mcu/atmega-hal/src/impl/port.rs | 85 ++ mcu/atmega-hal/src/impl/simple_pwm.rs | 535 +++++++++++ mcu/atmega-hal/src/impl/spi.rs | 74 ++ mcu/atmega-hal/src/impl/usart.rs | 199 +++++ mcu/atmega-hal/src/impl/wdt.rs | 88 ++ mcu/atmega-hal/src/lib.rs | 231 ++--- mcu/atmega-hal/src/port.rs | 109 --- mcu/atmega-hal/src/simple_pwm.rs | 1177 ------------------------- mcu/atmega-hal/src/spi.rs | 147 --- mcu/atmega-hal/src/usart.rs | 411 --------- mcu/atmega-hal/src/wdt.rs | 44 - 33 files changed, 3853 insertions(+), 2732 deletions(-) delete mode 100644 mcu/atmega-hal/src/adc.rs create mode 100644 mcu/atmega-hal/src/atmega1280.rs create mode 100644 mcu/atmega-hal/src/atmega1284p.rs create mode 100644 mcu/atmega-hal/src/atmega128a.rs create mode 100644 mcu/atmega-hal/src/atmega164pa.rs create mode 100644 mcu/atmega-hal/src/atmega168.rs create mode 100644 mcu/atmega-hal/src/atmega2560.rs create mode 100644 mcu/atmega-hal/src/atmega328p.rs create mode 100644 mcu/atmega-hal/src/atmega328pb.rs create mode 100644 mcu/atmega-hal/src/atmega32a.rs create mode 100644 mcu/atmega-hal/src/atmega32u4.rs create mode 100644 mcu/atmega-hal/src/atmega48p.rs create mode 100644 mcu/atmega-hal/src/atmega8.rs delete mode 100644 mcu/atmega-hal/src/eeprom.rs create mode 100644 mcu/atmega-hal/src/globals.rs delete mode 100644 mcu/atmega-hal/src/i2c.rs create mode 100644 mcu/atmega-hal/src/impl/adc.rs create mode 100644 mcu/atmega-hal/src/impl/eeprom.rs create mode 100644 mcu/atmega-hal/src/impl/i2c.rs create mode 100644 mcu/atmega-hal/src/impl/mod.rs create mode 100644 mcu/atmega-hal/src/impl/port.rs create mode 100644 mcu/atmega-hal/src/impl/simple_pwm.rs create mode 100644 mcu/atmega-hal/src/impl/spi.rs create mode 100644 mcu/atmega-hal/src/impl/usart.rs create mode 100644 mcu/atmega-hal/src/impl/wdt.rs delete mode 100644 mcu/atmega-hal/src/port.rs delete mode 100644 mcu/atmega-hal/src/simple_pwm.rs delete mode 100644 mcu/atmega-hal/src/spi.rs delete mode 100644 mcu/atmega-hal/src/usart.rs delete mode 100644 mcu/atmega-hal/src/wdt.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edbbe64a53..e0b0da4aa4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,7 @@ jobs: if: "${{ matrix.m.type == 'mcu' }}" run: cd "mcu/${{ matrix.m.crate }}" && cargo build --features "${{ matrix.m.name }}" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" - name: Test-compile HAL crate for an MCU (no deprecated globals) - if: "${{ matrix.m.crate == 'attiny-hal' }}" + if: "${{ matrix.m.crate == 'attiny-hal' || matrix.m.crate == 'atmega-hal' }}" run: >- cd "mcu/${{ matrix.m.crate }}" && cargo build --features "${{ matrix.m.name }}-no-deprecated-globals" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" diff --git a/mcu/atmega-hal/Cargo.toml b/mcu/atmega-hal/Cargo.toml index ebe5a12a4b..5d19b35218 100644 --- a/mcu/atmega-hal/Cargo.toml +++ b/mcu/atmega-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "atmega-hal" -version = "0.1.0" +version = "0.2.0" authors = ["Rahix "] edition = "2021" @@ -12,28 +12,137 @@ categories = ["no-std", "embedded", "hardware-support"] [features] rt = ["avr-device/rt"] -device-selected = [] enable-extra-adc = [] -atmega48p = ["avr-device/atmega48p", "device-selected"] -atmega164pa = ["avr-device/atmega164pa", "device-selected"] -atmega168 = ["avr-device/atmega168", "device-selected"] -atmega328p = ["avr-device/atmega328p", "device-selected"] -atmega328pb = ["avr-device/atmega328pb", "device-selected"] -atmega32a = ["avr-device/atmega32a", "device-selected"] -atmega32u4 = ["avr-device/atmega32u4", "device-selected"] -atmega2560 = ["avr-device/atmega2560", "device-selected"] -atmega128a = ["avr-device/atmega128a", "device-selected"] -atmega1280 = ["avr-device/atmega1280", "device-selected"] -atmega1284p = ["avr-device/atmega1284p", "device-selected"] -atmega8 = ["avr-device/atmega8", "device-selected"] + +# MCU-specific targets. Due to use of deprecated globals, only one MCU can be selected at a time +# In atmega-hal 0.3.0 the defaults will change to no deprecated globals +atmega48p = ["atmega48p-deprecated-globals"] +atmega164pa = ["atmega164pa-deprecated-globals"] +atmega168 = ["atmega168-deprecated-globals"] +atmega328p = ["atmega328p-deprecated-globals"] +atmega328pb = ["atmega328pb-deprecated-globals"] +atmega32a = ["atmega32a-deprecated-globals"] +atmega32u4 = ["atmega32u4-deprecated-globals"] +atmega2560 = ["atmega2560-deprecated-globals"] +atmega128a = ["atmega128a-deprecated-globals"] +atmega1280 = ["atmega1280-deprecated-globals"] +atmega1284p = ["atmega1284p-deprecated-globals"] +atmega8 = ["atmega8-deprecated-globals"] + +# MCU-specific targets with deprecated globals. This is the default in atmega-hal <0.3.0 +atmega48p-deprecated-globals = ["_mcu-atmega48p", "deprecated-globals"] +atmega164pa-deprecated-globals = ["_mcu-atmega164pa", "deprecated-globals"] +atmega168-deprecated-globals = ["_mcu-atmega168", "deprecated-globals"] +atmega328p-deprecated-globals = ["_mcu-atmega328p", "deprecated-globals"] +atmega328pb-deprecated-globals = ["_mcu-atmega328pb", "deprecated-globals"] +atmega32a-deprecated-globals = ["_mcu-atmega32a", "deprecated-globals"] +atmega32u4-deprecated-globals = ["_mcu-atmega32u4", "deprecated-globals"] +atmega2560-deprecated-globals = ["_mcu-atmega2560", "deprecated-globals"] +atmega128a-deprecated-globals = ["_mcu-atmega128a", "deprecated-globals"] +atmega1280-deprecated-globals = ["_mcu-atmega1280", "deprecated-globals"] +atmega1284p-deprecated-globals = ["_mcu-atmega1284p", "deprecated-globals"] +atmega8-deprecated-globals = ["_mcu-atmega8", "deprecated-globals"] + +# MCU-specific targets without deprecated globals. This will be the default in atmega-hal 0.3.0 +atmega48p-no-deprecated-globals = ["_mcu-atmega48p"] +atmega164pa-no-deprecated-globals = ["_mcu-atmega164pa"] +atmega168-no-deprecated-globals = ["_mcu-atmega168"] +atmega328p-no-deprecated-globals = ["_mcu-atmega328p"] +atmega328pb-no-deprecated-globals = ["_mcu-atmega328pb"] +atmega32a-no-deprecated-globals = ["_mcu-atmega32a"] +atmega32u4-no-deprecated-globals = ["_mcu-atmega32u4"] +atmega2560-no-deprecated-globals = ["_mcu-atmega2560"] +atmega128a-no-deprecated-globals = ["_mcu-atmega128a"] +atmega1280-no-deprecated-globals = ["_mcu-atmega1280"] +atmega1284p-no-deprecated-globals = ["_mcu-atmega1284p"] +atmega8-no-deprecated-globals = ["_mcu-atmega8"] critical-section-impl = ["avr-device/critical-section-impl"] -# Allow certain downstream crates to overwrite the device selection error by themselves. +default = [] + +docsrs = [ + "atmega48p-no-deprecated-globals", + "atmega164pa-no-deprecated-globals", + "atmega168-no-deprecated-globals", + "atmega328p-no-deprecated-globals", + "atmega328pb-no-deprecated-globals", + "atmega32a-no-deprecated-globals", + "atmega32u4-no-deprecated-globals", + "atmega2560-no-deprecated-globals", + "atmega128a-no-deprecated-globals", + "atmega1280-no-deprecated-globals", + "atmega1284p-no-deprecated-globals", + "atmega8-no-deprecated-globals", +] + +# Include soon-to-be-deprecated globals in the crate. Only one MCU can be selected if deprecated globals are enabled +deprecated-globals = [] + +# If using this crate from another library crate you may want to suppress this error and provide your own disable-device-selection-error = [] -# We must select a microcontroller to build on docs.rs -docsrs = ["atmega328p"] +# MCU-specific implementation features +# Do not use directly; use either an -deprecated-globals feature or any number of -no-deprecated-globals features +_mcu-atmega48p = ["_mcu-selected", "_peripheral-spi", "_peripheral-simple-pwm", "avr-device/atmega48p"] +_mcu-atmega164pa = ["_mcu-selected", "_peripheral-usart", "_peripheral-simple-pwm", "avr-device/atmega164pa"] +_mcu-atmega168 = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega168", +] +_mcu-atmega328p = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega328p", +] +_mcu-atmega328pb = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega328pb", +] +_mcu-atmega32a = ["_mcu-selected", "_peripheral-usart", "_peripheral-spi", "avr-device/atmega32a"] +_mcu-atmega32u4 = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega32u4", +] +_mcu-atmega2560 = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega2560", +] +_mcu-atmega128a = ["_mcu-selected", "_peripheral-usart", "_peripheral-spi", "avr-device/atmega128a"] +_mcu-atmega1280 = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega1280", +] +_mcu-atmega1284p = [ + "_mcu-selected", + "_peripheral-usart", + "_peripheral-spi", + "_peripheral-simple-pwm", + "avr-device/atmega1284p", +] +_mcu-atmega8 = ["_mcu-selected", "_peripheral-usart", "_peripheral-spi", "_peripheral-simple-pwm", "avr-device/atmega8"] + +_mcu-selected = [] +_peripheral-simple-pwm = [] +_peripheral-spi = [] +_peripheral-usart = [] [dependencies] avr-hal-generic = { path = "../../avr-hal-generic/" } diff --git a/mcu/atmega-hal/src/adc.rs b/mcu/atmega-hal/src/adc.rs deleted file mode 100644 index 97df94018b..0000000000 --- a/mcu/atmega-hal/src/adc.rs +++ /dev/null @@ -1,398 +0,0 @@ -//! Analog-to-Digital Converter -//! -//! # Example -//! -//! Complete example source code can be found in the repository: -//! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) -//! -//! ``` -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let pins = atmega_hal::pins!(dp); -//! -//! let mut adc = Adc::new(dp.ADC, Default::default()); -//! -//! let channels: [atmega_hal::adc::Channel; 4] = [ -//! pins.pf0.into_analog_input(&mut adc).into_channel(), -//! pins.pf1.into_analog_input(&mut adc).into_channel(), -//! pins.pf2.into_analog_input(&mut adc).into_channel(), -//! pins.pf3.into_analog_input(&mut adc).into_channel(), -//! ]; -//! -//! for (index, channel) in channels.iter().enumerate() { -//! let value = adc.read_blocking(channel); -//! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); -//! } -//! ``` - -use crate::port; -pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; - -/// Select the voltage reference for the ADC peripheral -/// -/// The internal voltage reference options may not be used if an external reference voltage is -/// being applied to the AREF pin. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum ReferenceVoltage { - /// Voltage applied to AREF pin. - Aref, - /// Default reference voltage (default). - AVcc, - /// Internal reference voltage. - Internal, -} - -impl Default for ReferenceVoltage { - fn default() -> Self { - Self::AVcc - } -} - -/// Configuration for the ADC peripheral. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub struct AdcSettings { - pub clock_divider: ClockDivider, - pub ref_voltage: ReferenceVoltage, -} - -fn apply_settings(peripheral: &crate::pac::ADC, settings: AdcSettings) { - peripheral.adcsra.write(|w| { - w.aden().set_bit(); - match settings.clock_divider { - ClockDivider::Factor2 => w.adps().prescaler_2(), - ClockDivider::Factor4 => w.adps().prescaler_4(), - ClockDivider::Factor8 => w.adps().prescaler_8(), - ClockDivider::Factor16 => w.adps().prescaler_16(), - ClockDivider::Factor32 => w.adps().prescaler_32(), - ClockDivider::Factor64 => w.adps().prescaler_64(), - ClockDivider::Factor128 => w.adps().prescaler_128(), - } - }); - peripheral.admux.write(|w| match settings.ref_voltage { - ReferenceVoltage::Aref => w.refs().aref(), - ReferenceVoltage::AVcc => w.refs().avcc(), - ReferenceVoltage::Internal => w.refs().internal(), - }); -} - -/// Check the [`avr_hal_generic::adc::Adc`] documentation. -pub type Adc = avr_hal_generic::adc::Adc; - -/// Check the [`avr_hal_generic::adc::Channel`] documentation. -pub type Channel = avr_hal_generic::adc::Channel; - -/// Additional channels -/// -/// Some channels are not directly connected to pins. This module provides types which can be used -/// to access them. -/// -/// # Example -/// ``` -/// let dp = atmega_hal::Peripherals::take().unwrap(); -/// let mut adc = atmega_hal::Adc::new(dp.ADC, Default::default()); -/// -/// let value = adc.read_blocking(&channel::Vbg); -/// ``` -pub mod channel { - #[cfg(all( - any( - feature = "atmega168", - feature = "atmega32a", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega48p", - feature = "atmega128a", - feature = "atmega1284p", - feature = "atmega8", - ), - feature = "enable-extra-adc", - ))] - pub struct ADC6; - #[cfg(all( - any( - feature = "atmega168", - feature = "atmega32a", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega48p", - feature = "atmega128a", - feature = "atmega1284p", - feature = "atmega8", - ), - feature = "enable-extra-adc", - ))] - pub struct ADC7; - #[cfg(any( - feature = "atmega1280", - feature = "atmega168", - feature = "atmega2560", - feature = "atmega32a", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega32u4", - feature = "atmega48p", - feature = "atmega128a", - feature = "atmega1284p", - feature = "atmega8", - feature = "atmega164pa", - ))] - pub struct Vbg; - #[cfg(any( - feature = "atmega1280", - feature = "atmega168", - feature = "atmega2560", - feature = "atmega32a", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega32u4", - feature = "atmega48p", - feature = "atmega128a", - feature = "atmega1284p", - feature = "atmega8", - feature = "atmega164pa", - ))] - pub struct Gnd; - #[cfg(any( - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega32u4", - feature = "atmega48p", - ))] - pub struct Temperature; -} - -#[cfg(any( - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega48p", -))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - }, - channels: { - #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, - #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - #[cfg(any(feature = "atmega328p", feature = "atmega328pb", feature = "atmega48p"))] - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} - -#[cfg(any(feature = "atmega32a"))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} - -#[cfg(feature = "atmega32u4")] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: u8, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f)); - peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0)); - }, - pins: { - port::PF0: (0b000000, didr0::adc0d), - port::PF1: (0b000001, didr0::adc1d), - port::PF4: (0b000100, didr0::adc4d), - port::PF5: (0b000101, didr0::adc5d), - port::PF6: (0b000110, didr0::adc6d), - port::PF7: (0b000111, didr0::adc7d), - port::PD4: (0b100000, didr2::adc8d), - port::PD6: (0b100001, didr2::adc9d), - port::PD7: (0b100010, didr2::adc10d), - port::PB4: (0b100011, didr2::adc11d), - port::PB5: (0b100100, didr2::adc12d), - port::PB6: (0b100101, didr2::adc13d), - }, - channels: { - channel::Vbg: 0b011110, - channel::Gnd: 0b011111, - channel::Temperature: 0b100111, - }, -} - -#[cfg(feature = "atmega128a")] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PF0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PF1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PF2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PF3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PF4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PF5: (crate::pac::adc::admux::MUX_A::ADC5), - port::PF6: (crate::pac::adc::admux::MUX_A::ADC6), - port::PF7: (crate::pac::adc::admux::MUX_A::ADC7), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} - -#[cfg(any(feature = "atmega2560", feature = "atmega1280"))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: u8, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f)); - peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0)); - }, - pins: { - port::PF0: (0b000000, didr0::adc0d), - port::PF1: (0b000001, didr0::adc1d), - port::PF2: (0b000010, didr0::adc2d), - port::PF3: (0b000011, didr0::adc3d), - port::PF4: (0b000100, didr0::adc4d), - port::PF5: (0b000101, didr0::adc5d), - port::PF6: (0b000110, didr0::adc6d), - port::PF7: (0b000111, didr0::adc7d), - port::PK0: (0b100000, didr2::adc8d), - port::PK1: (0b100001, didr2::adc9d), - port::PK2: (0b100010, didr2::adc10d), - port::PK3: (0b100011, didr2::adc11d), - port::PK4: (0b100100, didr2::adc12d), - port::PK5: (0b100101, didr2::adc13d), - port::PK6: (0b100110, didr2::adc14d), - port::PK7: (0b100111, didr2::adc15d), - }, - channels: { - channel::Vbg: 0b011110, - channel::Gnd: 0b011111, - }, -} - -#[cfg(any(feature = "atmega1284p"))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - }, - channels: { - #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, - #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} - -#[cfg(any(feature = "atmega8"))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5), - }, - channels: { - #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, - #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} - -#[cfg(any(feature = "atmega164pa"))] -avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} diff --git a/mcu/atmega-hal/src/atmega1280.rs b/mcu/atmega-hal/src/atmega1280.rs new file mode 100644 index 0000000000..8713ce3b52 --- /dev/null +++ b/mcu/atmega-hal/src/atmega1280.rs @@ -0,0 +1,130 @@ +pub use avr_device::atmega1280 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega1280, + pins: { + PF0: (0b000000, didr0::adc0d), + PF1: (0b000001, didr0::adc1d), + PF2: (0b000010, didr0::adc2d), + PF3: (0b000011, didr0::adc3d), + PF4: (0b000100, didr0::adc4d), + PF5: (0b000101, didr0::adc5d), + PF6: (0b000110, didr0::adc6d), + PF7: (0b000111, didr0::adc7d), + PK0: (0b100000, didr2::adc8d), + PK1: (0b100001, didr2::adc9d), + PK2: (0b100010, didr2::adc10d), + PK3: (0b100011, didr2::adc11d), + PK4: (0b100100, didr2::adc12d), + PK5: (0b100101, didr2::adc13d), + PK6: (0b100110, didr2::adc14d), + PK7: (0b100111, didr2::adc15d), + }, + channels: { + Vbg: 0b011110, + Gnd: 0b011111, + }, + impl!: impl_adc_admux_adcsrb, +} + +impl_mod_eeprom! { + hal: crate::atmega1280, + capacity: 4096, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega1280, + interfaces: { + I2c: { + peripheral: TWI, + sda: PD1, + scl: PD0, + }, + }, +} + +impl_mod_port! { + use crate::atmega1280 as hal; + impl_port_peripheral_a8_b8_c8_d8_e8_f8_g6_h8_j8_k8_l8! { + } + + #[macro_export] + macro_rules! atmega1280_pins { + ($p:expr) => { + $crate::atmega1280::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF, $p.PORTG, $p.PORTH, $p.PORTJ, $p.PORTK, $p.PORTL) + }; + } + + pub use atmega1280_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega1280, + impl!: impl_simple_pwm_1280_2560, +} + +impl_mod_spi! { + hal: crate::atmega1280, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB1, + mosi: PB2, + miso: PB3, + cs: PB0, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega1280, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PE0, + tx: PE1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + Usart2: { + peripheral: USART2, + rx: PH0, + tx: PH1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 2, + }, + }, + Usart3: { + peripheral: USART3, + rx: PJ0, + tx: PJ1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 3, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega1280 as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} diff --git a/mcu/atmega-hal/src/atmega1284p.rs b/mcu/atmega-hal/src/atmega1284p.rs new file mode 100644 index 0000000000..8e8894c547 --- /dev/null +++ b/mcu/atmega-hal/src/atmega1284p.rs @@ -0,0 +1,308 @@ +pub use avr_device::atmega1284p as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega1284p, + pins: { + PA0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PA1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PA2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PA3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PA4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PA5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega1284p, + capacity: 4096, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega1284p, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC1, + scl: PC0, + }, + }, +} + +impl_mod_port! { + use crate::atmega1284p as hal; + impl_port_peripheral_a8_b8_c8_d8! { + } + + #[macro_export] + macro_rules! atmega1284_pins { + ($p:expr) => { + $crate::atmega1284p::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega1284_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega1284p, + impl: { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB3`, `PB4`) + /// + /// # Example + /// ```no_run + /// use atmega_hal::atmega1284p as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut pb3 = pins.pb3.into_output().into_pwm(&mut timer0); + /// let mut pb4 = pins.pb4.into_output().into_pwm(&mut timer0); + /// + /// pb3.set_duty(128); + /// pb4.enable(); + /// ``` + pub struct Timer0Pwm { + timer: hal::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PB3: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PB4: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PD5`, `PD4`) + /// + /// # Example + /// ```no_run + /// use atmega_hal::atmega1284p as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut pd5 = pins.pd5.into_output().into_pwm(&mut timer1); + /// let mut pd4 = pins.pd4.into_output().into_pwm(&mut timer1); + /// + /// pd5.set_duty(128); + /// pd5.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_r, w| { + w.wgm1().bits(0b01); + + match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + } + }); + }, + pins: { + hal::port::PD5: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); + }, + }, + + hal::port::PD4: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC2` for PWM (pins `PD7`, `PD6`) + /// + /// # Example + /// ```no_run + /// use atmega_hal::atmega1284p as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer2Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); + /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); + /// + /// let mut pd7 = pins.pd7.into_output().into_pwm(&mut timer2); + /// let mut pd6 = pins.pd6.into_output().into_pwm(&mut timer2); + /// + /// pd7.set_duty(128); + /// pd7.enable(); + /// ``` + pub struct Timer2Pwm { + timer: hal::pac::TC2, + init: |tim, prescaler| { + tim.tccr2a.modify(|_r, w| w.wgm2().pwm_fast()); + tim.tccr2b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs2().direct(), + Prescaler::Prescale8 => w.cs2().prescale_8(), + Prescaler::Prescale64 => w.cs2().prescale_64(), + Prescaler::Prescale256 => w.cs2().prescale_256(), + Prescaler::Prescale1024 => w.cs2().prescale_1024(), + }); + }, + pins: { + hal::port::PD7: { + ocr: ocr2a, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); + }, + }, + + hal::port::PD6: { + ocr: ocr2b, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC3` for PWM (pins `PB6`, `PB7`) + pub struct Timer3Pwm { + timer: hal::pac::TC3, + init: |tim, prescaler| { + tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); + tim.tccr3b.modify(|_r, w| { + 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: { + hal::port::PB6: { + ocr: ocr3a, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); + }, + }, + + hal::port::PB7: { + ocr: ocr3b, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_spi! { + hal: crate::atmega1284p, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB7, + mosi: PB5, + miso: PB6, + cs: PB4, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega1284p, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega1284p as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} diff --git a/mcu/atmega-hal/src/atmega128a.rs b/mcu/atmega-hal/src/atmega128a.rs new file mode 100644 index 0000000000..5a79a4c3c6 --- /dev/null +++ b/mcu/atmega-hal/src/atmega128a.rs @@ -0,0 +1,203 @@ +pub use avr_device::atmega128a as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega128a, + pins: { + PF0: (hal::pac::adc::admux::MUX_A::ADC0), + PF1: (hal::pac::adc::admux::MUX_A::ADC1), + PF2: (hal::pac::adc::admux::MUX_A::ADC2), + PF3: (hal::pac::adc::admux::MUX_A::ADC3), + PF4: (hal::pac::adc::admux::MUX_A::ADC4), + PF5: (hal::pac::adc::admux::MUX_A::ADC5), + PF6: (hal::pac::adc::admux::MUX_A::ADC6), + PF7: (hal::pac::adc::admux::MUX_A::ADC7), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega128a, + capacity: 4096, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega_old, +} + +impl_mod_i2c! { + hal: crate::atmega128a, + interfaces: { + I2c: { + peripheral: TWI, + sda: PD1, + scl: PD0, + }, + }, +} + +impl_mod_port! { + use crate::atmega128a as hal; + + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + E: hal::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7], + F: hal::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7], + G: hal::pac::PORTG = [0, 1, 2, 3, 4], + } + } + + #[macro_export] + macro_rules! atmega128a_pins { + ($p:expr) => { + $crate::atmega128a::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF, $p.PORTG) + }; + } + + pub use atmega128a_pins as pins; +} + +impl_mod_spi! { + hal: crate::atmega128a, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB1, + mosi: PB2, + miso: PB3, + cs: PB0, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega128a, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PE0, + tx: PE1, + impl!: crate::atmega128a::impl_usart_atmega128a { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::atmega128a::impl_usart_atmega128a { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega128a as hal; + impl_wdt_peripheral_ms2000! { + mcusr: hal::pac::cpu::MCUCSR, + wdtcsr_name: wdtcr, + } +} + +macro_rules! impl_usart_atmega128a { + ( + hal: crate::$hal:ident, + peripheral: $peripheral:ident, + rx: $rx:ident, + tx: $tx:ident, + register_suffix: $register_suffix:literal, + ) => { + paste! { + impl + avr_hal_generic::usart::UsartOps< + crate::$hal::Hal, + crate::$hal::port::Pin, + crate::$hal::port::Pin, + > for crate::$hal::pac::$peripheral + { + fn raw_init(&mut self, baudrate: Baudrate) { + let [< ubrr $register_suffix h >]: u8 = (baudrate.ubrr >> 8) as u8; + let [< ubrr $register_suffix l >]: u8 = baudrate.ubrr as u8; + self.[< ubrr $register_suffix h >].write(|w| w.bits([< ubrr $register_suffix h >])); + self.[< ubrr $register_suffix l >].write(|w| w.bits([< ubrr $register_suffix l >])); + self.[< ucsr $register_suffix a >].write(|w| w.[< u2x $register_suffix >]().bit(baudrate.u2x)); + + // Enable receiver and transmitter but leave interrupts disabled. + #[rustfmt::skip] + self.[< ucsr $register_suffix b >].write(|w| w + .[< txen $register_suffix >]().set_bit() + .[< rxen $register_suffix >]().set_bit() + ); + + // Set frame format to [< 8n $register_suffix >] for now. At some point, this should be made + // configurable, similar to what is done in other HALs. + #[rustfmt::skip] + self.[< ucsr $register_suffix c >].write(|w| w + .[< umsel $register_suffix >]().usart_async() + .[< ucsz $register_suffix >]().chr8() + .[< usbs $register_suffix >]().stop1() + .[< upm $register_suffix >]().disabled() + ); + } + + fn raw_deinit(&mut self) { + // Wait for any ongoing transfer to finish. + avr_hal_generic::nb::block!(self.raw_flush()).ok(); + self.[< ucsr $register_suffix b >].reset(); + } + + fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { + if self.[< ucsr $register_suffix a >].read().[< udre $register_suffix >]().bit_is_clear() { + Err(avr_hal_generic::nb::Error::WouldBlock) + } else { + Ok(()) + } + } + + fn raw_write( + &mut self, + byte: u8, + ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { + // Call flush to make sure the data-register is empty + self.raw_flush()?; + + self.[< udr $register_suffix >].write(|w| w.bits(byte)); + Ok(()) + } + + fn raw_read(&mut self) -> avr_hal_generic::nb::Result { + if self.[< ucsr $register_suffix a >].read().[< rxc $register_suffix >]().bit_is_clear() { + return Err(avr_hal_generic::nb::Error::WouldBlock); + } + + Ok(self.[< udr $register_suffix >].read().bits()) + } + + fn raw_interrupt(&mut self, event: Event, state: bool) { + match event { + Event::RxComplete => self.[< ucsr $register_suffix b >].modify(|_, w| w.[< rxcie $register_suffix >]().bit(state)), + Event::TxComplete => self.[< ucsr $register_suffix b >].modify(|_, w| w.[< txcie $register_suffix >]().bit(state)), + Event::DataRegisterEmpty => self.[< ucsr $register_suffix b >].modify(|_, w| w.[< udrie $register_suffix >]().bit(state)), + } + } + } + } + }; +} + +pub(crate) use impl_usart_atmega128a; \ No newline at end of file diff --git a/mcu/atmega-hal/src/atmega164pa.rs b/mcu/atmega-hal/src/atmega164pa.rs new file mode 100644 index 0000000000..69770b4049 --- /dev/null +++ b/mcu/atmega-hal/src/atmega164pa.rs @@ -0,0 +1,200 @@ +pub use avr_device::atmega164pa as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega164pa, + pins: { + PA0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PA1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PA2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PA3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PA4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PA5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + PA6: (hal::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), + PA7: (hal::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), + }, + channels: { + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega164pa, + capacity: 512, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega164pa, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC1, + scl: PC0, + }, + }, +} + +impl_mod_port! { + use crate::atmega164pa as hal; + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6 ,7], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6 ,7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6 ,7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6 ,7], + } + } + + #[macro_export] + macro_rules! atmega164pa_pins { + ($p:expr) => { + $crate::atmega164pa::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega164pa_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega164pa, + impl: { + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB3`) + /// + /// # Example + /// ```no_run + /// use atmega_hal::atmega164pa as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut pb3 = pins.pb3.into_output().into_pwm(&mut timer0); + /// + /// pb3.set_duty(128); + /// pb3.enable(); + /// ``` + pub struct Timer0Pwm { + timer: hal::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().bits(0b11)); + tim.tccr0a.modify(|_r, w| w.com0a().bits(0b00)); + + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().running_no_prescaling(), + Prescaler::Prescale8 => w.cs0().running_clk_8(), + Prescaler::Prescale64 => w.cs0().running_clk_64(), + Prescaler::Prescale256 => w.cs0().running_clk_256(), + Prescaler::Prescale1024 => w.cs0().running_clk_1024(), + }); + }, + pins: { + hal::port::PB3: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().bits(0b11)); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().bits(0b00)); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PD4`, `PD5`) + /// + /// # Example + /// ```no_run + /// use atmega_hal::atmega164pa as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut pd4 = pins.pd4.into_output().into_pwm(&mut timer1); + /// let mut pd5 = pins.pd5.into_output().into_pwm(&mut timer1); + /// + /// pd4.set_duty(128); + /// pd4.enable(); + /// pd5.set_duty(64); + /// pd5.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1a.modify(|_r, w| w.com1a().bits(0b00)); + tim.tccr1a.modify(|_r, w| w.com1b().bits(0b00)); + tim.tccr1b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().running_no_prescaling(), + Prescaler::Prescale8 => w.cs1().running_clk_8(), + Prescaler::Prescale64 => w.cs1().running_clk_64(), + Prescaler::Prescale256 => w.cs1().running_clk_256(), + Prescaler::Prescale1024 => w.cs1().running_clk_1024(), + }); + }, + pins: { + hal::port::PD4: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().bits(0b11)); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().bits(0b00)); + }, + }, + hal::port::PD5: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().bits(0b11)); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().bits(0b00)); + }, + }, + }, + } + } + }, +} + +impl_mod_usart! { + hal: crate::atmega164pa, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega164pa as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega168.rs b/mcu/atmega-hal/src/atmega168.rs new file mode 100644 index 0000000000..798e4ffd44 --- /dev/null +++ b/mcu/atmega-hal/src/atmega168.rs @@ -0,0 +1,101 @@ +pub use avr_device::atmega168 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega168, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PC1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PC2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PC3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PC4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PC5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega168, + capacity: 512, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega168, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC4, + scl: PC5, + }, + }, +} + +impl_mod_port! { + use crate::atmega168 as hal; + impl_port_peripheral_b8_c7_d8! { + } + + #[macro_export] + macro_rules! atmega168_pins { + ($p:expr) => { + $crate::atmega168::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega168_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega168, + impl!: impl_simple_pwm_48p_168_328p_328pb, +} + +impl_mod_spi! { + hal: crate::atmega168, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega168, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega168 as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega2560.rs b/mcu/atmega-hal/src/atmega2560.rs new file mode 100644 index 0000000000..d96e4d56e4 --- /dev/null +++ b/mcu/atmega-hal/src/atmega2560.rs @@ -0,0 +1,115 @@ +pub use avr_device::atmega2560 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega2560, + pins: { + PF0: (0b000000, didr0::adc0d), + PF1: (0b000001, didr0::adc1d), + PF2: (0b000010, didr0::adc2d), + PF3: (0b000011, didr0::adc3d), + PF4: (0b000100, didr0::adc4d), + PF5: (0b000101, didr0::adc5d), + PF6: (0b000110, didr0::adc6d), + PF7: (0b000111, didr0::adc7d), + PK0: (0b100000, didr2::adc8d), + PK1: (0b100001, didr2::adc9d), + PK2: (0b100010, didr2::adc10d), + PK3: (0b100011, didr2::adc11d), + PK4: (0b100100, didr2::adc12d), + PK5: (0b100101, didr2::adc13d), + PK6: (0b100110, didr2::adc14d), + PK7: (0b100111, didr2::adc15d), + }, + channels: { + Vbg: 0b011110, + Gnd: 0b011111, + }, + impl!: impl_adc_admux_adcsrb, +} + +impl_mod_eeprom! { + hal: crate::atmega2560, + capacity: 4096, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega2560, + interfaces: { + I2c: { + peripheral: TWI, + sda: PD1, + scl: PD0, + }, + }, +} + +impl_mod_port! { + use crate::atmega2560 as hal; + impl_port_peripheral_a8_b8_c8_d8_e8_f8_g6_h8_j8_k8_l8! { + } + + #[macro_export] + macro_rules! atmega2560_pins { + ($p:expr) => { + $crate::atmega2560::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF, $p.PORTG, $p.PORTH, $p.PORTJ, $p.PORTK, $p.PORTL) + }; + } + + pub use atmega2560_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega2560, + impl!: impl_simple_pwm_1280_2560, +} + +impl_mod_spi! { + hal: crate::atmega2560, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB1, + mosi: PB2, + miso: PB3, + cs: PB0, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega2560, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PE0, + tx: PE1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega2560 as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega328p.rs b/mcu/atmega-hal/src/atmega328p.rs new file mode 100644 index 0000000000..59b0ff6c60 --- /dev/null +++ b/mcu/atmega-hal/src/atmega328p.rs @@ -0,0 +1,101 @@ +pub use avr_device::atmega328p as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega328p, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PC1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PC2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PC3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PC4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PC5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega328p, + capacity: 1024, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega328p, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC4, + scl: PC5, + }, + }, +} + +impl_mod_port! { + use crate::atmega328p as hal; + impl_port_peripheral_b8_c7_d8! { + } + + #[macro_export] + macro_rules! atmega328p_pins { + ($p:expr) => { + $crate::atmega328p::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega328p_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega328p, + impl!: impl_simple_pwm_48p_168_328p_328pb, +} + +impl_mod_spi! { + hal: crate::atmega328p, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega328p, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega328p as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} diff --git a/mcu/atmega-hal/src/atmega328pb.rs b/mcu/atmega-hal/src/atmega328pb.rs new file mode 100644 index 0000000000..d0a6d05b22 --- /dev/null +++ b/mcu/atmega-hal/src/atmega328pb.rs @@ -0,0 +1,210 @@ +pub use avr_device::atmega328pb as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega328pb, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PC1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PC2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PC3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PC4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PC5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega328pb, + capacity: 1024, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega328pb, + interfaces: { + I2c0: { + peripheral: TWI0, + sda: PC4, + scl: PC5, + }, + I2c1: { + peripheral: TWI1, + sda: PE0, + scl: PE1, + }, + }, +} + +impl_mod_port! { + use crate::atmega328pb as hal; + avr_hal_generic::impl_port_traditional! { + enum Ports { + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + E: hal::pac::PORTE = [0, 1, 2, 3], + } + } + + #[macro_export] + macro_rules! atmega328pb_pins { + ($p:expr) => { + $crate::atmega328pb::Pins::new($p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE) + }; + } + + pub use atmega328pb_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega328pb, + impl!: impl_simple_pwm_48p_168_328p_328pb, + impl: { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC3` for PWM (pins `PD0`, `PD2`) + pub struct Timer3Pwm { + timer: hal::pac::TC3, + init: |tim, prescaler| { + tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); + tim.tccr3b.modify(|_r, w| { + 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: { + hal::port::PD0: { + ocr: ocr3a, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); + }, + }, + + hal::port::PD2: { + ocr: ocr3b, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC4` for PWM (pins `PD1`, `PD2`) + pub struct Timer4Pwm { + timer: hal::pac::TC4, + init: |tim, prescaler| { + tim.tccr4a.modify(|_r, w| w.wgm4().bits(0b01)); + tim.tccr4b.modify(|_r, w| { + 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: { + hal::port::PD1: { + ocr: ocr4a, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); + }, + }, + + hal::port::PD2: { + ocr: ocr4b, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_spi! { + hal: crate::atmega328pb, + interfaces: { + Spi0: { + peripheral: SPI0, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, + }, + Spi1: { + peripheral: SPI1, + sclk: PC1, + mosi: PE3, + miso: PC0, + cs: PE2, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega328pb, + interfaces: { + Usart0: { + peripheral: USART0, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 0, + }, + }, + Usart1: { + peripheral: USART1, + rx: PB4, + tx: PB3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega328pb as hal; + + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega32a.rs b/mcu/atmega-hal/src/atmega32a.rs new file mode 100644 index 0000000000..08bcf6fc3b --- /dev/null +++ b/mcu/atmega-hal/src/atmega32a.rs @@ -0,0 +1,99 @@ +pub use avr_device::atmega32a as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega32a, + pins: { + PA0: (hal::pac::adc::admux::MUX_A::ADC0), + PA1: (hal::pac::adc::admux::MUX_A::ADC1), + PA2: (hal::pac::adc::admux::MUX_A::ADC2), + PA3: (hal::pac::adc::admux::MUX_A::ADC3), + PA4: (hal::pac::adc::admux::MUX_A::ADC4), + PA5: (hal::pac::adc::admux::MUX_A::ADC5), + PA6: (hal::pac::adc::admux::MUX_A::ADC6), + PA7: (hal::pac::adc::admux::MUX_A::ADC7), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + + +impl_mod_eeprom! { + hal: crate::atmega32a, + capacity: 1024, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega_old, +} + +impl_mod_i2c! { + hal: crate::atmega32a, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC1, + scl: PC0, + }, + }, +} + +impl_mod_port! { + use crate::atmega32a as hal; + + impl_port_peripheral_a8_b8_c8_d8! { + } + + #[macro_export] + macro_rules! atmega32a_pins { + ($p:expr) => { + $crate::atmega32a::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega32a_pins as pins; +} + +impl_mod_spi! { + hal: crate::atmega32a, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB7, + mosi: PB5, + miso: PB6, + cs: PB4, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega32a, + interfaces: { + Usart0: { + peripheral: USART, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_ubrrh_ucsrc, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega32a as hal; + + impl_wdt_peripheral_ms2000! { + mcusr: hal::pac::cpu::MCUCSR, + wdtcsr_name: wdtcr, + } +} + diff --git a/mcu/atmega-hal/src/atmega32u4.rs b/mcu/atmega-hal/src/atmega32u4.rs new file mode 100644 index 0000000000..1b305f3a5b --- /dev/null +++ b/mcu/atmega-hal/src/atmega32u4.rs @@ -0,0 +1,318 @@ +pub use avr_device::atmega32u4 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega32u4, + pins: { + PF0: (0b000000, didr0::adc0d), + PF1: (0b000001, didr0::adc1d), + PF4: (0b000100, didr0::adc4d), + PF5: (0b000101, didr0::adc5d), + PF6: (0b000110, didr0::adc6d), + PF7: (0b000111, didr0::adc7d), + PD4: (0b100000, didr2::adc8d), + PD6: (0b100001, didr2::adc9d), + PD7: (0b100010, didr2::adc10d), + PB4: (0b100011, didr2::adc11d), + PB5: (0b100100, didr2::adc12d), + PB6: (0b100101, didr2::adc13d), + }, + channels: { + Vbg: 0b011110, + Gnd: 0b011111, + Temperature: 0b100111, + }, + impl!: impl_adc_admux_adcsrb, +} + +impl_mod_eeprom! { + hal: crate::atmega32u4, + capacity: 1024, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega32u4, + interfaces: { + I2c: { + peripheral: TWI, + sda: PD1, + scl: PD0, + }, + }, +} + +impl_mod_port! { + use crate::atmega32u4 as hal; + + avr_hal_generic::impl_port_traditional! { + enum Ports { + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + E: hal::pac::PORTE = [2, 6], + F: hal::pac::PORTF = [0, 1, 4, 5, 6, 7], + } + } + + #[macro_export] + macro_rules! atmega32u4_pins { + ($p:expr) => { + $crate::atmega32u4::Pins::new($p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF) + }; + } + + pub use atmega32u4_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega32u4, + impl: { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB7`, `PD0`) + /// + /// # Example + /// ``` + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer0); + /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer0); + /// + /// d11.set_duty(128); + /// d11.enable(); + /// ``` + pub struct Timer0Pwm { + timer: hal::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PB7: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PD0: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); + /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); + /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); + /// + /// d9.set_duty(128); + /// d9.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_r, w| w.wgm1().bits(0b01)); + + tim.tccr1b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + }); + }, + pins: { + hal::port::PB5: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); + }, + }, + + hal::port::PB6: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); + }, + }, + + hal::port::PB7: { + ocr: ocr1c, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1c().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1c().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC3` for PWM (pins `PC6`) + /// + /// # Example + /// ``` + /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); + /// + /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); + /// + /// d5.set_duty(128); + /// d5.enable(); + /// ``` + pub struct Timer3Pwm { + timer: hal::pac::TC3, + init: |tim, prescaler| { + tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); + tim.tccr3b.modify(|_r, w| w.wgm3().bits(0b01)); + + tim.tccr3b.modify(|_r, w| 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: { + hal::port::PC6: { + ocr: ocr3a, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC4` for PWM (pins `PB6`, `PC7`, `PD7`) + /// + /// # Example + /// ``` + /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); + /// + /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); + /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer4); + /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer4); + /// + /// d6.set_duty(128); + /// d6.enable(); + /// ``` + pub struct Timer4Pwm { + timer: hal::pac::TC4, + init: |tim, prescaler| { + tim.tccr4a.modify(|_r, w| w.pwm4a().set_bit()); + tim.tccr4a.modify(|_r, w| w.pwm4b().set_bit()); + tim.tccr4c.modify(|_r, w| w.pwm4d().set_bit()); + + tim.tccr4b.modify(|_r, w| 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: { + hal::port::PB6: { + ocr: ocr4b, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); + }, + }, + + hal::port::PC7: { + ocr: ocr4a, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); + }, + }, + + hal::port::PD7: { + ocr: ocr4d, + into_pwm: |tim| if enable { + tim.tccr4c.modify(|_r, w| w.com4d().match_clear()); + } else { + tim.tccr4c.modify(|_r, w| w.com4d().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_spi! { + hal: crate::atmega32u4, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB1, + mosi: PB2, + miso: PB3, + cs: PB0, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega32u4, + interfaces: { + Usart1: { + peripheral: USART1, + rx: PD2, + tx: PD3, + impl!: crate::r#impl::impl_usart_traditional { + register_suffix: 1, + }, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega32u4 as hal; + + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega48p.rs b/mcu/atmega-hal/src/atmega48p.rs new file mode 100644 index 0000000000..1dd4960cd0 --- /dev/null +++ b/mcu/atmega-hal/src/atmega48p.rs @@ -0,0 +1,88 @@ +pub use avr_device::atmega48p as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega48p, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), + PC1: (hal::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), + PC2: (hal::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), + PC3: (hal::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), + PC4: (hal::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), + PC5: (hal::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + Temperature: hal::pac::adc::admux::MUX_A::TEMPSENS, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega48p, + capacity: 256, + addr_width: u8, + addr_reg: eearl, + impl!: avr_hal_generic::impl_eeprom_atmega, +} + +impl_mod_i2c! { + hal: crate::atmega48p, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC4, + scl: PC5, + }, + }, +} + +impl_mod_port! { + use crate::atmega48p as hal; + impl_port_peripheral_b8_c7_d8! { + } + + #[macro_export] + macro_rules! atmega48p_pins { + ($p:expr) => { + $crate::atmega48p::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega48p_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega48p, + impl!: impl_simple_pwm_48p_168_328p_328pb, +} + +impl_mod_spi! { + hal: crate::atmega48p, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega48p as hal; + impl_wdt_peripheral_ms8000! { + mcusr: hal::pac::cpu::MCUSR, + wdtcsr_name: wdtcsr, + } +} + diff --git a/mcu/atmega-hal/src/atmega8.rs b/mcu/atmega-hal/src/atmega8.rs new file mode 100644 index 0000000000..c4ea253270 --- /dev/null +++ b/mcu/atmega-hal/src/atmega8.rs @@ -0,0 +1,188 @@ +pub use avr_device::atmega8 as pac; + +pub struct Hal; + +use crate::r#impl::*; + +impl_mod_adc! { + hal: crate::atmega8, + pins: { + PC0: (hal::pac::adc::admux::MUX_A::ADC0), + PC1: (hal::pac::adc::admux::MUX_A::ADC1), + PC2: (hal::pac::adc::admux::MUX_A::ADC2), + PC3: (hal::pac::adc::admux::MUX_A::ADC3), + PC4: (hal::pac::adc::admux::MUX_A::ADC4), + PC5: (hal::pac::adc::admux::MUX_A::ADC5), + }, + channels: { + #[cfg(feature = "enable-extra-adc")] + ADC6: hal::pac::adc::admux::MUX_A::ADC6, + #[cfg(feature = "enable-extra-adc")] + ADC7: hal::pac::adc::admux::MUX_A::ADC7, + Vbg: hal::pac::adc::admux::MUX_A::ADC_VBG, + Gnd: hal::pac::adc::admux::MUX_A::ADC_GND, + }, + impl!: impl_adc_admux, +} + +impl_mod_eeprom! { + hal: crate::atmega8, + capacity: 512, + addr_width: u16, + addr_reg: eear, + impl!: avr_hal_generic::impl_eeprom_atmega_old, +} + +impl_mod_i2c! { + hal: crate::atmega8, + interfaces: { + I2c: { + peripheral: TWI, + sda: PC4, + scl: PC5, + }, + }, +} + +impl_mod_port! { + use crate::atmega8 as hal; + + impl_port_peripheral_b8_c7_d8! { + } + + #[macro_export] + macro_rules! atmega8_pins { + ($p:expr) => { + $crate::atmega8::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) + }; + } + + pub use atmega8_pins as pins; +} + +impl_mod_simple_pwm! { + hal: crate::atmega8, + impl: { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB1`, `PB2`) + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut b1 = pins.b1.into_output().into_pwm(&mut timer1); + /// let mut b2 = pins.b2.into_output().into_pwm(&mut timer1); + /// + /// d9.set_duty(128); + /// d9.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_r, w| { + w.wgm1().bits(0b01); + + match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + } + }); + }, + pins: { + hal::port::PB1: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); + }, + }, + + hal::port::PB2: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC2` for PWM (pin `PB3`) + /// + /// # Example + /// ``` + /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); + /// + /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); + /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); + /// + /// d11.set_duty(128); + /// d11.enable(); + /// ``` + pub struct Timer2Pwm { + timer: hal::pac::TC2, + init: |tim, prescaler| { + tim.tccr2.modify(|_r, w| w.wgm20().set_bit().wgm21().set_bit()); + tim.tccr2.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs2().direct(), + Prescaler::Prescale8 => w.cs2().prescale_8(), + Prescaler::Prescale64 => w.cs2().prescale_64(), + Prescaler::Prescale256 => w.cs2().prescale_256(), + Prescaler::Prescale1024 => w.cs2().prescale_1024(), + }); + }, + pins: { + hal::port::PB3: { + ocr: ocr2, + into_pwm: |tim| if enable { + tim.tccr2.modify(|_r, w| w.com2().match_clear()); + } else { + tim.tccr2.modify(|_r, w| w.com2().disconnected()); + }, + }, + }, + } + } + }, +} + +impl_mod_spi! { + hal: crate::atmega8, + interfaces: { + Spi: { + peripheral: SPI, + sclk: PB5, + mosi: PB3, + miso: PB4, + cs: PB2, + }, + }, +} + +impl_mod_usart! { + hal: crate::atmega8, + interfaces: { + Usart0: { + peripheral: USART, + rx: PD0, + tx: PD1, + impl!: crate::r#impl::impl_usart_ubrrh_ucsrc, + }, + }, +} + +impl_mod_wdt! { + use crate::atmega8 as hal; + impl_wdt_peripheral_ms2000! { + mcusr: hal::pac::cpu::MCUCSR, + wdtcsr_name: wdtcr, + } +} \ No newline at end of file diff --git a/mcu/atmega-hal/src/eeprom.rs b/mcu/atmega-hal/src/eeprom.rs deleted file mode 100644 index bcddc02fa1..0000000000 --- a/mcu/atmega-hal/src/eeprom.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! EEPROM -//! -//! # Example -//! -//! Complete example source code can be found in the repository: -//! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) -//! -//! ``` -//! const BOOT_COUNT_OFFSET: u16 = 0; -//! -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let mut eeprom = Eeprom::new(dp.EEPROM); -//! -//! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); -//! boot_count = boot_count.wrapping_add(1); -//! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); -//! -//! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); -//! ``` - -pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; - -pub type Eeprom = avr_hal_generic::eeprom::Eeprom; - -/////////////////////////////////////////////////////////// -#[cfg(feature = "atmega48p")] -avr_hal_generic::impl_eeprom_atmega! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 256, - addr_width: u8, - set_address: |peripheral, address| { - peripheral.eearl.write(|w| w.bits(address)); - }, -} - -#[cfg(any(feature = "atmega168", feature = "atmega164pa"))] -avr_hal_generic::impl_eeprom_atmega! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 512, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any( - feature = "atmega328pb", - feature = "atmega328p", - feature = "atmega32u4" -))] -avr_hal_generic::impl_eeprom_atmega! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 1024, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any( - feature = "atmega2560", - feature = "atmega1280", - feature = "atmega1284p" -))] -avr_hal_generic::impl_eeprom_atmega! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 4096, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any(feature = "atmega8"))] -avr_hal_generic::impl_eeprom_atmega_old! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 512, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any(feature = "atmega32a"))] -avr_hal_generic::impl_eeprom_atmega_old! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 1024, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} - -#[cfg(any(feature = "atmega128a",))] -avr_hal_generic::impl_eeprom_atmega_old! { - hal: crate::Atmega, - peripheral: crate::pac::EEPROM, - capacity: 4096, - addr_width: u16, - set_address: |peripheral, address| { - peripheral.eear.write(|w| w.bits(address)); - }, -} diff --git a/mcu/atmega-hal/src/globals.rs b/mcu/atmega-hal/src/globals.rs new file mode 100644 index 0000000000..d59f783d6d --- /dev/null +++ b/mcu/atmega-hal/src/globals.rs @@ -0,0 +1,271 @@ +// Deprecated globals + +#[cfg( + any( + // More than one MCU selected -> error + all( + feature = "_mcu-atmega48p", + any( + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega164pa", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega168", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega328p", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega328pb", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega32a", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega32u4", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega2560", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega128a", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega1280", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1284p", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega1284p", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega8", + ) + ), + all( + feature = "_mcu-atmega8", + any( + feature = "_mcu-atmega48p", + feature = "_mcu-atmega164pa", + feature = "_mcu-atmega168", + feature = "_mcu-atmega328p", + feature = "_mcu-atmega328pb", + feature = "_mcu-atmega32a", + feature = "_mcu-atmega32u4", + feature = "_mcu-atmega2560", + feature = "_mcu-atmega128a", + feature = "_mcu-atmega1280", + feature = "_mcu-atmega1284p", + ) + ), + ) +)] +compile_error!( + "When using deprecated globals (default in atmega-hal 0.1.x), you cannot target multiple chips. + + To target multiple chips, turn off deprecated globals by using the following features + + * atmega48p-no-deprecated-globals instead of atmega48p + * atmega164pa-no-deprecated-globals instead of atmega164pa + * atmega168-no-deprecated-globals instead of atmega168 + * atmega328p-no-deprecated-globals instead of atmega328p + * atmega328pb-no-deprecated-globals instead of atmega328pb + * atmega32a-no-deprecated-globals instead of atmega32a + * atmega32u4-no-deprecated-globals instead of atmega32u4 + * atmega2560-no-deprecated-globals instead of atmega2560 + * atmega128a-no-deprecated-globals instead of atmega128a + * atmega1280-no-deprecated-globals instead of atmega1280 + * atmega1284p-no-deprecated-globals instead of atmega1284p + * atmega8-no-deprecated-globals instead of atmega8 + " +); + +#[cfg(feature = "_mcu-atmega48p")] +pub use crate::atmega48p as hal; + +#[cfg(feature = "_mcu-atmega164pa")] +pub use crate::atmega164pa as hal; + +#[cfg(feature = "_mcu-atmega168")] +pub use crate::atmega168 as hal; + +#[cfg(feature = "_mcu-atmega328p")] +pub use crate::atmega328p as hal; + +#[cfg(feature = "_mcu-atmega328pb")] +pub use crate::atmega328pb as hal; + +#[cfg(feature = "_mcu-atmega32a")] +pub use crate::atmega32a as hal; + +#[cfg(feature = "_mcu-atmega32u4")] +pub use crate::atmega32u4 as hal; + +#[cfg(feature = "_mcu-atmega2560")] +pub use crate::atmega2560 as hal; + +#[cfg(feature = "_mcu-atmega128a")] +pub use crate::atmega128a as hal; + +#[cfg(feature = "_mcu-atmega1280")] +pub use crate::atmega1280 as hal; + +#[cfg(feature = "_mcu-atmega1284p")] +pub use crate::atmega1284p as hal; + +#[cfg(feature = "_mcu-atmega8")] +pub use crate::atmega8 as hal; + +pub use hal::{adc, eeprom, i2c, pac, port, wdt, Hal as Atmega, pins}; +pub use {adc::Adc, eeprom::Eeprom, i2c::I2c, pac::Peripherals, port::Pins, wdt::Wdt}; + +#[cfg(feature = "_peripheral-simple-pwm")] +pub use hal::simple_pwm; + +#[cfg(feature = "_peripheral-spi")] +pub use crate::spi::Spi; +#[cfg(feature = "_peripheral-spi")] +pub use hal::spi; + +#[cfg(feature = "_peripheral-usart")] +pub use hal::usart; +#[cfg(feature = "_peripheral-usart")] +pub use hal::usart::Usart; + diff --git a/mcu/atmega-hal/src/i2c.rs b/mcu/atmega-hal/src/i2c.rs deleted file mode 100644 index 192b1a1b3d..0000000000 --- a/mcu/atmega-hal/src/i2c.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! I2C -//! -//! # Example -//! -//! Complete example source code can be found in the repository: -//! [`atmega2560-i2cdetect.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs) -//! -//! ``` -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let pins = atmega_hal::pins!(dp); -//! -//! let mut i2c = I2c::new( -//! dp.TWI, -//! pins.pd1.into_pull_up_input(), -//! pins.pd0.into_pull_up_input(), -//! 50_000, -//! ); -//! -//! i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read).unwrap(); -//! ``` - -#[allow(unused_imports)] -use crate::port; -pub use avr_hal_generic::i2c::*; - -#[cfg(any( - feature = "atmega128a", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega32u4" -))] -pub type I2c = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any( - feature = "atmega128a", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega32u4" -))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI, - sda: port::PD1, - scl: port::PD0, -} - -#[cfg(any(feature = "atmega164pa"))] -pub type I2c = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega164pa"))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI, - sda: port::PC1, - scl: port::PC0, -} - -#[cfg(any( - feature = "atmega328p", - feature = "atmega168", - feature = "atmega48p", - feature = "atmega8" -))] -pub type I2c = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any( - feature = "atmega328p", - feature = "atmega168", - feature = "atmega48p", - feature = "atmega8" -))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI, - sda: port::PC4, - scl: port::PC5, -} - -#[cfg(any(feature = "atmega328pb"))] -pub type I2c0 = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI0, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega328pb"))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI0, - sda: port::PC4, - scl: port::PC5, -} -#[cfg(any(feature = "atmega328pb"))] -pub type I2c1 = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI1, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega328pb"))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI1, - sda: port::PE0, - scl: port::PE1, -} - -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -pub type I2c = avr_hal_generic::i2c::I2c< - crate::Atmega, - crate::pac::TWI, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -avr_hal_generic::impl_i2c_twi! { - hal: crate::Atmega, - peripheral: crate::pac::TWI, - sda: port::PC1, - scl: port::PC0, -} diff --git a/mcu/atmega-hal/src/impl/adc.rs b/mcu/atmega-hal/src/impl/adc.rs new file mode 100644 index 0000000000..bb5982924f --- /dev/null +++ b/mcu/atmega-hal/src/impl/adc.rs @@ -0,0 +1,229 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_adc { + ( + hal: crate::$hal:ident, + pins: { + $($pin_name:ident: ($pin_channel:expr$(, $didr:ident::$didr_method:ident)?),)+ + }, + channels: { + $( + $(#[$channel_attr:meta])* + $channel_name:ident: $channel_mux: expr, + )* + }, + impl!: $($impl_macro:ident)::* $({ + $($arg_name:ident: $arg_value:expr,)* + })?, + ) => { + pub mod adc { + //! Analog-to-Digital Converter + //! + //! # Example + //! + //! Complete example source code can be found in the repository: + //! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) + //! + //! ``` + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let pins = atmega_hal::pins!(dp); + //! + //! let mut adc = Adc::new(dp.ADC, Default::default()); + //! + //! let channels: [atmega_hal::adc::Channel; 4] = [ + //! pins.pf0.into_analog_input(&mut adc).into_channel(), + //! pins.pf1.into_analog_input(&mut adc).into_channel(), + //! pins.pf2.into_analog_input(&mut adc).into_channel(), + //! pins.pf3.into_analog_input(&mut adc).into_channel(), + //! ]; + //! + //! for (index, channel) in channels.iter().enumerate() { + //! let value = adc.read_blocking(channel); + //! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); + //! } + //! ``` + + use avr_hal_generic::paste::paste; + use crate::$hal as hal; + + #[allow(unused_imports)] + use crate::r#impl::{impl_adc_admux, impl_adc_admux_adcsrb}; + + /// Additional channels + /// + /// Some channels are not directly connected to pins. This module provides types which can be used + /// to access them. + /// + /// # Example + /// ``` + /// let dp = atmega_hal::Peripherals::take().unwrap(); + /// let mut adc = atmega_hal::Adc::new(dp.ADC, Default::default()); + /// + /// let value = adc.read_blocking(&channel::Vbg); + /// ``` + #[allow(non_camel_case_types)] + pub mod channel { + $( + $(#[$channel_attr])* + pub struct $channel_name; + )* + } + + pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; + + impl Default for ReferenceVoltage { + fn default() -> Self { + Self::AVcc + } + } + + /// Configuration for the ADC peripheral. + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] + pub struct AdcSettings { + pub clock_divider: ClockDivider, + pub ref_voltage: ReferenceVoltage, + } + + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// Voltage applied to AREF pin. + Aref, + /// Default reference voltage (default). + AVcc, + /// Internal reference voltage. + Internal, + } + + /// Check the [`avr_hal_generic::adc::Adc`] documentation. + pub type Adc = avr_hal_generic::adc::Adc; + + /// Check the [`avr_hal_generic::adc::Channel`] documentation. + pub type Channel = avr_hal_generic::adc::Channel; + + fn apply_settings(peripheral: &hal::pac::ADC, settings: AdcSettings) { + peripheral.adcsra.write(|w| { + w.aden().set_bit(); + match settings.clock_divider { + ClockDivider::Factor2 => w.adps().prescaler_2(), + ClockDivider::Factor4 => w.adps().prescaler_4(), + ClockDivider::Factor8 => w.adps().prescaler_8(), + ClockDivider::Factor16 => w.adps().prescaler_16(), + ClockDivider::Factor32 => w.adps().prescaler_32(), + ClockDivider::Factor64 => w.adps().prescaler_64(), + ClockDivider::Factor128 => w.adps().prescaler_128(), + } + }); + peripheral.admux.write(|w| match settings.ref_voltage { + ReferenceVoltage::Aref => w.refs().aref(), + ReferenceVoltage::AVcc => w.refs().avcc(), + ReferenceVoltage::Internal => w.refs().internal(), + }); + } + + $($impl_macro)::+! { + hal: crate::$hal, + pins: { + $($pin_name: ($pin_channel$(, $didr::$didr_method)?),)+ + }, + channels: { + $( + $(#[$channel_attr])* + $channel_name: $channel_mux, + )* + }, + $($($arg_name: $arg_value,)*)? + } + } + + pub use adc::Adc; + } +} +pub(crate) use impl_mod_adc; + +macro_rules! impl_adc_admux { + ( + hal: crate::$hal:ident, + pins: { + $($pin_name:ident: ($pin_channel:expr$(, $didr:ident::$didr_method:ident)?),)+ + }, + channels: { + $( + $(#[$channel_attr:meta])* + $channel_name:ident: $channel_mux: expr, + )* + }, + $(impl!: $($impl_macro:ident)::* $({ + $($arg_name:ident: $arg_value:expr,)* + })?,)? + ) => { + paste! { + avr_hal_generic::impl_adc! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::ADC, + settings: crate::$hal::adc::AdcSettings, + apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, + channel_id: crate::$hal::pac::adc::admux::MUX_A, + set_channel: |peripheral, id| { + peripheral.admux.modify(|_, w| w.mux().variant(id)); + }, + pins: { + $(hal::port::[<$pin_name>]: ($pin_channel $(, $didr::$didr_method)?),)* + }, + channels: { + $( + $(#[$channel_attr])* + channel::$channel_name: $channel_mux, + )* + }, + } + } + } +} +pub(crate) use impl_adc_admux; + +macro_rules! impl_adc_admux_adcsrb { + ( + hal: crate::$hal:ident, + pins: { + $($pin_name:ident: ($pin_channel:expr$(, $didr:ident::$didr_method:ident)?),)+ + }, + channels: { + $( + $(#[$channel_attr:meta])* + $channel_name:ident: $channel_mux: expr, + )* + }, + $(impl!: $($impl_macro:ident)::* $({ + $($arg_name:ident: $arg_value:expr,)* + })?,)? + ) => { + paste! { + avr_hal_generic::impl_adc! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::ADC, + settings: crate::$hal::adc::AdcSettings, + apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, + channel_id: u8, + set_channel: |peripheral, id| { + peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f)); + peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0)); + }, + pins: { + $(hal::port::[<$pin_name>]: ($pin_channel $(, $didr::$didr_method)?),)* + }, + channels: { + $( + $(#[$channel_attr])* + channel::$channel_name: $channel_mux, + )* + }, + } + } + } +} +pub(crate) use impl_adc_admux_adcsrb; diff --git a/mcu/atmega-hal/src/impl/eeprom.rs b/mcu/atmega-hal/src/impl/eeprom.rs new file mode 100644 index 0000000000..234af3eadc --- /dev/null +++ b/mcu/atmega-hal/src/impl/eeprom.rs @@ -0,0 +1,50 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_eeprom { + ( + hal: crate::$hal:ident, + capacity: $capacity:expr, + addr_width: $addr_width:ty, + addr_reg: $addr_reg:ident, + impl!: $($impl_macro:ident)::+ $(,)? + ) => { + pub mod eeprom { + //! EEPROM + //! + //! # Example + //! + //! Complete example source code can be found in the repository: + //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) + //! + //! ``` + //! const BOOT_COUNT_OFFSET: u16 = 0; + //! + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let mut eeprom = Eeprom::new(dp.EEPROM); + //! + //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); + //! boot_count = boot_count.wrapping_add(1); + //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); + //! + //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); + //! ``` + pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; + + pub type Eeprom = + avr_hal_generic::eeprom::Eeprom; + + $($impl_macro)::+! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::EEPROM, + capacity: $capacity, + addr_width: $addr_width, + set_address: |peripheral, address| { + peripheral.$addr_reg.write(|w| w.bits(address)); + }, + } + } + + pub use eeprom::Eeprom; + } +} +pub(crate) use impl_mod_eeprom; diff --git a/mcu/atmega-hal/src/impl/i2c.rs b/mcu/atmega-hal/src/impl/i2c.rs new file mode 100644 index 0000000000..258e3d238f --- /dev/null +++ b/mcu/atmega-hal/src/impl/i2c.rs @@ -0,0 +1,58 @@ +macro_rules! impl_mod_i2c { + ( + hal: crate::$hal:ident, + interfaces: {$( + $interface:ident: { + peripheral: $peripheral:ident, + sda: $sda:ident, + scl: $scl:ident, + }, + )+}, + ) => { + pub mod i2c { + //! I2C + //! + //! # Example + //! + //! Complete example source code can be found in the repository: + //! [`atmega2560-i2cdetect.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs) + //! + //! ``` + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let pins = atmega_hal::pins!(dp); + //! + //! let mut i2c = I2c::new( + //! dp.TWI, + //! pins.pd1.into_pull_up_input(), + //! pins.pd0.into_pull_up_input(), + //! 50_000, + //! ); + //! + //! i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read).unwrap(); + //! ``` + + pub use avr_hal_generic::i2c::*; + use crate::$hal as hal; + + $( + pub type $interface = avr_hal_generic::i2c::I2c< + hal::Hal, + hal::pac::$peripheral, + hal::port::Pin, + hal::port::Pin, + CLOCK, + >; + avr_hal_generic::impl_i2c_twi! { + hal: hal::Hal, + peripheral: hal::pac::$peripheral, + sda: hal::port::$sda, + scl: hal::port::$scl, + } + )+ + } + + pub use i2c::I2c; + } +} +pub(crate) use impl_mod_i2c; + diff --git a/mcu/atmega-hal/src/impl/mod.rs b/mcu/atmega-hal/src/impl/mod.rs new file mode 100644 index 0000000000..31035fd873 --- /dev/null +++ b/mcu/atmega-hal/src/impl/mod.rs @@ -0,0 +1,25 @@ +#![allow(unused_imports)] + +mod adc; +pub(crate) use adc::*; + +mod eeprom; +pub(crate) use eeprom::*; + +mod i2c; +pub(crate) use i2c::*; + +mod port; +pub(crate) use port::*; + +mod simple_pwm; +pub(crate) use simple_pwm::*; + +mod spi; +pub(crate) use spi::*; + +mod usart; +pub(crate) use usart::*; + +mod wdt; +pub(crate) use wdt::*; diff --git a/mcu/atmega-hal/src/impl/port.rs b/mcu/atmega-hal/src/impl/port.rs new file mode 100644 index 0000000000..2b3f0a105a --- /dev/null +++ b/mcu/atmega-hal/src/impl/port.rs @@ -0,0 +1,85 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_port { + (use crate::$hal:ident as hal; $($mod:item)*) => { + pub mod port { + //! Port + //! + //! # Example + //! + //! Complete example source code can be found in the repository: + //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) + //! + //! ``` + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let pins = atmega_hal::pins!(dp); + //! + //! let mut led = pins.pb7.into_output(); + //! + //! loop { + //! led.toggle(); + //! delay_ms(1000); + //! } + //! ``` + pub use avr_hal_generic::port::{mode, PinMode, PinOps}; + + #[allow(unused_imports)] + use crate::r#impl::{impl_port_peripheral_b8_c7_d8,impl_port_peripheral_a8_b8_c8_d8,impl_port_peripheral_a8_b8_c8_d8_e8_f8_g6_h8_j8_k8_l8}; + + use crate::$hal as hal; + $($mod)* + } + + pub use pac::Peripherals; + pub use port::{Pins, pins}; + } +} +pub(crate) use impl_mod_port; + +macro_rules! impl_port_peripheral_b8_c7_d8 { + () => { + avr_hal_generic::impl_port_traditional! { + enum Ports { + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + } + } + } +} +pub(crate) use impl_port_peripheral_b8_c7_d8; + +macro_rules! impl_port_peripheral_a8_b8_c8_d8 { + () => { + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + } + } + } +} +pub(crate) use impl_port_peripheral_a8_b8_c8_d8; + +macro_rules! impl_port_peripheral_a8_b8_c8_d8_e8_f8_g6_h8_j8_k8_l8 { + () => { + avr_hal_generic::impl_port_traditional! { + enum Ports { + A: hal::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], + B: hal::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], + C: hal::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], + D: hal::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], + E: hal::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7], + F: hal::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7], + G: hal::pac::PORTG = [0, 1, 2, 3, 4, 5], + H: hal::pac::PORTH = [0, 1, 2, 3, 4, 5, 6, 7], + J: hal::pac::PORTJ = [0, 1, 2, 3, 4, 5, 6, 7], + K: hal::pac::PORTK = [0, 1, 2, 3, 4, 5, 6, 7], + L: hal::pac::PORTL = [0, 1, 2, 3, 4, 5, 6, 7], + } + } + } +} +pub(crate) use impl_port_peripheral_a8_b8_c8_d8_e8_f8_g6_h8_j8_k8_l8; diff --git a/mcu/atmega-hal/src/impl/simple_pwm.rs b/mcu/atmega-hal/src/impl/simple_pwm.rs new file mode 100644 index 0000000000..cf2caf9c2d --- /dev/null +++ b/mcu/atmega-hal/src/impl/simple_pwm.rs @@ -0,0 +1,535 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_simple_pwm { + ( + hal: crate::$hal:ident, + $(impl!: $($impl_macro:ident)::* $({ + $($arg_name:ident: $arg_value:expr,)* + })?,)? + $(impl: { + $($impl:item)* + },)? + ) => { + pub mod simple_pwm { + pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; + + #[allow(unused_imports)] + use crate::r#impl::{impl_simple_pwm_48p_168_328p_328pb, impl_simple_pwm_1280_2560}; + + #[allow(unused_imports)] + use crate::$hal as hal; + + $( + $($impl_macro)::+! { + hal: crate::$hal, + $($($arg_name: $arg_value,)*)? + } + )? + + $($($impl)*)? + } + } +} +pub(crate) use impl_mod_simple_pwm; + +macro_rules! impl_simple_pwm_48p_168_328p_328pb { + ( + hal: crate::$hal:ident, + ) => { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PD5`, `PD6`) + /// + /// # Example + /// ``` + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer0); + /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer0); + /// + /// d5.set_duty(128); + /// d5.enable(); + /// ``` + pub struct Timer0Pwm { + timer: hal::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PD6: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PD5: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB1`, `PB2`) + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); + /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); + /// + /// d9.set_duty(128); + /// d9.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_r, w| { + w.wgm1().bits(0b01); + + match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + } + }); + }, + pins: { + hal::port::PB1: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); + }, + }, + + hal::port::PB2: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC2` for PWM (pins `PB3`, `PD3`) + /// + /// # Example + /// ``` + /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); + /// + /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); + /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); + /// + /// d11.set_duty(128); + /// d11.enable(); + /// ``` + pub struct Timer2Pwm { + timer: hal::pac::TC2, + init: |tim, prescaler| { + tim.tccr2a.modify(|_r, w| w.wgm2().pwm_fast()); + tim.tccr2b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs2().direct(), + Prescaler::Prescale8 => w.cs2().prescale_8(), + Prescaler::Prescale64 => w.cs2().prescale_64(), + Prescaler::Prescale256 => w.cs2().prescale_256(), + Prescaler::Prescale1024 => w.cs2().prescale_1024(), + }); + }, + pins: { + hal::port::PB3: { + ocr: ocr2a, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); + }, + }, + + hal::port::PD3: { + ocr: ocr2b, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); + }, + }, + }, + } + } + }; +} +pub(crate) use impl_simple_pwm_48p_168_328p_328pb; + +macro_rules! impl_simple_pwm_1280_2560 { + ( + hal: crate::$hal:ident, + ) => { + avr_hal_generic::impl_simple_pwm! { + /// Use `TC0` for PWM (pins `PB7`, `PG5`) + /// + /// # Example + /// ``` + /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); + /// + /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer0); + /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer0); + /// + /// d13.set_duty(128); + /// d13.enable(); + /// ``` + pub struct Timer0Pwm { + timer: hal::pac::TC0, + init: |tim, prescaler| { + tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); + tim.tccr0b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs0().direct(), + Prescaler::Prescale8 => w.cs0().prescale_8(), + Prescaler::Prescale64 => w.cs0().prescale_64(), + Prescaler::Prescale256 => w.cs0().prescale_256(), + Prescaler::Prescale1024 => w.cs0().prescale_1024(), + }); + }, + pins: { + hal::port::PB7: { + ocr: ocr0a, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); + }, + }, + + hal::port::PG5: { + ocr: ocr0b, + into_pwm: |tim| if enable { + tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); + } else { + tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) + /// + /// # Example + /// ``` + /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); + /// + /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); + /// let mut d12 = pins.d12.into_output().into_pwm(&mut timer1); + /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer1); + /// + /// d11.set_duty(128); + /// d11.enable(); + /// ``` + pub struct Timer1Pwm { + timer: hal::pac::TC1, + init: |tim, prescaler| { + tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); + tim.tccr1b.modify(|_r, w| match prescaler { + Prescaler::Direct => w.cs1().direct(), + Prescaler::Prescale8 => w.cs1().prescale_8(), + Prescaler::Prescale64 => w.cs1().prescale_64(), + Prescaler::Prescale256 => w.cs1().prescale_256(), + Prescaler::Prescale1024 => w.cs1().prescale_1024(), + }); + }, + pins: { + hal::port::PB5: { + ocr: ocr1a, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); + }, + }, + + hal::port::PB6: { + ocr: ocr1b, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); + }, + }, + + hal::port::PB7: { + ocr: ocr1c, + into_pwm: |tim| if enable { + tim.tccr1a.modify(|_r, w| w.com1c().match_clear()); + } else { + tim.tccr1a.modify(|_r, w| w.com1c().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC2` for PWM (pins `PB4`, `PH6`) + /// + /// # Example + /// ``` + /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); + /// + /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer2); + /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer2); + /// + /// d10.set_duty(128); + /// d10.enable(); + /// ``` + + pub struct Timer2Pwm { + timer: hal::pac::TC2, + init: |tim, prescaler| { + tim.tccr2a.modify(|_r, w| w.wgm2().bits(0b01)); + tim.tccr2b.modify(|_r, w| { + w.wgm22().clear_bit(); + + match prescaler { + Prescaler::Direct => w.cs2().direct(), + Prescaler::Prescale8 => w.cs2().prescale_8(), + Prescaler::Prescale64 => w.cs2().prescale_64(), + Prescaler::Prescale256 => w.cs2().prescale_256(), + Prescaler::Prescale1024 => w.cs2().prescale_1024(), + } + }); + }, + pins: { + hal::port::PB4: { + ocr: ocr2a, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); + }, + }, + + hal::port::PH6: { + ocr: ocr2b, + into_pwm: |tim| if enable { + tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); + } else { + tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); + }, + }, + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC3` for PWM (pins `PE3`, `PE4`, `PE5`) + /// + /// # Example + /// ``` + /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); + /// + /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); + /// let mut d2 = pins.d2.into_output().into_pwm(&mut timer3); + /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer3); + /// + /// d5.set_duty(128); + /// d5.enable(); + /// ``` + pub struct Timer3Pwm { + timer: hal::pac::TC3, + init: |tim, prescaler| { + tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); + tim.tccr3b.modify(|_r, w| { + 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: { + hal::port::PE3: { + ocr: ocr3a, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); + }, + }, + + hal::port::PE4: { + ocr: ocr3b, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); + }, + }, + + hal::port::PE5: { + ocr: ocr3c, + into_pwm: |tim| if enable { + tim.tccr3a.modify(|_r, w| w.com3c().match_clear()); + } else { + tim.tccr3a.modify(|_r, w| w.com3c().disconnected()); + }, + }, + + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC4` for PWM (pins `PH3`, `PH4`, `PH5`) + /// + /// # Example + /// ``` + /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); + /// + /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); + /// let mut d7 = pins.d7.into_output().into_pwm(&mut timer4); + /// let mut d8 = pins.d8.into_output().into_pwm(&mut timer4); + /// + /// d6.set_duty(128); + /// d6.enable(); + /// ``` + pub struct Timer4Pwm { + timer: hal::pac::TC4, + init: |tim, prescaler| { + tim.tccr4a.modify(|_r, w| w.wgm4().bits(0b01)); + tim.tccr4b.modify(|_r, w| { + 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: { + hal::port::PH3: { + ocr: ocr4a, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); + }, + }, + + hal::port::PH4: { + ocr: ocr4b, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); + }, + }, + + hal::port::PH5: { + ocr: ocr4c, + into_pwm: |tim| if enable { + tim.tccr4a.modify(|_r, w| w.com4c().match_clear()); + } else { + tim.tccr4a.modify(|_r, w| w.com4c().disconnected()); + }, + }, + + }, + } + } + + avr_hal_generic::impl_simple_pwm! { + /// Use `TC5` for PWM (pins `PL3`, `PL4`, `PL5`) + /// + /// # Example + /// ``` + /// let mut timer5 = Timer5Pwm::new(dp.TC5, Prescaler::Prescale64); + /// + /// let mut d46 = pins.d46.into_output().into_pwm(&mut timer5); + /// let mut d45 = pins.d45.into_output().into_pwm(&mut timer5); + /// let mut d44 = pins.d44.into_output().into_pwm(&mut timer5); + /// + /// d46.set_duty(128); + /// d46.enable(); + /// ``` + pub struct Timer5Pwm { + timer: hal::pac::TC5, + init: |tim, prescaler| { + tim.tccr5a.modify(|_r, w| w.wgm5().bits(0b01)); + tim.tccr5b.modify(|_r, w| { + w.wgm5().bits(0b01); + + match prescaler { + Prescaler::Direct => w.cs5().direct(), + Prescaler::Prescale8 => w.cs5().prescale_8(), + Prescaler::Prescale64 => w.cs5().prescale_64(), + Prescaler::Prescale256 => w.cs5().prescale_256(), + Prescaler::Prescale1024 => w.cs5().prescale_1024(), + } + }); + }, + pins: { + hal::port::PL3: { + ocr: ocr5a, + into_pwm: |tim| if enable { + tim.tccr5a.modify(|_r, w| w.com5a().match_clear()); + } else { + tim.tccr5a.modify(|_r, w| w.com5a().disconnected()); + }, + }, + + hal::port::PL4: { + ocr: ocr5b, + into_pwm: |tim| if enable { + tim.tccr5a.modify(|_r, w| w.com5b().match_clear()); + } else { + tim.tccr5a.modify(|_r, w| w.com5b().disconnected()); + }, + }, + + hal::port::PL5: { + ocr: ocr5c, + into_pwm: |tim| if enable { + tim.tccr5a.modify(|_r, w| w.com5c().match_clear()); + } else { + tim.tccr5a.modify(|_r, w| w.com5c().disconnected()); + }, + }, + + }, + } + } + + } +} +pub(crate) use impl_simple_pwm_1280_2560; diff --git a/mcu/atmega-hal/src/impl/spi.rs b/mcu/atmega-hal/src/impl/spi.rs new file mode 100644 index 0000000000..42e3d4718d --- /dev/null +++ b/mcu/atmega-hal/src/impl/spi.rs @@ -0,0 +1,74 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_spi { + ( + hal: crate::$hal:ident, + interfaces: {$( + $interface:ident: { + peripheral: $peripheral:ident, + sclk: $sclk:ident, + mosi: $mosi:ident, + miso: $miso:ident, + cs: $cs:ident, + }, + )+}, + ) => { + pub mod spi { + //! SPI + //! + //! # Example + //! + //! Complete example source code can be found in the repository + //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) + //! + //! ``` + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let pins = atmega_hal::pins!(dp); + //! + //! let (mut spi, mut cs) = spi::Spi::new( + //! dp.SPI, + //! pins.pb1.into_output(), + //! pins.pb2.into_output(), + //! pins.pb3.into_pull_up_input(), + //! pins.pb0.into_output(), + //! spi::Settings::default(), + //! ); + //! + //! let data_out = b"Hello World!"; + //! let mut data_in = [0u8; 12]; + //! + //! cs.set_low().unwrap(); + //! spi.transfer(&mut data_in, data_out).unwrap(); + //! cs.set_high().unwrap(); + //! + //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); + //! ``` + + pub use avr_hal_generic::spi::*; + use crate::$hal as hal; + + $( + pub type $interface = avr_hal_generic::spi::Spi< + hal::Hal, + hal::pac::$peripheral, + hal::port::$sclk, + hal::port::$mosi, + hal::port::$miso, + hal::port::$cs, + >; + + avr_hal_generic::impl_spi! { + hal: hal::Hal, + peripheral: hal::pac::$peripheral, + sclk: hal::port::$sclk, + mosi: hal::port::$mosi, + miso: hal::port::$miso, + cs: hal::port::$cs, + } + )+ + } + pub use spi::Spi; + } +} +pub(crate) use impl_mod_spi; + diff --git a/mcu/atmega-hal/src/impl/usart.rs b/mcu/atmega-hal/src/impl/usart.rs new file mode 100644 index 0000000000..03adf7be51 --- /dev/null +++ b/mcu/atmega-hal/src/impl/usart.rs @@ -0,0 +1,199 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_usart { + ( + hal: crate::$hal:ident, + interfaces: {$( + $interface:ident: { + peripheral: $peripheral:ident, + rx: $rx:ident, + tx: $tx:ident, + impl!: $($impl_macro:ident)::+ $({ + $($arg_name:ident: $arg_value:expr,)* + })?, + }, + )+}, + ) => { + pub mod usart { + //! USART + //! + //! # Example + //! + //! Complete example source code can be found in the repository: + //! [`atmega2560-usart.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-usart.rs) + //! + //! *Note: [ufmt](https://crates.io/crates/ufmt/) is used instead of `core::fmt` because + //! `core::fmt` code quickly grows too large for AVR platforms.* + //! + //! ``` + //! let dp = atmega_hal::Peripherals::take().unwrap(); + //! let pins = atmega_hal::pins!(dp); + //! + //! let mut serial = Usart::new( + //! dp.USART0, + //! pins.pe0, + //! pins.pe1.into_output(), + //! Baudrate::::new(57600), + //! ); + //! + //! ufmt::uwriteln!(&mut serial, "Hello from ATmega!").unwrap(); + //! + //! loop { + //! // Read a byte from the serial connection + //! let b = nb::block!(serial.read()).unwrap(); + //! // Answer + //! ufmt::uwriteln!(&mut serial, "Got {}!", b).unwrap(); + //! } + //! ``` + + #[allow(unused_imports)] + use avr_hal_generic::paste::paste; + + pub type Usart = + avr_hal_generic::usart::Usart; + pub type UsartWriter = + avr_hal_generic::usart::UsartWriter; + pub type UsartReader = + avr_hal_generic::usart::UsartReader; + + pub use avr_hal_generic::usart::*; + + $( + pub type $interface = Usart< + crate::$hal::pac::$peripheral, + crate::$hal::port::Pin, + crate::$hal::port::Pin, + CLOCK, + >; + + $($impl_macro)::+! { + hal: crate::$hal, + peripheral: $peripheral, + rx: $rx, + tx: $tx , + $($($arg_name: $arg_value,)*)? + } + )+ + } + pub use usart::Usart; + } +} +pub(crate) use impl_mod_usart; + +macro_rules! impl_usart_traditional { + ( + hal: crate::$hal:ident, + peripheral: $peripheral:ident, + rx: $rx:ident, + tx: $tx:ident, + register_suffix: $register_suffix:expr, + ) => { + avr_hal_generic::impl_usart_traditional! { + hal: crate::$hal::Hal, + peripheral: crate::$hal::pac::$peripheral, + register_suffix: $register_suffix, + rx: crate::$hal::port::$rx, + tx: crate::$hal::port::$tx, + } + } +} +pub(crate) use impl_usart_traditional; + +// TODO: atmega8 USART is different from other atmegas +// implemented so far. It uses the same register address +// for UBRRH and UCSRC, the way to select which register +// to write to, msb has to be 1 (for UCSRC) +// or 0 (for UBRRH). Because of the same address, +// these two are exposed as functions instead of +// fields. +macro_rules! impl_usart_ubrrh_ucsrc { + ( + hal: crate::$hal:ident, + peripheral: $peripheral:ident, + rx: $rx:ident, + tx: $tx:ident, + ) => { + impl + avr_hal_generic::usart::UsartOps< + crate::$hal::Hal, + crate::$hal::port::Pin, + crate::$hal::port::Pin, + > for crate::$hal::pac::$peripheral + { + fn raw_init(&mut self, baudrate: avr_hal_generic::usart::Baudrate) { + // msb of ubrrh has to be 0 to set ubrrh register. (see atmega8 datasheet) + let ubrrh: u8 = ((baudrate.ubrr >> 8) & 0x0F) as u8; + let ubrrl: u8 = (baudrate.ubrr & 0xFF) as u8; + self.ubrrh().write(|w| w.bits(ubrrh)); + self.ubrrl.write(|w| w.bits(ubrrl)); + self.ucsra.write(|w| w.u2x().bit(baudrate.u2x)); + + // Enable receiver and transmitter but leave interrupts disabled. + #[rustfmt::skip] + self.ucsrb.write(|w| w + .txen().set_bit() + .rxen().set_bit() + ); + + // Set frame format to 8n1 for now. At some point, this should be made + // configurable, similar to what is done in other HALs. + #[rustfmt::skip] + self.ucsrc().write(|w| w + .ursel().set_bit() // sets the ucsrc instead of ubrrh (ubrrh and ucsrc share same location on ATmega8, see atmega8 datasheet) + .umsel().usart_async() + .ucsz().chr8() + .usbs().stop1() + .upm().disabled() + ); + } + + fn raw_deinit(&mut self) { + // Wait for any ongoing transfer to finish. + avr_hal_generic::nb::block!(self.raw_flush()).ok(); + self.ucsrb.reset(); + } + + fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { + if self.ucsra.read().udre().bit_is_clear() { + Err(avr_hal_generic::nb::Error::WouldBlock) + } else { + Ok(()) + } + } + + fn raw_write( + &mut self, + byte: u8, + ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { + // Call flush to make sure the data-register is empty + self.raw_flush()?; + + self.udr.write(|w| w.bits(byte)); + Ok(()) + } + + fn raw_read(&mut self) -> avr_hal_generic::nb::Result { + if self.ucsra.read().rxc().bit_is_clear() { + return Err(avr_hal_generic::nb::Error::WouldBlock); + } + + Ok(self.udr.read().bits()) + } + + fn raw_interrupt(&mut self, event: avr_hal_generic::usart::Event, state: bool) { + match event { + avr_hal_generic::usart::Event::RxComplete => { + self.ucsrb.modify(|_, w| w.rxcie().bit(state)) + } + avr_hal_generic::usart::Event::TxComplete => { + self.ucsrb.modify(|_, w| w.txcie().bit(state)) + } + avr_hal_generic::usart::Event::DataRegisterEmpty => { + self.ucsrb.modify(|_, w| w.udrie().bit(state)) + } + } + } + } + }; +} +pub(crate) use impl_usart_ubrrh_ucsrc; diff --git a/mcu/atmega-hal/src/impl/wdt.rs b/mcu/atmega-hal/src/impl/wdt.rs new file mode 100644 index 0000000000..371b898911 --- /dev/null +++ b/mcu/atmega-hal/src/impl/wdt.rs @@ -0,0 +1,88 @@ +#![allow(unused_macros)] + +macro_rules! impl_mod_wdt { + ($($mod:item)*) => { + pub mod wdt { + #[allow(unused_imports)] + use crate::r#impl::{impl_wdt_peripheral_ms2000, impl_wdt_peripheral_ms8000, impl_wdt_peripheral}; + + pub use avr_hal_generic::wdt::{Timeout, WdtOps}; + + $($mod)* + } + + pub use wdt::Wdt; + } +} +pub(crate) use impl_mod_wdt; + +macro_rules! impl_wdt_peripheral { + ( + mcusr: $($mcusr:ident)::+, + wdtcsr_name: $wdtcsr_name:ident, + timeout: |$to:ident, $w:ident| $to_match:expr $(,)? +) => { + + avr_hal_generic::impl_wdt! { + hal: hal::Hal, + peripheral: hal::pac::WDT, + mcusr: $($mcusr)::+, + wdtcsr_name: $wdtcsr_name, + timeout: |$to, $w| $to_match, + } + + pub type Wdt = avr_hal_generic::wdt::Wdt; + }; +} +pub(crate) use impl_wdt_peripheral; + +macro_rules! impl_wdt_peripheral_ms8000 { + ( + mcusr: $($mcusr:ident)::+, + wdtcsr_name: $wdtcsr_name:ident, +) => { + impl_wdt_peripheral! { + mcusr: $($mcusr)::+, + wdtcsr_name: $wdtcsr_name, + timeout: |to, w| match to { + Timeout::Ms16 => w.wdpl().cycles_2k_512k(), + Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), + Timeout::Ms64 => w.wdpl().cycles_8k(), + Timeout::Ms125 => w.wdpl().cycles_16k(), + Timeout::Ms250 => w.wdpl().cycles_32k(), + Timeout::Ms500 => w.wdpl().cycles_64k(), + Timeout::Ms1000 => w.wdpl().cycles_128k(), + Timeout::Ms2000 => w.wdpl().cycles_256k(), + Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), + Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), + }, + } + + }; +} +pub(crate) use impl_wdt_peripheral_ms8000; + +macro_rules! impl_wdt_peripheral_ms2000 { + ( + mcusr: $($mcusr:ident)::+, + wdtcsr_name: $wdtcsr_name:ident, + ) => { + impl_wdt_peripheral! { + mcusr: $($mcusr)::+, + wdtcsr_name: $wdtcsr_name, + timeout: |to, w| match to { + Timeout::Ms16 => w.wdpl().cycles_16k(), + Timeout::Ms32 => w.wdpl().cycles_32k(), + Timeout::Ms64 => w.wdpl().cycles_64k(), + Timeout::Ms125 => w.wdpl().cycles_128k(), + Timeout::Ms250 => w.wdpl().cycles_256k(), + Timeout::Ms500 => w.wdpl().cycles_512k(), + Timeout::Ms1000 => w.wdpl().cycles_1024k(), + Timeout::Ms2000 => w.wdpl().cycles_2048k(), + Timeout::Ms4000 => panic!(), // Does not exist on this MCU ... + Timeout::Ms8000 => panic!() // Does not exist on this MCU ... + }, + } + }; +} +pub(crate) use impl_wdt_peripheral_ms2000; diff --git a/mcu/atmega-hal/src/lib.rs b/mcu/atmega-hal/src/lib.rs index e2ce9bf2e1..eb6a54f9d6 100644 --- a/mcu/atmega-hal/src/lib.rs +++ b/mcu/atmega-hal/src/lib.rs @@ -4,211 +4,82 @@ //! ============= //! Common HAL (hardware abstraction layer) for ATmega* microcontrollers. //! -//! **Note**: This version of the documentation was built for -#![cfg_attr(feature = "atmega48p", doc = "**ATmega48P**.")] -#![cfg_attr(feature = "atmega164pa", doc = "**ATmega164PA**.")] -#![cfg_attr(feature = "atmega168", doc = "**ATmega168**.")] -#![cfg_attr(feature = "atmega328p", doc = "**ATmega328P**.")] -#![cfg_attr(feature = "atmega328pb", doc = "**ATmega328PB**.")] -#![cfg_attr(feature = "atmega32a", doc = "**ATmega32a**.")] -#![cfg_attr(feature = "atmega32u4", doc = "**ATmega32U4**.")] -#![cfg_attr(feature = "atmega2560", doc = "**ATmega2560**.")] -#![cfg_attr(feature = "atmega128a", doc = "**ATmega128A**.")] -#![cfg_attr(feature = "atmega1280", doc = "**ATmega1280**.")] -#![cfg_attr(feature = "atmega1284p", doc = "**ATmega1284P**.")] -#![cfg_attr(feature = "atmega8", doc = "**ATmega8**.")] -//! This means that only items which are available for this MCU are visible. If you are using -//! a different chip, try building the documentation locally with: -//! -//! ```text -//! cargo doc --features --open -//! ``` + +// This crate can be configured in one of two ways: either you specify deprecated-globals and exactly one MCU +// Or you don't specify deprecated globals and at least one MCU #[cfg(all( - not(feature = "device-selected"), + not(feature = "_mcu-selected"), not(feature = "disable-device-selection-error") ))] compile_error!( - "This crate requires you to specify your target chip as a feature. + "You must specify your target chips as a feature. - Please select one of the following + Please select at least one of the following features * atmega48p * atmega164pa * atmega168 * atmega328p * atmega328pb + * atmega32a * atmega32u4 + * atmega2560 * atmega128a * atmega1280 - * atmega2560 * atmega1284p * atmega8 " ); -/// Reexport of `atmega1280` from `avr-device` -/// -#[cfg(feature = "atmega1280")] -pub use avr_device::atmega1280 as pac; -/// Reexport of `atmega1284p` from `avr-device` -/// -#[cfg(feature = "atmega1284p")] -pub use avr_device::atmega1284p as pac; -/// Reexport of `atmega128a` from `avr-device` -/// -#[cfg(feature = "atmega128a")] -pub use avr_device::atmega128a as pac; -/// Reexport of `atmega164pa` from `avr-device` -/// -#[cfg(feature = "atmega164pa")] -pub use avr_device::atmega164pa as pac; -/// Reexport of `atmega168` from `avr-device` -/// -#[cfg(feature = "atmega168")] -pub use avr_device::atmega168 as pac; -/// Reexport of `atmega2560` from `avr-device` -/// -#[cfg(feature = "atmega2560")] -pub use avr_device::atmega2560 as pac; -/// 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; -/// Reexport of `atmega32a` from `avr-device` -/// -#[cfg(feature = "atmega32a")] -pub use avr_device::atmega32a as pac; -/// Reexport of `atmega32u4` from `avr-device` -/// -#[cfg(feature = "atmega32u4")] -pub use avr_device::atmega32u4 as pac; -/// Reexport of `atmega48p` from `avr-device` -/// -#[cfg(feature = "atmega48p")] -pub use avr_device::atmega48p as pac; -/// Reexport of `atmega8` from `avr-device` -/// -#[cfg(feature = "atmega8")] -pub use avr_device::atmega8 as pac; - /// See [`avr_device::entry`](https://docs.rs/avr-device/latest/avr_device/attr.entry.html). #[cfg(feature = "rt")] pub use avr_device::entry; -#[cfg(feature = "device-selected")] -pub use pac::Peripherals; - pub use avr_hal_generic::clock; pub use avr_hal_generic::delay; pub use avr_hal_generic::prelude; -#[cfg(feature = "device-selected")] -pub mod adc; -#[cfg(feature = "device-selected")] -pub use adc::Adc; - -#[cfg(feature = "device-selected")] -pub mod i2c; -#[cfg(feature = "device-selected")] -pub use i2c::I2c; - -#[cfg(feature = "device-selected")] -pub mod spi; -#[cfg(feature = "device-selected")] -pub use spi::Spi; - -#[cfg(feature = "device-selected")] -pub mod port; -#[cfg(feature = "device-selected")] -pub use port::Pins; - -#[cfg(feature = "device-selected")] -pub mod simple_pwm; - -#[cfg(feature = "device-selected")] -pub mod usart; -#[cfg(feature = "device-selected")] -pub use usart::Usart; - -#[cfg(feature = "device-selected")] -pub mod wdt; -#[cfg(feature = "device-selected")] -pub use wdt::Wdt; - -#[cfg(feature = "device-selected")] -pub mod eeprom; -#[cfg(feature = "device-selected")] -pub use eeprom::Eeprom; - -pub struct Atmega; - -#[cfg(any(feature = "atmega48p", feature = "atmega168", feature = "atmega328p"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) - }; -} -#[cfg(any(feature = "atmega164pa"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) - }; -} -#[cfg(feature = "atmega328pb")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE) - }; -} -#[cfg(feature = "atmega32u4")] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF) - }; -} - -#[cfg(any(feature = "atmega128a"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new( - $p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF, $p.PORTG, - ) - }; -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new( - $p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD, $p.PORTE, $p.PORTF, $p.PORTG, $p.PORTH, - $p.PORTJ, $p.PORTK, $p.PORTL, - ) - }; -} - -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) - }; -} - -#[cfg(any(feature = "atmega8"))] -#[macro_export] -macro_rules! pins { - ($p:expr) => { - $crate::Pins::new($p.PORTB, $p.PORTC, $p.PORTD) - }; -} +#[cfg(feature = "_mcu-atmega48p")] +pub mod atmega48p; + +#[cfg(feature = "_mcu-atmega164pa")] +pub mod atmega164pa; + +#[cfg(feature = "_mcu-atmega168")] +pub mod atmega168; + +#[cfg(feature = "_mcu-atmega328p")] +pub mod atmega328p; + +#[cfg(feature = "_mcu-atmega328pb")] +pub mod atmega328pb; + +#[cfg(feature = "_mcu-atmega32a")] +pub mod atmega32a; + +#[cfg(feature = "_mcu-atmega32u4")] +pub mod atmega32u4; + +#[cfg(feature = "_mcu-atmega2560")] +pub mod atmega2560; + +#[cfg(feature = "_mcu-atmega128a")] +pub mod atmega128a; + +#[cfg(feature = "_mcu-atmega1280")] +pub mod atmega1280; + +#[cfg(feature = "_mcu-atmega1284p")] +pub mod atmega1284p; + +#[cfg(feature = "_mcu-atmega8")] +pub mod atmega8; + +#[cfg(feature = "deprecated-globals")] +mod globals; + +pub(crate) mod r#impl; + +#[cfg(feature = "deprecated-globals")] +pub use globals::*; diff --git a/mcu/atmega-hal/src/port.rs b/mcu/atmega-hal/src/port.rs deleted file mode 100644 index 746c0f09a0..0000000000 --- a/mcu/atmega-hal/src/port.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Port -//! -//! # Example -//! -//! Complete example source code can be found in the repository: -//! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) -//! -//! ``` -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let pins = atmega_hal::pins!(dp); -//! -//! let mut led = pins.pb7.into_output(); -//! -//! loop { -//! led.toggle(); -//! delay_ms(1000); -//! } -//! ``` - -pub use avr_hal_generic::port::{mode, PinMode, PinOps}; - -#[cfg(any(feature = "atmega48p", feature = "atmega168", feature = "atmega328p"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - } -} - -#[cfg(any(feature = "atmega164pa"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6 ,7], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6 ,7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6 ,7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6 ,7], - } -} - -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - E: crate::pac::PORTE = [0, 1, 2, 3], - } -} - -#[cfg(feature = "atmega32u4")] -avr_hal_generic::impl_port_traditional! { - enum Ports { - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - E: crate::pac::PORTE = [2, 6], - F: crate::pac::PORTF = [0, 1, 4, 5, 6, 7], - } -} - -#[cfg(any(feature = "atmega128a"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - E: crate::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7], - F: crate::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7], - G: crate::pac::PORTG = [0, 1, 2, 3, 4], - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - E: crate::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7], - F: crate::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7], - G: crate::pac::PORTG = [0, 1, 2, 3, 4, 5], - H: crate::pac::PORTH = [0, 1, 2, 3, 4, 5, 6, 7], - J: crate::pac::PORTJ = [0, 1, 2, 3, 4, 5, 6, 7], - K: crate::pac::PORTK = [0, 1, 2, 3, 4, 5, 6, 7], - L: crate::pac::PORTL = [0, 1, 2, 3, 4, 5, 6, 7], - } -} - -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - } -} - -#[cfg(any(feature = "atmega8"))] -avr_hal_generic::impl_port_traditional! { - enum Ports { - B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], - C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6], - D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], - } -} diff --git a/mcu/atmega-hal/src/simple_pwm.rs b/mcu/atmega-hal/src/simple_pwm.rs deleted file mode 100644 index d0bda71be0..0000000000 --- a/mcu/atmega-hal/src/simple_pwm.rs +++ /dev/null @@ -1,1177 +0,0 @@ -pub use avr_hal_generic::simple_pwm::{IntoPwmPin, Prescaler, PwmPinOps}; - -#[allow(unused_imports)] -use crate::port::*; - -#[cfg(any( - feature = "atmega48p", - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb" -))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PD5`, `PD6`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer0); - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer0); - /// - /// d5.set_duty(128); - /// d5.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PD6: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PD5: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any( - feature = "atmega48p", - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb" -))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB1`, `PB2`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); - /// - /// d9.set_duty(128); - /// d9.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_r, w| { - w.wgm1().bits(0b01); - - match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - } - }); - }, - pins: { - PB1: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); - }, - }, - - PB2: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any( - feature = "atmega48p", - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb" -))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC2` for PWM (pins `PB3`, `PD3`) - /// - /// # Example - /// ``` - /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); - /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); - /// - /// d11.set_duty(128); - /// d11.enable(); - /// ``` - pub struct Timer2Pwm { - timer: crate::pac::TC2, - init: |tim, prescaler| { - tim.tccr2a.modify(|_r, w| w.wgm2().pwm_fast()); - tim.tccr2b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs2().direct(), - Prescaler::Prescale8 => w.cs2().prescale_8(), - Prescaler::Prescale64 => w.cs2().prescale_64(), - Prescaler::Prescale256 => w.cs2().prescale_256(), - Prescaler::Prescale1024 => w.cs2().prescale_1024(), - }); - }, - pins: { - PB3: { - ocr: ocr2a, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); - }, - }, - - PD3: { - ocr: ocr2b, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC3` for PWM (pins `PD0`, `PD2`) - pub struct Timer3Pwm { - timer: crate::pac::TC3, - init: |tim, prescaler| { - tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); - tim.tccr3b.modify(|_r, w| { - 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: { - PD0: { - ocr: ocr3a, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); - }, - }, - - PD2: { - ocr: ocr3b, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); - }, - }, - }, - } -} - -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC4` for PWM (pins `PD1`, `PD2`) - pub struct Timer4Pwm { - timer: crate::pac::TC4, - init: |tim, prescaler| { - tim.tccr4a.modify(|_r, w| w.wgm4().bits(0b01)); - tim.tccr4b.modify(|_r, w| { - 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: { - PD1: { - ocr: ocr4a, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); - }, - }, - - PD2: { - ocr: ocr4b, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB7`, `PG5`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer0); - /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer0); - /// - /// d13.set_duty(128); - /// d13.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PB7: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PG5: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); - /// let mut d12 = pins.d12.into_output().into_pwm(&mut timer1); - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer1); - /// - /// d11.set_duty(128); - /// d11.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - }); - }, - pins: { - PB5: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); - }, - }, - - PB6: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); - }, - }, - - PB7: { - ocr: ocr1c, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1c().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1c().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC2` for PWM (pins `PB4`, `PH6`) - /// - /// # Example - /// ``` - /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); - /// - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer2); - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer2); - /// - /// d10.set_duty(128); - /// d10.enable(); - /// ``` - - pub struct Timer2Pwm { - timer: crate::pac::TC2, - init: |tim, prescaler| { - tim.tccr2a.modify(|_r, w| w.wgm2().bits(0b01)); - tim.tccr2b.modify(|_r, w| { - w.wgm22().clear_bit(); - - match prescaler { - Prescaler::Direct => w.cs2().direct(), - Prescaler::Prescale8 => w.cs2().prescale_8(), - Prescaler::Prescale64 => w.cs2().prescale_64(), - Prescaler::Prescale256 => w.cs2().prescale_256(), - Prescaler::Prescale1024 => w.cs2().prescale_1024(), - } - }); - }, - pins: { - PB4: { - ocr: ocr2a, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); - }, - }, - - PH6: { - ocr: ocr2b, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC3` for PWM (pins `PE3`, `PE4`, `PE5`) - /// - /// # Example - /// ``` - /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); - /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); - /// let mut d2 = pins.d2.into_output().into_pwm(&mut timer3); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer3); - /// - /// d5.set_duty(128); - /// d5.enable(); - /// ``` - pub struct Timer3Pwm { - timer: crate::pac::TC3, - init: |tim, prescaler| { - tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); - tim.tccr3b.modify(|_r, w| { - 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: { - PE3: { - ocr: ocr3a, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); - }, - }, - - PE4: { - ocr: ocr3b, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); - }, - }, - - PE5: { - ocr: ocr3c, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3c().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3c().disconnected()); - }, - }, - - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC4` for PWM (pins `PH3`, `PH4`, `PH5`) - /// - /// # Example - /// ``` - /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); - /// - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); - /// let mut d7 = pins.d7.into_output().into_pwm(&mut timer4); - /// let mut d8 = pins.d8.into_output().into_pwm(&mut timer4); - /// - /// d6.set_duty(128); - /// d6.enable(); - /// ``` - pub struct Timer4Pwm { - timer: crate::pac::TC4, - init: |tim, prescaler| { - tim.tccr4a.modify(|_r, w| w.wgm4().bits(0b01)); - tim.tccr4b.modify(|_r, w| { - 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: { - PH3: { - ocr: ocr4a, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); - }, - }, - - PH4: { - ocr: ocr4b, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); - }, - }, - - PH5: { - ocr: ocr4c, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4c().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4c().disconnected()); - }, - }, - - }, - } -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC5` for PWM (pins `PL3`, `PL4`, `PL5`) - /// - /// # Example - /// ``` - /// let mut timer5 = Timer5Pwm::new(dp.TC5, Prescaler::Prescale64); - /// - /// let mut d46 = pins.d46.into_output().into_pwm(&mut timer5); - /// let mut d45 = pins.d45.into_output().into_pwm(&mut timer5); - /// let mut d44 = pins.d44.into_output().into_pwm(&mut timer5); - /// - /// d46.set_duty(128); - /// d46.enable(); - /// ``` - pub struct Timer5Pwm { - timer: crate::pac::TC5, - init: |tim, prescaler| { - tim.tccr5a.modify(|_r, w| w.wgm5().bits(0b01)); - tim.tccr5b.modify(|_r, w| { - w.wgm5().bits(0b01); - - match prescaler { - Prescaler::Direct => w.cs5().direct(), - Prescaler::Prescale8 => w.cs5().prescale_8(), - Prescaler::Prescale64 => w.cs5().prescale_64(), - Prescaler::Prescale256 => w.cs5().prescale_256(), - Prescaler::Prescale1024 => w.cs5().prescale_1024(), - } - }); - }, - pins: { - PL3: { - ocr: ocr5a, - into_pwm: |tim| if enable { - tim.tccr5a.modify(|_r, w| w.com5a().match_clear()); - } else { - tim.tccr5a.modify(|_r, w| w.com5a().disconnected()); - }, - }, - - PL4: { - ocr: ocr5b, - into_pwm: |tim| if enable { - tim.tccr5a.modify(|_r, w| w.com5b().match_clear()); - } else { - tim.tccr5a.modify(|_r, w| w.com5b().disconnected()); - }, - }, - - PL5: { - ocr: ocr5c, - into_pwm: |tim| if enable { - tim.tccr5a.modify(|_r, w| w.com5c().match_clear()); - } else { - tim.tccr5a.modify(|_r, w| w.com5c().disconnected()); - }, - }, - - }, - } -} - -#[cfg(any(feature = "atmega32u4"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB7`, `PD0`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer0); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer0); - /// - /// d11.set_duty(128); - /// d11.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PB7: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PD0: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega32u4"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); - /// - /// d9.set_duty(128); - /// d9.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_r, w| w.wgm1().bits(0b01)); - - tim.tccr1b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - }); - }, - pins: { - PB5: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); - }, - }, - - PB6: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); - }, - }, - - PB7: { - ocr: ocr1c, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1c().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1c().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega32u4"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC3` for PWM (pins `PC6`) - /// - /// # Example - /// ``` - /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); - /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); - /// - /// d5.set_duty(128); - /// d5.enable(); - /// ``` - pub struct Timer3Pwm { - timer: crate::pac::TC3, - init: |tim, prescaler| { - tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); - tim.tccr3b.modify(|_r, w| w.wgm3().bits(0b01)); - - tim.tccr3b.modify(|_r, w| 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: { - PC6: { - ocr: ocr3a, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega32u4"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC4` for PWM (pins `PB6`, `PC7`, `PD7`) - /// - /// # Example - /// ``` - /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); - /// - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer4); - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer4); - /// - /// d6.set_duty(128); - /// d6.enable(); - /// ``` - pub struct Timer4Pwm { - timer: crate::pac::TC4, - init: |tim, prescaler| { - tim.tccr4a.modify(|_r, w| w.pwm4a().set_bit()); - tim.tccr4a.modify(|_r, w| w.pwm4b().set_bit()); - tim.tccr4c.modify(|_r, w| w.pwm4d().set_bit()); - - tim.tccr4b.modify(|_r, w| 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: { - PB6: { - ocr: ocr4b, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4b().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4b().disconnected()); - }, - }, - - PC7: { - ocr: ocr4a, - into_pwm: |tim| if enable { - tim.tccr4a.modify(|_r, w| w.com4a().match_clear()); - } else { - tim.tccr4a.modify(|_r, w| w.com4a().disconnected()); - }, - }, - - PD7: { - ocr: ocr4d, - into_pwm: |tim| if enable { - tim.tccr4c.modify(|_r, w| w.com4d().match_clear()); - } else { - tim.tccr4c.modify(|_r, w| w.com4d().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1284p"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB3`, `PB4`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut b3 = pins.b3.into_output().into_pwm(&mut timer0); - /// let mut b4 = pins.b4.into_output().into_pwm(&mut timer0); - /// - /// b3.set_duty(128); - /// b4.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().pwm_fast()); - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().direct(), - Prescaler::Prescale8 => w.cs0().prescale_8(), - Prescaler::Prescale64 => w.cs0().prescale_64(), - Prescaler::Prescale256 => w.cs0().prescale_256(), - Prescaler::Prescale1024 => w.cs0().prescale_1024(), - }); - }, - pins: { - PB3: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().disconnected()); - }, - }, - - PB4: { - ocr: ocr0b, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0b().match_clear()); - } else { - tim.tccr0a.modify(|_r, w| w.com0b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1284p"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PD5`, `PD4`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer1); - /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer1); - /// - /// d5.set_duty(128); - /// d5.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_r, w| { - w.wgm1().bits(0b01); - - match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - } - }); - }, - pins: { - PD5: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); - }, - }, - - PD4: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1284p"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC2` for PWM (pins `PD7`, `PD6`) - /// - /// # Example - /// ``` - /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); - /// - /// let mut d7 = pins.d7.into_output().into_pwm(&mut timer2); - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer2); - /// - /// d7.set_duty(128); - /// d7.enable(); - /// ``` - pub struct Timer2Pwm { - timer: crate::pac::TC2, - init: |tim, prescaler| { - tim.tccr2a.modify(|_r, w| w.wgm2().pwm_fast()); - tim.tccr2b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs2().direct(), - Prescaler::Prescale8 => w.cs2().prescale_8(), - Prescaler::Prescale64 => w.cs2().prescale_64(), - Prescaler::Prescale256 => w.cs2().prescale_256(), - Prescaler::Prescale1024 => w.cs2().prescale_1024(), - }); - }, - pins: { - PD7: { - ocr: ocr2a, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2a().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2a().disconnected()); - }, - }, - - PD6: { - ocr: ocr2b, - into_pwm: |tim| if enable { - tim.tccr2a.modify(|_r, w| w.com2b().match_clear()); - } else { - tim.tccr2a.modify(|_r, w| w.com2b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega1284p"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC3` for PWM (pins `PB6`, `PB7`) - pub struct Timer3Pwm { - timer: crate::pac::TC3, - init: |tim, prescaler| { - tim.tccr3a.modify(|_r, w| w.wgm3().bits(0b01)); - tim.tccr3b.modify(|_r, w| { - 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: { - PB6: { - ocr: ocr3a, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3a().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3a().disconnected()); - }, - }, - - PB7: { - ocr: ocr3b, - into_pwm: |tim| if enable { - tim.tccr3a.modify(|_r, w| w.com3b().match_clear()); - } else { - tim.tccr3a.modify(|_r, w| w.com3b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega8",))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PB1`, `PB2`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut b1 = pins.b1.into_output().into_pwm(&mut timer1); - /// let mut b2 = pins.b2.into_output().into_pwm(&mut timer1); - /// - /// d9.set_duty(128); - /// d9.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1b.modify(|_r, w| { - w.wgm1().bits(0b01); - - match prescaler { - Prescaler::Direct => w.cs1().direct(), - Prescaler::Prescale8 => w.cs1().prescale_8(), - Prescaler::Prescale64 => w.cs1().prescale_64(), - Prescaler::Prescale256 => w.cs1().prescale_256(), - Prescaler::Prescale1024 => w.cs1().prescale_1024(), - } - }); - }, - pins: { - PB1: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().disconnected()); - }, - }, - - PB2: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().match_clear()); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega8",))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC2` for PWM (pins `PB3`, `PD3`) - /// - /// # Example - /// ``` - /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); - /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); - /// - /// d11.set_duty(128); - /// d11.enable(); - /// ``` - pub struct Timer2Pwm { - timer: crate::pac::TC2, - init: |tim, prescaler| { - tim.tccr2.modify(|_r, w| w.wgm20().set_bit().wgm21().set_bit()); - tim.tccr2.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs2().direct(), - Prescaler::Prescale8 => w.cs2().prescale_8(), - Prescaler::Prescale64 => w.cs2().prescale_64(), - Prescaler::Prescale256 => w.cs2().prescale_256(), - Prescaler::Prescale1024 => w.cs2().prescale_1024(), - }); - }, - pins: { - PB3: { - ocr: ocr2, - into_pwm: |tim| if enable { - tim.tccr2.modify(|_r, w| w.com2().match_clear()); - } else { - tim.tccr2.modify(|_r, w| w.com2().disconnected()); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega164pa"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC0` for PWM (pins `PB3`) - /// - /// # Example - /// ``` - /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); - /// - /// let mut b3 = pins.pb3.into_output().into_pwm(&mut timer0); - /// - /// b3.set_duty(128); - /// b3.enable(); - /// ``` - pub struct Timer0Pwm { - timer: crate::pac::TC0, - init: |tim, prescaler| { - tim.tccr0a.modify(|_r, w| w.wgm0().bits(0b11)); - tim.tccr0a.modify(|_r, w| w.com0a().bits(0b00)); - - tim.tccr0b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs0().running_no_prescaling(), - Prescaler::Prescale8 => w.cs0().running_clk_8(), - Prescaler::Prescale64 => w.cs0().running_clk_64(), - Prescaler::Prescale256 => w.cs0().running_clk_256(), - Prescaler::Prescale1024 => w.cs0().running_clk_1024(), - }); - }, - pins: { - PB3: { - ocr: ocr0a, - into_pwm: |tim| if enable { - tim.tccr0a.modify(|_r, w| w.com0a().bits(0b11)); - } else { - tim.tccr0a.modify(|_r, w| w.com0a().bits(0b00)); - }, - }, - }, - } -} - -#[cfg(any(feature = "atmega164pa"))] -avr_hal_generic::impl_simple_pwm! { - /// Use `TC1` for PWM (pins `PD4`, `PD5`) - /// - /// # Example - /// ``` - /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); - /// - /// let mut d4 = pins.pd4.into_output().into_pwm(&mut timer1); - /// let mut d5 = pins.pd5.into_output().into_pwm(&mut timer1); - /// - /// d4.set_duty(128); - /// d4.enable(); - /// d5.set_duty(64); - /// d5.enable(); - /// ``` - pub struct Timer1Pwm { - timer: crate::pac::TC1, - init: |tim, prescaler| { - tim.tccr1a.modify(|_r, w| w.wgm1().bits(0b01)); - tim.tccr1a.modify(|_r, w| w.com1a().bits(0b00)); - tim.tccr1a.modify(|_r, w| w.com1b().bits(0b00)); - tim.tccr1b.modify(|_r, w| match prescaler { - Prescaler::Direct => w.cs1().running_no_prescaling(), - Prescaler::Prescale8 => w.cs1().running_clk_8(), - Prescaler::Prescale64 => w.cs1().running_clk_64(), - Prescaler::Prescale256 => w.cs1().running_clk_256(), - Prescaler::Prescale1024 => w.cs1().running_clk_1024(), - }); - }, - pins: { - PD4: { - ocr: ocr1a, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1a().bits(0b11)); - } else { - tim.tccr1a.modify(|_r, w| w.com1a().bits(0b00)); - }, - }, - PD5: { - ocr: ocr1b, - into_pwm: |tim| if enable { - tim.tccr1a.modify(|_r, w| w.com1b().bits(0b11)); - } else { - tim.tccr1a.modify(|_r, w| w.com1b().bits(0b00)); - }, - }, - }, - } -} diff --git a/mcu/atmega-hal/src/spi.rs b/mcu/atmega-hal/src/spi.rs deleted file mode 100644 index bb42147491..0000000000 --- a/mcu/atmega-hal/src/spi.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! SPI -//! -//! # Example -//! -//! Complete example source code can be found in the repository -//! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) -//! -//! ``` -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let pins = atmega_hal::pins!(dp); -//! -//! let (mut spi, mut cs) = spi::Spi::new( -//! dp.SPI, -//! pins.pb1.into_output(), -//! pins.pb2.into_output(), -//! pins.pb3.into_pull_up_input(), -//! pins.pb0.into_output(), -//! spi::Settings::default(), -//! ); -//! -//! let data_out = b"Hello World!"; -//! let mut data_in = [0u8; 12]; -//! -//! cs.set_low().unwrap(); -//! spi.transfer(&mut data_in, data_out).unwrap(); -//! cs.set_high().unwrap(); -//! -//! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); -//! ``` - -#[allow(unused_imports)] -use crate::port; -pub use avr_hal_generic::spi::*; - -#[cfg(any( - feature = "atmega128a", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega32u4" -))] -pub type Spi = avr_hal_generic::spi::Spi< - crate::Atmega, - crate::pac::SPI, - port::PB1, - port::PB2, - port::PB3, - port::PB0, ->; -#[cfg(any( - feature = "atmega128a", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega32u4" -))] -avr_hal_generic::impl_spi! { - hal: crate::Atmega, - peripheral: crate::pac::SPI, - sclk: port::PB1, - mosi: port::PB2, - miso: port::PB3, - cs: port::PB0, -} - -#[cfg(any( - feature = "atmega168", - feature = "atmega328p", - feature = "atmega48p", - feature = "atmega8" -))] -pub type Spi = avr_hal_generic::spi::Spi< - crate::Atmega, - crate::pac::SPI, - port::PB5, - port::PB3, - port::PB4, - port::PB2, ->; -#[cfg(any( - feature = "atmega168", - feature = "atmega328p", - feature = "atmega48p", - feature = "atmega8" -))] -avr_hal_generic::impl_spi! { - hal: crate::Atmega, - peripheral: crate::pac::SPI, - sclk: port::PB5, - mosi: port::PB3, - miso: port::PB4, - cs: port::PB2, -} - -#[cfg(feature = "atmega328pb")] -pub type Spi0 = avr_hal_generic::spi::Spi< - crate::Atmega, - crate::pac::SPI0, - port::PB5, - port::PB3, - port::PB4, - port::PB2, ->; -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_spi! { - hal: crate::Atmega, - peripheral: crate::pac::SPI0, - sclk: port::PB5, - mosi: port::PB3, - miso: port::PB4, - cs: port::PB2, -} -#[cfg(feature = "atmega328pb")] -pub type Spi1 = avr_hal_generic::spi::Spi< - crate::Atmega, - crate::pac::SPI1, - port::PC1, - port::PE3, - port::PC0, - port::PE2, ->; -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_spi! { - hal: crate::Atmega, - peripheral: crate::pac::SPI1, - sclk: port::PC1, - mosi: port::PE3, - miso: port::PC0, - cs: port::PE2, -} - -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -pub type Spi = avr_hal_generic::spi::Spi< - crate::Atmega, - crate::pac::SPI, - port::PB7, - port::PB5, - port::PB6, - port::PB4, ->; -#[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] -avr_hal_generic::impl_spi! { - hal: crate::Atmega, - peripheral: crate::pac::SPI, - sclk: port::PB7, - mosi: port::PB5, - miso: port::PB6, - cs: port::PB4, -} diff --git a/mcu/atmega-hal/src/usart.rs b/mcu/atmega-hal/src/usart.rs deleted file mode 100644 index 7a8aaeaea7..0000000000 --- a/mcu/atmega-hal/src/usart.rs +++ /dev/null @@ -1,411 +0,0 @@ -//! USART -//! -//! # Example -//! -//! Complete example source code can be found in the repository: -//! [`atmega2560-usart.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-usart.rs) -//! -//! *Note: [ufmt](https://crates.io/crates/ufmt/) is used instead of `core::fmt` because -//! `core::fmt` code quickly grows too large for AVR platforms.* -//! -//! ``` -//! let dp = atmega_hal::Peripherals::take().unwrap(); -//! let pins = atmega_hal::pins!(dp); -//! -//! let mut serial = Usart::new( -//! dp.USART0, -//! pins.pe0, -//! pins.pe1.into_output(), -//! Baudrate::::new(57600), -//! ); -//! -//! ufmt::uwriteln!(&mut serial, "Hello from ATmega!").unwrap(); -//! -//! loop { -//! // Read a byte from the serial connection -//! let b = nb::block!(serial.read()).unwrap(); -//! // Answer -//! ufmt::uwriteln!(&mut serial, "Got {}!", b).unwrap(); -//! } -//! ``` - -#[allow(unused_imports)] -use crate::port; -pub use avr_hal_generic::usart::*; - -pub type Usart = - avr_hal_generic::usart::Usart; -pub type UsartWriter = - avr_hal_generic::usart::UsartWriter; -pub type UsartReader = - avr_hal_generic::usart::UsartReader; - -#[cfg(any( - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega1284p", - feature = "atmega164pa" -))] -pub type Usart0 = Usart< - crate::pac::USART0, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any( - feature = "atmega168", - feature = "atmega328p", - feature = "atmega328pb", - feature = "atmega1284p", - feature = "atmega164pa" -))] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART0, - register_suffix: 0, - rx: port::PD0, - tx: port::PD1, -} - -#[cfg(feature = "atmega328pb")] -pub type Usart1 = Usart< - crate::pac::USART1, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(feature = "atmega328pb")] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART1, - register_suffix: 1, - rx: port::PB4, - tx: port::PB3, -} - -#[cfg(any( - feature = "atmega32u4", - feature = "atmega128a", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega1284p", - feature = "atmega164pa" -))] -pub type Usart1 = Usart< - crate::pac::USART1, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any( - feature = "atmega32u4", - feature = "atmega1280", - feature = "atmega2560", - feature = "atmega1284p", - feature = "atmega164pa" -))] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART1, - register_suffix: 1, - rx: port::PD2, - tx: port::PD3, -} - -#[cfg(any(feature = "atmega128A", feature = "atmega1280", feature = "atmega2560"))] -pub type Usart0 = Usart< - crate::pac::USART0, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART0, - register_suffix: 0, - rx: port::PE0, - tx: port::PE1, -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -pub type Usart2 = Usart< - crate::pac::USART2, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART2, - register_suffix: 2, - rx: port::PH0, - tx: port::PH1, -} - -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -pub type Usart3 = Usart< - crate::pac::USART3, - port::Pin, - port::Pin, - CLOCK, ->; -#[cfg(any(feature = "atmega1280", feature = "atmega2560"))] -avr_hal_generic::impl_usart_traditional! { - hal: crate::Atmega, - peripheral: crate::pac::USART3, - register_suffix: 3, - rx: port::PJ0, - tx: port::PJ1, -} - -#[cfg(any(feature = "atmega8", feature = "atmega32a"))] -pub type Usart0 = Usart< - crate::pac::USART, - port::Pin, - port::Pin, - CLOCK, ->; - -// TODO: atmega8 USART is different from other atmegas -// implemented so far. It uses the same register address -// for UBRRH and UCSRC, the way to select which register -// to write to, msb has to be 1 (for UCSRC) -// or 0 (for UBRRH). Because of the same address, -// these two are exposed as functions instead of -// fields. -#[cfg(any(feature = "atmega8", feature = "atmega32a"))] -impl - crate::usart::UsartOps< - crate::Atmega, - crate::port::Pin, - crate::port::Pin, - > for crate::pac::USART -{ - fn raw_init(&mut self, baudrate: crate::usart::Baudrate) { - // msb of ubrrh has to be 0 to set ubrrh register. (see atmega8 datasheet) - let ubrrh: u8 = ((baudrate.ubrr >> 8) & 0x0F) as u8; - let ubrrl: u8 = (baudrate.ubrr & 0xFF) as u8; - self.ubrrh().write(|w| w.bits(ubrrh)); - self.ubrrl.write(|w| w.bits(ubrrl)); - self.ucsra.write(|w| w.u2x().bit(baudrate.u2x)); - - // Enable receiver and transmitter but leave interrupts disabled. - #[rustfmt::skip] - self.ucsrb.write(|w| w - .txen().set_bit() - .rxen().set_bit() - ); - - // Set frame format to 8n1 for now. At some point, this should be made - // configurable, similar to what is done in other HALs. - #[rustfmt::skip] - self.ucsrc().write(|w| w - .ursel().set_bit() // sets the ucsrc instead of ubrrh (ubrrh and ucsrc share same location on ATmega8, see atmega8 datasheet) - .umsel().usart_async() - .ucsz().chr8() - .usbs().stop1() - .upm().disabled() - ); - } - - fn raw_deinit(&mut self) { - // Wait for any ongoing transfer to finish. - avr_hal_generic::nb::block!(self.raw_flush()).ok(); - self.ucsrb.reset(); - } - - fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - if self.ucsra.read().udre().bit_is_clear() { - Err(avr_hal_generic::nb::Error::WouldBlock) - } else { - Ok(()) - } - } - - fn raw_write( - &mut self, - byte: u8, - ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - // Call flush to make sure the data-register is empty - self.raw_flush()?; - - self.udr.write(|w| w.bits(byte)); - Ok(()) - } - - fn raw_read(&mut self) -> avr_hal_generic::nb::Result { - if self.ucsra.read().rxc().bit_is_clear() { - return Err(avr_hal_generic::nb::Error::WouldBlock); - } - - Ok(self.udr.read().bits()) - } - - fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) { - match event { - crate::usart::Event::RxComplete => self.ucsrb.modify(|_, w| w.rxcie().bit(state)), - crate::usart::Event::TxComplete => self.ucsrb.modify(|_, w| w.txcie().bit(state)), - crate::usart::Event::DataRegisterEmpty => { - self.ucsrb.modify(|_, w| w.udrie().bit(state)) - } - } - } -} - -// TODO: ATmega128A USART1 is also different from other atmegas -// Mainly needed because ubrr1 is split in ubrr1h and ubrr1l -#[cfg(any(feature = "atmega128a"))] -impl - crate::usart::UsartOps< - crate::Atmega, - crate::port::Pin, - crate::port::Pin, - > for crate::pac::USART1 -{ - fn raw_init(&mut self, baudrate: crate::usart::Baudrate) { - let ubrr1h: u8 = (baudrate.ubrr >> 8) as u8; - let ubrr1l: u8 = baudrate.ubrr as u8; - self.ubrr1h.write(|w| w.bits(ubrr1h)); - self.ubrr1l.write(|w| w.bits(ubrr1l)); - self.ucsr1a.write(|w| w.u2x1().bit(baudrate.u2x)); - - // Enable receiver and transmitter but leave interrupts disabled. - #[rustfmt::skip] - self.ucsr1b.write(|w| w - .txen1().set_bit() - .rxen1().set_bit() - ); - - // Set frame format to 8n1 for now. At some point, this should be made - // configurable, similar to what is done in other HALs. - #[rustfmt::skip] - self.ucsr1c.write(|w| w - .umsel1().usart_async() - .ucsz1().chr8() - .usbs1().stop1() - .upm1().disabled() - ); - } - - fn raw_deinit(&mut self) { - // Wait for any ongoing transfer to finish. - avr_hal_generic::nb::block!(self.raw_flush()).ok(); - self.ucsr1b.reset(); - } - - fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - if self.ucsr1a.read().udre1().bit_is_clear() { - Err(avr_hal_generic::nb::Error::WouldBlock) - } else { - Ok(()) - } - } - - fn raw_write( - &mut self, - byte: u8, - ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - // Call flush to make sure the data-register is empty - self.raw_flush()?; - - self.udr1.write(|w| w.bits(byte)); - Ok(()) - } - - fn raw_read(&mut self) -> avr_hal_generic::nb::Result { - if self.ucsr1a.read().rxc1().bit_is_clear() { - return Err(avr_hal_generic::nb::Error::WouldBlock); - } - - Ok(self.udr1.read().bits()) - } - - fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) { - match event { - crate::usart::Event::RxComplete => self.ucsr1b.modify(|_, w| w.rxcie1().bit(state)), - crate::usart::Event::TxComplete => self.ucsr1b.modify(|_, w| w.txcie1().bit(state)), - crate::usart::Event::DataRegisterEmpty => { - self.ucsr1b.modify(|_, w| w.udrie1().bit(state)) - } - } - } -} - -// TODO: ATmega128A USART0 is also different from other atmegas -// Mainly needed because ubrr1 is split in ubrr1h and ubrr1l -// For USART0 they are not even close to eachother in memory -#[cfg(any(feature = "atmega128a"))] -impl - crate::usart::UsartOps< - crate::Atmega, - crate::port::Pin, - crate::port::Pin, - > for crate::pac::USART0 -{ - fn raw_init(&mut self, baudrate: crate::usart::Baudrate) { - let ubrr0h: u8 = (baudrate.ubrr >> 8) as u8; - let ubrr0l: u8 = baudrate.ubrr as u8; - self.ubrr0h.write(|w| w.bits(ubrr0h)); - self.ubrr0l.write(|w| w.bits(ubrr0l)); - self.ucsr0a.write(|w| w.u2x0().bit(baudrate.u2x)); - - // Enable receiver and transmitter but leave interrupts disabled. - self.ucsr0b.write(|w| w.txen0().set_bit().rxen0().set_bit()); - - // Set frame format to 8n1 for now. At some point, this should be made - // configurable, similar to what is done in other HALs. - #[rustfmt::skip] - self.ucsr0c.write(|w| w - .umsel0().usart_async() - .ucsz0().chr8() - .usbs0().stop1() - .upm0().disabled() - ); - } - - fn raw_deinit(&mut self) { - // Wait for any ongoing transfer to finish. - avr_hal_generic::nb::block!(self.raw_flush()).ok(); - self.ucsr0b.reset(); - } - - fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - if self.ucsr0a.read().udre0().bit_is_clear() { - Err(avr_hal_generic::nb::Error::WouldBlock) - } else { - Ok(()) - } - } - - fn raw_write( - &mut self, - byte: u8, - ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> { - // Call flush to make sure the data-register is empty - self.raw_flush()?; - - self.udr0.write(|w| w.bits(byte)); - Ok(()) - } - - fn raw_read(&mut self) -> avr_hal_generic::nb::Result { - if self.ucsr0a.read().rxc0().bit_is_clear() { - return Err(avr_hal_generic::nb::Error::WouldBlock); - } - - Ok(self.udr0.read().bits()) - } - - fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) { - match event { - crate::usart::Event::RxComplete => self.ucsr0b.modify(|_, w| w.rxcie0().bit(state)), - crate::usart::Event::TxComplete => self.ucsr0b.modify(|_, w| w.txcie0().bit(state)), - crate::usart::Event::DataRegisterEmpty => { - self.ucsr0b.modify(|_, w| w.udrie0().bit(state)) - } - } - } -} diff --git a/mcu/atmega-hal/src/wdt.rs b/mcu/atmega-hal/src/wdt.rs deleted file mode 100644 index 434189a82e..0000000000 --- a/mcu/atmega-hal/src/wdt.rs +++ /dev/null @@ -1,44 +0,0 @@ -#[allow(unused_imports)] -pub use avr_hal_generic::wdt::{Timeout, WdtOps}; - -pub type Wdt = avr_hal_generic::wdt::Wdt; - -#[cfg(not(any(feature = "atmega8", feature = "atmega32a", feature = "atmega128a")))] -avr_hal_generic::impl_wdt! { - hal: crate::Atmega, - peripheral: crate::pac::WDT, - mcusr: crate::pac::cpu::MCUSR, - wdtcsr_name: wdtcsr, - timeout: |to, w| match to { - Timeout::Ms16 => w.wdpl().cycles_2k_512k(), - Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), - Timeout::Ms64 => w.wdpl().cycles_8k(), - Timeout::Ms125 => w.wdpl().cycles_16k(), - Timeout::Ms250 => w.wdpl().cycles_32k(), - Timeout::Ms500 => w.wdpl().cycles_64k(), - Timeout::Ms1000 => w.wdpl().cycles_128k(), - Timeout::Ms2000 => w.wdpl().cycles_256k(), - Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), - Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), - }, -} - -#[cfg(any(feature = "atmega8", feature = "atmega32a", feature = "atmega128a"))] -avr_hal_generic::impl_wdt! { - hal: crate::Atmega, - peripheral: crate::pac::WDT, - mcusr: crate::pac::cpu::MCUCSR, - wdtcsr_name: wdtcr, - timeout: |to, w| match to { - Timeout::Ms16 => w.wdpl().cycles_16k(), - Timeout::Ms32 => w.wdpl().cycles_32k(), - Timeout::Ms64 => w.wdpl().cycles_64k(), - Timeout::Ms125 => w.wdpl().cycles_128k(), - Timeout::Ms250 => w.wdpl().cycles_256k(), - Timeout::Ms500 => w.wdpl().cycles_512k(), - Timeout::Ms1000 => w.wdpl().cycles_1024k(), - Timeout::Ms2000 => w.wdpl().cycles_2048k(), - Timeout::Ms4000 => panic!(), // Does not exist for ATmega8 ... - Timeout::Ms8000 => panic!() // Does not exist for ATmega8 ... - }, -} From 754560513735d46dfbac6c10e3cec24000376c6f Mon Sep 17 00:00:00 2001 From: Iris Artin Date: Mon, 30 Dec 2024 07:30:47 -0500 Subject: [PATCH 4/4] Fixed atmega doctests --- .github/workflows/ci.yml | 5 + mcu/atmega-hal/Cargo.toml | 5 + mcu/atmega-hal/src/atmega32u4.rs | 62 +++++++---- mcu/atmega-hal/src/atmega8.rs | 28 +++-- mcu/atmega-hal/src/impl/adc.rs | 61 ++++++----- mcu/atmega-hal/src/impl/eeprom.rs | 9 +- mcu/atmega-hal/src/impl/i2c.rs | 28 +++-- mcu/atmega-hal/src/impl/port.rs | 18 ++-- mcu/atmega-hal/src/impl/simple_pwm.rs | 143 +++++++++++++++++--------- mcu/atmega-hal/src/impl/spi.rs | 34 +++--- mcu/atmega-hal/src/impl/usart.rs | 27 +++-- 11 files changed, 275 insertions(+), 145 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0b0da4aa4..4115c66d54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,6 +129,11 @@ jobs: run: >- cd "mcu/${{ matrix.m.crate }}" && cargo test --doc --features "${{ matrix.m.name }}-no-deprecated-globals" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" + - name: Compile doctests for an MCU (no deprecated globals) + if: "${{ matrix.m.crate == 'atmega-hal' }}" + run: >- + cd "mcu/${{ matrix.m.crate }}" && + cargo test --doc --features "${{ matrix.m.name }}-no-deprecated-globals,enable-extra-adc" -Z build-std=core --target "../../avr-specs/avr-${{ matrix.m.spec }}.json" ravedude: name: "ravedude" diff --git a/mcu/atmega-hal/Cargo.toml b/mcu/atmega-hal/Cargo.toml index 5d19b35218..e7d24ad4ae 100644 --- a/mcu/atmega-hal/Cargo.toml +++ b/mcu/atmega-hal/Cargo.toml @@ -144,6 +144,11 @@ _peripheral-simple-pwm = [] _peripheral-spi = [] _peripheral-usart = [] +[dev-dependencies] +embedded-hal = "1.0" +ufmt = "0.2.0" +nb = "1.1.0" + [dependencies] avr-hal-generic = { path = "../../avr-hal-generic/" } diff --git a/mcu/atmega-hal/src/atmega32u4.rs b/mcu/atmega-hal/src/atmega32u4.rs index 1b305f3a5b..74ec127feb 100644 --- a/mcu/atmega-hal/src/atmega32u4.rs +++ b/mcu/atmega-hal/src/atmega32u4.rs @@ -77,14 +77,19 @@ impl_mod_simple_pwm! { /// Use `TC0` for PWM (pins `PB7`, `PD0`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega32u4 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer0); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer0); + /// let mut pb7 = pins.pb7.into_output().into_pwm(&mut timer0); + /// let mut pd0 = pins.pd0.into_output().into_pwm(&mut timer0); /// - /// d11.set_duty(128); - /// d11.enable(); + /// pb7.set_duty(128); + /// pb7.enable(); /// ``` pub struct Timer0Pwm { timer: hal::pac::TC0, @@ -124,15 +129,20 @@ impl_mod_simple_pwm! { /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega32u4 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); + /// let mut pb5 = pins.pb5.into_output().into_pwm(&mut timer1); + /// let mut pb6 = pins.pb6.into_output().into_pwm(&mut timer1); + /// let mut pb7 = pins.pb7.into_output().into_pwm(&mut timer1); /// - /// d9.set_duty(128); - /// d9.enable(); + /// pb5.set_duty(128); + /// pb5.enable(); /// ``` pub struct Timer1Pwm { timer: hal::pac::TC1, @@ -183,13 +193,18 @@ impl_mod_simple_pwm! { /// Use `TC3` for PWM (pins `PC6`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega32u4 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer3Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); + /// let mut pc6 = pins.pc6.into_output().into_pwm(&mut timer3); /// - /// d5.set_duty(128); - /// d5.enable(); + /// pc6.set_duty(128); + /// pc6.enable(); /// ``` pub struct Timer3Pwm { timer: hal::pac::TC3, @@ -222,15 +237,20 @@ impl_mod_simple_pwm! { /// Use `TC4` for PWM (pins `PB6`, `PC7`, `PD7`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega32u4 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer4Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); /// - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer4); - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer4); + /// let mut pb6 = pins.pb6.into_output().into_pwm(&mut timer4); + /// let mut pc7 = pins.pc7.into_output().into_pwm(&mut timer4); + /// let mut pd7 = pins.pd7.into_output().into_pwm(&mut timer4); /// - /// d6.set_duty(128); - /// d6.enable(); + /// pb6.set_duty(128); + /// pb6.enable(); /// ``` pub struct Timer4Pwm { timer: hal::pac::TC4, diff --git a/mcu/atmega-hal/src/atmega8.rs b/mcu/atmega-hal/src/atmega8.rs index c4ea253270..d22439898b 100644 --- a/mcu/atmega-hal/src/atmega8.rs +++ b/mcu/atmega-hal/src/atmega8.rs @@ -67,14 +67,19 @@ impl_mod_simple_pwm! { /// Use `TC1` for PWM (pins `PB1`, `PB2`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega8 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut b1 = pins.b1.into_output().into_pwm(&mut timer1); - /// let mut b2 = pins.b2.into_output().into_pwm(&mut timer1); + /// let mut pb1 = pins.pb1.into_output().into_pwm(&mut timer1); + /// let mut pb2 = pins.pb2.into_output().into_pwm(&mut timer1); /// - /// d9.set_duty(128); - /// d9.enable(); + /// pb1.set_duty(128); + /// pb1.enable(); /// ``` pub struct Timer1Pwm { timer: hal::pac::TC1, @@ -118,14 +123,17 @@ impl_mod_simple_pwm! { /// Use `TC2` for PWM (pin `PB3`) /// /// # Example - /// ``` + /// ```no_run + /// use atmega_hal::atmega8 as hal; + /// use hal::simple_pwm::{IntoPwmPin,Timer2Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); + /// let mut pb3 = pins.pb3.into_output().into_pwm(&mut timer2); /// - /// d11.set_duty(128); - /// d11.enable(); + /// pb3.set_duty(128); /// ``` pub struct Timer2Pwm { timer: hal::pac::TC2, diff --git a/mcu/atmega-hal/src/impl/adc.rs b/mcu/atmega-hal/src/impl/adc.rs index bb5982924f..7368f73a97 100644 --- a/mcu/atmega-hal/src/impl/adc.rs +++ b/mcu/atmega-hal/src/impl/adc.rs @@ -19,28 +19,49 @@ macro_rules! impl_mod_adc { pub mod adc { //! Analog-to-Digital Converter //! - //! # Example - //! - //! Complete example source code can be found in the repository: + //! For full source code, please refer to the ATmega ADC example: //! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs) //! + //! # Example: Read pins using `analog_read()` + //! + //! ```no_run + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); + //! + //! let mut adc = hal::Adc::::new(dp.ADC, Default::default()); + //! + $( + #![doc = paste!{ concat!( + "let ", stringify!([< input_ $pin_name:lower >]), " = pins.", stringify!([< $pin_name:lower >]), ".into_analog_input(&mut adc);\n", + "let ", stringify!([< value_ $pin_name:lower >]), " = ", stringify!([< input_ $pin_name:lower >]), ".analog_read(&mut adc);\n\n" + )}] + )* //! ``` - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let pins = atmega_hal::pins!(dp); //! - //! let mut adc = Adc::new(dp.ADC, Default::default()); + //! # Example: Read channels (including pins) using `read_blocking()` + //! + //! ```no_run + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] //! - //! let channels: [atmega_hal::adc::Channel; 4] = [ - //! pins.pf0.into_analog_input(&mut adc).into_channel(), - //! pins.pf1.into_analog_input(&mut adc).into_channel(), - //! pins.pf2.into_analog_input(&mut adc).into_channel(), - //! pins.pf3.into_analog_input(&mut adc).into_channel(), - //! ]; + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! for (index, channel) in channels.iter().enumerate() { - //! let value = adc.read_blocking(channel); - //! ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap(); - //! } + //! let mut adc = hal::Adc::::new(dp.ADC, Default::default()); + //! + //! // + $( + #![doc = paste!{ concat!( + "let ", stringify!([< channel_ $pin_name:lower >]), " = pins.", stringify!([< $pin_name:lower >]), ".into_analog_input(&mut adc).into_channel();\n", + "let ", stringify!([< value_ $pin_name:lower >]), " = adc.read_blocking(&", stringify!([< channel_ $pin_name:lower >]), ");\n\n" + ) }] + )* + $( + #![doc = paste!{ concat!( + "let ", stringify!([< value_ $channel_name:lower >]), " = adc.read_blocking(&hal::adc::channel::", stringify!([< $channel_name >]), ");\n\n" + ) }] + )* //! ``` use avr_hal_generic::paste::paste; @@ -53,14 +74,6 @@ macro_rules! impl_mod_adc { /// /// Some channels are not directly connected to pins. This module provides types which can be used /// to access them. - /// - /// # Example - /// ``` - /// let dp = atmega_hal::Peripherals::take().unwrap(); - /// let mut adc = atmega_hal::Adc::new(dp.ADC, Default::default()); - /// - /// let value = adc.read_blocking(&channel::Vbg); - /// ``` #[allow(non_camel_case_types)] pub mod channel { $( diff --git a/mcu/atmega-hal/src/impl/eeprom.rs b/mcu/atmega-hal/src/impl/eeprom.rs index 234af3eadc..4f8327874a 100644 --- a/mcu/atmega-hal/src/impl/eeprom.rs +++ b/mcu/atmega-hal/src/impl/eeprom.rs @@ -16,17 +16,18 @@ macro_rules! impl_mod_eeprom { //! Complete example source code can be found in the repository: //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) //! - //! ``` + //! ```no_run + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] //! const BOOT_COUNT_OFFSET: u16 = 0; //! - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let mut eeprom = Eeprom::new(dp.EEPROM); + //! let dp = hal::Peripherals::take().unwrap(); + //! let mut eeprom = hal::Eeprom::new(dp.EEPROM); //! //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); //! boot_count = boot_count.wrapping_add(1); //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); //! - //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); + //! // ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); //! ``` pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; diff --git a/mcu/atmega-hal/src/impl/i2c.rs b/mcu/atmega-hal/src/impl/i2c.rs index 258e3d238f..e02146a031 100644 --- a/mcu/atmega-hal/src/impl/i2c.rs +++ b/mcu/atmega-hal/src/impl/i2c.rs @@ -17,21 +17,29 @@ macro_rules! impl_mod_i2c { //! Complete example source code can be found in the repository: //! [`atmega2560-i2cdetect.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs) //! - //! ``` - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let pins = atmega_hal::pins!(dp); + //! ```no_run + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! let mut i2c = I2c::new( - //! dp.TWI, - //! pins.pd1.into_pull_up_input(), - //! pins.pd0.into_pull_up_input(), - //! 50_000, - //! ); + //! type Clock = avr_hal_generic::clock::MHz16; + $( + #![doc = paste!{ concat!( + "let mut i2c = hal::i2c::", stringify!($interface), "::::new(\n", + " dp.", stringify!($peripheral), ",\n", + " pins.", stringify!([< $sda:lower >]), ".into_pull_up_input(),\n", + " pins.", stringify!([< $scl:lower >]), ".into_pull_up_input(),\n", + " 50_000,\n", + ");\n", + ) }] + )+ //! - //! i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read).unwrap(); + //! // i2c.i2cdetect(&mut serial, hal::i2c::Direction::Read).unwrap(); //! ``` pub use avr_hal_generic::i2c::*; + use avr_hal_generic::paste::paste; use crate::$hal as hal; $( diff --git a/mcu/atmega-hal/src/impl/port.rs b/mcu/atmega-hal/src/impl/port.rs index 2b3f0a105a..70634716f5 100644 --- a/mcu/atmega-hal/src/impl/port.rs +++ b/mcu/atmega-hal/src/impl/port.rs @@ -7,18 +7,24 @@ macro_rules! impl_mod_port { //! //! # Example //! - //! Complete example source code can be found in the repository: + //! For full source code, please refer to the ATmega port example: //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) //! - //! ``` - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let pins = atmega_hal::pins!(dp); + //! ```no_run + //! use atmega_hal::prelude::*; + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + //! + //! type Clock = atmega_hal::clock::MHz8; + //! let mut delay = atmega_hal::delay::Delay::::new(); + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! let mut led = pins.pb7.into_output(); + //! let mut led = pins.pb2.into_output(); //! //! loop { //! led.toggle(); - //! delay_ms(1000); + //! delay.delay_ms(1000u16); //! } //! ``` pub use avr_hal_generic::port::{mode, PinMode, PinOps}; diff --git a/mcu/atmega-hal/src/impl/simple_pwm.rs b/mcu/atmega-hal/src/impl/simple_pwm.rs index cf2caf9c2d..28ee56819f 100644 --- a/mcu/atmega-hal/src/impl/simple_pwm.rs +++ b/mcu/atmega-hal/src/impl/simple_pwm.rs @@ -40,14 +40,19 @@ macro_rules! impl_simple_pwm_48p_168_328p_328pb { /// Use `TC0` for PWM (pins `PD5`, `PD6`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer0); - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer0); + /// let mut pd5 = pins.pd5.into_output().into_pwm(&mut timer0); + /// let mut pd6 = pins.pd6.into_output().into_pwm(&mut timer0); /// - /// d5.set_duty(128); - /// d5.enable(); + /// pd5.set_duty(128); + /// pd5.enable(); /// ``` pub struct Timer0Pwm { timer: hal::pac::TC0, @@ -87,14 +92,19 @@ macro_rules! impl_simple_pwm_48p_168_328p_328pb { /// Use `TC1` for PWM (pins `PB1`, `PB2`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer1); - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer1); + /// let mut pb1 = pins.pb1.into_output().into_pwm(&mut timer1); + /// let mut pb2 = pins.pb2.into_output().into_pwm(&mut timer1); /// - /// d9.set_duty(128); - /// d9.enable(); + /// pb1.set_duty(128); + /// pb1.enable(); /// ``` pub struct Timer1Pwm { timer: hal::pac::TC1, @@ -138,14 +148,19 @@ macro_rules! impl_simple_pwm_48p_168_328p_328pb { /// Use `TC2` for PWM (pins `PB3`, `PD3`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer2Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer2); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer2); + /// let mut pb3 = pins.pb3.into_output().into_pwm(&mut timer2); + /// let mut pd3 = pins.pd3.into_output().into_pwm(&mut timer2); /// - /// d11.set_duty(128); - /// d11.enable(); + /// pb3.set_duty(128); + /// pb3.enable(); /// ``` pub struct Timer2Pwm { timer: hal::pac::TC2, @@ -192,14 +207,19 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC0` for PWM (pins `PB7`, `PG5`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer0Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); /// - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer0); - /// let mut d4 = pins.d4.into_output().into_pwm(&mut timer0); + /// let mut pb7 = pins.pb7.into_output().into_pwm(&mut timer0); + /// let mut pg5 = pins.pg5.into_output().into_pwm(&mut timer0); /// - /// d13.set_duty(128); - /// d13.enable(); + /// pb7.set_duty(128); + /// pb7.enable(); /// ``` pub struct Timer0Pwm { timer: hal::pac::TC0, @@ -239,15 +259,20 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC1` for PWM (pins `PB5`, `PB6`, `PB7`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer1Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer1 = Timer1Pwm::new(dp.TC1, Prescaler::Prescale64); /// - /// let mut d11 = pins.d11.into_output().into_pwm(&mut timer1); - /// let mut d12 = pins.d12.into_output().into_pwm(&mut timer1); - /// let mut d13 = pins.d13.into_output().into_pwm(&mut timer1); + /// let mut pb5 = pins.pb5.into_output().into_pwm(&mut timer1); + /// let mut pb6 = pins.pb6.into_output().into_pwm(&mut timer1); + /// let mut pb7 = pins.pb7.into_output().into_pwm(&mut timer1); /// - /// d11.set_duty(128); - /// d11.enable(); + /// pb5.set_duty(128); + /// pb5.enable(); /// ``` pub struct Timer1Pwm { timer: hal::pac::TC1, @@ -296,14 +321,19 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC2` for PWM (pins `PB4`, `PH6`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer2Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer2 = Timer2Pwm::new(dp.TC2, Prescaler::Prescale64); /// - /// let mut d10 = pins.d10.into_output().into_pwm(&mut timer2); - /// let mut d9 = pins.d9.into_output().into_pwm(&mut timer2); + /// let mut pb4 = pins.pb4.into_output().into_pwm(&mut timer2); + /// let mut ph6 = pins.ph6.into_output().into_pwm(&mut timer2); /// - /// d10.set_duty(128); - /// d10.enable(); + /// pb4.set_duty(128); + /// pb4.enable(); /// ``` pub struct Timer2Pwm { @@ -348,15 +378,20 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC3` for PWM (pins `PE3`, `PE4`, `PE5`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer3Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer3 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); /// - /// let mut d5 = pins.d5.into_output().into_pwm(&mut timer3); - /// let mut d2 = pins.d2.into_output().into_pwm(&mut timer3); - /// let mut d3 = pins.d3.into_output().into_pwm(&mut timer3); + /// let mut pe3 = pins.pe3.into_output().into_pwm(&mut timer3); + /// let mut pe4 = pins.pe4.into_output().into_pwm(&mut timer3); + /// let mut pe5 = pins.pe5.into_output().into_pwm(&mut timer3); /// - /// d5.set_duty(128); - /// d5.enable(); + /// pe3.set_duty(128); + /// pe3.enable(); /// ``` pub struct Timer3Pwm { timer: hal::pac::TC3, @@ -410,15 +445,20 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC4` for PWM (pins `PH3`, `PH4`, `PH5`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer4Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer4 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); /// - /// let mut d6 = pins.d6.into_output().into_pwm(&mut timer4); - /// let mut d7 = pins.d7.into_output().into_pwm(&mut timer4); - /// let mut d8 = pins.d8.into_output().into_pwm(&mut timer4); + /// let mut ph3 = pins.ph3.into_output().into_pwm(&mut timer4); + /// let mut ph4 = pins.ph4.into_output().into_pwm(&mut timer4); + /// let mut ph5 = pins.ph5.into_output().into_pwm(&mut timer4); /// - /// d6.set_duty(128); - /// d6.enable(); + /// ph3.set_duty(128); + /// ph3.enable(); /// ``` pub struct Timer4Pwm { timer: hal::pac::TC4, @@ -472,15 +512,20 @@ macro_rules! impl_simple_pwm_1280_2560 { /// Use `TC5` for PWM (pins `PL3`, `PL4`, `PL5`) /// /// # Example - /// ``` + /// ```no_run + #[doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + /// use hal::simple_pwm::{IntoPwmPin,Timer5Pwm,Prescaler}; + /// + /// let dp = hal::Peripherals::take().unwrap(); + /// let pins = hal::pins!(dp); /// let mut timer5 = Timer5Pwm::new(dp.TC5, Prescaler::Prescale64); /// - /// let mut d46 = pins.d46.into_output().into_pwm(&mut timer5); - /// let mut d45 = pins.d45.into_output().into_pwm(&mut timer5); - /// let mut d44 = pins.d44.into_output().into_pwm(&mut timer5); + /// let mut pl3 = pins.pl3.into_output().into_pwm(&mut timer5); + /// let mut pl4 = pins.pl4.into_output().into_pwm(&mut timer5); + /// let mut pl5 = pins.pl5.into_output().into_pwm(&mut timer5); /// - /// d46.set_duty(128); - /// d46.enable(); + /// pl3.set_duty(128); + /// pl3.enable(); /// ``` pub struct Timer5Pwm { timer: hal::pac::TC5, diff --git a/mcu/atmega-hal/src/impl/spi.rs b/mcu/atmega-hal/src/impl/spi.rs index 42e3d4718d..b3ddc8712e 100644 --- a/mcu/atmega-hal/src/impl/spi.rs +++ b/mcu/atmega-hal/src/impl/spi.rs @@ -21,18 +21,27 @@ macro_rules! impl_mod_spi { //! Complete example source code can be found in the repository //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) //! - //! ``` - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let pins = atmega_hal::pins!(dp); + //! ```no_run + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + //! + //! use embedded_hal::digital::OutputPin; + //! use embedded_hal::spi::SpiBus; + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); //! - //! let (mut spi, mut cs) = spi::Spi::new( - //! dp.SPI, - //! pins.pb1.into_output(), - //! pins.pb2.into_output(), - //! pins.pb3.into_pull_up_input(), - //! pins.pb0.into_output(), - //! spi::Settings::default(), - //! ); + $( + #![doc = paste!{ concat!( + "let (mut spi, mut cs) = hal::spi::", stringify!($interface), "::new(\n", + " dp.", stringify!($peripheral), ",\n", + " pins.", stringify!([< $sclk:lower >]), ".into_output(),\n", + " pins.", stringify!([< $mosi:lower >]), ".into_output(),\n", + " pins.", stringify!([< $miso:lower >]), ".into_pull_up_input(),\n", + " pins.", stringify!([< $cs:lower >]), ".into_output(),\n", + " hal::spi::Settings::default(),\n", + ");\n", + ) }] + )+ //! //! let data_out = b"Hello World!"; //! let mut data_in = [0u8; 12]; @@ -41,10 +50,11 @@ macro_rules! impl_mod_spi { //! spi.transfer(&mut data_in, data_out).unwrap(); //! cs.set_high().unwrap(); //! - //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); + //! // ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); //! ``` pub use avr_hal_generic::spi::*; + use avr_hal_generic::paste::paste; use crate::$hal as hal; $( diff --git a/mcu/atmega-hal/src/impl/usart.rs b/mcu/atmega-hal/src/impl/usart.rs index 03adf7be51..c18801c394 100644 --- a/mcu/atmega-hal/src/impl/usart.rs +++ b/mcu/atmega-hal/src/impl/usart.rs @@ -25,16 +25,25 @@ macro_rules! impl_mod_usart { //! *Note: [ufmt](https://crates.io/crates/ufmt/) is used instead of `core::fmt` because //! `core::fmt` code quickly grows too large for AVR platforms.* //! - //! ``` - //! let dp = atmega_hal::Peripherals::take().unwrap(); - //! let pins = atmega_hal::pins!(dp); + //! ```no_run + //! use atmega_hal::prelude::*; + #![doc = concat!("use atmega_hal::", stringify!($hal), " as hal;")] + //! + //! let dp = hal::Peripherals::take().unwrap(); + //! let pins = hal::pins!(dp); + //! //! - //! let mut serial = Usart::new( - //! dp.USART0, - //! pins.pe0, - //! pins.pe1.into_output(), - //! Baudrate::::new(57600), - //! ); + //! type Clock = avr_hal_generic::clock::MHz16; + $( + #![doc = paste!{ concat!( + "let mut serial = hal::usart::", stringify!($interface), "::new(\n", + " dp.", stringify!($peripheral), ",\n", + " pins.", stringify!([< $rx:lower >]), ",\n", + " pins.", stringify!([< $tx:lower >]), ".into_output(),\n", + " hal::usart::Baudrate::::new(57600),\n", + ");\n", + ) }] + )+ //! //! ufmt::uwriteln!(&mut serial, "Hello from ATmega!").unwrap(); //!