From c15509282eeb620b6ce70059ea10c4657cff7474 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Tue, 24 Sep 2024 00:13:11 -0400 Subject: pio i2s --- .cargo/config.toml | 2 +- .gitignore | 3 +- Cargo.lock | 706 +++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 12 +- flake.nix | 3 + pio_i2s/Cargo.toml | 11 + pio_i2s/src/lib.rs | 278 +++++++++++++++++++ src/bringup/i2s.rs | 281 +++++++++++++++++++ src/bringup/mod.rs | 87 +++++- src/lib.rs | 1 + src/main.rs | 81 +++++- target-rp2040-rescue.cfg | 28 ++ 12 files changed, 1450 insertions(+), 43 deletions(-) create mode 100644 pio_i2s/Cargo.toml create mode 100644 pio_i2s/src/lib.rs create mode 100644 src/bringup/i2s.rs create mode 100644 target-rp2040-rescue.cfg diff --git a/.cargo/config.toml b/.cargo/config.toml index 62f9cda..ae921aa 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,4 +5,4 @@ runner = "probe-rs run --chip RP2040" target = "thumbv6m-none-eabi" [env] -DEFMT_LOG = "debug,lora=trace,sx127x=debug,embedded_sdmmc=info" +DEFMT_LOG = "debug,lora=trace,sx127x=debug,embedded_sdmmc_async=info" diff --git a/.gitignore b/.gitignore index b83d222..109b25a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target/ +target/ +*.wav diff --git a/Cargo.lock b/Cargo.lock index 4be0af3..8ff026d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,15 @@ dependencies = [ "regex", ] +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.0" @@ -54,6 +63,70 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.89" @@ -164,6 +237,21 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "bare-metal" version = "0.2.5" @@ -259,6 +347,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytemuck" version = "1.18.0" @@ -271,6 +365,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + [[package]] name = "camino" version = "1.1.9" @@ -303,6 +403,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -315,10 +424,55 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "clap" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +dependencies = [ + "clap_builder", + "clap_derive", ] +[[package]] +name = "clap_builder" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "clru" version = "0.6.2" @@ -341,6 +495,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "const-default" version = "1.0.0" @@ -1241,6 +1401,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1263,6 +1424,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -1298,21 +1470,27 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] name = "genlog" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "cfg-if", "defmt", + "log", + "tracing", ] [[package]] @@ -1326,6 +1504,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + [[package]] name = "gix" version = "0.66.0" @@ -1893,6 +2077,18 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -1914,6 +2110,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hound" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" + [[package]] name = "humansize" version = "2.1.3" @@ -1923,6 +2125,29 @@ dependencies = [ "libm", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1955,17 +2180,33 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" +dependencies = [ + "core-foundation-sys", + "mach2", +] + [[package]] name = "is-terminal" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -2006,6 +2247,15 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lalrpop" version = "0.19.12" @@ -2120,12 +2370,31 @@ dependencies = [ "num-traits", ] +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + [[package]] name = "managed" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" +[[package]] +name = "matrixmultiply" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "memchr" version = "2.7.4" @@ -2141,6 +2410,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "micromath" version = "2.1.0" @@ -2178,10 +2456,47 @@ dependencies = [ "adler2", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "mio-serial" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a4c60ca5c9c0e114b3bd66ff4aa5f9b2b175442be51ca6c4365d687a97a2ac" +dependencies = [ + "log", + "mio 0.8.11", + "nix", + "serialport", + "winapi", +] + [[package]] name = "molybdos" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "defmt-rtt", "embassy-executor", @@ -2194,7 +2509,7 @@ dependencies = [ [[package]] name = "molybdos_build" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "anyhow", "askama", @@ -2205,7 +2520,7 @@ dependencies = [ [[package]] name = "molybdos_lib" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "anyhow", "cfg-if", @@ -2236,6 +2551,7 @@ dependencies = [ "portable-atomic", "postcard", "rand", + "rand_chacha", "rand_core", "serde", "spin", @@ -2247,7 +2563,7 @@ dependencies = [ [[package]] name = "molybdos_pal" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "cfg-if", "cortex-m", @@ -2266,7 +2582,7 @@ dependencies = [ [[package]] name = "molybdos_rt" version = "0.1.0-alpha0" -source = "git+https://pub.npry.dev/molybdos#04e7c666c65f92a1abed2687c4d9ff831f68aa9a" +source = "git+https://pub.npry.dev/molybdos#a4ab89a0811de9217295e63968fe0be6cb4d6309" dependencies = [ "cfg-if", "embassy-executor", @@ -2283,6 +2599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" dependencies = [ "approx", + "matrixmultiply", "num-complex 0.4.6", "num-rational 0.4.2", "num-traits", @@ -2312,6 +2629,19 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -2650,6 +2980,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + [[package]] name = "ocularium" version = "0.1.0-alpha0" @@ -2660,10 +2999,30 @@ dependencies = [ "lsm6dsm", "molybdos", "molybdos_build", + "pio", "serde", "veml7700_async", ] +[[package]] +name = "ocularium_host" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "embassy-executor", + "embassy-time", + "eyre", + "heapless 0.8.0", + "hound", + "molybdos_lib", + "postcard", + "serde", + "ssmarshal", + "tokio", + "tokio-serial", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -2699,7 +3058,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2815,6 +3174,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -2875,6 +3243,18 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", "rand_core", ] @@ -2883,6 +3263,15 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" @@ -2989,6 +3378,12 @@ dependencies = [ "crc-any", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc_version" version = "0.2.3" @@ -3032,6 +3427,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "safe_arch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3109,6 +3513,23 @@ dependencies = [ "serde", ] +[[package]] +name = "serialport" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ba776acc8c373b9175829206229366273225436845c04f9c20aab8099960e2e" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "core-foundation-sys", + "io-kit-sys", + "mach2", + "nix", + "scopeguard", + "unescaper", + "winapi", +] + [[package]] name = "sha1_smol" version = "1.0.1" @@ -3121,6 +3542,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -3150,6 +3577,7 @@ dependencies = [ "num-complex 0.4.6", "num-traits", "paste", + "wide", ] [[package]] @@ -3158,6 +3586,15 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -3177,6 +3614,16 @@ dependencies = [ "managed", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -3426,12 +3873,82 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio 1.0.2", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "tokio-serial" +version = "5.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa6e2e4cf0520a99c5f87d5abb24172b5bd220de57c3181baaaa5440540c64aa" +dependencies = [ + "cfg-if", + "futures", + "log", + "mio-serial", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unescaper" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" +dependencies = [ + "thiserror", +] + [[package]] name = "unicase" version = "2.7.0" @@ -3538,6 +4055,12 @@ dependencies = [ "usbd-hid-descriptors", ] +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.10.0" @@ -3639,6 +4162,71 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.77", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wide" +version = "0.7.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3676,8 +4264,17 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core", - "windows-targets", + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -3689,7 +4286,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-result", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3720,7 +4317,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -3729,7 +4335,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3738,7 +4344,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -3747,28 +4368,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3781,24 +4420,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3820,6 +4483,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] diff --git a/Cargo.toml b/Cargo.toml index d93e708..837058a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,11 @@ homepage = "https://blog.npry.dev/resenv/ocularium" repository = "https://pub.npry.dev/ocularium" include = ["build.rs", "/src/", "Cargo.toml", "README.md", "LICENSE"] +[workspace] +exclude = [ + "pio_i2s" +] + [features] disable_sd = [] @@ -19,10 +24,13 @@ veml7700_async = { git = "https://pub.npry.dev/veml7700_async" } drogue_bme680_async = { git = "https://pub.npry.dev/drogue_bme680_async" } lsm6dsm = { git = "https://pub.npry.dev/lsm6dsm" } -embassy-executor = { git = "https://github.com/embassy-rs/embassy", features = ["executor-interrupt", "executor-thread", "arch-cortex-m", "nightly"] } serde = { version = "1.0", default-features = false } + +embassy-executor = { git = "https://github.com/embassy-rs/embassy", features = ["executor-interrupt", "executor-thread", "arch-cortex-m", "nightly"] } cortex-m-rt = { version = "0.7", default-features = false } +pio = "0.2" + [dependencies.molybdos] git = "https://pub.npry.dev/molybdos" features = [ @@ -37,6 +45,7 @@ features = [ "impl_alloc", ] + [build-dependencies] molybdos_build = { git = "https://pub.npry.dev/molybdos", features = ["defmt", "vergen"] } @@ -52,6 +61,7 @@ embassy-executor = { git = "https://github.com/mammothbane/embassy" } embassy-time = { git = "https://github.com/mammothbane/embassy" } embassy-time-driver = { git = "https://github.com/mammothbane/embassy" } embassy-usb = { git = "https://github.com/mammothbane/embassy" } +embassy-rp = { git = "https://github.com/mammothbane/embassy" } [profile.dev] codegen-units = 1 diff --git a/flake.nix b/flake.nix index 78cfcb5..312184b 100644 --- a/flake.nix +++ b/flake.nix @@ -52,8 +52,11 @@ kikit probe-rs + elf2uf2-rs gcc-arm-embedded + + openocd-rp2040 ]; }; diff --git a/pio_i2s/Cargo.toml b/pio_i2s/Cargo.toml new file mode 100644 index 0000000..10c67c2 --- /dev/null +++ b/pio_i2s/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "pio_i2s" +version = "0.1.0" +edition = "2021" + +[dependencies] +embassy-rp = { git = "https://pub.npry.dev/embassy", default-features = false, features = ["rp2040"] } +embedded-io-async = { version = "0.6", default-features = false } +fixed = { version = "1.28", default-features = false } +defmt = { version = "0.3", default-features = false } +pio = { version = "0.2", default-features = false } diff --git a/pio_i2s/src/lib.rs b/pio_i2s/src/lib.rs new file mode 100644 index 0000000..62ef3ac --- /dev/null +++ b/pio_i2s/src/lib.rs @@ -0,0 +1,278 @@ +#![no_std] + +use core::{ + arch::asm, + mem, + time::Duration, +}; +use ::{ + embassy_rp, + embassy_rp::{ + clocks::clk_sys_freq, + pio, + pio::{ + ShiftDirection, + StateMachine, + }, + Peripheral, + }, + embassy_time, + embassy_time::{ + Duration, + Instant, + }, + embedded_io_async, + fixed::prelude::ToFixed, + genlog::defmt, + pio::{ + InSource, + JmpCondition, + MovDestination, + MovOperation, + MovSource, + OutDestination, + SetDestination, + SideSet, + }, + pio_proc, +}; + +pub trait GetSm<'inner, PIO, const IDX: usize> +where + PIO: embassy_rp::pio::Instance, +{ + fn sm<'p>(pio: &'p mut pio::Pio<'inner, PIO>) -> &'p mut StateMachine<'inner, PIO, IDX>; +} + +pub struct SmLookup; + +macro_rules! impl_getsm { + ($idx:literal, $name:ident) => { + impl<'inner, PIO> GetSm<'inner, PIO, $idx> for SmLookup<$idx> + where + PIO: embassy_rp::pio::Instance, + { + fn sm<'p>( + pio: &'p mut pio::Pio<'inner, PIO>, + ) -> &'p mut StateMachine<'inner, PIO, $idx> { + &mut pio.$name + } + } + }; +} + +impl_getsm!(0, sm0); +impl_getsm!(1, sm1); +impl_getsm!(2, sm2); +impl_getsm!(3, sm3); + +pub type StaticI2S = I2S<'static, 'static, PIO, IDX>; + +pub struct I2S<'b, 'p, PIO, const IDX: usize> +where + PIO: pio::Instance, +{ + sm: &'b mut StateMachine<'p, PIO, IDX>, +} + +impl<'b, 'p, PIO, const IDX: usize> I2S<'b, 'p, PIO, IDX> +where + PIO: pio::Instance, +{ + pub const BIT_DEPTH: usize = 16; + pub const CHANNELS: usize = 1; + pub const DEFAULT_BUFFER_SIZE: usize = 960; + pub const SAMPLE_RATE_HZ: usize = 48_000; + + pub fn new( + pio: &'b mut pio::Pio<'p, PIO>, + bclk: impl Peripheral

+ 'static, + data: impl Peripheral

+ 'static, + ws: impl Peripheral

+ 'static, + ) -> Self + where + SmLookup: GetSm<'p, PIO, IDX>, + { + defmt::info!("start"); + + let bclk = pio.common.make_pio_pin(bclk); + let data = pio.common.make_pio_pin(data); + let ws = pio.common.make_pio_pin(ws); + + defmt::info!("pins done"); + + let program = program::<1024>(None); + defmt::info!("made program: {}", defmt::Debug2Format(&program)); + + let program = pio.common.try_load_program(&program); + + let program = match program { + Err(e) => { + defmt::panic!("loading pio: {}", e); + }, + Ok(program) => program, + }; + + defmt::info!("program loaded"); + + let config = Self::config(&program, bclk, data, ws); + + defmt::info!("config run"); + + let sm = as GetSm>::sm(pio); + sm.set_enable(false); + sm.set_config(&config); + sm.clear_fifos(); + + Self { + sm, + } + } + + pub async fn run( + &mut self, + dma: impl Peripheral

, + mut pipe: impl embedded_io_async::Write, + ) { + self.sm.set_enable(true); + + let tx = self.sm.tx(); + let mut dma = dma.into_ref(); + + let mut front_buffer = [0u8; BUFFER_SIZE]; + let mut back_buffer = [0u8; BUFFER_SIZE]; + + loop { + let transfer = tx.dma_push(dma.reborrow(), &mut front_buffer); + let now = Instant::now(); + let deadline = now + Duration::from_hz(Self::SAMPLE_RATE_HZ as _) * BUFFER_SIZE as _; + + if let Err(e) = + molybdos::embassy_time::with_deadline(deadline, pipe.write_all(&back_buffer)).await + { + defmt::error!("audio timeout"); + } + + transfer.await; + mem::swap(&mut back_buffer, &mut front_buffer); + } + } + + fn config<'pin>( + prog: &pio::LoadedProgram<'p, PIO>, + bclk: pio::Pin<'pin, PIO>, + data: pio::Pin<'pin, PIO>, + ws: pio::Pin<'pin, PIO>, + ) -> pio::Config<'p, PIO> + where + 'pin: 'p, + { + let clock_frequency: usize = Self::SAMPLE_RATE_HZ * Self::CHANNELS * Self::BIT_DEPTH; + + let mut cfg = pio::Config::default(); + + cfg.use_program(&prog, &[&bclk]); + cfg.set_in_pins(&[&data]); + cfg.set_set_pins(&[&ws]); + + cfg.fifo_join = pio::FifoJoin::RxOnly; + + cfg.shift_in = pio::ShiftConfig { + threshold: 32, + direction: ShiftDirection::Left, + auto_fill: true, + }; + + cfg.clock_divider = (clk_sys_freq() as f64 / clock_frequency as f64 / 2.).to_fixed(); + + cfg + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct WarmupConfig { + clock_freq: usize, + warmup_period: embassy_time::Duration, +} + +/// I2S pio driver program. +/// +/// Pass `warmup` to have the PIO idle for a period before starting the clock. +pub fn program( + warmup: Option, +) -> molybdos::pio::Program { + let mut asm = + molybdos::pio::Assembler::::new_with_side_set(SideSet::new(true, 1, false)); + + asm.irq(true, false, 0, true); + asm.set(SetDestination::PINS, 1); + + // on boot, SPH0644LM4H wants 30ms warmup time with the clock running at full frequency. it's + // nice to do this in the PIO itself because it makes the host agnostic -- it can just wait + // until there is data available in the fifo. + if let Some(WarmupConfig { + clock_freq, + warmup_period, + }) = warmup + { + const SET_MAX_BITS: usize = 5; + + let warmup_period_clock_cycles = clock_freq / 1000 * warmup_period.as_millis() as usize; + debug_assert!(warmup_period_clock_cycles <= 1 << 31); + + asm.r#in(InSource::NULL, 32); + + let sig_bits = 32 - warmup_period_clock_cycles.leading_zeros(); + + for i in 0..(sig_bits / 5) { + const MASK: usize = 0b11111; + let shift = i * SET_MAX_BITS as u32; + + asm.set(SetDestination::X, ((warmup_period_clock_cycles >> shift) & MASK) as u8); + asm.r#in(InSource::X, SET_MAX_BITS as _); + } + + let rem_bits = sig_bits % SET_MAX_BITS as u32; + if rem_bits != 0 { + let mask = (1 << (rem_bits + 1)) - 1; + + asm.set( + SetDestination::X, + ((warmup_period_clock_cycles >> (sig_bits - rem_bits)) & mask) as u8, + ); + asm.r#in(InSource::X, SET_MAX_BITS as _); + } + + asm.mov(MovDestination::X, MovOperation::None, MovSource::ISR); + + let mut bootloop = asm.label(); + { + asm.nop_with_side_set(1); + asm.jmp_with_side_set(JmpCondition::XDecNonZero, &mut bootloop, 0); + } + } + + asm.irq_with_side_set(false, false, 0, true, 1); + + let mut wrap_target = asm.label(); + + asm.in_with_side_set(InSource::PINS, 1, 0); + asm.nop_with_side_set(1); + let wrap = asm.label(); + + defmt::info!("trying assemble..."); + asm.assemble_with_wrap(wrap_target, wrap) +} + +#[cfg(test)] +mod test { + use crate::{ + bringup::i2s::program, + program, + }; + + #[test] + fn test_program() { + program(None); + } +} diff --git a/src/bringup/i2s.rs b/src/bringup/i2s.rs new file mode 100644 index 0000000..37d8921 --- /dev/null +++ b/src/bringup/i2s.rs @@ -0,0 +1,281 @@ +use core::{ + arch::asm, + mem, +}; + +use molybdos::{ + embassy_rp, + embassy_rp::{ + clocks::clk_sys_freq, + pio, + pio::{ + Direction, + ShiftDirection, + StateMachine, + }, + Peripheral, + }, + embassy_time, + embassy_time::{ + Duration, + Instant, + }, + embedded_io_async, + fixed::prelude::ToFixed, + genlog::defmt, + pio::{ + InSource, + JmpCondition, + MovDestination, + MovOperation, + MovSource, + OutDestination, + SetDestination, + SideSet, + }, + pio_proc, +}; + +pub trait GetSm<'inner, PIO, const IDX: usize> +where + PIO: pio::Instance, +{ + fn sm<'p>(pio: &'p mut pio::Pio<'inner, PIO>) -> &'p mut StateMachine<'inner, PIO, IDX>; +} + +pub struct SmLookup; + +macro_rules! impl_getsm { + ($idx:literal, $name:ident) => { + impl<'inner, PIO> GetSm<'inner, PIO, $idx> for SmLookup<$idx> + where + PIO: embassy_rp::pio::Instance, + { + fn sm<'p>( + pio: &'p mut pio::Pio<'inner, PIO>, + ) -> &'p mut StateMachine<'inner, PIO, $idx> { + &mut pio.$name + } + } + }; +} + +impl_getsm!(0, sm0); +impl_getsm!(1, sm1); +impl_getsm!(2, sm2); +impl_getsm!(3, sm3); + +pub type StaticI2S = I2S<'static, 'static, PIO, IDX>; + +pub struct I2S<'b, 'p, PIO, const IDX: usize> +where + PIO: pio::Instance, +{ + sm: &'b mut StateMachine<'p, PIO, IDX>, +} + +impl<'b, 'p, PIO, const IDX: usize> I2S<'b, 'p, PIO, IDX> +where + PIO: pio::Instance, +{ + pub const DEFAULT_BUFFER_SIZE: usize = 960; + pub const SAMPLE_RATE_HZ: usize = 48_000 * 32; + + pub fn new( + pio: &'b mut pio::Pio<'p, PIO>, + bclk: impl Peripheral

+ 'static, + data: impl Peripheral

+ 'static, + ws: impl Peripheral

+ 'static, + ) -> Self + where + SmLookup: GetSm<'p, PIO, IDX>, + { + defmt::info!("start"); + + let bclk = pio.common.make_pio_pin(bclk); + let data = pio.common.make_pio_pin(data); + let ws = pio.common.make_pio_pin(ws); + + defmt::info!("pins done"); + + let program = program::<1024>(None); + defmt::info!("made program: {}", defmt::Debug2Format(&program)); + + let program = pio.common.try_load_program(&program); + + let program = match program { + Err(e) => { + defmt::panic!("loading pio: {}", e); + }, + Ok(program) => program, + }; + + defmt::info!("program loaded"); + + let config = Self::config(&program, &bclk, &data, &ws); + + defmt::info!("config run"); + + let sm = as GetSm>::sm(pio); + sm.set_enable(false); + sm.set_config(&config); + sm.clear_fifos(); + + sm.set_pin_dirs(Direction::Out, &[&bclk, &ws]); + sm.set_pin_dirs(Direction::In, &[&data]); + + Self { + sm, + } + } + + pub async fn run( + &mut self, + dma: impl Peripheral

, + mut pipe: impl embedded_io_async::Write, + ) { + self.sm.set_enable(true); + defmt::info!("i2s state machine started"); + + let rx = self.sm.rx(); + let mut dma = dma.into_ref(); + + let mut front_buffer = [0u8; BUFFER_SIZE]; + let mut back_buffer = [0u8; BUFFER_SIZE]; + + let per_sample_dur = + core::time::Duration::from_secs(1) * BUFFER_SIZE as _ / (Self::SAMPLE_RATE_HZ as _); + + defmt::info!("ready to loop, sample_dur = {}us", per_sample_dur.as_micros()); + + let per_sample_dur = embassy_time::Duration::from_nanos(per_sample_dur.as_nanos() as _); + + loop { + defmt::info!("loop"); + + let transfer = rx.dma_pull(dma.reborrow(), &mut front_buffer); + let now = Instant::now(); + let deadline = now + per_sample_dur; + + if let Err(e) = + molybdos::embassy_time::with_deadline(deadline, pipe.write_all(&back_buffer)).await + { + defmt::error!("audio timeout"); + } + + transfer.await; + mem::swap(&mut back_buffer, &mut front_buffer); + } + } + + fn config<'pin>( + prog: &pio::LoadedProgram<'p, PIO>, + bclk: &pio::Pin<'pin, PIO>, + data: &pio::Pin<'pin, PIO>, + ws: &pio::Pin<'pin, PIO>, + ) -> pio::Config<'p, PIO> + where + 'pin: 'p, + { + let clock_frequency: usize = Self::SAMPLE_RATE_HZ; + defmt::info!("using clock freq: {}", clock_frequency); + + let mut cfg = pio::Config::default(); + + cfg.use_program(&prog, &[&bclk]); + cfg.set_in_pins(&[&data]); + cfg.set_set_pins(&[&ws]); + + cfg.fifo_join = pio::FifoJoin::RxOnly; + + cfg.shift_in = pio::ShiftConfig { + threshold: 32, + direction: ShiftDirection::Left, + auto_fill: true, + }; + + cfg.clock_divider = (clk_sys_freq() as f64 / clock_frequency as f64 / 2.).to_fixed(); + defmt::info!( + "set clock divider: {} based on sys freq: {}Hz", + defmt::Debug2Format(&cfg.clock_divider), + clk_sys_freq() + ); + + cfg + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct WarmupConfig { + clock_freq: usize, + warmup_period: embassy_time::Duration, +} + +/// I2S pio driver program. +/// +/// Pass `warmup` to have the PIO idle for a period before starting the clock. +pub fn program( + warmup: Option, +) -> molybdos::pio::Program { + let mut asm = + molybdos::pio::Assembler::::new_with_side_set(SideSet::new(true, 1, false)); + + asm.set(SetDestination::PINS, 1); + + // on boot, SPH0644LM4H wants 30ms warmup time with the clock running at full frequency. it's + // nice to do this in the PIO itself because it makes the host agnostic -- it can just wait + // until there is data available in the fifo. + if let Some(WarmupConfig { + clock_freq, + warmup_period, + }) = warmup + { + const SET_MAX_BITS: usize = 5; + + let warmup_period_clock_cycles = clock_freq / 1000 * warmup_period.as_millis() as usize; + debug_assert!(warmup_period_clock_cycles <= 1 << 31); + + asm.r#in(InSource::NULL, 32); + + let sig_bits = 32 - warmup_period_clock_cycles.leading_zeros(); + + for i in 0..(sig_bits / 5) { + const MASK: usize = 0b11111; + let shift = i * SET_MAX_BITS as u32; + + asm.set(SetDestination::X, ((warmup_period_clock_cycles >> shift) & MASK) as u8); + asm.r#in(InSource::X, SET_MAX_BITS as _); + } + + let rem_bits = sig_bits % SET_MAX_BITS as u32; + if rem_bits != 0 { + let mask = (1 << (rem_bits + 1)) - 1; + + asm.set( + SetDestination::X, + ((warmup_period_clock_cycles >> (sig_bits - rem_bits)) & mask) as u8, + ); + asm.r#in(InSource::X, SET_MAX_BITS as _); + } + + asm.mov(MovDestination::X, MovOperation::None, MovSource::ISR); + + let mut bootloop = asm.label(); + { + asm.nop_with_side_set(1); + asm.jmp_with_side_set(JmpCondition::XDecNonZero, &mut bootloop, 0); + } + } + + let mut wrap_target = asm.label(); + asm.bind(&mut wrap_target); + + asm.in_with_side_set(InSource::PINS, 1, 0); + asm.nop_with_side_set(1); + + let mut wrap = asm.label(); + asm.bind(&mut wrap); + + defmt::info!("trying assemble..."); + asm.assemble_with_wrap(wrap, wrap_target) +} diff --git a/src/bringup/mod.rs b/src/bringup/mod.rs index 71c2d4b..e59e8c3 100644 --- a/src/bringup/mod.rs +++ b/src/bringup/mod.rs @@ -8,7 +8,12 @@ use embassy_rp::{ Output, Pin, }, + i2c::{ + self, + I2c, + }, peripherals::{ + I2C0, SPI0, SPI1, USB, @@ -27,48 +32,87 @@ use embassy_sync::{ }, mutex::Mutex, }; +use molybdos::embassy_rp::peripherals::{ + DMA_CH5, + I2C1, + PIO0, +}; use static_cell::StaticCell; use tap::Pipe; +use crate::SensorI2c; use molybdos::pal::StaticOutput; +pub mod i2s; + +pub use i2s::{ + StaticI2S, + I2S, +}; + embassy_rp::bind_interrupts! { struct Irqs { USBCTRL_IRQ => embassy_rp::usb::InterruptHandler; ADC_IRQ_FIFO => adc::InterruptHandler; + I2C0_IRQ => i2c::InterruptHandler; + I2C1_IRQ => i2c::InterruptHandler; + PIO0_IRQ_0 => embassy_rp::pio::InterruptHandler; } } -static BME_SPI: StaticCell>> = StaticCell::new(); -static SD_SPI: StaticCell>> = StaticCell::new(); +static BME_SPI: StaticCell>> = + StaticCell::new(); +static SD_SPI: StaticCell>> = + StaticCell::new(); static ADC: StaticCell>> = StaticCell::new(); - -pub struct Split -where +static SENSOR_I2C: StaticCell> = StaticCell::new(); + +static PIO0: StaticCell> = StaticCell::new(); + +pub struct Split< + BmeSpi, + BmeSpiMutex, + SdSpi, + SdSpiMutex, + // SensorI2c, + // SensorI2cMutex, +> where SdSpiMutex: RawMutex + 'static, SdSpi: 'static, BmeSpiMutex: RawMutex + 'static, BmeSpi: 'static, + // SensorI2cMutex: RawMutex + 'static, + // SensorI2c: 'static, { pub sd_spi: &'static Mutex, pub sd_cs: StaticOutput, pub bme_spi: &'static Mutex, pub bme_cs: StaticOutput, + // pub sensor_i2c: &'static Mutex, pub wdt: Watchdog, pub usb: molybdos::pal::UsbDriver, - pub adc: &'static Mutex>, + pub i2s: i2s::I2S<'static, 'static, embassy_rp::peripherals::PIO0, 0>, + pub i2s_dma: DMA_CH5, + pub adc: &'static Mutex>, // pub leds: [StaticOutput; crate::N_LED], } pub fn split( config: embassy_rp::config::Config, -) -> Split { - let periphs = embassy_rp::init(config); +) -> Split< + crate::BMESpi, + CriticalSectionRawMutex, + crate::SdSpi, + CriticalSectionRawMutex, + // crate::SensorI2c, + // CriticalSectionRawMutex, +> { + let mut periphs = embassy_rp::init(config); let wdt = Watchdog::new(periphs.WATCHDOG); - let bme_cs = periphs.PIN_5.degrade().pipe(|cs| Output::new(cs, Level::High)); + let bme_cs = periphs.PIN_13.degrade().pipe(|cs| Output::new(cs, Level::High)); let bme_spi = { let sck = periphs.PIN_10; let mosi = periphs.PIN_11; @@ -83,7 +127,7 @@ pub fn split( BME_SPI.init(bme_spi) }; - let sd_cs = periphs.PIN_9.degrade().pipe(|cs| Output::new(cs, Level::High)); + let sd_cs = periphs.PIN_17.degrade().pipe(|cs| Output::new(cs, Level::High)); let sd_spi = { let mosi = periphs.PIN_19; let sck = periphs.PIN_18; @@ -99,20 +143,39 @@ pub fn split( SD_SPI.init(sd_spi) }; + // let i2c = { + // let mut conf = i2c::Config::default(); + // conf.frequency = 400_000; + // + // let i2c = SensorI2c::new_async(periphs.I2C1, periphs.PIN_23, periphs.PIN_22, Irqs, conf) + // .pipe(Mutex::new); + // SENSOR_I2C.init(i2c) + // }; + let usb_driver = embassy_rp::usb::Driver::new(periphs.USB, Irqs); let adc = Adc::new(periphs.ADC, Irqs, adc::Config::default()); - let adc = ADC.init(Mutex::new(adc)); + // { + // StaticOutput::new(periphs.PIN_24, Level::High); + // } + + let pio0 = embassy_rp::pio::Pio::new(periphs.PIO0, Irqs); + let pio = PIO0.init(pio0); + + let i2s = i2s::I2S::new(pio, periphs.PIN_24, periphs.PIN_23, periphs.PIN_25); + Split { sd_spi, sd_cs, bme_spi, bme_cs, wdt, + // sensor_i2c: i2c, usb: usb_driver, - + i2s, + i2s_dma: periphs.DMA_CH5, adc, } } diff --git a/src/lib.rs b/src/lib.rs index fd70da7..6a9d858 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,4 +12,5 @@ pub enum Uplink { )] pub enum Downlink { Pong, + PDM(molybdos::heapless::Vec), } diff --git a/src/main.rs b/src/main.rs index 37b413c..6cf46be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,11 @@ #![no_main] #![feature(impl_trait_in_assoc_type)] +use crate::usb::COBS_DOWNLINK; use molybdos::{ embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice, + embassy_executor, + embassy_rp, embassy_rp::{ i2c::{ self, @@ -11,6 +14,8 @@ use molybdos::{ }, peripherals::{ I2C0, + I2C1, + PIO0, SPI0, SPI1, }, @@ -20,8 +25,17 @@ use molybdos::{ }, }, embassy_sync::{ - blocking_mutex::raw::CriticalSectionRawMutex, + blocking_mutex::raw::{ + CriticalSectionRawMutex, + ThreadModeRawMutex, + }, + pipe::Pipe, pubsub, + pubsub::PubSubBehavior, + }, + embedded_hal_async::spi::{ + Operation, + SpiDevice as _, }, embedded_sdmmc_async::{ VolumeIdx, @@ -29,8 +43,10 @@ use molybdos::{ }, genlog, genlog::defmt, + heapless, pal::StaticOutput, }; +use ocularium::Downlink; mod bringup; mod usb; @@ -40,13 +56,15 @@ pub type BMESpiDev = SpiDevice<'static, CriticalSectionRawMutex, BMESpi, StaticO pub type SdSpi = Spi<'static, SPI0, spi::Async>; pub type SdSpiDev = SpiDevice<'static, CriticalSectionRawMutex, SdSpi, StaticOutput>; -pub type SensorI2c = I2c<'static, I2C0, i2c::Async>; +pub type SensorI2c = I2c<'static, I2C1, i2c::Async>; + +pub static I2S_PIPE: Pipe = Pipe::new(); -#[embassy_executor::main] +#[::embassy_executor::main] async fn main(spawner: embassy_executor::Spawner) { molybdos::pal::heap::init(); - genlog::info!("boot"); + defmt::info!("boot"); let bringup::Split { sd_spi, @@ -55,9 +73,13 @@ async fn main(spawner: embassy_executor::Spawner) { bme_cs, wdt, usb, + i2s, + i2s_dma, .. } = bringup::split(Default::default()); + defmt::info!("split ok"); + // spawner.must_spawn(molybdos::pal::watchdog(wdt)); let (acm,) = molybdos::lib::usb::bringup!( @@ -81,18 +103,63 @@ async fn main(spawner: embassy_executor::Spawner) { &usb::COBS_DOWNLINK ); + let mut spidev = SpiDevice::new(bme_spi, bme_cs); + + let data = &mut [0u8]; + + let result = spidev + .transaction(&mut [Operation::Write(&[0x50 | (1 << 7)]), Operation::Read(data)]) + .await; + if let Err(e) = result { + defmt::error!("reading spi dev: {}", defmt::Debug2Format(&e)); + } else { + defmt::info!("read chipid: {:x}", data[0]); + } + #[cfg(not(feature = "disable_sd"))] { let vm = molybdos::rt::sd::bringup!(sd_spi, SdSpi, sd_cs); { - let vol = VolumeManager::open_volume(vm, VolumeIdx(0)).await.expect("opening volume"); - } + let vol = match VolumeManager::open_volume(vm, VolumeIdx(0)).await { + Ok(x) => x, + Err(e) => { + defmt::error!("opening volume: {}", defmt::Debug2Format(&e)); - // spawner.must_spawn(sd::run_sd(vm, pubsub::LED.sender().into())); + loop { + molybdos::embassy_time::Timer::after( + molybdos::embassy_time::Duration::from_secs(1), + ) + .await; + } + }, + }; + } } + spawner.must_spawn(drain_pipe()); + spawner.must_spawn(run_i2s(i2s, i2s_dma)); + loop { molybdos::embassy_time::Timer::after(molybdos::embassy_time::Duration::from_secs(1)).await; } } + +#[::embassy_executor::task] +async fn run_i2s(mut i2s: bringup::StaticI2S, dma: embassy_rp::peripherals::DMA_CH5) { + i2s.run::<960>(dma, &I2S_PIPE).await +} + +#[::embassy_executor::task] +async fn drain_pipe() { + let publ = COBS_DOWNLINK.publisher().expect("getting publisher"); + + loop { + let buf = &mut [0u8; 960]; + let n = I2S_PIPE.read(buf).await; + + for elem in (&buf[..n]).chunks(48) { + publ.publish_immediate(Downlink::PDM(heapless::Vec::from_slice(elem).unwrap())); + } + } +} diff --git a/target-rp2040-rescue.cfg b/target-rp2040-rescue.cfg new file mode 100644 index 0000000..b124dda --- /dev/null +++ b/target-rp2040-rescue.cfg @@ -0,0 +1,28 @@ +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +set _CHIPNAME rp2040 +set _CPUTAPID 0x01002927 +set _ENDIAN little + +swj_newdap $_CHIPNAME.rescue_dp cpu -dp-id $_CPUTAPID -instance-id 0xf +set _TARGETNAME_0 $_CHIPNAME.rescue +dap create $_TARGETNAME_0.dap -chain-position $_CHIPNAME.rescue_dp.cpu -ignore-syspwrupack + +# Have to init before we can do dpreg commands +init + +# The rescue debug port uses the AP CTRL/STAT bit DBGPWRUPREQ to reset the +# PSM (power on state machine) of the RP2040 with a flag set in the +# VREG_AND_POR_CHIP_RESET register. Once the reset is released +# (by clearing the DBGPWRUPREQ flag), the bootrom will run, see this flag, +# and halt. Allowing the user to load some fresh code, rather than loading +# the potentially broken code stored in flash + +# Clear DBGPWRUPREQ +$_TARGETNAME_0.dap dpreg 0x4 0x00000000 + +# Verifying CTRL/STAT is 0 +$_TARGETNAME_0.dap dpreg 0x4 + +echo "Now attach a debugger to your RP2040 and load some code" -- cgit v1.3.1