├── keyboard-hal ├── src │ ├── port │ │ ├── mod.rs │ │ └── pcb1.rs │ ├── keyboard_config.rs │ ├── matrix.rs │ ├── usb_keyboard.rs │ └── keycodes.rs ├── README.md └── Cargo.toml ├── ravedude ├── .gitignore ├── rust-toolchain.toml ├── flake.nix ├── Cargo.toml ├── src │ ├── ui.rs │ ├── console.rs │ └── board.rs ├── flake.lock └── README.md ├── .gitignore ├── rust-toolchain.toml ├── examples ├── trinket │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── trinket-blink.rs │ │ │ └── trinket-simple-pwm.rs │ └── Cargo.toml ├── trinket-pro │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ └── trinket-pro-blink.rs │ └── Cargo.toml ├── arduino-diecimila │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── diecimila-blink.rs │ │ │ ├── diecimila-usart.rs │ │ │ ├── diecimila-i2cdetect.rs │ │ │ ├── diecimila-adc.rs │ │ │ └── diecimila-spi-feedback.rs │ └── Cargo.toml ├── arduino-leonardo │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── leonardo-usart.rs │ │ │ ├── leonardo-blink.rs │ │ │ ├── leonardo-i2cdetect.rs │ │ │ ├── leonardo-spi-feedback.rs │ │ │ └── leonardo-adc.rs │ └── Cargo.toml ├── arduino-nano │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── nano-blink.rs │ │ │ ├── nano-adc.rs │ │ │ └── nano-panic.rs │ └── Cargo.toml ├── nano168 │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── nano168-blink.rs │ │ │ ├── nano168-usart.rs │ │ │ ├── nano168-i2cdetect.rs │ │ │ ├── nano168-watchdog.rs │ │ │ ├── nano168-adc.rs │ │ │ ├── nano168-ldr.rs │ │ │ └── nano168-millis.rs │ └── Cargo.toml ├── sparkfun-promicro │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── promicro-blink.rs │ │ │ ├── promicro-usart.rs │ │ │ ├── promicro-i2cdetect.rs │ │ │ ├── promicro-adc.rs │ │ │ └── promicro-spi-feedback.rs │ └── Cargo.toml ├── atmega2560 │ ├── .cargo │ │ └── config.toml │ ├── README.md │ ├── src │ │ └── bin │ │ │ ├── atmega2560-blink.rs │ │ │ ├── atmega2560-usart.rs │ │ │ ├── atmega2560-eeprom.rs │ │ │ ├── atmega2560-i2cdetect.rs │ │ │ ├── atmega2560-spi-feedback.rs │ │ │ └── atmega2560-adc.rs │ └── Cargo.toml ├── sparkfun-promini-3v3 │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ └── promini-3v3-blink.rs │ └── Cargo.toml ├── sparkfun-promini-5v │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ └── promini-5v-blink.rs │ └── Cargo.toml ├── arduino-mega1280 │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── mega1280-blink.rs │ │ │ ├── mega1280-usart.rs │ │ │ ├── mega1280-i2cdetect.rs │ │ │ ├── mega1280spi-feedback.rs │ │ │ └── mega1280-adc.rs │ ├── README.md │ └── Cargo.toml ├── arduino-mega2560 │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── mega2560-blink.rs │ │ │ ├── mega2560-usart.rs │ │ │ ├── mega2560-i2cdetect.rs │ │ │ ├── mega2560-spi-feedback.rs │ │ │ ├── mega2560-rgb-led.rs │ │ │ └── mega2560-adc.rs │ └── Cargo.toml ├── keyboard-dz60 │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ └── simple.rs │ └── Cargo.toml ├── arduino-uno │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── bin │ │ │ ├── uno-blink.rs │ │ │ ├── uno-simple-pwm.rs │ │ │ ├── uno-usart.rs │ │ │ ├── uno-watchdog.rs │ │ │ ├── uno-blink-embedded-hal.rs │ │ │ ├── uno-simple-pwm-embedded-hal.rs │ │ │ ├── uno-eeprom.rs │ │ │ ├── uno-i2cdetect.rs │ │ │ ├── uno-manual-servo.rs │ │ │ ├── uno-spi-feedback.rs │ │ │ ├── uno-74hc595.rs │ │ │ ├── uno-println.rs │ │ │ ├── uno-ext-interrupt.rs │ │ │ ├── uno-adc.rs │ │ │ ├── uno-16chan-servo-driver.rs │ │ │ ├── uno-pin-change-interrupt.rs │ │ │ ├── uno-panic.rs │ │ │ ├── uno-millis.rs │ │ │ └── uno-hc-sr04.rs │ └── Cargo.toml └── README.md ├── .github ├── dependabot.yml └── workflows │ └── docs.yml ├── CHANGELOG.md ├── arduino-hal ├── src │ ├── port │ │ ├── trinket.rs │ │ ├── mod.rs │ │ └── promicro.rs │ ├── delay.rs │ └── clock.rs └── Cargo.toml ├── avr-hal-generic ├── Cargo.toml └── src │ ├── lib.rs │ └── clock.rs ├── avr-specs ├── avr-atmega8.json ├── avr-atmega168.json ├── avr-atmega328.json ├── avr-atmega32a.json ├── avr-atmega48p.json ├── avr-attiny167.json ├── avr-attiny85.json ├── avr-attiny88.json ├── avr-atmega1280.json ├── avr-atmega128a.json ├── avr-atmega2560.json ├── avr-atmega328p.json ├── avr-atmega32u4.json ├── avr-attiny2313.json ├── avr-atmega1284p.json ├── avr-atmega164pa.json └── sync-from-upstream.py ├── Cargo.toml ├── LICENSE-MIT └── mcu ├── attiny-hal ├── Cargo.toml └── src │ ├── eeprom.rs │ ├── port.rs │ ├── wdt.rs │ ├── spi.rs │ └── lib.rs └── atmega-hal ├── src ├── wdt.rs ├── eeprom.rs ├── spi.rs ├── i2c.rs └── port.rs └── Cargo.toml /keyboard-hal/src/port/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod pcb1; 2 | -------------------------------------------------------------------------------- /ravedude/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | !Cargo.lock 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | /target 3 | **/*.rs.bk 4 | 5 | # IDEs 6 | .vscode 7 | .idea 8 | -------------------------------------------------------------------------------- /ravedude/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | profile = "minimal" 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2024-03-22" 3 | components = [ "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /keyboard-hal/src/keyboard_config.rs: -------------------------------------------------------------------------------- 1 | pub const MATRIX_ROWS: usize = 5; 2 | pub const MATRIX_COLS: usize = 15; 3 | pub const NUM_LAYERS: usize = 3; 4 | -------------------------------------------------------------------------------- /examples/trinket/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-attiny85.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude trinket" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/trinket-pro/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega328p.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude trinket-pro" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega168.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude diecimila" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega32u4.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude leonardo" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/arduino-nano/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega328p.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude nano -cb 57600" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/nano168/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega168.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude nano168 -cb 57600" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega32u4.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude promicro" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/atmega2560/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega2560.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude -cb 57600 mega2560" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-3v3/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega328p.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude promini-3v3" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-5v/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega328p.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude promini-5v" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega1280.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude -cb 57600 mega1280" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega2560.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude -cb 57600 mega2560" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | -------------------------------------------------------------------------------- /examples/keyboard-dz60/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega32u4.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude keyboard" 6 | 7 | [unstable] 8 | build-std = ["core"] 9 | 10 | -------------------------------------------------------------------------------- /examples/atmega2560/README.md: -------------------------------------------------------------------------------- 1 | # ATmega2560 Examples 2 | 3 | This directory includes examples of using plain `atmega-hal`, rather than the `hal` targeted at Arduino boards. 4 | 5 | The examples can be run and have been tested on the Arduino Mega2560 board. 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "cargo" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /examples/arduino-uno/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "../../avr-specs/avr-atmega328p.json" 3 | 4 | [target.'cfg(target_arch = "avr")'] 5 | runner = "ravedude uno -cb 57600" 6 | # To run in simulator, replace the line above with this: 7 | # runner = "simavr -m atmega328p" 8 | 9 | [unstable] 10 | build-std = ["core"] 11 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/src/bin/diecimila-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | let mut led = pins.d13.into_output().downgrade(); 12 | 13 | loop { 14 | led.toggle(); 15 | arduino_hal::delay_ms(1000); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/src/bin/mega1280-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | let mut led = pins.d13.into_output().downgrade(); 12 | 13 | loop { 14 | led.toggle(); 15 | arduino_hal::delay_ms(1000); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | let mut led = pins.d13.into_output().downgrade(); 12 | 13 | loop { 14 | led.toggle(); 15 | arduino_hal::delay_ms(1000); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /keyboard-hal/README.md: -------------------------------------------------------------------------------- 1 | # keyboard-hal 2 | 3 | Building: 4 | 5 | ```shell 6 | cd examples/keyboard-dz60 7 | cargo build --release 8 | cd - 9 | avr-objcopy -O ihex -R .eeprom target/avr-atmega32u4/release/simple.elf dz60.hex 10 | ``` 11 | 12 | Connect the keyboard and press reset. Then on macOS: 13 | 14 | ```shell 15 | dfu-programmer erase --force 16 | dfu-programmer atmega32u4 flash dz60.hex 17 | dfu-programmer atmega32u4 reset 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/README.md: -------------------------------------------------------------------------------- 1 | 2 | The `Mega1280` board cannot be auto-detected by ravedude, you need to specify the port explicitly. 3 | 4 | This can be done in two ways: 5 | 6 | * Add the `-P` flag to the ravedude invocation such as in the `.cargo/config.toml`, for example: 7 | ```toml 8 | runner = "ravedude -P /dev/ttyUSB0 -cb 57600 mega1280" 9 | ``` 10 | 11 | * Set the `RAVEDUDE_PORT` environment variable, for example: 12 | ```bash 13 | RAVEDUDE_PORT=/dev/ttyUSB0 cargo run --bin mega1280-i2cdetect 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/keyboard-dz60/src/bin/simple.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use keyboard_hal::{pins, usb_bus, Keyboard, UsbBus, UsbBusAllocator}; 5 | use panic_halt as _; 6 | 7 | #[keyboard_hal::entry] 8 | fn main() -> ! { 9 | let dp = keyboard_hal::Peripherals::take().unwrap(); 10 | let pins = pins!(dp); 11 | 12 | // Get the USB bus via our macro 13 | let usb_bus = usb_bus!(dp); 14 | 15 | // Create our keyboard instance 16 | let mut keyboard = Keyboard::new(pins, usb_bus); 17 | 18 | loop { 19 | keyboard.poll(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## Unreleased 9 | In the past, changes were not really tracked in a human-readable changelog 10 | beyond the commit-log. For some time, however, there was somewhat of a 11 | changelog, see here: 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/src/bin/promicro-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | let mut led1 = pins.led_rx.into_output(); 12 | let mut led2 = pins.led_tx.into_output(); 13 | 14 | loop { 15 | led1.set_high(); 16 | led2.set_low(); 17 | arduino_hal::delay_ms(300); 18 | led1.set_low(); 19 | led2.set_high(); 20 | arduino_hal::delay_ms(300); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/arduino-nano/src/bin/nano-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 13 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d13.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 13 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d13.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/trinket/src/bin/trinket-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 1 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d1.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/trinket-pro/src/bin/trinket-pro-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 13 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d13.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-3v3/src/bin/promini-3v3-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 13 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d13.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-5v/src/bin/promini-5v-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | // Digital pin 13 is also connected to an onboard LED marked "L" 12 | let mut led = pins.d13.into_output(); 13 | led.set_high(); 14 | 15 | loop { 16 | led.toggle(); 17 | arduino_hal::delay_ms(100); 18 | led.toggle(); 19 | arduino_hal::delay_ms(100); 20 | led.toggle(); 21 | arduino_hal::delay_ms(100); 22 | led.toggle(); 23 | arduino_hal::delay_ms(800); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /arduino-hal/src/port/trinket.rs: -------------------------------------------------------------------------------- 1 | pub use attiny_hal::port::{mode, Pin, PinMode, PinOps}; 2 | 3 | avr_hal_generic::renamed_pins! { 4 | pub struct Pins { 5 | /// `#0`: `PB0`, `DI`(SPI), `SDA`(I2C) 6 | pub d0: attiny_hal::port::PB0 = pb0, 7 | /// `#1`: `PB1`, `DO`(SPI), Builtin LED 8 | pub d1: attiny_hal::port::PB1 = pb1, 9 | /// `#2`: `PB2`, `SCK`(SPI), `SCL`(I2C) 10 | pub d2: attiny_hal::port::PB2 = pb2, 11 | /// `#3`: `PB3` 12 | pub d3: attiny_hal::port::PB3 = pb3, 13 | /// `#4`: `PB4` 14 | pub d4: attiny_hal::port::PB4 = pb4, 15 | } 16 | 17 | impl Pins { 18 | type Pin = Pin; 19 | type McuPins = attiny_hal::Pins; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/trinket/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "trinket-examples" 3 | version = "0.0.0" 4 | authors = ["Jan Paw "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | embedded-hal = "1.0" 11 | 12 | [dependencies.embedded-hal-v0] 13 | version = "0.2.3" 14 | package = "embedded-hal" 15 | 16 | [dependencies.arduino-hal] 17 | path = "../../arduino-hal/" 18 | features = ["trinket"] 19 | 20 | # The latest releases of `proc-macro2` do not support the rust toolchain that 21 | # we use. Thus, we must fix this dependency to an older version where our 22 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 23 | [build-dependencies.proc-macro2] 24 | version = "=1.0.79" 25 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/src/bin/leonardo-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/src/bin/mega1280-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/src/bin/promicro-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/trinket-pro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "trinket-pro-examples" 3 | version = "0.0.0" 4 | authors = ["Gaute Hope "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | embedded-hal = "1.0" 11 | 12 | [dependencies.embedded-hal-v0] 13 | version = "0.2.3" 14 | package = "embedded-hal" 15 | 16 | [dependencies.arduino-hal] 17 | path = "../../arduino-hal/" 18 | features = ["trinket-pro"] 19 | 20 | # The latest releases of `proc-macro2` do not support the rust toolchain that 21 | # we use. Thus, we must fix this dependency to an older version where our 22 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 23 | [build-dependencies.proc-macro2] 24 | version = "=1.0.79" 25 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/src/bin/diecimila-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use embedded_hal_v0::serial::Read; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 16 | 17 | loop { 18 | // Read a byte from the serial connection default 19 | let b = nb::block!(serial.read()).unwrap_infallible(); 20 | 21 | // Answer 22 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/keyboard-dz60/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keyboard-dz60" 3 | version = "0.0.0" 4 | authors = ["Felipe Coury "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.keyboard-hal] 19 | path = "../../keyboard-hal/" 20 | 21 | # The latest releases of `proc-macro2` do not support the rust toolchain that 22 | # we use. Thus, we must fix this dependency to an older version where our 23 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 24 | [build-dependencies.proc-macro2] 25 | version = "=1.0.79" 26 | 27 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | `avr-hal` examples 2 | ================== 3 | The subdirectories here contain various examples which demonstrate how to write 4 | firmware using `avr-hal`. Please note that often examples for a different 5 | board can be easily ported to other hardware, so if you can't find something 6 | for your board, look for examples with other hardware as well. 7 | 8 | All examples are ready to use if you have the respective board available. Just 9 | switch to the subdirectory and run an example via cargo. For example: 10 | 11 | ```bash 12 | cd examples/arduino-uno 13 | 14 | # Build and run it on a connected board 15 | cargo run --bin uno-blink 16 | ``` 17 | 18 | You need to install [`ravedude`](https://crates.io/crates/ravedude) with `cargo install ravedude` to make 19 | this work. -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-blink.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Blink the builtin LED - the "Hello World" of embedded programming. 3 | */ 4 | #![no_std] 5 | #![no_main] 6 | 7 | use panic_halt as _; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | 14 | // Digital pin 13 is also connected to an onboard LED marked "L" 15 | let mut led = pins.d13.into_output(); 16 | led.set_high(); 17 | 18 | loop { 19 | led.toggle(); 20 | arduino_hal::delay_ms(100); 21 | led.toggle(); 22 | arduino_hal::delay_ms(100); 23 | led.toggle(); 24 | arduino_hal::delay_ms(100); 25 | led.toggle(); 26 | arduino_hal::delay_ms(800); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-leonardo-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["arduino-leonardo"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-mega1280-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["arduino-mega1280"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-mega2560-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["arduino-mega2560"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-diecimila-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["arduino-diecimila"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-simple-pwm.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of using simple_pwm to fade a LED in and out on pin d5. 3 | */ 4 | #![no_std] 5 | #![no_main] 6 | 7 | use arduino_hal::simple_pwm::*; 8 | use panic_halt as _; 9 | 10 | #[arduino_hal::entry] 11 | fn main() -> ! { 12 | let dp = arduino_hal::Peripherals::take().unwrap(); 13 | let pins = arduino_hal::pins!(dp); 14 | 15 | let timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); 16 | 17 | // Digital pin 5 is connected to a LED and a resistor in series 18 | let mut pwm_led = pins.d5.into_output().into_pwm(&timer0); 19 | pwm_led.enable(); 20 | 21 | loop { 22 | for x in (0..=255).chain((0..=254).rev()) { 23 | pwm_led.set_duty(x); 24 | arduino_hal::delay_ms(10); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sparkfun-promicro-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["sparkfun-promicro"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-5v/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sparkfun-promini-5v-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["sparkfun-promini-5v"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/sparkfun-promini-3v3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sparkfun-promini-3v3-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["sparkfun-promini-3v3"] 21 | 22 | # The latest releases of `proc-macro2` do not support the rust toolchain that 23 | # we use. Thus, we must fix this dependency to an older version where our 24 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 25 | [build-dependencies.proc-macro2] 26 | version = "=1.0.79" 27 | -------------------------------------------------------------------------------- /examples/trinket/src/bin/trinket-simple-pwm.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of using simple_pwm to fade the built-in LED in and out. 3 | */ 4 | 5 | #![no_std] 6 | #![no_main] 7 | 8 | use arduino_hal::simple_pwm::*; 9 | use panic_halt as _; 10 | 11 | #[arduino_hal::entry] 12 | fn main() -> ! { 13 | let dp = arduino_hal::Peripherals::take().unwrap(); 14 | let pins = arduino_hal::pins!(dp); 15 | 16 | let timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); 17 | 18 | // Digital pin 1 is also connected to an onboard LED marked "L" 19 | let mut pwm_led = pins.d1.into_output().into_pwm(&timer0); 20 | pwm_led.enable(); 21 | 22 | loop { 23 | for x in (0..=255).chain((0..=254).rev()) { 24 | pwm_led.set_duty(x); 25 | arduino_hal::delay_ms(10); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ravedude/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | utils = { 4 | url = "github:numtide/flake-utils"; 5 | }; 6 | 7 | naersk = { 8 | url = "github:nix-community/naersk"; 9 | }; 10 | }; 11 | 12 | outputs = { self, nixpkgs, utils, naersk }: 13 | utils.lib.eachDefaultSystem (system: 14 | let 15 | pkgs = import nixpkgs { 16 | inherit system; 17 | }; 18 | 19 | naersk' = pkgs.callPackage naersk {}; 20 | 21 | lib = pkgs.lib; 22 | 23 | in 24 | rec { 25 | packages.default = naersk'.buildPackage { 26 | pname = "ravedude"; 27 | src = ./.; 28 | 29 | buildInputs = with pkgs; lib.optionals pkgs.stdenv.isLinux [ 30 | pkg-config 31 | udev 32 | ]; 33 | }; 34 | } 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-usart.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Demonstration of writing to and reading from the serial console. 3 | */ 4 | #![no_std] 5 | #![no_main] 6 | 7 | use arduino_hal::prelude::*; 8 | use panic_halt as _; 9 | 10 | use embedded_hal_v0::serial::Read; 11 | 12 | #[arduino_hal::entry] 13 | fn main() -> ! { 14 | let dp = arduino_hal::Peripherals::take().unwrap(); 15 | let pins = arduino_hal::pins!(dp); 16 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 17 | 18 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 19 | 20 | loop { 21 | // Read a byte from the serial connection 22 | let b = nb::block!(serial.read()).unwrap_infallible(); 23 | 24 | // Answer 25 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ravedude/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ravedude" 3 | version = "0.1.8" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | description = "Tool to easily flash code onto an AVR microcontroller with avrdude" 7 | readme = "README.md" 8 | repository = "https://github.com/Rahix/avr-hal/tree/main/ravedude" 9 | license = "MIT OR Apache-2.0" 10 | keywords = ["avr", "arduino", "avrdude"] 11 | categories = ["embedded", "hardware-support", "development-tools"] 12 | 13 | [dependencies] 14 | colored = "2.0.0" 15 | tempfile = "3.2.0" 16 | serialport = "4.0.0" 17 | anyhow = "1.0.38" 18 | git-version = "0.3.4" 19 | ctrlc = "3.2.1" 20 | serde = { version = "1.0.197", features = ["serde_derive"] } 21 | toml = "0.8.11" 22 | either = "1.10.0" 23 | 24 | [dependencies.structopt] 25 | version = "0.3.21" 26 | default-features = false 27 | features = ["color"] 28 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use embedded_hal::delay::DelayNs; 5 | use panic_halt as _; 6 | 7 | // Define core clock. This can be used in the rest of the project. 8 | type CoreClock = atmega_hal::clock::MHz16; 9 | type Delay = atmega_hal::delay::Delay; 10 | 11 | // Below are examples of a delay helper functions 12 | fn delay_ms(ms: u16) { 13 | Delay::new().delay_ms(u32::from(ms)) 14 | } 15 | 16 | #[allow(dead_code)] 17 | fn delay_us(us: u32) { 18 | Delay::new().delay_us(us) 19 | } 20 | 21 | #[avr_device::entry] 22 | fn main() -> ! { 23 | let dp = atmega_hal::Peripherals::take().unwrap(); 24 | let pins = atmega_hal::pins!(dp); 25 | 26 | let mut led = pins.pb7.into_output(); 27 | 28 | loop { 29 | led.toggle(); 30 | delay_ms(1000); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /avr-hal-generic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "avr-hal-generic" 3 | version = "0.1.0" 4 | 5 | authors = ["Rahix "] 6 | edition = "2021" 7 | description = "MCU-generic meta-HAL crate for AVR microcontrollers" 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rahix/avr-hal" 10 | keywords = ["avr", "arduino"] 11 | categories = ["no-std", "embedded", "hardware-support"] 12 | 13 | [package.metadata.docs.rs] 14 | features = ["docsrs"] 15 | 16 | [features] 17 | docsrs = ["avr-device/docsrs"] 18 | 19 | [dependencies] 20 | nb = "1.1.0" 21 | ufmt = "0.2.0" 22 | paste = "1.0.0" 23 | avr-device = "0.7" 24 | embedded-storage = "0.2" 25 | embedded-hal = "1.0" 26 | embedded-hal-bus = "0.1" 27 | unwrap-infallible = "0.1.5" 28 | 29 | [dependencies.embedded-hal-v0] 30 | version = "0.2.3" 31 | package = "embedded-hal" 32 | features = ["unproven"] 33 | -------------------------------------------------------------------------------- /examples/arduino-nano/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-nano-examples" 3 | version = "0.0.0" 4 | authors = ["David R. Morrison "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | 14 | [dependencies.embedded-hal-v0] 15 | version = "0.2.3" 16 | package = "embedded-hal" 17 | 18 | [dependencies.arduino-hal] 19 | path = "../../arduino-hal/" 20 | features = ["arduino-nano"] 21 | 22 | [dependencies.avr-device] 23 | version = "0.7" 24 | 25 | # The latest releases of `proc-macro2` do not support the rust toolchain that 26 | # we use. Thus, we must fix this dependency to an older version where our 27 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 28 | [build-dependencies.proc-macro2] 29 | version = "=1.0.79" 30 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/src/bin/leonardo-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | 6 | #[arduino_hal::entry] 7 | fn main() -> ! { 8 | let dp = arduino_hal::Peripherals::take().unwrap(); 9 | let pins = arduino_hal::pins!(dp); 10 | 11 | let mut leds = [ 12 | pins.led_rx.into_output().downgrade(), 13 | pins.led_tx.into_output().downgrade(), 14 | pins.d13.into_output().downgrade(), 15 | ]; 16 | 17 | // RX & TX LEDs are active low and the LED on D13 is active high. Thus invert LED13 here so 18 | // they are all in the same "state": 19 | leds[0].set_high(); 20 | leds[1].set_high(); 21 | leds[2].set_low(); 22 | 23 | loop { 24 | for i in 0..3 { 25 | leds[i].toggle(); 26 | arduino_hal::delay_ms(100); 27 | leds[i].toggle(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /avr-hal-generic/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(asm_experimental_arch)] 3 | 4 | pub use embedded_hal as hal; 5 | pub use embedded_hal_v0 as hal_v0; 6 | 7 | #[doc(hidden)] 8 | pub use avr_device; 9 | #[doc(hidden)] 10 | pub use nb; 11 | #[doc(hidden)] 12 | pub use paste; 13 | 14 | pub mod adc; 15 | pub mod clock; 16 | pub mod delay; 17 | pub mod eeprom; 18 | pub mod i2c; 19 | pub mod port; 20 | pub mod simple_pwm; 21 | pub mod spi; 22 | pub mod usart; 23 | pub mod wdt; 24 | 25 | /// Prelude containing all HAL traits 26 | pub mod prelude { 27 | pub use crate::hal_v0::prelude::*; 28 | pub use ufmt::uWrite as _ufmt_uWrite; 29 | pub use unwrap_infallible::UnwrapInfallible as _unwrap_infallible_UnwrapInfallible; 30 | } 31 | 32 | // For making certain traits unimplementable from outside this crate. 33 | mod sealed { 34 | pub trait Sealed {} 35 | } 36 | pub(crate) use sealed::Sealed; 37 | -------------------------------------------------------------------------------- /examples/atmega2560/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "atmega2560-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix ", "Armandas Jarušauskas "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | avr-device = { version = "0.7", features = ["rt"] } 14 | 15 | [dependencies.embedded-hal-v0] 16 | version = "0.2.3" 17 | package = "embedded-hal" 18 | 19 | [dependencies.atmega-hal] 20 | path = "../../mcu/atmega-hal/" 21 | features = ["atmega2560"] 22 | 23 | # The latest releases of `proc-macro2` do not support the rust toolchain that 24 | # we use. Thus, we must fix this dependency to an older version where our 25 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 26 | [build-dependencies.proc-macro2] 27 | version = "=1.0.79" 28 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-usart.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use atmega_hal::prelude::*; 5 | use atmega_hal::usart::{Baudrate, Usart}; 6 | use panic_halt as _; 7 | 8 | // Define core clock. This can be used in the rest of the project. 9 | type CoreClock = atmega_hal::clock::MHz16; 10 | 11 | #[avr_device::entry] 12 | fn main() -> ! { 13 | let dp = atmega_hal::Peripherals::take().unwrap(); 14 | let pins = atmega_hal::pins!(dp); 15 | let mut serial = Usart::new( 16 | dp.USART0, 17 | pins.pe0, 18 | pins.pe1.into_output(), 19 | Baudrate::::new(57600), 20 | ); 21 | 22 | ufmt::uwriteln!(&mut serial, "Hello from ATmega!\r").unwrap(); 23 | 24 | loop { 25 | // Read a byte from the serial connection 26 | let b = nb::block!(serial.read()).unwrap(); 27 | 28 | // Answer 29 | ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.a4.into_pull_up_input(), 16 | pins.a5.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/src/bin/leonardo-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.d2.into_pull_up_input(), 16 | pins.d3.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/src/bin/diecimila-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.a4.into_pull_up_input(), 16 | pins.a5.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/src/bin/mega1280-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.d20.into_pull_up_input(), 16 | pins.d21.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.d20.into_pull_up_input(), 16 | pins.d21.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /examples/nano168/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nano168-examples" 3 | description = "Examples for the arduino clones with Atmega168 chip" 4 | version = "0.0.0" 5 | authors = ["David R. Morrison ", "Franz Dietrich "] 6 | edition = "2021" 7 | publish = false 8 | 9 | [dependencies] 10 | panic-halt = "0.2.0" 11 | ufmt = "0.2.0" 12 | nb = "1.1.0" 13 | embedded-hal = "1.0" 14 | 15 | [dependencies.embedded-hal-v0] 16 | version = "0.2.3" 17 | package = "embedded-hal" 18 | 19 | [dependencies.arduino-hal] 20 | path = "../../arduino-hal/" 21 | features = ["nano168"] 22 | 23 | [dependencies.avr-device] 24 | version = "0.7" 25 | 26 | # The latest releases of `proc-macro2` do not support the rust toolchain that 27 | # we use. Thus, we must fix this dependency to an older version where our 28 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 29 | [build-dependencies.proc-macro2] 30 | version = "=1.0.79" 31 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/src/bin/promicro-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | #[arduino_hal::entry] 8 | fn main() -> ! { 9 | let dp = arduino_hal::Peripherals::take().unwrap(); 10 | let pins = arduino_hal::pins!(dp); 11 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 12 | 13 | let mut i2c = arduino_hal::I2c::new( 14 | dp.TWI, 15 | pins.d2.into_pull_up_input(), 16 | pins.d3.into_pull_up_input(), 17 | 50000, 18 | ); 19 | 20 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 21 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 22 | .unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 24 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 25 | .unwrap_infallible(); 26 | 27 | loop {} 28 | } 29 | -------------------------------------------------------------------------------- /arduino-hal/src/delay.rs: -------------------------------------------------------------------------------- 1 | use embedded_hal_v0::blocking::delay::{DelayMs, DelayUs}; 2 | 3 | /// Delay type for `embedded-hal` compatibility. 4 | /// 5 | /// This type can be used to pass a generic delay utility to `embedded-hal` drivers. For direct 6 | /// use in `arduino-hal` code, usage of [`delay_ms`] or [`delay_us`] is preferred. 7 | pub type Delay = avr_hal_generic::delay::Delay; 8 | 9 | /// Delay execution for a number of milliseconds. 10 | /// 11 | /// Busy-loop for the given time. This function assumes the default clock speed defined by 12 | /// [`arduino_hal::DefaultClock`][crate::DefaultClock]. 13 | pub fn delay_ms(ms: u16) { 14 | Delay::new().delay_ms(ms) 15 | } 16 | 17 | /// Delay execution for a number of microseconds. 18 | /// 19 | /// Busy-loop for the given time. This function assumes the default clock speed defined by 20 | /// [`arduino_hal::DefaultClock`][crate::DefaultClock]. 21 | pub fn delay_us(us: u32) { 22 | Delay::new().delay_us(us) 23 | } 24 | -------------------------------------------------------------------------------- /examples/arduino-uno/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-uno-examples" 3 | version = "0.0.0" 4 | authors = ["Rahix "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | panic-halt = "0.2.0" 10 | ufmt = "0.2.0" 11 | nb = "1.1.0" 12 | embedded-hal = "1.0" 13 | pwm-pca9685 = "1.0.0" 14 | infrared = "0.14.1" 15 | embedded-storage = "0.2" 16 | 17 | [dependencies.embedded-hal-v0] 18 | version = "0.2.3" 19 | package = "embedded-hal" 20 | 21 | [dependencies.arduino-hal] 22 | path = "../../arduino-hal/" 23 | features = ["arduino-uno"] 24 | 25 | [dependencies.avr-device] 26 | version = "0.7" 27 | 28 | [dependencies.either] 29 | version = "1.6.1" 30 | default-features = false 31 | 32 | # The latest releases of `proc-macro2` do not support the rust toolchain that 33 | # we use. Thus, we must fix this dependency to an older version where our 34 | # toolchain is still supported. See https://github.com/Rahix/avr-hal/issues/537 35 | [build-dependencies.proc-macro2] 36 | version = "=1.0.79" 37 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-watchdog.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Demonstration of setting up the watchdog timer. 3 | * 4 | * A watchdog timer is used to ensure the firmware did not lock itself up. This works by requiring 5 | * the firmware to periodically "feed" the watchdog. If it fails to do so for a certain 6 | * (configurable) timeout, the watchdog will reset the device. 7 | */ 8 | #![no_std] 9 | #![no_main] 10 | 11 | use arduino_hal::hal::wdt; 12 | use panic_halt as _; 13 | 14 | #[arduino_hal::entry] 15 | fn main() -> ! { 16 | let dp = arduino_hal::Peripherals::take().unwrap(); 17 | let pins = arduino_hal::pins!(dp); 18 | 19 | let mut led = pins.d13.into_output(); 20 | led.set_high(); 21 | 22 | for _ in 0..20 { 23 | led.toggle(); 24 | arduino_hal::delay_ms(100); 25 | } 26 | 27 | let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr); 28 | watchdog.start(wdt::Timeout::Ms2000).unwrap(); 29 | 30 | loop { 31 | led.toggle(); 32 | arduino_hal::delay_ms(1000); 33 | watchdog.feed(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega8.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega8", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega8", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega8", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega168.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega168", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega168", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega168", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega328.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega328", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega328", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega328", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega32a.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega32a", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega32a", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega32a", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega48p.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega48p", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega48p", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega48p", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-attiny167.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "attiny167", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=attiny167", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=attiny167", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-attiny85.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "attiny85", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=attiny85", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=attiny85", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-attiny88.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "attiny88", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=attiny88", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=attiny88", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | docs: 10 | name: Build Documentation 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | - name: Install Rust 16 | uses: dtolnay/rust-toolchain@master 17 | with: 18 | toolchain: nightly-2023-12-28 19 | components: rust-src 20 | - name: Build documentation (arduino-hal) 21 | run: cd arduino-hal/ && cargo doc --features arduino-uno 22 | - name: Build documentation (atmega-hal) 23 | run: cd mcu/atmega-hal/ && cargo doc --features atmega328p 24 | - name: Build documentation (attiny-hal) 25 | run: cd mcu/attiny-hal/ && cargo doc --features attiny85 26 | - name: Deploy to GH-Pages 27 | uses: peaceiris/actions-gh-pages@v4 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: ./target/doc 31 | publish_branch: gh-pages 32 | force_orphan: true 33 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega1280.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega1280", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega1280", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega1280", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega128a.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega128a", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega128a", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega128a", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega2560.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega2560", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega2560", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega2560", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega328p.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega328p", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega328p", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega328p", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega32u4.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega32u4", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega32u4", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega32u4", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-attiny2313.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "attiny2313", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=attiny2313", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=attiny2313", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega1284p.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega1284p", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega1284p", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega1284p", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /avr-specs/avr-atmega164pa.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "avr", 3 | "atomic-cas": false, 4 | "cpu": "atmega164pa", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 7 | "eh-frame-header": false, 8 | "exe-suffix": ".elf", 9 | "late-link-args": { 10 | "gnu-cc": [ 11 | "-lgcc" 12 | ], 13 | "gnu-lld-cc": [ 14 | "-lgcc" 15 | ] 16 | }, 17 | "linker": "avr-gcc", 18 | "linker-flavor": "gnu-cc", 19 | "llvm-target": "avr-unknown-unknown", 20 | "max-atomic-width": 16, 21 | "metadata": { 22 | "description": null, 23 | "host_tools": null, 24 | "std": null, 25 | "tier": null 26 | }, 27 | "no-default-libraries": false, 28 | "pre-link-args": { 29 | "gnu-cc": [ 30 | "-mmcu=atmega164pa", 31 | "-Wl,--as-needed,--print-memory-usage" 32 | ], 33 | "gnu-lld-cc": [ 34 | "-mmcu=atmega164pa", 35 | "-Wl,--as-needed,--print-memory-usage" 36 | ] 37 | }, 38 | "relocation-model": "static", 39 | "target-c-int-width": "16", 40 | "target-pointer-width": "16" 41 | } 42 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [profile.dev] 2 | panic = "abort" 3 | lto = true 4 | opt-level = "s" 5 | 6 | [profile.release] 7 | panic = "abort" 8 | codegen-units = 1 9 | debug = true 10 | lto = true 11 | opt-level = "s" 12 | 13 | [workspace] 14 | members = [ 15 | # The generic hal definitions 16 | "avr-hal-generic", 17 | 18 | # MCU HAL crates 19 | "mcu/atmega-hal", 20 | "mcu/attiny-hal", 21 | 22 | # Higher level crates 23 | "arduino-hal", 24 | "keyboard-hal", 25 | 26 | # Examples 27 | "examples/arduino-diecimila", 28 | "examples/arduino-leonardo", 29 | "examples/arduino-mega2560", 30 | "examples/arduino-mega1280", 31 | "examples/arduino-nano", 32 | "examples/arduino-uno", 33 | "examples/atmega2560", 34 | "examples/nano168", 35 | "examples/sparkfun-promicro", 36 | "examples/sparkfun-promini-3v3", 37 | "examples/sparkfun-promini-5v", 38 | "examples/trinket-pro", 39 | "examples/trinket", 40 | 41 | # Keyboards 42 | "examples/keyboard-dz60", 43 | ] 44 | exclude = [ 45 | # The RAVEDUDE! Yeah! 46 | "ravedude", 47 | ] 48 | resolver = "2" 49 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /ravedude/src/ui.rs: -------------------------------------------------------------------------------- 1 | /// Emit a message in the cargo style with a green "verb" up front and some text afterwards. 2 | #[macro_export] 3 | macro_rules! task_message { 4 | ($verb:expr, $($fmt:tt)+) => { 5 | eprint!("{:>12} ", colored::Colorize::bold(colored::Colorize::green($verb))); 6 | eprintln!($($fmt)+); 7 | }; 8 | } 9 | 10 | #[macro_export] 11 | macro_rules! warning { 12 | ($($fmt:tt)+) => { 13 | eprint!("{}", colored::Colorize::bold(colored::Colorize::yellow("Warning"))); 14 | eprint!("{}", colored::Colorize::bold(": ")); 15 | eprintln!("{}", colored::Colorize::bold(&*format!($($fmt)+))); 16 | }; 17 | } 18 | 19 | pub fn print_error(e: anyhow::Error) { 20 | use colored::Colorize as _; 21 | 22 | eprintln!( 23 | "{}{}{}", 24 | "Error".red().bold(), 25 | ": ".bold(), 26 | e.to_string().bold() 27 | ); 28 | 29 | eprintln!(""); 30 | 31 | for cause in e.chain().skip(1) { 32 | eprintln!( 33 | "{}{}{}", 34 | "Caused by".yellow().bold(), 35 | ": ".bold(), 36 | cause.to_string().bold() 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-eeprom.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use atmega_hal::delay::Delay; 5 | use atmega_hal::usart::{Baudrate, Usart}; 6 | use atmega_hal::Eeprom; 7 | use embedded_hal::delay::DelayNs; 8 | use panic_halt as _; 9 | 10 | // Define core clock in the root crate 11 | type CoreClock = atmega_hal::clock::MHz16; 12 | 13 | const BOOT_COUNT_OFFSET: u16 = 0; 14 | 15 | #[avr_device::entry] 16 | fn main() -> ! { 17 | let dp = atmega_hal::Peripherals::take().unwrap(); 18 | let pins = atmega_hal::pins!(dp); 19 | 20 | let mut delay = Delay::::new(); 21 | 22 | // set up serial interface for text output 23 | let mut serial = Usart::new( 24 | dp.USART0, 25 | pins.pe0, 26 | pins.pe1.into_output(), 27 | Baudrate::::new(57600), 28 | ); 29 | 30 | let mut eeprom = Eeprom::new(dp.EEPROM); 31 | 32 | let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); 33 | boot_count = boot_count.wrapping_add(1); 34 | eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); 35 | 36 | ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); 37 | 38 | loop {} 39 | } 40 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-blink-embedded-hal.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Blink the builtin LED - the "Hello World" of embedded programming, but with a twist: 3 | * the blink function is not aware of `avr-hal` and only uses `embedded-hal` traits. 4 | */ 5 | #![no_std] 6 | #![no_main] 7 | 8 | use embedded_hal::delay::DelayNs; 9 | use embedded_hal::digital::StatefulOutputPin; 10 | 11 | use panic_halt as _; 12 | 13 | fn blink(led: &mut impl StatefulOutputPin, delay: &mut impl DelayNs) -> ! { 14 | loop { 15 | led.toggle().unwrap(); 16 | delay.delay_ms(100); 17 | led.toggle().unwrap(); 18 | delay.delay_ms(100); 19 | led.toggle().unwrap(); 20 | delay.delay_ms(100); 21 | led.toggle().unwrap(); 22 | delay.delay_ms(800); 23 | } 24 | } 25 | 26 | #[arduino_hal::entry] 27 | fn main() -> ! { 28 | let dp = arduino_hal::Peripherals::take().unwrap(); 29 | let pins = arduino_hal::pins!(dp); 30 | 31 | // Digital pin 13 is also connected to an onboard LED marked "L" 32 | let mut led = pins.d13.into_output(); 33 | led.set_high(); 34 | 35 | let mut delay = arduino_hal::Delay::new(); 36 | 37 | blink(&mut led, &mut delay); 38 | } 39 | -------------------------------------------------------------------------------- /keyboard-hal/src/matrix.rs: -------------------------------------------------------------------------------- 1 | use crate::keyboard_config::{MATRIX_COLS, MATRIX_ROWS}; 2 | use atmega_hal::port::{ 3 | mode::{AnyInput, Input, Output}, 4 | Pin, 5 | }; 6 | 7 | pub struct Matrix { 8 | pub last_state: [[bool; MATRIX_COLS]; MATRIX_ROWS], 9 | rows: [Pin; MATRIX_ROWS], 10 | cols: [Pin>; MATRIX_COLS], 11 | } 12 | 13 | impl Matrix { 14 | pub fn new( 15 | rows: [Pin; MATRIX_ROWS], 16 | cols: [Pin>; MATRIX_COLS], 17 | ) -> Self { 18 | Matrix { 19 | last_state: [[false; MATRIX_COLS]; MATRIX_ROWS], 20 | rows, 21 | cols, 22 | } 23 | } 24 | 25 | pub fn scan(&mut self) -> [[bool; MATRIX_COLS]; MATRIX_ROWS] { 26 | let mut new_state = [[false; MATRIX_COLS]; MATRIX_ROWS]; 27 | 28 | for (row_idx, row_pin) in self.rows.iter_mut().enumerate() { 29 | row_pin.set_low(); 30 | 31 | for (col_idx, col_pin) in self.cols.iter().enumerate() { 32 | new_state[row_idx][col_idx] = col_pin.is_low(); 33 | } 34 | 35 | row_pin.set_high(); 36 | } 37 | 38 | new_state 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-simple-pwm-embedded-hal.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of using simple_pwm to fade a LED in and out on pin d5, but with a twist: 3 | * the fade function is not aware of `avr-hal` and only uses `embedded-hal` traits. 4 | */ 5 | #![no_std] 6 | #![no_main] 7 | 8 | use arduino_hal::simple_pwm::*; 9 | use embedded_hal::delay::DelayNs; 10 | use embedded_hal::pwm::SetDutyCycle; 11 | use panic_halt as _; 12 | 13 | fn fade(led: &mut impl SetDutyCycle, delay: &mut impl DelayNs) -> ! { 14 | loop { 15 | for pct in (0..=100).chain((0..100).rev()) { 16 | led.set_duty_cycle_percent(pct).unwrap(); 17 | delay.delay_ms(10); 18 | } 19 | } 20 | } 21 | 22 | #[arduino_hal::entry] 23 | fn main() -> ! { 24 | let dp = arduino_hal::Peripherals::take().unwrap(); 25 | let pins = arduino_hal::pins!(dp); 26 | 27 | let timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64); 28 | 29 | // Digital pin 5 is connected to a LED and a resistor in series 30 | let mut pwm_led = pins.d5.into_output().into_pwm(&timer0); 31 | pwm_led.enable(); 32 | 33 | let mut delay = arduino_hal::Delay::new(); 34 | 35 | fade(&mut pwm_led, &mut delay); 36 | } 37 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-watchdog.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::hal::wdt; 5 | use arduino_hal::prelude::*; 6 | use panic_halt as _; 7 | 8 | #[arduino_hal::entry] 9 | fn main() -> ! { 10 | let dp = arduino_hal::Peripherals::take().unwrap(); 11 | let pins = arduino_hal::pins!(dp); 12 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 13 | 14 | let mut led = pins.d13.into_output(); 15 | led.set_high(); 16 | 17 | ufmt::uwriteln!(&mut serial, "Setup started...").unwrap_infallible(); 18 | 19 | for _ in 0..20 { 20 | ufmt::uwrite!(&mut serial, ".").unwrap_infallible(); 21 | led.toggle(); 22 | arduino_hal::delay_ms(100); 23 | } 24 | ufmt::uwriteln!(&mut serial, "\nEnabling watchdog...").unwrap_infallible(); 25 | 26 | let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr); 27 | watchdog.start(wdt::Timeout::Ms4000).unwrap(); 28 | 29 | ufmt::uwriteln!(&mut serial, "\nWatchdog on watch...").unwrap_infallible(); 30 | 31 | loop { 32 | ufmt::uwriteln!(&mut serial, "\nWaiting...").unwrap_infallible(); 33 | 34 | led.toggle(); 35 | arduino_hal::delay_ms(1000); 36 | //watchdog.feed(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-eeprom.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Demonstration of writing to and reading from the eeprom. 3 | */ 4 | #![no_std] 5 | #![no_main] 6 | 7 | use arduino_hal::prelude::*; 8 | use panic_halt as _; 9 | 10 | #[arduino_hal::entry] 11 | fn main() -> ! { 12 | let dp = arduino_hal::Peripherals::take().unwrap(); 13 | let pins = arduino_hal::pins!(dp); 14 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 15 | 16 | let mut ep = arduino_hal::Eeprom::new(dp.EEPROM); 17 | let ep_capacity = ep.capacity(); 18 | ufmt::uwriteln!(&mut serial, "eeprom capacity is:{}\r", ep_capacity).unwrap_infallible(); 19 | 20 | // KNOWN ISSUE: Avoid to read entire eeprom capacity at once 21 | // See: https://github.com/Rahix/avr-hal/issues/410 22 | let mut data = [0_u8; 10]; 23 | 24 | let _start_address: u16 = 0; 25 | 26 | if ep.read(0, &mut data).is_err() { 27 | ufmt::uwriteln!(&mut serial, "read eeprom fail:\r").unwrap_infallible(); 28 | loop {} 29 | } 30 | 31 | ufmt::uwriteln!(&mut serial, "Got:\r").unwrap_infallible(); 32 | for i in data { 33 | ufmt::uwriteln!(&mut serial, "{}", i).unwrap_infallible(); 34 | } 35 | 36 | let _ = ep.erase(0, arduino_hal::Eeprom::CAPACITY); 37 | 38 | loop {} 39 | } 40 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use atmega_hal::usart::{Baudrate, Usart}; 5 | use panic_halt as _; 6 | 7 | // Define core clock in the root crate 8 | type CoreClock = atmega_hal::clock::MHz16; 9 | // Use it as follows in the rest of the project 10 | type I2c = atmega_hal::i2c::I2c; 11 | 12 | #[avr_device::entry] 13 | fn main() -> ! { 14 | let dp = atmega_hal::Peripherals::take().unwrap(); 15 | let pins = atmega_hal::pins!(dp); 16 | 17 | // set up serial interface for text output 18 | let mut serial = Usart::new( 19 | dp.USART0, 20 | pins.pe0, 21 | pins.pe1.into_output(), 22 | Baudrate::::new(57600), 23 | ); 24 | 25 | let mut i2c = I2c::new( 26 | dp.TWI, 27 | pins.pd1.into_pull_up_input(), 28 | pins.pd0.into_pull_up_input(), 29 | 50_000, 30 | ); 31 | 32 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap(); 33 | i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Write) 34 | .unwrap(); 35 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap(); 36 | i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read) 37 | .unwrap(); 38 | 39 | loop {} 40 | } 41 | -------------------------------------------------------------------------------- /keyboard-hal/src/port/pcb1.rs: -------------------------------------------------------------------------------- 1 | use atmega_hal::port::Pin; 2 | 3 | avr_hal_generic::renamed_pins! { 4 | pub struct Pins { 5 | // Row pins (D0-D3, D5) 6 | pub row0: atmega_hal::port::PD0 = pd0, 7 | pub row1: atmega_hal::port::PD1 = pd1, 8 | pub row2: atmega_hal::port::PD2 = pd2, 9 | pub row3: atmega_hal::port::PD3 = pd3, 10 | pub row4: atmega_hal::port::PD5 = pd5, 11 | 12 | // Column pins (F0, F1, E6, C7, C6, B7, D4, B1, B0, B5, B4, D7, D6, B3, F4) 13 | pub col0: atmega_hal::port::PF0 = pf0, 14 | pub col1: atmega_hal::port::PF1 = pf1, 15 | pub col2: atmega_hal::port::PE6 = pe6, 16 | pub col3: atmega_hal::port::PC7 = pc7, 17 | pub col4: atmega_hal::port::PC6 = pc6, 18 | pub col5: atmega_hal::port::PB7 = pb7, 19 | pub col6: atmega_hal::port::PD4 = pd4, 20 | pub col7: atmega_hal::port::PB1 = pb1, 21 | pub col8: atmega_hal::port::PB0 = pb0, 22 | pub col9: atmega_hal::port::PB5 = pb5, 23 | pub col10: atmega_hal::port::PB4 = pb4, 24 | pub col11: atmega_hal::port::PD7 = pd7, 25 | pub col12: atmega_hal::port::PD6 = pd6, 26 | pub col13: atmega_hal::port::PB3 = pb3, 27 | pub col14: atmega_hal::port::PF4 = pf4, 28 | } 29 | 30 | impl Pins { 31 | type Pin = Pin; 32 | type McuPins = atmega_hal::Pins; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /arduino-hal/src/clock.rs: -------------------------------------------------------------------------------- 1 | //! MCU core clock support. 2 | //! 3 | //! This module contains common definitions to abtract over the MCU core clock speed. `avr-hal` 4 | //! does not support changing the clock-speed at runtime. 5 | //! 6 | //! Most items in this module are re-exported from [`avr_hal_generic::clock`]. 7 | pub use avr_hal_generic::clock::*; 8 | 9 | pub(crate) mod default { 10 | /// Default clock speed for this board. 11 | /// 12 | /// `arduino-hal` contains a lot of type aliases for assuming this clock speed. As such it is 13 | /// easiest to keep the processor at the selected default speed. 14 | /// 15 | /// However, you can of course still use other clock speeds but you'll then need to correctly 16 | /// name the types from the HAL crate using your own clock definition. 17 | #[cfg(any( 18 | feature = "arduino-diecimila", 19 | feature = "arduino-leonardo", 20 | feature = "arduino-mega2560", 21 | feature = "arduino-mega1280", 22 | feature = "arduino-nano", 23 | feature = "arduino-uno", 24 | feature = "sparkfun-promicro", 25 | feature = "sparkfun-promini-5v", 26 | feature = "trinket-pro", 27 | feature = "nano168", 28 | ))] 29 | pub type DefaultClock = avr_hal_generic::clock::MHz16; 30 | #[cfg(any(feature = "trinket", feature = "sparkfun-promini-3v3"))] 31 | pub type DefaultClock = avr_hal_generic::clock::MHz8; 32 | } 33 | -------------------------------------------------------------------------------- /keyboard-hal/src/usb_keyboard.rs: -------------------------------------------------------------------------------- 1 | use usb_device::{bus::UsbBus, device::UsbDevice}; 2 | use usbd_hid::{descriptor::KeyboardReport, hid_class::HIDClass}; 3 | 4 | pub struct UsbKeyboard { 5 | usb_device: UsbDevice<'static, B>, 6 | hid_class: HIDClass<'static, B>, 7 | last_report: KeyboardReport, 8 | } 9 | 10 | impl UsbKeyboard { 11 | pub fn new(usb_device: UsbDevice<'static, B>, hid_class: HIDClass<'static, B>) -> Self { 12 | UsbKeyboard { 13 | usb_device, 14 | hid_class, 15 | last_report: KeyboardReport::default(), 16 | } 17 | } 18 | 19 | pub fn handle_keypress(&mut self, keycode: u8, pressed: bool) { 20 | if pressed { 21 | // Add keycode to the report 22 | if let Some(slot) = self 23 | .last_report 24 | .keycodes 25 | .iter_mut() 26 | .find(|slot| **slot == 0) 27 | { 28 | *slot = keycode; 29 | } 30 | } else { 31 | // Remove keycode from the report 32 | for slot in self.last_report.keycodes.iter_mut() { 33 | if *slot == keycode { 34 | *slot = 0; 35 | } 36 | } 37 | } 38 | 39 | self.send_report(); 40 | } 41 | 42 | fn send_report(&mut self) { 43 | if self.usb_device.poll(&mut [&mut self.hid_class]) { 44 | self.hid_class.push_input(&self.last_report).ok(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/src/bin/diecimila-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | ); 21 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 22 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 23 | 24 | // To store multiple channels in an array, we use the `into_channel()` method. 25 | let channels: [adc::Channel; 6] = [ 26 | pins.a0.into_analog_input(&mut adc).into_channel(), 27 | pins.a1.into_analog_input(&mut adc).into_channel(), 28 | pins.a2.into_analog_input(&mut adc).into_channel(), 29 | pins.a3.into_analog_input(&mut adc).into_channel(), 30 | pins.a4.into_analog_input(&mut adc).into_channel(), 31 | pins.a5.into_analog_input(&mut adc).into_channel(), 32 | ]; 33 | 34 | loop { 35 | for (i, ch) in channels.iter().enumerate() { 36 | let v = adc.read_blocking(ch); 37 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 38 | } 39 | 40 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 41 | arduino_hal::delay_ms(1000); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/src/bin/promicro-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd, tmp) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | adc.read_blocking(&adc::channel::Temperature), 21 | ); 22 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 24 | ufmt::uwriteln!(&mut serial, "Temperature: {}", tmp).unwrap_infallible(); 25 | 26 | let a0 = pins.a0.into_analog_input(&mut adc); 27 | let a1 = pins.a1.into_analog_input(&mut adc); 28 | let a2 = pins.a2.into_analog_input(&mut adc); 29 | let a3 = pins.a3.into_analog_input(&mut adc); 30 | 31 | loop { 32 | let values = [ 33 | a0.analog_read(&mut adc), 34 | a1.analog_read(&mut adc), 35 | a2.analog_read(&mut adc), 36 | a3.analog_read(&mut adc), 37 | ]; 38 | 39 | for (i, v) in values.iter().enumerate() { 40 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 41 | } 42 | 43 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 44 | arduino_hal::delay_ms(1000); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /keyboard-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keyboard-hal" 3 | version = "0.1.0" 4 | authors = ["Felipe Coury "] 5 | edition = "2021" 6 | description = "Board support crate for popular AVR dev-boards" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/rahix/avr-hal" 9 | keywords = ["avr", "keyboard"] 10 | categories = ["no-std", "embedded", "hardware-support"] 11 | 12 | [features] 13 | default = ["rt"] 14 | rt = ["avr-device/rt"] 15 | 16 | [dependencies] 17 | cfg-if = "1" 18 | embedded-hal = "1.0" 19 | ufmt = "0.2.0" 20 | usb-device = "0.3" 21 | usbd-hid = "0.7" 22 | 23 | [dependencies.embedded-hal-v0] 24 | version = "0.2.3" 25 | package = "embedded-hal" 26 | 27 | [dependencies.avr-hal-generic] 28 | path = "../avr-hal-generic/" 29 | 30 | [dependencies.atmega-hal] 31 | path = "../mcu/atmega-hal/" 32 | 33 | # Because this crate has its own check that at least one device is selected, we 34 | # can safely "circumvent" the check in `atmega-hal`. Due to compile order, 35 | # this allows us to show our error instead of the one from `atmega-hal` (which 36 | # is much less helpful in this situation). 37 | features = ["atmega32u4", "disable-device-selection-error"] 38 | 39 | [dependencies.avr-device] 40 | version = "0.7" 41 | 42 | # Because this crate has its own check that at least one device is selected, we 43 | # can safely "circumvent" the check in `avr-device`. 44 | # 45 | # Why would we want that? Otherwise, as `avr-device` is compiled first, its 46 | # error will be shown and ours won't which leads to a degraded user experience 47 | # as the displayed error message does not really tell what needs to be done... 48 | features = ["device-selected"] 49 | -------------------------------------------------------------------------------- /mcu/attiny-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "attiny-hal" 3 | version = "0.1.0" 4 | 5 | authors = ["Rahix "] 6 | edition = "2021" 7 | description = "HAL crate for ATtiny-series AVR microcontrollers" 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rahix/avr-hal" 10 | keywords = ["avr", "arduino"] 11 | categories = ["no-std", "embedded", "hardware-support"] 12 | 13 | [features] 14 | rt = ["avr-device/rt"] 15 | device-selected = [] 16 | attiny84 = ["avr-device/attiny84", "device-selected"] 17 | attiny85 = ["avr-device/attiny85", "device-selected"] 18 | attiny88 = ["avr-device/attiny88", "device-selected"] 19 | attiny167 = ["avr-device/attiny167", "device-selected"] 20 | attiny2313 = ["avr-device/attiny2313", "device-selected"] 21 | 22 | critical-section-impl = ["avr-device/critical-section-impl"] 23 | 24 | # Allow certain downstream crates to overwrite the device selection error by themselves. 25 | disable-device-selection-error = [] 26 | 27 | # We must select a microcontroller to build on docs.rs 28 | docsrs = ["attiny85"] 29 | 30 | [dependencies] 31 | avr-hal-generic = { path = "../../avr-hal-generic/" } 32 | 33 | [dependencies.avr-device] 34 | version = "0.7" 35 | 36 | # Because this crate has its own check that at least one device is selected, we 37 | # can safely "circumvent" the check in `avr-device`. 38 | # 39 | # Why would we want that? Otherwise, as `avr-device` is compiled first, its 40 | # error will be shown and ours won't which leads to a degraded user experience 41 | # as the displayed error message does not really tell what needs to be done... 42 | features = ["device-selected"] 43 | 44 | [package.metadata.docs.rs] 45 | features = ["docsrs"] 46 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-i2cdetect.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Detect all devices connected on the I2C/TWI bus. Useful if you can't figure out the address of 3 | * an I2C device. 4 | * 5 | * This example will check all possible addresses on the I2C bus for whether a device responds to 6 | * them. It will output a table of the results. This check is done twice, once for reading and 7 | * once for writing, as some devices only respond to one of the two operations. 8 | * 9 | * ATTENTION: Randomly reading from and writing to devices can lead to unexpected results. Some 10 | * devices do not cope well with this. Use with care! 11 | * 12 | * Connections 13 | * ----------- 14 | * - `A4`: I2C SDA signal 15 | * - `A5`: I2C SCL signal 16 | */ 17 | #![no_std] 18 | #![no_main] 19 | 20 | use arduino_hal::prelude::*; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 28 | 29 | let mut i2c = arduino_hal::I2c::new( 30 | dp.TWI, 31 | pins.a4.into_pull_up_input(), 32 | pins.a5.into_pull_up_input(), 33 | 50000, 34 | ); 35 | 36 | ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap_infallible(); 37 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Write) 38 | .unwrap_infallible(); 39 | ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap_infallible(); 40 | i2c.i2cdetect(&mut serial, arduino_hal::i2c::Direction::Read) 41 | .unwrap_infallible(); 42 | 43 | loop { 44 | arduino_hal::delay_ms(1000); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-manual-servo.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Sweep a standard SG90 compatible servo from its left limit all the way to its right limit. 3 | * 4 | * Because avr-hal does not have a dedicated servo driver library yet, we do this manually using 5 | * timer TC1. The servo should be connected to D9 (AND D9 ONLY! THIS DOES NOT WORK ON OTHER PINS 6 | * AS IT IS). 7 | * 8 | * As the limits are not precisely defined, we undershoot the datasheets 1ms left limit and 9 | * overshoot the 2ms right limit by a bit - you can figure out where exactly the limits are for 10 | * your model by experimentation. 11 | * 12 | * Connections 13 | * ----------- 14 | * - `D9`: Servo's PWM signal 15 | */ 16 | #![no_std] 17 | #![no_main] 18 | 19 | use panic_halt as _; 20 | 21 | #[arduino_hal::entry] 22 | fn main() -> ! { 23 | let dp = arduino_hal::Peripherals::take().unwrap(); 24 | let pins = arduino_hal::pins!(dp); 25 | 26 | // Important because this sets the bit in the DDR register! 27 | pins.d9.into_output(); 28 | 29 | // - TC1 runs off a 250kHz clock, with 5000 counts per overflow => 50 Hz signal. 30 | // - Each count increases the duty-cycle by 4us. 31 | // - Use OC1A which is connected to D9 of the Arduino Uno. 32 | let tc1 = dp.TC1; 33 | tc1.icr1.write(|w| w.bits(4999)); 34 | tc1.tccr1a 35 | .write(|w| w.wgm1().bits(0b10).com1a().match_clear()); 36 | tc1.tccr1b 37 | .write(|w| w.wgm1().bits(0b11).cs1().prescale_64()); 38 | 39 | loop { 40 | // 100 counts => 0.4ms 41 | // 700 counts => 2.8ms 42 | for duty in 100..=700 { 43 | tc1.ocr1a.write(|w| w.bits(duty)); 44 | arduino_hal::delay_ms(20); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `~11` to pin `~12`. 4 | //! 5 | //! Once this program is written to the board, the serial output can be 6 | //! accessed with 7 | //! 8 | //! ``` 9 | //! sudo screen /dev/ttyACM0 57600 10 | //! ``` 11 | //! 12 | //! You should see it output the line `data: 15` repeatedly (aka 0b00001111). 13 | //! If the output you see is `data: 255`, you may need to check your jumper. 14 | 15 | #![no_std] 16 | #![no_main] 17 | 18 | use arduino_hal::prelude::*; 19 | use arduino_hal::spi; 20 | use embedded_hal_v0::spi::FullDuplex; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | 28 | // set up serial interface for text output 29 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 30 | 31 | // Create SPI interface. 32 | let (mut spi, _) = arduino_hal::Spi::new( 33 | dp.SPI, 34 | pins.d52.into_output(), 35 | pins.d51.into_output(), 36 | pins.d50.into_pull_up_input(), 37 | pins.d53.into_output(), 38 | spi::Settings::default(), 39 | ); 40 | 41 | loop { 42 | // Send a byte 43 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 44 | // Because MISO is connected to MOSI, the read data should be the same 45 | let data = nb::block!(spi.read()).unwrap_infallible(); 46 | 47 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of the SPI bus, by looping back output to input. 3 | * 4 | * This example demonstrates how to set up a SPI interface and communicate 5 | * over it. The physical hardware configuation consists of connecting a 6 | * jumper directly from pin `D11` to pin `D12`. 7 | * 8 | * If done correctly, you should see it output the line `data: 15` repeatedly (aka 0b00001111). If 9 | * the output you see is `data: 255`, you may need to check your jumper. 10 | * 11 | * Connections: 12 | * - `D11` connected directly to `D12` (loop MOSI to MISO) 13 | */ 14 | #![no_std] 15 | #![no_main] 16 | 17 | use arduino_hal::prelude::*; 18 | use arduino_hal::spi; 19 | use embedded_hal_v0::spi::FullDuplex; 20 | use panic_halt as _; 21 | 22 | #[arduino_hal::entry] 23 | fn main() -> ! { 24 | let dp = arduino_hal::Peripherals::take().unwrap(); 25 | let pins = arduino_hal::pins!(dp); 26 | 27 | // set up serial interface for text output 28 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 29 | 30 | // Create SPI interface. 31 | let (mut spi, _) = arduino_hal::Spi::new( 32 | dp.SPI, 33 | pins.d13.into_output(), 34 | pins.d11.into_output(), 35 | pins.d12.into_pull_up_input(), 36 | pins.d10.into_output(), 37 | spi::Settings::default(), 38 | ); 39 | 40 | loop { 41 | // Send a byte 42 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 43 | // Because MISO is connected to MOSI, the read data should be the same 44 | let data = nb::block!(spi.read()).unwrap_infallible(); 45 | 46 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 47 | arduino_hal::delay_ms(1000); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/arduino-diecimila/src/bin/diecimila-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `~11` to pin `~12`. 4 | //! 5 | //! Once this program is written to the board, the serial output can be 6 | //! accessed with 7 | //! 8 | //! ``` 9 | //! sudo screen /dev/ttyACM0 57600 10 | //! ``` 11 | //! 12 | //! You should see it output the line `data: 15` repeatedly (aka 0b00001111). 13 | //! If the output you see is `data: 255`, you may need to check your jumper. 14 | 15 | #![no_std] 16 | #![no_main] 17 | 18 | use arduino_hal::prelude::*; 19 | use arduino_hal::spi; 20 | use embedded_hal_v0::spi::FullDuplex; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | 28 | // set up serial interface for text output 29 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 30 | 31 | // Create SPI interface. 32 | let (mut spi, _) = arduino_hal::Spi::new( 33 | dp.SPI, 34 | pins.d13.into_output(), 35 | pins.d11.into_output(), 36 | pins.d12.into_pull_up_input(), 37 | pins.d10.into_output(), 38 | spi::Settings::default(), 39 | ); 40 | 41 | loop { 42 | // Send a byte 43 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 44 | // Because MISO is connected to MOSI, the read data should be the same 45 | let data = nb::block!(spi.read()).unwrap_infallible(); 46 | 47 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/src/bin/leonardo-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `~11` to pin `~12`. 4 | //! 5 | //! Once this program is written to the board, the serial output can be 6 | //! accessed with 7 | //! 8 | //! ``` 9 | //! sudo screen /dev/ttyACM0 57600 10 | //! ``` 11 | //! 12 | //! You should see it output the line `data: 15` repeatedly (aka 0b00001111). 13 | //! If the output you see is `data: 255`, you may need to check your jumper. 14 | 15 | #![no_std] 16 | #![no_main] 17 | 18 | use arduino_hal::prelude::*; 19 | use arduino_hal::spi; 20 | use embedded_hal_v0::spi::FullDuplex; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | 28 | // set up serial interface for text output 29 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 30 | 31 | // Create SPI interface. 32 | let (mut spi, _) = arduino_hal::Spi::new( 33 | dp.SPI, 34 | pins.sck.into_output(), 35 | pins.mosi.into_output(), 36 | pins.miso.into_pull_up_input(), 37 | pins.led_rx.into_output(), 38 | spi::Settings::default(), 39 | ); 40 | 41 | loop { 42 | // Send a byte 43 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 44 | // Because MISO is connected to MOSI, the read data should be the same 45 | let data = nb::block!(spi.read()).unwrap_infallible(); 46 | 47 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/sparkfun-promicro/src/bin/promicro-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `~14` to pin `~16`. 4 | //! 5 | //! Once this program is written to the board, the serial output can be 6 | //! accessed with 7 | //! 8 | //! ``` 9 | //! sudo screen /dev/ttyACM0 57600 10 | //! ``` 11 | //! 12 | //! You should see it output the line `data: 15` repeatedly (aka 0b00001111). 13 | //! If the output you see is `data: 255`, you may need to check your jumper. 14 | 15 | #![no_std] 16 | #![no_main] 17 | 18 | use arduino_hal::prelude::*; 19 | use arduino_hal::spi; 20 | use embedded_hal_v0::spi::FullDuplex; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | 28 | // set up serial interface for text output 29 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 30 | 31 | // Create SPI interface. 32 | let (mut spi, _) = arduino_hal::Spi::new( 33 | dp.SPI, 34 | pins.d15.into_output(), 35 | pins.d14.into_output(), 36 | pins.d16.into_pull_up_input(), 37 | pins.led_rx.into_output(), 38 | spi::Settings::default(), 39 | ); 40 | 41 | loop { 42 | // Send a byte 43 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 44 | // Because MISO is connected to MOSI, the read data should be the same 45 | let data = nb::block!(spi.read()).unwrap_infallible(); 46 | 47 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/src/bin/mega1280spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `d50` (MISO/PB3) to pin `d51` (MOSI/PB2). 4 | //! 5 | //! Once this program is written to the board, the serial output can be 6 | //! accessed with 7 | //! 8 | //! ``` 9 | //! sudo screen /dev/ttyACM0 57600 10 | //! ``` 11 | //! 12 | //! You should see it output the line `data: 15` repeatedly (aka 0b00001111). 13 | //! If the output you see is `data: 255`, you may need to check your jumper. 14 | 15 | #![no_std] 16 | #![no_main] 17 | 18 | use arduino_hal::prelude::*; 19 | use arduino_hal::spi; 20 | use embedded_hal_v0::spi::FullDuplex; 21 | use panic_halt as _; 22 | 23 | #[arduino_hal::entry] 24 | fn main() -> ! { 25 | let dp = arduino_hal::Peripherals::take().unwrap(); 26 | let pins = arduino_hal::pins!(dp); 27 | 28 | // set up serial interface for text output 29 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 30 | 31 | // Create SPI interface. 32 | let (mut spi, _) = arduino_hal::Spi::new( 33 | dp.SPI, 34 | pins.d52.into_output(), 35 | pins.d51.into_output(), 36 | pins.d50.into_pull_up_input(), 37 | pins.d53.into_output(), 38 | spi::Settings::default(), 39 | ); 40 | 41 | loop { 42 | // Send a byte 43 | nb::block!(spi.send(0b00001111)).unwrap_infallible(); 44 | // Because MISO is connected to MOSI, the read data should be the same 45 | let data = nb::block!(spi.read()).unwrap_infallible(); 46 | 47 | ufmt::uwriteln!(&mut serial, "data: {}\r", data).unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/arduino-leonardo/src/bin/leonardo-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd, tmp) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | adc.read_blocking(&adc::channel::Temperature), 21 | ); 22 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 24 | ufmt::uwriteln!(&mut serial, "Temperature: {}", tmp).unwrap_infallible(); 25 | 26 | let a0 = pins.a0.into_analog_input(&mut adc); 27 | let a1 = pins.a1.into_analog_input(&mut adc); 28 | let a2 = pins.a2.into_analog_input(&mut adc); 29 | let a3 = pins.a3.into_analog_input(&mut adc); 30 | let a4 = pins.a4.into_analog_input(&mut adc); 31 | let a5 = pins.a5.into_analog_input(&mut adc); 32 | 33 | loop { 34 | let values = [ 35 | a0.analog_read(&mut adc), 36 | a1.analog_read(&mut adc), 37 | a2.analog_read(&mut adc), 38 | a3.analog_read(&mut adc), 39 | a4.analog_read(&mut adc), 40 | a5.analog_read(&mut adc), 41 | ]; 42 | 43 | for (i, v) in values.iter().enumerate() { 44 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 45 | } 46 | 47 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 48 | arduino_hal::delay_ms(1000); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mcu/attiny-hal/src/eeprom.rs: -------------------------------------------------------------------------------- 1 | //! EEPROM 2 | //! 3 | //! # Example 4 | //! 5 | //! For full source code, please refer to the ATmega EEPROM example: 6 | //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) 7 | //! 8 | //! ``` 9 | //! const BOOT_COUNT_OFFSET: u16 = 0; 10 | //! 11 | //! let dp = attiny_hal::Peripherals::take().unwrap(); 12 | //! let mut eeprom = Eeprom::new(dp.EEPROM); 13 | //! 14 | //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); 15 | //! boot_count = boot_count.wrapping_add(1); 16 | //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); 17 | //! 18 | //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); 19 | //! ``` 20 | 21 | pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; 22 | 23 | pub type Eeprom = avr_hal_generic::eeprom::Eeprom; 24 | 25 | #[cfg(feature = "attiny2313")] 26 | avr_hal_generic::impl_eeprom_attiny! { 27 | hal: crate::Attiny, 28 | peripheral: crate::pac::EEPROM, 29 | capacity: 128, 30 | addr_width: u8, 31 | set_address: |peripheral, address| { 32 | peripheral.eear.write(|w| w.bits(address)); 33 | }, 34 | } 35 | 36 | #[cfg(any(feature = "attiny167", feature = "attiny85"))] 37 | avr_hal_generic::impl_eeprom_attiny! { 38 | hal: crate::Attiny, 39 | peripheral: crate::pac::EEPROM, 40 | capacity: 512, 41 | addr_width: u16, 42 | set_address: |peripheral, address| { 43 | peripheral.eear.write(|w| w.bits(address)); 44 | }, 45 | } 46 | 47 | #[cfg(feature = "attiny88")] 48 | avr_hal_generic::impl_eeprom_attiny! { 49 | hal: crate::Attiny, 50 | peripheral: crate::pac::EEPROM, 51 | capacity: 64, 52 | addr_width: u8, 53 | set_address: |peripheral, address| { 54 | peripheral.eearl.write(|w| w.bits(address)); 55 | }, 56 | } 57 | -------------------------------------------------------------------------------- /mcu/attiny-hal/src/port.rs: -------------------------------------------------------------------------------- 1 | //! Port 2 | //! 3 | //! # Example 4 | //! 5 | //! For full source code, please refer to the ATmega port example: 6 | //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs) 7 | //! 8 | //! ``` 9 | //! let dp = attiny_hal::Peripherals::take().unwrap(); 10 | //! let pins = attiny_hal::pins!(dp); 11 | //! 12 | //! let mut led = pins.pb2.into_output(); 13 | //! 14 | //! loop { 15 | //! led.toggle(); 16 | //! delay_ms(1000); 17 | //! } 18 | //! ``` 19 | 20 | pub use avr_hal_generic::port::{mode, PinMode, PinOps}; 21 | 22 | #[cfg(feature = "attiny2313")] 23 | avr_hal_generic::impl_port_traditional! { 24 | enum Ports { 25 | A: crate::pac::PORTA = [0, 1, 2], 26 | B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], 27 | D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6], 28 | } 29 | } 30 | 31 | #[cfg(feature = "attiny167")] 32 | avr_hal_generic::impl_port_traditional! { 33 | enum Ports { 34 | A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], 35 | B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], 36 | } 37 | } 38 | 39 | #[cfg(feature = "attiny84")] 40 | avr_hal_generic::impl_port_traditional! { 41 | enum Ports { 42 | A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7], 43 | B: crate::pac::PORTB = [0, 1, 2, 3], 44 | } 45 | } 46 | 47 | #[cfg(feature = "attiny85")] 48 | avr_hal_generic::impl_port_traditional! { 49 | enum Ports { 50 | B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5], 51 | } 52 | } 53 | 54 | #[cfg(feature = "attiny88")] 55 | avr_hal_generic::impl_port_traditional! { 56 | enum Ports { 57 | A: crate::pac::PORTA = [0, 1, 2, 3], 58 | B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7], 59 | C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7], 60 | D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7], 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /mcu/attiny-hal/src/wdt.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | pub use avr_hal_generic::wdt::{Timeout, WdtOps}; 3 | 4 | pub type Wdt = avr_hal_generic::wdt::Wdt; 5 | 6 | #[cfg(any(feature = "attiny85", feature = "attiny167", feature = "attiny2313"))] 7 | avr_hal_generic::impl_wdt! { 8 | hal: crate::Attiny, 9 | peripheral: crate::pac::WDT, 10 | mcusr: crate::pac::cpu::MCUSR, 11 | wdtcsr_name: wdtcr, 12 | timeout: |to, w| match to { 13 | Timeout::Ms16 => w.wdpl().cycles_2k_512k(), 14 | Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), 15 | Timeout::Ms64 => w.wdpl().cycles_8k(), 16 | Timeout::Ms125 => w.wdpl().cycles_16k(), 17 | Timeout::Ms250 => w.wdpl().cycles_32k(), 18 | Timeout::Ms500 => w.wdpl().cycles_64k(), 19 | Timeout::Ms1000 => w.wdpl().cycles_128k(), 20 | Timeout::Ms2000 => w.wdpl().cycles_256k(), 21 | Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), 22 | Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), 23 | }, 24 | } 25 | 26 | #[cfg(any(feature = "attiny84", feature = "attiny88"))] 27 | avr_hal_generic::impl_wdt! { 28 | hal: crate::Attiny, 29 | peripheral: crate::pac::WDT, 30 | mcusr: crate::pac::cpu::MCUSR, 31 | wdtcsr_name: wdtcsr, 32 | timeout: |to, w| match to { 33 | Timeout::Ms16 => w.wdpl().cycles_2k_512k(), 34 | Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), 35 | Timeout::Ms64 => w.wdpl().cycles_8k(), 36 | Timeout::Ms125 => w.wdpl().cycles_16k(), 37 | Timeout::Ms250 => w.wdpl().cycles_32k(), 38 | Timeout::Ms500 => w.wdpl().cycles_64k(), 39 | Timeout::Ms1000 => w.wdpl().cycles_128k(), 40 | Timeout::Ms2000 => w.wdpl().cycles_256k(), 41 | Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), 42 | Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-74hc595.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * Code sample to work with 74HC595 shift register, 4 | * wired as in https://lastminuteengineers.com/74hc595-shift-register-arduino-tutorial/ 5 | * 6 | * Connections 7 | * ----------- 8 | * 9 | * - D4: SER (14) 10 | * - D5: RCLK (12) 11 | * - D6: SRCLK (11) 12 | */ 13 | 14 | #![no_std] 15 | #![no_main] 16 | 17 | use panic_halt as _; 18 | 19 | use arduino_hal::{ 20 | hal::port::{PD4, PD5, PD6}, 21 | port::{mode::Output, Pin}, 22 | }; 23 | 24 | fn shift_out(data_pin: &mut Pin, clock_pin: &mut Pin, data: &u8) { 25 | for i in 0..8 { 26 | let n = data & (1 << i); 27 | 28 | if n == 0 { 29 | data_pin.set_low(); 30 | } else { 31 | data_pin.set_high(); 32 | } 33 | 34 | clock_pin.set_high(); 35 | clock_pin.set_low(); 36 | } 37 | } 38 | 39 | fn update_shift_register( 40 | data_pin: &mut Pin, 41 | latch_pin: &mut Pin, 42 | clock_pin: &mut Pin, 43 | data: &u8, 44 | ) { 45 | latch_pin.set_low(); 46 | 47 | shift_out(data_pin, clock_pin, data); 48 | 49 | latch_pin.set_high(); 50 | } 51 | 52 | #[arduino_hal::entry] 53 | fn main() -> ! { 54 | let dp = arduino_hal::Peripherals::take().unwrap(); 55 | let pins = arduino_hal::pins!(dp); 56 | 57 | let mut data_pin = pins.d4.into_output(); 58 | let mut latch_pin = pins.d5.into_output(); 59 | let mut clock_pin = pins.d6.into_output(); 60 | 61 | loop { 62 | let mut data: u8 = 0; 63 | 64 | update_shift_register(&mut data_pin, &mut latch_pin, &mut clock_pin, &data); 65 | arduino_hal::delay_ms(500); 66 | 67 | for i in 0..8 { 68 | data |= 1 << i; 69 | 70 | update_shift_register(&mut data_pin, &mut latch_pin, &mut clock_pin, &data); 71 | arduino_hal::delay_ms(500); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /mcu/atmega-hal/src/wdt.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | pub use avr_hal_generic::wdt::{Timeout, WdtOps}; 3 | 4 | pub type Wdt = avr_hal_generic::wdt::Wdt; 5 | 6 | #[cfg(not(any(feature = "atmega8", feature = "atmega32a", feature = "atmega128a")))] 7 | avr_hal_generic::impl_wdt! { 8 | hal: crate::Atmega, 9 | peripheral: crate::pac::WDT, 10 | mcusr: crate::pac::cpu::MCUSR, 11 | wdtcsr_name: wdtcsr, 12 | timeout: |to, w| match to { 13 | Timeout::Ms16 => w.wdpl().cycles_2k_512k(), 14 | Timeout::Ms32 => w.wdpl().cycles_4k_1024k(), 15 | Timeout::Ms64 => w.wdpl().cycles_8k(), 16 | Timeout::Ms125 => w.wdpl().cycles_16k(), 17 | Timeout::Ms250 => w.wdpl().cycles_32k(), 18 | Timeout::Ms500 => w.wdpl().cycles_64k(), 19 | Timeout::Ms1000 => w.wdpl().cycles_128k(), 20 | Timeout::Ms2000 => w.wdpl().cycles_256k(), 21 | Timeout::Ms4000 => w.wdph().set_bit().wdpl().cycles_2k_512k(), 22 | Timeout::Ms8000 => w.wdph().set_bit().wdpl().cycles_4k_1024k(), 23 | }, 24 | } 25 | 26 | #[cfg(any(feature = "atmega8", feature = "atmega32a", feature = "atmega128a"))] 27 | avr_hal_generic::impl_wdt! { 28 | hal: crate::Atmega, 29 | peripheral: crate::pac::WDT, 30 | mcusr: crate::pac::cpu::MCUCSR, 31 | wdtcsr_name: wdtcr, 32 | timeout: |to, w| match to { 33 | Timeout::Ms16 => w.wdpl().cycles_16k(), 34 | Timeout::Ms32 => w.wdpl().cycles_32k(), 35 | Timeout::Ms64 => w.wdpl().cycles_64k(), 36 | Timeout::Ms125 => w.wdpl().cycles_128k(), 37 | Timeout::Ms250 => w.wdpl().cycles_256k(), 38 | Timeout::Ms500 => w.wdpl().cycles_512k(), 39 | Timeout::Ms1000 => w.wdpl().cycles_1024k(), 40 | Timeout::Ms2000 => w.wdpl().cycles_2048k(), 41 | Timeout::Ms4000 => panic!(), // Does not exist for ATmega8 ... 42 | Timeout::Ms8000 => panic!() // Does not exist for ATmega8 ... 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /mcu/attiny-hal/src/spi.rs: -------------------------------------------------------------------------------- 1 | //! SPI 2 | //! 3 | //! # Example 4 | //! 5 | //! For full source code, please refer to the ATmega SPI example: 6 | //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) 7 | //! 8 | //! ``` 9 | //! let dp = attiny_hal::Peripherals::take().unwrap(); 10 | //! let pins = attiny_hal::pins!(dp); 11 | //! 12 | //! let (mut spi, mut cs) = spi::Spi::new( 13 | //! dp.SPI, 14 | //! pins.pa4.into_output(), 15 | //! pins.pa6.into_output(), 16 | //! pins.pa5.into_pull_up_input(), 17 | //! pins.pa3.into_output(), 18 | //! spi::Settings::default(), 19 | //! ); 20 | //! 21 | //! let data_out = b"Hello World!"; 22 | //! let mut data_in = [0u8; 12]; 23 | //! 24 | //! cs.set_low().unwrap(); 25 | //! spi.transfer(&mut data_in, data_out).unwrap(); 26 | //! cs.set_high().unwrap(); 27 | //! 28 | //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); 29 | //! ``` 30 | 31 | 32 | #[allow(unused_imports)] 33 | use crate::port; 34 | pub use avr_hal_generic::spi::*; 35 | 36 | #[cfg(feature = "attiny88")] 37 | pub type Spi = avr_hal_generic::spi::Spi< 38 | crate::Attiny, 39 | crate::pac::SPI, 40 | port::PB5, 41 | port::PB3, 42 | port::PB4, 43 | port::PB2, 44 | >; 45 | #[cfg(feature = "attiny88")] 46 | avr_hal_generic::impl_spi! { 47 | hal: crate::Attiny, 48 | peripheral: crate::pac::SPI, 49 | sclk: port::PB5, 50 | mosi: port::PB3, 51 | miso: port::PB4, 52 | cs: port::PB2, 53 | } 54 | 55 | #[cfg(feature = "attiny167")] 56 | pub type Spi = avr_hal_generic::spi::Spi< 57 | crate::Attiny, 58 | crate::pac::SPI, 59 | port::PA5, 60 | port::PA4, 61 | port::PA2, 62 | port::PA6, 63 | >; 64 | #[cfg(feature = "attiny167")] 65 | avr_hal_generic::impl_spi! { 66 | hal: crate::Attiny, 67 | peripheral: crate::pac::SPI, 68 | sclk: port::PA5, 69 | mosi: port::PA4, 70 | miso: port::PA2, 71 | cs: port::PA6, 72 | } 73 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-spi-feedback.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuration consists of connecting a 3 | //! jumper directly from pin `PB2` to pin `PB3`. 4 | //! 5 | //! Run the program using `cargo run`. 6 | //! You should see it output the line `data: 42` repeatedly. 7 | //! If the output you see is `data: 255`, you may need to check your jumper. 8 | 9 | #![no_std] 10 | #![no_main] 11 | 12 | use atmega_hal::delay::Delay; 13 | use atmega_hal::spi; 14 | use atmega_hal::usart::{Baudrate, Usart}; 15 | use embedded_hal::delay::DelayNs; 16 | use embedded_hal::spi::SpiBus; 17 | use panic_halt as _; 18 | 19 | // Define core clock. This can be used in the rest of the project. 20 | type CoreClock = atmega_hal::clock::MHz16; 21 | 22 | #[avr_device::entry] 23 | fn main() -> ! { 24 | let dp = atmega_hal::Peripherals::take().unwrap(); 25 | let pins = atmega_hal::pins!(dp); 26 | 27 | let mut delay = Delay::::new(); 28 | 29 | // set up serial interface for text output 30 | let mut serial = Usart::new( 31 | dp.USART0, 32 | pins.pe0, 33 | pins.pe1.into_output(), 34 | Baudrate::::new(57600), 35 | ); 36 | 37 | // Create SPI interface. 38 | let (mut spi, _) = spi::Spi::new( 39 | dp.SPI, 40 | pins.pb1.into_output(), 41 | pins.pb2.into_output(), 42 | pins.pb3.into_pull_up_input(), 43 | pins.pb0.into_output(), 44 | spi::Settings::default(), 45 | ); 46 | 47 | loop { 48 | // Send a byte 49 | let data_out: [u8; 1] = [42]; 50 | let mut data_in: [u8; 1] = [0]; 51 | // Send a byte 52 | // Because MISO is connected to MOSI, the read data should be the same 53 | spi.transfer(&mut data_in, &data_out).unwrap(); 54 | 55 | ufmt::uwriteln!(&mut serial, "data: {}\r", data_in[0]).unwrap(); 56 | delay.delay_ms(1000); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ravedude/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "naersk": { 4 | "inputs": { 5 | "nixpkgs": "nixpkgs" 6 | }, 7 | "locked": { 8 | "lastModified": 1679567394, 9 | "narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=", 10 | "owner": "nix-community", 11 | "repo": "naersk", 12 | "rev": "88cd22380154a2c36799fe8098888f0f59861a15", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "nix-community", 17 | "repo": "naersk", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 0, 24 | "narHash": "sha256-eOnCn0o3I6LP48fAi8xWFcn49V2rL7oX5jCtJTeN1LI=", 25 | "path": "/nix/store/jcb1zr0g47d0cd13jfvg64fwczy2cfd7-source", 26 | "type": "path" 27 | }, 28 | "original": { 29 | "id": "nixpkgs", 30 | "type": "indirect" 31 | } 32 | }, 33 | "nixpkgs_2": { 34 | "locked": { 35 | "lastModified": 0, 36 | "narHash": "sha256-eOnCn0o3I6LP48fAi8xWFcn49V2rL7oX5jCtJTeN1LI=", 37 | "path": "/nix/store/jcb1zr0g47d0cd13jfvg64fwczy2cfd7-source", 38 | "type": "path" 39 | }, 40 | "original": { 41 | "id": "nixpkgs", 42 | "type": "indirect" 43 | } 44 | }, 45 | "root": { 46 | "inputs": { 47 | "naersk": "naersk", 48 | "nixpkgs": "nixpkgs_2", 49 | "utils": "utils" 50 | } 51 | }, 52 | "utils": { 53 | "locked": { 54 | "lastModified": 1680776469, 55 | "narHash": "sha256-3CXUDK/3q/kieWtdsYpDOBJw3Gw4Af6x+2EiSnIkNQw=", 56 | "owner": "numtide", 57 | "repo": "flake-utils", 58 | "rev": "411e8764155aa9354dbcd6d5faaeb97e9e3dce24", 59 | "type": "github" 60 | }, 61 | "original": { 62 | "owner": "numtide", 63 | "repo": "flake-utils", 64 | "type": "github" 65 | } 66 | } 67 | }, 68 | "root": "root", 69 | "version": 7 70 | } 71 | -------------------------------------------------------------------------------- /arduino-hal/src/port/mod.rs: -------------------------------------------------------------------------------- 1 | //! GPIO & Pin control. 2 | //! 3 | //! This module contains a [`Pins`] struct which represents all pins of the board. The [`Pins`] 4 | //! struct is most easily constructed using the [`arduino_hal::pins!()`][crate::pins] macro: 5 | //! 6 | //! ```no_run 7 | //! let dp = arduino_hal::Peripherals::take().unwrap(); 8 | //! let pins = arduino_hal::pins!(dp); 9 | //! ``` 10 | //! 11 | //! Additionally, the [`mode`] submodule contains all valid types for the `MODE` generic parameter 12 | //! of a pin. The [`Pin`] type-alias represents a pin which can represent _any_ of the pins 13 | //! dynamically (while usually each pin has its own type). 14 | //! 15 | //! Check the documentation for [`avr_hal_generic::port::Pin`] for a detailed explanation of GPIO 16 | //! pins in `avr-hal`. 17 | 18 | #[cfg(feature = "arduino-diecimila")] 19 | mod diecimila; 20 | #[cfg(feature = "arduino-diecimila")] 21 | pub use diecimila::*; 22 | #[cfg(feature = "arduino-leonardo")] 23 | mod leonardo; 24 | #[cfg(feature = "arduino-leonardo")] 25 | pub use leonardo::*; 26 | #[cfg(any(feature = "arduino-mega2560", feature = "arduino-mega1280"))] 27 | mod mega; 28 | #[cfg(any(feature = "arduino-mega2560", feature = "arduino-mega1280"))] 29 | pub use mega::*; 30 | #[cfg(any( 31 | feature = "arduino-nano", 32 | feature = "arduino-uno", 33 | feature = "nano168", 34 | feature = "sparkfun-promini-3v3", 35 | feature = "sparkfun-promini-5v" 36 | ))] 37 | mod uno; 38 | #[cfg(any( 39 | feature = "arduino-nano", 40 | feature = "arduino-uno", 41 | feature = "nano168", 42 | feature = "sparkfun-promini-3v3", 43 | feature = "sparkfun-promini-5v" 44 | ))] 45 | pub use uno::*; 46 | #[cfg(feature = "sparkfun-promicro")] 47 | mod promicro; 48 | #[cfg(feature = "sparkfun-promicro")] 49 | pub use promicro::*; 50 | #[cfg(feature = "trinket-pro")] 51 | mod trinket_pro; 52 | #[cfg(feature = "trinket-pro")] 53 | pub use trinket_pro::*; 54 | #[cfg(feature = "trinket")] 55 | mod trinket; 56 | #[cfg(feature = "trinket")] 57 | pub use trinket::*; 58 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-println.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * This is an example of how one can define a println!() macro which can be called anywhere to 3 | * write data to the console. 4 | * 5 | * Keep in mind that this will enter a critical section while printing so no interrupts can be 6 | * served in the meantime. 7 | */ 8 | #![no_std] 9 | #![no_main] 10 | 11 | use panic_halt as _; 12 | 13 | use avr_device::interrupt; 14 | use core::cell::RefCell; 15 | 16 | type Console = arduino_hal::hal::usart::Usart0; 17 | static CONSOLE: interrupt::Mutex>> = 18 | interrupt::Mutex::new(RefCell::new(None)); 19 | 20 | macro_rules! print { 21 | ($($t:tt)*) => { 22 | interrupt::free( 23 | |cs| { 24 | if let Some(console) = CONSOLE.borrow(cs).borrow_mut().as_mut() { 25 | let _ = ufmt::uwrite!(console, $($t)*); 26 | } 27 | }, 28 | ) 29 | }; 30 | } 31 | 32 | macro_rules! println { 33 | ($($t:tt)*) => { 34 | interrupt::free( 35 | |cs| { 36 | if let Some(console) = CONSOLE.borrow(cs).borrow_mut().as_mut() { 37 | let _ = ufmt::uwriteln!(console, $($t)*); 38 | } 39 | }, 40 | ) 41 | }; 42 | } 43 | 44 | fn put_console(console: Console) { 45 | interrupt::free(|cs| { 46 | *CONSOLE.borrow(cs).borrow_mut() = Some(console); 47 | }) 48 | } 49 | 50 | fn subfunction() { 51 | println!("We can also call println!() in a subfunction!"); 52 | } 53 | 54 | fn demo_print_without_ln() { 55 | for i in 0..10 { 56 | print!("{} ", i); 57 | } 58 | println!("numbers!"); 59 | } 60 | 61 | #[arduino_hal::entry] 62 | fn main() -> ! { 63 | let dp = arduino_hal::Peripherals::take().unwrap(); 64 | let pins = arduino_hal::pins!(dp); 65 | let serial = arduino_hal::default_serial!(dp, pins, 57600); 66 | put_console(serial); 67 | 68 | println!("Hello from main!"); 69 | subfunction(); 70 | demo_print_without_ln(); 71 | 72 | loop {} 73 | } 74 | -------------------------------------------------------------------------------- /mcu/atmega-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "atmega-hal" 3 | version = "0.1.0" 4 | 5 | authors = ["Rahix "] 6 | edition = "2021" 7 | description = "HAL crate for ATmega-series AVR microcontrollers" 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rahix/avr-hal" 10 | keywords = ["avr", "arduino"] 11 | categories = ["no-std", "embedded", "hardware-support"] 12 | 13 | [features] 14 | rt = ["avr-device/rt"] 15 | device-selected = [] 16 | enable-extra-adc = [] 17 | atmega48p = ["avr-device/atmega48p", "device-selected"] 18 | atmega164pa = ["avr-device/atmega164pa", "device-selected"] 19 | atmega168 = ["avr-device/atmega168", "device-selected"] 20 | atmega328p = ["avr-device/atmega328p", "device-selected"] 21 | atmega328pb = ["avr-device/atmega328pb", "device-selected"] 22 | atmega32a = ["avr-device/atmega32a", "device-selected"] 23 | atmega32u4 = ["avr-device/atmega32u4", "device-selected"] 24 | atmega2560 = ["avr-device/atmega2560", "device-selected"] 25 | atmega128a = ["avr-device/atmega128a", "device-selected"] 26 | atmega1280 = ["avr-device/atmega1280", "device-selected"] 27 | atmega1284p = ["avr-device/atmega1284p", "device-selected"] 28 | atmega8 = ["avr-device/atmega8", "device-selected"] 29 | 30 | critical-section-impl = ["avr-device/critical-section-impl"] 31 | 32 | # Allow certain downstream crates to overwrite the device selection error by themselves. 33 | disable-device-selection-error = [] 34 | 35 | # We must select a microcontroller to build on docs.rs 36 | docsrs = ["atmega328p"] 37 | 38 | [dependencies] 39 | avr-hal-generic = { path = "../../avr-hal-generic/" } 40 | 41 | [dependencies.avr-device] 42 | version = "0.7" 43 | 44 | # Because this crate has its own check that at least one device is selected, we 45 | # can safely "circumvent" the check in `avr-device`. 46 | # 47 | # Why would we want that? Otherwise, as `avr-device` is compiled first, its 48 | # error will be shown and ours won't which leads to a degraded user experience 49 | # as the displayed error message does not really tell what needs to be done... 50 | features = ["device-selected"] 51 | 52 | [package.metadata.docs.rs] 53 | features = ["docsrs"] 54 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | // The ATmega168 chip does not support the temperature functionality. 21 | ); 22 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 24 | 25 | let a0 = pins.a0.into_analog_input(&mut adc); 26 | let a1 = pins.a1.into_analog_input(&mut adc); 27 | let a2 = pins.a2.into_analog_input(&mut adc); 28 | let a3 = pins.a3.into_analog_input(&mut adc); 29 | let a4 = pins.a4.into_analog_input(&mut adc); 30 | let a5 = pins.a5.into_analog_input(&mut adc); 31 | 32 | loop { 33 | let values = [ 34 | a0.analog_read(&mut adc), 35 | a1.analog_read(&mut adc), 36 | a2.analog_read(&mut adc), 37 | a3.analog_read(&mut adc), 38 | a4.analog_read(&mut adc), 39 | a5.analog_read(&mut adc), 40 | ]; 41 | 42 | for (i, v) in values.iter().enumerate() { 43 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 44 | } 45 | 46 | // Nano clone (with ATmega168) has two more ADC pins A6 and A7. Accessing them works a bit different from 47 | // the other pins as they are not normal IO pins. The code below shows how it works. 48 | let (a6, a7) = ( 49 | adc.read_blocking(&adc::channel::ADC6), 50 | adc.read_blocking(&adc::channel::ADC7), 51 | ); 52 | ufmt::uwrite!(&mut serial, "A6: {} A7: {}", a6, a7).unwrap_infallible(); 53 | 54 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 55 | arduino_hal::delay_ms(1000); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ravedude/src/console.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use std::io::Read as _; 3 | use std::io::Write as _; 4 | 5 | pub fn open(port: &std::path::Path, baudrate: u32) -> anyhow::Result<()> { 6 | let mut rx = serialport::new(port.to_string_lossy(), baudrate) 7 | .timeout(std::time::Duration::from_secs(2)) 8 | .open_native() 9 | .with_context(|| format!("failed to open serial port `{}`", port.display()))?; 10 | let mut tx = rx.try_clone_native()?; 11 | 12 | let mut stdin = std::io::stdin(); 13 | let mut stdout = std::io::stdout(); 14 | 15 | // Set a CTRL+C handler to terminate cleanly instead of with an error. 16 | ctrlc::set_handler(move || { 17 | eprintln!(""); 18 | eprintln!("Exiting."); 19 | std::process::exit(0); 20 | }) 21 | .context("failed setting a CTRL+C handler")?; 22 | 23 | // Spawn a thread for the receiving end because stdio is not portably non-blocking... 24 | std::thread::spawn(move || loop { 25 | #[cfg(not(target_os = "windows"))] 26 | let mut buf = [0u8; 4098]; 27 | 28 | // Use buffer size 1 for windows because it blocks on rx.read until the buffer is full 29 | #[cfg(target_os = "windows")] 30 | let mut buf = [0u8; 1]; 31 | 32 | match rx.read(&mut buf) { 33 | Ok(count) => { 34 | #[cfg(target_os = "windows")] 35 | { 36 | // On windows, we must ensure that we are not sending anything outside of the 37 | // ASCII range. 38 | for byte in &mut buf[..count] { 39 | if *byte & 0x80 != 0 { 40 | *byte = '?'.try_into().unwrap(); 41 | } 42 | } 43 | } 44 | stdout.write(&buf[..count]).unwrap(); 45 | stdout.flush().unwrap(); 46 | } 47 | Err(e) => { 48 | assert!(e.kind() == std::io::ErrorKind::TimedOut); 49 | } 50 | } 51 | }); 52 | 53 | loop { 54 | let mut buf = [0u8; 4098]; 55 | let count = stdin.read(&mut buf)?; 56 | tx.write(&buf[..count])?; 57 | tx.flush()?; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-rgb-led.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to fade an RGB LED connected to an Arduino board. 2 | //! 3 | //! Wiring: 4 | //! - Connect the common cathode of the RGB LED to GND. 5 | //! - Connect the red LED anode to pin D6 through a current-limiting resistor. 6 | //! - Connect the green LED anode to pin D5 through a current-limiting resistor. 7 | //! - Connect the blue LED anode to pin D3 through a current-limiting resistor. 8 | //! 9 | //! Note: The current-limiting resistor values depend on the specific RGB LED and the desired brightness. 10 | //! Typically, a resistor value between 220Ω and 1kΩ is suitable. 11 | 12 | #![no_std] 13 | #![no_main] 14 | 15 | use panic_halt as _; 16 | use arduino_hal::simple_pwm::IntoPwmPin; 17 | use arduino_hal::simple_pwm::Prescaler; 18 | use arduino_hal::simple_pwm::{Timer3Pwm, Timer4Pwm}; 19 | 20 | #[arduino_hal::entry] 21 | fn main() -> ! { 22 | let dp = arduino_hal::Peripherals::take().unwrap(); 23 | let pins = arduino_hal::pins!(dp); 24 | 25 | let timer0 = Timer4Pwm::new(dp.TC4, Prescaler::Prescale64); 26 | let timer1 = Timer3Pwm::new(dp.TC3, Prescaler::Prescale64); 27 | 28 | let mut d6 = pins.d6.into_output().into_pwm(&timer0); 29 | let mut d5 = pins.d5.into_output().into_pwm(&timer1); 30 | let mut d3 = pins.d3.into_output().into_pwm(&timer1); 31 | 32 | let max_duty_d6 = d6.get_max_duty(); 33 | let max_duty_d5 = d5.get_max_duty(); 34 | let max_duty_d3 = d3.get_max_duty(); 35 | 36 | let delay_time = 10; 37 | 38 | d6.enable(); 39 | d5.enable(); 40 | d3.enable(); 41 | 42 | loop { 43 | // Fade in/out red 44 | for i in (0..=max_duty_d6).chain((0..=max_duty_d6 - 1).rev()) { 45 | d6.set_duty(i); 46 | arduino_hal::delay_ms(delay_time); 47 | } 48 | 49 | // Fade in/out green 50 | for i in (0..=max_duty_d5).chain((0..=max_duty_d5 - 1).rev()) { 51 | d5.set_duty(i); 52 | arduino_hal::delay_ms(delay_time); 53 | } 54 | 55 | // Fade in/out blue 56 | for i in (0..=max_duty_d3).chain((0..=max_duty_d3 - 1).rev()) { 57 | d3.set_duty(i); 58 | arduino_hal::delay_ms(delay_time); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-ext-interrupt.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Blinks a 4 leds in sequence on pins D3 - D6. When an external interrupt on D2/INT0 comes in 3 | * the sequence is reversed. 4 | * 5 | * Note: The use of the either crate requires the deactivation of std to use it in core. See the Cargo.toml 6 | * in this directory for details. 7 | */ 8 | #![no_std] 9 | #![no_main] 10 | #![feature(abi_avr_interrupt)] 11 | 12 | use arduino_hal::port::{mode, Pin}; 13 | use core::sync::atomic::{AtomicBool, Ordering}; 14 | use either::*; 15 | use panic_halt as _; 16 | 17 | static REVERSED: AtomicBool = AtomicBool::new(false); 18 | 19 | fn is_reversed() -> bool { 20 | REVERSED.load(Ordering::SeqCst) 21 | } 22 | 23 | #[avr_device::interrupt(atmega328p)] 24 | fn INT0() { 25 | let current = REVERSED.load(Ordering::SeqCst); 26 | REVERSED.store(!current, Ordering::SeqCst); 27 | } 28 | 29 | fn blink_for_range(range: impl Iterator, leds: &mut [Pin]) { 30 | range.map(|i| i * 100).for_each(|ms| { 31 | let iter = if is_reversed() { 32 | Left(leds.iter_mut().rev()) 33 | } else { 34 | Right(leds.iter_mut()) 35 | }; 36 | iter.for_each(|led| { 37 | led.toggle(); 38 | arduino_hal::delay_ms(ms as u16); 39 | }) 40 | }); 41 | } 42 | 43 | #[arduino_hal::entry] 44 | fn main() -> ! { 45 | let dp = arduino_hal::Peripherals::take().unwrap(); 46 | let pins = arduino_hal::pins!(dp); 47 | 48 | // thanks to tsemczyszyn and Rahix: https://github.com/Rahix/avr-hal/issues/240 49 | // Configure INT0 for falling edge. 0x03 would be rising edge. 50 | dp.EXINT.eicra.modify(|_, w| w.isc0().bits(0x02)); 51 | // Enable the INT0 interrupt source. 52 | dp.EXINT.eimsk.modify(|_, w| w.int0().set_bit()); 53 | 54 | let mut leds: [Pin; 4] = [ 55 | pins.d3.into_output().downgrade(), 56 | pins.d4.into_output().downgrade(), 57 | pins.d5.into_output().downgrade(), 58 | pins.d6.into_output().downgrade(), 59 | ]; 60 | 61 | unsafe { avr_device::interrupt::enable() }; 62 | 63 | loop { 64 | blink_for_range(0..10, &mut leds); 65 | blink_for_range((0..10).rev(), &mut leds); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/arduino-nano/src/bin/nano-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd, tmp) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | adc.read_blocking(&adc::channel::Temperature), 21 | ); 22 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 23 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 24 | ufmt::uwriteln!(&mut serial, "Temperature: {}", tmp).unwrap_infallible(); 25 | 26 | let a0 = pins.a0.into_analog_input(&mut adc); 27 | let a1 = pins.a1.into_analog_input(&mut adc); 28 | let a2 = pins.a2.into_analog_input(&mut adc); 29 | let a3 = pins.a3.into_analog_input(&mut adc); 30 | let a4 = pins.a4.into_analog_input(&mut adc); 31 | let a5 = pins.a5.into_analog_input(&mut adc); 32 | 33 | loop { 34 | let values = [ 35 | a0.analog_read(&mut adc), 36 | a1.analog_read(&mut adc), 37 | a2.analog_read(&mut adc), 38 | a3.analog_read(&mut adc), 39 | a4.analog_read(&mut adc), 40 | a5.analog_read(&mut adc), 41 | ]; 42 | 43 | for (i, v) in values.iter().enumerate() { 44 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 45 | } 46 | 47 | // Arduino Nano has two more ADC pins A6 and A7. Accessing them works a bit different from 48 | // the other pins as they are not normal IO pins. The code below shows how it works. 49 | let (a6, a7) = ( 50 | adc.read_blocking(&adc::channel::ADC6), 51 | adc.read_blocking(&adc::channel::ADC7), 52 | ); 53 | ufmt::uwrite!(&mut serial, "A6: {} A7: {}", a6, a7).unwrap_infallible(); 54 | 55 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 56 | arduino_hal::delay_ms(1000); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/arduino-mega1280/src/bin/mega1280-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | ); 21 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 22 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 23 | 24 | // To store multiple channels in an array, we use the `into_channel()` method. 25 | let channels: [adc::Channel; 16] = [ 26 | pins.a0.into_analog_input(&mut adc).into_channel(), 27 | pins.a1.into_analog_input(&mut adc).into_channel(), 28 | pins.a2.into_analog_input(&mut adc).into_channel(), 29 | pins.a3.into_analog_input(&mut adc).into_channel(), 30 | pins.a4.into_analog_input(&mut adc).into_channel(), 31 | pins.a5.into_analog_input(&mut adc).into_channel(), 32 | pins.a6.into_analog_input(&mut adc).into_channel(), 33 | pins.a7.into_analog_input(&mut adc).into_channel(), 34 | pins.a8.into_analog_input(&mut adc).into_channel(), 35 | pins.a9.into_analog_input(&mut adc).into_channel(), 36 | pins.a10.into_analog_input(&mut adc).into_channel(), 37 | pins.a11.into_analog_input(&mut adc).into_channel(), 38 | pins.a12.into_analog_input(&mut adc).into_channel(), 39 | pins.a13.into_analog_input(&mut adc).into_channel(), 40 | pins.a14.into_analog_input(&mut adc).into_channel(), 41 | pins.a15.into_analog_input(&mut adc).into_channel(), 42 | ]; 43 | 44 | loop { 45 | for (i, ch) in channels.iter().enumerate() { 46 | let v = adc.read_blocking(ch); 47 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 48 | } 49 | 50 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 51 | arduino_hal::delay_ms(1000); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/arduino-mega2560/src/bin/mega2560-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use arduino_hal::prelude::*; 5 | use panic_halt as _; 6 | 7 | use arduino_hal::adc; 8 | 9 | #[arduino_hal::entry] 10 | fn main() -> ! { 11 | let dp = arduino_hal::Peripherals::take().unwrap(); 12 | let pins = arduino_hal::pins!(dp); 13 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 14 | 15 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 16 | 17 | let (vbg, gnd) = ( 18 | adc.read_blocking(&adc::channel::Vbg), 19 | adc.read_blocking(&adc::channel::Gnd), 20 | ); 21 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 22 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 23 | 24 | // To store multiple channels in an array, we use the `into_channel()` method. 25 | let channels: [adc::Channel; 16] = [ 26 | pins.a0.into_analog_input(&mut adc).into_channel(), 27 | pins.a1.into_analog_input(&mut adc).into_channel(), 28 | pins.a2.into_analog_input(&mut adc).into_channel(), 29 | pins.a3.into_analog_input(&mut adc).into_channel(), 30 | pins.a4.into_analog_input(&mut adc).into_channel(), 31 | pins.a5.into_analog_input(&mut adc).into_channel(), 32 | pins.a6.into_analog_input(&mut adc).into_channel(), 33 | pins.a7.into_analog_input(&mut adc).into_channel(), 34 | pins.a8.into_analog_input(&mut adc).into_channel(), 35 | pins.a9.into_analog_input(&mut adc).into_channel(), 36 | pins.a10.into_analog_input(&mut adc).into_channel(), 37 | pins.a11.into_analog_input(&mut adc).into_channel(), 38 | pins.a12.into_analog_input(&mut adc).into_channel(), 39 | pins.a13.into_analog_input(&mut adc).into_channel(), 40 | pins.a14.into_analog_input(&mut adc).into_channel(), 41 | pins.a15.into_analog_input(&mut adc).into_channel(), 42 | ]; 43 | 44 | loop { 45 | for (i, ch) in channels.iter().enumerate() { 46 | let v = adc.read_blocking(ch); 47 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 48 | } 49 | 50 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 51 | arduino_hal::delay_ms(1000); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-adc.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Show readouts of all ADC channels. 3 | * 4 | * This example displays values for all ADC channels over the serial console. During startup, it 5 | * also displays the values for Vbandgap, GND, and a readout of the MCU's temperature sensor. For 6 | * the meanings of these values, please reference the ATmega328P datasheet. 7 | * 8 | * Connections 9 | * ----------- 10 | * - `A0` - `A5`: Connect analog voltages as you like to see them read out. 11 | */ 12 | #![no_std] 13 | #![no_main] 14 | 15 | use arduino_hal::prelude::*; 16 | use panic_halt as _; 17 | 18 | use arduino_hal::adc; 19 | 20 | #[arduino_hal::entry] 21 | fn main() -> ! { 22 | let dp = arduino_hal::Peripherals::take().unwrap(); 23 | let pins = arduino_hal::pins!(dp); 24 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 25 | 26 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 27 | 28 | let (vbg, gnd, tmp) = ( 29 | adc.read_blocking(&adc::channel::Vbg), 30 | adc.read_blocking(&adc::channel::Gnd), 31 | adc.read_blocking(&adc::channel::Temperature), 32 | ); 33 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap_infallible(); 34 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap_infallible(); 35 | ufmt::uwriteln!(&mut serial, "Temperature: {}", tmp).unwrap_infallible(); 36 | 37 | let a0 = pins.a0.into_analog_input(&mut adc); 38 | let a1 = pins.a1.into_analog_input(&mut adc); 39 | let a2 = pins.a2.into_analog_input(&mut adc); 40 | let a3 = pins.a3.into_analog_input(&mut adc); 41 | let a4 = pins.a4.into_analog_input(&mut adc); 42 | let a5 = pins.a5.into_analog_input(&mut adc); 43 | 44 | loop { 45 | let values = [ 46 | a0.analog_read(&mut adc), 47 | a1.analog_read(&mut adc), 48 | a2.analog_read(&mut adc), 49 | a3.analog_read(&mut adc), 50 | a4.analog_read(&mut adc), 51 | a5.analog_read(&mut adc), 52 | ]; 53 | 54 | for (i, v) in values.iter().enumerate() { 55 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap_infallible(); 56 | } 57 | 58 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 59 | arduino_hal::delay_ms(1000); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-16chan-servo-driver.rs: -------------------------------------------------------------------------------- 1 | //! Example for using an Arduno Uno with a 16-channel PCA9685 to control 2 | //! servo motors. 3 | //! 4 | //! Makes the servo on channel 0 turn clockwise, and the servo on channel 1 turn 5 | //! counterclockwise. 6 | //! 7 | //! Connections: 8 | //! ``` 9 | //! GND <-> GND 10 | //! A4 <-> SDA 11 | //! A5 <-> SCL 12 | //! 5V <-> VCC 13 | //! 14 | //! Two servo motors connected to channel 0 and channel 1. 15 | //! ``` 16 | #![no_std] 17 | #![no_main] 18 | 19 | use panic_halt as _; 20 | use pwm_pca9685::{Address, Channel, Pca9685}; 21 | 22 | #[arduino_hal::entry] 23 | fn main() -> ! { 24 | let dp = arduino_hal::Peripherals::take().unwrap(); 25 | let pins = arduino_hal::pins!(dp); 26 | 27 | // Digital pin 13 is also connected to an onboard LED marked "L" 28 | let mut led = pins.d13.into_output(); 29 | 30 | let i2c = arduino_hal::I2c::new( 31 | dp.TWI, 32 | pins.a4.into_pull_up_input(), 33 | pins.a5.into_pull_up_input(), 34 | 100_000, 35 | ); 36 | 37 | // We use 0x40 as an address as that is the first default address. 38 | let mut pwm = Pca9685::new(i2c, Address::from(0x40)).unwrap(); 39 | // This results in 60 Hz. 40 | pwm.set_prescale(100).unwrap(); 41 | pwm.enable().unwrap(); 42 | // Turn all channels on with a setting of "0". 43 | pwm.set_channel_on(Channel::All, 0).unwrap(); 44 | 45 | // These need to be tweaked based on your own servo. 46 | let servo_min = 130; // Minimum pulse length out of 4096. 47 | let servo_max = 610; // Maximum pulse length out of 4096. 48 | 49 | let mut current = servo_min; 50 | let mut factor = 1i16; 51 | 52 | loop { 53 | // Blink the LED to indicate that everything is working properly. 54 | led.toggle(); 55 | arduino_hal::delay_ms(500); 56 | led.toggle(); 57 | arduino_hal::delay_ms(500); 58 | 59 | pwm.set_channel_off(Channel::C0, current).unwrap(); 60 | pwm.set_channel_off(Channel::C1, servo_min + (servo_max - current)) 61 | .unwrap(); 62 | 63 | if current == servo_max { 64 | factor -= 1; 65 | } else if current == servo_min { 66 | factor = 1; 67 | } 68 | current = (current as i16 + factor) as u16; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /keyboard-hal/src/keycodes.rs: -------------------------------------------------------------------------------- 1 | #[repr(u8)] 2 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 3 | pub enum Keycode { 4 | // Special 5 | No = 0x00, 6 | Trans = 0x01, // _______ in QMK 7 | MomentaryLayer1 = 0xF1, // Custom code for MO(_FL) 8 | MomentaryLayer2 = 0xF2, // Custom code for MO(_CL) 9 | 10 | // Standard Keys 11 | A = 0x04, 12 | B = 0x05, 13 | C = 0x06, 14 | D = 0x07, 15 | E = 0x08, 16 | F = 0x09, 17 | G = 0x0A, 18 | H = 0x0B, 19 | I = 0x0C, 20 | J = 0x0D, 21 | K = 0x0E, 22 | L = 0x0F, 23 | M = 0x10, 24 | N = 0x11, 25 | O = 0x12, 26 | P = 0x13, 27 | Q = 0x14, 28 | R = 0x15, 29 | S = 0x16, 30 | T = 0x17, 31 | U = 0x18, 32 | V = 0x19, 33 | W = 0x1A, 34 | X = 0x1B, 35 | Y = 0x1C, 36 | Z = 0x1D, 37 | 38 | Num1 = 0x1E, 39 | Num2 = 0x1F, 40 | Num3 = 0x20, 41 | Num4 = 0x21, 42 | Num5 = 0x22, 43 | Num6 = 0x23, 44 | Num7 = 0x24, 45 | Num8 = 0x25, 46 | Num9 = 0x26, 47 | Num0 = 0x27, 48 | 49 | Enter = 0x28, 50 | Escape = 0x29, 51 | BSpace = 0x2A, 52 | Tab = 0x2B, 53 | Space = 0x2C, 54 | Minus = 0x2D, 55 | Equal = 0x2E, 56 | LBracket = 0x2F, 57 | RBracket = 0x30, 58 | BSlash = 0x31, 59 | Semicolon = 0x33, 60 | Quote = 0x34, 61 | Grave = 0x35, 62 | Comma = 0x36, 63 | Dot = 0x37, 64 | Slash = 0x38, 65 | Caps = 0x39, 66 | 67 | F1 = 0x3A, 68 | F2 = 0x3B, 69 | F3 = 0x3C, 70 | F4 = 0x3D, 71 | F5 = 0x3E, 72 | F6 = 0x3F, 73 | F7 = 0x40, 74 | F8 = 0x41, 75 | F9 = 0x42, 76 | F10 = 0x43, 77 | F11 = 0x44, 78 | F12 = 0x45, 79 | 80 | PScreen = 0x46, 81 | ScrollLock = 0x47, 82 | Pause = 0x48, 83 | Insert = 0x49, 84 | Home = 0x4A, 85 | PgUp = 0x4B, 86 | Delete = 0x4C, 87 | End = 0x4D, 88 | PgDown = 0x4E, 89 | 90 | Right = 0x4F, 91 | Left = 0x50, 92 | Down = 0x51, 93 | Up = 0x52, 94 | 95 | LCtrl = 0xE0, 96 | LShift = 0xE1, 97 | LAlt = 0xE2, 98 | LGui = 0xE3, 99 | RCtrl = 0xE4, 100 | RShift = 0xE5, 101 | RAlt = 0xE6, 102 | RGui = 0xE7, 103 | 104 | // Custom function keys 105 | GraveEsc = 0xF0, // QK_GESC 106 | Reset = 0xF3, // QK_BOOT 107 | } 108 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-pin-change-interrupt.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of enabling and handling pin change interrupts 3 | * 4 | * In this example we can get an interrupt when pin 2 changes 5 | * and use that to move a stepper motor. 6 | * 7 | */ 8 | #![no_std] 9 | #![no_main] 10 | #![feature(abi_avr_interrupt)] 11 | 12 | use panic_halt as _; 13 | 14 | use core::sync::atomic::{AtomicBool, Ordering}; 15 | 16 | static PIN_CHANGED: AtomicBool = AtomicBool::new(false); 17 | 18 | //This function is called on change of pin 2 19 | #[avr_device::interrupt(atmega328p)] 20 | #[allow(non_snake_case)] 21 | fn PCINT2() { 22 | PIN_CHANGED.store(true, Ordering::SeqCst); 23 | } 24 | 25 | fn rotate(flag: &AtomicBool) -> bool { 26 | avr_device::interrupt::free(|_cs| { 27 | if flag.load(Ordering::SeqCst) { 28 | flag.store(false, Ordering::SeqCst); 29 | true 30 | } else { 31 | false 32 | } 33 | }) 34 | } 35 | 36 | #[arduino_hal::entry] 37 | fn main() -> ! { 38 | let dp = arduino_hal::Peripherals::take().unwrap(); 39 | let pins = arduino_hal::pins!(dp); 40 | 41 | //Pins used to drive the stepper motor 42 | let mut dir_pin = pins.d4.into_output(); 43 | let mut step_pin = pins.d5.into_output(); 44 | 45 | //Rotary encoder attached on these pins 46 | let rotary_pins = [ 47 | pins.d2.into_floating_input().downgrade(), //CLK 48 | pins.d3.into_floating_input().downgrade(), //DT 49 | ]; 50 | 51 | // Enable the PCINT2 pin change interrupt 52 | dp.EXINT.pcicr.write(|w| unsafe { w.bits(0b100) }); 53 | 54 | // Enable pin change interrupts on PCINT18 which is pin PD2 (= d2) 55 | dp.EXINT.pcmsk2.write(|w| w.bits(0b100)); 56 | 57 | //From this point on an interrupt can happen 58 | unsafe { avr_device::interrupt::enable() }; 59 | 60 | loop { 61 | if rotate(&PIN_CHANGED) { 62 | //Check which direction the rotary encoder was turned 63 | if rotary_pins[0].is_high() != rotary_pins[1].is_high() { 64 | dir_pin.set_high(); 65 | } else { 66 | dir_pin.set_low(); 67 | } 68 | 69 | //Move the stepper motor 70 | for _ in 0..=50 { 71 | step_pin.set_high(); 72 | arduino_hal::delay_us(2000); 73 | step_pin.set_low(); 74 | arduino_hal::delay_us(2000); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-ldr.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # A light sensor application 3 | 4 | This is a simple circuit with a light dependent resistor (light sensor). 5 | According to the brightness the lightsensor is seeing a sentences like: "This is a well lit room!" are emitted using the serial USB connection. 6 | 7 | # The hardware 8 | 9 | * a ldr sensor 10 | * a 10k Ohm resistor 11 | * some patch cables/connections 12 | * The ports on the board (GND, A5, 5V) 13 | 14 | # The board layout 15 | 16 | A5----------+ 17 | | 18 | GND---10K---+--+ 19 | LDR 20 | 5V-------------+ 21 | 22 | A connection from ground to the 10K resistor, to the light defined resistor, to 5V. Additionally the Analog port 5 of the arduino needs to be connected between the 10K and light defined resistor. 23 | !*/ 24 | 25 | #![no_std] 26 | #![no_main] 27 | 28 | use arduino_hal::prelude::*; 29 | use panic_halt as _; 30 | 31 | #[arduino_hal::entry] 32 | fn main() -> ! { 33 | let dp = arduino_hal::Peripherals::take().unwrap(); 34 | // setup the pins 35 | let pins = arduino_hal::pins!(dp); 36 | // setup the serial connection for the output. 37 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 38 | // setup the analog digital converter 39 | let mut adc = arduino_hal::Adc::new(dp.ADC, Default::default()); 40 | // in this example we only need pin a5 41 | let a5 = pins.a5.into_analog_input(&mut adc); 42 | 43 | loop { 44 | // read the voltage at a5 and convert it to an integer between 0 and 1023 45 | let sensor_value = a5.analog_read(&mut adc); 46 | 47 | // convert the number to human readable words 48 | let worded = match sensor_value { 49 | x if x > 950 => "bright", 50 | x if x > 750 => "well lit", 51 | x if x > 450 => "lit", 52 | x if x > 250 => "dimmly lit", 53 | x if x > 50 => "rather dark", 54 | x if x <= 50 => "very dark", 55 | _ => "invalid", // to satisfy the compiler () 56 | }; 57 | 58 | // output to the serial 59 | ufmt::uwrite!(&mut serial, "This is a {} room! – ", worded).unwrap_infallible(); 60 | ufmt::uwrite!(&mut serial, "Raw value: {} ", sensor_value).unwrap_infallible(); 61 | ufmt::uwriteln!(&mut serial, "").unwrap_infallible(); 62 | 63 | // wait for half a second then measure again 64 | arduino_hal::delay_ms(500); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /avr-hal-generic/src/clock.rs: -------------------------------------------------------------------------------- 1 | //! Core clock speed management 2 | //! 3 | //! AVR microcontrollers support different core clock speeds. Peripheral drivers need to know 4 | //! about this speed to calculate timing parameters. To make this as efficient as possible, the 5 | //! clock speed is tracked as a compile-time constant. This means peripheral drivers can do 6 | //! compile-time calculation of timing parameters. 7 | //! 8 | //! # How To Use 9 | //! If you are using `arduino-hal`, there is nothing you need to do - the core clock speed is 10 | //! defined in `arduino-hal` as `arduino_hal::DefaultClock` and the const-generic parameters of all 11 | //! peripheral drivers are preset to this value. 12 | //! 13 | //! If you are using a MCU HAL like `atmega-hal` or `attiny-hal`, you need to take care of clock 14 | //! speed management manually. The best way to do this is as follows: 15 | //! 16 | //! - Define a "constant" for your core clock speed in the crate root: 17 | //! ```ignore 18 | //! type CoreClock = atmega_hal::clock::MHz16; 19 | //! ``` 20 | //! - Define aliases for peripheral driver types based on this clock: 21 | //! ```ignore 22 | //! type Adc = atmega_hal::adc::Adc; 23 | //! type I2c = atmega_hal::i2c::I2c; 24 | //! ``` 25 | 26 | /// A clock speed 27 | pub trait Clock { 28 | /// Frequency of this clock in Hz 29 | const FREQ: u32; 30 | } 31 | 32 | /// 24 MHz Clock 33 | #[derive(ufmt::derive::uDebug, Debug)] 34 | pub struct MHz24; 35 | impl Clock for MHz24 { 36 | const FREQ: u32 = 24_000_000; 37 | } 38 | 39 | /// 20 MHz Clock 40 | #[derive(ufmt::derive::uDebug, Debug)] 41 | pub struct MHz20; 42 | impl Clock for MHz20 { 43 | const FREQ: u32 = 20_000_000; 44 | } 45 | 46 | /// 16 MHz Clock 47 | #[derive(ufmt::derive::uDebug, Debug)] 48 | pub struct MHz16; 49 | impl Clock for MHz16 { 50 | const FREQ: u32 = 16_000_000; 51 | } 52 | 53 | /// 12 MHz Clock 54 | #[derive(ufmt::derive::uDebug, Debug)] 55 | pub struct MHz12; 56 | impl Clock for MHz12 { 57 | const FREQ: u32 = 12_000_000; 58 | } 59 | 60 | /// 10 MHz Clock 61 | #[derive(ufmt::derive::uDebug, Debug)] 62 | pub struct MHz10; 63 | impl Clock for MHz10 { 64 | const FREQ: u32 = 10_000_000; 65 | } 66 | 67 | /// 8 MHz Clock 68 | #[derive(ufmt::derive::uDebug, Debug)] 69 | pub struct MHz8; 70 | impl Clock for MHz8 { 71 | const FREQ: u32 = 8_000_000; 72 | } 73 | 74 | /// 1 MHz Clock 75 | #[derive(ufmt::derive::uDebug, Debug)] 76 | pub struct MHz1; 77 | impl Clock for MHz1 { 78 | const FREQ: u32 = 1_000_000; 79 | } 80 | -------------------------------------------------------------------------------- /examples/arduino-nano/src/bin/nano-panic.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of a custom panic handler. 3 | * 4 | * The panic handler will print out where the panic occurred and then blink the oboard LED rapidly 5 | * to make the user aware of the problem. 6 | */ 7 | #![no_std] 8 | #![no_main] 9 | 10 | use arduino_hal::prelude::*; 11 | 12 | // Documentation build does not like this and fails with the following error, even though 13 | // everything is fine when compiling the binary. 14 | // 15 | // error[E0152]: found duplicate lang item `panic_impl` 16 | // 17 | // Ignore the panic handler in documentation builds. This is not needed in downstream code, it is 18 | // an artifact of the avr-hal examples structure. 19 | #[cfg(not(doc))] 20 | #[panic_handler] 21 | fn panic(info: &core::panic::PanicInfo) -> ! { 22 | // disable interrupts - firmware has panicked so no ISRs should continue running 23 | avr_device::interrupt::disable(); 24 | 25 | // get the peripherals so we can access serial and the LED. 26 | // 27 | // SAFETY: Because main() already has references to the peripherals this is an unsafe 28 | // operation - but because no other code can run after the panic handler was called, 29 | // we know it is okay. 30 | let dp = unsafe { arduino_hal::Peripherals::steal() }; 31 | let pins = arduino_hal::pins!(dp); 32 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 33 | 34 | // Print out panic location 35 | ufmt::uwriteln!(&mut serial, "Firmware panic!\r").unwrap_infallible(); 36 | if let Some(loc) = info.location() { 37 | ufmt::uwriteln!( 38 | &mut serial, 39 | " At {}:{}:{}\r", 40 | loc.file(), 41 | loc.line(), 42 | loc.column(), 43 | ) 44 | .unwrap_infallible(); 45 | } 46 | 47 | // Blink LED rapidly 48 | let mut led = pins.d13.into_output(); 49 | loop { 50 | led.toggle(); 51 | arduino_hal::delay_ms(100); 52 | } 53 | } 54 | 55 | #[arduino_hal::entry] 56 | fn main() -> ! { 57 | let dp = arduino_hal::Peripherals::take().unwrap(); 58 | let pins = arduino_hal::pins!(dp); 59 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 60 | 61 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 62 | ufmt::uwriteln!(&mut serial, "Panic in 5 seconds!\r").unwrap_infallible(); 63 | 64 | arduino_hal::delay_ms(5000); 65 | 66 | // Panic messages cannot yet be captured because they rely on core::fmt 67 | // which is way too big for AVR 68 | panic!(); 69 | } 70 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-panic.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example of a custom panic handler. 3 | * 4 | * The panic handler will print out where the panic occurred and then blink the oboard LED rapidly 5 | * to make the user aware of the problem. 6 | */ 7 | #![no_std] 8 | #![no_main] 9 | 10 | use arduino_hal::prelude::*; 11 | 12 | // Documentation build does not like this and fails with the following error, even though 13 | // everything is fine when compiling the binary. 14 | // 15 | // error[E0152]: found duplicate lang item `panic_impl` 16 | // 17 | // Ignore the panic handler in documentation builds. This is not needed in downstream code, it is 18 | // an artifact of the avr-hal examples structure. 19 | #[cfg(not(doc))] 20 | #[panic_handler] 21 | fn panic(info: &core::panic::PanicInfo) -> ! { 22 | // disable interrupts - firmware has panicked so no ISRs should continue running 23 | avr_device::interrupt::disable(); 24 | 25 | // get the peripherals so we can access serial and the LED. 26 | // 27 | // SAFETY: Because main() already has references to the peripherals this is an unsafe 28 | // operation - but because no other code can run after the panic handler was called, 29 | // we know it is okay. 30 | let dp = unsafe { arduino_hal::Peripherals::steal() }; 31 | let pins = arduino_hal::pins!(dp); 32 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 33 | 34 | // Print out panic location 35 | ufmt::uwriteln!(&mut serial, "Firmware panic!\r").unwrap_infallible(); 36 | if let Some(loc) = info.location() { 37 | ufmt::uwriteln!( 38 | &mut serial, 39 | " At {}:{}:{}\r", 40 | loc.file(), 41 | loc.line(), 42 | loc.column(), 43 | ) 44 | .unwrap_infallible(); 45 | } 46 | 47 | // Blink LED rapidly 48 | let mut led = pins.d13.into_output(); 49 | loop { 50 | led.toggle(); 51 | arduino_hal::delay_ms(100); 52 | } 53 | } 54 | 55 | #[arduino_hal::entry] 56 | fn main() -> ! { 57 | let dp = arduino_hal::Peripherals::take().unwrap(); 58 | let pins = arduino_hal::pins!(dp); 59 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 60 | 61 | ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible(); 62 | ufmt::uwriteln!(&mut serial, "Panic in 5 seconds!\r").unwrap_infallible(); 63 | 64 | arduino_hal::delay_ms(5000); 65 | 66 | // Panic messages cannot yet be captured because they rely on core::fmt 67 | // which is way too big for AVR 68 | panic!(); 69 | } 70 | -------------------------------------------------------------------------------- /arduino-hal/src/port/promicro.rs: -------------------------------------------------------------------------------- 1 | pub use atmega_hal::port::{mode, Pin, PinMode, PinOps}; 2 | 3 | avr_hal_generic::renamed_pins! { 4 | /// Pins of the **SparkFun ProMicro**. 5 | /// 6 | /// This struct is best initialized via the [`arduino_hal::pins!()`][crate::pins] macro. 7 | pub struct Pins { 8 | /// `RX` 9 | /// 10 | /// `RX` (UART) 11 | pub rx: atmega_hal::port::PD2 = pd2, 12 | /// `TX` 13 | /// 14 | /// `TX` (UART) 15 | pub tx: atmega_hal::port::PD3 = pd3, 16 | /// `D2` / `SDA` 17 | /// 18 | /// `SDA`: i2c/twi data 19 | pub d2: atmega_hal::port::PD1 = pd1, 20 | /// `D3` / `SCL` 21 | /// 22 | /// `SCL`: i2c/twi clock 23 | pub d3: atmega_hal::port::PD0 = pd0, 24 | /// `D4` 25 | pub d4: atmega_hal::port::PD4 = pd4, 26 | /// `D5` 27 | pub d5: atmega_hal::port::PC6 = pc6, 28 | /// `D6` 29 | pub d6: atmega_hal::port::PD7 = pd7, 30 | /// `D7` 31 | pub d7: atmega_hal::port::PE6 = pe6, 32 | /// `D8` 33 | pub d8: atmega_hal::port::PB4 = pb4, 34 | /// `D9` 35 | pub d9: atmega_hal::port::PB5 = pb5, 36 | /// `D10` 37 | pub d10: atmega_hal::port::PB6 = pb6, 38 | /// `LED_RX` 39 | /// 40 | /// Led for indicating inbound data (yellow). Also the CS pin for SPI. 41 | pub led_rx: atmega_hal::port::PB0 = pb0, 42 | /// `LED_TX` 43 | /// 44 | /// Led for indicating outbound data (green). 45 | pub led_tx: atmega_hal::port::PD5 = pd5, 46 | /// `D15`, `SCK` 47 | /// 48 | /// ICSP SCLK pin 49 | pub d15: atmega_hal::port::PB1 = pb1, 50 | /// `D14`, `MISO` 51 | /// 52 | /// ICSP MISO pin 53 | pub d16: atmega_hal::port::PB3 = pb3, 54 | /// `D16`, `MOSI` 55 | /// 56 | /// ICSP MOSI pin 57 | pub d14: atmega_hal::port::PB2 = pb2, 58 | /// `A0` 59 | /// 60 | /// `ADC7` channel 61 | pub a0: atmega_hal::port::PF7 = pf7, 62 | /// `A1` 63 | /// 64 | /// `ADC6` channel 65 | pub a1: atmega_hal::port::PF6 = pf6, 66 | /// `A2` 67 | /// 68 | /// `ADC5` channel 69 | pub a2: atmega_hal::port::PF5 = pf5, 70 | /// `A3` 71 | /// 72 | /// `ADC4` channel 73 | pub a3: atmega_hal::port::PF4 = pf4, 74 | } 75 | 76 | impl Pins { 77 | type Pin = Pin; 78 | type McuPins = atmega_hal::Pins; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/atmega2560/src/bin/atmega2560-adc.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use atmega_hal::adc::channel; 5 | use atmega_hal::delay::Delay; 6 | use atmega_hal::usart::{Baudrate, Usart}; 7 | use embedded_hal::delay::DelayNs; 8 | use panic_halt as _; 9 | 10 | // Define core clock in the root crate 11 | type CoreClock = atmega_hal::clock::MHz16; 12 | // Use it as follows in the rest of the project 13 | type Adc = atmega_hal::adc::Adc; 14 | 15 | #[avr_device::entry] 16 | fn main() -> ! { 17 | let dp = atmega_hal::Peripherals::take().unwrap(); 18 | let pins = atmega_hal::pins!(dp); 19 | 20 | let mut delay = Delay::::new(); 21 | 22 | // set up serial interface for text output 23 | let mut serial = Usart::new( 24 | dp.USART0, 25 | pins.pe0, 26 | pins.pe1.into_output(), 27 | Baudrate::::new(57600), 28 | ); 29 | 30 | let mut adc = Adc::new(dp.ADC, Default::default()); 31 | 32 | let (vbg, gnd) = ( 33 | adc.read_blocking(&channel::Vbg), 34 | adc.read_blocking(&channel::Gnd), 35 | ); 36 | ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap(); 37 | ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap(); 38 | 39 | // To store multiple channels in an array, we use the `into_channel()` method. 40 | let channels: [atmega_hal::adc::Channel; 16] = [ 41 | pins.pf0.into_analog_input(&mut adc).into_channel(), 42 | pins.pf1.into_analog_input(&mut adc).into_channel(), 43 | pins.pf2.into_analog_input(&mut adc).into_channel(), 44 | pins.pf3.into_analog_input(&mut adc).into_channel(), 45 | pins.pf4.into_analog_input(&mut adc).into_channel(), 46 | pins.pf5.into_analog_input(&mut adc).into_channel(), 47 | pins.pf6.into_analog_input(&mut adc).into_channel(), 48 | pins.pf7.into_analog_input(&mut adc).into_channel(), 49 | pins.pk0.into_analog_input(&mut adc).into_channel(), 50 | pins.pk1.into_analog_input(&mut adc).into_channel(), 51 | pins.pk2.into_analog_input(&mut adc).into_channel(), 52 | pins.pk3.into_analog_input(&mut adc).into_channel(), 53 | pins.pk4.into_analog_input(&mut adc).into_channel(), 54 | pins.pk5.into_analog_input(&mut adc).into_channel(), 55 | pins.pk6.into_analog_input(&mut adc).into_channel(), 56 | pins.pk7.into_analog_input(&mut adc).into_channel(), 57 | ]; 58 | 59 | loop { 60 | for (i, ch) in channels.iter().enumerate() { 61 | let v = adc.read_blocking(ch); 62 | ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap(); 63 | } 64 | 65 | ufmt::uwriteln!(&mut serial, "").unwrap(); 66 | delay.delay_ms(1000); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /arduino-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arduino-hal" 3 | version = "0.1.0" 4 | 5 | authors = ["Rahix "] 6 | edition = "2021" 7 | description = "Board support crate for popular AVR dev-boards" 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rahix/avr-hal" 10 | keywords = ["avr", "arduino"] 11 | categories = ["no-std", "embedded", "hardware-support"] 12 | 13 | [features] 14 | default = ["rt"] 15 | rt = ["avr-device/rt"] 16 | 17 | critical-section-impl = ["avr-device/critical-section-impl"] 18 | 19 | board-selected = [] 20 | mcu-atmega = [] 21 | mcu-attiny = [] 22 | arduino-diecimila = ["mcu-atmega", "atmega-hal/atmega168", "board-selected"] 23 | arduino-leonardo = ["mcu-atmega", "atmega-hal/atmega32u4", "board-selected"] 24 | arduino-mega2560 = ["mcu-atmega", "atmega-hal/atmega2560", "board-selected"] 25 | arduino-mega1280 = ["mcu-atmega", "atmega-hal/atmega1280", "board-selected"] 26 | arduino-nano = ["mcu-atmega", "atmega-hal/atmega328p", "atmega-hal/enable-extra-adc", "board-selected"] 27 | arduino-uno = ["mcu-atmega", "atmega-hal/atmega328p", "board-selected"] 28 | trinket-pro = ["mcu-atmega", "atmega-hal/atmega328p", "board-selected"] 29 | sparkfun-promicro = ["mcu-atmega", "atmega-hal/atmega32u4", "board-selected"] 30 | sparkfun-promini-3v3 = ["mcu-atmega", "atmega-hal/atmega328p", "atmega-hal/enable-extra-adc", "board-selected"] 31 | sparkfun-promini-5v = ["mcu-atmega", "atmega-hal/atmega328p", "atmega-hal/enable-extra-adc", "board-selected"] 32 | trinket = ["mcu-attiny", "attiny-hal/attiny85", "board-selected"] 33 | nano168 = ["mcu-atmega", "atmega-hal/atmega168", "atmega-hal/enable-extra-adc", "board-selected"] 34 | 35 | # We must select a board to build on docs.rs 36 | docsrs = ["arduino-uno"] 37 | 38 | [dependencies] 39 | cfg-if = "1" 40 | embedded-hal = "1.0" 41 | ufmt = "0.2.0" 42 | 43 | [dependencies.embedded-hal-v0] 44 | version = "0.2.3" 45 | package = "embedded-hal" 46 | 47 | [dependencies.avr-hal-generic] 48 | path = "../avr-hal-generic/" 49 | 50 | [dependencies.atmega-hal] 51 | path = "../mcu/atmega-hal/" 52 | optional = true 53 | 54 | # Because this crate has its own check that at least one device is selected, we 55 | # can safely "circumvent" the check in `atmega-hal`. Due to compile order, 56 | # this allows us to show our error instead of the one from `atmega-hal` (which 57 | # is much less helpful in this situation). 58 | features = ["disable-device-selection-error"] 59 | 60 | [dependencies.attiny-hal] 61 | path = "../mcu/attiny-hal/" 62 | optional = true 63 | 64 | [dependencies.avr-device] 65 | version = "0.7" 66 | 67 | # Because this crate has its own check that at least one device is selected, we 68 | # can safely "circumvent" the check in `avr-device`. 69 | # 70 | # Why would we want that? Otherwise, as `avr-device` is compiled first, its 71 | # error will be shown and ours won't which leads to a degraded user experience 72 | # as the displayed error message does not really tell what needs to be done... 73 | features = ["device-selected"] 74 | 75 | [package.metadata.docs.rs] 76 | features = ["docsrs"] 77 | -------------------------------------------------------------------------------- /avr-specs/sync-from-upstream.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import copy 3 | import json 4 | import subprocess 5 | 6 | SPECS = { 7 | "atmega32u4": { 8 | "cpu": "atmega32u4", 9 | }, 10 | "atmega48p": { 11 | "cpu": "atmega48p", 12 | }, 13 | "atmega164pa": { 14 | "cpu": "atmega164pa", 15 | }, 16 | "atmega168": { 17 | "cpu": "atmega168", 18 | }, 19 | "atmega32a": { 20 | "cpu": "atmega32a" 21 | }, 22 | "atmega328": { 23 | "cpu": "atmega328", 24 | }, 25 | "atmega328p": { 26 | "cpu": "atmega328p", 27 | }, 28 | "atmega128a": { 29 | "cpu": "atmega128a", 30 | }, 31 | "atmega1280": { 32 | "cpu": "atmega1280", 33 | }, 34 | "atmega2560": { 35 | "cpu": "atmega2560", 36 | }, 37 | "atmega1284p": { 38 | "cpu": "atmega1284p", 39 | }, 40 | "atmega8": { 41 | "cpu": "atmega8", 42 | }, 43 | "attiny85": { 44 | "cpu": "attiny85", 45 | }, 46 | "attiny88": { 47 | "cpu": "attiny88", 48 | }, 49 | "attiny167": { 50 | "cpu": "attiny167", 51 | }, 52 | "attiny2313": { 53 | "cpu": "attiny2313", 54 | }, 55 | } 56 | 57 | COMMON = { 58 | # needed because we currently rely on avr-libc 59 | "no-default-libraries": False, 60 | # 8-bit operations on AVR are atomic 61 | # LLVM also supports 16-bit atomics by disabling interrupts 62 | # see also https://github.com/rust-lang/rust/pull/114495 63 | "max-atomic-width": 16, 64 | } 65 | 66 | 67 | def main(): 68 | rustc_version = subprocess.run( 69 | ["rustc", "--version"], 70 | check=True, 71 | stdout=subprocess.PIPE, 72 | ).stdout.decode() 73 | 74 | if "nightly" not in rustc_version: 75 | raise Exception("You need nightly rustc!") 76 | 77 | upstream_spec_string = subprocess.run( 78 | [ 79 | "rustc", 80 | "--print", 81 | "target-spec-json", 82 | "-Z", 83 | "unstable-options", 84 | "--target", 85 | "avr-unknown-gnu-atmega328", 86 | ], 87 | check=True, 88 | stdout=subprocess.PIPE, 89 | ).stdout 90 | 91 | upstream_spec = json.loads(upstream_spec_string) 92 | 93 | # our targets are of course not built into rustc 94 | del upstream_spec["is-builtin"] 95 | 96 | for mcu, settings in SPECS.items(): 97 | spec = copy.deepcopy(upstream_spec) 98 | spec.update(COMMON) 99 | spec.update(settings) 100 | 101 | for pre_link_args in spec["pre-link-args"].values(): 102 | pre_link_args[0] = f"-mmcu={settings['cpu']}" 103 | pre_link_args.append("-Wl,--as-needed,--print-memory-usage") 104 | 105 | with open(f"avr-specs/avr-{mcu}.json", "w") as f: 106 | json.dump(spec, f, sort_keys=True, indent=2) 107 | f.write("\n") 108 | 109 | 110 | if __name__ == "__main__": 111 | main() 112 | -------------------------------------------------------------------------------- /examples/nano168/src/bin/nano168-millis.rs: -------------------------------------------------------------------------------- 1 | //! A basic implementation of the `millis()` function from Arduino: 2 | //! 3 | //! https://www.arduino.cc/reference/en/language/functions/time/millis/ 4 | //! 5 | //! Uses timer 0 and one of its interrupts to update a global millisecond 6 | //! counter. A walkthough of this code is available here: 7 | //! 8 | //! https://blog.rahix.de/005-avr-hal-millis/ 9 | #![no_std] 10 | #![no_main] 11 | #![feature(abi_avr_interrupt)] 12 | 13 | use arduino_hal::prelude::*; 14 | use core::cell; 15 | use panic_halt as _; 16 | 17 | use embedded_hal_v0::serial::Read; 18 | 19 | // Possible Values: 20 | // 21 | // ╔═══════════╦══════════════╦═══════════════════╗ 22 | // ║ PRESCALER ║ TIMER_COUNTS ║ Overflow Interval ║ 23 | // ╠═══════════╬══════════════╬═══════════════════╣ 24 | // ║ 64 ║ 250 ║ 1 ms ║ 25 | // ║ 256 ║ 125 ║ 2 ms ║ 26 | // ║ 256 ║ 250 ║ 4 ms ║ 27 | // ║ 1024 ║ 125 ║ 8 ms ║ 28 | // ║ 1024 ║ 250 ║ 16 ms ║ 29 | // ╚═══════════╩══════════════╩═══════════════════╝ 30 | const PRESCALER: u32 = 1024; 31 | const TIMER_COUNTS: u32 = 125; 32 | 33 | const MILLIS_INCREMENT: u32 = PRESCALER * TIMER_COUNTS / 16000; 34 | 35 | static MILLIS_COUNTER: avr_device::interrupt::Mutex> = 36 | avr_device::interrupt::Mutex::new(cell::Cell::new(0)); 37 | 38 | fn millis_init(tc0: arduino_hal::pac::TC0) { 39 | // Configure the timer for the above interval (in CTC mode) 40 | // and enable its interrupt. 41 | tc0.tccr0a.write(|w| w.wgm0().ctc()); 42 | tc0.ocr0a.write(|w| w.bits(TIMER_COUNTS as u8)); 43 | tc0.tccr0b.write(|w| match PRESCALER { 44 | 8 => w.cs0().prescale_8(), 45 | 64 => w.cs0().prescale_64(), 46 | 256 => w.cs0().prescale_256(), 47 | 1024 => w.cs0().prescale_1024(), 48 | _ => panic!(), 49 | }); 50 | tc0.timsk0.write(|w| w.ocie0a().set_bit()); 51 | 52 | // Reset the global millisecond counter 53 | avr_device::interrupt::free(|cs| { 54 | MILLIS_COUNTER.borrow(cs).set(0); 55 | }); 56 | } 57 | 58 | #[avr_device::interrupt(atmega328p)] 59 | fn TIMER0_COMPA() { 60 | avr_device::interrupt::free(|cs| { 61 | let counter_cell = MILLIS_COUNTER.borrow(cs); 62 | let counter = counter_cell.get(); 63 | counter_cell.set(counter + MILLIS_INCREMENT); 64 | }) 65 | } 66 | 67 | fn millis() -> u32 { 68 | avr_device::interrupt::free(|cs| MILLIS_COUNTER.borrow(cs).get()) 69 | } 70 | 71 | // ---------------------------------------------------------------------------- 72 | 73 | #[arduino_hal::entry] 74 | fn main() -> ! { 75 | let dp = arduino_hal::Peripherals::take().unwrap(); 76 | let pins = arduino_hal::pins!(dp); 77 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 78 | 79 | millis_init(dp.TC0); 80 | 81 | // Enable interrupts globally 82 | unsafe { avr_device::interrupt::enable() }; 83 | 84 | // Wait for a character and print current time once it is received 85 | loop { 86 | let b = nb::block!(serial.read()).unwrap_infallible(); 87 | 88 | let time = millis(); 89 | ufmt::uwriteln!(&mut serial, "Got {} after {} ms!\r", b, time).unwrap_infallible(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-millis.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * A basic implementation of the `millis()` function from Arduino: 3 | * 4 | * https://www.arduino.cc/reference/en/language/functions/time/millis/ 5 | * 6 | * Uses timer TC0 and one of its interrupts to update a global millisecond 7 | * counter. A walkthough of this code is available here: 8 | * 9 | * https://blog.rahix.de/005-avr-hal-millis/ 10 | */ 11 | #![no_std] 12 | #![no_main] 13 | #![feature(abi_avr_interrupt)] 14 | 15 | use arduino_hal::prelude::*; 16 | use core::cell; 17 | use panic_halt as _; 18 | 19 | use embedded_hal_v0::serial::Read; 20 | 21 | // Possible Values: 22 | // 23 | // ╔═══════════╦══════════════╦═══════════════════╗ 24 | // ║ PRESCALER ║ TIMER_COUNTS ║ Overflow Interval ║ 25 | // ╠═══════════╬══════════════╬═══════════════════╣ 26 | // ║ 64 ║ 250 ║ 1 ms ║ 27 | // ║ 256 ║ 125 ║ 2 ms ║ 28 | // ║ 256 ║ 250 ║ 4 ms ║ 29 | // ║ 1024 ║ 125 ║ 8 ms ║ 30 | // ║ 1024 ║ 250 ║ 16 ms ║ 31 | // ╚═══════════╩══════════════╩═══════════════════╝ 32 | const PRESCALER: u32 = 1024; 33 | const TIMER_COUNTS: u32 = 125; 34 | 35 | const MILLIS_INCREMENT: u32 = PRESCALER * TIMER_COUNTS / 16000; 36 | 37 | static MILLIS_COUNTER: avr_device::interrupt::Mutex> = 38 | avr_device::interrupt::Mutex::new(cell::Cell::new(0)); 39 | 40 | fn millis_init(tc0: arduino_hal::pac::TC0) { 41 | // Configure the timer for the above interval (in CTC mode) 42 | // and enable its interrupt. 43 | tc0.tccr0a.write(|w| w.wgm0().ctc()); 44 | tc0.ocr0a.write(|w| w.bits(TIMER_COUNTS as u8)); 45 | tc0.tccr0b.write(|w| match PRESCALER { 46 | 8 => w.cs0().prescale_8(), 47 | 64 => w.cs0().prescale_64(), 48 | 256 => w.cs0().prescale_256(), 49 | 1024 => w.cs0().prescale_1024(), 50 | _ => panic!(), 51 | }); 52 | tc0.timsk0.write(|w| w.ocie0a().set_bit()); 53 | 54 | // Reset the global millisecond counter 55 | avr_device::interrupt::free(|cs| { 56 | MILLIS_COUNTER.borrow(cs).set(0); 57 | }); 58 | } 59 | 60 | #[avr_device::interrupt(atmega328p)] 61 | fn TIMER0_COMPA() { 62 | avr_device::interrupt::free(|cs| { 63 | let counter_cell = MILLIS_COUNTER.borrow(cs); 64 | let counter = counter_cell.get(); 65 | counter_cell.set(counter + MILLIS_INCREMENT); 66 | }) 67 | } 68 | 69 | fn millis() -> u32 { 70 | avr_device::interrupt::free(|cs| MILLIS_COUNTER.borrow(cs).get()) 71 | } 72 | 73 | // ---------------------------------------------------------------------------- 74 | 75 | #[arduino_hal::entry] 76 | fn main() -> ! { 77 | let dp = arduino_hal::Peripherals::take().unwrap(); 78 | let pins = arduino_hal::pins!(dp); 79 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 80 | 81 | millis_init(dp.TC0); 82 | 83 | // Enable interrupts globally 84 | unsafe { avr_device::interrupt::enable() }; 85 | 86 | // Wait for a character and print current time once it is received 87 | loop { 88 | let b = nb::block!(serial.read()).unwrap_infallible(); 89 | 90 | let time = millis(); 91 | ufmt::uwriteln!(&mut serial, "Got {} after {} ms!\r", b, time).unwrap_infallible(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /examples/arduino-uno/src/bin/uno-hc-sr04.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Example for using the HC-SR04 ultrasonic distance sensor. 3 | * 4 | * This example prints out the distance reported by the sensor over the serial console. 5 | * 6 | * Sensor Datasheet: https://www.electroschematics.com/hc-sr04-datasheet/ 7 | * 8 | * Connections 9 | * ----------- 10 | * - `D2`: HC-SR04 `TRIG` 11 | * - `D3`: HC-SR04 `ECHO` 12 | */ 13 | #![no_std] 14 | #![no_main] 15 | 16 | use arduino_hal::prelude::*; 17 | use panic_halt as _; 18 | 19 | #[arduino_hal::entry] 20 | fn main() -> ! { 21 | let dp = arduino_hal::Peripherals::take().unwrap(); 22 | let pins = arduino_hal::pins!(dp); 23 | let mut serial = arduino_hal::default_serial!(dp, pins, 57600); 24 | 25 | let mut trig = pins.d2.into_output(); 26 | let echo = pins.d3; // pin is input by default 27 | 28 | // Starting and initializing the timer with prescaling 64. 29 | // it gives one clock count every 4 µs. 30 | // since the clock register size is 16 bits, the timer is full every 31 | // 1/(16e6/64)*2^16 ≈ 260 ms 32 | let timer1 = dp.TC1; 33 | timer1.tccr1b.write(|w| w.cs1().prescale_64()); 34 | 35 | 'outer: loop { 36 | // the timer is reinitialized with value 0. 37 | timer1.tcnt1.write(|w| w.bits(0)); 38 | 39 | // the trigger must be set to high under 10 µs as per the HC-SR04 datasheet 40 | trig.set_high(); 41 | arduino_hal::delay_us(10); 42 | trig.set_low(); 43 | 44 | while echo.is_low() { 45 | // exiting the loop if the timer has reached 200 ms. 46 | // 0.2s/4µs = 50000 47 | if timer1.tcnt1.read().bits() >= 50000 { 48 | // jump to the beginning of the outer loop if no obstacle is detected 49 | ufmt::uwriteln!( 50 | &mut serial, 51 | "Nothing was detected and jump to outer loop.\r" 52 | ) 53 | .unwrap_infallible(); 54 | continue 'outer; 55 | } 56 | } 57 | // Restarting the timer 58 | timer1.tcnt1.write(|w| w.bits(0)); 59 | 60 | // Wait for the echo to get low again 61 | while echo.is_high() {} 62 | 63 | // 1 count == 4 µs, so the value is multiplied by 4. 64 | // 1/58 ≈ (34000 cm/s) * 1µs / 2 65 | // when no object is detected, instead of keeping the echo pin completely low, 66 | // some HC-SR04 labeled sensor holds the echo pin in high state for very long time, 67 | // thus overflowing the u16 value when multiplying the timer1 value with 4. 68 | // overflow during runtime causes panic! so it must be handled 69 | let temp_timer = timer1.tcnt1.read().bits().saturating_mul(4); 70 | let value = match temp_timer { 71 | u16::MAX => { 72 | ufmt::uwriteln!( 73 | &mut serial, 74 | "Nothing was detected and jump to outer loop.\r" 75 | ) 76 | .unwrap_infallible(); 77 | continue 'outer; 78 | } 79 | _ => temp_timer / 58, 80 | }; 81 | 82 | // Await 100 ms before sending the next trig 83 | // 0.1s/4µs = 25000 84 | while timer1.tcnt1.read().bits() < 25000 {} 85 | 86 | ufmt::uwriteln!( 87 | &mut serial, 88 | "Hello, we are {} cms away from target!\r", 89 | value 90 | ) 91 | .unwrap_infallible(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /mcu/atmega-hal/src/eeprom.rs: -------------------------------------------------------------------------------- 1 | //! EEPROM 2 | //! 3 | //! # Example 4 | //! 5 | //! Complete example source code can be found in the repository: 6 | //! [`atmega2560-eeprom.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-eeprom.rs) 7 | //! 8 | //! ``` 9 | //! const BOOT_COUNT_OFFSET: u16 = 0; 10 | //! 11 | //! let dp = atmega_hal::Peripherals::take().unwrap(); 12 | //! let mut eeprom = Eeprom::new(dp.EEPROM); 13 | //! 14 | //! let mut boot_count = eeprom.read_byte(BOOT_COUNT_OFFSET); 15 | //! boot_count = boot_count.wrapping_add(1); 16 | //! eeprom.write_byte(BOOT_COUNT_OFFSET, boot_count); 17 | //! 18 | //! ufmt::uwriteln!(&mut serial, "Boot count: {}", boot_count).unwrap(); 19 | //! ``` 20 | 21 | pub use avr_hal_generic::eeprom::{EepromOps, OutOfBoundsError}; 22 | 23 | pub type Eeprom = avr_hal_generic::eeprom::Eeprom; 24 | 25 | /////////////////////////////////////////////////////////// 26 | #[cfg(feature = "atmega48p")] 27 | avr_hal_generic::impl_eeprom_atmega! { 28 | hal: crate::Atmega, 29 | peripheral: crate::pac::EEPROM, 30 | capacity: 256, 31 | addr_width: u8, 32 | set_address: |peripheral, address| { 33 | peripheral.eearl.write(|w| w.bits(address)); 34 | }, 35 | } 36 | 37 | #[cfg(any(feature = "atmega168", feature = "atmega164pa"))] 38 | avr_hal_generic::impl_eeprom_atmega! { 39 | hal: crate::Atmega, 40 | peripheral: crate::pac::EEPROM, 41 | capacity: 512, 42 | addr_width: u16, 43 | set_address: |peripheral, address| { 44 | peripheral.eear.write(|w| w.bits(address)); 45 | }, 46 | } 47 | 48 | #[cfg(any( 49 | feature = "atmega328pb", 50 | feature = "atmega328p", 51 | feature = "atmega32u4" 52 | ))] 53 | avr_hal_generic::impl_eeprom_atmega! { 54 | hal: crate::Atmega, 55 | peripheral: crate::pac::EEPROM, 56 | capacity: 1024, 57 | addr_width: u16, 58 | set_address: |peripheral, address| { 59 | peripheral.eear.write(|w| w.bits(address)); 60 | }, 61 | } 62 | 63 | #[cfg(any( 64 | feature = "atmega2560", 65 | feature = "atmega1280", 66 | feature = "atmega1284p" 67 | ))] 68 | avr_hal_generic::impl_eeprom_atmega! { 69 | hal: crate::Atmega, 70 | peripheral: crate::pac::EEPROM, 71 | capacity: 4096, 72 | addr_width: u16, 73 | set_address: |peripheral, address| { 74 | peripheral.eear.write(|w| w.bits(address)); 75 | }, 76 | } 77 | 78 | #[cfg(any(feature = "atmega8"))] 79 | avr_hal_generic::impl_eeprom_atmega_old! { 80 | hal: crate::Atmega, 81 | peripheral: crate::pac::EEPROM, 82 | capacity: 512, 83 | addr_width: u16, 84 | set_address: |peripheral, address| { 85 | peripheral.eear.write(|w| w.bits(address)); 86 | }, 87 | } 88 | 89 | #[cfg(any(feature = "atmega32a"))] 90 | avr_hal_generic::impl_eeprom_atmega_old! { 91 | hal: crate::Atmega, 92 | peripheral: crate::pac::EEPROM, 93 | capacity: 1024, 94 | addr_width: u16, 95 | set_address: |peripheral, address| { 96 | peripheral.eear.write(|w| w.bits(address)); 97 | }, 98 | } 99 | 100 | #[cfg(any(feature = "atmega128a",))] 101 | avr_hal_generic::impl_eeprom_atmega_old! { 102 | hal: crate::Atmega, 103 | peripheral: crate::pac::EEPROM, 104 | capacity: 4096, 105 | addr_width: u16, 106 | set_address: |peripheral, address| { 107 | peripheral.eear.write(|w| w.bits(address)); 108 | }, 109 | } 110 | -------------------------------------------------------------------------------- /mcu/attiny-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | //! `attiny-hal` 4 | //! ============= 5 | //! Common HAL (hardware abstraction layer) for ATtiny* microcontrollers. 6 | //! 7 | //! **Note**: This version of the documentation was built for 8 | #![cfg_attr(feature = "attiny85", doc = "**ATtiny85**.")] 9 | #![cfg_attr(feature = "attiny88", doc = "**ATtiny88**.")] 10 | #![cfg_attr(feature = "attiny167", doc = "**ATtiny167**.")] 11 | #![cfg_attr(feature = "attiny2313", doc = "**ATtiny2313**.")] 12 | //! This means that only items which are available for this MCU are visible. If you are using 13 | //! a different chip, try building the documentation locally with: 14 | //! 15 | //! ```text 16 | //! cargo doc --features --open 17 | //! ``` 18 | 19 | #[cfg(all( 20 | not(feature = "device-selected"), 21 | not(feature = "disable-device-selection-error") 22 | ))] 23 | compile_error!( 24 | "This crate requires you to specify your target chip as a feature. 25 | 26 | Please select one of the following 27 | 28 | * attiny85 29 | * attiny88 30 | * attiny167 31 | * attiny2313 32 | " 33 | ); 34 | 35 | /// Reexport of `attiny167` from `avr-device` 36 | /// 37 | #[cfg(feature = "attiny167")] 38 | pub use avr_device::attiny167 as pac; 39 | /// Reexport of `attiny2313` from `avr-device` 40 | /// 41 | #[cfg(feature = "attiny2313")] 42 | pub use avr_device::attiny2313 as pac; 43 | /// Reexport of `attiny84` from `avr-device` 44 | /// 45 | #[cfg(feature = "attiny84")] 46 | pub use avr_device::attiny84 as pac; 47 | /// Reexport of `attiny85` from `avr-device` 48 | /// 49 | #[cfg(feature = "attiny85")] 50 | pub use avr_device::attiny85 as pac; 51 | /// Reexport of `attiny88` from `avr-device` 52 | /// 53 | #[cfg(feature = "attiny88")] 54 | pub use avr_device::attiny88 as pac; 55 | 56 | /// See [`avr_device::entry`](https://docs.rs/avr-device/latest/avr_device/attr.entry.html). 57 | #[cfg(feature = "rt")] 58 | pub use avr_device::entry; 59 | 60 | #[cfg(feature = "device-selected")] 61 | pub use pac::Peripherals; 62 | 63 | pub use avr_hal_generic::clock; 64 | pub use avr_hal_generic::delay; 65 | pub use avr_hal_generic::prelude; 66 | 67 | // ATtiny2313 does not have ADC and will not compile with this module 68 | #[cfg(all(feature = "device-selected", not(feature = "attiny2313")))] 69 | pub mod adc; 70 | #[cfg(all(feature = "device-selected", not(feature = "attiny2313")))] 71 | pub use adc::Adc; 72 | 73 | #[cfg(feature = "device-selected")] 74 | pub mod port; 75 | #[cfg(feature = "device-selected")] 76 | pub use port::Pins; 77 | 78 | #[cfg(feature = "device-selected")] 79 | pub mod simple_pwm; 80 | 81 | #[cfg(feature = "device-selected")] 82 | pub mod wdt; 83 | #[cfg(feature = "device-selected")] 84 | pub use wdt::Wdt; 85 | 86 | #[cfg(feature = "device-selected")] 87 | pub mod eeprom; 88 | #[cfg(feature = "device-selected")] 89 | pub use eeprom::Eeprom; 90 | 91 | #[cfg(feature = "device-selected")] 92 | pub mod spi; 93 | #[cfg(feature = "device-selected")] 94 | pub use spi::Spi; 95 | 96 | pub struct Attiny; 97 | 98 | #[cfg(feature = "attiny84")] 99 | #[macro_export] 100 | macro_rules! pins { 101 | ($p:expr) => { 102 | $crate::Pins::new($p.PORTA, $p.PORTB) 103 | }; 104 | } 105 | #[cfg(feature = "attiny85")] 106 | #[macro_export] 107 | macro_rules! pins { 108 | ($p:expr) => { 109 | $crate::Pins::new($p.PORTB) 110 | }; 111 | } 112 | #[cfg(feature = "attiny88")] 113 | #[macro_export] 114 | macro_rules! pins { 115 | ($p:expr) => { 116 | $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTC, $p.PORTD) 117 | }; 118 | } 119 | #[cfg(feature = "attiny167")] 120 | #[macro_export] 121 | macro_rules! pins { 122 | ($p:expr) => { 123 | $crate::Pins::new($p.PORTA, $p.PORTB) 124 | }; 125 | } 126 | #[cfg(feature = "attiny2313")] 127 | #[macro_export] 128 | macro_rules! pins { 129 | ($p:expr) => { 130 | $crate::Pins::new($p.PORTA, $p.PORTB, $p.PORTD) 131 | }; 132 | } 133 | -------------------------------------------------------------------------------- /mcu/atmega-hal/src/spi.rs: -------------------------------------------------------------------------------- 1 | //! SPI 2 | //! 3 | //! # Example 4 | //! 5 | //! Complete example source code can be found in the repository 6 | //! [`atmega2560-spi-feedback.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs) 7 | //! 8 | //! ``` 9 | //! let dp = atmega_hal::Peripherals::take().unwrap(); 10 | //! let pins = atmega_hal::pins!(dp); 11 | //! 12 | //! let (mut spi, mut cs) = spi::Spi::new( 13 | //! dp.SPI, 14 | //! pins.pb1.into_output(), 15 | //! pins.pb2.into_output(), 16 | //! pins.pb3.into_pull_up_input(), 17 | //! pins.pb0.into_output(), 18 | //! spi::Settings::default(), 19 | //! ); 20 | //! 21 | //! let data_out = b"Hello World!"; 22 | //! let mut data_in = [0u8; 12]; 23 | //! 24 | //! cs.set_low().unwrap(); 25 | //! spi.transfer(&mut data_in, data_out).unwrap(); 26 | //! cs.set_high().unwrap(); 27 | //! 28 | //! ufmt::uwriteln!(&mut serial, "data: {:?}", data_in).unwrap(); 29 | //! ``` 30 | 31 | #[allow(unused_imports)] 32 | use crate::port; 33 | pub use avr_hal_generic::spi::*; 34 | 35 | #[cfg(any( 36 | feature = "atmega128a", 37 | feature = "atmega1280", 38 | feature = "atmega2560", 39 | feature = "atmega32u4" 40 | ))] 41 | pub type Spi = avr_hal_generic::spi::Spi< 42 | crate::Atmega, 43 | crate::pac::SPI, 44 | port::PB1, 45 | port::PB2, 46 | port::PB3, 47 | port::PB0, 48 | >; 49 | #[cfg(any( 50 | feature = "atmega128a", 51 | feature = "atmega1280", 52 | feature = "atmega2560", 53 | feature = "atmega32u4" 54 | ))] 55 | avr_hal_generic::impl_spi! { 56 | hal: crate::Atmega, 57 | peripheral: crate::pac::SPI, 58 | sclk: port::PB1, 59 | mosi: port::PB2, 60 | miso: port::PB3, 61 | cs: port::PB0, 62 | } 63 | 64 | #[cfg(any( 65 | feature = "atmega168", 66 | feature = "atmega328p", 67 | feature = "atmega48p", 68 | feature = "atmega8" 69 | ))] 70 | pub type Spi = avr_hal_generic::spi::Spi< 71 | crate::Atmega, 72 | crate::pac::SPI, 73 | port::PB5, 74 | port::PB3, 75 | port::PB4, 76 | port::PB2, 77 | >; 78 | #[cfg(any( 79 | feature = "atmega168", 80 | feature = "atmega328p", 81 | feature = "atmega48p", 82 | feature = "atmega8" 83 | ))] 84 | avr_hal_generic::impl_spi! { 85 | hal: crate::Atmega, 86 | peripheral: crate::pac::SPI, 87 | sclk: port::PB5, 88 | mosi: port::PB3, 89 | miso: port::PB4, 90 | cs: port::PB2, 91 | } 92 | 93 | #[cfg(feature = "atmega328pb")] 94 | pub type Spi0 = avr_hal_generic::spi::Spi< 95 | crate::Atmega, 96 | crate::pac::SPI0, 97 | port::PB5, 98 | port::PB3, 99 | port::PB4, 100 | port::PB2, 101 | >; 102 | #[cfg(feature = "atmega328pb")] 103 | avr_hal_generic::impl_spi! { 104 | hal: crate::Atmega, 105 | peripheral: crate::pac::SPI0, 106 | sclk: port::PB5, 107 | mosi: port::PB3, 108 | miso: port::PB4, 109 | cs: port::PB2, 110 | } 111 | #[cfg(feature = "atmega328pb")] 112 | pub type Spi1 = avr_hal_generic::spi::Spi< 113 | crate::Atmega, 114 | crate::pac::SPI1, 115 | port::PC1, 116 | port::PE3, 117 | port::PC0, 118 | port::PE2, 119 | >; 120 | #[cfg(feature = "atmega328pb")] 121 | avr_hal_generic::impl_spi! { 122 | hal: crate::Atmega, 123 | peripheral: crate::pac::SPI1, 124 | sclk: port::PC1, 125 | mosi: port::PE3, 126 | miso: port::PC0, 127 | cs: port::PE2, 128 | } 129 | 130 | #[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] 131 | pub type Spi = avr_hal_generic::spi::Spi< 132 | crate::Atmega, 133 | crate::pac::SPI, 134 | port::PB7, 135 | port::PB5, 136 | port::PB6, 137 | port::PB4, 138 | >; 139 | #[cfg(any(feature = "atmega1284p", feature = "atmega32a"))] 140 | avr_hal_generic::impl_spi! { 141 | hal: crate::Atmega, 142 | peripheral: crate::pac::SPI, 143 | sclk: port::PB7, 144 | mosi: port::PB5, 145 | miso: port::PB6, 146 | cs: port::PB4, 147 | } 148 | -------------------------------------------------------------------------------- /ravedude/README.md: -------------------------------------------------------------------------------- 1 | ravedude [![crates.io page](https://img.shields.io/crates/v/ravedude.svg)](https://crates.io/crates/ravedude) 2 | ======== 3 | `ravedude` is a CLI utility to make Rust development for AVR microcontrollers 4 | super smooth. It's a wrapper around `avrdude` and provides easy access to the 5 | target's serial console, similar to the Arduino IDE. 6 | 7 | 8 | `ravedude` is meant to be used as a cargo "runner". This allows you to just use 9 | `cargo run` for building, deploying, and running your AVR code! 10 | 11 | 12 | if you get an `Error: no matching serial port found, use -P or set RAVEDUDE_PORT in your environment` , 13 | run `cargo run` with set environment variable or adjust `runner = "ravedude {X} -cb {X} -P /dev/ttyUSB{X}"` inside `.cargo/config.toml` (replace {X} with your respective values) 14 | 15 | 16 | ## Installation 17 | On Linux systems, you'll need pkg-config and libudev development files 18 | installed: 19 | 20 | 21 | - *Archlinux*: `pacman -S systemd pkgconf` 22 | - *Ubuntu/Debian*: `apt install libudev-dev pkg-config` 23 | - *Fedora*: `dnf install systemd-devel pkgconf-pkg-config` 24 | 25 | 26 | Next, install the latest version from crates.io with the following command: 27 | 28 | 29 | ```bash 30 | cargo +stable install --locked ravedude 31 | ``` 32 | 33 | 34 | Alternatively, if you're using Nix (the package manager) + Flakes, you can install `ravedude` by adding `inputs.ravedude.url = "github:Rahix/avr-hal?dir=ravedude";` and use the package `ravedude.packages."${system}".default`. 35 | 36 | 37 | Now you need to add *ravedude* to your project. For example in a project for 38 | Arduino Uno, place the following into your `.cargo/config.toml` (**not in 39 | `Cargo.toml`**): 40 | 41 | 42 | ```toml 43 | [target.'cfg(target_arch = "avr")'] 44 | runner = "ravedude uno --open-console --baudrate 57600" 45 | ``` 46 | 47 | 48 | And that's all, now just call `cargo run` and watch it do its magic: 49 | 50 | 51 |
avr-hal/examples/arduino-uno on ravedude via v1.51.0-nightly 
52 |  cargo run --bin uno-i2cdetect
53 |    Compiling arduino-uno-examples v0.0.0 (avr-hal/examples/arduino-uno)
54 |     Finished dev [optimized + debuginfo] target(s) in 1.26s
55 |      Running `ravedude uno -cb 57600 avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf`
56 |        Board Arduino Uno
57 |  Programming avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf => /dev/ttyACM0
58 | 
59 | 
60 | avrdude: AVR device initialized and ready to accept instructions
61 | 
62 | 
63 | Reading | ################################################## | 100% 0.00s
64 | 
65 | 
66 | avrdude: Device signature = 0x1e950f (probably m328p)
67 | avrdude: erasing chip
68 | avrdude: reading input file "avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf"
69 | avrdude: writing flash (1654 bytes):
70 | 
71 | 
72 | Writing | ################################################## | 100% 0.27s
73 | 
74 | 
75 | avrdude: 1654 bytes of flash written
76 | avrdude: verifying flash memory against avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf:
77 | avrdude: load data flash data from input file avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf:
78 | avrdude: input file avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf contains 1654 bytes
79 | avrdude: reading on-chip flash data:
80 | 
81 | 
82 | Reading | ################################################## | 100% 0.21s
83 | 
84 | 
85 | avrdude: verifying ...
86 | avrdude: 1654 bytes of flash verified
87 | 
88 | 
89 | avrdude: safemode: Fuses OK (E:00, H:00, L:00)
90 | 
91 | 
92 | avrdude done.  Thank you.
93 | 
94 | 
95 |   Programmed avr-hal/target/avr-atmega328p/debug/uno-i2cdetect.elf
96 |      Console /dev/ttyACM0 at 57600 baud
97 | 


