Repository: HaoboGu/rmk (language: rust)

Issue:
Support embassy
Current implementation of RMK requires only `rtic-monotonics`. It's possible to support embassy, or both by removing `rtic-monotonics`.


Discussion / hints:

Fix patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 1bbc3196..8fd858e4 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -67,7 +67,7 @@
             "flashingConfig": {
                 "flashingEnabled": true,
                 "resetAfterFlashing": true,
-                "haltAfterReset": true,
+                "haltAfterReset": false,
             },
             "coreConfigs": [
                 {
diff --git a/Cargo.lock b/Cargo.lock
index 84b67dec..9b633ea8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,12 +2,30 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "arrayvec"
 version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
+[[package]]
+name = "ascii-canvas"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
+dependencies = [
+ "term",
+]
+
 [[package]]
 name = "atomic-polyfill"
 version = "1.0.3"
@@ -17,6 +35,18 @@ dependencies = [
  "critical-section",
 ]
 
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "az"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
+
 [[package]]
 name = "bare-metal"
 version = "0.2.5"
@@ -27,10 +57,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "bare-metal"
-version = "1.0.0"
+name = "bit-set"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bit_field"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
 
 [[package]]
 name = "bitfield"
@@ -44,6 +89,12 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "bitflags"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+
 [[package]]
 name = "bitvec"
 version = "1.0.1"
@@ -57,16 +108,28 @@ dependencies = [
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
+name = "bxcan"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "40ac3d0c0a542d0ab5521211f873f62706a7136df415676f676d347e5a41dd80"
+dependencies = [
+ "bitflags 1.3.2",
+ "embedded-hal 0.2.7",
+ "nb 1.1.0",
+ "vcell",
+]
 
 [[package]]
-name = "cast"
-version = "0.3.0"
+name = "bytemuck"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "cfg-if"
@@ -74,13 +137,23 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width",
+]
+
 [[package]]
 name = "cortex-m"
 version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
 dependencies = [
- "bare-metal 0.2.5",
+ "bare-metal",
  "bitfield",
  "critical-section",
  "embedded-hal 0.2.7",
@@ -109,9 +182,9 @@ dependencies = [
 
 [[package]]
 name = "crc-any"
-version = "2.4.3"
+version = "2.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
+checksum = "c01a5e1f881f6fb6099a7bdf949e946719fd4f1fefa56264890574febf0eb6d0"
 dependencies = [
  "debug-helper",
 ]
@@ -122,6 +195,47 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
 
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "darling"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.48",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.48",
+]
+
 [[package]]
 name = "debug-helper"
 version = "0.3.13"
@@ -134,7 +248,7 @@ version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "defmt-macros",
 ]
 
@@ -148,7 +262,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.31",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -170,6 +284,42 @@ dependencies = [
  "defmt",
 ]
 
+[[package]]
+name = "diff"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
+
+[[package]]
+name = "dirs-next"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
+dependencies = [
+ "cfg-if",
+ "dirs-sys-next",
+]
+
+[[package]]
+name = "dirs-sys-next"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
+name = "document-features"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
+dependencies = [
+ "litrs",
+]
+
 [[package]]
 name = "either"
 version = "1.9.0"
@@ -177,22 +327,226 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
 
 [[package]]
-name = "embedded-alloc"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815"
+name = "embassy-embedded-hal"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
 dependencies = [
+ "embassy-futures",
+ "embassy-sync",
+ "embassy-time",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0",
+ "embedded-hal-async",
+ "embedded-storage",
+ "embedded-storage-async",
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "embassy-executor"
+version = "0.5.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "cortex-m",
  "critical-section",
- "linked_list_allocator",
+ "defmt",
+ "document-features",
+ "embassy-executor-macros",
+ "embassy-time-driver",
+ "embassy-time-queue-driver",
 ]
 
 [[package]]
-name = "embedded-dma"
+name = "embassy-executor-macros"
+version = "0.4.1"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.48",
+]
+
+[[package]]
+name = "embassy-futures"
+version = "0.1.1"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+
+[[package]]
+name = "embassy-hal-internal"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "cortex-m",
+ "critical-section",
+ "defmt",
+ "num-traits",
+]
+
+[[package]]
+name = "embassy-net-driver"
 version = "0.2.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+
+[[package]]
+name = "embassy-net-driver-channel"
+version = "0.2.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "embassy-futures",
+ "embassy-net-driver",
+ "embassy-sync",
+]
+
+[[package]]
+name = "embassy-rp"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "atomic-polyfill",
+ "cfg-if",
+ "cortex-m",
+ "cortex-m-rt",
+ "critical-section",
+ "defmt",
+ "document-features",
+ "embassy-embedded-hal",
+ "embassy-futures",
+ "embassy-hal-internal",
+ "embassy-sync",
+ "embassy-time",
+ "embassy-time-driver",
+ "embassy-usb-driver",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0",
+ "embedded-hal-async",
+ "embedded-hal-nb",
+ "embedded-io",
+ "embedded-io-async",
+ "embedded-storage",
+ "embedded-storage-async",
+ "fixed",
+ "futures",
+ "nb 1.1.0",
+ "pio",
+ "pio-proc",
+ "rand_core",
+ "rp-pac",
+ "rp2040-boot2",
+]
+
+[[package]]
+name = "embassy-stm32"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "bit_field",
+ "bxcan",
+ "cfg-if",
+ "cortex-m",
+ "cortex-m-rt",
+ "critical-section",
+ "document-features",
+ "embassy-embedded-hal",
+ "embassy-futures",
+ "embassy-hal-internal",
+ "embassy-net-driver",
+ "embassy-sync",
+ "embassy-time",
+ "embassy-time-driver",
+ "embassy-usb-driver",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0",
+ "embedded-hal-async",
+ "embedded-hal-nb",
+ "embedded-io",
+ "embedded-io-async",
+ "embedded-storage",
+ "embedded-storage-async",
+ "futures",
+ "nb 1.1.0",
+ "proc-macro2",
+ "quote",
+ "rand_core",
+ "sdio-host",
+ "stm32-fmc",
+ "stm32-metapac",
+ "vcell",
+]
+
+[[package]]
+name = "embassy-sync"
+version = "0.5.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "cfg-if",
+ "critical-section",
+ "embedded-io-async",
+ "futures-util",
+ "heapless",
+]
+
+[[package]]
+name = "embassy-time"
+version = "0.3.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "cfg-if",
+ "critical-section",
+ "defmt",
+ "document-features",
+ "embassy-time-driver",
+ "embassy-time-queue-driver",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0",
+ "embedded-hal-async",
+ "futures-util",
+ "heapless",
+]
+
+[[package]]
+name = "embassy-time-driver"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "document-features",
+]
+
+[[package]]
+name = "embassy-time-queue-driver"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+
+[[package]]
+name = "embassy-usb"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "embassy-futures",
+ "embassy-net-driver-channel",
+ "embassy-sync",
+ "embassy-usb-driver",
+ "heapless",
+ "ssmarshal",
+ "usbd-hid",
+]
+
+[[package]]
+name = "embassy-usb-driver"
+version = "0.1.0"
+source = "git+https://github.com/embassy-rs/embassy#686069b4c97b201e4fd444785d784b9836ee2271"
+dependencies = [
+ "defmt",
+]
+
+[[package]]
+name = "embedded-alloc"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
+checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815"
 dependencies = [
- "stable_deref_trait",
+ "critical-section",
+ "linked_list_allocator",
 ]
 
 [[package]]
@@ -210,12 +564,67 @@ name = "embedded-hal"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
+dependencies = [
+ "defmt",
+]
+
+[[package]]
+name = "embedded-hal-async"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
+dependencies = [
+ "embedded-hal 1.0.0",
+]
+
+[[package]]
+name = "embedded-hal-nb"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605"
+dependencies = [
+ "embedded-hal 1.0.0",
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "embedded-io"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
+
+[[package]]
+name = "embedded-io-async"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f"
+dependencies = [
+ "embedded-io",
+]
 
 [[package]]
 name = "embedded-storage"
-version = "0.3.0"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032"
+
+[[package]]
+name = "embedded-storage-async"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723"
+checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc"
+dependencies = [
+ "embedded-storage",
+]
+
+[[package]]
+name = "ena"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
+dependencies = [
+ "log",
+]
 
 [[package]]
 name = "encode_unicode"
@@ -230,105 +639,197 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
-name = "frunk"
-version = "0.4.2"
+name = "errno"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a351b59e12f97b4176ee78497dff72e4276fb1ceb13e19056aca7fa0206287"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
- "frunk_core",
- "frunk_derives",
+ "libc",
+ "windows-sys",
 ]
 
 [[package]]
-name = "frunk_core"
-version = "0.4.2"
+name = "fixed"
+version = "1.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af2469fab0bd07e64ccf0ad57a1438f63160c69b2e57f04a439653d68eb558d6"
+checksum = "02c69ce7e7c0f17aa18fdd9d0de39727adb9c6281f2ad12f57cbe54ae6e76e7d"
+dependencies = [
+ "az",
+ "bytemuck",
+ "half",
+ "typenum",
+]
 
 [[package]]
-name = "frunk_derives"
+name = "fixedbitset"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e"
-dependencies = [
- "frunk_proc_macro_helpers",
- "quote",
- "syn 2.0.31",
-]
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
 
 [[package]]
-name = "frunk_proc_macro_helpers"
-version = "0.1.2"
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "funty"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35b54add839292b743aeda6ebedbd8b11e93404f902c56223e51b9ec18a13d2c"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
 dependencies = [
- "frunk_core",
- "proc-macro2",
- "quote",
- "syn 2.0.31",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
 ]
 
 [[package]]
-name = "fugit"
-version = "0.3.7"
+name = "futures-channel"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
 dependencies = [
- "gcd",
+ "futures-core",
+ "futures-sink",
 ]
 
 [[package]]
-name = "funty"
-version = "2.0.0"
+name = "futures-core"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
-name = "futures-core"
-version = "0.3.28"
+name = "futures-io"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.48",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 
 [[package]]
 name = "futures-task"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-util"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-core",
+ "futures-macro",
+ "futures-sink",
  "futures-task",
  "pin-project-lite",
  "pin-utils",
 ]
 
 [[package]]
-name = "gcd"
-version = "2.3.0"
+name = "getrandom"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "half"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
+
+[[package]]
+name = "hash32"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
+dependencies = [
+ "byteorder",
+]
 
 [[package]]
 name = "hashbrown"
