Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add atmega328p-hal & arduino-uno support #3

Merged
merged 9 commits into from Jun 27, 2019
2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -18,11 +18,13 @@ members = [
"avr-hal-generic",

# The chip definitions
"chips/atmega328p-hal",
"chips/atmega32u4-hal",
"chips/attiny85-hal",

# The board crates
"boards/arduino-leonardo",
"boards/arduino-uno",
"boards/trinket",
]

Expand Down
15 changes: 15 additions & 0 deletions boards/arduino-uno/Cargo.toml
@@ -0,0 +1,15 @@
[package]
name = "arduino-uno"
version = "0.1.0"
authors = ["Jonah Dahlquist <jonah@jonah.name>"]
edition = "2018"

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

[dev-dependencies]
panic-halt = "0.2.0"
nb = "0.1.2"
ufmt = "0.1.0-beta.4"

1 change: 1 addition & 0 deletions boards/arduino-uno/avr-atmega328p.json
33 changes: 33 additions & 0 deletions boards/arduino-uno/examples/uno-blink.rs
@@ -0,0 +1,33 @@
#![no_std]
#![no_main]

extern crate panic_halt;
use arduino_uno::prelude::*;

#[no_mangle]
pub extern fn main() -> ! {
let dp = arduino_uno::Peripherals::take().unwrap();

let mut delay = arduino_uno::Delay::new();
let mut pins = arduino_uno::Pins::new(
dp.PORTB,
dp.PORTC,
dp.PORTD,
);

// Digital pin 13 is also connected to an onboard LED marked "L"
let mut led = pins.d13.into_output(&mut pins.ddr);

led.set_high().void_unwrap();

loop {
led.toggle().void_unwrap();
delay.delay_ms(200);
led.toggle().void_unwrap();
delay.delay_ms(200);
led.toggle().void_unwrap();
delay.delay_ms(200);
led.toggle().void_unwrap();
delay.delay_ms(800);
}
}
39 changes: 39 additions & 0 deletions boards/arduino-uno/examples/uno-i2cdetect.rs
@@ -0,0 +1,39 @@
#![no_std]
#![no_main]
#![feature(proc_macro_hygiene)]

extern crate panic_halt;
use arduino_uno::prelude::*;

#[no_mangle]
pub extern fn main() -> ! {
let dp = arduino_uno::Peripherals::take().unwrap();

let mut delay = arduino_uno::Delay::new();
let mut pins = arduino_uno::Pins::new(
dp.PORTB,
dp.PORTC,
dp.PORTD,
);
let mut serial = arduino_uno::Serial::new(
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
);
let mut i2c = arduino_uno::I2c::new(
dp.TWI,
pins.a4.into_pull_up_input(&mut pins.ddr),
pins.a5.into_pull_up_input(&mut pins.ddr),
50000,
);

ufmt::uwriteln!(&mut serial, "Write direction test:\r").unwrap();
i2c.i2cdetect(&mut serial, arduino_uno::hal::i2c::Direction::Write).unwrap();
ufmt::uwriteln!(&mut serial, "\r\nRead direction test:\r").unwrap();
i2c.i2cdetect(&mut serial, arduino_uno::hal::i2c::Direction::Read).unwrap();

loop {
delay.delay_ms(1000);
}
}
49 changes: 49 additions & 0 deletions boards/arduino-uno/examples/uno-panic.rs
@@ -0,0 +1,49 @@
#![no_std]
#![no_main]
#![feature(proc_macro_hygiene)]

use arduino_uno::prelude::*;

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let mut serial: arduino_uno::Serial<arduino_uno::hal::port::mode::Floating> = unsafe {
core::mem::uninitialized()
};

ufmt::uwriteln!(&mut serial, "Firmware panic!\r");

if let Some(loc) = info.location() {
ufmt::uwriteln!(
&mut serial,
" At {}:{}:{}\r",
loc.file(),
loc.line(),
loc.column(),
);
}