--------------------------------------------------------------------------------
/mcu/atmega-hal/src/i2c.rs:
--------------------------------------------------------------------------------
  1 | //! I2C
  2 | //!
  3 | //! # Example
  4 | //!
  5 | //! Complete example source code can be found in the repository:
  6 | //! [`atmega2560-i2cdetect.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs)
  7 | //!
  8 | //! ```
  9 | //! let dp = atmega_hal::Peripherals::take().unwrap();
 10 | //! let pins = atmega_hal::pins!(dp);
 11 | //!
 12 | //! let mut i2c = I2c::new(
 13 | //!     dp.TWI,
 14 | //!     pins.pd1.into_pull_up_input(),
 15 | //!     pins.pd0.into_pull_up_input(),
 16 | //!     50_000,
 17 | //! );
 18 | //!
 19 | //! i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read).unwrap();
 20 | //! ```
 21 | 
 22 | #[allow(unused_imports)]
 23 | use crate::port;
 24 | pub use avr_hal_generic::i2c::*;
 25 | 
 26 | #[cfg(any(
 27 |     feature = "atmega128a",
 28 |     feature = "atmega1280",
 29 |     feature = "atmega2560",
 30 |     feature = "atmega32u4"
 31 | ))]
 32 | pub type I2c = avr_hal_generic::i2c::I2c<
 33 |     crate::Atmega,
 34 |     crate::pac::TWI,
 35 |     port::Pin,
 36 |     port::Pin,
 37 |     CLOCK,
 38 | >;
 39 | #[cfg(any(
 40 |     feature = "atmega128a",
 41 |     feature = "atmega1280",
 42 |     feature = "atmega2560",
 43 |     feature = "atmega32u4"
 44 | ))]
 45 | avr_hal_generic::impl_i2c_twi! {
 46 |     hal: crate::Atmega,
 47 |     peripheral: crate::pac::TWI,
 48 |     sda: port::PD1,
 49 |     scl: port::PD0,
 50 | }
 51 | 
 52 | #[cfg(any(feature = "atmega164pa"))]
 53 | pub type I2c = avr_hal_generic::i2c::I2c<
 54 |     crate::Atmega,
 55 |     crate::pac::TWI,
 56 |     port::Pin,
 57 |     port::Pin,
 58 |     CLOCK,
 59 | >;
 60 | #[cfg(any(feature = "atmega164pa"))]
 61 | avr_hal_generic::impl_i2c_twi! {
 62 |     hal: crate::Atmega,
 63 |     peripheral: crate::pac::TWI,
 64 |     sda: port::PC1,
 65 |     scl: port::PC0,
 66 | }
 67 | 
 68 | #[cfg(any(
 69 |     feature = "atmega328p",
 70 |     feature = "atmega168",
 71 |     feature = "atmega48p",
 72 |     feature = "atmega8"
 73 | ))]
 74 | pub type I2c = avr_hal_generic::i2c::I2c<
 75 |     crate::Atmega,
 76 |     crate::pac::TWI,
 77 |     port::Pin,
 78 |     port::Pin,
 79 |     CLOCK,
 80 | >;
 81 | #[cfg(any(
 82 |     feature = "atmega328p",
 83 |     feature = "atmega168",
 84 |     feature = "atmega48p",
 85 |     feature = "atmega8"
 86 | ))]
 87 | avr_hal_generic::impl_i2c_twi! {
 88 |     hal: crate::Atmega,
 89 |     peripheral: crate::pac::TWI,
 90 |     sda: port::PC4,
 91 |     scl: port::PC5,
 92 | }
 93 | 
 94 | #[cfg(any(feature = "atmega328pb"))]
 95 | pub type I2c0 = avr_hal_generic::i2c::I2c<
 96 |     crate::Atmega,
 97 |     crate::pac::TWI0,
 98 |     port::Pin,
 99 |     port::Pin,
