commit 0f1eb8da31112ebc39fa15dcf3b38bb799843a5b Author: doryan Date: Thu Feb 20 19:16:06 2025 +0400 feat(neopixel): first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8ec2da8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,304 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arduino-hal" +version = "0.1.0" +source = "git+https://github.com/rahix/avr-hal?rev=3e362624547462928a219c40f9ea8e3a64f21e5f#3e362624547462928a219c40f9ea8e3a64f21e5f" +dependencies = [ + "atmega-hal", + "avr-device", + "avr-hal-generic", + "cfg-if 1.0.0", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "ufmt", +] + +[[package]] +name = "atmega-hal" +version = "0.1.0" +source = "git+https://github.com/rahix/avr-hal?rev=3e362624547462928a219c40f9ea8e3a64f21e5f#3e362624547462928a219c40f9ea8e3a64f21e5f" +dependencies = [ + "avr-device", + "avr-hal-generic", +] + +[[package]] +name = "avr-device" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546b09da5e933d18b790ccb5aae351371c6c4f8094a7b011dcd7c7e7fb69cc94" +dependencies = [ + "avr-device-macros", + "bare-metal", + "cfg-if 1.0.0", + "vcell", +] + +[[package]] +name = "avr-device-macros" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b108541dc1ea060dfa9b824acbded94f658f8daecca549144d05a4d01e65b6f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "avr-hal-generic" +version = "0.1.0" +source = "git+https://github.com/rahix/avr-hal?rev=3e362624547462928a219c40f9ea8e3a64f21e5f#3e362624547462928a219c40f9ea8e3a64f21e5f" +dependencies = [ + "avr-device", + "cfg-if 0.1.10", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-bus", + "embedded-storage", + "nb 1.1.0", + "paste", + "rustversion", + "ufmt", + "unwrap-infallible", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-bus" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b4e6ede84339ebdb418cd986e6320a34b017cdf99b5cc3efceec6450b06886" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-storage" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723dce4e9f25b6e6c5f35628e144794e5b459216ed7da97b7c4b66cdb3fa82ca" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "neopixel_avr" +version = "0.1.0" +dependencies = [ + "arduino-hal", + "avr-device", + "embedded-hal 1.0.0", + "nb 1.1.0", + "neopixel_macros", + "panic-halt", + "proc-macro2", + "smart-leds", + "smart-leds-trait", + "ufmt", +] + +[[package]] +name = "neopixel_macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "syn 2.0.58", +] + +[[package]] +name = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "smart-leds" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66df34e571fa9993fa6f99131a374d58ca3d694b75f9baac93458fe0d6057bf0" +dependencies = [ + "smart-leds-trait", +] + +[[package]] +name = "smart-leds-trait" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edeb89c73244414bb0568611690dd095b2358b3fda5bae65ad784806cca00157" +dependencies = [ + "rgb", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "ufmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a64846ec02b57e9108d6469d98d1648782ad6bb150a95a9baac26900bbeab9d" +dependencies = [ + "ufmt-macros", + "ufmt-write", +] + +[[package]] +name = "ufmt-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d337d3be617449165cb4633c8dece429afd83f84051024079f97ad32a9663716" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ufmt-write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..485688c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "neopixel_avr" +version = "0.1.0" +edition = "2021" + +[dependencies] +panic-halt = "0.2.0" +ufmt = "0.2.0" +nb = "1.1.0" +embedded-hal = "1.0" +smart-leds-trait = "0.3.1" +smart-leds = "0.4.0" + +[dependencies.neopixel_macros] +path = "neopixel_macros" + +[dependencies.avr-device] +version = "0.5.4" +features = ["atmega32u4"] + +[dependencies.arduino-hal] +git = "https://github.com/rahix/avr-hal" +rev = "3e362624547462928a219c40f9ea8e3a64f21e5f" +features = ["sparkfun-promicro"] + +[build-dependencies.proc-macro2] +version = "=1.0.79" + diff --git a/neopixel_macros/Cargo.lock b/neopixel_macros/Cargo.lock new file mode 100644 index 0000000..ac52083 --- /dev/null +++ b/neopixel_macros/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "neopixel_macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" diff --git a/neopixel_macros/Cargo.toml b/neopixel_macros/Cargo.toml new file mode 100644 index 0000000..36b36e7 --- /dev/null +++ b/neopixel_macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "neopixel_macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc_macro = true + +[dependencies] +syn = "2.0.58" + +[build-dependencies.proc-macro2] +version = "=1.0.79" diff --git a/neopixel_macros/rust-toolchain.toml b/neopixel_macros/rust-toolchain.toml new file mode 100644 index 0000000..d0c456a --- /dev/null +++ b/neopixel_macros/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-03-22" +components = [ "rust-src" ] +profile = "complete" diff --git a/neopixel_macros/src/lib.rs b/neopixel_macros/src/lib.rs new file mode 100644 index 0000000..75cbac5 --- /dev/null +++ b/neopixel_macros/src/lib.rs @@ -0,0 +1,54 @@ +#![feature(proc_macro_quote)] +#![no_std] + +use core::str::FromStr; + +extern crate alloc; + +use alloc::string::ToString; +use proc_macro::{quote, TokenStream}; +use syn::parse; + +#[proc_macro] +pub fn impl_static_pin(pin: TokenStream) -> TokenStream { + let parsing_result = parse::(pin.clone()); + + if let Ok(ident) = parsing_result { + let pin = TokenStream::from_str(ident.to_string().as_str()).unwrap(); + let mut identifier = ident.to_string(); + identifier.insert_str(1, "ORT"); + + let pin_num = identifier.pop().unwrap(); + + if pin_num.is_ascii_digit() { + let pin_num = TokenStream::from_str(&pin_num.to_string()).unwrap(); + + let port_field = TokenStream::from_str(&identifier.to_ascii_lowercase()).unwrap(); + + let port_ident = TokenStream::from_str(identifier.as_str()).unwrap(); + let trait_ident = TokenStream::from_str("StaticPin").unwrap(); + + quote! { + impl $trait_ident for $pin { + type Port = $port_ident; + const PIN_NUM: u8 = $pin_num; + + fn write(data: u8) { + unsafe { + (*Self::Port::ptr()) + .$port_field + .write(|w| w.bits(data)); + } + } + fn read() -> u8 { + unsafe { (*Self::Port::ptr()).$port_field.read().bits() } + } + } + } + } else { + unreachable!() + } + } else { + unreachable!() + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..7426853 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-06-13" +components = [ "rust-src" ] +profile = "complete" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9914b9a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,96 @@ +#![no_std] +#![feature(asm_experimental_arch)] + +extern crate core; + +mod macros; +mod types; + +use types::*; + +use core::arch::asm; + +use arduino_hal::{ + delay_us, + hal::port::{PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7}, + pac::PORTD, + port::{mode::Output, Pin, PinOps}, +}; +use avr_device::interrupt::free; +use neopixel_macros::impl_static_pin; + +use smart_leds::{SmartLedsWrite, RGB8}; + +const LAST_BIT: u8 = 0x80; + +#[repr(transparent)] +pub struct Neopixel

