Repository: OpenDevicePartnership/embassy-imxrt
Pull request #421: Add support for using the OS Timer0 as time source
Author: login: felipebalbi
Labels: name: bug
description: Something isn't working
name: enhancement
description: New feature or request
name: BREAKING CHANGE
description: PR causes a breaking change
name: cargo vet
description: PR requiring auditor review
Created: 2025-05-07T19:51:20Z | Merged: 2025-05-09T17:05:56Z

This PR lets the user choose between RTC and OS Timer0 as a time source.


Diff:
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 4a8a0444..3ecb5ee6 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -115,8 +115,8 @@ jobs:
 
       - name: cargo doc
         run: |
-          cargo doc --no-deps -F mimxrt685s,rt,defmt,time,time-driver,unstable-pac --locked
-          cargo doc --no-deps -F mimxrt633s,rt,defmt,time,time-driver,unstable-pac --locked
+          cargo doc --no-deps -F mimxrt685s,rt,defmt,time,time-driver-os-timer,unstable-pac --locked
+          cargo doc --no-deps -F mimxrt633s,rt,defmt,time,time-driver-os-timer,unstable-pac --locked
         env:
           RUSTDOCFLAGS: --cfg docsrs
 
@@ -130,51 +130,51 @@ jobs:
       fail-fast: false
       matrix:
         feature: [ "mimxrt633s", "mimxrt633s,rt", "mimxrt633s,defmt",
-          "mimxrt633s,time", "mimxrt633s,time-driver",
+          "mimxrt633s,time", "mimxrt633s,time-driver-os-timer",
           "mimxrt633s,unstable-pac", "mimxrt633s,rt,defmt",
-          "mimxrt633s,rt,time", "mimxrt633s,rt,time-driver",
+          "mimxrt633s,rt,time", "mimxrt633s,rt,time-driver-os-timer",
           "mimxrt633s,rt,unstable-pac", "mimxrt633s,defmt,time",
-          "mimxrt633s,defmt,time-driver", "mimxrt633s,defmt,unstable-pac",
-          "mimxrt633s,time,time-driver", "mimxrt633s,time,unstable-pac",
-          "mimxrt633s,time-driver,unstable-pac",
-          "mimxrt633s,rt,defmt,time", "mimxrt633s,rt,defmt,time-driver",
+          "mimxrt633s,defmt,time-driver-os-timer", "mimxrt633s,defmt,unstable-pac",
+          "mimxrt633s,time,time-driver-os-timer", "mimxrt633s,time,unstable-pac",
+          "mimxrt633s,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,rt,defmt,time", "mimxrt633s,rt,defmt,time-driver-os-timer",
           "mimxrt633s,rt,defmt,unstable-pac",
-          "mimxrt633s,rt,time,time-driver",
+          "mimxrt633s,rt,time,time-driver-os-timer",
           "mimxrt633s,rt,time,unstable-pac",
-          "mimxrt633s,rt,time-driver,unstable-pac",
-          "mimxrt633s,defmt,time,time-driver",
+          "mimxrt633s,rt,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,defmt,time,time-driver-os-timer",
           "mimxrt633s,defmt,time,unstable-pac",
-          "mimxrt633s,defmt,time-driver,unstable-pac",
-          "mimxrt633s,time,time-driver,unstable-pac",
-          "mimxrt633s,rt,defmt,time,time-driver",
+          "mimxrt633s,defmt,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,time,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,rt,defmt,time,time-driver-os-timer",
           "mimxrt633s,rt,defmt,time,unstable-pac",
-          "mimxrt633s,rt,defmt,time-driver,unstable-pac",
-          "mimxrt633s,rt,time,time-driver,unstable-pac",
-          "mimxrt633s,defmt,time,time-driver,unstable-pac",
-          "mimxrt633s,rt,defmt,time,time-driver,unstable-pac",
+          "mimxrt633s,rt,defmt,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,rt,time,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,defmt,time,time-driver-os-timer,unstable-pac",
+          "mimxrt633s,rt,defmt,time,time-driver-os-timer,unstable-pac",
           "mimxrt685s", "mimxrt685s,rt", "mimxrt685s,defmt",
-          "mimxrt685s,time", "mimxrt685s,time-driver",
+          "mimxrt685s,time", "mimxrt685s,time-driver-os-timer",
           "mimxrt685s,unstable-pac", "mimxrt685s,rt,defmt",
-          "mimxrt685s,rt,time", "mimxrt685s,rt,time-driver",
+          "mimxrt685s,rt,time", "mimxrt685s,rt,time-driver-os-timer",
           "mimxrt685s,rt,unstable-pac", "mimxrt685s,defmt,time",
-          "mimxrt685s,defmt,time-driver", "mimxrt685s,defmt,unstable-pac",
-          "mimxrt685s,time,time-driver", "mimxrt685s,time,unstable-pac",
-          "mimxrt685s,time-driver,unstable-pac",
-          "mimxrt685s,rt,defmt,time", "mimxrt685s,rt,defmt,time-driver",
+          "mimxrt685s,defmt,time-driver-os-timer", "mimxrt685s,defmt,unstable-pac",
+          "mimxrt685s,time,time-driver-os-timer", "mimxrt685s,time,unstable-pac",
+          "mimxrt685s,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,rt,defmt,time", "mimxrt685s,rt,defmt,time-driver-os-timer",
           "mimxrt685s,rt,defmt,unstable-pac",
-          "mimxrt685s,rt,time,time-driver",
+          "mimxrt685s,rt,time,time-driver-os-timer",
           "mimxrt685s,rt,time,unstable-pac",
-          "mimxrt685s,rt,time-driver,unstable-pac",
-          "mimxrt685s,defmt,time,time-driver",
+          "mimxrt685s,rt,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,defmt,time,time-driver-os-timer",
           "mimxrt685s,defmt,time,unstable-pac",
-          "mimxrt685s,defmt,time-driver,unstable-pac",
-          "mimxrt685s,time,time-driver,unstable-pac",
-          "mimxrt685s,rt,defmt,time,time-driver",
+          "mimxrt685s,defmt,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,time,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,rt,defmt,time,time-driver-os-timer",
           "mimxrt685s,rt,defmt,time,unstable-pac",
-          "mimxrt685s,rt,defmt,time-driver,unstable-pac",
-          "mimxrt685s,rt,time,time-driver,unstable-pac",
-          "mimxrt685s,defmt,time,time-driver,unstable-pac",
-          "mimxrt685s,rt,defmt,time,time-driver,unstable-pac" ]
+          "mimxrt685s,rt,defmt,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,rt,time,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,defmt,time,time-driver-os-timer,unstable-pac",
+          "mimxrt685s,rt,defmt,time,time-driver-os-timer,unstable-pac" ]
 
     steps:
       - uses: actions/checkout@v4
@@ -249,5 +249,5 @@ jobs:
 
       - name: cargo +${{ matrix.msrv }} check
         run: |
-          cargo check -F mimxrt685s,rt,defmt,time,time-driver,unstable-pac --locked
-          cargo check -F mimxrt633s,rt,defmt,time,time-driver,unstable-pac --locked
\ No newline at end of file
+          cargo check -F mimxrt685s,rt,defmt,time,time-driver-os-timer,unstable-pac --locked
+          cargo check -F mimxrt633s,rt,defmt,time,time-driver-os-timer,unstable-pac --locked
diff --git a/Cargo.lock b/Cargo.lock
index 82aea8a9..ecc74ca0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -273,10 +273,27 @@ version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
 