100 |     CLOCK,
101 | >;
102 | #[cfg(any(feature = "atmega328pb"))]
103 | avr_hal_generic::impl_i2c_twi! {
104 |     hal: crate::Atmega,
105 |     peripheral: crate::pac::TWI0,
106 |     sda: port::PC4,
107 |     scl: port::PC5,
108 | }
109 | #[cfg(any(feature = "atmega328pb"))]
110 | pub type I2c1 = avr_hal_generic::i2c::I2c<
111 |     crate::Atmega,
112 |     crate::pac::TWI1,
113 |     port::Pin,
114 |     port::Pin,
115 |     CLOCK,
116 | >;
117 | #[cfg(any(feature = "atmega328pb"))]
118 | avr_hal_generic::impl_i2c_twi! {
119 |     hal: crate::Atmega,
120 |     peripheral: crate::pac::TWI1,
121 |     sda: port::PE0,
122 |     scl: port::PE1,
123 | }
124 | 
125 | #[cfg(any(feature = "atmega1284p", feature = "atmega32a"))]
126 | pub type I2c = avr_hal_generic::i2c::I2c<
127 |     crate::Atmega,
128 |     crate::pac::TWI,
129 |     port::Pin,
130 |     port::Pin,
131 |     CLOCK,
132 | >;
133 | #[cfg(any(feature = "atmega1284p", feature = "atmega32a"))]
134 | avr_hal_generic::impl_i2c_twi! {
135 |     hal: crate::Atmega,
136 |     peripheral: crate::pac::TWI,
137 |     sda: port::PC1,
138 |     scl: port::PC0,
139 | }
140 | 


