Skip to content

Commit

Permalink
examples: Add atmega-hal examples using ATmega2560
Browse files Browse the repository at this point in the history
Add some examples that demonstrate direct usage of `atmega-hal` instead
of going through `arduino-hal` like most examples currently do.
  • Loading branch information
armandas authored Apr 1, 2024
1 parent c565c1c commit e2c5433
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,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
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ members = [
"examples/arduino-mega1280",
"examples/arduino-nano",
"examples/arduino-uno",
"examples/atmega2560",
"examples/nano168",
"examples/sparkfun-promicro",
"examples/sparkfun-promini-3v3",
Expand Down
8 changes: 8 additions & 0 deletions examples/atmega2560/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -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"]
21 changes: 21 additions & 0 deletions examples/atmega2560/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "atmega2560-examples"
version = "0.0.0"
authors = ["Rahix <[email protected]>", "Armandas Jarušauskas <[email protected]>"]
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"]
5 changes: 5 additions & 0 deletions examples/atmega2560/README.md
Original file line number Diff line number Diff line change
@@ -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.
68 changes: 68 additions & 0 deletions examples/atmega2560/src/bin/atmega2560-adc.rs
Original file line number Diff line number Diff line change
@@ -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<crate::CoreClock>;

#[avr_device::entry]
fn main() -> ! {
let dp = atmega_hal::Peripherals::take().unwrap();
let pins = atmega_hal::pins!(dp);

let mut delay = Delay::<crate::CoreClock>::new();

// set up serial interface for text output
let mut serial = Usart::new(
dp.USART0,
pins.pe0,
pins.pe1.into_output(),
Baudrate::<crate::CoreClock>::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);
}
}
32 changes: 32 additions & 0 deletions examples/atmega2560/src/bin/atmega2560-blink.rs
Original file line number Diff line number Diff line change
@@ -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<crate::CoreClock>;

// 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);
}
}
40 changes: 40 additions & 0 deletions examples/atmega2560/src/bin/atmega2560-i2cdetect.rs
Original file line number Diff line number Diff line change
@@ -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<crate::CoreClock>;

#[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::<crate::CoreClock>::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 {}
}
58 changes: 58 additions & 0 deletions examples/atmega2560/src/bin/atmega2560-spi-feedback.rs
Original file line number Diff line number Diff line change
@@ -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::<crate::CoreClock>::new();

// set up serial interface for text output
let mut serial = Usart::new(
dp.USART0,
pins.pe0,
pins.pe1.into_output(),
Baudrate::<crate::CoreClock>::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);
}
}
31 changes: 31 additions & 0 deletions examples/atmega2560/src/bin/atmega2560-usart.rs
Original file line number Diff line number Diff line change
@@ -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::<crate::CoreClock>::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();
}
}

0 comments on commit e2c5433

Please sign in to comment.