diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89507e7075..fc5b67c087 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,9 @@ jobs: - type: board name: nano168 examples: true + - type: board + name: digispark + examples: true - type: mcu name: atmega1280 spec: atmega1280 diff --git a/Cargo.toml b/Cargo.toml index ae61c621bb..15128bc7ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ members = [ "examples/sparkfun-promicro", "examples/trinket-pro", "examples/trinket", + "examples/digispark", ] exclude = [ # The RAVEDUDE! Yeah! diff --git a/arduino-hal/Cargo.toml b/arduino-hal/Cargo.toml index 5e5b69c043..a921dcfdde 100644 --- a/arduino-hal/Cargo.toml +++ b/arduino-hal/Cargo.toml @@ -23,6 +23,7 @@ trinket-pro = ["mcu-atmega", "atmega-hal/atmega328p", "board-selected"] sparkfun-promicro = ["mcu-atmega", "atmega-hal/atmega32u4", "board-selected"] trinket = ["mcu-attiny", "attiny-hal/attiny85", "board-selected"] nano168 = ["mcu-atmega", "atmega-hal/atmega168", "atmega-hal/enable-extra-adc", "board-selected"] +digispark = ["mcu-attiny", "attiny-hal/attiny85", "board-selected"] [dependencies] cfg-if = "1" diff --git a/arduino-hal/src/clock.rs b/arduino-hal/src/clock.rs index af1db44848..6a7332b2f6 100644 --- a/arduino-hal/src/clock.rs +++ b/arduino-hal/src/clock.rs @@ -24,6 +24,7 @@ pub(crate) mod default { feature = "sparkfun-promicro", feature = "trinket-pro", feature = "nano168", + feature = "digispark", ))] pub type DefaultClock = avr_hal_generic::clock::MHz16; #[cfg(feature = "trinket")] diff --git a/arduino-hal/src/lib.rs b/arduino-hal/src/lib.rs index 487c34ca0a..7c76558483 100644 --- a/arduino-hal/src/lib.rs +++ b/arduino-hal/src/lib.rs @@ -16,6 +16,7 @@ #![cfg_attr(feature = "trinket-pro", doc = "**Trinket Pro**.")] #![cfg_attr(feature = "trinket", doc = "**Trinket**.")] #![cfg_attr(feature = "nano168", doc = "**Nano clone (ATmega168)**.")] +#![cfg_attr(feature = "digispark", doc = "**Digispark (model A)**.")] //! This means that only items which are available for this board are visible. If you are using a //! different board, try building the documentation locally with //! @@ -62,6 +63,7 @@ compile_error!( * trinket-pro * trinket * nano168 + * digispark " ); diff --git a/arduino-hal/src/port/digispark.rs b/arduino-hal/src/port/digispark.rs new file mode 100644 index 0000000000..902c62a8f0 --- /dev/null +++ b/arduino-hal/src/port/digispark.rs @@ -0,0 +1,49 @@ +pub use attiny_hal::port::{mode, Pin, PinOps, PinMode}; + +avr_hal_generic::renamed_pins! { + type Pin = Pin; + + /// Pins of the **Digispark (model A)** . + /// + /// This struct is best initialized via the [`arduino_hal::pins!()`][crate::pins] macro. + pub struct Pins from attiny_hal::Pins { + /// `P0` + /// + /// * PWM: [attiny_hal::timer::Timer0Pwm] + /// * MOSI (SPI bus master/slave input) + /// * SDA (2-wire serial bus data input/output line) + /// * PCINT0 (pin change interrupt 0) + pub p0: attiny_hal::port::PB0 = pb0, + /// `P1` + /// + /// * PWM: [attiny_hal::timer::Timer0Pwm] + /// * MISO (SPI bus master input/slave output) + /// * PCINT1 (pin change interrupt 1) + pub p1: attiny_hal::port::PB1 = pb1, + /// `P2` + /// + /// * ADC1 (ADC input channel 1) + /// * SCK (SPI bus master clock input) + /// * SCL (2-wire serial bus clock line) + /// * PCINT2 (pin change interrupt 2) + pub p2: attiny_hal::port::PB2 = pb2, + /// `P3` + /// + /// * ADC3 (ADC input channel 3) + /// * USB+ (USB data + pin) + /// * PCINT3 (pin change interrupt 3) + pub p3: attiny_hal::port::PB3 = pb3, + /// `P4` + /// + /// * PWM: [attiny_hal::timer::Timer1Pwm] + /// * ADC2 (ADC input channel 2) + /// * USB- (USB data - pin) + /// * PCINT4 (pin change interrupt 4) + pub p4: attiny_hal::port::PB4 = pb4, + /// `P5` + /// + /// * ADC0 (ADC input channel 0) + /// * PCINT5 (pin change interrupt 5) + pub p5: attiny_hal::port::PB5 = pb5, + } +} diff --git a/arduino-hal/src/port/mod.rs b/arduino-hal/src/port/mod.rs index ce94ced476..9cea7f88b7 100644 --- a/arduino-hal/src/port/mod.rs +++ b/arduino-hal/src/port/mod.rs @@ -43,3 +43,7 @@ pub use trinket_pro::*; mod trinket; #[cfg(feature = "trinket")] pub use trinket::*; +#[cfg(feature = "digispark")] +mod digispark; +#[cfg(feature = "digispark")] +pub use digispark::*; diff --git a/examples/digispark/.cargo/config.toml b/examples/digispark/.cargo/config.toml new file mode 100644 index 0000000000..048bb69c4d --- /dev/null +++ b/examples/digispark/.cargo/config.toml @@ -0,0 +1,8 @@ +[build] +target = "../../avr-specs/avr-attiny85.json" + +[target.'cfg(target_arch = "avr")'] +runner = "ravedude digispark" + +[unstable] +build-std = ["core"] diff --git a/examples/digispark/Cargo.toml b/examples/digispark/Cargo.toml new file mode 100644 index 0000000000..320617e239 --- /dev/null +++ b/examples/digispark/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "digispark-examples" +version = "0.0.0" +authors = ["Petr Scheubrein "] +edition = "2021" + +[dependencies] +panic-halt = "0.2.0" +embedded-hal = "0.2.7" + +[dependencies.arduino-hal] +path = "../../arduino-hal/" +features = ["digispark"] diff --git a/examples/digispark/src/bin/digispark-blink.rs b/examples/digispark/src/bin/digispark-blink.rs new file mode 100644 index 0000000000..3a58d1a9f3 --- /dev/null +++ b/examples/digispark/src/bin/digispark-blink.rs @@ -0,0 +1,19 @@ +#![no_std] +#![no_main] + +use panic_halt as _; + +#[arduino_hal::entry] +fn main() -> ! { + let dp = arduino_hal::Peripherals::take().unwrap(); + let pins = arduino_hal::pins!(dp); + + // Digital pin 1 is also connected to the onboard LED + let mut led = pins.p1.into_output(); + led.set_high(); + + loop { + led.toggle(); + arduino_hal::delay_ms(100); + } +} diff --git a/ravedude/src/avrdude/avrdude.conf b/ravedude/src/avrdude/avrdude.conf index 9acaddc948..2453242149 100644 --- a/ravedude/src/avrdude/avrdude.conf +++ b/ravedude/src/avrdude/avrdude.conf @@ -874,6 +874,16 @@ programmer usbpid = 0x0c9f; ; +programmer + id = "micronucleus"; + desc = "Micronucleus for bootloader"; + type = "micronucleus"; + #prog_modes = PM_SPM; + connection_type = usb; + usbvid = 0x16d0; + usbpid = 0x0753; +; + programmer id = "butterfly"; desc = "Atmel Butterfly Development Board"; diff --git a/ravedude/src/avrdude/mod.rs b/ravedude/src/avrdude/mod.rs index 172d9ab19b..39a8e70a63 100644 --- a/ravedude/src/avrdude/mod.rs +++ b/ravedude/src/avrdude/mod.rs @@ -8,6 +8,21 @@ pub struct AvrdudeOptions<'a> { pub partno: &'a str, pub baudrate: Option, pub do_chip_erase: bool, + pub do_verify_check: bool, + pub extended_parameters: &'a [&'a str], +} + +impl<'a> Default for AvrdudeOptions<'a> { + fn default() -> Self { + AvrdudeOptions { + programmer: "", + partno: "", + baudrate: None, + do_chip_erase: true, + do_verify_check: true, + extended_parameters: &[], + } + } } #[derive(Debug)] @@ -84,6 +99,14 @@ impl Avrdude { command = command.arg("-b").arg(baudrate.to_string()); } + if !options.do_verify_check { + command = command.arg("-V"); + } + + for param in options.extended_parameters { + command = command.arg("-x").arg(param); + } + // TODO: Check that `bin` does not contain : let mut flash_instruction: std::ffi::OsString = "flash:w:".into(); flash_instruction.push(bin); diff --git a/ravedude/src/board.rs b/ravedude/src/board.rs index ce0ac79149..5f616ce0f4 100644 --- a/ravedude/src/board.rs +++ b/ravedude/src/board.rs @@ -21,6 +21,7 @@ pub fn get_board(board: &str) -> Option> { "trinket-pro" => Box::new(TrinketPro), "trinket" => Box::new(Trinket), "nano168" => Box::new(Nano168), + "digispark" => Box::new(Digispark), _ => return None, }) } @@ -63,6 +64,7 @@ impl Board for ArduinoUno { partno: "atmega328p", baudrate: None, do_chip_erase: true, + ..Default::default() } } @@ -93,6 +95,7 @@ impl Board for ArduinoMicro { partno: "atmega32u4", baudrate: Some(115200), do_chip_erase: true, + ..Default::default() } } @@ -125,6 +128,7 @@ impl Board for ArduinoNano { partno: "atmega328p", baudrate: Some(57600), do_chip_erase: true, + ..Default::default() } } @@ -150,6 +154,7 @@ impl Board for ArduinoNanoNew { partno: "atmega328p", baudrate: Some(115200), do_chip_erase: true, + ..Default::default() } } @@ -187,6 +192,7 @@ impl Board for ArduinoLeonardo { partno: "atmega32u4", baudrate: None, do_chip_erase: true, + ..Default::default() } } @@ -218,6 +224,7 @@ impl Board for ArduinoMega1280 { partno: "atmega1280", baudrate: Some(57600), do_chip_erase: false, + ..Default::default() } } @@ -245,6 +252,7 @@ impl Board for ArduinoMega2560 { partno: "atmega2560", baudrate: Some(115200), do_chip_erase: false, + ..Default::default() } } @@ -277,6 +285,7 @@ impl Board for ArduinoDiecimila { partno: "atmega168", baudrate: Some(19200), do_chip_erase: false, + ..Default::default() } } @@ -302,6 +311,7 @@ impl Board for SparkFunProMicro { partno: "atmega32u4", baudrate: None, do_chip_erase: true, + ..Default::default() } } @@ -332,6 +342,7 @@ impl Board for TrinketPro { partno: "atmega328p", baudrate: None, do_chip_erase: false, + ..Default::default() } } @@ -357,6 +368,7 @@ impl Board for Trinket { partno: "attiny85", baudrate: None, do_chip_erase: true, + ..Default::default() } } @@ -382,6 +394,7 @@ impl Board for Nano168 { partno: "atmega168", baudrate: Some(19200), do_chip_erase: false, + ..Default::default() } } @@ -389,3 +402,31 @@ impl Board for Nano168 { Some(Err(anyhow::anyhow!("Not able to guess port"))) } } + +struct Digispark; + +impl Board for Digispark { + fn display_name(&self) -> &str { + "Digispark (Model A)" + } + + fn needs_reset(&self) -> Option<&str> { + None + } + + fn avrdude_options(&self) -> avrdude::AvrdudeOptions { + avrdude::AvrdudeOptions { + programmer: "micronucleus", + partno: "attiny85", + baudrate: None, + do_chip_erase: true, + do_verify_check: false, + extended_parameters: &["wait"], + ..Default::default() + } + } + + fn guess_port(&self) -> Option> { + None + } +} diff --git a/ravedude/src/main.rs b/ravedude/src/main.rs index 4159682ef5..182a57e12b 100644 --- a/ravedude/src/main.rs +++ b/ravedude/src/main.rs @@ -64,6 +64,7 @@ struct Args { /// * trinket-pro /// * trinket /// * nano168 + /// * digispark #[structopt(name = "BOARD", verbatim_doc_comment)] board: String,