loop {}
}

#[no_mangle]
pub extern fn main() -> ! {
let dp = arduino_uno::Peripherals::take().unwrap();

let mut pins = arduino_uno::Pins::new(
dp.PORTB,
dp.PORTC,
dp.PORTD,
);

let mut serial = arduino_uno::Serial::new(
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap();
// Panic messages cannot yet be captured because they rely on core::fmt
// which is way too big for AVR
panic!();
}
39 changes: 39 additions & 0 deletions boards/arduino-uno/examples/uno-serial.rs
@@ -0,0 +1,39 @@
#![no_std]
#![no_main]
#![feature(proc_macro_hygiene)]

extern crate panic_halt;
use arduino_uno::prelude::*;

// This example opens a serial connection to the host computer. On most POSIX operating systems (like GNU/Linux or
// OSX), you can interface with the program by running (assuming the device appears as ttyACM0)
//
// $ sudo screen /dev/ttyACM0 57600

#[no_mangle]
pub extern fn main() -> ! {
let dp = arduino_uno::Peripherals::take().unwrap();

let mut pins = arduino_uno::Pins::new(
dp.PORTB,
dp.PORTC,
dp.PORTD,
);

let mut serial = arduino_uno::Serial::new(
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600,
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\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();
}
}
14 changes: 14 additions & 0 deletions boards/arduino-uno/src/lib.rs
@@ -0,0 +1,14 @@
#![no_std]

pub extern crate atmega328p_hal as hal;

mod pins;

pub use atmega328p_hal::atmega328p;
pub use crate::atmega328p::Peripherals;
pub use atmega328p_hal::prelude;
pub use crate::pins::*;

pub type Delay = hal::delay::Delay<hal::clock::MHz16>;
pub type Serial<IMODE> = hal::usart::Usart0<hal::clock::MHz16, IMODE>;
pub type I2c<M> = hal::i2c::I2c<hal::clock::MHz16, M>;
jonahbron marked this conversation as resolved.
Show resolved Hide resolved
134 changes: 134 additions & 0 deletions boards/arduino-uno/src/pins.rs
@@ -0,0 +1,134 @@
use atmega328p_hal::port::PortExt;

avr_hal_generic::impl_board_pins! {
#[port_defs]
use atmega328p_hal::port;

/// Generic DDR that works for all ports
pub struct DDR {
portb: crate::atmega328p::PORTB,
portc: crate::atmega328p::PORTC,
portd: crate::atmega328p::PORTD,
}

/// Reexport of the Leonardo's pins, with the names they have on the board
pub struct Pins {
/// `A0`
///
/// * ADC0 (ADC input channel 0)
/// * PCINT8 (pin change interrupt 8)
pub a0: portc::pc0::PC0,
/// `A1`
///
/// * ADC1 (ADC input channel 1)
/// * PCINT9 (pin change interrupt 9)
pub a1: portc::pc1::PC1,
/// `A2`
///
/// * ADC2 (ADC input channel 2)
/// * PCINT10 (pin change interrupt 10)
pub a2: portc::pc2::PC2,
/// `A3`
///
/// * ADC3 (ADC input channel 3)
/// * PCINT11 (pin change interrupt 11)
pub a3: portc::pc3::PC3,
/// `A4`
///
/// * ADC4 (ADC input channel 4)
/// * SDA (2-wire serial bus data input/output line)
/// * PCINT12 (pin change interrupt 12)
pub a4: portc::pc4::PC4,
/// `A5`
///
/// ADC5 (ADC input channel 5)
/// SCL (2-wire serial bus clock line)
/// PCINT13 (pin change interrupt 13)
pub a5: portc::pc5::PC5,

/// `D0` / `RX`
///
/// * RXD (USART input pin)
/// * PCINT16 (pin change interrupt 16)
pub d0: portd::pd0::PD0,
/// `D1` / `TX`
///
/// * TXD (USART output pin)
/// * PCINT17 (pin change interrupt 17)
pub d1: portd::pd1::PD1,
/// `D2`
///
/// * INT0 (external interrupt 0 input)
/// * PCINT18 (pin change interrupt 18)
pub d2: portd::pd2::PD2,
/// `D3`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * INT1 (external interrupt 1 input)
/// * OC2B (Timer/Counter2 output compare match B output)
/// * PCINT19 (pin change interrupt 19)
pub d3: portd::pd3::PD3,
/// `D4`
///
/// * XCK (USART external clock input/output)
/// * T0 (Timer/Counter 0 external counter input)
/// * PCINT20 (pin change interrupt 20)
pub d4: portd::pd4::PD4,
/// `D5`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * T1 (Timer/Counter 1 external counter input)
/// * OC0B (Timer/Counter0 output compare match B output)
/// * PCINT21 (pin change interrupt 21)
pub d5: portd::pd5::PD5,
/// `D6`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * AIN0 (analog comparator positive input)
/// * OC0A (Timer/Counter0 output compare match A output)
/// * PCINT22 (pin change interrupt 22)
pub d6: portd::pd6::PD6,
/// `D7`
///
/// * AIN1 (analog comparator negative input)
/// * PCINT23 (pin change interrupt 23)
pub d7: portd::pd7::PD7,
/// `D8`
///
/// * ICP1 (Timer/Counter1 input capture input)
/// * CLKO (divided system clock output)
/// * PCINT0 (pin change interrupt 0)
pub d8: portb::pb0::PB0,
/// `D9`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * OC1A (Timer/Counter1 output compare match A output)
/// * PCINT1 (pin change interrupt 1)
pub d9: portb::pb1::PB1,
/// `D10`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * SS (SPI bus master slave select)
/// * OC1B (Timer/Counter1 output compare match B output)
/// * PCINT2 (pin change interrupt 2)
pub d10: portb::pb2::PB2,
/// `D11`
///
/// * **PWM**: [atmega328p_hal::timer::Timer3Pwm]
/// * MOSI (SPI bus master/slave input)
/// * OC2A (Timer/Counter2 output compare match A output)
/// * PCINT3 (pin change interrupt 3)
pub d11: portb::pb3::PB3,
/// `D12`
///
/// * MISO (SPI bus master input/slave output)
/// * PCINT4 (pin change interrupt 4)
pub d12: portb::pb4::PB4,
/// `D13`
///
/// * SCK (SPI bus master clock input)
/// * PCINT5 (pin change interrupt 5)
/// * L LED on Arduino Uno
pub d13: portb::pb5::PB5,
jonahbron marked this conversation as resolved.
Show resolved Hide resolved
}
}
13 changes: 13 additions & 0 deletions chips/atmega328p-hal/Cargo.toml
@@ -0,0 +1,13 @@
[package]
name = "atmega328p-hal"
version = "0.1.0"
authors = ["Jonah Dahlquist <jonah@jonah.name>"]
edition = "2018"

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

[dependencies.avr-device]
git = "https://github.com/Rahix/avr-device"
features = ["atmega328p"]

29 changes: 29 additions & 0 deletions chips/atmega328p-hal/avr-atmega328p.json
@@ -0,0 +1,29 @@
{
"llvm-target": "avr-unknown-unknown",
"cpu": "atmega328p",
"target-endian": "little",
"target-pointer-width": "16",
"target-c-int-width": "16",
"os": "unknown",
"target-env": "",
"target-vendor": "unknown",
"arch": "avr",
"data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",

"executables": true,

"linker": "avr-gcc",
"linker-flavor": "gcc",
"pre-link-args": {
"gcc": ["-Os", "-mmcu=atmega328p"]
},
"exe-suffix": ".elf",
"post-link-args": {
"gcc": ["-Wl,--gc-sections"]
},

"singlethread": true,
"no-builtins": false,

"no-default-libraries": false
}