diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6829e98bf..1f1fbf6f5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,10 @@ jobs: - type: board name: nano168 examples: true + - type: board + # Not really a board, but also an examples crate + name: atmega2560 + examples: true - type: mcu name: atmega1280 spec: atmega1280 diff --git a/Cargo.toml b/Cargo.toml index 33bffe79e4..a6846b4a1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "examples/arduino-mega1280", "examples/arduino-nano", "examples/arduino-uno", + "examples/atmega2560", "examples/nano168", "examples/sparkfun-promicro", "examples/sparkfun-promini-5v", diff --git a/examples/atmega2560/.cargo/config.toml b/examples/atmega2560/.cargo/config.toml new file mode 100644 index 0000000000..b5ee8592cf --- /dev/null +++ b/examples/atmega2560/.cargo/config.toml @@ -0,0 +1,8 @@ +[build] +target = "../../avr-specs/avr-atmega2560.json" + +[target.'cfg(target_arch = "avr")'] +runner = "ravedude -cb 57600 mega2560" + +[unstable] +build-std = ["core"] diff --git a/examples/atmega2560/Cargo.toml b/examples/atmega2560/Cargo.toml new file mode 100644 index 0000000000..70c289cb76 --- /dev/null +++ b/examples/atmega2560/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "atmega2560-examples" +version = "0.0.0" +authors = ["Rahix ", "Armandas JaruĊĦauskas "] +edition = "2021" +publish = false + +[dependencies] +panic-halt = "0.2.0" +ufmt = "0.2.0" +nb = "1.1.0" +embedded-hal = "1.0" +avr-device = { version = "0.5.4", features = ["rt"] } + +[dependencies.embedded-hal-v0] +version = "0.2.3" +package = "embedded-hal" + +[dependencies.atmega-hal] +path = "../../mcu/atmega-hal/" +features = ["atmega2560"] diff --git a/examples/atmega2560/README.md b/examples/atmega2560/README.md new file mode 100644 index 0000000000..e66a2a53aa --- /dev/null +++ b/examples/atmega2560/README.md @@ -0,0 +1,5 @@ +# ATmega2560 Examples + +This directory includes examples of using plain `atmega-hal`, rather than the `hal` targeted at Arduino boards. + +The examples can be run and have been tested on the Arduino Mega2560 board. diff --git a/examples/atmega2560/src/bin/atmega2560-adc.rs b/examples/atmega2560/src/bin/atmega2560-adc.rs new file mode 100644 index 0000000000..ce801d19cc --- /dev/null +++ b/examples/atmega2560/src/bin/atmega2560-adc.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +use atmega_hal::adc::channel; +use atmega_hal::delay::Delay; +use atmega_hal::usart::{Baudrate, Usart}; +use embedded_hal::delay::DelayNs; +use panic_halt as _; + +// Define core clock in the root crate +type CoreClock = atmega_hal::clock::MHz16; +// Use it as follows in the rest of the project +type Adc = atmega_hal::adc::Adc; + +#[avr_device::entry] +fn main() -> ! { + let dp = atmega_hal::Peripherals::take().unwrap(); + let pins = atmega_hal::pins!(dp); + + let mut delay = Delay::::new(); + + // set up serial interface for text output + let mut serial = Usart::new( + dp.USART0, + pins.pe0, + pins.pe1.into_output(), + Baudrate::::new(57600), + ); + + let mut adc = Adc::new(dp.ADC, Default::default()); + + let (vbg, gnd) = ( + adc.read_blocking(&channel::Vbg), + adc.read_blocking(&channel::Gnd), + ); + ufmt::uwriteln!(&mut serial, "Vbandgap: {}", vbg).unwrap(); + ufmt::uwriteln!(&mut serial, "Ground: {}", gnd).unwrap(); + + // To store multiple channels in an array, we use the `into_channel()` method. + let channels: [atmega_hal::adc::Channel; 16] = [ + pins.pf0.into_analog_input(&mut adc).into_channel(), + pins.pf1.into_analog_input(&mut adc).into_channel(), + pins.pf2.into_analog_input(&mut adc).into_channel(), + pins.pf3.into_analog_input(&mut adc).into_channel(), + pins.pf4.into_analog_input(&mut adc).into_channel(), + pins.pf5.into_analog_input(&mut adc).into_channel(), + pins.pf6.into_analog_input(&mut adc).into_channel(), + pins.pf7.into_analog_input(&mut adc).into_channel(), + pins.pk0.into_analog_input(&mut adc).into_channel(), + pins.pk1.into_analog_input(&mut adc).into_channel(), + pins.pk2.into_analog_input(&mut adc).into_channel(), + pins.pk3.into_analog_input(&mut adc).into_channel(), + pins.pk4.into_analog_input(&mut adc).into_channel(), + pins.pk5.into_analog_input(&mut adc).into_channel(), + pins.pk6.into_analog_input(&mut adc).into_channel(), + pins.pk7.into_analog_input(&mut adc).into_channel(), + ]; + + loop { + for (i, ch) in channels.iter().enumerate() { + let v = adc.read_blocking(ch); + ufmt::uwrite!(&mut serial, "A{}: {} ", i, v).unwrap(); + } + + ufmt::uwriteln!(&mut serial, "").unwrap(); + delay.delay_ms(1000); + } +} diff --git a/examples/atmega2560/src/bin/atmega2560-blink.rs b/examples/atmega2560/src/bin/atmega2560-blink.rs new file mode 100644 index 0000000000..bd10bd71e2 --- /dev/null +++ b/examples/atmega2560/src/bin/atmega2560-blink.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] + +use panic_halt as _; +use embedded_hal::delay::DelayNs; + +// Define core clock. This can be used in the rest of the project. +type CoreClock = atmega_hal::clock::MHz16; +type Delay = atmega_hal::delay::Delay; + +// Below are examples of a delay helper functions +fn delay_ms(ms: u16) { + Delay::new().delay_ms(u32::from(ms)) +} + +#[allow(dead_code)] +fn delay_us(us: u32) { + Delay::new().delay_us(us) +} + +#[avr_device::entry] +fn main() -> ! { + let dp = atmega_hal::Peripherals::take().unwrap(); + let pins = atmega_hal::pins!(dp); + + let mut led = pins.pb7.into_output(); + + loop { + led.toggle(); + delay_ms(1000); + } +} diff --git a/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs b/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs new file mode 100644 index 0000000000..35f3e136cc --- /dev/null +++ b/examples/atmega2560/src/bin/atmega2560-i2cdetect.rs @@ -0,0 +1,40 @@ +#![no_std] +#![no_main] + +use atmega_hal::usart::{Baudrate, Usart}; +use panic_halt as _; + +// Define core clock in the root crate +type CoreClock = atmega_hal::clock::MHz16; +// Use it as follows in the rest of the project +type I2c = atmega_hal::i2c::I2c; + +#[avr_device::entry] +fn main() -> ! { + let dp = atmega_hal::Peripherals::take().unwrap(); + let pins = atmega_hal::pins!(dp); + + // set up serial interface for text output + let mut serial = Usart::new( + dp.USART0, + pins.pe0, + pins.pe1.into_output(), + Baudrate::::new(57600), + ); + + let mut i2c = I2c::new( + dp.TWI, + pins.pd1.into_pull_up_input(), + pins.pd0.into_pull_up_input(), + 50_000, + ); + + ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap(); + i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Write) + .unwrap(); + ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap(); + i2c.i2cdetect(&mut serial, atmega_hal::i2c::Direction::Read) + .unwrap(); + + loop {} +} diff --git a/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs b/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs new file mode 100644 index 0000000000..37dfc6213a --- /dev/null +++ b/examples/atmega2560/src/bin/atmega2560-spi-feedback.rs @@ -0,0 +1,58 @@ +//! This example demonstrates how to set up a SPI interface and communicate +//! over it. The physical hardware configuration consists of connecting a +//! jumper directly from pin `PB2` to pin `PB3`. +//! +//! Run the program using `cargo run`. +//! You should see it output the line `data: 42` repeatedly. +//! If the output you see is `data: 255`, you may need to check your jumper. + +#![no_std] +#![no_main] + +use atmega_hal::spi; +use atmega_hal::usart::{Baudrate, Usart}; +use atmega_hal::delay::Delay; +use embedded_hal::delay::DelayNs; +use embedded_hal::spi::SpiBus; +use panic_halt as _; + +// Define core clock. This can be used in the rest of the project. +type CoreClock = atmega_hal::clock::MHz16; + +#[avr_device::entry] +fn main() -> ! { + let dp = atmega_hal::Peripherals::take().unwrap(); + let pins = atmega_hal::pins!(dp); + + let mut delay = Delay::::new(); + + // set up serial interface for text output + let mut serial = Usart::new( + dp.USART0, + pins.pe0, + pins.pe1.into_output(), + Baudrate::::new(57600), + ); + + // Create SPI interface. + let (mut spi, _) = spi::Spi::new( + dp.SPI, + pins.pb1.into_output(), + pins.pb2.into_output(), + pins.pb3.into_pull_up_input(), + pins.pb0.into_output(), + spi::Settings::default(), + ); + + loop { + // Send a byte + let data_out: [u8; 1] = [42]; + let mut data_in: [u8; 1] = [0]; + // Send a byte + // Because MISO is connected to MOSI, the read data should be the same + spi.transfer(&mut data_in, &data_out).unwrap(); + + ufmt::uwriteln!(&mut serial, "data: {}\r", data_in[0]).unwrap(); + delay.delay_ms(1000); + } +} diff --git a/examples/atmega2560/src/bin/atmega2560-usart.rs b/examples/atmega2560/src/bin/atmega2560-usart.rs new file mode 100644 index 0000000000..30781e7fbd --- /dev/null +++ b/examples/atmega2560/src/bin/atmega2560-usart.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use atmega_hal::prelude::*; +use atmega_hal::usart::{Baudrate, Usart}; +use panic_halt as _; + +// Define core clock. This can be used in the rest of the project. +type CoreClock = atmega_hal::clock::MHz16; + +#[avr_device::entry] +fn main() -> ! { + let dp = atmega_hal::Peripherals::take().unwrap(); + let pins = atmega_hal::pins!(dp); + let mut serial = Usart::new( + dp.USART0, + pins.pe0, + pins.pe1.into_output(), + Baudrate::::new(57600), + ); + + ufmt::uwriteln!(&mut serial, "Hello from ATmega!\r").unwrap(); + + loop { + // Read a byte from the serial connection + let b = nb::block!(serial.read()).unwrap(); + + // Answer + ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap(); + } +}