From 9ff9f51c07f7226d6467bc9db608cc53c82365bd Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 6 Aug 2019 08:53:42 -0400 Subject: Initial commit. --- .cargo/config | 2 + .gitignore | 4 + Cargo.lock | 390 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 25 ++++ Makefile | 52 ++++++++ find-serial-port | 16 +++ src/dotstar.rs | 42 ++++++ src/logger.rs | 139 ++++++++++++++++++++ src/macros.rs | 15 +++ src/main.rs | 144 ++++++++++++++++++++ src/rtc.rs | 74 +++++++++++ 11 files changed, 903 insertions(+) create mode 100644 .cargo/config create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Makefile create mode 100755 find-serial-port create mode 100644 src/dotstar.rs create mode 100644 src/logger.rs create mode 100644 src/macros.rs create mode 100755 src/main.rs create mode 100644 src/rtc.rs diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..b10f29d --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "thumbv6m-none-eabi" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27bca1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.bin +*.uf2 +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..432a5ce --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,390 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aligned" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "aligned" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "apa102-spi" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "as-slice" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atsamd-hal" +version = "0.6.0" +source = "git+https://github.com/atsamd-rs/atsamd?rev=97d55c19#97d55c19f0e5234cf9766311477bc696357271fd" +dependencies = [ + "atsamd21e18a 0.5.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)", + "bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atsamd21e18a" +version = "0.5.0" +source = "git+https://github.com/atsamd-rs/atsamd?rev=97d55c19#97d55c19f0e5234cf9766311477bc696357271fd" +dependencies = [ + "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bare-metal" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bleusb" +version = "0.1.0" +dependencies = [ + "apa102-spi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smart-leds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "starb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trinket_m0 0.4.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)", +] + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clint" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cortex-m" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cortex-m" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cortex-m-rt" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cortex-m-rt-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "embedded-hal" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "paste" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paste-impl" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "r0" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rgb" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smart-leds" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smart-leds-trait" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "starb" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.15.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trinket_m0" +version = "0.4.0" +source = "git+https://github.com/atsamd-rs/atsamd?rev=97d55c19#97d55c19f0e5234cf9766311477bc696357271fd" +dependencies = [ + "atsamd-hal 0.6.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)", + "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vcell" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "volatile-register" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5" +"checksum aligned 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a316c7ea8e1e9ece54862c992def5a7ac14de9f5832b69d71760680efeeefa" +"checksum apa102-spi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "244c305e53cabeadfce23409fe24bfcedaa20166aa3f16f6c4ab256302158fd5" +"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27" +"checksum atsamd-hal 0.6.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)" = "" +"checksum atsamd21e18a 0.5.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)" = "" +"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" +"checksum bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum clint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "200296af81a4cbe7da52afd9e5c35b7782eca865678caf2280251b777c9c37aa" +"checksum cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0b159a1e8306949579de3698c841dba58058197b65c60807194e4fa1e7a554" +"checksum cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c18719fdc57db65668bfc977db9a0fa1a41d718c5d9cd4f652c9d4b0e0956a" +"checksum cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17805910e3ecf029bdbfcc42b7384d9e3d9e5626153fa810002c1ef9839338ac" +"checksum cortex-m-rt-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ae692573e0acccb1579fef1abf5a5bf1d2f3f0149a22b16870ec9309aee25f" +"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc" +"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" +"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" +"checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" +"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum smart-leds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0a30e934e60850bfc020d4c2727cc8a3635371f6af2cb3f55f36f0134ed080" +"checksum smart-leds-trait 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef18e60d41a6fde19e640cd7590c03fb27aa23146bf60e4da85028d7410cee7" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum starb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36de9f301031f2a692afe144c8a757950d2b60b7fbf447055b8e19a9c232fb2c" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" +"checksum trinket_m0 0.4.0 (git+https://github.com/atsamd-rs/atsamd?rev=97d55c19)" = "" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..003cfcb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "bleusb" +version = "0.1.0" +authors = ["Brian Cully "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +embedded-hal = "0.2" +#atsamd-hal = "0.6" +trinket_m0 = "0.4" +log = "0.4" +starb = "0.1" +clint = "0.2" +nb = "0.1" +cortex-m = "0.6" +cortex-m-rt = "0.6" +smart-leds-trait = "0.2" +smart-leds = "0.2" +apa102-spi = "0.2" + +[patch.crates-io] +#atsamd-hal = { git = "https://github.com/atsamd-rs/atsamd", rev = "97d55c19" } +trinket_m0 = { git = "https://github.com/atsamd-rs/atsamd", rev = "97d55c19" } diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a78d29f --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +# How to compile the examples. +APP = bleusb +RELEASE = debug +TARGET = thumbv6m-none-eabi + +# VID and PID of device to flash firmware to. +USBVID = 239a +USBPID = '001e|801e' + +BOSSAC = bossac +SERIAL = $(shell ./find-serial-port $(USBVID) $(USBPID) || echo 'cant-find-serial-port') +OFFSET = 0x2000 + +OBJCOPY = arm-none-eabi-objcopy + +TARGETDIR = target/$(TARGET) +OUTDIR = $(TARGETDIR)/$(RELEASE) + +CARGOFLAGS = --target thumbv6m-none-eabi + +.PHONY: all clean cargo-build $(OUTDIR)/$(APP) + +all: $(OUTDIR)/$(APP) + +clean: + rm -f $(APP).uf2 + rm -f $(APP).bin + cargo clean + +test: + cargo test + +cargo-build: + cargo rustc $(CARGOFLAGS) -- -C link-arg=-Tlink.x + +$(OUTDIR)/$(APP): cargo-build + +flash: $(APP).bin $(SERIAL) + $(BOSSAC) -R -e -w -v -o$(OFFSET) -p$(SERIAL) $< + +qemu: $(OUTDIR)/$(APP) + qemu-system-arm -d in_asm,int,exec,cpu,guest_errors,unimp -pidfile qemu.pid -cpu cortex-m0 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -s -S -kernel $< + +gdb: $(OUTDIR)/$(APP) + gdb-multiarch -ex "target remote localhost:1234" -ex "break main" -ex "continue" $< + +%.bin: $(OUTDIR)/% + $(OBJCOPY) -O binary $< $@ + +# Requires https://github.com/sajattack/uf2conv-rs.git +%.uf2: %.bin + uf2conv-rs $< --base $(OFFSET) --output $@ diff --git a/find-serial-port b/find-serial-port new file mode 100755 index 0000000..62e2c0c --- /dev/null +++ b/find-serial-port @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ $# -ne 2 ]; then + echo "Usage: $0 vid pid" >&2 + exit 1 +fi + +prefix=/dev/serial/by-id + +for dev in `ls $prefix`; do + if [ `udevadm info -q property --name $prefix/$dev | egrep -i "ID_VENDOR_ID=($1)|ID_MODEL_ID=($2)" | wc -l` -eq 2 ]; then + echo `readlink -f $prefix/$dev` + exit 0 + fi +done +exit 2 diff --git a/src/dotstar.rs b/src/dotstar.rs new file mode 100644 index 0000000..8e930d0 --- /dev/null +++ b/src/dotstar.rs @@ -0,0 +1,42 @@ +use trinket_m0::{ + clock::GenericClockController, + gpio::{self, Floating, Input}, + prelude::*, + sercom::{self, PadPin, SPIMaster1}, + PM, SERCOM1, +}; + +use apa102_spi::Apa102; + +pub fn new( + sercom: SERCOM1, + miso: gpio::Pa31>, + mosi: gpio::Pa0>, + sck: gpio::Pa1>, + port: &mut gpio::Port, + pm: &mut PM, + clocks: &mut GenericClockController, +) -> Apa102< + SPIMaster1< + sercom::Sercom1Pad3>, + sercom::Sercom1Pad0>, + sercom::Sercom1Pad1>, + >, +> { + let gclk = clocks.gclk0(); + let miso = miso.into_pad(port); + let mosi = mosi.into_pad(port); + let sck = sck.into_pad(port); + let spi = SPIMaster1::new( + &clocks + .sercom1_core(&gclk) + .expect("setting up sercom1 clock"), + 3.mhz(), + apa102_spi::MODE, + sercom, + pm, + (miso, mosi, sck), + ); + + Apa102::new(spi) +} diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..be9d391 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,139 @@ +use crate::rtc; +use starb::{Reader, RingBuffer, Writer}; + +use core::cell::UnsafeCell; +use core::fmt::{self, Write}; +use embedded_hal::{digital::v2::OutputPin, serial}; +use log::{Metadata, Record}; +use trinket_m0::{ + gpio::{Pa6, Pa7, PfD}, + sercom::{Sercom0Pad2, Sercom0Pad3, UART0}, +}; + +static mut UART0: usize = 0; + +struct JoinedRingBuffer<'a> { + lbr: Reader<'a, u8>, + lbw: Writer<'a, u8>, +} + +impl<'a> JoinedRingBuffer<'a> { + const fn new(rb: &'a RingBuffer) -> Self { + let (lbr, lbw) = rb.split(); + Self { lbr: lbr, lbw: lbw } + } +} + +impl fmt::Write for JoinedRingBuffer<'_> { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + for b in s.bytes() { + if let Err(_) = self.lbw.unshift(b) { + // Ignore buffer full errors for logging. + return Ok(()); + } + } + Ok(()) + } +} + +static mut LB: RingBuffer = RingBuffer::::new(0); +static mut JRB: JoinedRingBuffer = unsafe { JoinedRingBuffer::new(&LB) }; + +// The UART isn't necessarily Sync, so wrap it in something that +// is. As long as flush() is only called from one thread, we're fine, +// but this is a guarantee that the logger module doesn't make. +pub struct WriteWrapper { + w: W, +} +impl WriteWrapper +where + W: serial::Write, +{ + pub fn new(writer: W) -> Self { + Self { w: writer } + } +} +unsafe impl Sync for WriteWrapper {} + +pub struct SerialLogger { + writer: UnsafeCell>, + led: UnsafeCell, +} + +impl SerialLogger +where + W: serial::Write, + L: OutputPin + Send + Sync, +{ + pub fn new(writer: WriteWrapper, led: L) -> Self { + // Stash this for unsafe usage in case there's an issue with + // the rest of the logging. + unsafe { UART0 = core::mem::transmute(&writer.w) }; + Self { + writer: UnsafeCell::new(writer), + led: UnsafeCell::new(led), + } + } +} +unsafe impl Send for SerialLogger {} +unsafe impl Sync for SerialLogger {} + +impl log::Log for SerialLogger +where + W: serial::Write, + L: OutputPin + Send + Sync, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= log::max_level() + } + + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + + let jrb = unsafe { &mut JRB }; + write!( + jrb, + "[{}] {} {} -- {}\r\n", + rtc::millis(), + record.level(), + record.target(), + record.args() + ) + .ok(); + } + + fn flush(&self) { + // Unsafe due to mutable static. We can only deal with the + // tail position of the buffer here to keep things safe. + let jrb = unsafe { &mut JRB }; + if jrb.lbr.is_empty() { + return; + } + + let led = unsafe { &mut (*self.led.get()) }; + let writer = unsafe { &mut (*self.writer.get()) }; + + led.set_high().ok(); + while let Some(b) = jrb.lbr.shift() { + nb::block!(writer.w.write(b)).ok(); + } + led.set_low().ok(); + } +} + +// Write to the UART right now, instead of putting it on a ring +// buffer. This function is a huge hack, and only useful for debugging +// either before the main loop starts or if the ring buffer is broken. +pub unsafe fn write_fmt_now(args: fmt::Arguments, nl: bool) { + if UART0 == 0 { + return; + } + let uart: &mut UART0>, Sercom0Pad2>, (), ()> = + core::mem::transmute(UART0); + fmt::write(uart, args).expect("writing fmt now to uart"); + if nl { + uart.write_str("\r\n").expect("writing nl now to uart"); + } +} diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..46d2d07 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,15 @@ +#[macro_export] +macro_rules! logln_now { + ($($arg:tt)*) => { + unsafe {crate::logger::write_fmt_now(format_args!($($arg)*), true);} + }; + (_) => {}; +} + +#[macro_export] +macro_rules! log_now { + ($($arg:tt)*) => { + unsafe {crate::logger::write_fmt_now(format_args!($($arg)*), false);} + }; + (_) => {}; +} diff --git a/src/main.rs b/src/main.rs new file mode 100755 index 0000000..071966a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,144 @@ +#![no_std] +#![no_main] + +mod dotstar; +mod logger; +mod macros; +mod rtc; + +use clint::HandlerArray; +use core::mem; +use core::panic::PanicInfo; +use cortex_m::asm::wfi; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_hal::digital::v2::OutputPin; +use log::{info, LevelFilter}; +use smart_leds::colors; +use smart_leds_trait::SmartLedsWrite; +use trinket_m0::{ + self as hal, + clock::GenericClockController, + gpio::{OpenDrain, Output, Pa10, Pa6, Pa7, PfD}, + sercom, + target_device::{interrupt, Interrupt}, + time::*, + CorePeripherals, Peripherals, +}; + +// I²C on trinket is on SERCOM2 + +static mut LED: usize = 0; + +static HANDLERS: HandlerArray = HandlerArray::new(); + +#[entry] +fn main() -> ! { + let mut cp = CorePeripherals::take().expect("taking core peripherals"); + let mut dp = Peripherals::take().expect("taking device peripherals"); + + let mut clocks = GenericClockController::with_internal_32kosc( + dp.GCLK, + &mut dp.PM, + &mut dp.SYSCTRL, + &mut dp.NVMCTRL, + ); + + let mut pins = hal::Pins::new(dp.PORT); + + let uart = hal::uart( + &mut clocks, + 115_200.hz(), + dp.SERCOM0, + &mut cp.NVIC, + &mut dp.PM, + pins.d3, + pins.d4, + &mut pins.port, + ); + + let mut red_led = pins.d13.into_open_drain_output(&mut pins.port); + red_led.set_low().expect("turning off red LED"); + unsafe { LED = mem::transmute(&red_led) } + + let mut dotstar = dotstar::new( + dp.SERCOM1, + pins.swdio, + pins.dotstar_di, + pins.dotstar_ci, + &mut pins.port, + &mut dp.PM, + &mut clocks, + ); + let black = [colors::BLACK]; + dotstar + .write(black.iter().cloned()) + .expect("turning off dotstar"); + + // We do the transmute because, while all the underlying data is + // static, we're unable to get a referecence to the UART or LED + // until run-time. Another option would be to use Option in the + // SerialLogger definition, but that requires a check every time + // they might be used. + let uart_wrapped = logger::WriteWrapper::new(uart); + let logger = logger::SerialLogger::new(uart_wrapped, red_led); + + // Wow, would I love to not be annotating this type. + let logger_ref: &'static logger::SerialLogger< + sercom::UART0>, sercom::Sercom0Pad2>, (), ()>, + Pa10>, + > = unsafe { mem::transmute(&logger) }; + unsafe { log::set_logger_racy(logger_ref).expect("couldn't set logger") }; + log::set_max_level(LevelFilter::Trace); + + let mut rtc_handler = rtc::setup(dp.RTC, &mut clocks); + + HANDLERS.with_overrides(|hs| { + hs.register(0, &mut rtc_handler); + cp.NVIC.enable(Interrupt::RTC); + + info!("Bootstrap complete."); + + loop { + wfi() + } + }); + unreachable!(); +} + +#[panic_handler] +fn panic_handler(pi: &PanicInfo) -> ! { + let red_led: &mut Pa10> = unsafe { mem::transmute(LED) }; + red_led.set_high().ok(); + + logln_now!("~~~ PANIC ~~~"); + logln_now!("{}", pi); + logln_now!("flushing log"); + loop { + log::logger().flush(); + wfi() + } +} + +#[exception] +fn HardFault(ef: &ExceptionFrame) -> ! { + let red_led: &mut Pa10> = unsafe { mem::transmute(LED) }; + red_led.set_high().ok(); + + log::logger().flush(); + logln_now!("!!! Hard Fault - ef: {:?} !!!", ef); + logln_now!("flushing log"); + loop { + log::logger().flush(); + wfi() + } +} + +#[interrupt] +fn RTC() { + HANDLERS.call(0); +} + +#[interrupt] +fn USB() { + HANDLERS.call(1); +} diff --git a/src/rtc.rs b/src/rtc.rs new file mode 100644 index 0000000..79e450a --- /dev/null +++ b/src/rtc.rs @@ -0,0 +1,74 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use log; +use trinket_m0::{clock::GenericClockController, RTC}; + +struct Clock(AtomicUsize); +impl Clock { + const fn new() -> Self { + Self(AtomicUsize::new(0)) + } + + fn set(&self, millis: usize) { + self.0.store(millis, Ordering::SeqCst) + } + + // Slightly less than 1ms, due to using a 32,768Hz clock, we can't + // hit exactly 1ms, so we shoot for a bit under. + fn millis(&self) -> usize { + self.0.load(Ordering::SeqCst) + } +} + +static CLOCK: Clock = Clock::new(); + +// Set to run every ~500µs. +static COUNTER: u32 = 16; // 32 ticks requires 1024 cycles at 32,768Hz for 1 second. + +pub fn setup(mut rtc: RTC, clocks: &mut GenericClockController) -> impl FnMut() { + let rtc_clock = &clocks.gclk1(); + clocks.rtc(&rtc_clock); + + rtc.mode0().ctrl.write(|w| w.swrst().set_bit()); + while rtc.mode0().status.read().syncbusy().bit_is_set() {} + + rtc.mode0().ctrl.write(|w| { + w.mode().count32(); + + // Neither the prescaler nor matchlr values seem to work. Not + // sure why. + //w.prescaler().div1024(); + w.matchclr().set_bit() // Reset on match for periodic + }); + + rtc.mode0().comp[0].write(|w| unsafe { w.bits(COUNTER) }); + rtc.mode0().intflag.write(|w| w.cmp0().set_bit()); + rtc.mode0().intenset.write(|w| w.cmp0().set_bit()); + + // Enable the RTC and wait for sync. + rtc.mode0().ctrl.write(|w| w.enable().set_bit()); + while rtc.mode0().status.read().syncbusy().bit_is_set() {} + + move || handler(&mut rtc) +} + +pub fn millis() -> usize { + CLOCK.millis() +} + +fn handler(rtc: &mut RTC) { + // FIXME: matchclr doesn't seem to work to reset the counter? + rtc.mode0().count.write(|w| unsafe { w.bits(0) }); + rtc.mode0().intflag.write(|w| w.cmp0().set_bit()); + + static mut TICKS: usize = 0; + static mut ADD: bool = false; + unsafe { + if ADD { + TICKS += 1; + CLOCK.set(TICKS); + } + ADD = !ADD; + + log::logger().flush(); + } +} -- cgit v1.2.3