+[[package]]
+name = "embassy-embedded-hal"
+version = "0.3.0"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
+dependencies = [
+ "embassy-futures",
+ "embassy-hal-internal",
+ "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.7.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "critical-section",
  "document-features",
@@ -286,7 +303,7 @@ dependencies = [
 [[package]]
 name = "embassy-executor-macros"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -297,12 +314,12 @@ dependencies = [
 [[package]]
 name = "embassy-futures"
 version = "0.1.1"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 
 [[package]]
 name = "embassy-hal-internal"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cortex-m",
  "critical-section",
@@ -321,6 +338,7 @@ dependencies = [
  "critical-section",
  "defmt 1.0.1",
  "document-features",
+ "embassy-embedded-hal",
  "embassy-executor",
  "embassy-futures",
  "embassy-hal-internal",
@@ -350,7 +368,7 @@ dependencies = [
 [[package]]
 name = "embassy-sync"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -364,7 +382,7 @@ dependencies = [
 [[package]]
 name = "embassy-time"
 version = "0.4.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -379,7 +397,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-driver"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "document-features",
 ]
@@ -387,7 +405,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-queue-utils"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "embassy-executor",
  "heapless 0.8.0",
diff --git a/Cargo.toml b/Cargo.toml
index a12eecba..3b7bb37c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,13 +12,13 @@ documentation = "https://docs.embassy.dev/embassy-imxrt"
 [package.metadata.embassy_docs]
 src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
 src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
-features = ["time", "defmt", "unstable-pac", "time-driver"]
+features = ["time", "defmt", "unstable-pac", "time-driver-os-timer"]
 flavors = [
     { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
 ]
 
 [package.metadata.docs.rs]
-features = ["time", "defmt", "unstable-pac", "time-driver"]
+features = ["time", "defmt", "unstable-pac", "time-driver-os-timer"]
 
 [features]
 default = ["rt", "time"]
@@ -34,14 +34,20 @@ rt = [
 defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"]
 
 ## Enable features requiring `embassy-time`
-time = ["dep:embassy-time"]
+time = ["dep:embassy-time", "embassy-embedded-hal/time"]
 
-## Enable custom embassy time-driver implementation, using 1kHz RTC
-time-driver = [
-    "dep:embassy-time-driver",
-    "embassy-time-driver?/tick-hz-1_000",
-    "dep:embassy-time-queue-utils",
-]
+## Enable custom embassy time-driver implementation, using 32KHz RTC
+time-driver-rtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000"]
+
+## Enable custom embassy time-driver implementation, using 32KHz RTC
+time-driver-os-timer = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"]
+
+_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
+
+## DEPRECATED FEATURE!!! Kept only for the purposes of backwards
+## compatibility. DO NOT use, make sure to choose a time driver
+## explicitly
+time-driver = ["time-driver-rtc"]
 
 ## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
 unstable-pac = []
@@ -67,6 +73,7 @@ embassy-sync = { git = "https://github.com/embassy-rs/embassy" }
 embassy-time-driver = { git = "https://github.com/embassy-rs/embassy", optional = true }
 embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy", optional = true }
 embassy-time = { git = "https://github.com/embassy-rs/embassy", optional = true}
+embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy", default-features = false }
 embassy-futures = { git = "https://github.com/embassy-rs/embassy" }
 embassy-hal-internal = { git = "https://github.com/embassy-rs/embassy", features = [
     "cortex-m",
diff --git a/examples/rt633/Cargo.lock b/examples/rt633/Cargo.lock
index 9ddbf026..10bf9d50 100644
--- a/examples/rt633/Cargo.lock
+++ b/examples/rt633/Cargo.lock
@@ -275,10 +275,27 @@ version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
 
+[[package]]
+name = "embassy-embedded-hal"
+version = "0.3.0"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
+dependencies = [
+ "embassy-futures",
+ "embassy-hal-internal",
+ "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.7.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cortex-m",
  "critical-section",
@@ -290,7 +307,7 @@ dependencies = [
 [[package]]
 name = "embassy-executor-macros"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -301,12 +318,12 @@ dependencies = [
 [[package]]
 name = "embassy-futures"
 version = "0.1.1"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 
 [[package]]
 name = "embassy-hal-internal"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cortex-m",
  "critical-section",
@@ -324,6 +341,7 @@ dependencies = [
  "critical-section",
  "defmt 1.0.1",
  "document-features",
+ "embassy-embedded-hal",
  "embassy-futures",
  "embassy-hal-internal",
  "embassy-sync",
@@ -350,7 +368,7 @@ dependencies = [
 [[package]]
 name = "embassy-sync"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -364,7 +382,7 @@ dependencies = [
 [[package]]
 name = "embassy-time"
 version = "0.4.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -380,7 +398,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-driver"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "document-features",
 ]
@@ -388,7 +406,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-queue-utils"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "embassy-executor",
  "heapless 0.8.0",
diff --git a/examples/rt633/Cargo.toml b/examples/rt633/Cargo.toml
index 41ea8210..b1425668 100644
--- a/examples/rt633/Cargo.toml
+++ b/examples/rt633/Cargo.toml
@@ -18,7 +18,7 @@ defmt-rtt = "0.4.0"
 panic-probe = { version = "0.3.1", features = ["print-defmt"] }
 embassy-imxrt = { version = "0.1.0", path = "../../", features = [
     "defmt",
-    "time-driver",
+    "time-driver-os-timer",
     "time",
     "mimxrt633s",
     "unstable-pac",
diff --git a/examples/rt685s-evk/Cargo.lock b/examples/rt685s-evk/Cargo.lock
index 2b9f2ba1..f3ef5ac6 100644
--- a/examples/rt685s-evk/Cargo.lock
+++ b/examples/rt685s-evk/Cargo.lock
@@ -275,10 +275,27 @@ version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
 
+[[package]]
+name = "embassy-embedded-hal"
+version = "0.3.0"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
+dependencies = [
+ "embassy-futures",
+ "embassy-hal-internal",
+ "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.7.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cortex-m",
  "critical-section",
@@ -290,7 +307,7 @@ dependencies = [
 [[package]]
 name = "embassy-executor-macros"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -301,12 +318,12 @@ dependencies = [
 [[package]]
 name = "embassy-futures"
 version = "0.1.1"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 
 [[package]]
 name = "embassy-hal-internal"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cortex-m",
  "critical-section",
@@ -324,6 +341,7 @@ dependencies = [
  "critical-section",
  "defmt 1.0.1",
  "document-features",
+ "embassy-embedded-hal",
  "embassy-futures",
  "embassy-hal-internal",
  "embassy-sync",
@@ -374,7 +392,7 @@ dependencies = [
 [[package]]
 name = "embassy-sync"
 version = "0.6.2"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -388,7 +406,7 @@ dependencies = [
 [[package]]
 name = "embassy-time"
 version = "0.4.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -404,7 +422,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-driver"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "document-features",
 ]
@@ -412,7 +430,7 @@ dependencies = [
 [[package]]
 name = "embassy-time-queue-utils"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy#61b77624219eac1b5e74bdeeb64f5c38df997a93"
+source = "git+https://github.com/embassy-rs/embassy#6c6ae4f9fca1eaff6cb9f2896de333d9493ea840"
 dependencies = [
  "embassy-executor",
  "heapless 0.8.0",
diff --git a/examples/rt685s-evk/Cargo.toml b/examples/rt685s-evk/Cargo.toml
index b18abd44..6017e657 100644
--- a/examples/rt685s-evk/Cargo.toml
+++ b/examples/rt685s-evk/Cargo.toml
@@ -19,7 +19,7 @@ defmt-rtt = "0.4.0"
 panic-probe = { version = "0.3.1", features = ["print-defmt"] }
 embassy-imxrt = { version = "0.1.0", path = "../../", features = [
     "defmt",
-    "time-driver",
+    "time-driver-os-timer",
     "time",
     "mimxrt685s",
     "unstable-pac",
diff --git a/examples/rt685s-evk/src/bin/rtc-time.rs b/examples/rt685s-evk/src/bin/rtc-time.rs
index 8d04adb9..8b84d00c 100644
--- a/examples/rt685s-evk/src/bin/rtc-time.rs
+++ b/examples/rt685s-evk/src/bin/rtc-time.rs
@@ -5,7 +5,7 @@ extern crate embassy_imxrt_examples;
 
 use defmt::info;
 use embassy_executor::Spawner;
-use embassy_imxrt::time_driver::*;
+use embassy_imxrt::rtc::*;
 use embassy_time::Timer;
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/src/clocks.rs b/src/clocks.rs
index 3db07495..2b22a98e 100644
--- a/src/clocks.rs
+++ b/src/clocks.rs
@@ -503,7 +503,6 @@ impl ConfigurableClock for LposcConfig {
                 }
             }
         } else {
-            error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq);
             Err(ClockError::InvalidFrequency)
         }
     }
@@ -549,7 +548,6 @@ impl ConfigurableClock for FfroConfig {
         Ok(())
     }
     fn get_clock_rate(&self) -> Result<u32, ClockError> {
-        trace!("getting ffro clock rate");
         Ok(self.freq.load(Ordering::Relaxed))
     }
     fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -579,7 +577,6 @@ impl ConfigurableClock for FfroConfig {
                 }
             }
         } else {
-            error!("failed to convert desired clock rate, {:#}, to FFRO Freq", freq);
             Err(ClockError::InvalidFrequency)
         }
     }
@@ -616,7 +613,6 @@ impl ConfigurableClock for SfroConfig {
     fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
         if self.state == State::Enabled {
             if freq == SFRO_FREQ {
-                trace!("Sfro frequency is already set at 16MHz");
                 Ok(())
             } else {
                 Err(ClockError::InvalidFrequency)
@@ -677,7 +673,6 @@ impl MultiSourceClock for MainPllClkConfig {
                 }
                 MainPllClkSrc::SFRO => {
                     if !clock_src_config.is_enabled() {
-                        error!("Can't set SFRO as source for MainPll as it's not enabled");
                         return Err(ClockError::ClockNotEnabled);
                     }
                     // check if desired frequency is a valid multiple of 16m SFRO clock
@@ -703,7 +698,6 @@ impl ConfigurableClock for MainPllClkConfig {
     }
     fn disable(&self) -> Result<(), ClockError> {
         if self.is_enabled() {
-            error!("Attempting to reset the Main Pll Clock, should be resetting its source");
             Err(ClockError::ClockNotSupported)
         } else {
             Err(ClockError::ClockNotEnabled)
@@ -719,7 +713,6 @@ impl ConfigurableClock for MainPllClkConfig {
     }
     fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> {
         if self.is_enabled() {
-            trace!("attempting to set main pll clock rate");
             // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
             let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
             let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
@@ -741,15 +734,12 @@ impl ConfigurableClock for MainPllClkConfig {
                             base_rate = r;
                         }
                         MainPllClkSrc::FFRO => {
-                            trace!("found FFRO as source, wait a bit");
                             delay_loop_clocks(1000, desired_freq);
                             match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() {
                                 true => base_rate = Into::into(FfroFreq::Ffro48m),
                                 false => base_rate = Into::into(FfroFreq::Ffro60m),
                             }
-                            trace!("found ffro rate to be: {:#}", base_rate);
                             if div == 2 {
-                                trace!("dividing FFRO rate by 2");
                                 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
                                 delay_loop_clocks(150, desired_freq);
                                 base_rate /= 2;
@@ -763,10 +753,8 @@ impl ConfigurableClock for MainPllClkConfig {
                         }
                     };
                     base_rate *= u32::from(mult);
-                    trace!("calculated base rate at: {:#}", base_rate);
                     if base_rate != freq {
                         // make sure to power syspll back up before returning the error
-                        error!("invalid frequency found, powering syspll back up before returning error. Check div and mult");
                         // Clear System PLL reset
                         clkctl0.syspll0ctl0().write(|w| w.reset().normal());
                         // Power up SYSPLL
@@ -775,13 +763,11 @@ impl ConfigurableClock for MainPllClkConfig {
                             .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
                         return Err(ClockError::InvalidFrequency);
                     }
-                    trace!("setting default num and denom");
                     // SAFETY: unsafe needed to write the bits for the num and demon fields
                     clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) });
                     clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) });
                     delay_loop_clocks(30, desired_freq);
                     self.mult.store(mult, Ordering::Relaxed);
-                    trace!("setting self.mult as: {:#}", mult);
                     match mult {
                         16 => {
                             clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16());
@@ -803,7 +789,6 @@ impl ConfigurableClock for MainPllClkConfig {
                         }
                         _ => return Err(ClockError::InvalidMult),
                     }
-                    trace!("clear syspll reset");
                     // Clear System PLL reset
                     clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal());
                     // Power up SYSPLL
@@ -819,7 +804,6 @@ impl ConfigurableClock for MainPllClkConfig {
                     clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
                     delay_loop_clocks(15, desired_freq);
 
-                    trace!("setting new PFD0 bits");
                     // gate the output and clear bits.
                     // SAFETY: unsafe needed to write the bits for pfd0
                     clkctl0
@@ -833,7 +817,6 @@ impl ConfigurableClock for MainPllClkConfig {
                         .modify(|_r, w| unsafe { w.pfd0().bits(0x12) }.pfd0_clkgate().not_gated());
                     // wait for ready bit to be set
                     delay_loop_clocks(50, desired_freq);
-                    trace!("waiting for mainpll clock to be ready");
                     while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
                     // clear by writing a 1
                     clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit());
@@ -854,14 +837,11 @@ impl ConfigurableClock for MainPllClkConfig {
 impl MainPllClkConfig {
     /// Calculate the mult value of a desired frequency, return error if invalid
     pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> {
-        trace!("calculating mult for {:#} / {:#}", rate, base_freq);
         const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33];
 
         if rate > base_freq && rate % base_freq == 0 {
             let mult = (rate / base_freq) as u8;
 
-            trace!("verifying that calculated mult {:#} is valid", mult);
-
             if VALIDMULTS.contains(&mult) {
                 Ok(mult)
             } else {
@@ -1111,7 +1091,6 @@ impl ConfigurableClock for MainClkConfig {
         Ok(())
     }
     fn disable(&self) -> Result<(), ClockError> {
-        error!("Attempting to reset the main clock, should NOT happen during runtime");
         Err(ClockError::ClockNotSupported)
     }
     fn get_clock_rate(&self) -> Result<u32, ClockError> {
@@ -1119,7 +1098,6 @@ impl ConfigurableClock for MainClkConfig {
         Ok(rate)
     }
     fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
-        error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate");
         Err(ClockError::ClockNotSupported)
     }
     fn is_enabled(&self) -> bool {
@@ -1133,7 +1111,6 @@ impl ConfigurableClock for ClkInConfig {
         Ok(())
     }
     fn disable(&self) -> Result<(), ClockError> {
-        error!("Attempting to reset a clock input");
         Err(ClockError::ClockNotSupported)
     }
     fn get_clock_rate(&self) -> Result<u32, ClockError> {
@@ -1144,7 +1121,6 @@ impl ConfigurableClock for ClkInConfig {
         }
     }
     fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
-        trace!("Setting value of clk in config, this won't change the clock itself");
         self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed);
         Ok(())
     }
@@ -1187,7 +1163,6 @@ impl ConfigurableClock for RtcClkConfig {
         Ok(())
     }
     fn disable(&self) -> Result<(), ClockError> {
-        error!("Resetting the RTC clock, this should NOT happen during runtime");
         Err(ClockError::ClockNotSupported)
     }
     fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -1198,7 +1173,6 @@ impl ConfigurableClock for RtcClkConfig {
             match r {
                 RtcFreq::Default1Hz => {
                     if rtc.ctrl().read().rtc_en().is_enable() {
-                        trace!("Attempting to enable an already enabled clock, RTC 1Hz");
                     } else {
                         rtc.ctrl().modify(|_r, w| w.rtc_en().enable());
                     }
@@ -1206,7 +1180,6 @@ impl ConfigurableClock for RtcClkConfig {
                 }
                 RtcFreq::HighResolution1khz => {
                     if rtc.ctrl().read().rtc1khz_en().is_enable() {
-                        trace!("Attempting to enable an already enabled clock, RTC 1Hz");
                     } else {
                         rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable());
                     }
@@ -1214,7 +1187,6 @@ impl ConfigurableClock for RtcClkConfig {
                 }
                 RtcFreq::SubSecond32kHz => {
                     if rtc.ctrl().read().rtc_subsec_ena().is_enable() {
-                        trace!("Attempting to enable an already enabled clock, RTC 1Hz");
                     } else {
                         rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable());
                     }
@@ -1244,18 +1216,12 @@ impl ConfigurableClock for RtcClkConfig {
 
 impl SysClkConfig {
     /// Updates the system core clock frequency, SW concept used for systick
-    fn update_sys_core_clock(&self) {
-        trace!(
-            "System core clock has been updated to {:?}, this involves no HW reg writes",
-            self.sysclkfreq.load(Ordering::Relaxed)
-        );
-    }
+    fn update_sys_core_clock(&self) {}
 }
 
 impl ConfigurableClock for SysOscConfig {
     fn enable_and_reset(&self) -> Result<(), ClockError> {
         if self.state == State::Enabled {
-            trace!("SysOsc was already enabled");
             return Ok(());
         }
 
@@ -1496,32 +1462,26 @@ impl ClockOutConfig {
 /// Using the config, enables all desired clocks to desired clock rates
 fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
     if let Err(e) = config.rtc.enable_and_reset() {
-        error!("couldn't Power on OSC for RTC, result: {:?}", e);
         return Err(e);
     }
 
     if let Err(e) = config.lposc.enable_and_reset() {
-        error!("couldn't Power on LPOSC, result: {:?}", e);
         return Err(e);
     }
 
     if let Err(e) = config.ffro.enable_and_reset() {
-        error!("couldn't Power on FFRO, result: {:?}", e);
         return Err(e);
     }
 
     if let Err(e) = config.sfro.enable_and_reset() {
-        error!("couldn't Power on SFRO, result: {:?}", e);
         return Err(e);
     }
 
     if let Err(e) = config.sys_osc.enable_and_reset() {
-        error!("Couldn't enable sys oscillator {:?}", e);
         return Err(e);
     }
 
     if let Err(e) = config.main_pll_clk.enable_and_reset() {
-        error!("Couldn't enable main pll clock {:?}", e);
         return Err(e);
     }
 
@@ -1540,7 +1500,6 @@ fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
     init_syscpuahb_clk();
 
     if let Err(e) = config.main_clk.enable_and_reset() {
-        error!("Couldn't enable main clock {:?}", e);
         return Err(e);
     }
 
@@ -1559,7 +1518,8 @@ pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> {
 
 ///Trait to expose perph clocks
 trait SealedSysconPeripheral {
-    fn enable_and_reset_perph_clock();
+    fn enable_perph_clock();
+    fn reset_perph();
     fn disable_perph_clock();
 }
 
@@ -1572,7 +1532,18 @@ pub trait SysconPeripheral: SealedSysconPeripheral + 'static {}
 ///
 /// Peripheral must not be in use.
 pub fn enable_and_reset<T: SysconPeripheral>() {
-    T::enable_and_reset_perph_clock();
+    T::enable_perph_clock();
+    T::reset_perph();
+}
+
+/// Enables peripheral `T`.
+pub fn enable<T: SysconPeripheral>() {
+    T::enable_perph_clock();
+}
+
+/// Reset peripheral `T`.
+pub fn reset<T: SysconPeripheral>() {
+    T::reset_perph();
 }
 
 /// Disables peripheral `T`.
@@ -1586,15 +1557,21 @@ pub fn disable<T: SysconPeripheral>() {
 macro_rules! impl_perph_clk {
     ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => {
         impl SealedSysconPeripheral for crate::peripherals::$peripheral {
-            fn enable_and_reset_perph_clock() {
+            fn enable_perph_clock() {
                 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
                 let cc1 = unsafe { pac::$clkctl::steal() };
-                let rc1 = unsafe { pac::$rstctl::steal() };
 
                 paste! {
                     // SAFETY: unsafe due to the use of bits()
                     cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
+                }
+            }
+
+            fn reset_perph() {
+                // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
+                let rc1 = unsafe { pac::$rstctl::steal() };
 
+                paste! {
                     // SAFETY: unsafe due to the use of bits()
                     rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
                 }
@@ -1603,12 +1580,8 @@ macro_rules! impl_perph_clk {
             fn disable_perph_clock() {
                 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
                 let cc1 = unsafe { pac::$clkctl::steal() };
-                let rc1 = unsafe { pac::$rstctl::steal() };
 
                 paste! {
-                    // SAFETY: unsafe due to the use of bits()
-                    rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
-
                     // SAFETY: unsafe due to the use of bits()
                     cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
                 }
diff --git a/src/lib.rs b/src/lib.rs
index dcd716e4..2435d3c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -35,8 +35,9 @@ pub mod i2c;
 pub mod iopctl;
 pub mod pwm;
 pub mod rng;
+pub mod rtc;
 /// Time driver for the iMX RT600 series.
-#[cfg(feature = "time-driver")]
+#[cfg(feature = "_time-driver")]
 pub mod time_driver;
 /// NXP Timer Driver for handling timer-related functionalities.
 /// Module provides functionality for
@@ -113,7 +114,7 @@ pub mod config {
         /// Clock configuration.
         pub clocks: ClockConfig,
         /// Time driver interrupt priority. Should be lower priority than softdevice if used.
-        #[cfg(feature = "time-driver")]
+        #[cfg(feature = "_time-driver")]
         pub time_interrupt_priority: crate::interrupt::Priority,
     }
 
@@ -121,7 +122,7 @@ pub mod config {
         fn default() -> Self {
             Self {
                 clocks: ClockConfig::crystal(),
-                #[cfg(feature = "time-driver")]
+                #[cfg(feature = "_time-driver")]
                 time_interrupt_priority: crate::interrupt::Priority::P0,
             }
         }
@@ -132,7 +133,7 @@ pub mod config {
         pub fn new(clocks: ClockConfig) -> Self {
             Self {
                 clocks,
-                #[cfg(feature = "time-driver")]
+                #[cfg(feature = "_time-driver")]
                 time_interrupt_priority: crate::interrupt::Priority::P0,
             }
         }
@@ -154,9 +155,9 @@ pub fn init(config: config::Config) -> Peripherals {
             error!("unable to initialize Clocks for reason: {:?}", e);
             // Panic here?
         }
-        flash::init();
-        #[cfg(feature = "time-driver")]
+        #[cfg(feature = "_time-driver")]
         time_driver::init(config.time_interrupt_priority);
+        flash::init();
         dma::init();
         gpio::init();
         timer::init();
diff --git a/src/rtc.rs b/src/rtc.rs
new file mode 100644
index 00000000..b64bd5ec
--- /dev/null
+++ b/src/rtc.rs
@@ -0,0 +1,282 @@
+//! RTC DateTime driver.
+
+use crate::{pac, peripherals, Peri};
+
+fn rtc() -> &'static pac::rtc::RegisterBlock {
+    unsafe { &*pac::Rtc::ptr() }
+}
+
+/// Represents a date and time.
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+#[derive(PartialEq, Debug)]
+pub struct Datetime {
+    /// The year component of the date.
+    pub year: u16,
+    /// The month component of the date (1-12).
+    pub month: u8,
+    /// The day component of the date (1-31).
+    pub day: u8,
+    /// The hour component of the time (0-23).
+    pub hour: u8,
+    /// The minute component of the time (0-59).
+    pub minute: u8,
+    /// The second component of the time (0-59).
+    pub second: u8,
+}
+
+/// Default implementation for `Datetime`.
+impl Default for Datetime {
+    fn default() -> Self {
+        Datetime {
+            year: 1970,
+            month: 1,
+            day: 1,
+            hour: 0,
+            minute: 0,
+            second: 0,
+        }
+    }
+}
+
+/// Represents a real-time clock datetime.
+pub struct RtcDatetime<'r> {
+    _p: Peri<'r, peripherals::RTC>,
+}
+
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+#[derive(PartialEq, Debug)]
+/// Represents the result of a datetime validation.
+pub enum Error {
+    /// The year is invalid.
+    InvalidYear,
+    /// The month is invalid.
+    InvalidMonth,
+    /// The day is invalid.
+    InvalidDay,
+    /// The hour is invalid.
+    InvalidHour,
+    /// The minute is invalid.
+    InvalidMinute,
+    /// The second is invalid.
+    InvalidSecond,
+    /// RTC is not enabled.
+    RTCNotEnabled,
+}
+
+/// Implementation for `RtcDatetime`.
+impl<'r> RtcDatetime<'r> {
+    /// Create a new `RtcDatetime` instance.
+    pub fn new(rtc: Peri<'r, peripherals::RTC>) -> Self {
+        Self { _p: rtc }
+    }
+    /// check valid datetime.
+    pub fn is_valid_datetime(&self, time: &Datetime) -> Result<(), Error> {
+        // Validate year
+        if time.year < 1970 {
+            return Err(Error::InvalidYear);
+        }
+
+        // Validate month
+        if time.month < 1 || time.month > 12 {
+            return Err(Error::InvalidMonth);
+        }
+
+        // Validate day
+        if time.day < 1 {
+            return Err(Error::InvalidDay);
+        }
+
+        match time.month {
+            1 | 3 | 5 | 7 | 8 | 10 | 12 => {
+                if time.day > 31 {
+                    return Err(Error::InvalidDay);
+                }
+            }
+            4 | 6 | 9 | 11 => {
+                if time.day > 30 {
+                    return Err(Error::InvalidDay);
+                }
+            }
+            2 => {
+                if self.is_leap_year(time.year) {
+                    if time.day > 29 {
+                        return Err(Error::InvalidDay);
+                    }
+                } else if time.day > 28 {
+                    return Err(Error::InvalidDay);
+                }
+            }
+            _ => return Err(Error::InvalidDay),
+        }
+
+        // Validate hour
+        if time.hour > 23 {
+            return Err(Error::InvalidHour);
+        }
+
+        // Validate minute
+        if time.minute > 59 {
+            return Err(Error::InvalidMinute);
+        }
+
+        // Validate second
+        if time.second > 59 {
+            return Err(Error::InvalidSecond);
+        }
+        Ok(())
+    }
+
+    /// Check if a year is a leap year.
+    fn is_leap_year(&self, year: u16) -> bool {
+        (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
+    }
+
+    /// Convert a datetime to seconds since 1970-01-01 00:00:00.
+    pub fn convert_datetime_to_secs(&self, datetime: &Datetime) -> u32 {
+        let mut days: u32 = 0;
+
+        // Calculate days from full years from 1970 to the current year
+        for year in 1970..datetime.year {
+            days += 365;
+            if self.is_leap_year(year) {
+                days += 1;
+            }
+        }
+
+        // Calculate days from January to the current month
+        const DAYS_IN_MONTH: [u32; 12] = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
+        for month in 1..datetime.month {
+            days += DAYS_IN_MONTH[month as usize];
+            if month == 2 && self.is_leap_year(datetime.year) {
+                days += 1;
+            }
+        }
+
+        // Calculate days from the first day of the month to the current day
+        days += datetime.day as u32 - 1;
+
+        // Calculate seconds from the first day of the month to the current day
+        let secs = datetime.second as u32 + datetime.minute as u32 * 60 + datetime.hour as u32 * 3600;
+
+        days * 86400 + secs
+    }
+
+    /// Convert seconds since 1970-01-01 00:00:00 to a datetime.
+    fn convert_secs_to_datetime(&self, secs: u32) -> Datetime {
+        let mut days = secs / 86400;
+        let mut secs = secs % 86400;
+
+        let mut year = 1970;
+        let mut month = 1;
+        let mut day = 1;
+
+        // Calculate year
+        while days >= 365 {
+            if self.is_leap_year(year) {
+                if days >= 366 {
+                    days -= 366;
+                } else {
+                    break;
+                }
+            } else {
+                days -= 365;
+            }
+            year += 1;
+        }
+
+        // Calculate month
+        let days_in_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
+        while days >= days_in_month[month as usize] {
+            if month == 2 && self.is_leap_year(year) {
+                if days >= 29 {
+                    days -= 29;
+                } else {
+                    break;
+                }
+            } else {
+                days -= days_in_month[month as usize];
+            }
+            month += 1;
+        }
+
+        // Calculate day
+        day += days;
+
+        // Calculate hour, minute, and second
+        let hour = secs / 3600;
+        secs %= 3600;
+        let minute = secs / 60;
+        let second = secs % 60;
+
+        Datetime {
+            year,
+            month,
+            day: day as u8,
+            hour: hour as u8,
+            minute: minute as u8,
+            second: second as u8,
+        }
+    }
+
+    /// Set the datetime.
+    pub fn set_datetime(&self, datetime: &Datetime) -> Result<(), Error> {
+        // SAFETY: Clear RTC_EN bit before setting time to handle race condition
+        //         when the count is in middle of a transition
+        //         There is 21 mS inacurracy in the time set
+        //         Todo: https://github.com/OpenDevicePartnership/embassy-imxrt/issues/121
+        self.is_valid_datetime(datetime)?;
+        let secs = self.convert_datetime_to_secs(datetime);
+        _ = self.set_datetime_in_secs(secs);
+        Ok(())
+    }
+
+    ///Set the datetime in seconds
+    pub fn set_datetime_in_secs(&self, secs: u32) {
+        let r = rtc();
+        r.ctrl().modify(|_r, w| w.rtc_en().disable());
+        r.count().write(|w| unsafe { w.bits(secs) });
+        r.ctrl().modify(|_r, w| w.rtc_en().enable());
+    }
+
+    /// Get the datetime.
+    pub fn get_datetime(&self) -> Result<Datetime, Error> {
+        let datetime;
+        let res;
+        match self.get_datetime_as_secs() {
+            Ok(secs) => {
+                datetime = self.convert_secs_to_datetime(secs);
+                match self.is_valid_datetime(&datetime) {
+                    Ok(()) => {
+                        res = Ok(datetime);
+                    }
+                    Err(e) => {
+                        res = Err(e);
+                    }
+                }
+            }
+            Err(e) => {
+                res = Err(e);
+            }
+        }
+        res
+    }
+
+    /// Get the datetime as UTC seconds
+    pub fn get_datetime_as_secs(&self) -> Result<u32, Error> {
+        let r = rtc();
+        let secs;
+        //  If RTC is not enabled return error
+        if r.ctrl().read().rtc_en().bit_is_clear() {
+            return Err(Error::RTCNotEnabled);
+        }
+        loop {
+            let secs1 = r.count().read().bits();
+            let secs2 = r.count().read().bits();
+            if secs1 == secs2 {
+                secs = secs1;
+                break;
+            }
+        }
+        Ok(secs)
+    }
+}
diff --git a/src/time_driver/mod.rs b/src/time_driver/mod.rs
new file mode 100644
index 00000000..cbcb15e6
--- /dev/null
+++ b/src/time_driver/mod.rs
@@ -0,0 +1,28 @@
+//! Time Driver.
+use core::cell::Cell;
+
+#[cfg(feature = "time-driver-rtc")]
+pub mod rtc;
+
+#[cfg(feature = "time-driver-rtc")]
+pub use rtc::*;
+
+#[cfg(feature = "time-driver-os-timer")]
+pub mod ostimer;
+
+#[cfg(feature = "time-driver-os-timer")]
+pub use ostimer::*;
+
+struct AlarmState {
+    timestamp: Cell<u64>,
+}
+
+unsafe impl Send for AlarmState {}
+
+impl AlarmState {
+    const fn new() -> Self {
+        Self {
+            timestamp: Cell::new(u64::MAX),
+        }
+    }
+}
diff --git a/src/time_driver/ostimer.rs b/src/time_driver/ostimer.rs
new file mode 100644
index 00000000..1cfc97bc
--- /dev/null
+++ b/src/time_driver/ostimer.rs
@@ -0,0 +1,155 @@
+//! OS Timer Driver.
+use core::cell::RefCell;
+
+use critical_section::CriticalSection;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::Mutex;
+use embassy_time_driver::Driver;
+use embassy_time_queue_utils::Queue;
+
+use super::AlarmState;
+use crate::clocks::enable;
+use crate::interrupt::InterruptExt;
+use crate::{interrupt, pac};
+
+fn os() -> &'static pac::ostimer0::RegisterBlock {
+    unsafe { &*pac::Ostimer0::ptr() }
+}
+
+/// Convert gray to decimal
+///
+/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
+/// do here is read both 32-bit halves of the register and convert
+/// from gray to regular binary.
+fn gray_to_dec(gray: u64) -> u64 {
+    let mut dec = gray;
+
+    dec ^= dec >> 1;
+    dec ^= dec >> 2;
+    dec ^= dec >> 4;
+    dec ^= dec >> 8;
+    dec ^= dec >> 16;
+    dec ^= dec >> 32;
+
+    dec
+}
+
+/// Convert decimal to gray
+///
+/// Before writing match value to the target register, we must convert
+/// it back into gray code.
+fn dec_to_gray(dec: u64) -> u64 {
+    let gray = dec;
+    gray ^ (gray >> 1)
+}
+
+embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
+    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
+    queue: Mutex::new(RefCell::new(Queue::new())),
+});
+
+struct OsTimer {
+    /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
+    alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
+    queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
+}
+
+impl OsTimer {
+    fn init(&'static self, irq_prio: crate::interrupt::Priority) {
+        interrupt::OS_EVENT.disable();
+
+        // init alarms
+        critical_section::with(|cs| {
+            let alarm = DRIVER.alarms.borrow(cs);
+            alarm.timestamp.set(u64::MAX);
+        });
+
+        // Enable clocks. Documentation advises AGAINST resetting this
+        // peripheral.
+        enable::<crate::peripherals::OS_EVENT>();
+
+        // Make sure interrupt is masked
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+
+        // Default to the end of time
+        os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
+        os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
+
+        interrupt::OS_EVENT.unpend();
+        interrupt::OS_EVENT.set_priority(irq_prio);
+        unsafe { interrupt::OS_EVENT.enable() };
+    }
+
+    fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
+        let alarm = self.alarms.borrow(cs);
+        alarm.timestamp.set(timestamp);
+
+        let t = self.now();
+        if timestamp <= t {
+            os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+            alarm.timestamp.set(u64::MAX);
+            return false;
+        }
+
+        let gray_timestamp = dec_to_gray(timestamp);
+
+        os().match_l()
+            .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) });
+        os().match_h()
+            .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) });
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit());
+
+        true
+    }
+
+    #[cfg(feature = "rt")]
+    fn trigger_alarm(&self, cs: CriticalSection) {
+        let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
+        while !self.set_alarm(cs, next) {
+            next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
+        }
+    }
+
+    #[cfg(feature = "rt")]
+    fn on_interrupt(&self) {
+        critical_section::with(|cs| {
+            if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() {
+                os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+                self.trigger_alarm(cs);
+            }
+        });
+    }
+}
+
+impl Driver for OsTimer {
+    fn now(&self) -> u64 {
+        let mut t = os().evtimerh().read().bits() as u64;
+        t <<= 32;
+        t |= os().evtimerl().read().bits() as u64;
+        gray_to_dec(t)
+    }
+
+    fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
+        critical_section::with(|cs| {
+            let mut queue = self.queue.borrow(cs).borrow_mut();
+
+            if queue.schedule_wake(at, waker) {
+                let mut next = queue.next_expiration(self.now());
+                while !self.set_alarm(cs, next) {
+                    next = queue.next_expiration(self.now());
+                }
+            }
+        })
+    }
+}
+
+#[cfg(feature = "rt")]
+#[allow(non_snake_case)]
+#[interrupt]
+fn OS_EVENT() {
+    DRIVER.on_interrupt()
+}
+
+pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
+    DRIVER.init(irq_prio)
+}
diff --git a/src/time_driver.rs b/src/time_driver/rtc.rs
similarity index 54%
rename from src/time_driver.rs
rename to src/time_driver/rtc.rs
index f18bda67..247bff66 100644
--- a/src/time_driver.rs
+++ b/src/time_driver/rtc.rs
@@ -1,4 +1,5 @@
-use core::cell::{Cell, RefCell};
+//! RTC Driver.
+use core::cell::RefCell;
 use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
 
 use critical_section::CriticalSection;
@@ -7,8 +8,9 @@ use embassy_sync::blocking_mutex::Mutex;
 use embassy_time_driver::Driver;
 use embassy_time_queue_utils::Queue;
 
+use super::AlarmState;
 use crate::interrupt::InterruptExt;
-use crate::{interrupt, pac, peripherals, Peri};
+use crate::{interrupt, pac};
 
 fn rtc() -> &'static pac::rtc::RegisterBlock {
     unsafe { &*pac::Rtc::ptr() }
@@ -24,25 +26,20 @@ fn rtc() -> &'static pac::rtc::RegisterBlock {
 /// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels,
 /// so using a 32 bit GPREG0-2 as counter, compare, and int_en
 /// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection
+#[cfg(feature = "time-driver-rtc")]
 fn calc_now(period: u32, counter: u32) -> u64 {
     ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64)
 }
 
-struct AlarmState {
-    timestamp: Cell<u64>,
-}
-
-unsafe impl Send for AlarmState {}
-
-impl AlarmState {
-    const fn new() -> Self {
-        Self {
-            timestamp: Cell::new(u64::MAX),
-        }
-    }
-}
+#[cfg(feature = "time-driver-rtc")]
+embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc {
+    period: AtomicU32::new(0),
+    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
+    queue: Mutex::new(RefCell::new(Queue::new())),
+});
 
-struct TimerDriver {
+#[cfg(feature = "time-driver-rtc")]
+struct Rtc {
     /// Number of 2^31 periods elapsed since boot.
     period: AtomicU32,
     /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
@@ -50,13 +47,8 @@ struct TimerDriver {
     queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
 }
 
-embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver {
-    period: AtomicU32::new(0),
-    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
-    queue: Mutex::new(RefCell::new(Queue::new())),
-});
-
-impl TimerDriver {
+#[cfg(feature = "time-driver-rtc")]
+impl Rtc {
     /// Access the GPREG0 register to use it as a 31-bit counter.
     #[inline]
     fn counter_reg(&self) -> &pac::rtc::Gpreg {
@@ -218,7 +210,8 @@ impl TimerDriver {
     }
 }
 
-impl Driver for TimerDriver {
+#[cfg(feature = "time-driver-rtc")]
+impl Driver for Rtc {
     fn now(&self) -> u64 {
         // `period` MUST be read before `counter`, see comment at the top for details.
         let period = self.period.load(Ordering::Acquire);
@@ -241,280 +234,7 @@ impl Driver for TimerDriver {
     }
 }
 
-/// Represents a date and time.
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[derive(PartialEq, Debug)]
-pub struct Datetime {
-    /// The year component of the date.
-    pub year: u16,
-    /// The month component of the date (1-12).
-    pub month: u8,
-    /// The day component of the date (1-31).
-    pub day: u8,
-    /// The hour component of the time (0-23).
-    pub hour: u8,
-    /// The minute component of the time (0-59).
-    pub minute: u8,
-    /// The second component of the time (0-59).
-    pub second: u8,
-}
-
-/// Default implementation for `Datetime`.
-impl Default for Datetime {
-    fn default() -> Self {
-        Datetime {
-            year: 1970,
-            month: 1,
-            day: 1,
-            hour: 0,
-            minute: 0,
-            second: 0,
-        }
-    }
-}
-/// Represents a real-time clock datetime.
-pub struct RtcDatetime<'r> {
-    _p: Peri<'r, peripherals::RTC>,
-}
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[derive(PartialEq, Debug)]
-/// Represents the result of a datetime validation.
-pub enum Error {
-    /// The year is invalid.
-    InvalidYear,
-    /// The month is invalid.
-    InvalidMonth,
-    /// The day is invalid.
-    InvalidDay,
-    /// The hour is invalid.
-    InvalidHour,
-    /// The minute is invalid.
-    InvalidMinute,
-    /// The second is invalid.
-    InvalidSecond,
-    /// RTC is not enabled.
-    RTCNotEnabled,
-}
-
-/// Implementation for `RtcDatetime`.
-impl<'r> RtcDatetime<'r> {
-    /// Create a new `RtcDatetime` instance.
-    pub fn new(rtc: Peri<'r, peripherals::RTC>) -> Self {
-        Self { _p: rtc }
-    }
-    /// check valid datetime.
-    pub fn is_valid_datetime(&self, time: &Datetime) -> Result<(), Error> {
-        // Validate year
-        if time.year < 1970 {
-            return Err(Error::InvalidYear);
-        }
-
-        // Validate month
-        if time.month < 1 || time.month > 12 {
-            return Err(Error::InvalidMonth);
-        }
-
-        // Validate day
-        if time.day < 1 {
-            return Err(Error::InvalidDay);
-        }
-
-        match time.month {
-            1 | 3 | 5 | 7 | 8 | 10 | 12 => {
-                if time.day > 31 {
-                    return Err(Error::InvalidDay);
-                }
-            }
-            4 | 6 | 9 | 11 => {
-                if time.day > 30 {
-                    return Err(Error::InvalidDay);
-                }
-            }
-            2 => {
-                if self.is_leap_year(time.year) {
-                    if time.day > 29 {
-                        return Err(Error::InvalidDay);
-                    }
-                } else if time.day > 28 {
-                    return Err(Error::InvalidDay);
-                }
-            }
-            _ => return Err(Error::InvalidDay),
-        }
-
-        // Validate hour
-        if time.hour > 23 {
-            return Err(Error::InvalidHour);
-        }
-
-        // Validate minute
-        if time.minute > 59 {
-            return Err(Error::InvalidMinute);
-        }
-
-        // Validate second
-        if time.second > 59 {
-            return Err(Error::InvalidSecond);
-        }
-        Ok(())
-    }
-
-    /// Check if a year is a leap year.
-    fn is_leap_year(&self, year: u16) -> bool {
-        (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
-    }
-
-    /// Convert a datetime to seconds since 1970-01-01 00:00:00.
-    pub fn convert_datetime_to_secs(&self, datetime: &Datetime) -> u32 {
-        let mut days: u32 = 0;
-
-        // Calculate days from full years from 1970 to the current year
-        for year in 1970..datetime.year {
-            days += 365;
-            if self.is_leap_year(year) {
-                days += 1;
-            }
-        }
-
-        // Calculate days from January to the current month
-        const DAYS_IN_MONTH: [u32; 12] = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
-        for month in 1..datetime.month {
-            days += DAYS_IN_MONTH[month as usize];
-            if month == 2 && self.is_leap_year(datetime.year) {
-                days += 1;
-            }
-        }
-
-        // Calculate days from the first day of the month to the current day
-        days += datetime.day as u32 - 1;
-
-        // Calculate seconds from the first day of the month to the current day
-        let secs = datetime.second as u32 + datetime.minute as u32 * 60 + datetime.hour as u32 * 3600;
-
-        days * 86400 + secs
-    }
-
-    /// Convert seconds since 1970-01-01 00:00:00 to a datetime.
-    fn convert_secs_to_datetime(&self, secs: u32) -> Datetime {
-        let mut days = secs / 86400;
-        let mut secs = secs % 86400;
-
-        let mut year = 1970;
-        let mut month = 1;
-        let mut day = 1;
-
-        // Calculate year
-        while days >= 365 {
-            if self.is_leap_year(year) {
-                if days >= 366 {
-                    days -= 366;
-                } else {
-                    break;
-                }
-            } else {
-                days -= 365;
-            }
-            year += 1;
-        }
-
-        // Calculate month
-        let days_in_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
-        while days >= days_in_month[month as usize] {
-            if month == 2 && self.is_leap_year(year) {
-                if days >= 29 {
-                    days -= 29;
-                } else {
-                    break;
-                }
-            } else {
-                days -= days_in_month[month as usize];
-            }
-            month += 1;
-        }
-
-        // Calculate day
-        day += days;
-
-        // Calculate hour, minute, and second
-        let hour = secs / 3600;
-        secs %= 3600;
-        let minute = secs / 60;
-        let second = secs % 60;
-
-        Datetime {
-            year,
-            month,
-            day: day as u8,
-            hour: hour as u8,
-            minute: minute as u8,
-            second: second as u8,
-        }
-    }
-
-    /// Set the datetime.
-    pub fn set_datetime(&self, datetime: &Datetime) -> Result<(), Error> {
-        // SAFETY: Clear RTC_EN bit before setting time to handle race condition
-        //         when the count is in middle of a transition
-        //         There is 21 mS inacurracy in the time set
-        //         Todo: https://github.com/OpenDevicePartnership/embassy-imxrt/issues/121
-        self.is_valid_datetime(datetime)?;
-        let secs = self.convert_datetime_to_secs(datetime);
-        _ = self.set_datetime_in_secs(secs);
-        Ok(())
-    }
-
-    ///Set the datetime in seconds
-    pub fn set_datetime_in_secs(&self, secs: u32) {
-        let r = rtc();
-        r.ctrl().modify(|_r, w| w.rtc_en().disable());
-        r.count().write(|w| unsafe { w.bits(secs) });
-        r.ctrl().modify(|_r, w| w.rtc_en().enable());
-    }
-
-    /// Get the datetime.
-    pub fn get_datetime(&self) -> Result<Datetime, Error> {
-        let datetime;
-        let res;
-        match self.get_datetime_as_secs() {
-            Ok(secs) => {
-                datetime = self.convert_secs_to_datetime(secs);
-                match self.is_valid_datetime(&datetime) {
-                    Ok(()) => {
-                        res = Ok(datetime);
-                    }
-                    Err(e) => {
-                        res = Err(e);
-                    }
-                }
-            }
-            Err(e) => {
-                res = Err(e);
-            }
-        }
-        res
-    }
-
-    /// Get the datetime as UTC seconds
-    pub fn get_datetime_as_secs(&self) -> Result<u32, Error> {
-        let r = rtc();
-        let secs;
-        //  If RTC is not enabled return error
-        if r.ctrl().read().rtc_en().bit_is_clear() {
-            return Err(Error::RTCNotEnabled);
-        }
-        loop {
-            let secs1 = r.count().read().bits();
-            let secs2 = r.count().read().bits();
-            if secs1 == secs2 {
-                secs = secs1;
-                break;
-            }
-        }
-        Ok(secs)
-    }
-}
-
-#[cfg(feature = "rt")]
+#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
 #[allow(non_snake_case)]
 #[interrupt]
 fn RTC() {


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds support for using OS Timer0 as an alternative time source alongside RTC. Key changes include the introduction of OS Timer driver functionality in src/time_driver.rs, updates to feature flags in Cargo.toml and src/lib.rs, and minor cleanup in related clock configuration files.

### Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

<details>
<summary>Show a summary per file</summary>

| File                                | Description                                                              |
| ----------------------------------- | ------------------------------------------------------------------------ |
| src/time_driver.rs                  | Adds OS Timer driver implementation including gray-code conversion and alarm management |
| src/lib.rs                          | Updates feature flags from "time-driver" to "_time-driver" and "time-driver-os-timer" |
| src/clocks.rs                       | Removes several debug trace logs to reduce verbosity                      |
| examples/rt685s-evk/Cargo.toml        | Updates feature flags to use "time-driver-os-timer"                       |
| examples/rt633/Cargo.toml             | Updates feature flags to use "time-driver-os-timer"                       |
| Cargo.toml                          | Modifies default features to include support for OS Timer driver          |
</details>





state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T19:52:23Z
user: login: RobertZ2011
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T20:30:14Z
user: login: felipebalbi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T21:30:59Z
user: login: RobertZ2011
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T15:21:11Z
user: login: jerrysxie
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T02:22:55Z
user: login: felipebalbi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T03:08:47Z
user: login: jerrysxie
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T16:14:44Z
user: login: madeleyneVaca
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T17:05:54Z

Review comments:
diff_hunk: @@ -518,13 +531,158 @@ impl<'r> RtcDatetime<'r> {
     }
 }
 
-#[cfg(feature = "rt")]
+#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
 #[allow(non_snake_case)]
 #[interrupt]
 fn RTC() {
     DRIVER.on_interrupt()
 }
 
+#[cfg(feature = "time-driver-os-timer")]
+fn os() -> &'static pac::ostimer0::RegisterBlock {
+    unsafe { &*pac::Ostimer0::ptr() }
+}
+
+/// Convert gray to decimal
+///
+/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
+/// do here is read both 32-bit halves of the register and convert
+/// from gray to regular binary.
+#[cfg(feature = "time-driver-os-timer")]
path: src/time_driver.rs
user: login: Copilot
body: [nitpick] Consider marking both gray_to_dec and dec_to_gray functions with #[inline] to improve performance, as they may be called frequently in time-critical paths.
```suggestion
#[cfg(feature = "time-driver-os-timer")]
#[inline]
```
created_at: 2025-05-07T19:52:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -518,13 +531,158 @@ impl<'r> RtcDatetime<'r> {
     }
 }
 
-#[cfg(feature = "rt")]
+#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
 #[allow(non_snake_case)]
 #[interrupt]
 fn RTC() {
     DRIVER.on_interrupt()
 }
 
+#[cfg(feature = "time-driver-os-timer")]
+fn os() -> &'static pac::ostimer0::RegisterBlock {
+    unsafe { &*pac::Ostimer0::ptr() }
+}
+
+/// Convert gray to decimal
+///
+/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
+/// do here is read both 32-bit halves of the register and convert
+/// from gray to regular binary.
+#[cfg(feature = "time-driver-os-timer")]
+fn gray_to_dec(gray: u64) -> u64 {
+    let mut dec = gray;
+
+    dec ^= dec >> 1;
+    dec ^= dec >> 2;
+    dec ^= dec >> 4;
+    dec ^= dec >> 8;
+    dec ^= dec >> 16;
+    dec ^= dec >> 32;
+
+    dec
+}
+
+/// Convert decimal to gray
+///
+/// Before writing match value to the target register, we must convert
+/// it back into gray code.
+#[cfg(feature = "time-driver-os-timer")]
+fn dec_to_gray(dec: u64) -> u64 {
+    let gray = dec;
+    gray ^ (gray >> 1)
+}
+
+#[cfg(feature = "time-driver-os-timer")]
+embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
+    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
+    queue: Mutex::new(RefCell::new(Queue::new())),
+});
+
+#[cfg(feature = "time-driver-os-timer")]
+struct OsTimer {
+    /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
+    alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
+    queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
+}
+
+#[cfg(feature = "time-driver-os-timer")]
+impl OsTimer {
+    fn init(&'static self, irq_prio: crate::interrupt::Priority) {
+        interrupt::OS_EVENT.disable();
+
+        // init alarms
+        critical_section::with(|cs| {
+            let alarm = DRIVER.alarms.borrow(cs);
+            alarm.timestamp.set(u64::MAX);
+        });
+
+        // Enable clocks. Documentation advises AGAINST resetting this
+        // peripheral.
+        enable::<crate::peripherals::OS_EVENT>();
+
+        // Make sure interrupt is masked
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+
+        // Default to the end of time
+        os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
+        os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
+
+        interrupt::OS_EVENT.unpend();
+        interrupt::OS_EVENT.set_priority(irq_prio);
+        unsafe { interrupt::OS_EVENT.enable() };
+    }
+
+    fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
+        let alarm = self.alarms.borrow(cs);
+        alarm.timestamp.set(timestamp);
+
+        let t = self.now();
+        if timestamp <= t {
+            os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+            alarm.timestamp.set(u64::MAX);
+            return false;
+        }
+
+        let gray_timestamp = dec_to_gray(timestamp);
+
+        os().match_l()
+            .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) });
+        os().match_h()
+            .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) });
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit());
+
+        true
+    }
+
+    #[cfg(feature = "rt")]
+    fn trigger_alarm(&self, cs: CriticalSection) {
+        let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
+        while !self.set_alarm(cs, next) {
path: src/time_driver.rs
user: login: Copilot
body: [nitpick] Ensure that the while loop in trigger_alarm eventually exits by verifying that the wake queue returns a valid expiration; a safeguard may be needed to avoid potential infinite loops if the queue remains unscheduled.
created_at: 2025-05-07T19:52:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,4 +1,6 @@
+//! Time Driver.
path: src/time_driver.rs
user: login: RobertZ2011
body: Can you break up this file into one for the RTC implementation and another for the OS implementation?
created_at: 2025-05-07T20:30:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,4 +1,6 @@
+//! Time Driver.
path: src/time_driver.rs
user: login: felipebalbi
body: done
created_at: 2025-05-07T21:30:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,155 @@
+//! OS Timer Driver.
+use core::cell::RefCell;
+
+use critical_section::CriticalSection;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::Mutex;
+use embassy_time_driver::Driver;
+use embassy_time_queue_utils::Queue;
+
+use super::AlarmState;
+use crate::clocks::enable;
+use crate::interrupt::InterruptExt;
+use crate::{interrupt, pac};
+
+fn os() -> &'static pac::ostimer0::RegisterBlock {
+    unsafe { &*pac::Ostimer0::ptr() }
+}
+
+/// Convert gray to decimal
+///
+/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
+/// do here is read both 32-bit halves of the register and convert
+/// from gray to regular binary.
+fn gray_to_dec(gray: u64) -> u64 {
+    let mut dec = gray;
+
+    dec ^= dec >> 1;
+    dec ^= dec >> 2;
+    dec ^= dec >> 4;
+    dec ^= dec >> 8;
+    dec ^= dec >> 16;
+    dec ^= dec >> 32;
+
+    dec
+}
+
+/// Convert decimal to gray
+///
+/// Before writing match value to the target register, we must convert
+/// it back into gray code.
+fn dec_to_gray(dec: u64) -> u64 {
+    let gray = dec;
+    gray ^ (gray >> 1)
+}
+
+embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
+    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
+    queue: Mutex::new(RefCell::new(Queue::new())),
+});
+
+struct OsTimer {
+    /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
+    alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
+    queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
+}
+
+impl OsTimer {
+    fn init(&'static self, irq_prio: crate::interrupt::Priority) {
+        interrupt::OS_EVENT.disable();
+
+        // init alarms
+        critical_section::with(|cs| {
+            let alarm = DRIVER.alarms.borrow(cs);
+            alarm.timestamp.set(u64::MAX);
+        });
+
+        // Enable clocks. Documentation advises AGAINST resetting this
+        // peripheral.
+        enable::<crate::peripherals::OS_EVENT>();
+
+        // Make sure interrupt is masked
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+
+        // Default to the end of time
+        os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
+        os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
+
+        interrupt::OS_EVENT.unpend();
+        interrupt::OS_EVENT.set_priority(irq_prio);
+        unsafe { interrupt::OS_EVENT.enable() };
+    }
+
+    fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
+        let alarm = self.alarms.borrow(cs);
+        alarm.timestamp.set(timestamp);
+
+        let t = self.now();
+        if timestamp <= t {
+            os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+            alarm.timestamp.set(u64::MAX);
+            return false;
+        }
+
+        let gray_timestamp = dec_to_gray(timestamp);
+
+        os().match_l()
path: src/time_driver/ostimer.rs
user: login: jerrysxie
body: ![alt text](image.png)

It seems like we have to wait for minimum of 3 bus clocks between updating the match registers. We can test the status register to see whether the write is safe. However, looking at the code, we do satisfy the minimum of 3 bus clock cycles between writes to match. Should we test the status bit to be safe?
created_at: 2025-05-09T02:12:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,155 @@
+//! OS Timer Driver.
+use core::cell::RefCell;
+
+use critical_section::CriticalSection;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::Mutex;
+use embassy_time_driver::Driver;
+use embassy_time_queue_utils::Queue;
+
+use super::AlarmState;
+use crate::clocks::enable;
+use crate::interrupt::InterruptExt;
+use crate::{interrupt, pac};
+
+fn os() -> &'static pac::ostimer0::RegisterBlock {
+    unsafe { &*pac::Ostimer0::ptr() }
+}
+
+/// Convert gray to decimal
+///
+/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
+/// do here is read both 32-bit halves of the register and convert
+/// from gray to regular binary.
+fn gray_to_dec(gray: u64) -> u64 {
+    let mut dec = gray;
+
+    dec ^= dec >> 1;
+    dec ^= dec >> 2;
+    dec ^= dec >> 4;
+    dec ^= dec >> 8;
+    dec ^= dec >> 16;
+    dec ^= dec >> 32;
+
+    dec
+}
+
+/// Convert decimal to gray
+///
+/// Before writing match value to the target register, we must convert
+/// it back into gray code.
+fn dec_to_gray(dec: u64) -> u64 {
+    let gray = dec;
+    gray ^ (gray >> 1)
+}
+
+embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
+    alarms:  Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
+    queue: Mutex::new(RefCell::new(Queue::new())),
+});
+
+struct OsTimer {
+    /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
+    alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
+    queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
+}
+
+impl OsTimer {
+    fn init(&'static self, irq_prio: crate::interrupt::Priority) {
+        interrupt::OS_EVENT.disable();
+
+        // init alarms
+        critical_section::with(|cs| {
+            let alarm = DRIVER.alarms.borrow(cs);
+            alarm.timestamp.set(u64::MAX);
+        });
+
+        // Enable clocks. Documentation advises AGAINST resetting this
+        // peripheral.
+        enable::<crate::peripherals::OS_EVENT>();
+
+        // Make sure interrupt is masked
+        os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+
+        // Default to the end of time
+        os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
+        os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
+
+        interrupt::OS_EVENT.unpend();
+        interrupt::OS_EVENT.set_priority(irq_prio);
+        unsafe { interrupt::OS_EVENT.enable() };
+    }
+
+    fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
+        let alarm = self.alarms.borrow(cs);
+        alarm.timestamp.set(timestamp);
+
+        let t = self.now();
+        if timestamp <= t {
+            os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
+            alarm.timestamp.set(u64::MAX);
+            return false;
+        }
+
+        let gray_timestamp = dec_to_gray(timestamp);
+
+        os().match_l()
path: src/time_driver/ostimer.rs
user: login: felipebalbi
body: There isn't much we can actually do. If we test, we add more latency which would result in a larger slack requirement. If the user passes a far too short timeout, it will just result in a "timeout in the past" but nothing catastrophic will happen. I think we keep it as is.
created_at: 2025-05-09T03:08:47Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-07T20:08:19Z
body: # Cargo Vet Audit Passed
`cargo vet` has passed in this PR. No new unvetted dependencies were found.

<!--
This comment is auto-generated by the cargo-vet workflow.
Please do not edit it directly.

comment-tag: [cargo-vet]
-->
author_association: NONE
user: login: felipebalbi
created_at: 2025-05-08T16:38:02Z
body: Tagged with "Breaking Change" because once this is merged, the old `time-driver` feature is no more. User must select either `time-driver-rtc` or `time-driver-os-timer`. If need be, we can define `time-driver` to just enable one of those two and keep backwards compatibility.
author_association: CONTRIBUTOR
user: login: jerrysxie
created_at: 2025-05-09T02:24:07Z
body: > Tagged with "Breaking Change" because once this is merged, the old `time-driver` feature is no more. User must select either `time-driver-rtc` or `time-driver-os-timer`. If need be, we can define `time-driver` to just enable one of those two and keep backwards compatibility.

We should define `time-driver` to just enable one of them as default to keep backwards compatibility.
author_association: CONTRIBUTOR
user: login: felipebalbi
created_at: 2025-05-09T03:09:55Z
body: > > Tagged with "Breaking Change" because once this is merged, the old `time-driver` feature is no more. User must select either `time-driver-rtc` or `time-driver-os-timer`. If need be, we can define `time-driver` to just enable one of those two and keep backwards compatibility.
> 
> We should define `time-driver` to just enable one of them as default to keep backwards compatibility.

Defaulted to RTC as it was before. No impact to users. Removed breaking change label; it no longer applies.
author_association: CONTRIBUTOR