-version = "0.14.0"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "heapless"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
+dependencies = [
+ "hash32",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
 name = "indexmap"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
 dependencies = [
  "equivalent",
  "hashbrown",
 ]
 
+[[package]]
+name = "is-terminal"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
+dependencies = [
+ "hermit-abi",
+ "rustix",
+ "windows-sys",
+]
+
 [[package]]
 name = "itertools"
 version = "0.10.5"
@@ -338,18 +839,94 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "lalrpop"
+version = "0.19.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b"
+dependencies = [
+ "ascii-canvas",
+ "bit-set",
+ "diff",
+ "ena",
+ "is-terminal",
+ "itertools",
+ "lalrpop-util",
+ "petgraph",
+ "regex",
+ "regex-syntax 0.6.29",
+ "string_cache",
+ "term",
+ "tiny-keccak",
+ "unicode-xid",
+]
+
+[[package]]
+name = "lalrpop-util"
+version = "0.19.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.152"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+
+[[package]]
+name = "libredox"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
+dependencies = [
+ "bitflags 2.4.2",
+ "libc",
+ "redox_syscall",
+]
+
 [[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.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
+[[package]]
+name = "litrs"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
+
+[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
 [[package]]
 name = "log"
 version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
+[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
 [[package]]
 name = "nb"
 version = "0.1.3"
@@ -365,6 +942,21 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
 
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
 [[package]]
 name = "num_enum"
 version = "0.5.11"
@@ -376,11 +968,11 @@ dependencies = [
 
 [[package]]
 name = "num_enum"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
 dependencies = [
- "num_enum_derive 0.7.0",
+ "num_enum_derive 0.7.2",
 ]
 
 [[package]]
@@ -396,15 +988,21 @@ dependencies = [
 
 [[package]]
 name = "num_enum_derive"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.31",
+ "syn 2.0.48",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
 [[package]]
 name = "packed_struct"
 version = "0.10.1"
@@ -446,12 +1044,54 @@ dependencies = [
  "rtt-target 0.3.1",
 ]
 
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.48.5",
+]
+
 [[package]]
 name = "paste"
 version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
 
+[[package]]
+name = "petgraph"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
+dependencies = [
+ "siphasher",
+]
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.13"
@@ -475,6 +1115,50 @@ dependencies = [
  "paste",
 ]
 
+[[package]]
+name = "pio-parser"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77532c2b8279aef98dfc7207ef15298a5a3d6b6cc76ccc8b65913d69f3a8dd6b"
+dependencies = [
+ "lalrpop",
+ "lalrpop-util",
+ "pio",
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "pio-proc"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b04dc870fb3a4fd8b3e4ca8c61b53bc8ac4eb78b66805d2b3c2e5c4829e0d7a"
+dependencies = [
+ "codespan-reporting",
+ "lalrpop-util",
+ "pio",
+ "pio-parser",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "regex-syntax 0.6.29",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+dependencies = [
+ "critical-section",
+]
+
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
 [[package]]
 name = "proc-macro-error"
 version = "1.0.4"
@@ -494,102 +1178,163 @@ version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
 dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
 ]
 
 [[package]]
-name = "proc-macro2"
-version = "1.0.66"
+name = "regex"
+version = "1.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
 dependencies = [
- "unicode-ident",
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
-name = "quote"
-version = "1.0.33"
+name = "regex-automata"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 dependencies = [
- "proc-macro2",
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
-name = "radium"
-version = "0.7.0"
+name = "regex-syntax"
+version = "0.6.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
 [[package]]
-name = "rand_core"
-version = "0.6.4"
+name = "regex-syntax"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "rmk"
-version = "0.0.6"
+version = "0.1.0"
 dependencies = [
  "byteorder",
+ "embassy-sync",
+ "embassy-time",
+ "embassy-usb",
  "embedded-alloc",
  "embedded-hal 1.0.0",
  "embedded-storage",
  "log",
- "num_enum 0.7.0",
+ "num_enum 0.7.2",
  "packed_struct",
- "rtic-monotonics",
- "usb-device",
+ "static_cell",
  "usbd-hid",
 ]
 
 [[package]]
 name = "rmk-rp2040"
-version = "0.0.3"
+version = "0.1.0"
 dependencies = [
  "cortex-m",
  "cortex-m-rt",
  "defmt",
  "defmt-rtt",
- "embedded-hal 0.2.7",
+ "embassy-executor",
+ "embassy-futures",
+ "embassy-rp",
+ "embassy-time",
+ "embedded-hal 1.0.0",
+ "embedded-storage",
  "log",
+ "packed_struct",
  "panic-probe",
+ "portable-atomic",
  "rmk",
- "rp-pico",
- "rtic",
- "rtic-monotonics",
+ "static_cell",
 ]
 
 [[package]]
 name = "rmk-stm32h7"
-version = "0.0.3"
+version = "0.1.0"
 dependencies = [
  "cortex-m",
  "cortex-m-rt",
+ "embassy-executor",
+ "embassy-futures",
+ "embassy-stm32",
+ "embassy-time",
  "embedded-storage",
  "log",
  "packed_struct",
  "panic-rtt-target",
  "rmk",
- "rtic",
- "rtic-monotonics",
- "rtt-target 0.4.0",
- "stm32h7xx-hal",
+ "rtt-target 0.5.0",
+ "static_cell",
 ]
 
 [[package]]
-name = "rp-pico"
-version = "0.8.0"
+name = "rp-pac"
+version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6341771e6f8e5d130b2b3cbc23435b7847761adf198af09f4b2a60407d43bd56"
+checksum = "f30f6c4c846269293db805e9c77864ff7b923395b480550df44f0868e3765337"
 dependencies = [
+ "cortex-m",
  "cortex-m-rt",
- "fugit",
- "rp2040-boot2",
- "rp2040-hal",
- "usb-device",
 ]
 
 [[package]]
@@ -602,146 +1347,63 @@ dependencies = [
 ]
 
 [[package]]
-name = "rp2040-hal"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ec610f738b69100fbe75f3b835501b669d41c889ac9a62ef284f8e6d1f17385"
-dependencies = [
- "cortex-m",
- "critical-section",
- "embedded-dma",
- "embedded-hal 0.2.7",
- "frunk",
- "fugit",
- "itertools",
- "nb 1.1.0",
- "paste",
- "pio",
- "rand_core",
- "rp2040-hal-macros",
- "rp2040-pac",
- "usb-device",
- "vcell",
- "void",
-]
-
-[[package]]
-name = "rp2040-hal-macros"
-version = "0.1.0"
+name = "rtt-target"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e"
+checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
 dependencies = [
- "cortex-m-rt",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
+ "ufmt-write",
 ]
 
 [[package]]
-name = "rp2040-pac"
+name = "rtt-target"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12d9d8375815f543f54835d01160d4e47f9e2cae75f17ff8f1ec19ce1da96e4c"
-dependencies = [
- "cortex-m",
- "cortex-m-rt",
- "critical-section",
- "vcell",
-]
-
-[[package]]
-name = "rtic"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "857ce76a2517808a303bcb7e5b6d4a9c1d84e5de88b302aec2e53744633c0f4d"
-dependencies = [
- "atomic-polyfill",
- "bare-metal 1.0.0",
- "cortex-m",
- "critical-section",
- "rtic-core",
- "rtic-macros",
-]
-
-[[package]]
-name = "rtic-common"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c"
+checksum = "10b34c9e6832388e45f3c01f1bb60a016384a0a4ad80cdd7d34913bed25037f0"
 dependencies = [
  "critical-section",
+ "ufmt-write",
 ]
 
 [[package]]
-name = "rtic-core"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
-
-[[package]]
-name = "rtic-macros"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8617533990b728e31bc65fcec8fec51fa1b4000fb33189ebeb05fb9d8625444d"
-dependencies = [
- "indexmap",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "rtic-monotonics"
-version = "1.1.0"
+name = "rustc_version"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e9f99e2119d5bdd927c45a31ef9e8d9888f02ede3e357bcbd7ab79c426e02d"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 dependencies = [
- "atomic-polyfill",
- "cfg-if",
- "cortex-m",
- "fugit",
- "rtic-time",
+ "semver",
 ]
 
 [[package]]
-name = "rtic-time"
-version = "1.0.0"
+name = "rustix"
+version = "0.38.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55127cfa37ad32522eca2b70a12298bdb035c75ee3a4e403af8773ffe1a64bd3"
+checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
 dependencies = [
- "critical-section",
- "futures-util",
- "rtic-common",
+ "bitflags 2.4.2",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
 ]
 
 [[package]]
-name = "rtt-target"
-version = "0.3.1"
+name = "rustversion"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
-dependencies = [
- "ufmt-write",
-]
+checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
 
 [[package]]
-name = "rtt-target"
-version = "0.4.0"
+name = "scopeguard"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3afa12c77ba1b9bf560e4039a9b9a08bb9cde0e9e6923955eeb917dd8d5cf303"
-dependencies = [
- "critical-section",
- "ufmt-write",
-]
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
-name = "rustc_version"
-version = "0.2.3"
+name = "sdio-host"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver",
-]
+checksum = "f93c025f9cfe4c388c328ece47d11a54a823da3b5ad0370b22d95ad47137f85a"
 
 [[package]]
 name = "semver"
@@ -760,24 +1422,36 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.188"
+version = "1.0.195"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
+checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.188"
+version = "1.0.195"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
+checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.31",
+ "syn 2.0.48",
 ]
 
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "smallvec"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
+
 [[package]]
 name = "ssmarshal"
 version = "1.0.0"
@@ -795,37 +1469,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
-name = "stm32h7"
-version = "0.15.1"
+name = "static_cell"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa6ba4cf83bf80d3eb25f098ea5e790a0a1fcb5e357442259b231e412c2d3ca0"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "stm32-fmc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830ed60f33e6194ecb377f5d6ab765dc0e37e7b65e765f1fa87df13336658d63"
+dependencies = [
+ "embedded-hal 0.2.7",
+]
+
+[[package]]
+name = "stm32-metapac"
+version = "15.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "362f288cd8341e9209587b889c385f323e82fc237b60c272868965bb879bb9b1"
+checksum = "deabea56a8821dcea05d0109f3ab3135f31eb572444e5da203d06149c594c8c6"
 dependencies = [
- "bare-metal 1.0.0",
  "cortex-m",
  "cortex-m-rt",
- "vcell",
 ]
 
 [[package]]
-name = "stm32h7xx-hal"
-version = "0.15.1"
+name = "string_cache"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08bcfbdbe4458133f2fd55994a5c4f1b4bf28084f0218e93cdbc19d7c70219f"
+checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
 dependencies = [
- "bare-metal 1.0.0",
- "cast",
- "cortex-m",
- "embedded-dma",
- "embedded-hal 0.2.7",
- "embedded-storage",
- "fugit",
- "nb 1.1.0",
- "paste",
- "stm32h7",
- "synopsys-usb-otg",
- "void",
+ "new_debug_unreachable",
+ "once_cell",
+ "parking_lot",
+ "phf_shared",
+ "precomputed-hash",
 ]
 
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
 [[package]]
 name = "syn"
 version = "1.0.109"
@@ -839,9 +1528,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.31"
+version = "2.0.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
+checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -849,43 +1538,66 @@ dependencies = [
 ]
 
 [[package]]
-name = "synopsys-usb-otg"
-version = "0.3.2"
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "term"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678f3707a7b1fd4863023292c42f73c6bab0e9b0096f41ae612d1af0ff221b45"
+checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
 dependencies = [
- "cortex-m",
- "embedded-hal 0.2.7",
- "usb-device",
- "vcell",
+ "dirs-next",
+ "rustversion",
+ "winapi",
 ]
 
 [[package]]
-name = "tap"
-version = "1.0.1"
+name = "termcolor"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
 
 [[package]]
 name = "thiserror"
-version = "1.0.48"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
+checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.48"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
+checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.31",
+ "syn 2.0.48",
+]
+
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
 [[package]]
 name = "ufmt-write"
 version = "0.1.0"
@@ -894,9 +1606,21 @@ checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.11"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
 
 [[package]]
 name = "usb-device"
@@ -959,13 +1683,173 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 
 [[package]]
 name = "volatile-register"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
+checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
 dependencies = [
  "vcell",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[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]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
 [[package]]
 name = "wyz"
 version = "0.5.1"
diff --git a/README.md b/README.md
index 2f57874c..e3274164 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,10 @@
 
 Keyboard firmware for cortex-m, with layer/dynamic keymap/vial support, written in Rust and tested on stm32 and rp2040.
 
+## News
+
+Rmk just released version 0.1.0, migrate to [Embassy](https://github.com/embassy-rs/embassy)! By migrating to Embassy, Rmk now has better async support, supports more MCUs  much easier APIs than before. For examples using Embassy, check [`boards`](https://github.com/HaoboGu/rmk/tree/main/boards) folder!
+
 ## Prerequisites
 
 This crate requires **nightly** Rust. `openocd`(stm32) or `probe-rs`(rp2040) is used for flashing & debugging.
@@ -73,8 +77,15 @@ A lot of todos at the list, any contributions are welcomed :)
 - [x] system/media keys
 - [x] vial support
 - [x] eeprom
-- [ ] support embassy runtime
-- [ ] macro
+- [ ] keyboard macro
 - [ ] encoder
 - [ ] RGB
-- [ ] cli tools
\ No newline at end of file
+- [ ] cli tools
+
+## License
+Rmk is licensed under either of
+
+- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
+- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
+
+at your option.
\ No newline at end of file
diff --git a/boards/rp2040/Cargo.toml b/boards/rp2040/Cargo.toml
index 0bbcb491..532c7403 100644
--- a/boards/rp2040/Cargo.toml
+++ b/boards/rp2040/Cargo.toml
@@ -2,7 +2,7 @@ cargo-features = ["per-package-target"]
 
 [package]
 name = "rmk-rp2040"
-version = "0.0.3"
+version = "0.1.0"
 authors = ["Haobo Gu <haobogu@outlook.com>"]
 description = "Keyboard firmware written in Rust"
 homepage = "https://github.com/haobogu/rmk"
@@ -14,32 +14,45 @@ license = "MIT OR Apache-2.0"
 forced-target = "thumbv6m-none-eabi"
 
 [dependencies]
-rmk = { version = "0.0.6", path = "../../rmk", features = [
+rmk = { version = "0.1.0", path = "../../rmk", features = [
     "eeprom",
     "col2row",
 ] }
+embassy-time = { version = "0.3.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "defmt",
+    "defmt-timestamp-uptime",
+] }
+embassy-rp = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "defmt",
+    "time-driver",
+    "critical-section-impl",
+] }
+embassy-executor = { version = "0.5.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "defmt",
+    "arch-cortex-m",
+    "executor-thread",
+    "integrated-timers",
+] }
+embassy-futures = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy" }
 
-# Use pico as the BSP crate
-rp-pico = "0.8"
-
+cortex-m = { version = "0.7.7", features = ["inline-asm"] }
+cortex-m-rt = "0.7.3"
 defmt = "0.3"
 defmt-rtt = "0.4"
-panic-probe = { version = "0.3", features = ["print-defmt"] }
-
-# Workspace dependencies
-embedded-hal = { version = "0.2.7", features = ["unproven"] }
-cortex-m = "0.7.7"
-cortex-m-rt = "0.7.3"
+embedded-hal = { version = "1.0.0", features = ["defmt-03"] }
+embedded-storage = "0.3"
 log = "0.4.19"
-rtic = { version = "2.0.0", features = ["thumbv6-backend"] }
-rtic-monotonics = { version = "1.0.0", features = ["cortex-m-systick"] }
+panic-probe = { version = "0.3", features = ["print-defmt"] }
+portable-atomic = { version = "1.5", features = ["critical-section"] }
+packed_struct = { version = "0.10.1", default-features = false }
+static_cell = { version = "2" }
 
 [features]
 # avoid having to use --allow-multiple-definition linker flag
 # on macOS with Apple Silicon at least
-default = ["rp-pico/disable-intrinsics"]
+# default = ["rp-pico/disable-intrinsics"]
 
 [[bin]]
 name = "rmk-rp2040"
 test = false
-bench = false
\ No newline at end of file
+bench = false
diff --git a/boards/rp2040/src/keymap.rs b/boards/rp2040/src/keymap.rs
index 2da774aa..40dd1b3f 100644
--- a/boards/rp2040/src/keymap.rs
+++ b/boards/rp2040/src/keymap.rs
@@ -1,9 +1,10 @@
 use rmk::action::KeyAction;
 use rmk::{a, k, layer, mo};
-const COL: usize = 3;
-const ROW: usize = 4;
-const NUM_LAYER: usize = 2;
+pub(crate) const COL: usize = 3;
+pub(crate) const ROW: usize = 4;
+pub(crate) const NUM_LAYER: usize = 2;
 
+#[rustfmt::skip]
 pub static KEYMAP: [[[KeyAction; COL]; ROW]; NUM_LAYER] = [
     layer!([
         [k!(A), k!(B), k!(C)],
diff --git a/boards/rp2040/src/macros.rs b/boards/rp2040/src/macros.rs
new file mode 100644
index 00000000..37938a02
--- /dev/null
+++ b/boards/rp2040/src/macros.rs
@@ -0,0 +1,12 @@
+macro_rules! config_matrix_pins_rp {
+    (peripherals: $p:ident, input: [$($in_pin:ident), *], output: [$($out_pin:ident), +]) => {
+        {
+            let mut output_pins = [$(Output::new(AnyPin::from($p.$out_pin), embassy_rp::gpio::Level::Low)), +];
+            let input_pins = [$(Input::new(AnyPin::from($p.$in_pin), embassy_rp::gpio::Pull::Down)), +];
+            output_pins.iter_mut().for_each(|p| {
+                p.set_low();
+            });
+            (input_pins, output_pins)
+        }
+    };
+}
\ No newline at end of file
diff --git a/boards/rp2040/src/main.rs b/boards/rp2040/src/main.rs
index d89a8b25..20b6a5f2 100644
--- a/boards/rp2040/src/main.rs
+++ b/boards/rp2040/src/main.rs
@@ -1,169 +1,108 @@
-#![no_std]
 #![no_main]
+#![no_std]
 #![feature(type_alias_impl_trait)]
 
+#[macro_use]
 mod keymap;
 
+#[macro_use]
+mod macros;
+
+use core::cell::RefCell;
+use embassy_executor::Spawner;
+use embassy_futures::join::join;
+use embassy_rp::{
+    bind_interrupts,
+    flash::{Blocking, Flash},
+    gpio::{AnyPin, Input, Output},
+    peripherals::{self, USB},
+    usb::{Driver, InterruptHandler},
+};
+use embassy_time::Timer;
+
+use defmt::*;
 use defmt_rtt as _;
 use panic_probe as _;
-
-#[rtic::app(
-    device = rp_pico::hal::pac,
-    dispatchers = [TIMER_IRQ_1]
-)]
-mod app {
-    use defmt::*;
-    use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
-    use rmk::{
-        config::KEYBOARD_CONFIG, eeprom::EepromStorageConfig, flash::EmptyFlashWrapper,
-        initialize_keyboard_and_usb_device, keyboard::Keyboard, usb::KeyboardUsbDevice,
-        usb_device::class_prelude::UsbBusAllocator,
-    };
-    use rp_pico::{
-        hal::{
-            clocks::init_clocks_and_plls, gpio::*, sio, sio::Sio, usb::UsbBus, watchdog::Watchdog,
-        },
-        Pins, XOSC_CRYSTAL_FREQ,
-    };
-    use rtic_monotonics::systick::*;
-
-    // Static usb bus instance
-    static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
-
-    #[shared]
-    struct Shared {
-        usb_device: KeyboardUsbDevice<'static, UsbBus>,
-    }
-
-    #[local]
-    struct Local {
-        led: Pin<bank0::Gpio25, FunctionSio<SioOutput>, PullDown>,
-        keyboard: Keyboard<
-            Pin<DynPinId, FunctionSio<SioInput>, PullDown>,
-            Pin<DynPinId, FunctionSio<SioOutput>, PullDown>,
-            EmptyFlashWrapper,
-            0,
-            4,
-            3,
-            2,
+use rmk::{eeprom::EepromStorageConfig, initialize_keyboard_and_usb_device, keymap::KeyMap};
+use static_cell::StaticCell;
+
+use crate::keymap::{COL, NUM_LAYER, ROW};
+
+bind_interrupts!(struct Irqs {
+    USBCTRL_IRQ => InterruptHandler<USB>;
+});
+
+// static SUSPENDED: AtomicBool = AtomicBool::new(false);
+const FLASH_SECTOR_15_ADDR: u32 = 15 * 8192;
+const EEPROM_SIZE: usize = 128;
+const FLASH_SIZE: usize = 2 * 1024 * 1024;
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+    info!("Rmk start!");
+    // Initialize peripherals
+    let p = embassy_rp::init(Default::default());
+
+    // Create the usb driver, from the HAL
+    let driver = Driver::new(p.USB, Irqs);
+
+    // Pin config
+    let (input_pins, output_pins) = config_matrix_pins_rp!(peripherals: p, input: [PIN_6, PIN_7, PIN_8, PIN_9], output: [PIN_19, PIN_20, PIN_21]);
+
+    // Keymap + eeprom config
+    static MY_KEYMAP: StaticCell<
+        RefCell<
+            KeyMap<
+                Flash<peripherals::FLASH, Blocking, FLASH_SIZE>,
+                EEPROM_SIZE,
+                ROW,
+                COL,
+                NUM_LAYER,
+            >,
         >,
-    }
-
-    #[init]
-    fn init(c: init::Context) -> (Shared, Local) {
-        // Soft-reset does not release the hardware spinlocks
-        // Release them now to avoid a deadlock after debug or watchdog reset
-        unsafe {
-            sio::spinlock_reset();
-        }
-
-        // Initialize the systick interrupt & obtain the token to prove that we did
-        let systick_mono_token = rtic_monotonics::create_systick_token!();
-        // Default rp2040 clock-rate is 125MHz
-        Systick::start(c.core.SYST, 125_000_000, systick_mono_token);
-
-        let mut resets = c.device.RESETS;
-        // Initialize clocks
-        let mut watchdog = Watchdog::new(c.device.WATCHDOG);
-        let clocks = init_clocks_and_plls(
-            XOSC_CRYSTAL_FREQ,
-            c.device.XOSC,
-            c.device.CLOCKS,
-            c.device.PLL_SYS,
-            c.device.PLL_USB,
-            &mut resets,
-            &mut watchdog,
-        )
-        .ok()
-        .unwrap();
-
-        // GPIO config
-        let sio = Sio::new(c.device.SIO);
-        let pins = Pins::new(
-            c.device.IO_BANK0,
-            c.device.PADS_BANK0,
-            sio.gpio_bank0,
-            &mut resets,
-        );
-        let mut led = pins.led.into_push_pull_output();
-        led.set_low().unwrap();
-
-        // Usb config
-        let usb_bus = UsbBusAllocator::new(UsbBus::new(
-            c.device.USBCTRL_REGS,
-            c.device.USBCTRL_DPRAM,
-            clocks.usb_clock,
-            true,
-            &mut resets,
-        ));
-
-        unsafe {
-            USB_BUS = Some(usb_bus);
+    > = StaticCell::new();
+    let eeprom_storage_config = EepromStorageConfig {
+        start_addr: FLASH_SECTOR_15_ADDR,
+        storage_size: 8192, // uses 8KB for eeprom
+        page_size: 32,
+    };
+    // Use internal flash to emulate eeprom
+    // let f = Flash::new_blocking(p.FLASH);
+    let flash = Flash::<_, Blocking, FLASH_SIZE>::new_blocking(p.FLASH);
+    // let mut flash = Flash::new_blocking(p.FLASH);
+    let keymap = MY_KEYMAP.init(RefCell::new(KeyMap::new(
+        crate::keymap::KEYMAP,
+        Some(flash),
+        eeprom_storage_config,
+        None,
+    )));
+
+    // Initialize all utilities: keyboard, usb and keymap
+    let (mut keyboard, mut usb_device, vial) = initialize_keyboard_and_usb_device::<
+        Driver<'_, USB>,
+        Input<'_, AnyPin>,
+        Output<'_, AnyPin>,
+        Flash<peripherals::FLASH, Blocking, FLASH_SIZE>,
+        EEPROM_SIZE,
+        ROW,
+        COL,
+        NUM_LAYER,
+    >(driver, input_pins, output_pins, keymap);
+
+    let usb_fut = usb_device.device.run();
+    let keyboard_fut = async {
+        loop {
+            let _ = keyboard.keyboard_task().await;
+            keyboard.send_report(&mut usb_device.keyboard_hid).await;
+            keyboard.send_media_report(&mut usb_device.other_hid).await;
         }
+    };
 
-        // Matrix config
-        let gp6 = pins.gpio6.into_pull_down_input().into_dyn_pin();
-        let gp7 = pins.gpio7.into_pull_down_input().into_dyn_pin();
-        let gp8 = pins.gpio8.into_pull_down_input().into_dyn_pin();
-        let gp9 = pins.gpio9.into_pull_down_input().into_dyn_pin();
-        let gp19 = pins
-            .gpio19
-            .into_push_pull_output_in_state(PinState::Low)
-            .into_dyn_pin();
-        let gp20 = pins
-            .gpio20
-            .into_push_pull_output_in_state(PinState::Low)
-            .into_dyn_pin();
-        let gp21 = pins
-            .gpio21
-            .into_push_pull_output_in_state(PinState::Low)
-            .into_dyn_pin();
-        let output_pins = [gp19, gp20, gp21];
-        let input_pins = [gp6, gp7, gp8, gp9];
-
-        let (keyboard, usb_device) = initialize_keyboard_and_usb_device(
-            unsafe { USB_BUS.as_ref().unwrap() },
-            &KEYBOARD_CONFIG,
-            None,
-            EepromStorageConfig::default(),
-            None,
-            input_pins,
-            output_pins,
-            crate::keymap::KEYMAP,
-        );
-
-        // Spawn heartbeat task
-        scan::spawn().ok();
-
-        (Shared { usb_device }, Local { led, keyboard })
-    }
-
-    #[task(local = [keyboard, led], priority = 1, shared = [usb_device])]
-    async fn scan(mut cx: scan::Context) {
-        // Keyboard scan task
-        info!("Start matrix scanning");
+    let via_fut = async {
         loop {
-            cx.local.keyboard.keyboard_task().await.unwrap();
-            cx.shared.usb_device.lock(|usb_device| {
-                // Send keyboard report
-                cx.local.keyboard.send_report(usb_device);
-
-                // Process via report
-                cx.local.keyboard.process_via_report(usb_device);
-            });
-
-            // Blink LED
-            let _ = cx.local.led.toggle();
-
-            // Scanning frequency: 10KHZ
-            Systick::delay(100.micros()).await;
+            vial.process_via_report(&mut usb_device.via_hid).await;
+            Timer::after_millis(1).await;
         }
-    }
-
-    #[task(binds = USBCTRL_IRQ, priority = 2, shared = [usb_device])]
-    fn usb_poll(mut cx: usb_poll::Context) {
-        cx.shared.usb_device.lock(|usb_device| {
-            usb_device.usb_poll();
-        });
-    }
+    };
+    join(usb_fut, join(keyboard_fut, via_fut)).await;
 }
diff --git a/boards/stm32h7/.cargo/config.toml b/boards/stm32h7/.cargo/config.toml
index 7381a285..c6eb38be 100644
--- a/boards/stm32h7/.cargo/config.toml
+++ b/boards/stm32h7/.cargo/config.toml
@@ -5,7 +5,7 @@
 [target.'cfg(all(target_arch = "arm", target_os = "none"))']
 # uncomment ONE of these three option to make `cargo run` start a GDB session
 # which option to pick depends on your system
-runner = "arm-none-eabi-gdb -q -x openocd.gdb"
+runner = "probe-rs run --chip STM32H7B0VBTx"
 # runner = "gdb-multiarch -q -x openocd.gdb"
 # runner = "gdb -q -x openocd.gdb"
 
diff --git a/boards/stm32h7/Cargo.toml b/boards/stm32h7/Cargo.toml
index c902264e..c9508ad1 100644
--- a/boards/stm32h7/Cargo.toml
+++ b/boards/stm32h7/Cargo.toml
@@ -2,7 +2,7 @@ cargo-features = ["per-package-target"]
 
 [package]
 name = "rmk-stm32h7"
-version = "0.0.3"
+version = "0.1.0"
 authors = ["Haobo Gu <haobogu@outlook.com>"]
 description = "Keyboard firmware written in Rust"
 homepage = "https://github.com/haobogu/rmk"
@@ -14,26 +14,39 @@ license = "MIT OR Apache-2.0"
 forced-target = "thumbv7em-none-eabihf"
 
 [dependencies]
-rmk = { version = "0.0.6", path = "../../rmk", features = [
+rmk = { version = "0.1.0", path = "../../rmk", features = [
     "eeprom",
     "col2row",
 ] }
-stm32h7xx-hal = { version = "0.15.1", features = [
-    "stm32h7b0",
-    "rt",
-    "log-rtt",
-    "usb_hs",
-] }
-# Workspace dependencies
-cortex-m = "0.7.7"
+cortex-m = { version = "0.7.7", features = ['critical-section-single-core'] }
 cortex-m-rt = "0.7.3"
 panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
-rtt-target = "0.4.0"
+embassy-time = { version = "0.3", git = "https://github.com/embassy-rs/embassy", features = [
+    # "tick-hz-1_000_000",
+    "tick-hz-32_768",
+] }
+embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "stm32h7b0vb",
+    "time-driver-any",
+    "exti",
+    "time",
+] }
+embassy-executor = { version = "0.5.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "arch-cortex-m",
+    "executor-thread",
+    "integrated-timers",
+] }
+embassy-futures = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy" }
+rtt-target = "0.5.0"
 log = "0.4.19"
-rtic = { version = "2.0.1", features = ["thumbv7-backend"] }
-rtic-monotonics = { version = "1.0.0", features = ["cortex-m-systick"] }
 packed_struct = { version = "0.10.1", default-features = false }
 embedded-storage = { version = "0.3" }
+static_cell = { version = "2" }
+
+# defmt deps
+# defmt = "0.3.5"
+# defmt-rtt = "0.4.0"
+# panic-probe = "0.3.1"
 
 [[bin]]
 name = "rmk-stm32h7"
diff --git a/boards/stm32h7/build.rs b/boards/stm32h7/build.rs
index cbcc6944..6177bbbe 100644
--- a/boards/stm32h7/build.rs
+++ b/boards/stm32h7/build.rs
@@ -41,5 +41,8 @@ fn main() {
     // Set the linker script to the one provided by cortex-m-rt.
     println!("cargo:rustc-link-arg=-Tlink.x");
 
+    // Set the extra linker script from defmt
+    // println!("cargo:rustc-link-arg=-Tdefmt.x");
+
     println!("cargo:rustc-linker=flip-link");
 }
diff --git a/boards/stm32h7/src/flash.rs b/boards/stm32h7/src/flash.rs
deleted file mode 100644
index 74e6c2ca..00000000
--- a/boards/stm32h7/src/flash.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
-use stm32h7xx_hal::flash::{Error, LockedFlashBank, UnlockedFlashBank};
-
-/// rmk::Keyboard requires `NorFlash` trait to emulate the eeprom, but `stm32h7xx-hal` doesn't implement `NorFlash` for it's internal flash.
-pub struct FlashWrapper {
-    locked_flash: LockedFlashBank,
-}
-
-impl FlashWrapper {
-    pub fn new(locked: LockedFlashBank) -> Self {
-        Self {
-            locked_flash: locked,
-        }
-    }
-}
-
-impl ErrorType for FlashWrapper {
-    type Error = Error;
-}
-
-impl NorFlash for FlashWrapper {
-    const WRITE_SIZE: usize = UnlockedFlashBank::WRITE_SIZE;
-    const ERASE_SIZE: usize = UnlockedFlashBank::ERASE_SIZE;
-
-    fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
-        let mut unlocked = self.locked_flash.unlocked();
-        unlocked.erase(from, to)
-    }
-
-    fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
-        let mut unlocked = self.locked_flash.unlocked();
-        unlocked.write(offset, bytes)
-    }
-}
-
-impl ReadNorFlash for FlashWrapper {
-    const READ_SIZE: usize = 1;
-    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-        self.locked_flash.read(offset, bytes)
-    }
-
-    fn capacity(&self) -> usize {
-        self.locked_flash.capacity()
-    }
-}
diff --git a/boards/stm32h7/src/macros.rs b/boards/stm32h7/src/macros.rs
index 02fedc0d..7808d3a4 100644
--- a/boards/stm32h7/src/macros.rs
+++ b/boards/stm32h7/src/macros.rs
@@ -1,5 +1,6 @@
-macro_rules! config_matrix_pins {
-    (input: [$($in_port:ident.$in_pin:ident), *], output: [$($out_port: ident.$out_pin: ident), +]) => {
+// DEPRECIATED
+macro_rules! _config_matrix_pins {
+    (input: [$($in_port:ident.$in_pin:ident), *], output: [$($out_port:ident.$out_pin:ident), +]) => {
         {
             $(
                 let $in_pin = $in_port.$in_pin.into_pull_down_input().erase();
@@ -17,3 +18,15 @@ macro_rules! config_matrix_pins {
     };
 }
 
+macro_rules! config_matrix_pins_stm32 {
+    (peripherals: $p:ident, input: [$($in_pin:ident), *], output: [$($out_pin:ident), +]) => {
+        {
+            let mut output_pins = [$(Output::new($p.$out_pin, embassy_stm32::gpio::Level::Low, embassy_stm32::gpio::Speed::VeryHigh).degrade()), +];
+            let input_pins = [$(Input::new($p.$in_pin, embassy_stm32::gpio::Pull::Down).degrade()), +];
+            output_pins.iter_mut().for_each(|p| {
+                p.set_low();
+            });
+            (input_pins, output_pins)
+        }
+    };
+}
diff --git a/boards/stm32h7/src/main.rs b/boards/stm32h7/src/main.rs
index 8aec34a3..83dae497 100644
--- a/boards/stm32h7/src/main.rs
+++ b/boards/stm32h7/src/main.rs
@@ -8,165 +8,136 @@ mod macros;
 mod keymap;
 #[macro_use]
 pub mod rtt_logger;
-mod flash;
 
+use core::{cell::RefCell, sync::atomic::AtomicBool};
+use embassy_executor::Spawner;
+use embassy_futures::join::join;
+use embassy_stm32::{
+    bind_interrupts,
+    flash::{Blocking, Flash},
+    gpio::{AnyPin, Input, Output},
+    peripherals::USB_OTG_HS,
+    time::Hertz,
+    usb_otg::{Driver, InterruptHandler},
+    Config,
+};
+use embassy_time::Timer;
+use log::info;
 use panic_rtt_target as _;
-use rtic::app;
+use rmk::{eeprom::EepromStorageConfig, initialize_keyboard_and_usb_device, keymap::KeyMap};
+use static_cell::StaticCell;
 
-#[app(device = stm32h7xx_hal::pac, peripherals = true)]
-mod app {
-    use crate::{
-        flash::FlashWrapper,
-        keymap::{COL, NUM_LAYER, ROW},
-        rtt_logger,
-    };
-    use log::info;
-    use rmk::eeprom::EepromStorageConfig;
-    use rmk::keyboard::Keyboard;
-    use rmk::usb::KeyboardUsbDevice;
-    use rmk::{config::KEYBOARD_CONFIG, initialize_keyboard_and_usb_device};
-    use rtic_monotonics::systick::*;
-    use stm32h7xx_hal::{
-        gpio::{ErasedPin, Input, Output, PE3},
-        pac::rcc::cdccip2r::USBSEL_A::Hsi48,
-        prelude::*,
-        usb_hs::{UsbBus, USB1},
-    };
+use crate::keymap::{COL, NUM_LAYER, ROW};
 
-    static mut EP_MEMORY: [u32; 1024] = [0; 1024];
-    const FLASH_SECTOR_15_ADDR: u32 = 15 * 8192;
-    const EEPROM_SIZE: usize = 256;
+bind_interrupts!(struct Irqs {
+    OTG_HS => InterruptHandler<USB_OTG_HS>;
+});
 
-    #[shared]
-    struct Shared {
-        usb_device: KeyboardUsbDevice<'static, UsbBus<USB1>>,
-        led: PE3<Output>,
-    }
+static SUSPENDED: AtomicBool = AtomicBool::new(false);
+const FLASH_SECTOR_15_ADDR: u32 = 15 * 8192;
+const EEPROM_SIZE: usize = 128;
 
-    #[local]
-    struct Local {
-        keyboard: Keyboard<
-            ErasedPin<Input>,
-            ErasedPin<Output>,
-            FlashWrapper,
-            EEPROM_SIZE,
-            ROW,
-            COL,
-            NUM_LAYER,
-        >,
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+    if cfg!(debug_assertions) {
+        rtt_logger::init(log::LevelFilter::Info);
     }
-
-    #[init]
-    fn init(cx: init::Context) -> (Shared, Local) {
-        if cfg!(debug_assertions) {
-            rtt_logger::init(log::LevelFilter::Info);
-        }
-
-        let cp = cx.core;
-        let dp = cx.device;
-
-        // Initialize the systick interrupt & obtain the token to prove that we did
-        let systick_mono_token = rtic_monotonics::create_systick_token!();
-        // Default clock rate is 225MHz
-        Systick::start(cp.SYST, 225_000_000, systick_mono_token);
-
-        // Power config
-        let pwr = dp.PWR.constrain();
-        let pwrcfg = pwr.freeze();
-
-        // Clock config
-        let rcc = dp.RCC.constrain();
-        let mut ccdr = rcc
-            .use_hse(25.MHz())
-            .sys_ck(225.MHz())
-            .hclk(225.MHz())
-            .per_ck(225.MHz())
-            .freeze(pwrcfg, &dp.SYSCFG);
-        // Check HSI 48MHZ
-        let _ = ccdr.clocks.hsi48_ck().expect("HSI48 must run");
-        // Config HSI
-        ccdr.peripheral.kernel_usb_clk_mux(Hsi48);
-
-        // GPIO config
-        let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
-        let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
-        let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
-        let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
-
-        // USB config
-        let usb_dm = gpioa.pa11.into_analog();
-        let usb_dp = gpioa.pa12.into_analog();
-        let usb: USB1 = USB1::new(
-            dp.OTG1_HS_GLOBAL,
-            dp.OTG1_HS_DEVICE,
-            dp.OTG1_HS_PWRCLK,
-            usb_dm,
-            usb_dp,
-            ccdr.peripheral.USB1OTG,
-            &ccdr.clocks,
-        );
-        let usb_allocator = cortex_m::singleton!(
-            : rmk::usb_device::class_prelude::UsbBusAllocator<UsbBus<USB1>> =
-                UsbBus::new(usb, unsafe { &mut EP_MEMORY })
-        )
-        .unwrap();
-
-        // Initialize keyboard matrix pins
-        let (input_pins, output_pins) = config_matrix_pins!(input: [gpiod.pd9, gpiod.pd8, gpiob.pb13, gpiob.pb12], output: [gpioe.pe13,gpioe.pe14,gpioe.pe15]);
-
-        // Get flash for eeprom
-        let (flash, _) = dp.FLASH.split();
-        let internal_flash = crate::flash::FlashWrapper::new(flash);
-        let storage_config = EepromStorageConfig {
-            start_addr: FLASH_SECTOR_15_ADDR,
-            storage_size: 8192,
-            page_size: 16,
-        };
-
-        // Initialize keyboard
-        let (keyboard, usb_device) = initialize_keyboard_and_usb_device(
-            usb_allocator,
-            &KEYBOARD_CONFIG,
-            Some(internal_flash),
-            storage_config,
-            None,
-            input_pins,
-            output_pins,
-            crate::keymap::KEYMAP,
-        );
-
-        // Led config
-        let mut led = gpioe.pe3.into_push_pull_output();
-        led.set_high();
-
-        // Spawn keyboard task
-        scan::spawn().ok();
-
-        // RTIC resources
-        (Shared { usb_device, led }, Local { keyboard })
+    info!("Rmk start!");
+    // RCC config
+    let mut config = Config::default();
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi = Some(HSIPrescaler::DIV1);
+        config.rcc.csi = true;
+        // Needed for USB
+        config.rcc.hsi48 = Some(Hsi48Config {
+            sync_from_usb: true,
+        });
+        // External oscillator 25MHZ
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(25_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll1 = Some(Pll {
+            source: PllSource::HSE,
+            prediv: PllPreDiv::DIV5,
+            mul: PllMul::MUL112,
+            divp: Some(PllDiv::DIV2),
+            divq: Some(PllDiv::DIV2),
+            divr: Some(PllDiv::DIV2),
+        });
+        config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.ahb_pre = AHBPrescaler::DIV2;
+        config.rcc.apb1_pre = APBPrescaler::DIV2;
+        config.rcc.apb2_pre = APBPrescaler::DIV2;
+        config.rcc.apb3_pre = APBPrescaler::DIV2;
+        config.rcc.apb4_pre = APBPrescaler::DIV2;
+        config.rcc.voltage_scale = VoltageScale::Scale0;
     }
 
-    #[task(local = [keyboard], shared = [usb_device])]
-    async fn scan(mut cx: scan::Context) {
-        // Keyboard scan task
-        info!("Start matrix scanning");
+    // Initialize peripherals
+    let p = embassy_stm32::init(config);
+
+    // Usb config
+    static EP_OUT_BUFFER: StaticCell<[u8; 1024]> = StaticCell::new();
+    let mut usb_config = embassy_stm32::usb_otg::Config::default();
+    usb_config.vbus_detection = false;
+    let driver = Driver::new_fs(
+        p.USB_OTG_HS,
+        Irqs,
+        p.PA12,
+        p.PA11,
+        &mut EP_OUT_BUFFER.init([0; 1024])[..],
+        usb_config,
+    );
+
+    // Pin config
+    let (input_pins, output_pins) = config_matrix_pins_stm32!(peripherals: p, input: [PD9, PD8, PB13, PB12], output: [PE13, PE14, PE15]);
+
+    // Keymap + eeprom config
+    static MY_KEYMAP: StaticCell<
+        RefCell<KeyMap<Flash<'_, Blocking>, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
+    > = StaticCell::new();
+    let eeprom_storage_config = EepromStorageConfig {
+        start_addr: FLASH_SECTOR_15_ADDR,
+        storage_size: 8192, // uses 8KB for eeprom
+        page_size: 32,
+    };
+    // Use internal flash to emulate eeprom
+    let f = Flash::new_blocking(p.FLASH);
+    let keymap = MY_KEYMAP.init(RefCell::new(KeyMap::new(
+        crate::keymap::KEYMAP,
+        Some(f),
+        eeprom_storage_config,
+        None,
+    )));
+
+    // Initialize all utilities: keyboard, usb and keymap
+    let (mut keyboard, mut usb_device, vial) = initialize_keyboard_and_usb_device::<
+        Driver<'_, USB_OTG_HS>,
+        Input<'_, AnyPin>,
+        Output<'_, AnyPin>,
+        Flash<'_, Blocking>,
+        EEPROM_SIZE,
+        ROW,
+        COL,
+        NUM_LAYER,
+    >(driver, input_pins, output_pins, keymap);
+
+    let usb_fut = usb_device.device.run();
+    let keyboard_fut = async {
         loop {
-            cx.local.keyboard.keyboard_task().await.unwrap();
-            cx.shared.usb_device.lock(|usb_device| {
-                // Send keyboard report
-                cx.local.keyboard.send_report(usb_device);
-                // Process via report
-                cx.local.keyboard.process_via_report(usb_device);
-            });
-            // Scanning frequency: 10KHZ
-            Systick::delay(100.micros()).await;
+            let _ = keyboard.keyboard_task().await;
+            keyboard.send_report(&mut usb_device.keyboard_hid).await;
+            keyboard.send_media_report(&mut usb_device.other_hid).await;
         }
-    }
+    };
 
-    #[task(binds = OTG_HS, shared = [usb_device])]
-    fn usb_poll(mut cx: usb_poll::Context) {
-        cx.shared.usb_device.lock(|usb_device| {
-            usb_device.usb_poll();
-        });
-    }
+    let via_fut = async {
+        loop {
+            vial.process_via_report(&mut usb_device.via_hid).await;
+            Timer::after_millis(1).await;
+        }
+    };
+    join(usb_fut, join(keyboard_fut, via_fut)).await;
 }
diff --git a/rmk/Cargo.toml b/rmk/Cargo.toml
index 6f4efe29..628cb4f6 100644
--- a/rmk/Cargo.toml
+++ b/rmk/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rmk"
-version = "0.0.6"
+version = "0.1.0"
 authors = ["Haobo Gu <haobogu@outlook.com>"]
 description = "Keyboard firmware written in Rust"
 homepage = "https://github.com/haobogu/rmk"
@@ -11,18 +11,21 @@ license = "MIT OR Apache-2.0"
 
 [dependencies]
 embedded-hal = "1.0.0"
-embedded-storage = { version = "0.3" }
-num_enum = { version = "0.7.0", default-features = false }
-log = "0.4.19"
-rtic-monotonics = { version = "1.0.0", features = [
-    "cortex-m-systick",
-    "systick-10khz",
+embedded-storage = "0.3"
+embedded-alloc = "0.5"
+embassy-time = { version = "0.3", git = "https://github.com/embassy-rs/embassy" }
+embassy-usb = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy", features = [
+    "usbd-hid",
+    "max-interface-count-8",
+    "max-handler-count-8",
 ] }
-usb-device = "0.2.9"
+embassy-sync = { version = "0.5.0", git = "https://github.com/embassy-rs/embassy" }
+num_enum = { version = "0.7", default-features = false }
+log = "0.4"
+static_cell = { version = "2" }
 usbd-hid = "0.6.1"
-packed_struct = { version = "0.10.1", default-features = false }
+packed_struct = { version = "0.10", default-features = false }
 byteorder = { version = "1.4", default-features = false }
-embedded-alloc = "0.5.0"
 
 [features]
 default = ["col2row"]
diff --git a/rmk/src/config.rs b/rmk/src/config.rs
deleted file mode 100644
index f8c0ce5a..00000000
--- a/rmk/src/config.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-pub mod usb_config;
-
-use usb_config::UsbHidConfig;
-
-pub struct KeyboardConfig<'a> {
-    pub usb_config: UsbHidConfig<'a>,
-    pub enable_eeprom: bool,
-}
-
-pub static KEYBOARD_CONFIG: KeyboardConfig = KeyboardConfig {
-    usb_config: UsbHidConfig {
-        pid: 0x4643,
-        vid: 0x4C4B,
-        manufacturer: "RMK",
-        product: "RMK product",
-        serial_number: "vial:f64c2b3c:000001",
-    },
-    enable_eeprom: true,
-};
diff --git a/rmk/src/config/usb_config.rs b/rmk/src/config/usb_config.rs
deleted file mode 100644
index a7b493e0..00000000
--- a/rmk/src/config/usb_config.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub struct UsbHidConfig<'a> {
-    pub pid: u16,
-    pub vid: u16,
-    pub manufacturer: &'a str,
-    pub product: &'a str,
-    pub serial_number: &'a str,
-}
diff --git a/rmk/src/debounce.rs b/rmk/src/debounce.rs
index 62219589..ed0ffd8d 100644
--- a/rmk/src/debounce.rs
+++ b/rmk/src/debounce.rs
@@ -1,5 +1,6 @@
+use embassy_time::Instant;
+
 use crate::matrix::KeyState;
-use rtic_monotonics::{systick::Systick, Monotonic};
 
 /// Default DEBOUNCE_THRESHOLD in ms.
 static DEBOUNCE_THRESHOLD: u16 = 10;
@@ -55,7 +56,7 @@ impl<const INPUT_PIN_NUM: usize, const OUTPUT_PIN_NUM: usize>
         key_state: &mut KeyState,
     ) {
         // Record debounce state per ms
-        let cur_tick = Systick::now().ticks();
+        let cur_tick = Instant::now().as_ticks() as u32;
         let elapsed_ms = (cur_tick - self.last_tick) as u16;
 
         if elapsed_ms > 0 {
diff --git a/rmk/src/eeprom.rs b/rmk/src/eeprom.rs
index f7569ac0..5e9dab94 100644
--- a/rmk/src/eeprom.rs
+++ b/rmk/src/eeprom.rs
@@ -234,7 +234,8 @@ impl<F: NorFlash, const EEPROM_SIZE: usize> Eeprom<F, EEPROM_SIZE> {
         let mut buf = vec![0xFF_u8; self.storage_config.page_size as usize];
         buf[..bytes.len()].copy_from_slice(&bytes);
         debug!(
-            "EEPROM write storage at 0x{:X}: {:02X?} ",
+            "EEPROM write storage length {:?} at 0x{:X}: {:X?} ",
+            buf.len(),
             self.storage_config.start_addr + self.pos,
             buf,
         );
@@ -247,7 +248,7 @@ impl<F: NorFlash, const EEPROM_SIZE: usize> Eeprom<F, EEPROM_SIZE> {
             Ok(_) => self.pos += self.storage_config.page_size,
             Err(e) => {
                 error!(
-                    "Failed to write record to storage at {:X}: {:?}",
+                    "Failed to write record to storage at 0x{:X}: {:?}",
                     self.storage_config.start_addr + self.pos,
                     e
                 )
diff --git a/rmk/src/keyboard.rs b/rmk/src/keyboard.rs
index 7714921c..5e6cf0f0 100644
--- a/rmk/src/keyboard.rs
+++ b/rmk/src/keyboard.rs
@@ -1,25 +1,20 @@
 use crate::{
     action::{Action, KeyAction},
-    eeprom::{eeconfig::Eeconfig, Eeprom, EepromStorageConfig},
     keycode::{KeyCode, ModifierCombination},
     keymap::KeyMap,
     matrix::{KeyState, Matrix},
-    usb::KeyboardUsbDevice,
-    via::{descriptor::ViaReport, process::process_via_packet},
+    usb::descriptor::ViaReport,
 };
-use core::convert::Infallible;
-use embedded_alloc::Heap;
+use core::{cell::RefCell, convert::Infallible};
+use embassy_time::Timer;
+use embassy_usb::{class::hid::HidReaderWriter, driver::Driver};
 use embedded_hal::digital::{InputPin, OutputPin};
 use embedded_storage::nor_flash::NorFlash;
-use log::{debug, warn};
-use rtic_monotonics::systick::*;
-use usb_device::class_prelude::UsbBus;
+use log::{debug, error, warn};
 use usbd_hid::descriptor::{KeyboardReport, MediaKeyboardReport, SystemControlReport};
 
-#[global_allocator]
-static HEAP: Heap = Heap::empty();
-
 pub struct Keyboard<
+    'a,
     In: InputPin,
     Out: OutputPin,
     F: NorFlash,
@@ -35,7 +30,7 @@ pub struct Keyboard<
     matrix: Matrix<In, Out, COL, ROW>,
 
     /// Keymap
-    pub keymap: KeyMap<ROW, COL, NUM_LAYER>,
+    pub keymap: &'a RefCell<KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
 
     /// Keyboard internal hid report buf
     report: KeyboardReport,
@@ -43,8 +38,6 @@ pub struct Keyboard<
     /// Media internal report
     media_report: MediaKeyboardReport,
 
-    eeprom: Option<Eeprom<F, EEPROM_SIZE>>,
-
     /// System control internal report
     system_control_report: SystemControlReport,
 
@@ -62,6 +55,7 @@ pub struct Keyboard<
 }
 
 impl<
+        'a,
         In: InputPin<Error = Infallible>,
         Out: OutputPin<Error = Infallible>,
         F: NorFlash,
@@ -69,47 +63,17 @@ impl<
         const ROW: usize,
         const COL: usize,
         const NUM_LAYER: usize,
-    > Keyboard<In, Out, F, EEPROM_SIZE, ROW, COL, NUM_LAYER>
+    > Keyboard<'a, In, Out, F, EEPROM_SIZE, ROW, COL, NUM_LAYER>
 {
     #[cfg(feature = "col2row")]
     pub fn new(
         input_pins: [In; ROW],
         output_pins: [Out; COL],
-        storage: Option<F>,
-        eeprom_storage_config: EepromStorageConfig,
-        eeconfig: Option<Eeconfig>,
-        mut keymap: [[[KeyAction; COL]; ROW]; NUM_LAYER],
+        keymap: &'a RefCell<KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
     ) -> Self {
-        // Initialize the allocator at the very beginning of the initialization of the keyboard
-        {
-            use core::mem::MaybeUninit;
-            // 1KB heap size
-            const HEAP_SIZE: usize = 1024;
-            // Check page_size and heap size
-            assert!((eeprom_storage_config.page_size as usize) < HEAP_SIZE);
-            static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
-            unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
-        }
-
-        let eeprom = match storage {
-            Some(s) => {
-                let e = Eeprom::new(s, eeprom_storage_config, eeconfig, &keymap);
-                // If eeprom is initialized, read keymap from it.
-                match e {
-                    Some(e) => {
-                        e.read_keymap(&mut keymap);
-                        Some(e)
-                    }
-                    None => None,
-                }
-            }
-            None => None,
-        };
-
         Keyboard {
             matrix: Matrix::new(input_pins, output_pins),
-            keymap: KeyMap::new(keymap),
-            eeprom,
+            keymap,
             report: KeyboardReport {
                 modifier: 0,
                 reserved: 0,
@@ -172,35 +136,39 @@ impl<
     }
 
     /// Send hid report. The report is sent only when key state changes.
-    pub fn send_report<B: UsbBus>(&mut self, usb_device: &KeyboardUsbDevice<'_, B>) {
-        // TODO: refine changed, separate hid/media/system
+    pub async fn send_report<'d, D: Driver<'d>>(
+        &mut self,
+        hid_interface: &mut HidReaderWriter<'d, D, 1, 8>,
+    ) {
         if self.need_send_key_report {
-            usb_device.send_keyboard_report(&self.report);
+            // usb_device.send_keyboard_report(&self.report).await;
+            match hid_interface.write_serialize(&self.report).await {
+                Ok(()) => {}
+                Err(e) => error!("Send keyboard report error: {:?}", e),
+            };
             // Reset report key states
             for bit in &mut self.report.keycodes {
                 *bit = 0;
             }
             self.need_send_key_report = false;
         }
+    }
 
+    pub async fn send_media_report<'d, D: Driver<'d>>(
+        &mut self,
+        hid_interface: &mut HidReaderWriter<'d, D, 1, 8>,
+    ) {
         if self.need_send_consumer_control_report {
             debug!("Sending consumer report: {:?}", self.media_report);
-            usb_device.send_consumer_control_report(&self.media_report);
+            match hid_interface.write_serialize(&self.media_report).await {
+                Ok(()) => {}
+                Err(e) => error!("Send media(consumer control) report error: {:?}", e),
+            };
             self.media_report.usage_id = 0;
             self.need_send_consumer_control_report = false;
         }
     }
 
-    /// Read hid report.
-    pub fn process_via_report<B: UsbBus>(&mut self, usb_device: &mut KeyboardUsbDevice<'_, B>) {
-        if usb_device.read_via_report(&mut self.via_report) > 0 {
-            process_via_packet(&mut self.via_report, &mut self.keymap, &mut self.eeprom);
-
-            // Send via report back after processing
-            usb_device.send_via_report(&self.via_report);
-        }
-    }
-
     /// Main keyboard task, it scans matrix, processes active keys
     /// If there is any change of key states, set self.changed=true
     pub async fn keyboard_task(&mut self) -> Result<(), Infallible> {
@@ -229,7 +197,10 @@ impl<
 
         // Process key
         let key_state = self.matrix.get_key_state(row, col);
-        let action = self.keymap.get_action_with_layer_cache(row, col, key_state);
+        let action = self
+            .keymap
+            .borrow_mut()
+            .get_action_with_layer_cache(row, col, key_state);
         match action {
             KeyAction::No | KeyAction::Transparent => (),
             KeyAction::Single(a) => self.process_key_action_normal(a, key_state),
@@ -263,13 +234,13 @@ impl<
                 // Turn off a layer temporarily when the key is pressed
                 // Reactivate the layer after the key is released
                 if key_state.changed && key_state.pressed {
-                    self.keymap.deactivate_layer(layer_num);
+                    self.keymap.borrow_mut().deactivate_layer(layer_num);
                 }
             }
             Action::LayerToggle(layer_num) => {
                 // Toggle a layer when the key is release
                 if key_state.changed && !key_state.pressed {
-                    self.keymap.toggle_layer(layer_num);
+                    self.keymap.borrow_mut().toggle_layer(layer_num);
                 }
             }
             _ => (),
@@ -298,7 +269,7 @@ impl<
 
             // TODO: need to trigger hid send manually, then, release the key to perform a tap operation
             // Wait 10ms, then send release
-            Systick::delay(10.millis()).await;
+            Timer::after_millis(10).await;
 
             key_state.pressed = false;
             self.process_key_action_normal(action, key_state);
@@ -344,9 +315,9 @@ impl<
             return;
         }
         if key_state.pressed {
-            self.keymap.activate_layer(layer_num);
+            self.keymap.borrow_mut().activate_layer(layer_num);
         } else {
-            self.keymap.deactivate_layer(layer_num);
+            self.keymap.borrow_mut().deactivate_layer(layer_num);
         }
     }
 
diff --git a/rmk/src/keymap.rs b/rmk/src/keymap.rs
index 26de2b23..aa29baed 100644
--- a/rmk/src/keymap.rs
+++ b/rmk/src/keymap.rs
@@ -1,6 +1,15 @@
-use crate::{action::KeyAction, matrix::KeyState};
+use crate::{
+    action::KeyAction,
+    eeprom::{eeconfig::Eeconfig, Eeprom, EepromStorageConfig},
+    matrix::KeyState,
+};
+use embedded_alloc::Heap;
+use embedded_storage::nor_flash::NorFlash;
 use log::warn;
 
+#[global_allocator]
+static HEAP: Heap = Heap::empty();
+
 pub struct KeyMapConfig {
     /// Number of rows.
     pub row: usize,
@@ -14,7 +23,13 @@ pub struct KeyMapConfig {
 /// The conception of KeyMap in rmk is borrowed from qmk: <https://docs.qmk.fm/#/keymap>.
 /// Keymap should be bind to the actual pcb matrix definition.
 /// RMK detects hardware key strokes, uses (row,col) to retrieve the action from KeyMap.
-pub struct KeyMap<const ROW: usize, const COL: usize, const NUM_LAYER: usize> {
+pub struct KeyMap<
+    F: NorFlash,
+    const EEPROM_SIZE: usize,
+    const ROW: usize,
+    const COL: usize,
+    const NUM_LAYER: usize,
+> {
     /// Layers
     pub(crate) layers: [[[KeyAction; COL]; ROW]; NUM_LAYER],
     /// Current state of each layer
@@ -23,16 +38,58 @@ pub struct KeyMap<const ROW: usize, const COL: usize, const NUM_LAYER: usize> {
     default_layer: u8,
     /// Layer cache
     layer_cache: [[u8; COL]; ROW],
+    /// Eeprom for storing keymap
+    pub(crate) eeprom: Option<Eeprom<F, EEPROM_SIZE>>,
 }
 
-impl<const ROW: usize, const COL: usize, const NUM_LAYER: usize> KeyMap<ROW, COL, NUM_LAYER> {
+impl<
+        F: NorFlash,
+        const EEPROM_SIZE: usize,
+        const ROW: usize,
+        const COL: usize,
+        const NUM_LAYER: usize,
+    > KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>
+{
     /// Initialize a keymap from a matrix of actions
-    pub fn new(action_map: [[[KeyAction; COL]; ROW]; NUM_LAYER]) -> KeyMap<ROW, COL, NUM_LAYER> {
+    pub fn new(
+        mut action_map: [[[KeyAction; COL]; ROW]; NUM_LAYER],
+        storage: Option<F>,
+        eeprom_storage_config: EepromStorageConfig,
+        eeconfig: Option<Eeconfig>,
+    ) -> KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER> {
+        // Initialize the allocator at the very beginning of the initialization of the keymap
+        {
+            use core::mem::MaybeUninit;
+            // 1KB heap size
+            const HEAP_SIZE: usize = 512;
+            // Check page_size and heap size
+            assert!((eeprom_storage_config.page_size as usize) < HEAP_SIZE);
+            static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
+            unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
+        }
+
+        // Initialize eeprom, if success, re-load keymap from it
+        let eeprom = match storage {
+            Some(s) => {
+                let e = Eeprom::new(s, eeprom_storage_config, eeconfig, &mut action_map);
+                // If eeprom is initialized, read keymap from it.
+                match e {
+                    Some(e) => {
+                        e.read_keymap(&mut action_map);
+                        Some(e)
+                    }
+                    None => None,
+                }
+            }
+            None => None,
+        };
+
         KeyMap {
             layers: action_map,
             layer_state: [false; NUM_LAYER],
             default_layer: 0,
             layer_cache: [[0; COL]; ROW],
+            eeprom,
         }
     }
 
diff --git a/rmk/src/lib.rs b/rmk/src/lib.rs
index 9d6b8f51..df5c3764 100644
--- a/rmk/src/lib.rs
+++ b/rmk/src/lib.rs
@@ -6,21 +6,20 @@
 // Enable std in test
 #![cfg_attr(not(test), no_std)]
 
-use action::KeyAction;
-use config::KeyboardConfig;
-use core::convert::Infallible;
-use eeprom::{eeconfig::Eeconfig, EepromStorageConfig};
+use core::{cell::RefCell, convert::Infallible};
+use embassy_usb::driver::Driver;
 use embedded_hal::digital::{InputPin, OutputPin};
 use embedded_storage::nor_flash::NorFlash;
 use keyboard::Keyboard;
+use keymap::KeyMap;
 use usb::KeyboardUsbDevice;
-use usb_device::class_prelude::{UsbBus, UsbBusAllocator};
 
-pub use usb_device;
+pub use embassy_sync;
+pub use embassy_usb;
 pub use usbd_hid;
+use via::process::VialService;
 
 pub mod action;
-pub mod config;
 pub mod debounce;
 pub mod eeprom;
 pub mod flash;
@@ -34,8 +33,7 @@ pub mod via;
 
 /// Initialize keyboard core and keyboard usb device
 pub fn initialize_keyboard_and_usb_device<
-    'a,
-    B: UsbBus,
+    D: Driver<'static>,
     In: InputPin<Error = Infallible>,
     Out: OutputPin<Error = Infallible>,
     F: NorFlash,
@@ -44,27 +42,18 @@ pub fn initialize_keyboard_and_usb_device<
     const COL: usize,
     const NUM_LAYER: usize,
 >(
-    usb_allocator: &'a UsbBusAllocator<B>,
-    config: &KeyboardConfig<'a>,
-    storage: Option<F>,
-    eeprom_storage_config: EepromStorageConfig,
-    eeconfig: Option<Eeconfig>,
+    driver: D,
     input_pins: [In; ROW],
     output_pins: [Out; COL],
-    keymap: [[[KeyAction; COL]; ROW]; NUM_LAYER],
+    keymap: &'static RefCell<KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
 ) -> (
     Keyboard<In, Out, F, EEPROM_SIZE, ROW, COL, NUM_LAYER>,
-    KeyboardUsbDevice<'a, B>,
+    KeyboardUsbDevice<'static, D>,
+    VialService<'static, F, EEPROM_SIZE, ROW, COL, NUM_LAYER>,
 ) {
     (
-        Keyboard::new(
-            input_pins,
-            output_pins,
-            storage,
-            eeprom_storage_config,
-            eeconfig,
-            keymap,
-        ),
-        KeyboardUsbDevice::new(usb_allocator, config),
+        Keyboard::new(input_pins, output_pins, keymap),
+        KeyboardUsbDevice::new(driver),
+        VialService::new(keymap),
     )
 }
diff --git a/rmk/src/matrix.rs b/rmk/src/matrix.rs
index 9a4d6aa2..f64a268a 100644
--- a/rmk/src/matrix.rs
+++ b/rmk/src/matrix.rs
@@ -1,14 +1,14 @@
 use crate::debounce::Debouncer;
 use core::convert::Infallible;
 use embedded_hal::digital::{InputPin, OutputPin};
-use rtic_monotonics::{systick::*, Monotonic};
+use embassy_time::{Instant, Duration, Timer};
 
 /// KeyState represents the state of a key.
 #[derive(Copy, Clone, Debug)]
 pub struct KeyState {
     pub pressed: bool,
     pub changed: bool,
-    pub hold_start: Option<<Systick as Monotonic>::Instant>,
+    pub hold_start: Option<Instant>,
 }
 
 impl Default for KeyState {
@@ -27,12 +27,12 @@ impl KeyState {
     }
 
     pub fn start_timer(&mut self) {
-        self.hold_start = Some(Systick::now());
+        self.hold_start = Some(Instant::now());
     }
 
-    pub fn elapsed(&self) -> Option<<Systick as Monotonic>::Duration> {
+    pub fn elapsed(&self) -> Option<Duration> {
         match self.hold_start {
-            Some(t) => Systick::now().checked_duration_since(t),
+            Some(t) => Instant::now().checked_duration_since(t),
             None => None,
         }
     }
@@ -87,7 +87,7 @@ impl<
         for (out_idx, out_pin) in self.output_pins.iter_mut().enumerate() {
             // Pull up output pin, wait 1us ensuring the change comes into effect
             out_pin.set_high()?;
-            Systick::delay(1.micros()).await;
+            Timer::after_micros(1).await;
             for (in_idx, in_pin) in self.input_pins.iter_mut().enumerate() {
                 // Check input pins and debounce
                 self.debouncer.debounce(
diff --git a/rmk/src/usb.rs b/rmk/src/usb.rs
index c88fddcd..0450a130 100644
--- a/rmk/src/usb.rs
+++ b/rmk/src/usb.rs
@@ -1,147 +1,193 @@
-use log::error;
-use usb_device::{
-    class_prelude::{UsbBus, UsbBusAllocator},
-    prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
-    UsbError,
-};
-use usbd_hid::{
-    descriptor::{KeyboardReport, MediaKeyboardReport, SerializedDescriptor, SystemControlReport},
-    hid_class::{
-        HIDClass, HidClassSettings, HidCountryCode, HidProtocol, HidSubClass, ProtocolModeConfig,
-    },
+use core::sync::atomic::{AtomicBool, Ordering};
+use embassy_usb::{
+    class::hid::{Config, HidReaderWriter, ReportId, RequestHandler, State},
+    control::OutResponse,
+    driver::Driver,
+    Builder, Handler, UsbDevice,
 };
+use log::info;
+use static_cell::StaticCell;
+use usbd_hid::descriptor::{KeyboardReport, MediaKeyboardReport, SerializedDescriptor};
+
+pub mod descriptor;
 
-use crate::{config::KeyboardConfig, via::descriptor::ViaReport};
+use crate::usb::descriptor::ViaReport;
+
+static SUSPENDED: AtomicBool = AtomicBool::new(false);
 
 // TODO: Use a composite hid device for Keyboard + Mouse + System control + Consumer control
 // In this case, report id should be used.
 // The keyboard usb device should have 3 hid instances:
 // 1. Boot keyboard: 1 endpoint in
-// 2. Composite keyboard: Keyboard + Mouse + System control + Consumer control: 1 endpoint in
-// 3. Raw hid communication: used to communicate with via: 2 endpoints(in/out)
-pub struct KeyboardUsbDevice<'a, B: UsbBus> {
-    /// Usb hid instance
-    hid: HIDClass<'a, B>,
-    /// Consumer control hid instance
-    consumer_control_hid: HIDClass<'a, B>,
-    /// System control hid instance
-    system_control_hid: HIDClass<'a, B>,
-    /// Via communication instance
-    via_hid: HIDClass<'a, B>,
-    /// Usb device instance
-    usb_device: UsbDevice<'a, B>,
+// 2. Other: Mouse + System control + Consumer control: 1 endpoint in
+// 3. Via: used to communicate with via: 2 endpoints(in/out)
+pub struct KeyboardUsbDevice<'d, D: Driver<'d>> {
+    pub device: UsbDevice<'d, D>,
+    pub keyboard_hid: HidReaderWriter<'d, D, 1, 8>,
+    pub other_hid: HidReaderWriter<'d, D, 1, 8>,
+    pub via_hid: HidReaderWriter<'d, D, 32, 32>,
 }
 
-impl<'a, B: UsbBus> KeyboardUsbDevice<'a, B> {
-    pub fn new(usb_allocator: &'a UsbBusAllocator<B>, config: &KeyboardConfig<'a>) -> Self {
-        KeyboardUsbDevice {
-            hid: HIDClass::new_ep_in_with_settings(
-                usb_allocator,
-                KeyboardReport::desc(),
-                10,
-                HidClassSettings {
-                    subclass: HidSubClass::Boot,
-                    protocol: HidProtocol::Keyboard,
-                    config: ProtocolModeConfig::ForceBoot,
-                    locale: HidCountryCode::NotSupported,
-                },
-            ),
-            consumer_control_hid: HIDClass::new_ep_in_with_settings(
-                usb_allocator,
-                MediaKeyboardReport::desc(),
-                10,
-                HidClassSettings {
-                    subclass: HidSubClass::NoSubClass,
-                    protocol: HidProtocol::Keyboard,
-                    config: ProtocolModeConfig::DefaultBehavior,
-                    locale: HidCountryCode::NotSupported,
-                },
-            ),
-            system_control_hid: HIDClass::new_ep_in_with_settings(
-                usb_allocator,
-                SystemControlReport::desc(),
-                10,
-                HidClassSettings {
-                    subclass: HidSubClass::NoSubClass,
-                    protocol: HidProtocol::Keyboard,
-                    config: ProtocolModeConfig::DefaultBehavior,
-                    locale: HidCountryCode::NotSupported,
-                },
-            ),
-            via_hid: HIDClass::new(usb_allocator, ViaReport::desc(), 10),
-            usb_device: UsbDeviceBuilder::new(
-                usb_allocator,
-                UsbVidPid(config.usb_config.vid, config.usb_config.pid),
-            )
-            .manufacturer(config.usb_config.manufacturer)
-            .product(config.usb_config.product)
-            .serial_number(config.usb_config.serial_number)
-            .max_power(500)
-            // .composite_with_iads() // Only used when the usb device is a composite device, like HID + MSC
-            .supports_remote_wakeup(true)
-            .build(),
-        }
+impl<D: Driver<'static>> KeyboardUsbDevice<'static, D> {
+    pub fn new(driver: D) -> Self {
+        // Create embassy-usb Config
+        let mut usb_config = embassy_usb::Config::new(0xc0de, 0xcafe);
+        usb_config.manufacturer = Some("rmk");
+        usb_config.product = Some("demo keyboard");
+        usb_config.serial_number = Some("00000001");
+
+        // Create embassy-usb DeviceBuilder using the driver and config.
+        static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
+        static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
+        static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
+        static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new();
+        static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
+
+        // UsbDevice builder
+        let mut builder = Builder::new(
+            driver,
+            usb_config,
+            &mut DEVICE_DESC.init([0; 256])[..],
+            &mut CONFIG_DESC.init([0; 256])[..],
+            &mut BOS_DESC.init([0; 256])[..],
+            &mut MSOS_DESC.init([0; 128])[..],
+            &mut CONTROL_BUF.init([0; 128])[..],
+        );
+
+        static device_handler: StaticCell<MyDeviceHandler> = StaticCell::new();
+        builder.handler(device_handler.init(MyDeviceHandler::new()));
+
+        // Create classes on the builder.
+        static request_handler: MyRequestHandler = MyRequestHandler {};
+
+        // Initialize two hid interfaces: keyboard & via
+        let keyboard_hid_config = Config {
+            report_descriptor: KeyboardReport::desc(),
+            request_handler: Some(&request_handler),
+            poll_ms: 60,
+            max_packet_size: 64,
+        };
+        static KEYBOARD_HID_STATE: StaticCell<State> = StaticCell::new();
+        let keyboard_hid: HidReaderWriter<'_, D, 1, 8> = HidReaderWriter::new(
+            &mut builder,
+            KEYBOARD_HID_STATE.init(State::new()),
+            keyboard_hid_config,
+        );
+
+        let other_hid_config = Config {
+            report_descriptor: MediaKeyboardReport::desc(),
+            request_handler: Some(&request_handler),
+            poll_ms: 60,
+            max_packet_size: 64,
+        };
+        static OTHER_HID_STATE: StaticCell<State> = StaticCell::new();
+        let other_hid: HidReaderWriter<'_, D, 1, 8> = HidReaderWriter::new(
+            &mut builder,
+            OTHER_HID_STATE.init(State::new()),
+            other_hid_config,
+        );
+
+        let via_config = Config {
+            report_descriptor: ViaReport::desc(),
+            request_handler: Some(&request_handler),
+            poll_ms: 60,
+            max_packet_size: 64,
+        };
+        static VIA_STATE: StaticCell<State> = StaticCell::new();
+        let via_hid: HidReaderWriter<'_, D, 32, 32> =
+            HidReaderWriter::new(&mut builder, VIA_STATE.init(State::new()), via_config);
+
+        // Build usb device
+        let usb = builder.build();
+        return Self {
+            device: usb,
+            keyboard_hid,
+            other_hid,
+            via_hid,
+        };
     }
+}
 
-    /// Usb polling
-    pub fn usb_poll(&mut self) {
-        self.usb_device.poll(&mut [
-            &mut self.hid,
-            &mut self.consumer_control_hid,
-            &mut self.system_control_hid,
-            &mut self.via_hid,
-        ]);
+struct MyRequestHandler {}
+
+impl RequestHandler for MyRequestHandler {
+    fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
+        info!("Get report for {:?}", id);
+        None
     }
 
-    /// Read via report, returns the length of the report, 0 if no report is available.
-    pub fn read_via_report(&mut self, report: &mut ViaReport) -> usize {
-        // Use output_data: host to device data
-        match self.via_hid.pull_raw_output(&mut report.output_data) {
-            Ok(l) => l,
-            Err(UsbError::WouldBlock) => 0,
-            Err(e) => {
-                error!("Read via report error: {:?}", e);
-                0
-            }
-        }
+    fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
+        info!("Set report for {:?}: {:?}", id, data);
+        OutResponse::Accepted
     }
 
-    pub fn send_via_report(&self, report: &ViaReport) -> usize {
-        // Use output_data: host to device data
-        match self.via_hid.push_input(report) {
-            Ok(l) => l,
-            Err(UsbError::WouldBlock) => 0,
-            Err(e) => {
-                error!("Send via report error: {:?}", e);
-                0
-            }
+    fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
+        info!("Set idle rate for {:?} to {:?}", id, dur);
+    }
+
+    fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
+        info!("Get idle rate for {:?}", id);
+        None
+    }
+}
+
+struct MyDeviceHandler {
+    configured: AtomicBool,
+}
+
+impl MyDeviceHandler {
+    fn new() -> Self {
+        MyDeviceHandler {
+            configured: AtomicBool::new(false),
         }
     }
+}
 
-    /// Send keyboard hid report
-    pub fn send_keyboard_report(&self, report: &KeyboardReport) {
-        match self.hid.push_input(report) {
-            Ok(_) => (),
-            Err(UsbError::WouldBlock) => (),
-            Err(e) => error!("Send keyboard report error: {:?}", e),
+impl Handler for MyDeviceHandler {
+    fn enabled(&mut self, enabled: bool) {
+        self.configured.store(false, Ordering::Relaxed);
+        SUSPENDED.store(false, Ordering::Release);
+        if enabled {
+            info!("Device enabled");
+        } else {
+            info!("Device disabled");
         }
     }
 
-    /// Send consumer control report, commonly used in keyboard media control
-    pub fn send_consumer_control_report(&self, report: &MediaKeyboardReport) {
-        match self.consumer_control_hid.push_input(report) {
-            Ok(_) => (),
-            Err(UsbError::WouldBlock) => (),
-            Err(e) => error!("Send consumer control report error: {:?}", e),
+    fn reset(&mut self) {
+        self.configured.store(false, Ordering::Relaxed);
+        info!("Bus reset, the Vbus current limit is 100mA");
+    }
+
+    fn addressed(&mut self, addr: u8) {
+        self.configured.store(false, Ordering::Relaxed);
+        info!("USB address set to: {}", addr);
+    }
+
+    fn configured(&mut self, configured: bool) {
+        self.configured.store(configured, Ordering::Relaxed);
+        if configured {
+            info!(
+                "Device configured, it may now draw up to the configured current limit from Vbus."
+            )
+        } else {
+            info!("Device is no longer configured, the Vbus current limit is 100mA.");
         }
     }
 
-    /// Send system control report
-    pub fn send_system_control_report(&self, report: &SystemControlReport) {
-        match self.system_control_hid.push_input(report) {
-            Ok(_) => (),
-            Err(UsbError::WouldBlock) => (),
-            Err(e) => error!("Send system control report error: {:?}", e),
+    fn suspended(&mut self, suspended: bool) {
+        if suspended {
+            info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
+            SUSPENDED.store(true, Ordering::Release);
+        } else {
+            SUSPENDED.store(false, Ordering::Release);
+            if self.configured.load(Ordering::Relaxed) {
+                info!(
+                    "Device resumed, it may now draw up to the configured current limit from Vbus"
+                );
+            } else {
+                info!("Device resumed, the Vbus current limit is 100mA");
+            }
         }
     }
 }
diff --git a/rmk/src/usb/descriptor.rs b/rmk/src/usb/descriptor.rs
new file mode 100644
index 00000000..0cbe5f77
--- /dev/null
+++ b/rmk/src/usb/descriptor.rs
@@ -0,0 +1,59 @@
+use usbd_hid::descriptor::generator_prelude::*;
+
+#[gen_hid_descriptor(
+    (collection = APPLICATION, usage_page = 0xFF60, usage = 0x61) = {
+        (usage = 0x62, logical_min = 0x0) = {
+            #[item_settings data,variable,absolute] input_data=input;
+        };
+        (usage = 0x63, logical_min = 0x0) = {
+            #[item_settings data,variable,absolute] output_data=output;
+        };
+    }
+)]
+pub struct ViaReport {
+    pub input_data: [u8; 32],
+    pub output_data: [u8; 32],
+}
+
+// TODO: Composite hid report
+// KeyboardReport describes a report and its companion descriptor that can be
+// used to send keyboard button presses to a host and receive the status of the
+// keyboard LEDs.
+// #[gen_hid_descriptor(
+//     (report_id = 0x01, collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = KEYBOARD) = {
+//         (usage_page = KEYBOARD, usage_min = 0xE0, usage_max = 0xE7) = {
+//             #[packed_bits 8] #[item_settings data,variable,absolute] modifier=input;
+//         };
+//         (usage_min = 0x00, usage_max = 0xFF) = {
+//             #[item_settings constant,variable,absolute] reserved=input;
+//         };
+//         (usage_page = LEDS, usage_min = 0x01, usage_max = 0x05) = {
+//             #[packed_bits 5] #[item_settings data,variable,absolute] leds=output;
+//         };
+//         (usage_page = KEYBOARD, usage_min = 0x00, usage_max = 0xDD) = {
+//             #[item_settings data,array,absolute] keycodes=input;
+//         };
+//     },
+//     (report_id = 0x02, collection = APPLICATION, usage_page = CONSUMER, usage = CONSUMER_CONTROL) = {
+//         (usage_page = CONSUMER, usage_min = 0x00, usage_max = 0x514) = {
+//             #[item_settings data,array,absolute,not_null] usage_id=input;
+//         };
+//     },
+//     (report_id = 0x03, collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = SYSTEM_CONTROL) = {
+//         (usage_min = 0x81, usage_max = 0xB7, logical_min = 1) = {
+//             #[item_settings data,array,absolute,not_null] usage_id=input;
+//         };
+//     }
+// )]
+// #[allow(dead_code)]
+// pub struct MyKeyboardReport {
+//     pub modifier: u8,
+//     pub reserved: u8,
+//     pub leds: u8,
+//     pub keycodes: [u8; 6],
+//     pub usage_id: u16,
+// }
+
+// impl AsInputReport for MyKeyboardReport {
+
+// }
\ No newline at end of file
diff --git a/rmk/src/usb_backup.rs b/rmk/src/usb_backup.rs
new file mode 100644
index 00000000..0df16f58
--- /dev/null
+++ b/rmk/src/usb_backup.rs
@@ -0,0 +1,148 @@
+// DEPRECIATED
+// use log::error;
+// use usb_device::{
+//     class_prelude::{UsbBus, UsbBusAllocator},
+//     prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
+//     UsbError,
+// };
+// use usbd_hid::{
+//     descriptor::{KeyboardReport, MediaKeyboardReport, SerializedDescriptor, SystemControlReport},
+//     hid_class::{
+//         HIDClass, HidClassSettings, HidCountryCode, HidProtocol, HidSubClass, ProtocolModeConfig,
+//     },
+// };
+
+// use crate::{config::KeyboardConfig, via::descriptor::ViaReport};
+
+// // TODO: Use a composite hid device for Keyboard + Mouse + System control + Consumer control
+// // In this case, report id should be used.
+// // The keyboard usb device should have 3 hid instances:
+// // 1. Boot keyboard: 1 endpoint in
+// // 2. Composite keyboard: Keyboard + Mouse + System control + Consumer control: 1 endpoint in
+// // 3. Raw hid communication: used to communicate with via: 2 endpoints(in/out)
+// pub struct KeyboardUsbDevice<'a, B: UsbBus> {
+//     /// Usb hid instance
+//     hid: HIDClass<'a, B>,
+//     /// Consumer control hid instance
+//     consumer_control_hid: HIDClass<'a, B>,
+//     /// System control hid instance
+//     system_control_hid: HIDClass<'a, B>,
+//     /// Via communication instance
+//     via_hid: HIDClass<'a, B>,
+//     /// Usb device instance
+//     usb_device: UsbDevice<'a, B>,
+// }
+
+// impl<'a, B: UsbBus> KeyboardUsbDevice<'a, B> {
+//     pub fn new(usb_allocator: &'a UsbBusAllocator<B>, config: &KeyboardConfig<'a>) -> Self {
+//         KeyboardUsbDevice {
+//             hid: HIDClass::new_ep_in_with_settings(
+//                 usb_allocator,
+//                 KeyboardReport::desc(),
+//                 10,
+//                 HidClassSettings {
+//                     subclass: HidSubClass::Boot,
+//                     protocol: HidProtocol::Keyboard,
+//                     config: ProtocolModeConfig::ForceBoot,
+//                     locale: HidCountryCode::NotSupported,
+//                 },
+//             ),
+//             consumer_control_hid: HIDClass::new_ep_in_with_settings(
+//                 usb_allocator,
+//                 MediaKeyboardReport::desc(),
+//                 10,
+//                 HidClassSettings {
+//                     subclass: HidSubClass::NoSubClass,
+//                     protocol: HidProtocol::Keyboard,
+//                     config: ProtocolModeConfig::DefaultBehavior,
+//                     locale: HidCountryCode::NotSupported,
+//                 },
+//             ),
+//             system_control_hid: HIDClass::new_ep_in_with_settings(
+//                 usb_allocator,
+//                 SystemControlReport::desc(),
+//                 10,
+//                 HidClassSettings {
+//                     subclass: HidSubClass::NoSubClass,
+//                     protocol: HidProtocol::Keyboard,
+//                     config: ProtocolModeConfig::DefaultBehavior,
+//                     locale: HidCountryCode::NotSupported,
+//                 },
+//             ),
+//             via_hid: HIDClass::new(usb_allocator, ViaReport::desc(), 10),
+//             usb_device: UsbDeviceBuilder::new(
+//                 usb_allocator,
+//                 UsbVidPid(config.usb_config.vid, config.usb_config.pid),
+//             )
+//             .manufacturer(config.usb_config.manufacturer)
+//             .product(config.usb_config.product)
+//             .serial_number(config.usb_config.serial_number)
+//             .max_power(500)
+//             // .composite_with_iads() // Only used when the usb device is a composite device, like HID + MSC
+//             .supports_remote_wakeup(true)
+//             .build(),
+//         }
+//     }
+
+//     /// Usb polling
+//     pub fn usb_poll(&mut self) {
+//         self.usb_device.poll(&mut [
+//             &mut self.hid,
+//             &mut self.consumer_control_hid,
+//             &mut self.system_control_hid,
+//             &mut self.via_hid,
+//         ]);
+//     }
+
+//     /// Read via report, returns the length of the report, 0 if no report is available.
+//     pub fn read_via_report(&mut self, report: &mut ViaReport) -> usize {
+//         // Use output_data: host to device data
+//         match self.via_hid.pull_raw_output(&mut report.output_data) {
+//             Ok(l) => l,
+//             Err(UsbError::WouldBlock) => 0,
+//             Err(e) => {
+//                 error!("Read via report error: {:?}", e);
+//                 0
+//             }
+//         }
+//     }
+
+//     pub fn send_via_report(&self, report: &ViaReport) -> usize {
+//         // Use output_data: host to device data
+//         match self.via_hid.push_input(report) {
+//             Ok(l) => l,
+//             Err(UsbError::WouldBlock) => 0,
+//             Err(e) => {
+//                 error!("Send via report error: {:?}", e);
+//                 0
+//             }
+//         }
+//     }
+
+//     /// Send keyboard hid report
+//     pub fn send_keyboard_report(&self, report: &KeyboardReport) {
+//         match self.hid.push_input(report) {
+//             Ok(_) => (),
+//             Err(UsbError::WouldBlock) => (),
+//             Err(e) => error!("Send keyboard report error: {:?}", e),
+//         }
+//     }
+
+//     /// Send consumer control report, commonly used in keyboard media control
+//     pub fn send_consumer_control_report(&self, report: &MediaKeyboardReport) {
+//         match self.consumer_control_hid.push_input(report) {
+//             Ok(_) => (),
+//             Err(UsbError::WouldBlock) => (),
+//             Err(e) => error!("Send consumer control report error: {:?}", e),
+//         }
+//     }
+
+//     /// Send system control report
+//     pub fn send_system_control_report(&self, report: &SystemControlReport) {
+//         match self.system_control_hid.push_input(report) {
+//             Ok(_) => (),
+//             Err(UsbError::WouldBlock) => (),
+//             Err(e) => error!("Send system control report error: {:?}", e),
+//         }
+//     }
+// }
diff --git a/rmk/src/via.rs b/rmk/src/via.rs
index 03d0960e..f2b4e4f8 100644
--- a/rmk/src/via.rs
+++ b/rmk/src/via.rs
@@ -1,7 +1,4 @@
-use log::error;
-
-pub(crate) mod descriptor;
 pub(crate) mod keycode_convert;
-pub(crate) mod process;
+pub mod process;
 mod protocol;
 mod vial;
\ No newline at end of file
diff --git a/rmk/src/via/descriptor.rs b/rmk/src/via/descriptor.rs
deleted file mode 100644
index 865b7650..00000000
--- a/rmk/src/via/descriptor.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use usbd_hid::descriptor::generator_prelude::*;
-
-#[gen_hid_descriptor(
-    (collection = APPLICATION, usage_page = 0xFF60, usage = 0x61) = {
-        (usage = 0x62, logical_min = 0x0) = {
-            #[item_settings data,variable,absolute] input_data=input;
-        };
-        (usage = 0x63, logical_min = 0x0) = {
-            #[item_settings data,variable,absolute] output_data=output;
-        };
-    }
-)]
-pub struct ViaReport {
-    pub input_data: [u8; 32],
-    pub output_data: [u8; 32],
-}
diff --git a/rmk/src/via/process.rs b/rmk/src/via/process.rs
index 17b561d4..e4ec3cb7 100644
--- a/rmk/src/via/process.rs
+++ b/rmk/src/via/process.rs
@@ -1,14 +1,76 @@
-use super::{descriptor::*, protocol::*, *};
+use core::cell::RefCell;
+
+use super::{protocol::*, vial::process_vial};
 use crate::{
-    eeprom::Eeprom,
     keymap::KeyMap,
+    usb::descriptor::ViaReport,
     via::keycode_convert::{from_via_keycode, to_via_keycode},
 };
 use byteorder::{BigEndian, ByteOrder, LittleEndian};
+use embassy_time::Instant;
+use embassy_usb::{
+    class::hid::{HidReaderWriter, ReadError},
+    driver::Driver,
+};
 use embedded_storage::nor_flash::NorFlash;
-use log::{debug, info, warn};
+use log::{debug, error, info, warn};
 use num_enum::{FromPrimitive, TryFromPrimitive};
-use rtic_monotonics::{systick::Systick, Monotonic};
+
+pub struct VialService<
+    'a,
+    F: NorFlash,
+    const EEPROM_SIZE: usize,
+    const ROW: usize,
+    const COL: usize,
+    const NUM_LAYER: usize,
+> {
+    // VialService holds a reference of keymap, for updating
+    pub keymap: &'a RefCell<KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
+}
+
+impl<
+        'a,
+        F: NorFlash,
+        const EEPROM_SIZE: usize,
+        const ROW: usize,
+        const COL: usize,
+        const NUM_LAYER: usize,
+    > VialService<'a, F, EEPROM_SIZE, ROW, COL, NUM_LAYER>
+{
+    pub fn new(keymap: &'a RefCell<KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>>) -> Self {
+        Self { keymap }
+    }
+
+    pub async fn process_via_report<D: Driver<'a>>(
+        &self,
+        hid_interface: &mut HidReaderWriter<'a, D, 32, 32>,
+    ) {
+        let mut via_report = ViaReport {
+            input_data: [0; 32],
+            output_data: [0; 32],
+        };
+        match hid_interface.read(&mut via_report.output_data).await {
+            Ok(_) => {
+                {
+                    process_via_packet(&mut via_report, &mut self.keymap.borrow_mut());
+                }
+
+                // Send via report back after processing
+                match hid_interface.write_serialize(&mut via_report).await {
+                    Ok(_) => {}
+                    Err(e) => {
+                        error!("Send via report error: {:?}", e);
+                    }
+                }
+            }
+            Err(e) => {
+                if e != ReadError::Disabled {
+                    error!("Read via report error: {:?}", e);
+                }
+            }
+        }
+    }
+}
 
 pub fn process_via_packet<
     F: NorFlash,
@@ -18,8 +80,7 @@ pub fn process_via_packet<
     const NUM_LAYER: usize,
 >(
     report: &mut ViaReport,
-    keymap: &mut KeyMap<ROW, COL, NUM_LAYER>,
-    eeprom: &mut Option<Eeprom<F, EEPROM_SIZE>>,
+    keymap: &mut KeyMap<F, EEPROM_SIZE, ROW, COL, NUM_LAYER>,
 ) {
     let command_id = report.output_data[0];
 
@@ -36,7 +97,7 @@ pub fn process_via_packet<
             match ViaKeyboardInfo::try_from_primitive(report.output_data[1]) {
                 Ok(v) => match v {
                     ViaKeyboardInfo::Uptime => {
-                        let value = Systick::now().ticks();
+                        let value = Instant::now().as_ticks() as u32;
                         BigEndian::write_u32(&mut report.input_data[2..6], value);
                     }
                     ViaKeyboardInfo::LayoutOptions => {
@@ -60,7 +121,7 @@ pub fn process_via_packet<
                 Ok(v) => match v {
                     ViaKeyboardInfo::LayoutOptions => {
                         let layout_option = BigEndian::read_u32(&report.output_data[2..6]);
-                        match eeprom {
+                        match &mut keymap.eeprom {
                             Some(e) => e.set_layout_option(layout_option),
                             None => (),
                         }
@@ -97,7 +158,7 @@ pub fn process_via_packet<
                 keycode, row, col, layer, action
             );
             keymap.set_action_at(row, col, layer, action.clone());
-            match eeprom {
+            match &mut keymap.eeprom {
                 Some(e) => e.set_keymap_action(row, col, layer, action),
                 None => (),
             }
@@ -198,7 +259,7 @@ pub fn process_via_packet<
                         "Setting keymap buffer of offset: {}, row,col,layer: {},{},{}",
                         offset, row, col, layer
                     );
-                    match eeprom {
+                    match &mut keymap.eeprom {
                         Some(e) => e.set_keymap_action(row, col, layer, action),
                         None => (),
                     }
@@ -210,7 +271,7 @@ pub fn process_via_packet<
         ViaCommand::DynamicKeymapSetEncoder => {
             warn!("Keymap get encoder -- not supported");
         }
-        ViaCommand::Vial => vial::process_vial(report),
+        ViaCommand::Vial => process_vial(report),
         ViaCommand::Unhandled => report.input_data[0] = ViaCommand::Unhandled as u8,
     }
 }
diff --git a/rmk/src/via/vial.rs b/rmk/src/via/vial.rs
index 91df6b79..eb380440 100644
--- a/rmk/src/via/vial.rs
+++ b/rmk/src/via/vial.rs
@@ -2,7 +2,7 @@ use byteorder::{ByteOrder, LittleEndian};
 use log::debug;
 use num_enum::FromPrimitive;
 
-use super::descriptor::ViaReport;
+use crate::usb::descriptor::ViaReport;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
 #[repr(u8)]


Test patch: