diff --git a/Cargo.lock b/Cargo.lock index 1d2c079..e1ca0dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,7 +78,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891" dependencies = [ - "term 1.2.0", + "term 1.0.2", ] [[package]] @@ -128,6 +128,12 @@ dependencies = [ "rustc_version 0.2.3", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "bit-set" version = "0.5.3" @@ -232,9 +238,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" [[package]] name = "byteorder" @@ -272,9 +278,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "clap" @@ -310,6 +316,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + [[package]] name = "cortex-m" version = "0.7.7" @@ -339,7 +351,7 @@ checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -436,7 +448,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -447,7 +459,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -485,7 +497,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -494,7 +506,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.12", ] [[package]] @@ -634,7 +646,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -706,7 +718,7 @@ dependencies = [ "embassy-hal-internal 0.2.0", "embassy-sync 0.6.2", "embassy-time 0.4.0", - "embassy-usb-driver 0.1.1", + "embassy-usb-driver 0.1.0", "embedded-hal 0.2.7", "embedded-hal 1.0.0", "embedded-hal-async", @@ -866,12 +878,9 @@ dependencies = [ [[package]] name = "embassy-usb-driver" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340c5ce591ef58c6449e43f51d2c53efe1bf0bb6a40cbf80afa0d259c7d52c76" -dependencies = [ - "embedded-io-async", -] +checksum = "4fc247028eae04174b6635104a35b1ed336aabef4654f5e87a8f32327d231970" [[package]] name = "embassy-usb-driver" @@ -883,6 +892,18 @@ dependencies = [ "embedded-io-async", ] +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + [[package]] name = "embedded-graphics" version = "0.8.1" @@ -999,7 +1020,7 @@ checksum = "4f6e621fe4c7e05b695274b722dc0a60bacd1c8696b58191baa0154713d52400" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -1040,9 +1061,9 @@ dependencies = [ [[package]] name = "embedded-text" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d" +checksum = "6cf5c72c52db2f7dbe4a9c1ed81cd21301e8d66311b194fa41c04fb4f71843ba" dependencies = [ "az", "embedded-graphics", @@ -1077,7 +1098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys", ] [[package]] @@ -1191,7 +1212,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -1247,19 +1268,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] [[package]] @@ -1273,9 +1294,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a80adfd63bd7ffd94fefc3d22167880c440a724303080e5aa686fa36abaa96" +checksum = "7be320f077239a0361c20d608b4768c62a1b77aa4946dd76395aa4cd502cba7d" dependencies = [ "plain", "scroll", @@ -1326,9 +1347,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heapless" @@ -1381,6 +1402,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1399,12 +1429,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.15.4", ] [[package]] @@ -1415,7 +1445,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi 0.5.2", "libc", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1444,9 +1474,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -1472,6 +1502,7 @@ dependencies = [ "bumpalo", "cortex-m", "cortex-m-rt", + "critical-section", "cyw43", "cyw43-pio", "defmt 0.3.100", @@ -1483,6 +1514,7 @@ dependencies = [ "embassy-sync 0.7.2", "embassy-time 0.5.0", "embassy-usb", + "embedded-alloc", "embedded-graphics", "embedded-hal 0.2.7", "embedded-hal 1.0.0", @@ -1555,10 +1587,10 @@ dependencies = [ "petgraph 0.7.1", "pico-args", "regex", - "regex-syntax 0.8.6", + "regex-syntax 0.8.5", "sha3", "string_cache", - "term 1.2.0", + "term 1.0.2", "unicode-xid", "walkdir", ] @@ -1590,20 +1622,26 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ "bitflags 2.9.4", "libc", ] +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1612,9 +1650,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litrs" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" @@ -1628,9 +1666,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -1712,7 +1750,7 @@ checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -1779,7 +1817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.11.4", + "indexmap 2.9.0", ] [[package]] @@ -1789,7 +1827,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset 0.5.7", - "indexmap 2.11.4", + "indexmap 2.9.0", ] [[package]] @@ -1904,7 +1942,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -1971,14 +2009,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -2027,9 +2065,9 @@ checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.4", ] @@ -2047,25 +2085,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.6", + "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax 0.8.5", ] [[package]] @@ -2076,19 +2114,31 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rgb" -version = "0.8.52" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" dependencies = [ "bytemuck", ] +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + [[package]] name = "rp-pac" version = "7.0.0" @@ -2136,14 +2186,14 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -2195,9 +2245,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2205,22 +2255,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -2396,7 +2446,20 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", +] + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", ] [[package]] @@ -2412,9 +2475,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -2443,10 +2506,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys", ] [[package]] @@ -2462,11 +2525,12 @@ dependencies = [ [[package]] name = "term" -version = "1.2.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2111ef44dae28680ae9752bb89409e7310ca33a8c621ebe7b106cf5c928b3ac0" +checksum = "8a984c8d058c627faaf5e8e2ed493fa3c51771889196de1016cf9c1c6e90d750" dependencies = [ - "windows-sys 0.61.0", + "home", + "windows-sys", ] [[package]] @@ -2495,11 +2559,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.12", ] [[package]] @@ -2510,18 +2574,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] [[package]] @@ -2590,7 +2654,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", "uuid", ] @@ -2602,9 +2666,9 @@ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -2667,9 +2731,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.18.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "js-sys", "wasm-bindgen", @@ -2718,15 +2782,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -2738,36 +2793,35 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", - "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.103" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2775,22 +2829,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] @@ -2813,11 +2867,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.11" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.61.0", + "windows-sys", ] [[package]] @@ -2826,12 +2880,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" - [[package]] name = "windows-sys" version = "0.59.0" @@ -2841,15 +2889,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -2931,20 +2970,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.104", ] diff --git a/Cargo.toml b/Cargo.toml index 183d200..2170336 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "3" members = [ "kernel", + "abi_sys", "abi", "user-apps/calculator", "user-apps/snake", diff --git a/README.md b/README.md index 9bffec0..2d4d4e0 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,6 @@ git clone https://github.com/LegitCamper/picocalc-os-rs.git cd picocalc-os-rs just userapps # copy the build applications from target/thumbv8m.main-none-eabihf/release-binary/application to the sdcard and rename them to app.bin -just kernel-release # keep in mind that https://github.com/StripedMonkey/elf2uf2-rs version is required until https://github.com/JoNil/elf2uf2-rs/pull/41 is merged + +# has builds for the official rp2350 board and the pimoroni2w board +just kernel-release rp235x # keep in mind that https://github.com/StripedMonkey/elf2uf2-rs version is required until https://github.com/JoNil/elf2uf2-rs/pull/41 is merged diff --git a/justfile b/justfile index 871025d..a8fa389 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ -kernel-dev: - cargo run --bin kernel -kernel-release: - cargo build --bin kernel --release +kernel-dev board: + cargo run --bin kernel --features {{board}} +kernel-release board: + cargo build --bin kernel --release --no-default-features --features {{board}} elf2uf2-rs -d target/thumbv8m.main-none-eabihf/release/kernel binary-args := "RUSTFLAGS=\"-C link-arg=-pie -C relocation-model=pic\"" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2db6363..b2f237a 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -12,6 +12,7 @@ bench = false [features] default = ["rp235x", "defmt"] +pimoroni2w = ["rp235x"] rp2040 = ["embassy-rp/rp2040"] rp235x = ["embassy-rp/rp235xb"] trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"] @@ -58,6 +59,7 @@ cyw43 = { version = "0.3.0", features = [ ], optional = true } cyw43-pio = { version = "0.3.0", optional = true } +critical-section = "1.2.0" embedded-hal-bus = { version = "0.3.0", features = ["async"] } embedded-hal = "0.2.7" embedded-hal_2 = { package = "embedded-hal", version = "1.0.0" } @@ -88,6 +90,7 @@ spin = "0.10.0" num_enum = { version = "0.7.4", default-features = false } goblin = { version = "0.10.1", default-features = false, features = ["elf32"] } talc = "4.4.3" +embedded-alloc = "0.6.0" bumpalo = "3.19.0" abi_sys = { path = "../abi_sys" } diff --git a/kernel/build.rs b/kernel/build.rs index 30691aa..8220df0 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -13,13 +13,18 @@ use std::fs::File; use std::io::Write; use std::path::PathBuf; +#[cfg(all(feature = "rp235x", not(feature = "pimoroni2w")))] +const MEMORY: &'static [u8] = include_bytes!("rp2350.x"); +#[cfg(feature = "pimoroni2w")] +const MEMORY: &'static [u8] = include_bytes!("rp2350.x"); + fn main() { // Put `memory.x` in our output directory and ensure it's // on the linker search path. let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() - .write_all(include_bytes!("memory.x")) + .write_all(MEMORY) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); diff --git a/kernel/pimoroni2w.x b/kernel/pimoroni2w.x new file mode 100644 index 0000000..56e741f --- /dev/null +++ b/kernel/pimoroni2w.x @@ -0,0 +1,60 @@ +MEMORY { + FLASH : ORIGIN = 0x10000000, LENGTH = 16M - 4K + + RAM : ORIGIN = 0x20000000, LENGTH = 512K + SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K + SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K +} + +SECTIONS { + /* ### Boot ROM info + * + * Goes after .vector_table, to keep it in the first 4K of flash + * where the Boot ROM (and picotool) can find it + */ + .start_block : ALIGN(4) + { + __start_block_addr = .; + KEEP(*(.start_block)); + KEEP(*(.boot_info)); + } > FLASH + +} INSERT AFTER .vector_table; + +/* move .text to start /after/ the boot info */ +_stext = ADDR(.start_block) + SIZEOF(.start_block); + +SECTIONS { + /* ### Picotool 'Binary Info' Entries + * + * Picotool looks through this block (as we have pointers to it in our + * header) to find interesting information. + */ + .bi_entries : ALIGN(4) + { + /* We put this in the header */ + __bi_entries_start = .; + /* Here are the entries */ + KEEP(*(.bi_entries)); + /* Keep this block a nice round size */ + . = ALIGN(4); + /* We put this in the header */ + __bi_entries_end = .; + } > FLASH +} INSERT AFTER .text; + +SECTIONS { + /* ### Boot ROM extra info + * + * Goes after everything in our program, so it can contain a signature. + */ + .end_block : ALIGN(4) + { + __end_block_addr = .; + KEEP(*(.end_block)); + } > FLASH + +} INSERT AFTER .uninit; + +PROVIDE(start_to_end = __end_block_addr - __start_block_addr); +PROVIDE(end_to_start = __start_block_addr - __end_block_addr); diff --git a/kernel/memory.x b/kernel/rp2350.x similarity index 100% rename from kernel/memory.x rename to kernel/rp2350.x diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 3bed7c0..027b021 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -20,9 +20,11 @@ pub extern "C" fn print(ptr: *const u8, len: usize) { // SAFETY: caller guarantees `ptr` is valid for `len` bytes let slice = unsafe { core::slice::from_raw_parts(ptr, len) }; - if let Ok(msg) = core::str::from_utf8(slice) { - defmt::info!("print: {}", msg); + if let Ok(_msg) = core::str::from_utf8(slice) { + #[cfg(feature = "defmt")] + defmt::info!("print: {}", _msg); } else { + #[cfg(feature = "defmt")] defmt::warn!("print: "); } } diff --git a/kernel/src/heap.rs b/kernel/src/heap.rs new file mode 100644 index 0000000..c4f444c --- /dev/null +++ b/kernel/src/heap.rs @@ -0,0 +1,132 @@ +// This whole file was taken from: +// https://github.com/wezterm/picocalc-wezterm/blob/main/src/heap.rs + +use core::alloc::{GlobalAlloc, Layout}; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering}; +use embedded_alloc::LlffHeap as Heap; + +#[global_allocator] +pub static HEAP: DualHeap = DualHeap::empty(); +const HEAP_SIZE: usize = 64 * 1024; +static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; + +struct Region { + start: AtomicUsize, + size: AtomicUsize, +} + +impl Region { + const fn default() -> Self { + Self { + start: AtomicUsize::new(0), + size: AtomicUsize::new(0), + } + } + + fn contains(&self, address: usize) -> bool { + let start = self.start.load(Ordering::Relaxed); + let end = self.start.load(Ordering::Relaxed); + (start..start + end).contains(&address) + } + + fn new(start: usize, size: usize) -> Self { + Self { + start: AtomicUsize::new(start), + size: AtomicUsize::new(size), + } + } +} + +/// This is an allocator that combines two regions of memory. +/// The intent is to use some of the directly connected RAM +/// for this, and if we find some XIP capable PSRAM, add that +/// as a secondary region. +/// Allocation from the primary region is always preferred, +/// as it is expected to be a bit faster than PSRAM. +/// FIXME: PSRAM-allocated memory isn't compatible with +/// CAS atomics, so we might need a bit of a think about this! +pub struct DualHeap { + primary: Heap, + primary_region: Region, + secondary: Heap, +} + +impl DualHeap { + pub const fn empty() -> Self { + Self { + primary: Heap::empty(), + primary_region: Region::default(), + secondary: Heap::empty(), + } + } + + unsafe fn add_primary(&self, region: Region) { + let start = region.start.load(Ordering::SeqCst); + let size = region.size.load(Ordering::SeqCst); + unsafe { + self.primary.init(start, size); + } + self.primary_region.start.store(start, Ordering::SeqCst); + self.primary_region.size.store(size, Ordering::SeqCst); + } + + unsafe fn add_secondary(&self, region: Region) { + let start = region.start.load(Ordering::SeqCst); + let size = region.size.load(Ordering::SeqCst); + unsafe { + self.secondary.init(start, size); + } + } + + pub fn used(&self) -> usize { + self.primary.used() + self.secondary.used() + } + + pub fn free(&self) -> usize { + self.primary.free() + self.secondary.free() + } +} + +unsafe impl GlobalAlloc for DualHeap { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + unsafe { + let ptr = self.primary.alloc(layout); + if !ptr.is_null() { + return ptr; + } + // start using secondary area when primary heap is full + self.secondary.alloc(layout) + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + unsafe { + let ptr_usize = ptr as usize; + if self.primary_region.contains(ptr_usize) { + self.primary.dealloc(ptr, layout); + } else { + self.secondary.dealloc(ptr, layout); + } + } + } +} + +pub fn init_heap() { + let primary_start = &raw mut HEAP_MEM as usize; + unsafe { HEAP.add_primary(Region::new(primary_start, HEAP_SIZE)) } +} + +pub fn init_qmi_psram_heap(size: u32) { + unsafe { HEAP.add_secondary(Region::new(0x11000000, size as usize)) } +} + +pub async fn free_command(_args: &[&str]) { + let ram_used = HEAP.primary.used(); + let ram_free = HEAP.primary.free(); + let ram_total = ram_used + ram_free; + + let qmi_used = HEAP.secondary.used(); + let qmi_free = HEAP.secondary.free(); + let qmi_total = qmi_used + qmi_free; +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 57490ec..887b65d 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -10,13 +10,19 @@ mod abi; mod display; mod elf; mod framebuffer; +#[cfg(feature = "pimoroni2w")] +mod heap; mod peripherals; +mod psram; mod scsi; mod storage; mod ui; mod usb; mod utils; +#[cfg(feature = "pimoroni2w")] +use crate::{heap::init_qmi_psram_heap, psram::init_psram_qmi}; + use crate::{ abi::{KEY_CACHE, MS_SINCE_LAUNCH}, display::{FRAMEBUFFER, display_handler, init_display}, @@ -24,6 +30,7 @@ use crate::{ conf_peripherals, keyboard::{KeyState, read_keyboard_fifo}, }, + psram::init_psram, scsi::MSC_SHUTDOWN, storage::{SDCARD, SdCard}, ui::{SELECTIONS, clear_selection, ui_handler}, @@ -38,7 +45,6 @@ use embedded_graphics::{ use {defmt_rtt as _, panic_probe as _}; use core::sync::atomic::{AtomicBool, Ordering}; -use defmt::unwrap; use embassy_executor::{Executor, Spawner}; use embassy_futures::{join::join, select::select}; use embassy_rp::{ @@ -47,9 +53,11 @@ use embassy_rp::{ i2c::{self, I2c}, multicore::{Stack, spawn_core1}, peripherals::{ - DMA_CH0, DMA_CH1, I2C1, PIN_6, PIN_7, PIN_10, PIN_11, PIN_12, PIN_13, PIN_14, PIN_15, - PIN_16, PIN_17, PIN_18, PIN_19, PIN_22, SPI0, SPI1, USB, + DMA_CH0, DMA_CH1, DMA_CH3, DMA_CH4, I2C1, PIN_2, PIN_3, PIN_6, PIN_7, PIN_10, PIN_11, + PIN_12, PIN_13, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, PIN_20, PIN_21, PIN_22, + PIO0, SPI0, SPI1, USB, }, + pio, spi::{self, Spi}, usb as embassy_rp_usb, }; @@ -65,14 +73,17 @@ use talc::*; embassy_rp::bind_interrupts!(struct Irqs { I2C1_IRQ => i2c::InterruptHandler; USBCTRL_IRQ => embassy_rp_usb::InterruptHandler; + PIO0_IRQ_0 => pio::InterruptHandler; }); static mut CORE1_STACK: Stack<16384> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); +#[cfg(not(feature = "pimoroni2w"))] static mut ARENA: [u8; 200 * 1024] = [0; 200 * 1024]; +#[cfg(not(feature = "pimoroni2w"))] #[global_allocator] static ALLOCATOR: Talck, ClaimOnOom> = Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) }) @@ -90,7 +101,7 @@ async fn main(_spawner: Spawner) { unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, move || { let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(userland_task()))); + executor1.run(|spawner| spawner.spawn(userland_task()).unwrap()); }, ); @@ -113,13 +124,26 @@ async fn main(_spawner: Spawner) { cs: p.PIN_17, det: p.PIN_22, }; + let psram = Psram { + pio: p.PIO0, + sclk: p.PIN_21, + mosi: p.PIN_2, + miso: p.PIN_3, + cs: p.PIN_20, + dma1: p.DMA_CH3, + dma2: p.DMA_CH4, + }; let mcu = Mcu { i2c: p.I2C1, clk: p.PIN_7, data: p.PIN_6, }; let executor0 = EXECUTOR0.init(Executor::new()); - executor0.run(|spawner| unwrap!(spawner.spawn(kernel_task(spawner, display, sd, mcu, p.USB)))); + executor0.run(|spawner| { + spawner + .spawn(kernel_task(spawner, display, sd, psram, mcu, p.USB)) + .unwrap() + }); } // One-slot channel to pass EntryFn from core1 @@ -143,6 +167,7 @@ async fn userland_task() { } unsafe { MS_SINCE_LAUNCH = Some(Instant::now()) }; + #[cfg(feature = "defmt")] defmt::info!("Executing Binary"); entry(); @@ -177,6 +202,15 @@ struct Sd { cs: Peri<'static, PIN_17>, det: Peri<'static, PIN_22>, } +struct Psram { + pio: Peri<'static, PIO0>, + sclk: Peri<'static, PIN_21>, + mosi: Peri<'static, PIN_2>, + miso: Peri<'static, PIN_3>, + cs: Peri<'static, PIN_20>, + dma1: Peri<'static, DMA_CH3>, + dma2: Peri<'static, DMA_CH4>, +} struct Mcu { i2c: Peri<'static, I2C1>, clk: Peri<'static, PIN_7>, @@ -207,6 +241,29 @@ async fn setup_display(display: Display, spawner: Spawner) { spawner.spawn(display_handler(display)).unwrap(); } +async fn setup_psram(psram: Psram) { + let psram = init_psram( + psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2, + ) + .await; + + #[cfg(feature = "defmt")] + defmt::info!("psram size: {}", psram.size); + + if psram.size == 0 { + #[cfg(feature = "defmt")] + defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m"); + } + + #[cfg(feature = "pimoroni2w")] + { + let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL); + if psram_qmi_size > 0 { + init_qmi_psram_heap(psram_qmi_size); + } + } +} + async fn setup_sd(sd: Sd) { let mut config = spi::Config::default(); config.frequency = 400_000; @@ -227,12 +284,14 @@ async fn kernel_task( spawner: Spawner, display: Display, sd: Sd, + psram: Psram, mcu: Mcu, usb: Peri<'static, USB>, ) { setup_mcu(mcu).await; Timer::after_millis(250).await; setup_display(display, spawner).await; + setup_psram(psram).await; setup_sd(sd).await; let _usb = embassy_rp_usb::Driver::new(usb, Irqs); diff --git a/kernel/src/psram.rs b/kernel/src/psram.rs new file mode 100644 index 0000000..9145090 --- /dev/null +++ b/kernel/src/psram.rs @@ -0,0 +1,623 @@ +// This whole file was taken from +// +// +use crate::Irqs; +use embassy_futures::yield_now; +use embassy_rp::Peri; +use embassy_rp::clocks::clk_peri_freq; +use embassy_rp::gpio::{Drive, SlewRate}; +use embassy_rp::peripherals::{DMA_CH3, DMA_CH4, PIN_2, PIN_3, PIN_20, PIN_21, PIO0}; +use embassy_rp::pio::program::pio_asm; +use embassy_rp::pio::{Config, Direction, Pio, ShiftDirection}; +use embassy_rp::pio_programs::clock_divider::calculate_pio_clock_divider; +use embassy_time::{Duration, Instant, Timer}; + +// The physical connections in the picocalc schematic are: +// LABEL PICO ESP-PSRAM64H +// RAM_CS - PIN_20 CE (pulled up to 3v3 via 10kOhm) +// RAM_SCK - PIN_21 SCLK +// RAM_TX - PIN_2 SI/SIO0 +// RAM_RX - PIN_3 SO/SIO1 +// RAM_IO2 - PIN_4 SIO2 (QPI Mode) +// RAM_IO3 - PIN_5 SIO3 (QPI Mode) + +#[allow(unused)] +const PSRAM_CMD_QUAD_END: u8 = 0xf5; +#[allow(unused)] +const PSRAM_CMD_QUAD_ENABLE: u8 = 0x35; +#[allow(unused)] +const PSRAM_CMD_READ_ID: u8 = 0x9F; +const PSRAM_CMD_RSTEN: u8 = 0x66; +const PSRAM_CMD_RST: u8 = 0x99; +const PSRAM_CMD_WRITE: u8 = 0x02; +const PSRAM_CMD_FAST_READ: u8 = 0x0B; +#[allow(unused)] +const PSRAM_CMD_QUAD_READ: u8 = 0xEB; +#[allow(unused)] +const PSRAM_CMD_QUAD_WRITE: u8 = 0x38; +#[allow(unused)] +const PSRAM_CMD_NOOP: u8 = 0xFF; +#[allow(unused)] +const PSRAM_KNOWN_GOOD_DIE_PASS: u8 = 0x5d; + +const MAX_PSRAM_FREQ: u32 = 133_000_000; + +pub struct PsRam { + sm: embassy_rp::pio::StateMachine<'static, PIO0, 0>, + tx_ch: Peri<'static, DMA_CH3>, + rx_ch: Peri<'static, DMA_CH4>, + pub size: u32, +} + +impl PsRam { + pub async fn send_command(&mut self, cmd: &[u8], out: &mut [u8]) { + if out.is_empty() { + self.sm + .tx() + .dma_push(self.tx_ch.reborrow(), cmd, false) + .await; + } else { + let (rx, tx) = self.sm.rx_tx(); + tx.dma_push(self.tx_ch.reborrow(), cmd, false).await; + rx.dma_pull(self.rx_ch.reborrow(), out, false).await; + } + } + + pub async fn write(&mut self, mut addr: u32, mut data: &[u8]) { + // I haven't seen this work reliably over 24 bytes + const MAX_CHUNK: usize = 24; + while data.len() > 0 { + let to_write = data.len().min(MAX_CHUNK); + //defmt::info!("writing {to_write} @ {addr}"); + + #[rustfmt::skip] + let mut to_send = [ + 32 + (to_write as u8 * 8), // write address + data + 0, // read 0 bits + PSRAM_CMD_WRITE, + ((addr >> 16) & 0xff) as u8, + ((addr >> 8) & 0xff) as u8, + (addr & 0xff) as u8, + // This sequence must be MAX_CHUNK in length + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + + for (src, dst) in data.iter().zip(to_send.iter_mut().skip(6)) { + *dst = *src; + } + + self.send_command(&to_send[0..6 + to_write], &mut []).await; + addr += to_write as u32; + data = &data[to_write..]; + } + } + + pub async fn read_id(&mut self) -> [u8; 3] { + let mut id = [0u8; 3]; + #[rustfmt::skip] + self.send_command( + &[ + 32, // write 32 bits + 3 * 8, // read 8 bytes = 64 bits + PSRAM_CMD_READ_ID, + // don't care: 24-bit "address" + 0, 0, 0, + ], + &mut id, + ) + .await; + id + } + + pub async fn read(&mut self, mut addr: u32, mut out: &mut [u8]) { + // Cannot get reliable reads above 4 bytes at a time. + // out[4] will always have a bit error + const MAX_CHUNK: usize = 4; + while out.len() > 0 { + let to_read = out.len().min(MAX_CHUNK); + //defmt::info!("reading {to_read} @ {addr}"); + self.send_command( + &[ + 40, // write 40 bits + to_read as u8 * 8, // read n bytes + PSRAM_CMD_FAST_READ, + ((addr >> 16) & 0xff) as u8, + ((addr >> 8) & 0xff) as u8, + (addr & 0xff) as u8, + 0, // 8 cycle delay by sending 8 bits of don't care data + ], + &mut out[0..to_read], + ) + .await; + addr += to_read as u32; + out = &mut out[to_read..]; + } + } + + #[allow(unused)] + pub async fn write8(&mut self, addr: u32, data: u8) { + //defmt::info!("write8 addr {addr} <- {data:x}"); + self.send_command( + &[ + 40, // write 40 bits + 0, // read 0 bits + PSRAM_CMD_WRITE, + ((addr >> 16) & 0xff) as u8, + ((addr >> 8) & 0xff) as u8, + (addr & 0xff) as u8, + data, + ], + &mut [], + ) + .await; + } + + #[allow(unused)] + pub async fn read8(&mut self, addr: u32) -> u8 { + let mut buf = [0u8]; + self.send_command( + &[ + 40, // write 40 bits + 8, // read 8 bits + PSRAM_CMD_FAST_READ, + ((addr >> 16) & 0xff) as u8, + ((addr >> 8) & 0xff) as u8, + (addr & 0xff) as u8, + 0, // 8 cycle delay + ], + &mut buf, + ) + .await; + buf[0] + } +} + +pub async fn init_psram( + pio: Peri<'static, PIO0>, + sclk: Peri<'static, PIN_21>, + mosi: Peri<'static, PIN_2>, + miso: Peri<'static, PIN_3>, + cs: Peri<'static, PIN_20>, + dma1: Peri<'static, DMA_CH3>, + dma2: Peri<'static, DMA_CH4>, +) -> PsRam { + let mut pio = Pio::new(pio, Irqs); + + let divider = calculate_pio_clock_divider(MAX_PSRAM_FREQ); + + // This pio program was taken from + // + // which is Copyright © 2023 Ian Scott, reproduced here under the MIT license + + let p = pio_asm!( + r#" +.side_set 2 ; sideset bit 1 is SCK, bit 0 is CS +begin: + out x, 8 side 0b01 ; x = number of bits to output. CS deasserted + out y, 8 side 0b01 ; y = number of bits to input + jmp x--, writeloop side 0b01 ; Pre-decement x by 1 so loop has correct number of iterations +writeloop: + out pins, 1 side 0b00 ; Write value on pin, lower clock. CS asserted + jmp x--, writeloop side 0b10 ; Raise clock: this is when PSRAM reads the value. Loop if we have more to write + jmp !y, done side 0b00 ; If this is a write-only operation, jump back to beginning + nop side 0b10 ; Fudge factor of extra clock cycle; the PSRAM needs 1 extra for output to start appearing + jmp readloop_mid side 0b00 ; Jump to middle of readloop to decrement y and get right clock phase +readloop: + in pins, 1 side 0b00 ; Read value on pin, lower clock. Datasheet says to read on falling edge > 83MHz +readloop_mid: + jmp y--, readloop side 0b10 ; Raise clock. Loop if we have more to read +done: + nop side 0b11 ; CS deasserted + "# + ); + let prog = pio.common.load_program(&p.program); + + let mut cfg = Config::default(); + + let mut cs = pio.common.make_pio_pin(cs); + let mut sclk = pio.common.make_pio_pin(sclk); + let mut mosi = pio.common.make_pio_pin(mosi); + let mut miso = pio.common.make_pio_pin(miso); + + sclk.set_slew_rate(SlewRate::Fast); + mosi.set_slew_rate(SlewRate::Fast); + + cs.set_drive_strength(Drive::_4mA); + sclk.set_drive_strength(Drive::_4mA); + mosi.set_drive_strength(Drive::_4mA); + miso.set_drive_strength(Drive::_4mA); + + cfg.use_program(&prog, &[&cs, &sclk]); + cfg.set_out_pins(&[&mosi]); + cfg.set_in_pins(&[&miso]); + + cfg.shift_out.direction = ShiftDirection::Left; + cfg.shift_out.auto_fill = true; + cfg.shift_out.threshold = 8; + + cfg.shift_in = cfg.shift_out; + cfg.clock_divider = divider; + + let mut sm = pio.sm0; + sm.restart(); + sm.set_pin_dirs(Direction::Out, &[&cs, &sclk]); + sm.set_pin_dirs(Direction::Out, &[&mosi]); + sm.set_pin_dirs(Direction::In, &[&miso]); + miso.set_input_sync_bypass(true); + + sm.set_config(&cfg); + sm.set_enable(true); + + let mut psram = PsRam { + sm, + tx_ch: dma1, + rx_ch: dma2, + size: 0, + }; + + // Issue a reset command + psram.send_command(&[8, 0, PSRAM_CMD_RSTEN], &mut []).await; + Timer::after(Duration::from_micros(50)).await; + psram.send_command(&[8, 0, PSRAM_CMD_RST], &mut []).await; + Timer::after(Duration::from_micros(100)).await; + + #[cfg(feature = "defmt")] + defmt::info!("Verifying 1 byte write and read..."); + for i in 0..10u8 { + psram.write8(i as u32, i).await; + } + for i in 0..10u32 { + let n = psram.read8(i as u32).await; + if n as u32 != i {} + } + #[cfg(feature = "defmt")] + defmt::info!("testing read again @ 0"); + let mut got = [0u8; 8]; + psram.read(0, &mut got).await; + const EXPECT: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7]; + if got != EXPECT { + #[cfg(feature = "defmt")] + defmt::warn!("Got Read error"); + } + + const DEADBEEF: &[u8] = &[0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf]; + #[cfg(feature = "defmt")] + defmt::info!("testing write of deadbeef at 0"); + psram.write(0, DEADBEEF).await; + + #[cfg(feature = "defmt")] + defmt::info!("testing read of deadbeef from 0"); + psram.read(0, &mut got).await; + if got != DEADBEEF { + for addr in 0..DEADBEEF.len() { + let bad = got[addr]; + if bad != DEADBEEF[addr] { + let x = psram.read8(addr as u32).await; + #[cfg(feature = "defmt")] + defmt::info!("read addr: {}, got: {:X}", addr, x); + } + } + } + + const TEST_STRING: &[u8] = b"hello there, this is a test, how is it?"; + psram.write(16, TEST_STRING).await; + + let mut buffer = [0u8; 42]; + psram.read(16, &mut buffer).await; + + let got = &buffer[0..TEST_STRING.len()]; + + if got != TEST_STRING {} + + #[cfg(feature = "defmt")] + defmt::info!("PSRAM test complete"); + + let id = psram.read_id().await; + #[cfg(feature = "defmt")] + defmt::info!("psram id: {}", id); + // id: [d, 5d, 53, 15, 49, e3, 7c, 7b] + // id[0] -- manufacturer id + // id[1] -- "known good die" status + if id[1] == PSRAM_KNOWN_GOOD_DIE_PASS { + // See + // for information on deciding the size of ESP PSRAM chips, + // such as the one used in the picocalc + let size = match (id[2] >> 5) & 0x7 { + 0 => 16, + 1 => 32, + 2 => 64, + _ => 0, + }; + psram.size = size * 1024 * 1024 / 8; + } + + psram +} + +#[allow(unused)] +pub async fn test_psram(psram: &mut PsRam) -> bool { + const REPORT_CHUNK: u32 = 256 * 1024; + const BLOCK_SIZE: usize = 8; + let limit = psram.size; //.min(4 * 1024 * 1024); + + let start = Instant::now(); + + fn expect(addr: u32) -> [u8; BLOCK_SIZE] { + [ + !((addr >> 24 & 0xff) as u8), + !((addr >> 16 & 0xff) as u8), + !((addr >> 8 & 0xff) as u8), + !((addr & 0xff) as u8), + ((addr >> 24 & 0xff) as u8), + ((addr >> 16 & 0xff) as u8), + ((addr >> 8 & 0xff) as u8), + ((addr & 0xff) as u8), + ] + } + + for i in 0..limit / BLOCK_SIZE as u32 { + let addr = i * BLOCK_SIZE as u32; + let data = expect(addr); + psram.write(addr, &data).await; + if addr > 0 && addr % REPORT_CHUNK == 0 { + if start.elapsed() > Duration::from_secs(5) {} + } + // Yield so that the watchdog doesn't kick in + yield_now().await; + } + let writes_took = start.elapsed(); + + #[cfg(feature = "defmt")] + defmt::info!("Starting reads..."); + Timer::after(Duration::from_millis(200)).await; + + let start = Instant::now(); + let mut bad_count = 0; + let mut data = [0u8; BLOCK_SIZE]; + for i in 0..limit / BLOCK_SIZE as u32 { + let addr = i * BLOCK_SIZE as u32; + let expect = expect(addr); + psram.read(addr, &mut data).await; + if addr == 0 { + Timer::after(Duration::from_millis(200)).await; + } + if data != expect { + bad_count += 1; + if bad_count < 50 {} + } + if addr > 0 && addr % REPORT_CHUNK == 0 { + if start.elapsed() > Duration::from_secs(5) {} + } + + // Yield so that the watchdog doesn't kick in + yield_now().await; + } + let reads_took = start.elapsed(); + + bad_count == 0 +} + +// The origin of the code in this file is: +// +// which is MIT/Apache-2 licensed. +#[unsafe(link_section = ".data")] +#[inline(never)] +pub fn detect_psram_qmi(qmi: &embassy_rp::pac::qmi::Qmi) -> u32 { + const GPIO_FUNC_XIP_CS1: u8 = 9; + const XIP_CS_PIN: usize = 47; + embassy_rp::pac::PADS_BANK0.gpio(XIP_CS_PIN).modify(|w| { + w.set_iso(true); + }); + embassy_rp::pac::PADS_BANK0.gpio(XIP_CS_PIN).modify(|w| { + w.set_ie(true); + w.set_od(false); + }); + embassy_rp::pac::IO_BANK0 + .gpio(XIP_CS_PIN) + .ctrl() + .write(|w| w.set_funcsel(GPIO_FUNC_XIP_CS1)); + embassy_rp::pac::PADS_BANK0.gpio(XIP_CS_PIN).modify(|w| { + w.set_iso(false); + }); + + critical_section::with(|_cs| { + // Try and read the PSRAM ID via direct_csr. + qmi.direct_csr().write(|w| { + w.set_clkdiv(30); + w.set_en(true); + }); + + // Need to poll for the cooldown on the last XIP transfer to expire + // (via direct-mode BUSY flag) before it is safe to perform the first + // direct-mode operation + while qmi.direct_csr().read().busy() { + // rp235x_hal::arch::nop(); + } + + // Exit out of QMI in case we've inited already + qmi.direct_csr().modify(|w| w.set_assert_cs1n(true)); + + // Transmit the command to exit QPI quad mode - read ID as standard SPI + // Transmit as quad. + qmi.direct_tx().write(|w| { + w.set_oe(true); + w.set_iwidth(embassy_rp::pac::qmi::vals::Iwidth::Q); + w.set_data(PSRAM_CMD_QUAD_END.into()); + }); + + while qmi.direct_csr().read().busy() { + // rp235x_hal::arch::nop(); + } + + let _ = qmi.direct_rx().read(); + + qmi.direct_csr().modify(|w| { + w.set_assert_cs1n(false); + }); + + // Read the id + qmi.direct_csr().modify(|w| { + w.set_assert_cs1n(true); + }); + + // kgd is "known good die" + let mut kgd: u16 = 0; + let mut eid: u16 = 0; + for i in 0usize..7 { + qmi.direct_tx().write(|w| { + w.set_data(if i == 0 { + PSRAM_CMD_READ_ID.into() + } else { + PSRAM_CMD_NOOP.into() + }) + }); + + while !qmi.direct_csr().read().txempty() { + // rp235x_hal::arch::nop(); + } + + while qmi.direct_csr().read().busy() { + // rp235x_hal::arch::nop(); + } + + let value = qmi.direct_rx().read().direct_rx(); + match i { + 5 => { + kgd = value; + } + 6 => { + eid = value; + } + _ => {} + } + } + + qmi.direct_csr().modify(|w| { + w.set_assert_cs1n(false); + w.set_en(false); + }); + let mut param_size: u32 = 0; + if kgd == PSRAM_KNOWN_GOOD_DIE_PASS as u16 { + param_size = 1024 * 1024; + let size_id = eid >> 5; + if eid == 0x26 || size_id == 2 { + param_size *= 8; + } else if size_id == 0 { + param_size *= 2; + } else if size_id == 1 { + param_size *= 4; + } + } + param_size + }) +} + +#[unsafe(link_section = ".data")] +#[inline(never)] +pub fn init_psram_qmi( + qmi: &embassy_rp::pac::qmi::Qmi, + xip: &embassy_rp::pac::xip_ctrl::XipCtrl, +) -> u32 { + let psram_size = detect_psram_qmi(qmi); + + if psram_size == 0 { + return 0; + } + + // Set PSRAM timing for APS6404 + // + // Using an rxdelay equal to the divisor isn't enough when running the APS6404 close to 133MHz. + // So: don't allow running at divisor 1 above 100MHz (because delay of 2 would be too late), + // and add an extra 1 to the rxdelay if the divided clock is > 100MHz (i.e. sys clock > 200MHz). + const MAX_PSRAM_FREQ: u32 = 133_000_000; + + let clock_hz = clk_peri_freq(); + + let mut divisor: u32 = (clock_hz + MAX_PSRAM_FREQ - 1) / MAX_PSRAM_FREQ; + if divisor == 1 && clock_hz > 100_000_000 { + divisor = 2; + } + let mut rxdelay: u32 = divisor; + if clock_hz / divisor > 100_000_000 { + rxdelay += 1; + } + + // - Max select must be <= 8us. The value is given in multiples of 64 system clocks. + // - Min deselect must be >= 18ns. The value is given in system clock cycles - ceil(divisor / 2). + let clock_period_fs: u64 = 1_000_000_000_000_000_u64 / u64::from(clock_hz); + let max_select: u8 = ((125 * 1_000_000) / clock_period_fs) as u8; + let min_deselect: u32 = ((18 * 1_000_000 + (clock_period_fs - 1)) / clock_period_fs + - u64::from(divisor + 1) / 2) as u32; + + #[cfg(feature = "defmt")] + defmt::info!( + "clock_period_fs={} max_select={} min_deselect={}", + clock_period_fs, + max_select, + min_deselect + ); + + qmi.direct_csr().write(|w| { + w.set_clkdiv(10); + w.set_en(true); + w.set_auto_cs1n(true); + }); + + while qmi.direct_csr().read().busy() { + // rp235x_hal::arch::nop(); + } + + qmi.direct_tx().write(|w| { + w.set_nopush(true); + w.0 = 0x35; + }); + + while qmi.direct_csr().read().busy() { + // rp235x_hal::arch::nop(); + } + + qmi.mem(1).timing().write(|w| { + w.set_cooldown(1); + w.set_pagebreak(embassy_rp::pac::qmi::vals::Pagebreak::_1024); + w.set_max_select(max_select as u8); + w.set_min_deselect(min_deselect as u8); + w.set_rxdelay(rxdelay as u8); + w.set_clkdiv(divisor as u8); + }); + + // // Set PSRAM commands and formats + qmi.mem(1).rfmt().write(|w| { + w.set_prefix_width(embassy_rp::pac::qmi::vals::PrefixWidth::Q); + w.set_addr_width(embassy_rp::pac::qmi::vals::AddrWidth::Q); + w.set_suffix_width(embassy_rp::pac::qmi::vals::SuffixWidth::Q); + w.set_dummy_width(embassy_rp::pac::qmi::vals::DummyWidth::Q); + w.set_data_width(embassy_rp::pac::qmi::vals::DataWidth::Q); + w.set_prefix_len(embassy_rp::pac::qmi::vals::PrefixLen::_8); + w.set_dummy_len(embassy_rp::pac::qmi::vals::DummyLen::_24); + }); + + qmi.mem(1).rcmd().write(|w| w.0 = 0xEB); + + qmi.mem(1).wfmt().write(|w| { + w.set_prefix_width(embassy_rp::pac::qmi::vals::PrefixWidth::Q); + w.set_addr_width(embassy_rp::pac::qmi::vals::AddrWidth::Q); + w.set_suffix_width(embassy_rp::pac::qmi::vals::SuffixWidth::Q); + w.set_dummy_width(embassy_rp::pac::qmi::vals::DummyWidth::Q); + w.set_data_width(embassy_rp::pac::qmi::vals::DataWidth::Q); + w.set_prefix_len(embassy_rp::pac::qmi::vals::PrefixLen::_8); + }); + + qmi.mem(1).wcmd().write(|w| w.0 = 0x38); + + // Disable direct mode + qmi.direct_csr().write(|w| w.0 = 0); + + // Enable writes to PSRAM + xip.ctrl().modify(|w| w.set_writable_m1(true)); + psram_size +} diff --git a/kernel/src/scsi/mod.rs b/kernel/src/scsi/mod.rs index b61acee..9618563 100644 --- a/kernel/src/scsi/mod.rs +++ b/kernel/src/scsi/mod.rs @@ -54,6 +54,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { select(self.handle_cbw(), MSC_SHUTDOWN.wait()).await; if MSC_SHUTDOWN.signaled() { + #[cfg(feature = "defmt")] defmt::info!("MSC shutting down"); if self.temp_sd.is_some() { @@ -80,6 +81,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { if let Some(sd) = guard.take() { self.temp_sd = Some(sd); } else { + #[cfg(feature = "defmt")] defmt::warn!("Tried to take SDCARD but it was already taken"); return; } @@ -363,6 +365,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { } pub async fn send_csw_fail(&mut self, tag: u32) { + #[cfg(feature = "defmt")] defmt::error!("Command Failed: {}", tag); self.send_csw(tag, 0x01, 0).await; // 0x01 = Command Failed }