{ + _pin: Pin, +} + +impl

Neopixel

+where + P: PinOps + StaticPin, +{ + #[inline] + pub const fn new(_pin: Pin) -> Self { + Self { _pin } + } +} + +impl

SmartLedsWrite for Neopixel

+where + P: PinOps + StaticPin, +{ + type Error = (); + type Color = smart_leds::RGB; + fn write(&mut self, iterator: T) -> Result<(), Self::Error> + where + T: IntoIterator, + I: Into, + { + free(|_cs| { + for i in iterator { + let RGB8 { r, g, b } = i.into(); + for value in [g, r, b] { + self.priv_write(value); + } + } + }); + Ok(()) + } +} + +impl

Neopixel

+where + P: PinOps + StaticPin, +{ + fn priv_write(&self, data: u8) { + let (mut count, mut data, port_data, pin_data) = (8, data, P::read(), 1 << P::PIN_NUM); + unsafe { + while count > 0 { + P::write(port_data | pin_data); + asm!("rjmp +0"); + if data & LAST_BIT == 0 { + P::write(port_data & !pin_data); + } + asm!( + " + rjmp +0 + rjmp +0 + " + ); + P::write(port_data & !pin_data); + asm!( + " + rjmp +0 + rjmp +0 + rjmp +0 + " + ); + data <<= 1; + count -= 1; + } + } + } +} diff --git a/src/macros/mod.rs b/src/macros/mod.rs new file mode 100644 index 0000000..57d237d --- /dev/null +++ b/src/macros/mod.rs @@ -0,0 +1,8 @@ +#[macro_export] +macro_rules! impl_static_pins { + ($($pin:ident),+) => { + $( + impl_static_pin!($pin); + )+ + }; +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..7c5ec70 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,2 @@ +mod static_pin; +pub(crate) use static_pin::*; diff --git a/src/types/static_pin.rs b/src/types/static_pin.rs new file mode 100644 index 0000000..d04b482 --- /dev/null +++ b/src/types/static_pin.rs @@ -0,0 +1,16 @@ +use arduino_hal::{hal::port::*, pac::*}; + +use crate::{impl_static_pin, impl_static_pins}; + +pub trait StaticPin { + type Port; + const PIN_NUM: u8; + + fn write(data: u8); + fn read() -> u8; +} + +impl_static_pins!( + PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PC6, PC7, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PE2, + PE6, PF0, PF1, PF4, PF5, PF6, PF7 +);