--------------------------------------------------------------------------------
/mcu/atmega-hal/src/port.rs:
--------------------------------------------------------------------------------
  1 | //! Port
  2 | //!
  3 | //! # Example
  4 | //!
  5 | //! Complete example source code can be found in the repository:
  6 | //! [`atmega2560-blink.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-blink.rs)
  7 | //!
  8 | //! ```
  9 | //! let dp = atmega_hal::Peripherals::take().unwrap();
 10 | //! let pins = atmega_hal::pins!(dp);
 11 | //!
 12 | //! let mut led = pins.pb7.into_output();
 13 | //!
 14 | //! loop {
 15 | //!     led.toggle();
 16 | //!     delay_ms(1000);
 17 | //! }
 18 | //! ```
 19 | 
 20 | pub use avr_hal_generic::port::{mode, PinMode, PinOps};
 21 | 
 22 | #[cfg(any(feature = "atmega48p", feature = "atmega168", feature = "atmega328p"))]
 23 | avr_hal_generic::impl_port_traditional! {
 24 |     enum Ports {
 25 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 26 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6],
 27 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 28 |     }
 29 | }
 30 | 
 31 | #[cfg(any(feature = "atmega164pa"))]
 32 | avr_hal_generic::impl_port_traditional! {
 33 |     enum Ports {
 34 |         A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6 ,7],
 35 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6 ,7],
 36 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6 ,7],
 37 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6 ,7],
 38 |     }
 39 | }
 40 | 
 41 | #[cfg(feature = "atmega328pb")]
 42 | avr_hal_generic::impl_port_traditional! {
 43 |     enum Ports {
 44 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 45 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6],
 46 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 47 |         E: crate::pac::PORTE = [0, 1, 2, 3],
 48 |     }
 49 | }
 50 | 
 51 | #[cfg(feature = "atmega32u4")]
 52 | avr_hal_generic::impl_port_traditional! {
 53 |     enum Ports {
 54 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 55 |         C: crate::pac::PORTC = [6, 7],
 56 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 57 |         E: crate::pac::PORTE = [2, 6],
 58 |         F: crate::pac::PORTF = [0, 1, 4, 5, 6, 7],
 59 |     }
 60 | }
 61 | 
 62 | #[cfg(any(feature = "atmega128a"))]
 63 | avr_hal_generic::impl_port_traditional! {
 64 |     enum Ports {
 65 |         A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7],
 66 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 67 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7],
 68 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 69 |         E: crate::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7],
 70 |         F: crate::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7],
 71 |         G: crate::pac::PORTG = [0, 1, 2, 3, 4],
 72 |     }
 73 | }
 74 | 
 75 | #[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
 76 | avr_hal_generic::impl_port_traditional! {
 77 |     enum Ports {
 78 |         A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7],
 79 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 80 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7],
 81 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 82 |         E: crate::pac::PORTE = [0, 1, 2, 3, 4, 5, 6, 7],
 83 |         F: crate::pac::PORTF = [0, 1, 2, 3, 4, 5, 6, 7],
 84 |         G: crate::pac::PORTG = [0, 1, 2, 3, 4, 5],
 85 |         H: crate::pac::PORTH = [0, 1, 2, 3, 4, 5, 6, 7],
 86 |         J: crate::pac::PORTJ = [0, 1, 2, 3, 4, 5, 6, 7],
 87 |         K: crate::pac::PORTK = [0, 1, 2, 3, 4, 5, 6, 7],
 88 |         L: crate::pac::PORTL = [0, 1, 2, 3, 4, 5, 6, 7],
 89 |     }
 90 | }
 91 | 
 92 | #[cfg(any(feature = "atmega1284p", feature = "atmega32a"))]
 93 | avr_hal_generic::impl_port_traditional! {
 94 |     enum Ports {
 95 |         A: crate::pac::PORTA = [0, 1, 2, 3, 4, 5, 6, 7],
 96 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
 97 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6, 7],
 98 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
 99 |     }
100 | }
101 | 
102 | #[cfg(any(feature = "atmega8"))]
103 | avr_hal_generic::impl_port_traditional! {
104 |     enum Ports {
105 |         B: crate::pac::PORTB = [0, 1, 2, 3, 4, 5, 6, 7],
106 |         C: crate::pac::PORTC = [0, 1, 2, 3, 4, 5, 6],
107 |         D: crate::pac::PORTD = [0, 1, 2, 3, 4, 5, 6, 7],
108 |     }
109 | }
110 | 


--------------------------------------------------------------------------------
/ravedude/src/board.rs:
--------------------------------------------------------------------------------
  1 | use std::{collections::HashMap, path::Path};
  2 | 
  3 | use crate::config;
  4 | 
  5 | fn get_all_boards() -> anyhow::Result> {
  6 |     toml::from_str(include_str!("boards.toml")).map_err(|err| {
  7 |         if cfg!(test) {
  8 |             anyhow::anyhow!(
  9 |                 "boards.toml in ravedude source is invalid.\n{}",
 10 |                 err.message()
 11 |             )
 12 |         } else {
 13 |             anyhow::anyhow!(
 14 |                 "boards.toml in ravedude source is invalid. This is a bug, please report it!\n{}",
 15 |                 err.message()
 16 |             )
 17 |         }
 18 |     })
 19 | }
 20 | 
 21 | pub fn get_board_from_name(board_name: &str) -> anyhow::Result {
 22 |     let mut all_boards = get_all_boards()?;
 23 | 
 24 |     Ok(config::RavedudeConfig {
 25 |         board_config: Some(all_boards.remove(board_name).ok_or_else(|| {
 26 |             let mut msg = format!("invalid board: {board_name}\n");
 27 | 
 28 |             msg.push_str("valid boards:");
 29 | 
 30 |             for board in all_boards.keys() {
 31 |                 msg.push('\n');
 32 |                 msg.push_str(&board);
 33 |             }
 34 |             anyhow::anyhow!(msg)
 35 |         })?),
 36 |         ..Default::default()
 37 |     })
 38 | }
 39 | 
 40 | pub fn get_board_from_manifest(manifest_path: &Path) -> anyhow::Result {
 41 |     Ok({
 42 |         let file_contents = std::fs::read_to_string(manifest_path)
 43 |             .map_err(|err| anyhow::anyhow!("Ravedude.toml read error:\n{}", err))?;
 44 | 
 45 |         let mut board: config::RavedudeConfig = toml::from_str(&file_contents)
 46 |             .map_err(|err| anyhow::anyhow!("invalid Ravedude.toml:\n{}", err))?;
 47 | 
 48 |         if let Some(board_config) = board.board_config.as_ref() {
 49 |             if let Some(board_name) = board.general_options.board.as_deref() {
 50 |                 anyhow::bail!(
 51 |                     "can't both have board in [general] and [board] section; set inherit = \"{}\" under [board] to inherit its options",
 52 |                     board_name
 53 |                 )
 54 |             }
 55 |             if let Some(inherit) = board_config.inherit.as_deref() {
 56 |                 let base_board = get_board_from_name(inherit)?.board_config.unwrap();
 57 |                 board.board_config = Some(board.board_config.take().unwrap().merge(base_board));
 58 |             }
 59 |         } else if let Some(board_name) = board.general_options.board.as_deref() {
 60 |             let base_board = get_board_from_name(board_name)?.board_config.unwrap();
 61 |             board.board_config = Some(base_board);
 62 |         }
 63 |         board
 64 |     })
 65 | }
 66 | 
 67 | #[cfg(test)]
 68 | mod tests {
 69 |     use super::get_all_boards;
 70 | 
 71 |     #[test]
 72 |     fn validate_board_list() -> anyhow::Result<()> {
 73 |         let all_boards = get_all_boards()?;
 74 | 
 75 |         for (name, board) in all_boards.iter() {
 76 |             assert!(
 77 |                 board.name.is_some(),
 78 |                 "Board {name:?} doesn't have a `name` key"
 79 |             );
 80 |             assert!(
 81 |                 board.inherit.is_none(),
 82 |                 "Board {name:?} has illegal `inherit` key"
 83 |             );
 84 |             assert!(
 85 |                 board.reset.is_some(),
 86 |                 "Board {name:?} doesn't have a `reset` key"
 87 |             );
 88 |             assert!(
 89 |                 board.avrdude.is_some(),
 90 |                 "Board {name:?} doesn't have an `avrdude` key"
 91 |             );
 92 |             let avrdude = board.avrdude.as_ref().unwrap();
 93 |             assert!(
 94 |                 avrdude.programmer.is_some(),
 95 |                 "Board {name:?}'s avrdude options doesn't have a `programmer` key"
 96 |             );
 97 |             assert!(
 98 |                 avrdude.partno.is_some(),
 99 |                 "Board {name:?}'s avrdude options doesn't have a `partno` key"
100 |             );
101 |             assert!(
102 |                 avrdude.baudrate.is_some(),
103 |                 "Board {name:?}'s avrdude options doesn't have a `baudrate` key"
104 |             );
105 |             assert!(
106 |                 avrdude.do_chip_erase.is_some(),
107 |                 "Board {name:?}'s avrdude options doesn't have a `do_chip_erase` key"
108 |             );
109 |         }
110 | 
111 |         Ok(())
112 |     }
113 | }
114 | 


--------------------------------------------------------------------------------