diff options
| author | Mathias <[email protected]> | 2022-10-27 07:12:34 +0200 |
|---|---|---|
| committer | Mathias <[email protected]> | 2022-10-27 07:12:34 +0200 |
| commit | c871fe0848e50c8682b8a8d9fe8da31ca9185592 (patch) | |
| tree | e24f9edc23385080968d4b427aed3eddb4bd2f21 | |
| parent | 3c6c382465131c6f76567f976198b77e327df4b2 (diff) | |
| parent | 61560e740dea1b4c7ca036dafd66c834a1ff92e2 (diff) | |
Rebase on master
76 files changed, 1894 insertions, 464 deletions
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index d0be6d195..85ee856a6 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml | |||
| @@ -20,7 +20,7 @@ nightly = ["embedded-hal-async", "embedded-storage-async"] | |||
| 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 23 | embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true } | 23 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true } |
| 24 | embedded-storage = "0.3.0" | 24 | embedded-storage = "0.3.0" |
| 25 | embedded-storage-async = { version = "0.3.0", optional = true } | 25 | embedded-storage-async = { version = "0.3.0", optional = true } |
| 26 | nb = "1.0.0" | 26 | nb = "1.0.0" |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e1258ebb5..181dabe8e 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -354,46 +354,54 @@ impl Executor { | |||
| 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's | 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's |
| 355 | /// no `poll()` already running. | 355 | /// no `poll()` already running. |
| 356 | pub unsafe fn poll(&'static self) { | 356 | pub unsafe fn poll(&'static self) { |
| 357 | #[cfg(feature = "integrated-timers")] | 357 | loop { |
| 358 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | 358 | #[cfg(feature = "integrated-timers")] |
| 359 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | ||
| 359 | 360 | ||
| 360 | self.run_queue.dequeue_all(|p| { | 361 | self.run_queue.dequeue_all(|p| { |
| 361 | let task = p.as_ref(); | 362 | let task = p.as_ref(); |
| 362 | 363 | ||
| 363 | #[cfg(feature = "integrated-timers")] | 364 | #[cfg(feature = "integrated-timers")] |
| 364 | task.expires_at.set(Instant::MAX); | 365 | task.expires_at.set(Instant::MAX); |
| 365 | |||
| 366 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); | ||
| 367 | if state & STATE_SPAWNED == 0 { | ||
| 368 | // If task is not running, ignore it. This can happen in the following scenario: | ||
| 369 | // - Task gets dequeued, poll starts | ||
| 370 | // - While task is being polled, it gets woken. It gets placed in the queue. | ||
| 371 | // - Task poll finishes, returning done=true | ||
| 372 | // - RUNNING bit is cleared, but the task is already in the queue. | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | 366 | ||
| 376 | #[cfg(feature = "rtos-trace")] | 367 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); |
| 377 | trace::task_exec_begin(p.as_ptr() as u32); | 368 | if state & STATE_SPAWNED == 0 { |
| 369 | // If task is not running, ignore it. This can happen in the following scenario: | ||
| 370 | // - Task gets dequeued, poll starts | ||
| 371 | // - While task is being polled, it gets woken. It gets placed in the queue. | ||
| 372 | // - Task poll finishes, returning done=true | ||
| 373 | // - RUNNING bit is cleared, but the task is already in the queue. | ||
| 374 | return; | ||
| 375 | } | ||
| 378 | 376 | ||
| 379 | // Run the task | 377 | #[cfg(feature = "rtos-trace")] |
| 380 | task.poll_fn.read()(p as _); | 378 | trace::task_exec_begin(p.as_ptr() as u32); |
| 381 | 379 | ||
| 382 | #[cfg(feature = "rtos-trace")] | 380 | // Run the task |
| 383 | trace::task_exec_end(); | 381 | task.poll_fn.read()(p as _); |
| 382 | |||
| 383 | #[cfg(feature = "rtos-trace")] | ||
| 384 | trace::task_exec_end(); | ||
| 385 | |||
| 386 | // Enqueue or update into timer_queue | ||
| 387 | #[cfg(feature = "integrated-timers")] | ||
| 388 | self.timer_queue.update(p); | ||
| 389 | }); | ||
| 384 | 390 | ||
| 385 | // Enqueue or update into timer_queue | ||
| 386 | #[cfg(feature = "integrated-timers")] | 391 | #[cfg(feature = "integrated-timers")] |
| 387 | self.timer_queue.update(p); | 392 | { |
| 388 | }); | 393 | // If this is already in the past, set_alarm might return false |
| 394 | // In that case do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | } | ||
| 389 | 400 | ||
| 390 | #[cfg(feature = "integrated-timers")] | 401 | #[cfg(not(feature = "integrated-timers"))] |
| 391 | { | 402 | { |
| 392 | // If this is already in the past, set_alarm will immediately trigger the alarm. | 403 | break; |
| 393 | // This will cause `signal_fn` to be called, which will cause `poll()` to be called again, | 404 | } |
| 394 | // so we immediately do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | driver::set_alarm(self.alarm, next_expiration.as_ticks()); | ||
| 397 | } | 405 | } |
| 398 | 406 | ||
| 399 | #[cfg(feature = "rtos-trace")] | 407 | #[cfg(feature = "rtos-trace")] |
| @@ -436,14 +444,21 @@ pub unsafe fn wake_task(task: NonNull<TaskHeader>) { | |||
| 436 | } | 444 | } |
| 437 | 445 | ||
| 438 | #[cfg(feature = "integrated-timers")] | 446 | #[cfg(feature = "integrated-timers")] |
| 439 | #[no_mangle] | 447 | struct TimerQueue; |
| 440 | unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) { | 448 | |
| 441 | let task = waker::task_from_waker(waker); | 449 | #[cfg(feature = "integrated-timers")] |
| 442 | let task = task.as_ref(); | 450 | impl embassy_time::queue::TimerQueue for TimerQueue { |
| 443 | let expires_at = task.expires_at.get(); | 451 | fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { |
| 444 | task.expires_at.set(expires_at.min(at)); | 452 | let task = waker::task_from_waker(waker); |
| 453 | let task = unsafe { task.as_ref() }; | ||
| 454 | let expires_at = task.expires_at.get(); | ||
| 455 | task.expires_at.set(expires_at.min(at)); | ||
| 456 | } | ||
| 445 | } | 457 | } |
| 446 | 458 | ||
| 459 | #[cfg(feature = "integrated-timers")] | ||
| 460 | embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); | ||
| 461 | |||
| 447 | #[cfg(feature = "rtos-trace")] | 462 | #[cfg(feature = "rtos-trace")] |
| 448 | impl rtos_trace::RtosTraceOSCallbacks for Executor { | 463 | impl rtos_trace::RtosTraceOSCallbacks for Executor { |
| 449 | fn task_list() { | 464 | fn task_list() { |
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index ea2c3fe67..dc2004172 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml | |||
| @@ -32,7 +32,7 @@ embassy-time = { version = "0.1.0", path = "../embassy-time" } | |||
| 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } | 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } |
| 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 35 | embedded-hal-async = { version = "=0.1.0-alpha.2" } | 35 | embedded-hal-async = { version = "=0.1.0-alpha.3" } |
| 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } | 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } |
| 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } | 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } |
| 38 | embedded-hal = { version = "0.2", features = ["unproven"] } | 38 | embedded-hal = { version = "0.2", features = ["unproven"] } |
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 967ef26a7..76217075a 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml | |||
| @@ -42,7 +42,7 @@ log = { version = "0.4.14", optional = true } | |||
| 42 | 42 | ||
| 43 | embassy-time = { version = "0.1.0", path = "../embassy-time" } | 43 | embassy-time = { version = "0.1.0", path = "../embassy-time" } |
| 44 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 44 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 45 | embedded-io = { version = "0.3.0", optional = true } | 45 | embedded-io = { version = "0.3.1", optional = true } |
| 46 | 46 | ||
| 47 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } | 47 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } |
| 48 | heapless = { version = "0.7.5", default-features = false } | 48 | heapless = { version = "0.7.5", default-features = false } |
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index f8fff3e2d..f3bd2361c 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -292,7 +292,7 @@ mod embedded_io_impls { | |||
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { | 294 | impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { |
| 295 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 295 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 296 | where | 296 | where |
| 297 | Self: 'a; | 297 | Self: 'a; |
| 298 | 298 | ||
| @@ -302,7 +302,7 @@ mod embedded_io_impls { | |||
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { | 304 | impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { |
| 305 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 305 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 306 | where | 306 | where |
| 307 | Self: 'a; | 307 | Self: 'a; |
| 308 | 308 | ||
| @@ -310,7 +310,7 @@ mod embedded_io_impls { | |||
| 310 | self.io.write(buf) | 310 | self.io.write(buf) |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 313 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 314 | where | 314 | where |
| 315 | Self: 'a; | 315 | Self: 'a; |
| 316 | 316 | ||
| @@ -324,7 +324,7 @@ mod embedded_io_impls { | |||
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | impl<'d> embedded_io::asynch::Read for TcpReader<'d> { | 326 | impl<'d> embedded_io::asynch::Read for TcpReader<'d> { |
| 327 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 327 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 328 | where | 328 | where |
| 329 | Self: 'a; | 329 | Self: 'a; |
| 330 | 330 | ||
| @@ -338,7 +338,7 @@ mod embedded_io_impls { | |||
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | impl<'d> embedded_io::asynch::Write for TcpWriter<'d> { | 340 | impl<'d> embedded_io::asynch::Write for TcpWriter<'d> { |
| 341 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 341 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 342 | where | 342 | where |
| 343 | Self: 'a; | 343 | Self: 'a; |
| 344 | 344 | ||
| @@ -346,7 +346,7 @@ mod embedded_io_impls { | |||
| 346 | self.io.write(buf) | 346 | self.io.write(buf) |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 349 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 350 | where | 350 | where |
| 351 | Self: 'a; | 351 | Self: 'a; |
| 352 | 352 | ||
| @@ -445,7 +445,7 @@ pub mod client { | |||
| 445 | impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read | 445 | impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read |
| 446 | for TcpConnection<'d, N, TX_SZ, RX_SZ> | 446 | for TcpConnection<'d, N, TX_SZ, RX_SZ> |
| 447 | { | 447 | { |
| 448 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 448 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 449 | where | 449 | where |
| 450 | Self: 'a; | 450 | Self: 'a; |
| 451 | 451 | ||
| @@ -457,7 +457,7 @@ pub mod client { | |||
| 457 | impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write | 457 | impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write |
| 458 | for TcpConnection<'d, N, TX_SZ, RX_SZ> | 458 | for TcpConnection<'d, N, TX_SZ, RX_SZ> |
| 459 | { | 459 | { |
| 460 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 460 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 461 | where | 461 | where |
| 462 | Self: 'a; | 462 | Self: 'a; |
| 463 | 463 | ||
| @@ -465,7 +465,7 @@ pub mod client { | |||
| 465 | self.socket.write(buf) | 465 | self.socket.write(buf) |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 468 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 469 | where | 469 | where |
| 470 | Self: 'a; | 470 | Self: 'a; |
| 471 | 471 | ||
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 5459bc90c..67b6bec40 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -75,8 +75,8 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona | |||
| 75 | 75 | ||
| 76 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 76 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 77 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 77 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 78 | embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true} | 78 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} |
| 79 | embedded-io = { version = "0.3.0", features = ["async"], optional = true } | 79 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } |
| 80 | 80 | ||
| 81 | defmt = { version = "0.3", optional = true } | 81 | defmt = { version = "0.3", optional = true } |
| 82 | log = { version = "0.4.14", optional = true } | 82 | log = { version = "0.4.14", optional = true } |
| @@ -90,13 +90,13 @@ embedded-storage = "0.3.0" | |||
| 90 | embedded-storage-async = { version = "0.3.0", optional = true } | 90 | embedded-storage-async = { version = "0.3.0", optional = true } |
| 91 | cfg-if = "1.0.0" | 91 | cfg-if = "1.0.0" |
| 92 | 92 | ||
| 93 | nrf52805-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 93 | nrf52805-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 94 | nrf52810-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 94 | nrf52810-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 95 | nrf52811-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 95 | nrf52811-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 96 | nrf52820-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 96 | nrf52820-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 97 | nrf52832-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 97 | nrf52832-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 98 | nrf52833-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 98 | nrf52833-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 99 | nrf52840-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 99 | nrf52840-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 100 | nrf5340-app-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 100 | nrf5340-app-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 101 | nrf5340-net-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 101 | nrf5340-net-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
| 102 | nrf9160-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } | 102 | nrf9160-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } |
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 6e85a159f..9c8fe65f4 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -341,7 +341,7 @@ impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUar | |||
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { | 343 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { |
| 344 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 344 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 345 | where | 345 | where |
| 346 | Self: 'a; | 346 | Self: 'a; |
| 347 | 347 | ||
| @@ -351,7 +351,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for Buffe | |||
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { | 353 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { |
| 354 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 354 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 355 | where | 355 | where |
| 356 | Self: 'a; | 356 | Self: 'a; |
| 357 | 357 | ||
| @@ -361,7 +361,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read f | |||
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { | 363 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { |
| 364 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 364 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 365 | where | 365 | where |
| 366 | Self: 'a; | 366 | Self: 'a; |
| 367 | 367 | ||
| @@ -375,7 +375,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for Bu | |||
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { | 377 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { |
| 378 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 378 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 379 | where | 379 | where |
| 380 | Self: 'a; | 380 | Self: 'a; |
| 381 | 381 | ||
| @@ -389,7 +389,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRea | |||
| 389 | } | 389 | } |
| 390 | 390 | ||
| 391 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { | 391 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { |
| 392 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 392 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 393 | where | 393 | where |
| 394 | Self: 'a; | 394 | Self: 'a; |
| 395 | 395 | ||
| @@ -397,7 +397,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for Buff | |||
| 397 | self.inner_write(buf) | 397 | self.inner_write(buf) |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 400 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 401 | where | 401 | where |
| 402 | Self: 'a; | 402 | Self: 'a; |
| 403 | 403 | ||
| @@ -407,7 +407,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for Buff | |||
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { | 409 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { |
| 410 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 410 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 411 | where | 411 | where |
| 412 | Self: 'a; | 412 | Self: 'a; |
| 413 | 413 | ||
| @@ -415,7 +415,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write | |||
| 415 | self.inner.inner_write(buf) | 415 | self.inner.inner_write(buf) |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 418 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 419 | where | 419 | where |
| 420 | Self: 'a; | 420 | Self: 'a; |
| 421 | 421 | ||
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index d078fa0ad..dec31a84c 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -193,8 +193,8 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 193 | impl_ppi_channel!(PPI_CH30, 30 => static); | 193 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 194 | impl_ppi_channel!(PPI_CH31, 31 => static); | 194 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 195 | 195 | ||
| 196 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 196 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 197 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 197 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 198 | 198 | ||
| 199 | pub mod irqs { | 199 | pub mod irqs { |
| 200 | use embassy_cortex_m::interrupt::_export::declare; | 200 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 3e500098c..e57a4a383 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -211,14 +211,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 211 | impl_ppi_channel!(PPI_CH30, 30 => static); | 211 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 212 | impl_ppi_channel!(PPI_CH31, 31 => static); | 212 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 213 | 213 | ||
| 214 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 214 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 215 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 215 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 216 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 216 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 217 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 217 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 218 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 218 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 219 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 219 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 220 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 220 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 221 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 221 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 222 | 222 | ||
| 223 | pub mod irqs { | 223 | pub mod irqs { |
| 224 | use embassy_cortex_m::interrupt::_export::declare; | 224 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 25c7c0d91..918404cf1 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -212,14 +212,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 212 | impl_ppi_channel!(PPI_CH30, 30 => static); | 212 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 213 | impl_ppi_channel!(PPI_CH31, 31 => static); | 213 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 214 | 214 | ||
| 215 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 215 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 216 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 216 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 217 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 217 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 218 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 218 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 219 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 219 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 220 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 220 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 221 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 221 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 222 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 222 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 223 | 223 | ||
| 224 | pub mod irqs { | 224 | pub mod irqs { |
| 225 | use embassy_cortex_m::interrupt::_export::declare; | 225 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 18b8eda67..81e66c193 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -225,14 +225,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 225 | impl_ppi_channel!(PPI_CH30, 30 => static); | 225 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 226 | impl_ppi_channel!(PPI_CH31, 31 => static); | 226 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 227 | 227 | ||
| 228 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 228 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 229 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 229 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 230 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 230 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 231 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 231 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 232 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 232 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 233 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 233 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 234 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 234 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 235 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 235 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 236 | 236 | ||
| 237 | pub mod irqs { | 237 | pub mod irqs { |
| 238 | use embassy_cortex_m::interrupt::_export::declare; | 238 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 3b33907d2..92499e3c9 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -271,14 +271,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 271 | impl_ppi_channel!(PPI_CH30, 30 => static); | 271 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 272 | impl_ppi_channel!(PPI_CH31, 31 => static); | 272 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 273 | 273 | ||
| 274 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 274 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 275 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 275 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 276 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 276 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 277 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 277 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 278 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 278 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 279 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 279 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 280 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 280 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 281 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 281 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 282 | 282 | ||
| 283 | pub mod irqs { | 283 | pub mod irqs { |
| 284 | use embassy_cortex_m::interrupt::_export::declare; | 284 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index ae59f8b25..4beadfba8 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -276,14 +276,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 276 | impl_ppi_channel!(PPI_CH30, 30 => static); | 276 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 277 | impl_ppi_channel!(PPI_CH31, 31 => static); | 277 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 278 | 278 | ||
| 279 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 279 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 280 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 280 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 281 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 281 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 282 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 282 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 283 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 283 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 284 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 284 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 285 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 285 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 286 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 286 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 287 | 287 | ||
| 288 | pub mod irqs { | 288 | pub mod irqs { |
| 289 | use embassy_cortex_m::interrupt::_export::declare; | 289 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index edf800ef3..7845d4a8e 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs | |||
| @@ -458,14 +458,14 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); | |||
| 458 | impl_ppi_channel!(PPI_CH30, 30 => configurable); | 458 | impl_ppi_channel!(PPI_CH30, 30 => configurable); |
| 459 | impl_ppi_channel!(PPI_CH31, 31 => configurable); | 459 | impl_ppi_channel!(PPI_CH31, 31 => configurable); |
| 460 | 460 | ||
| 461 | impl_saadc_input!(P0_13, ANALOGINPUT0); | 461 | impl_saadc_input!(P0_13, ANALOG_INPUT0); |
| 462 | impl_saadc_input!(P0_14, ANALOGINPUT1); | 462 | impl_saadc_input!(P0_14, ANALOG_INPUT1); |
| 463 | impl_saadc_input!(P0_15, ANALOGINPUT2); | 463 | impl_saadc_input!(P0_15, ANALOG_INPUT2); |
| 464 | impl_saadc_input!(P0_16, ANALOGINPUT3); | 464 | impl_saadc_input!(P0_16, ANALOG_INPUT3); |
| 465 | impl_saadc_input!(P0_17, ANALOGINPUT4); | 465 | impl_saadc_input!(P0_17, ANALOG_INPUT4); |
| 466 | impl_saadc_input!(P0_18, ANALOGINPUT5); | 466 | impl_saadc_input!(P0_18, ANALOG_INPUT5); |
| 467 | impl_saadc_input!(P0_19, ANALOGINPUT6); | 467 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 468 | impl_saadc_input!(P0_20, ANALOGINPUT7); | 468 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 469 | 469 | ||
| 470 | pub mod irqs { | 470 | pub mod irqs { |
| 471 | use embassy_cortex_m::interrupt::_export::declare; | 471 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index f8ed11e03..b5a53ed80 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs | |||
| @@ -339,14 +339,14 @@ impl_ppi_channel!(PPI_CH13, 13 => configurable); | |||
| 339 | impl_ppi_channel!(PPI_CH14, 14 => configurable); | 339 | impl_ppi_channel!(PPI_CH14, 14 => configurable); |
| 340 | impl_ppi_channel!(PPI_CH15, 15 => configurable); | 340 | impl_ppi_channel!(PPI_CH15, 15 => configurable); |
| 341 | 341 | ||
| 342 | impl_saadc_input!(P0_13, ANALOGINPUT0); | 342 | impl_saadc_input!(P0_13, ANALOG_INPUT0); |
| 343 | impl_saadc_input!(P0_14, ANALOGINPUT1); | 343 | impl_saadc_input!(P0_14, ANALOG_INPUT1); |
| 344 | impl_saadc_input!(P0_15, ANALOGINPUT2); | 344 | impl_saadc_input!(P0_15, ANALOG_INPUT2); |
| 345 | impl_saadc_input!(P0_16, ANALOGINPUT3); | 345 | impl_saadc_input!(P0_16, ANALOG_INPUT3); |
| 346 | impl_saadc_input!(P0_17, ANALOGINPUT4); | 346 | impl_saadc_input!(P0_17, ANALOG_INPUT4); |
| 347 | impl_saadc_input!(P0_18, ANALOGINPUT5); | 347 | impl_saadc_input!(P0_18, ANALOG_INPUT5); |
| 348 | impl_saadc_input!(P0_19, ANALOGINPUT6); | 348 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 349 | impl_saadc_input!(P0_20, ANALOGINPUT7); | 349 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 350 | 350 | ||
| 351 | pub mod irqs { | 351 | pub mod irqs { |
| 352 | use embassy_cortex_m::interrupt::_export::declare; | 352 | use embassy_cortex_m::interrupt::_export::declare; |
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index c32a44637..bc2c8a3c1 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs | |||
| @@ -243,21 +243,24 @@ impl Driver for RtcDriver { | |||
| 243 | }) | 243 | }) |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 246 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 247 | critical_section::with(|cs| { | 247 | critical_section::with(|cs| { |
| 248 | let n = alarm.id() as _; | 248 | let n = alarm.id() as _; |
| 249 | let alarm = self.get_alarm(cs, alarm); | 249 | let alarm = self.get_alarm(cs, alarm); |
| 250 | alarm.timestamp.set(timestamp); | 250 | alarm.timestamp.set(timestamp); |
| 251 | 251 | ||
| 252 | let t = self.now(); | 252 | let r = rtc(); |
| 253 | 253 | ||
| 254 | // If alarm timestamp has passed, trigger it instantly. | 254 | let t = self.now(); |
| 255 | if timestamp <= t { | 255 | if timestamp <= t { |
| 256 | self.trigger_alarm(n, cs); | 256 | // If alarm timestamp has passed the alarm will not fire. |
| 257 | return; | 257 | // Disarm the alarm and return `false` to indicate that. |
| 258 | } | 258 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); |
| 259 | 259 | ||
| 260 | let r = rtc(); | 260 | alarm.timestamp.set(u64::MAX); |
| 261 | |||
| 262 | return false; | ||
| 263 | } | ||
| 261 | 264 | ||
| 262 | // If it hasn't triggered yet, setup it in the compare channel. | 265 | // If it hasn't triggered yet, setup it in the compare channel. |
| 263 | 266 | ||
| @@ -287,6 +290,8 @@ impl Driver for RtcDriver { | |||
| 287 | // It will be setup later by `next_period`. | 290 | // It will be setup later by `next_period`. |
| 288 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); | 291 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); |
| 289 | } | 292 | } |
| 293 | |||
| 294 | true | ||
| 290 | }) | 295 | }) |
| 291 | } | 296 | } |
| 292 | } | 297 | } |
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 00da5c9dd..eb1472fa5 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -313,7 +313,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 313 | } | 313 | } |
| 314 | }) | 314 | }) |
| 315 | .await; | 315 | .await; |
| 316 | regs.eventcause.write(|w| w.ready().set_bit()); // Write 1 to clear. | 316 | regs.eventcause.write(|w| w.ready().clear_bit_by_one()); |
| 317 | 317 | ||
| 318 | errata::post_enable(); | 318 | errata::post_enable(); |
| 319 | 319 | ||
| @@ -367,24 +367,24 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 367 | let r = regs.eventcause.read(); | 367 | let r = regs.eventcause.read(); |
| 368 | 368 | ||
| 369 | if r.isooutcrc().bit() { | 369 | if r.isooutcrc().bit() { |
| 370 | regs.eventcause.write(|w| w.isooutcrc().set_bit()); | 370 | regs.eventcause.write(|w| w.isooutcrc().detected()); |
| 371 | trace!("USB event: isooutcrc"); | 371 | trace!("USB event: isooutcrc"); |
| 372 | } | 372 | } |
| 373 | if r.usbwuallowed().bit() { | 373 | if r.usbwuallowed().bit() { |
| 374 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | 374 | regs.eventcause.write(|w| w.usbwuallowed().allowed()); |
| 375 | trace!("USB event: usbwuallowed"); | 375 | trace!("USB event: usbwuallowed"); |
| 376 | } | 376 | } |
| 377 | if r.suspend().bit() { | 377 | if r.suspend().bit() { |
| 378 | regs.eventcause.write(|w| w.suspend().set_bit()); | 378 | regs.eventcause.write(|w| w.suspend().detected()); |
| 379 | regs.lowpower.write(|w| w.lowpower().low_power()); | 379 | regs.lowpower.write(|w| w.lowpower().low_power()); |
| 380 | return Poll::Ready(Event::Suspend); | 380 | return Poll::Ready(Event::Suspend); |
| 381 | } | 381 | } |
| 382 | if r.resume().bit() { | 382 | if r.resume().bit() { |
| 383 | regs.eventcause.write(|w| w.resume().set_bit()); | 383 | regs.eventcause.write(|w| w.resume().detected()); |
| 384 | return Poll::Ready(Event::Resume); | 384 | return Poll::Ready(Event::Resume); |
| 385 | } | 385 | } |
| 386 | if r.ready().bit() { | 386 | if r.ready().bit() { |
| 387 | regs.eventcause.write(|w| w.ready().set_bit()); | 387 | regs.eventcause.write(|w| w.ready().ready()); |
| 388 | trace!("USB event: ready"); | 388 | trace!("USB event: ready"); |
| 389 | } | 389 | } |
| 390 | 390 | ||
| @@ -512,7 +512,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 512 | } else if r.resume().bit() { | 512 | } else if r.resume().bit() { |
| 513 | Poll::Ready(()) | 513 | Poll::Ready(()) |
| 514 | } else if r.usbwuallowed().bit() { | 514 | } else if r.usbwuallowed().bit() { |
| 515 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | 515 | regs.eventcause.write(|w| w.usbwuallowed().allowed()); |
| 516 | 516 | ||
| 517 | regs.dpdmvalue.write(|w| w.state().resume()); | 517 | regs.dpdmvalue.write(|w| w.state().resume()); |
| 518 | regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); | 518 | regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); |
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 2f9c9b9af..04b0c13ce 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -53,13 +53,13 @@ cortex-m = "0.7.6" | |||
| 53 | critical-section = "1.1" | 53 | critical-section = "1.1" |
| 54 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 54 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 55 | chrono = { version = "0.4", default-features = false, optional = true } | 55 | chrono = { version = "0.4", default-features = false, optional = true } |
| 56 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } | ||
| 56 | embedded-storage = { version = "0.3" } | 57 | embedded-storage = { version = "0.3" } |
| 57 | embedded-io = { version = "0.3.0", features = ["async"], optional = true } | ||
| 58 | 58 | ||
| 59 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } | 59 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } |
| 60 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } | 60 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } |
| 61 | 61 | ||
| 62 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 62 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 63 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 63 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 64 | embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true} | 64 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} |
| 65 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 65 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} |
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index 5215c0c0f..80efd779f 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs | |||
| @@ -68,7 +68,7 @@ impl Driver for TimerDriver { | |||
| 68 | }) | 68 | }) |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 71 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 72 | let n = alarm.id() as usize; | 72 | let n = alarm.id() as usize; |
| 73 | critical_section::with(|cs| { | 73 | critical_section::with(|cs| { |
| 74 | let alarm = &self.alarms.borrow(cs)[n]; | 74 | let alarm = &self.alarms.borrow(cs)[n]; |
| @@ -81,11 +81,16 @@ impl Driver for TimerDriver { | |||
| 81 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 81 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; |
| 82 | 82 | ||
| 83 | let now = self.now(); | 83 | let now = self.now(); |
| 84 | |||
| 85 | // If alarm timestamp has passed, trigger it instantly. | ||
| 86 | // This disarms it. | ||
| 87 | if timestamp <= now { | 84 | if timestamp <= now { |
| 88 | self.trigger_alarm(n, cs); | 85 | // If alarm timestamp has passed the alarm will not fire. |
| 86 | // Disarm the alarm and return `false` to indicate that. | ||
| 87 | unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } | ||
| 88 | |||
| 89 | alarm.timestamp.set(u64::MAX); | ||
| 90 | |||
| 91 | false | ||
| 92 | } else { | ||
| 93 | true | ||
| 89 | } | 94 | } |
| 90 | }) | 95 | }) |
| 91 | } | 96 | } |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 87e16f0eb..4f0a55532 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -355,7 +355,7 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> { | |||
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | 357 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { |
| 358 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 358 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 359 | where | 359 | where |
| 360 | Self: 'a; | 360 | Self: 'a; |
| 361 | 361 | ||
| @@ -376,7 +376,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { | 378 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { |
| 379 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 379 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 380 | where | 380 | where |
| 381 | Self: 'a; | 381 | Self: 'a; |
| 382 | 382 | ||
| @@ -397,7 +397,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { | |||
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | 399 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { |
| 400 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 400 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 401 | where | 401 | where |
| 402 | Self: 'a; | 402 | Self: 'a; |
| 403 | 403 | ||
| @@ -419,7 +419,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> | |||
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { | 421 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { |
| 422 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 422 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 423 | where | 423 | where |
| 424 | Self: 'a; | 424 | Self: 'a; |
| 425 | 425 | ||
| @@ -441,7 +441,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T | |||
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | 443 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { |
| 444 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 444 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 445 | where | 445 | where |
| 446 | Self: 'a; | 446 | Self: 'a; |
| 447 | 447 | ||
| @@ -455,7 +455,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 455 | }) | 455 | }) |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 458 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 459 | where | 459 | where |
| 460 | Self: 'a; | 460 | Self: 'a; |
| 461 | 461 | ||
| @@ -465,7 +465,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { | 467 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { |
| 468 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 468 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 469 | where | 469 | where |
| 470 | Self: 'a; | 470 | Self: 'a; |
| 471 | 471 | ||
| @@ -479,7 +479,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> | |||
| 479 | }) | 479 | }) |
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 482 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 483 | where | 483 | where |
| 484 | Self: 'a; | 484 | Self: 'a; |
| 485 | 485 | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 9194ae788..6b00518a6 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -44,7 +44,7 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona | |||
| 44 | 44 | ||
| 45 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 45 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 46 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 46 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 47 | embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true} | 47 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} |
| 48 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 48 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} |
| 49 | 49 | ||
| 50 | embedded-storage = "0.3.0" | 50 | embedded-storage = "0.3.0" |
| @@ -67,7 +67,7 @@ nb = "1.0.0" | |||
| 67 | stm32-fmc = "0.2.4" | 67 | stm32-fmc = "0.2.4" |
| 68 | seq-macro = "0.3.0" | 68 | seq-macro = "0.3.0" |
| 69 | cfg-if = "1.0.0" | 69 | cfg-if = "1.0.0" |
| 70 | embedded-io = { version = "0.3.0", features = ["async"], optional = true } | 70 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } |
| 71 | 71 | ||
| 72 | [build-dependencies] | 72 | [build-dependencies] |
| 73 | proc-macro2 = "1.0.36" | 73 | proc-macro2 = "1.0.36" |
| @@ -82,9 +82,12 @@ memory-x = ["stm32-metapac/memory-x"] | |||
| 82 | subghz = [] | 82 | subghz = [] |
| 83 | exti = [] | 83 | exti = [] |
| 84 | 84 | ||
| 85 | # Enables additional driver features that depend on embassy-time | ||
| 86 | time = ["dep:embassy-time"] | ||
| 87 | |||
| 85 | # Features starting with `_` are for internal use only. They're not intended | 88 | # Features starting with `_` are for internal use only. They're not intended |
| 86 | # to be enabled by other crates, and are not covered by semver guarantees. | 89 | # to be enabled by other crates, and are not covered by semver guarantees. |
| 87 | _time-driver = ["dep:embassy-time"] | 90 | _time-driver = ["time"] |
| 88 | time-driver-any = ["_time-driver"] | 91 | time-driver-any = ["_time-driver"] |
| 89 | time-driver-tim2 = ["_time-driver"] | 92 | time-driver-tim2 = ["_time-driver"] |
| 90 | time-driver-tim3 = ["_time-driver"] | 93 | time-driver-tim3 = ["_time-driver"] |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 50d4f9bf9..c5b317ce9 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -86,7 +86,6 @@ pub use sample_time::SampleTime; | |||
| 86 | 86 | ||
| 87 | pub struct Adc<'d, T: Instance> { | 87 | pub struct Adc<'d, T: Instance> { |
| 88 | sample_time: SampleTime, | 88 | sample_time: SampleTime, |
| 89 | calibrated_vdda: u32, | ||
| 90 | phantom: PhantomData<&'d mut T>, | 89 | phantom: PhantomData<&'d mut T>, |
| 91 | } | 90 | } |
| 92 | 91 | ||
| @@ -122,7 +121,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 122 | 121 | ||
| 123 | Self { | 122 | Self { |
| 124 | sample_time: Default::default(), | 123 | sample_time: Default::default(), |
| 125 | calibrated_vdda: VDDA_CALIB_MV, | ||
| 126 | phantom: PhantomData, | 124 | phantom: PhantomData, |
| 127 | } | 125 | } |
| 128 | } | 126 | } |
| @@ -162,29 +160,10 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 162 | Temperature {} | 160 | Temperature {} |
| 163 | } | 161 | } |
| 164 | 162 | ||
| 165 | /// Calculates the system VDDA by sampling the internal VREF channel and comparing | ||
| 166 | /// to the expected value. If the chip's VDDA is not stable, run this before each ADC | ||
| 167 | /// conversion. | ||
| 168 | pub fn calibrate(&mut self, vref: &mut Vref) -> u32 { | ||
| 169 | let old_sample_time = self.sample_time; | ||
| 170 | self.sample_time = SampleTime::Cycles239_5; | ||
| 171 | |||
| 172 | let vref_samp = self.read(vref); | ||
| 173 | self.sample_time = old_sample_time; | ||
| 174 | |||
| 175 | self.calibrated_vdda = (ADC_MAX * VREF_INT) / u32::from(vref_samp); | ||
| 176 | self.calibrated_vdda | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 163 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 180 | self.sample_time = sample_time; | 164 | self.sample_time = sample_time; |
| 181 | } | 165 | } |
| 182 | 166 | ||
| 183 | /// Convert a measurement to millivolts | ||
| 184 | pub fn to_millivolts(&self, sample: u16) -> u16 { | ||
| 185 | ((u32::from(sample) * self.calibrated_vdda) / ADC_MAX) as u16 | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Perform a single conversion. | 167 | /// Perform a single conversion. |
| 189 | fn convert(&mut self) -> u16 { | 168 | fn convert(&mut self) -> u16 { |
| 190 | unsafe { | 169 | unsafe { |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4fe4ad1f0..53419c7f2 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -80,15 +80,6 @@ impl super::sealed::InternalChannel<ADC1> for Temperature { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | impl Temperature { | 82 | impl Temperature { |
| 83 | /// Converts temperature sensor reading in millivolts to degrees celcius | ||
| 84 | pub fn to_celcius(sample_mv: u16) -> f32 { | ||
| 85 | // From 6.3.22 Temperature sensor characteristics | ||
| 86 | const V25: i32 = 760; // mV | ||
| 87 | const AVG_SLOPE: f32 = 2.5; // mV/C | ||
| 88 | |||
| 89 | (sample_mv as i32 - V25) as f32 / AVG_SLOPE + 25.0 | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Time needed for temperature sensor readings to stabilize | 83 | /// Time needed for temperature sensor readings to stabilize |
| 93 | pub fn start_time_us() -> u32 { | 84 | pub fn start_time_us() -> u32 { |
| 94 | 10 | 85 | 10 |
| @@ -172,7 +163,6 @@ impl Prescaler { | |||
| 172 | 163 | ||
| 173 | pub struct Adc<'d, T: Instance> { | 164 | pub struct Adc<'d, T: Instance> { |
| 174 | sample_time: SampleTime, | 165 | sample_time: SampleTime, |
| 175 | vref_mv: u32, | ||
| 176 | resolution: Resolution, | 166 | resolution: Resolution, |
| 177 | phantom: PhantomData<&'d mut T>, | 167 | phantom: PhantomData<&'d mut T>, |
| 178 | } | 168 | } |
| @@ -200,7 +190,6 @@ where | |||
| 200 | Self { | 190 | Self { |
| 201 | sample_time: Default::default(), | 191 | sample_time: Default::default(), |
| 202 | resolution: Resolution::default(), | 192 | resolution: Resolution::default(), |
| 203 | vref_mv: VREF_DEFAULT_MV, | ||
| 204 | phantom: PhantomData, | 193 | phantom: PhantomData, |
| 205 | } | 194 | } |
| 206 | } | 195 | } |
| @@ -213,18 +202,6 @@ where | |||
| 213 | self.resolution = resolution; | 202 | self.resolution = resolution; |
| 214 | } | 203 | } |
| 215 | 204 | ||
| 216 | /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion. | ||
| 217 | /// | ||
| 218 | /// Use this if you have a known precise VREF (VDDA) pin reference voltage. | ||
| 219 | pub fn set_vref_mv(&mut self, vref_mv: u32) { | ||
| 220 | self.vref_mv = vref_mv; | ||
| 221 | } | ||
| 222 | |||
| 223 | /// Convert a measurement to millivolts | ||
| 224 | pub fn to_millivolts(&self, sample: u16) -> u16 { | ||
| 225 | ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Enables internal voltage reference and returns [VrefInt], which can be used in | 205 | /// Enables internal voltage reference and returns [VrefInt], which can be used in |
| 229 | /// [Adc::read_internal()] to perform conversion. | 206 | /// [Adc::read_internal()] to perform conversion. |
| 230 | pub fn enable_vrefint(&self) -> VrefInt { | 207 | pub fn enable_vrefint(&self) -> VrefInt { |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 0f1090888..816feeac7 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -205,7 +205,6 @@ pub use sample_time::SampleTime; | |||
| 205 | 205 | ||
| 206 | pub struct Adc<'d, T: Instance> { | 206 | pub struct Adc<'d, T: Instance> { |
| 207 | sample_time: SampleTime, | 207 | sample_time: SampleTime, |
| 208 | vref_mv: u32, | ||
| 209 | resolution: Resolution, | 208 | resolution: Resolution, |
| 210 | phantom: PhantomData<&'d mut T>, | 209 | phantom: PhantomData<&'d mut T>, |
| 211 | } | 210 | } |
| @@ -244,7 +243,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 244 | Self { | 243 | Self { |
| 245 | sample_time: Default::default(), | 244 | sample_time: Default::default(), |
| 246 | resolution: Resolution::default(), | 245 | resolution: Resolution::default(), |
| 247 | vref_mv: VREF_DEFAULT_MV, | ||
| 248 | phantom: PhantomData, | 246 | phantom: PhantomData, |
| 249 | } | 247 | } |
| 250 | } | 248 | } |
| @@ -285,31 +283,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 285 | Vbat {} | 283 | Vbat {} |
| 286 | } | 284 | } |
| 287 | 285 | ||
| 288 | /// Calculates the system VDDA by sampling the internal VREFINT channel and comparing | ||
| 289 | /// the result with the value stored at the factory. If the chip's VDDA is not stable, run | ||
| 290 | /// this before each ADC conversion. | ||
| 291 | #[cfg(not(stm32g0))] // TODO is this supposed to be public? | ||
| 292 | #[allow(unused)] // TODO is this supposed to be public? | ||
| 293 | fn calibrate(&mut self, vrefint: &mut VrefInt) { | ||
| 294 | #[cfg(stm32l5)] | ||
| 295 | let vrefint_cal: u32 = todo!(); | ||
| 296 | #[cfg(not(stm32l5))] | ||
| 297 | let vrefint_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() }; | ||
| 298 | let old_sample_time = self.sample_time; | ||
| 299 | |||
| 300 | // "Table 24. Embedded internal voltage reference" states that the sample time needs to be | ||
| 301 | // at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving | ||
| 302 | // some headroom. | ||
| 303 | self.sample_time = SampleTime::Cycles640_5; | ||
| 304 | |||
| 305 | // This can't actually fail, it's just in a result to satisfy hal trait | ||
| 306 | let vrefint_samp = self.read(vrefint); | ||
| 307 | |||
| 308 | self.sample_time = old_sample_time; | ||
| 309 | |||
| 310 | self.vref_mv = (VREF_CALIB_MV * u32::from(vrefint_cal)) / u32::from(vrefint_samp); | ||
| 311 | } | ||
| 312 | |||
| 313 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 286 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 314 | self.sample_time = sample_time; | 287 | self.sample_time = sample_time; |
| 315 | } | 288 | } |
| @@ -318,18 +291,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 318 | self.resolution = resolution; | 291 | self.resolution = resolution; |
| 319 | } | 292 | } |
| 320 | 293 | ||
| 321 | /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion. | ||
| 322 | /// | ||
| 323 | /// Use this if you have a known precise VREF (VDDA) pin reference voltage. | ||
| 324 | pub fn set_vref_mv(&mut self, vref_mv: u32) { | ||
| 325 | self.vref_mv = vref_mv; | ||
| 326 | } | ||
| 327 | |||
| 328 | /// Convert a measurement to millivolts | ||
| 329 | pub fn to_millivolts(&self, sample: u16) -> u16 { | ||
| 330 | ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 | ||
| 331 | } | ||
| 332 | |||
| 333 | /* | 294 | /* |
| 334 | /// Convert a raw sample from the `Temperature` to deg C | 295 | /// Convert a raw sample from the `Temperature` to deg C |
| 335 | pub fn to_degrees_centigrade(sample: u16) -> f32 { | 296 | pub fn to_degrees_centigrade(sample: u16) -> f32 { |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index eda2b2a72..2b8f10533 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -314,7 +314,6 @@ impl Prescaler { | |||
| 314 | 314 | ||
| 315 | pub struct Adc<'d, T: Instance> { | 315 | pub struct Adc<'d, T: Instance> { |
| 316 | sample_time: SampleTime, | 316 | sample_time: SampleTime, |
| 317 | vref_mv: u32, | ||
| 318 | resolution: Resolution, | 317 | resolution: Resolution, |
| 319 | phantom: PhantomData<&'d mut T>, | 318 | phantom: PhantomData<&'d mut T>, |
| 320 | } | 319 | } |
| @@ -352,7 +351,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> { | |||
| 352 | 351 | ||
| 353 | let mut s = Self { | 352 | let mut s = Self { |
| 354 | sample_time: Default::default(), | 353 | sample_time: Default::default(), |
| 355 | vref_mv: VREF_DEFAULT_MV, | ||
| 356 | resolution: Resolution::default(), | 354 | resolution: Resolution::default(), |
| 357 | phantom: PhantomData, | 355 | phantom: PhantomData, |
| 358 | }; | 356 | }; |
| @@ -459,18 +457,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> { | |||
| 459 | self.resolution = resolution; | 457 | self.resolution = resolution; |
| 460 | } | 458 | } |
| 461 | 459 | ||
| 462 | /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion. | ||
| 463 | /// | ||
| 464 | /// Use this if you have a known precise VREF (VDDA) pin reference voltage. | ||
| 465 | pub fn set_vref_mv(&mut self, vref_mv: u32) { | ||
| 466 | self.vref_mv = vref_mv; | ||
| 467 | } | ||
| 468 | |||
| 469 | /// Convert a measurement to millivolts | ||
| 470 | pub fn to_millivolts(&self, sample: u16) -> u16 { | ||
| 471 | ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 | ||
| 472 | } | ||
| 473 | |||
| 474 | /// Perform a single conversion. | 460 | /// Perform a single conversion. |
| 475 | fn convert(&mut self) -> u16 { | 461 | fn convert(&mut self) -> u16 { |
| 476 | unsafe { | 462 | unsafe { |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 9d314f411..f898fcc8b 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -7,6 +7,11 @@ use crate::interrupt::Interrupt; | |||
| 7 | mod _version; | 7 | mod _version; |
| 8 | pub use _version::*; | 8 | pub use _version::*; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "time")] | ||
| 11 | mod timeout; | ||
| 12 | #[cfg(feature = "time")] | ||
| 13 | pub use timeout::*; | ||
| 14 | |||
| 10 | use crate::peripherals; | 15 | use crate::peripherals; |
| 11 | 16 | ||
| 12 | #[derive(Debug)] | 17 | #[derive(Debug)] |
diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs new file mode 100644 index 000000000..4fca1ca2b --- /dev/null +++ b/embassy-stm32/src/i2c/timeout.rs | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | use embassy_time::{Duration, Instant}; | ||
| 2 | |||
| 3 | use super::{Error, I2c, Instance}; | ||
| 4 | |||
| 5 | /// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods. | ||
| 6 | /// | ||
| 7 | /// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state. | ||
| 8 | /// A regular [I2c] would freeze until condition is removed. | ||
| 9 | pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> { | ||
| 10 | i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, | ||
| 11 | timeout: Duration, | ||
| 12 | } | ||
| 13 | |||
| 14 | fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { | ||
| 15 | let deadline = Instant::now() + timeout; | ||
| 16 | move || { | ||
| 17 | if Instant::now() > deadline { | ||
| 18 | Err(Error::Timeout) | ||
| 19 | } else { | ||
| 20 | Ok(()) | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 26 | pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self { | ||
| 27 | Self { i2c, timeout } | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Blocking read with a custom timeout | ||
| 31 | pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { | ||
| 32 | self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout)) | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 36 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 37 | self.blocking_read_timeout(addr, buffer, self.timeout) | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Blocking write with a custom timeout | ||
| 41 | pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> { | ||
| 42 | self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout)) | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 46 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 47 | self.blocking_write_timeout(addr, bytes, self.timeout) | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Blocking write-read with a custom timeout | ||
| 51 | pub fn blocking_write_read_timeout( | ||
| 52 | &mut self, | ||
| 53 | addr: u8, | ||
| 54 | bytes: &[u8], | ||
| 55 | buffer: &mut [u8], | ||
| 56 | timeout: Duration, | ||
| 57 | ) -> Result<(), Error> { | ||
| 58 | self.i2c | ||
| 59 | .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout)) | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 63 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 64 | self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout) | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 69 | type Error = Error; | ||
| 70 | |||
| 71 | fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 72 | self.blocking_read(addr, buffer) | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 77 | type Error = Error; | ||
| 78 | |||
| 79 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 80 | self.blocking_write(addr, bytes) | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 85 | type Error = Error; | ||
| 86 | |||
| 87 | fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 88 | self.blocking_write_read(addr, bytes, buffer) | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | #[cfg(feature = "unstable-traits")] | ||
| 93 | mod eh1 { | ||
| 94 | use super::*; | ||
| 95 | |||
| 96 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 97 | type Error = Error; | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 101 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 102 | self.blocking_read(address, buffer) | ||
| 103 | } | ||
| 104 | |||
| 105 | fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 106 | self.blocking_write(address, buffer) | ||
| 107 | } | ||
| 108 | |||
| 109 | fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> | ||
| 110 | where | ||
| 111 | B: IntoIterator<Item = u8>, | ||
| 112 | { | ||
| 113 | todo!(); | ||
| 114 | } | ||
| 115 | |||
| 116 | fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> | ||
| 117 | where | ||
| 118 | B: IntoIterator<Item = u8>, | ||
| 119 | { | ||
| 120 | todo!(); | ||
| 121 | } | ||
| 122 | |||
| 123 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 124 | self.blocking_write_read(address, wr_buffer, rd_buffer) | ||
| 125 | } | ||
| 126 | |||
| 127 | fn transaction<'a>( | ||
| 128 | &mut self, | ||
| 129 | _address: u8, | ||
| 130 | _operations: &mut [embedded_hal_1::i2c::Operation<'a>], | ||
| 131 | ) -> Result<(), Self::Error> { | ||
| 132 | todo!(); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> | ||
| 136 | where | ||
| 137 | O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>, | ||
| 138 | { | ||
| 139 | todo!(); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f39a37df6..f140e2b0d 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use embassy_embedded_hal::SetConfig; | 3 | use embassy_embedded_hal::SetConfig; |
| 4 | use embassy_hal_common::into_ref; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 5 | 5 | ||
| 6 | use crate::dma::NoDma; | ||
| 6 | use crate::gpio::sealed::AFType; | 7 | use crate::gpio::sealed::AFType; |
| 7 | use crate::gpio::Pull; | 8 | use crate::gpio::Pull; |
| 8 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 9 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| @@ -34,19 +35,26 @@ impl State { | |||
| 34 | } | 35 | } |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | pub struct I2c<'d, T: Instance> { | 38 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { |
| 38 | phantom: PhantomData<&'d mut T>, | 39 | phantom: PhantomData<&'d mut T>, |
| 40 | #[allow(dead_code)] | ||
| 41 | tx_dma: PeripheralRef<'d, TXDMA>, | ||
| 42 | #[allow(dead_code)] | ||
| 43 | rx_dma: PeripheralRef<'d, RXDMA>, | ||
| 39 | } | 44 | } |
| 40 | 45 | ||
| 41 | impl<'d, T: Instance> I2c<'d, T> { | 46 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 42 | pub fn new( | 47 | pub fn new( |
| 43 | _peri: impl Peripheral<P = T> + 'd, | 48 | _peri: impl Peripheral<P = T> + 'd, |
| 44 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | 49 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, |
| 45 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | 50 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |
| 51 | _irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 52 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||
| 53 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||
| 46 | freq: Hertz, | 54 | freq: Hertz, |
| 47 | config: Config, | 55 | config: Config, |
| 48 | ) -> Self { | 56 | ) -> Self { |
| 49 | into_ref!(scl, sda); | 57 | into_ref!(scl, sda, tx_dma, rx_dma); |
| 50 | 58 | ||
| 51 | T::enable(); | 59 | T::enable(); |
| 52 | T::reset(); | 60 | T::reset(); |
| @@ -99,7 +107,11 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 99 | }); | 107 | }); |
| 100 | } | 108 | } |
| 101 | 109 | ||
| 102 | Self { phantom: PhantomData } | 110 | Self { |
| 111 | phantom: PhantomData, | ||
| 112 | tx_dma, | ||
| 113 | rx_dma, | ||
| 114 | } | ||
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { | 117 | unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { |
| @@ -141,7 +153,12 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 141 | Ok(sr1) | 153 | Ok(sr1) |
| 142 | } | 154 | } |
| 143 | 155 | ||
| 144 | unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 156 | unsafe fn write_bytes( |
| 157 | &mut self, | ||
| 158 | addr: u8, | ||
| 159 | bytes: &[u8], | ||
| 160 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 161 | ) -> Result<(), Error> { | ||
| 145 | // Send a START condition | 162 | // Send a START condition |
| 146 | 163 | ||
| 147 | T::regs().cr1().modify(|reg| { | 164 | T::regs().cr1().modify(|reg| { |
| @@ -149,7 +166,9 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 149 | }); | 166 | }); |
| 150 | 167 | ||
| 151 | // Wait until START condition was generated | 168 | // Wait until START condition was generated |
| 152 | while !self.check_and_clear_error_flags()?.start() {} | 169 | while !self.check_and_clear_error_flags()?.start() { |
| 170 | check_timeout()?; | ||
| 171 | } | ||
| 153 | 172 | ||
| 154 | // Also wait until signalled we're master and everything is waiting for us | 173 | // Also wait until signalled we're master and everything is waiting for us |
| 155 | while { | 174 | while { |
| @@ -157,7 +176,9 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 157 | 176 | ||
| 158 | let sr2 = T::regs().sr2().read(); | 177 | let sr2 = T::regs().sr2().read(); |
| 159 | !sr2.msl() && !sr2.busy() | 178 | !sr2.msl() && !sr2.busy() |
| 160 | } {} | 179 | } { |
| 180 | check_timeout()?; | ||
| 181 | } | ||
| 161 | 182 | ||
| 162 | // Set up current address, we're trying to talk to | 183 | // Set up current address, we're trying to talk to |
| 163 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); | 184 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); |
| @@ -165,26 +186,30 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 165 | // Wait until address was sent | 186 | // Wait until address was sent |
| 166 | // Wait for the address to be acknowledged | 187 | // Wait for the address to be acknowledged |
| 167 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 188 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 168 | while !self.check_and_clear_error_flags()?.addr() {} | 189 | while !self.check_and_clear_error_flags()?.addr() { |
| 190 | check_timeout()?; | ||
| 191 | } | ||
| 169 | 192 | ||
| 170 | // Clear condition by reading SR2 | 193 | // Clear condition by reading SR2 |
| 171 | let _ = T::regs().sr2().read(); | 194 | let _ = T::regs().sr2().read(); |
| 172 | 195 | ||
| 173 | // Send bytes | 196 | // Send bytes |
| 174 | for c in bytes { | 197 | for c in bytes { |
| 175 | self.send_byte(*c)?; | 198 | self.send_byte(*c, &check_timeout)?; |
| 176 | } | 199 | } |
| 177 | 200 | ||
| 178 | // Fallthrough is success | 201 | // Fallthrough is success |
| 179 | Ok(()) | 202 | Ok(()) |
| 180 | } | 203 | } |
| 181 | 204 | ||
| 182 | unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> { | 205 | unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 183 | // Wait until we're ready for sending | 206 | // Wait until we're ready for sending |
| 184 | while { | 207 | while { |
| 185 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 208 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 186 | !self.check_and_clear_error_flags()?.txe() | 209 | !self.check_and_clear_error_flags()?.txe() |
| 187 | } {} | 210 | } { |
| 211 | check_timeout()?; | ||
| 212 | } | ||
| 188 | 213 | ||
| 189 | // Push out a byte of data | 214 | // Push out a byte of data |
| 190 | T::regs().dr().write(|reg| reg.set_dr(byte)); | 215 | T::regs().dr().write(|reg| reg.set_dr(byte)); |
| @@ -193,24 +218,33 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 193 | while { | 218 | while { |
| 194 | // Check for any potential error conditions. | 219 | // Check for any potential error conditions. |
| 195 | !self.check_and_clear_error_flags()?.btf() | 220 | !self.check_and_clear_error_flags()?.btf() |
| 196 | } {} | 221 | } { |
| 222 | check_timeout()?; | ||
| 223 | } | ||
| 197 | 224 | ||
| 198 | Ok(()) | 225 | Ok(()) |
| 199 | } | 226 | } |
| 200 | 227 | ||
| 201 | unsafe fn recv_byte(&self) -> Result<u8, Error> { | 228 | unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { |
| 202 | while { | 229 | while { |
| 203 | // Check for any potential error conditions. | 230 | // Check for any potential error conditions. |
| 204 | self.check_and_clear_error_flags()?; | 231 | self.check_and_clear_error_flags()?; |
| 205 | 232 | ||
| 206 | !T::regs().sr1().read().rxne() | 233 | !T::regs().sr1().read().rxne() |
| 207 | } {} | 234 | } { |
| 235 | check_timeout()?; | ||
| 236 | } | ||
| 208 | 237 | ||
| 209 | let value = T::regs().dr().read().dr(); | 238 | let value = T::regs().dr().read().dr(); |
| 210 | Ok(value) | 239 | Ok(value) |
| 211 | } | 240 | } |
| 212 | 241 | ||
| 213 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { | 242 | pub fn blocking_read_timeout( |
| 243 | &mut self, | ||
| 244 | addr: u8, | ||
| 245 | buffer: &mut [u8], | ||
| 246 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 247 | ) -> Result<(), Error> { | ||
| 214 | if let Some((last, buffer)) = buffer.split_last_mut() { | 248 | if let Some((last, buffer)) = buffer.split_last_mut() { |
| 215 | // Send a START condition and set ACK bit | 249 | // Send a START condition and set ACK bit |
| 216 | unsafe { | 250 | unsafe { |
| @@ -221,27 +255,33 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 221 | } | 255 | } |
| 222 | 256 | ||
| 223 | // Wait until START condition was generated | 257 | // Wait until START condition was generated |
| 224 | while unsafe { !T::regs().sr1().read().start() } {} | 258 | while unsafe { !self.check_and_clear_error_flags()?.start() } { |
| 259 | check_timeout()?; | ||
| 260 | } | ||
| 225 | 261 | ||
| 226 | // Also wait until signalled we're master and everything is waiting for us | 262 | // Also wait until signalled we're master and everything is waiting for us |
| 227 | while { | 263 | while { |
| 228 | let sr2 = unsafe { T::regs().sr2().read() }; | 264 | let sr2 = unsafe { T::regs().sr2().read() }; |
| 229 | !sr2.msl() && !sr2.busy() | 265 | !sr2.msl() && !sr2.busy() |
| 230 | } {} | 266 | } { |
| 267 | check_timeout()?; | ||
| 268 | } | ||
| 231 | 269 | ||
| 232 | // Set up current address, we're trying to talk to | 270 | // Set up current address, we're trying to talk to |
| 233 | unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } | 271 | unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } |
| 234 | 272 | ||
| 235 | // Wait until address was sent | 273 | // Wait until address was sent |
| 236 | // Wait for the address to be acknowledged | 274 | // Wait for the address to be acknowledged |
| 237 | while unsafe { !self.check_and_clear_error_flags()?.addr() } {} | 275 | while unsafe { !self.check_and_clear_error_flags()?.addr() } { |
| 276 | check_timeout()?; | ||
| 277 | } | ||
| 238 | 278 | ||
| 239 | // Clear condition by reading SR2 | 279 | // Clear condition by reading SR2 |
| 240 | let _ = unsafe { T::regs().sr2().read() }; | 280 | let _ = unsafe { T::regs().sr2().read() }; |
| 241 | 281 | ||
| 242 | // Receive bytes into buffer | 282 | // Receive bytes into buffer |
| 243 | for c in buffer { | 283 | for c in buffer { |
| 244 | *c = unsafe { self.recv_byte()? }; | 284 | *c = unsafe { self.recv_byte(&check_timeout)? }; |
| 245 | } | 285 | } |
| 246 | 286 | ||
| 247 | // Prepare to send NACK then STOP after next byte | 287 | // Prepare to send NACK then STOP after next byte |
| @@ -253,10 +293,12 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 253 | } | 293 | } |
| 254 | 294 | ||
| 255 | // Receive last byte | 295 | // Receive last byte |
| 256 | *last = unsafe { self.recv_byte()? }; | 296 | *last = unsafe { self.recv_byte(&check_timeout)? }; |
| 257 | 297 | ||
| 258 | // Wait for the STOP to be sent. | 298 | // Wait for the STOP to be sent. |
| 259 | while unsafe { T::regs().cr1().read().stop() } {} | 299 | while unsafe { T::regs().cr1().read().stop() } { |
| 300 | check_timeout()?; | ||
| 301 | } | ||
| 260 | 302 | ||
| 261 | // Fallthrough is success | 303 | // Fallthrough is success |
| 262 | Ok(()) | 304 | Ok(()) |
| @@ -265,25 +307,50 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 265 | } | 307 | } |
| 266 | } | 308 | } |
| 267 | 309 | ||
| 268 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 310 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 311 | self.blocking_read_timeout(addr, buffer, || Ok(())) | ||
| 312 | } | ||
| 313 | |||
| 314 | pub fn blocking_write_timeout( | ||
| 315 | &mut self, | ||
| 316 | addr: u8, | ||
| 317 | bytes: &[u8], | ||
| 318 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 319 | ) -> Result<(), Error> { | ||
| 269 | unsafe { | 320 | unsafe { |
| 270 | self.write_bytes(addr, bytes)?; | 321 | self.write_bytes(addr, bytes, &check_timeout)?; |
| 271 | // Send a STOP condition | 322 | // Send a STOP condition |
| 272 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | 323 | T::regs().cr1().modify(|reg| reg.set_stop(true)); |
| 273 | // Wait for STOP condition to transmit. | 324 | // Wait for STOP condition to transmit. |
| 274 | while T::regs().cr1().read().stop() {} | 325 | while T::regs().cr1().read().stop() { |
| 326 | check_timeout()?; | ||
| 327 | } | ||
| 275 | }; | 328 | }; |
| 276 | 329 | ||
| 277 | // Fallthrough is success | 330 | // Fallthrough is success |
| 278 | Ok(()) | 331 | Ok(()) |
| 279 | } | 332 | } |
| 280 | 333 | ||
| 281 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | 334 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { |
| 282 | unsafe { self.write_bytes(addr, bytes)? }; | 335 | self.blocking_write_timeout(addr, bytes, || Ok(())) |
| 283 | self.blocking_read(addr, buffer)?; | 336 | } |
| 337 | |||
| 338 | pub fn blocking_write_read_timeout( | ||
| 339 | &mut self, | ||
| 340 | addr: u8, | ||
| 341 | bytes: &[u8], | ||
| 342 | buffer: &mut [u8], | ||
| 343 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 344 | ) -> Result<(), Error> { | ||
| 345 | unsafe { self.write_bytes(addr, bytes, &check_timeout)? }; | ||
| 346 | self.blocking_read_timeout(addr, buffer, &check_timeout)?; | ||
| 284 | 347 | ||
| 285 | Ok(()) | 348 | Ok(()) |
| 286 | } | 349 | } |
| 350 | |||
| 351 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 352 | self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(())) | ||
| 353 | } | ||
| 287 | } | 354 | } |
| 288 | 355 | ||
| 289 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | 356 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 89b52da98..aa4e6bb08 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -147,14 +147,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) { | 150 | unsafe fn master_read( |
| 151 | address: u8, | ||
| 152 | length: usize, | ||
| 153 | stop: Stop, | ||
| 154 | reload: bool, | ||
| 155 | restart: bool, | ||
| 156 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 157 | ) -> Result<(), Error> { | ||
| 151 | assert!(length < 256); | 158 | assert!(length < 256); |
| 152 | 159 | ||
| 153 | if !restart { | 160 | if !restart { |
| 154 | // Wait for any previous address sequence to end | 161 | // Wait for any previous address sequence to end |
| 155 | // automatically. This could be up to 50% of a bus | 162 | // automatically. This could be up to 50% of a bus |
| 156 | // cycle (ie. up to 0.5/freq) | 163 | // cycle (ie. up to 0.5/freq) |
| 157 | while T::regs().cr2().read().start() {} | 164 | while T::regs().cr2().read().start() { |
| 165 | check_timeout()?; | ||
| 166 | } | ||
| 158 | } | 167 | } |
| 159 | 168 | ||
| 160 | // Set START and prepare to receive bytes into | 169 | // Set START and prepare to receive bytes into |
| @@ -176,15 +185,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 176 | w.set_autoend(stop.autoend()); | 185 | w.set_autoend(stop.autoend()); |
| 177 | w.set_reload(reload); | 186 | w.set_reload(reload); |
| 178 | }); | 187 | }); |
| 188 | |||
| 189 | Ok(()) | ||
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) { | 192 | unsafe fn master_write( |
| 193 | address: u8, | ||
| 194 | length: usize, | ||
| 195 | stop: Stop, | ||
| 196 | reload: bool, | ||
| 197 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 198 | ) -> Result<(), Error> { | ||
| 182 | assert!(length < 256); | 199 | assert!(length < 256); |
| 183 | 200 | ||
| 184 | // Wait for any previous address sequence to end | 201 | // Wait for any previous address sequence to end |
| 185 | // automatically. This could be up to 50% of a bus | 202 | // automatically. This could be up to 50% of a bus |
| 186 | // cycle (ie. up to 0.5/freq) | 203 | // cycle (ie. up to 0.5/freq) |
| 187 | while T::regs().cr2().read().start() {} | 204 | while T::regs().cr2().read().start() { |
| 205 | check_timeout()?; | ||
| 206 | } | ||
| 188 | 207 | ||
| 189 | let reload = if reload { | 208 | let reload = if reload { |
| 190 | i2c::vals::Reload::NOTCOMPLETED | 209 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -204,12 +223,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 204 | w.set_autoend(stop.autoend()); | 223 | w.set_autoend(stop.autoend()); |
| 205 | w.set_reload(reload); | 224 | w.set_reload(reload); |
| 206 | }); | 225 | }); |
| 226 | |||
| 227 | Ok(()) | ||
| 207 | } | 228 | } |
| 208 | 229 | ||
| 209 | unsafe fn master_continue(length: usize, reload: bool) { | 230 | unsafe fn master_continue( |
| 231 | length: usize, | ||
| 232 | reload: bool, | ||
| 233 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 234 | ) -> Result<(), Error> { | ||
| 210 | assert!(length < 256 && length > 0); | 235 | assert!(length < 256 && length > 0); |
| 211 | 236 | ||
| 212 | while !T::regs().isr().read().tcr() {} | 237 | while !T::regs().isr().read().tcr() { |
| 238 | check_timeout()?; | ||
| 239 | } | ||
| 213 | 240 | ||
| 214 | let reload = if reload { | 241 | let reload = if reload { |
| 215 | i2c::vals::Reload::NOTCOMPLETED | 242 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -221,6 +248,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 221 | w.set_nbytes(length as u8); | 248 | w.set_nbytes(length as u8); |
| 222 | w.set_reload(reload); | 249 | w.set_reload(reload); |
| 223 | }); | 250 | }); |
| 251 | |||
| 252 | Ok(()) | ||
| 224 | } | 253 | } |
| 225 | 254 | ||
| 226 | fn flush_txdr(&self) { | 255 | fn flush_txdr(&self) { |
| @@ -243,7 +272,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 243 | //} | 272 | //} |
| 244 | } | 273 | } |
| 245 | 274 | ||
| 246 | fn wait_txe(&self) -> Result<(), Error> { | 275 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 247 | loop { | 276 | loop { |
| 248 | unsafe { | 277 | unsafe { |
| 249 | let isr = T::regs().isr().read(); | 278 | let isr = T::regs().isr().read(); |
| @@ -261,10 +290,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 261 | return Err(Error::Nack); | 290 | return Err(Error::Nack); |
| 262 | } | 291 | } |
| 263 | } | 292 | } |
| 293 | |||
| 294 | check_timeout()?; | ||
| 264 | } | 295 | } |
| 265 | } | 296 | } |
| 266 | 297 | ||
| 267 | fn wait_rxne(&self) -> Result<(), Error> { | 298 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 268 | loop { | 299 | loop { |
| 269 | unsafe { | 300 | unsafe { |
| 270 | let isr = T::regs().isr().read(); | 301 | let isr = T::regs().isr().read(); |
| @@ -282,10 +313,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 282 | return Err(Error::Nack); | 313 | return Err(Error::Nack); |
| 283 | } | 314 | } |
| 284 | } | 315 | } |
| 316 | |||
| 317 | check_timeout()?; | ||
| 285 | } | 318 | } |
| 286 | } | 319 | } |
| 287 | 320 | ||
| 288 | fn wait_tc(&self) -> Result<(), Error> { | 321 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 289 | loop { | 322 | loop { |
| 290 | unsafe { | 323 | unsafe { |
| 291 | let isr = T::regs().isr().read(); | 324 | let isr = T::regs().isr().read(); |
| @@ -303,10 +336,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 303 | return Err(Error::Nack); | 336 | return Err(Error::Nack); |
| 304 | } | 337 | } |
| 305 | } | 338 | } |
| 339 | |||
| 340 | check_timeout()?; | ||
| 306 | } | 341 | } |
| 307 | } | 342 | } |
| 308 | 343 | ||
| 309 | fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { | 344 | fn read_internal( |
| 345 | &mut self, | ||
| 346 | address: u8, | ||
| 347 | buffer: &mut [u8], | ||
| 348 | restart: bool, | ||
| 349 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 350 | ) -> Result<(), Error> { | ||
| 310 | let completed_chunks = buffer.len() / 255; | 351 | let completed_chunks = buffer.len() / 255; |
| 311 | let total_chunks = if completed_chunks * 255 == buffer.len() { | 352 | let total_chunks = if completed_chunks * 255 == buffer.len() { |
| 312 | completed_chunks | 353 | completed_chunks |
| @@ -322,20 +363,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 322 | Stop::Automatic, | 363 | Stop::Automatic, |
| 323 | last_chunk_idx != 0, | 364 | last_chunk_idx != 0, |
| 324 | restart, | 365 | restart, |
| 325 | ); | 366 | &check_timeout, |
| 367 | )?; | ||
| 326 | } | 368 | } |
| 327 | 369 | ||
| 328 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { | 370 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { |
| 329 | if number != 0 { | 371 | if number != 0 { |
| 330 | // NOTE(unsafe) We have &mut self | 372 | // NOTE(unsafe) We have &mut self |
| 331 | unsafe { | 373 | unsafe { |
| 332 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 374 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 333 | } | 375 | } |
| 334 | } | 376 | } |
| 335 | 377 | ||
| 336 | for byte in chunk { | 378 | for byte in chunk { |
| 337 | // Wait until we have received something | 379 | // Wait until we have received something |
| 338 | self.wait_rxne()?; | 380 | self.wait_rxne(&check_timeout)?; |
| 339 | 381 | ||
| 340 | unsafe { | 382 | unsafe { |
| 341 | *byte = T::regs().rxdr().read().rxdata(); | 383 | *byte = T::regs().rxdr().read().rxdata(); |
| @@ -345,7 +387,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 345 | Ok(()) | 387 | Ok(()) |
| 346 | } | 388 | } |
| 347 | 389 | ||
| 348 | fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | 390 | fn write_internal( |
| 391 | &mut self, | ||
| 392 | address: u8, | ||
| 393 | bytes: &[u8], | ||
| 394 | send_stop: bool, | ||
| 395 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 396 | ) -> Result<(), Error> { | ||
| 349 | let completed_chunks = bytes.len() / 255; | 397 | let completed_chunks = bytes.len() / 255; |
| 350 | let total_chunks = if completed_chunks * 255 == bytes.len() { | 398 | let total_chunks = if completed_chunks * 255 == bytes.len() { |
| 351 | completed_chunks | 399 | completed_chunks |
| @@ -359,14 +407,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 359 | // ST SAD+W | 407 | // ST SAD+W |
| 360 | // NOTE(unsafe) We have &mut self | 408 | // NOTE(unsafe) We have &mut self |
| 361 | unsafe { | 409 | unsafe { |
| 362 | Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0); | 410 | Self::master_write( |
| 411 | address, | ||
| 412 | bytes.len().min(255), | ||
| 413 | Stop::Software, | ||
| 414 | last_chunk_idx != 0, | ||
| 415 | &check_timeout, | ||
| 416 | )?; | ||
| 363 | } | 417 | } |
| 364 | 418 | ||
| 365 | for (number, chunk) in bytes.chunks(255).enumerate() { | 419 | for (number, chunk) in bytes.chunks(255).enumerate() { |
| 366 | if number != 0 { | 420 | if number != 0 { |
| 367 | // NOTE(unsafe) We have &mut self | 421 | // NOTE(unsafe) We have &mut self |
| 368 | unsafe { | 422 | unsafe { |
| 369 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 423 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 370 | } | 424 | } |
| 371 | } | 425 | } |
| 372 | 426 | ||
| @@ -374,7 +428,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 374 | // Wait until we are allowed to send data | 428 | // Wait until we are allowed to send data |
| 375 | // (START has been ACKed or last byte when | 429 | // (START has been ACKed or last byte when |
| 376 | // through) | 430 | // through) |
| 377 | self.wait_txe()?; | 431 | self.wait_txe(&check_timeout)?; |
| 378 | 432 | ||
| 379 | unsafe { | 433 | unsafe { |
| 380 | T::regs().txdr().write(|w| w.set_txdata(*byte)); | 434 | T::regs().txdr().write(|w| w.set_txdata(*byte)); |
| @@ -382,7 +436,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 382 | } | 436 | } |
| 383 | } | 437 | } |
| 384 | // Wait until the write finishes | 438 | // Wait until the write finishes |
| 385 | self.wait_tc()?; | 439 | self.wait_tc(&check_timeout)?; |
| 386 | 440 | ||
| 387 | if send_stop { | 441 | if send_stop { |
| 388 | self.master_stop(); | 442 | self.master_stop(); |
| @@ -396,6 +450,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 396 | bytes: &[u8], | 450 | bytes: &[u8], |
| 397 | first_slice: bool, | 451 | first_slice: bool, |
| 398 | last_slice: bool, | 452 | last_slice: bool, |
| 453 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 399 | ) -> Result<(), Error> | 454 | ) -> Result<(), Error> |
| 400 | where | 455 | where |
| 401 | TXDMA: crate::i2c::TxDma<T>, | 456 | TXDMA: crate::i2c::TxDma<T>, |
| @@ -447,11 +502,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 447 | total_len.min(255), | 502 | total_len.min(255), |
| 448 | Stop::Software, | 503 | Stop::Software, |
| 449 | (total_chunks != 1) || !last_slice, | 504 | (total_chunks != 1) || !last_slice, |
| 450 | ); | 505 | &check_timeout, |
| 506 | )?; | ||
| 451 | } | 507 | } |
| 452 | } else { | 508 | } else { |
| 453 | unsafe { | 509 | unsafe { |
| 454 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice); | 510 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?; |
| 455 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 511 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 456 | } | 512 | } |
| 457 | } | 513 | } |
| @@ -461,32 +517,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 461 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 517 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 462 | 518 | ||
| 463 | if chunks_transferred == total_chunks { | 519 | if chunks_transferred == total_chunks { |
| 464 | return Poll::Ready(()); | 520 | return Poll::Ready(Ok(())); |
| 465 | } else if chunks_transferred != 0 { | 521 | } else if chunks_transferred != 0 { |
| 466 | remaining_len = remaining_len.saturating_sub(255); | 522 | remaining_len = remaining_len.saturating_sub(255); |
| 467 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; | 523 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; |
| 468 | 524 | ||
| 469 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | 525 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers |
| 470 | unsafe { | 526 | unsafe { |
| 471 | Self::master_continue(remaining_len.min(255), !last_piece); | 527 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 528 | return Poll::Ready(Err(e)); | ||
| 529 | } | ||
| 472 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 530 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 473 | } | 531 | } |
| 474 | } | 532 | } |
| 475 | Poll::Pending | 533 | Poll::Pending |
| 476 | }) | 534 | }) |
| 477 | .await; | 535 | .await?; |
| 478 | 536 | ||
| 479 | dma_transfer.await; | 537 | dma_transfer.await; |
| 480 | 538 | ||
| 481 | if last_slice { | 539 | if last_slice { |
| 482 | // This should be done already | 540 | // This should be done already |
| 483 | self.wait_tc()?; | 541 | self.wait_tc(&check_timeout)?; |
| 484 | self.master_stop(); | 542 | self.master_stop(); |
| 485 | } | 543 | } |
| 486 | Ok(()) | 544 | Ok(()) |
| 487 | } | 545 | } |
| 488 | 546 | ||
| 489 | async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> | 547 | async fn read_dma_internal( |
| 548 | &mut self, | ||
| 549 | address: u8, | ||
| 550 | buffer: &mut [u8], | ||
| 551 | restart: bool, | ||
| 552 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 553 | ) -> Result<(), Error> | ||
| 490 | where | 554 | where |
| 491 | RXDMA: crate::i2c::RxDma<T>, | 555 | RXDMA: crate::i2c::RxDma<T>, |
| 492 | { | 556 | { |
| @@ -527,7 +591,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 527 | 591 | ||
| 528 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 592 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 529 | unsafe { | 593 | unsafe { |
| 530 | Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart); | 594 | Self::master_read( |
| 595 | address, | ||
| 596 | total_len.min(255), | ||
| 597 | Stop::Software, | ||
| 598 | total_chunks != 1, | ||
| 599 | restart, | ||
| 600 | &check_timeout, | ||
| 601 | )?; | ||
| 531 | } | 602 | } |
| 532 | 603 | ||
| 533 | poll_fn(|cx| { | 604 | poll_fn(|cx| { |
| @@ -535,25 +606,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 535 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 606 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 536 | 607 | ||
| 537 | if chunks_transferred == total_chunks { | 608 | if chunks_transferred == total_chunks { |
| 538 | return Poll::Ready(()); | 609 | return Poll::Ready(Ok(())); |
| 539 | } else if chunks_transferred != 0 { | 610 | } else if chunks_transferred != 0 { |
| 540 | remaining_len = remaining_len.saturating_sub(255); | 611 | remaining_len = remaining_len.saturating_sub(255); |
| 541 | let last_piece = chunks_transferred + 1 == total_chunks; | 612 | let last_piece = chunks_transferred + 1 == total_chunks; |
| 542 | 613 | ||
| 543 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 614 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 544 | unsafe { | 615 | unsafe { |
| 545 | Self::master_continue(remaining_len.min(255), !last_piece); | 616 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 617 | return Poll::Ready(Err(e)); | ||
| 618 | } | ||
| 546 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 619 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 547 | } | 620 | } |
| 548 | } | 621 | } |
| 549 | Poll::Pending | 622 | Poll::Pending |
| 550 | }) | 623 | }) |
| 551 | .await; | 624 | .await?; |
| 552 | 625 | ||
| 553 | dma_transfer.await; | 626 | dma_transfer.await; |
| 554 | 627 | ||
| 555 | // This should be done already | 628 | // This should be done already |
| 556 | self.wait_tc()?; | 629 | self.wait_tc(&check_timeout)?; |
| 557 | self.master_stop(); | 630 | self.master_stop(); |
| 558 | Ok(()) | 631 | Ok(()) |
| 559 | } | 632 | } |
| @@ -566,9 +639,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 566 | TXDMA: crate::i2c::TxDma<T>, | 639 | TXDMA: crate::i2c::TxDma<T>, |
| 567 | { | 640 | { |
| 568 | if bytes.is_empty() { | 641 | if bytes.is_empty() { |
| 569 | self.write_internal(address, bytes, true) | 642 | self.write_internal(address, bytes, true, || Ok(())) |
| 570 | } else { | 643 | } else { |
| 571 | self.write_dma_internal(address, bytes, true, true).await | 644 | self.write_dma_internal(address, bytes, true, true, || Ok(())).await |
| 572 | } | 645 | } |
| 573 | } | 646 | } |
| 574 | 647 | ||
| @@ -587,7 +660,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 587 | let next = iter.next(); | 660 | let next = iter.next(); |
| 588 | let is_last = next.is_none(); | 661 | let is_last = next.is_none(); |
| 589 | 662 | ||
| 590 | self.write_dma_internal(address, c, first, is_last).await?; | 663 | self.write_dma_internal(address, c, first, is_last, || Ok(())).await?; |
| 591 | first = false; | 664 | first = false; |
| 592 | current = next; | 665 | current = next; |
| 593 | } | 666 | } |
| @@ -599,9 +672,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 599 | RXDMA: crate::i2c::RxDma<T>, | 672 | RXDMA: crate::i2c::RxDma<T>, |
| 600 | { | 673 | { |
| 601 | if buffer.is_empty() { | 674 | if buffer.is_empty() { |
| 602 | self.read_internal(address, buffer, false) | 675 | self.read_internal(address, buffer, false, || Ok(())) |
| 603 | } else { | 676 | } else { |
| 604 | self.read_dma_internal(address, buffer, false).await | 677 | self.read_dma_internal(address, buffer, false, || Ok(())).await |
| 605 | } | 678 | } |
| 606 | } | 679 | } |
| 607 | 680 | ||
| @@ -611,15 +684,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 611 | RXDMA: super::RxDma<T>, | 684 | RXDMA: super::RxDma<T>, |
| 612 | { | 685 | { |
| 613 | if bytes.is_empty() { | 686 | if bytes.is_empty() { |
| 614 | self.write_internal(address, bytes, false)?; | 687 | self.write_internal(address, bytes, false, || Ok(()))?; |
| 615 | } else { | 688 | } else { |
| 616 | self.write_dma_internal(address, bytes, true, true).await?; | 689 | self.write_dma_internal(address, bytes, true, true, || Ok(())).await?; |
| 617 | } | 690 | } |
| 618 | 691 | ||
| 619 | if buffer.is_empty() { | 692 | if buffer.is_empty() { |
| 620 | self.read_internal(address, buffer, true)?; | 693 | self.read_internal(address, buffer, true, || Ok(()))?; |
| 621 | } else { | 694 | } else { |
| 622 | self.read_dma_internal(address, buffer, true).await?; | 695 | self.read_dma_internal(address, buffer, true, || Ok(())).await?; |
| 623 | } | 696 | } |
| 624 | 697 | ||
| 625 | Ok(()) | 698 | Ok(()) |
| @@ -628,22 +701,55 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 628 | // ========================= | 701 | // ========================= |
| 629 | // Blocking public API | 702 | // Blocking public API |
| 630 | 703 | ||
| 631 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 704 | pub fn blocking_read_timeout( |
| 632 | self.read_internal(address, buffer, false) | 705 | &mut self, |
| 706 | address: u8, | ||
| 707 | buffer: &mut [u8], | ||
| 708 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 709 | ) -> Result<(), Error> { | ||
| 710 | self.read_internal(address, buffer, false, &check_timeout) | ||
| 633 | // Automatic Stop | 711 | // Automatic Stop |
| 634 | } | 712 | } |
| 635 | 713 | ||
| 714 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 715 | self.blocking_read_timeout(address, buffer, || Ok(())) | ||
| 716 | } | ||
| 717 | |||
| 718 | pub fn blocking_write_timeout( | ||
| 719 | &mut self, | ||
| 720 | address: u8, | ||
| 721 | bytes: &[u8], | ||
| 722 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 723 | ) -> Result<(), Error> { | ||
| 724 | self.write_internal(address, bytes, true, &check_timeout) | ||
| 725 | } | ||
| 726 | |||
| 636 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | 727 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { |
| 637 | self.write_internal(address, bytes, true) | 728 | self.blocking_write_timeout(address, bytes, || Ok(())) |
| 638 | } | 729 | } |
| 639 | 730 | ||
| 640 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | 731 | pub fn blocking_write_read_timeout( |
| 641 | self.write_internal(address, bytes, false)?; | 732 | &mut self, |
| 642 | self.read_internal(address, buffer, true) | 733 | address: u8, |
| 734 | bytes: &[u8], | ||
| 735 | buffer: &mut [u8], | ||
| 736 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 737 | ) -> Result<(), Error> { | ||
| 738 | self.write_internal(address, bytes, false, &check_timeout)?; | ||
| 739 | self.read_internal(address, buffer, true, &check_timeout) | ||
| 643 | // Automatic Stop | 740 | // Automatic Stop |
| 644 | } | 741 | } |
| 645 | 742 | ||
| 646 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | 743 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { |
| 744 | self.blocking_write_read_timeout(address, bytes, buffer, || Ok(())) | ||
| 745 | } | ||
| 746 | |||
| 747 | pub fn blocking_write_vectored_timeout( | ||
| 748 | &mut self, | ||
| 749 | address: u8, | ||
| 750 | bytes: &[&[u8]], | ||
| 751 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 752 | ) -> Result<(), Error> { | ||
| 647 | if bytes.is_empty() { | 753 | if bytes.is_empty() { |
| 648 | return Err(Error::ZeroLengthTransfer); | 754 | return Err(Error::ZeroLengthTransfer); |
| 649 | } | 755 | } |
| @@ -657,7 +763,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 657 | first_length.min(255), | 763 | first_length.min(255), |
| 658 | Stop::Software, | 764 | Stop::Software, |
| 659 | (first_length > 255) || (last_slice_index != 0), | 765 | (first_length > 255) || (last_slice_index != 0), |
| 660 | ); | 766 | &check_timeout, |
| 767 | )?; | ||
| 661 | } | 768 | } |
| 662 | 769 | ||
| 663 | for (idx, slice) in bytes.iter().enumerate() { | 770 | for (idx, slice) in bytes.iter().enumerate() { |
| @@ -673,7 +780,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 673 | if idx != 0 { | 780 | if idx != 0 { |
| 674 | // NOTE(unsafe) We have &mut self | 781 | // NOTE(unsafe) We have &mut self |
| 675 | unsafe { | 782 | unsafe { |
| 676 | Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255)); | 783 | Self::master_continue( |
| 784 | slice_len.min(255), | ||
| 785 | (idx != last_slice_index) || (slice_len > 255), | ||
| 786 | &check_timeout, | ||
| 787 | )?; | ||
| 677 | } | 788 | } |
| 678 | } | 789 | } |
| 679 | 790 | ||
| @@ -681,7 +792,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 681 | if number != 0 { | 792 | if number != 0 { |
| 682 | // NOTE(unsafe) We have &mut self | 793 | // NOTE(unsafe) We have &mut self |
| 683 | unsafe { | 794 | unsafe { |
| 684 | Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index)); | 795 | Self::master_continue( |
| 796 | chunk.len(), | ||
| 797 | (number != last_chunk_idx) || (idx != last_slice_index), | ||
| 798 | &check_timeout, | ||
| 799 | )?; | ||
| 685 | } | 800 | } |
| 686 | } | 801 | } |
| 687 | 802 | ||
| @@ -689,7 +804,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 689 | // Wait until we are allowed to send data | 804 | // Wait until we are allowed to send data |
| 690 | // (START has been ACKed or last byte when | 805 | // (START has been ACKed or last byte when |
| 691 | // through) | 806 | // through) |
| 692 | self.wait_txe()?; | 807 | self.wait_txe(&check_timeout)?; |
| 693 | 808 | ||
| 694 | // Put byte on the wire | 809 | // Put byte on the wire |
| 695 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); | 810 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); |
| @@ -700,11 +815,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 700 | } | 815 | } |
| 701 | } | 816 | } |
| 702 | // Wait until the write finishes | 817 | // Wait until the write finishes |
| 703 | self.wait_tc()?; | 818 | self.wait_tc(&check_timeout)?; |
| 704 | self.master_stop(); | 819 | self.master_stop(); |
| 705 | 820 | ||
| 706 | Ok(()) | 821 | Ok(()) |
| 707 | } | 822 | } |
| 823 | |||
| 824 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | ||
| 825 | self.blocking_write_vectored_timeout(address, bytes, || Ok(())) | ||
| 826 | } | ||
| 708 | } | 827 | } |
| 709 | 828 | ||
| 710 | mod eh02 { | 829 | mod eh02 { |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 0392e8086..bcf2feee8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -52,7 +52,7 @@ pub mod sdmmc; | |||
| 52 | pub mod spi; | 52 | pub mod spi; |
| 53 | #[cfg(usart)] | 53 | #[cfg(usart)] |
| 54 | pub mod usart; | 54 | pub mod usart; |
| 55 | #[cfg(usb)] | 55 | #[cfg(all(usb, feature = "time"))] |
| 56 | pub mod usb; | 56 | pub mod usb; |
| 57 | #[cfg(any(otgfs, otghs))] | 57 | #[cfg(any(otgfs, otghs))] |
| 58 | pub mod usb_otg; | 58 | pub mod usb_otg; |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index a8bc6385f..c91f3c8bf 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -1534,14 +1534,14 @@ mod sdmmc_rs { | |||
| 1534 | 1534 | ||
| 1535 | impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> { | 1535 | impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> { |
| 1536 | type Error = Error; | 1536 | type Error = Error; |
| 1537 | type ReadFuture<'a> | 1537 | |
| 1538 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 1538 | where | 1539 | where |
| 1539 | Self: 'a, | 1540 | Self: 'a; |
| 1540 | = impl Future<Output = Result<(), Self::Error>> + 'a; | 1541 | |
| 1541 | type WriteFuture<'a> | 1542 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 1542 | where | 1543 | where |
| 1543 | Self: 'a, | 1544 | Self: 'a; |
| 1544 | = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 1545 | 1545 | ||
| 1546 | fn read<'a>( | 1546 | fn read<'a>( |
| 1547 | &'a mut self, | 1547 | &'a mut self, |
diff --git a/embassy-stm32/src/subghz/timeout.rs b/embassy-stm32/src/subghz/timeout.rs index 28b3b0c21..0ae49dd90 100644 --- a/embassy-stm32/src/subghz/timeout.rs +++ b/embassy-stm32/src/subghz/timeout.rs | |||
| @@ -439,6 +439,7 @@ impl From<Timeout> for [u8; 3] { | |||
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | #[cfg(feature = "time")] | ||
| 442 | impl From<Timeout> for embassy_time::Duration { | 443 | impl From<Timeout> for embassy_time::Duration { |
| 443 | fn from(to: Timeout) -> Self { | 444 | fn from(to: Timeout) -> Self { |
| 444 | embassy_time::Duration::from_micros(to.as_micros().into()) | 445 | embassy_time::Duration::from_micros(to.as_micros().into()) |
diff --git a/embassy-stm32/src/subghz/tx_params.rs b/embassy-stm32/src/subghz/tx_params.rs index cede6f2c1..03bdb1ea8 100644 --- a/embassy-stm32/src/subghz/tx_params.rs +++ b/embassy-stm32/src/subghz/tx_params.rs | |||
| @@ -44,6 +44,7 @@ impl From<RampTime> for core::time::Duration { | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | #[cfg(feature = "time")] | ||
| 47 | impl From<RampTime> for embassy_time::Duration { | 48 | impl From<RampTime> for embassy_time::Duration { |
| 48 | fn from(rt: RampTime) -> Self { | 49 | fn from(rt: RampTime) -> Self { |
| 49 | match rt { | 50 | match rt { |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index ed3225c51..8e84570a4 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -292,19 +292,23 @@ impl Driver for RtcDriver { | |||
| 292 | }) | 292 | }) |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 295 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 296 | critical_section::with(|cs| { | 296 | critical_section::with(|cs| { |
| 297 | let r = T::regs_gp16(); | 297 | let r = T::regs_gp16(); |
| 298 | 298 | ||
| 299 | let n = alarm.id() as _; | 299 | let n = alarm.id() as usize; |
| 300 | let alarm = self.get_alarm(cs, alarm); | 300 | let alarm = self.get_alarm(cs, alarm); |
| 301 | alarm.timestamp.set(timestamp); | 301 | alarm.timestamp.set(timestamp); |
| 302 | 302 | ||
| 303 | let t = self.now(); | 303 | let t = self.now(); |
| 304 | if timestamp <= t { | 304 | if timestamp <= t { |
| 305 | // If alarm timestamp has passed the alarm will not fire. | ||
| 306 | // Disarm the alarm and return `false` to indicate that. | ||
| 305 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; | 307 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; |
| 306 | self.trigger_alarm(n, cs); | 308 | |
| 307 | return; | 309 | alarm.timestamp.set(u64::MAX); |
| 310 | |||
| 311 | return false; | ||
| 308 | } | 312 | } |
| 309 | 313 | ||
| 310 | let safe_timestamp = timestamp.max(t + 3); | 314 | let safe_timestamp = timestamp.max(t + 3); |
| @@ -317,6 +321,8 @@ impl Driver for RtcDriver { | |||
| 317 | let diff = timestamp - t; | 321 | let diff = timestamp - t; |
| 318 | // NOTE(unsafe) We're in a critical section | 322 | // NOTE(unsafe) We're in a critical section |
| 319 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; | 323 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; |
| 324 | |||
| 325 | true | ||
| 320 | }) | 326 | }) |
| 321 | } | 327 | } |
| 322 | } | 328 | } |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 2a711bc06..3be0677bd 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -46,16 +46,44 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} | |||
| 46 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 46 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 47 | pub fn new( | 47 | pub fn new( |
| 48 | state: &'d mut State<'d, T>, | 48 | state: &'d mut State<'d, T>, |
| 49 | _uart: Uart<'d, T, NoDma, NoDma>, | 49 | _peri: impl Peripheral<P = T> + 'd, |
| 50 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 51 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 50 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 52 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| 51 | tx_buffer: &'d mut [u8], | 53 | tx_buffer: &'d mut [u8], |
| 52 | rx_buffer: &'d mut [u8], | 54 | rx_buffer: &'d mut [u8], |
| 55 | config: Config, | ||
| 53 | ) -> BufferedUart<'d, T> { | 56 | ) -> BufferedUart<'d, T> { |
| 54 | into_ref!(irq); | 57 | into_ref!(_peri, rx, tx, irq); |
| 58 | |||
| 59 | T::enable(); | ||
| 60 | T::reset(); | ||
| 55 | 61 | ||
| 56 | let r = T::regs(); | 62 | let r = T::regs(); |
| 63 | |||
| 64 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 65 | |||
| 57 | unsafe { | 66 | unsafe { |
| 58 | r.cr1().modify(|w| { | 67 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 68 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 69 | |||
| 70 | r.cr2().write(|_w| {}); | ||
| 71 | r.cr3().write(|_w| {}); | ||
| 72 | r.cr1().write(|w| { | ||
| 73 | w.set_ue(true); | ||
| 74 | w.set_te(true); | ||
| 75 | w.set_re(true); | ||
| 76 | w.set_m0(if config.parity != Parity::ParityNone { | ||
| 77 | vals::M0::BIT9 | ||
| 78 | } else { | ||
| 79 | vals::M0::BIT8 | ||
| 80 | }); | ||
| 81 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 82 | w.set_ps(match config.parity { | ||
| 83 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 84 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 85 | _ => vals::Ps::EVEN, | ||
| 86 | }); | ||
| 59 | w.set_rxneie(true); | 87 | w.set_rxneie(true); |
| 60 | w.set_idleie(true); | 88 | w.set_idleie(true); |
| 61 | }); | 89 | }); |
| @@ -283,7 +311,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> { | |||
| 283 | } | 311 | } |
| 284 | 312 | ||
| 285 | impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { | 313 | impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { |
| 286 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 314 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 287 | where | 315 | where |
| 288 | Self: 'a; | 316 | Self: 'a; |
| 289 | 317 | ||
| @@ -293,7 +321,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { | |||
| 293 | } | 321 | } |
| 294 | 322 | ||
| 295 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> { | 323 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> { |
| 296 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 324 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 297 | where | 325 | where |
| 298 | Self: 'a; | 326 | Self: 'a; |
| 299 | 327 | ||
| @@ -303,7 +331,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, | |||
| 303 | } | 331 | } |
| 304 | 332 | ||
| 305 | impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | 333 | impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> { |
| 306 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 334 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 307 | where | 335 | where |
| 308 | Self: 'a; | 336 | Self: 'a; |
| 309 | 337 | ||
| @@ -317,7 +345,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> | |||
| 317 | } | 345 | } |
| 318 | 346 | ||
| 319 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> { | 347 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> { |
| 320 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | 348 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a |
| 321 | where | 349 | where |
| 322 | Self: 'a; | 350 | Self: 'a; |
| 323 | 351 | ||
| @@ -331,7 +359,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<' | |||
| 331 | } | 359 | } |
| 332 | 360 | ||
| 333 | impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | 361 | impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { |
| 334 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 362 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 335 | where | 363 | where |
| 336 | Self: 'a; | 364 | Self: 'a; |
| 337 | 365 | ||
| @@ -339,7 +367,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 339 | self.inner_write(buf) | 367 | self.inner_write(buf) |
| 340 | } | 368 | } |
| 341 | 369 | ||
| 342 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 370 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 343 | where | 371 | where |
| 344 | Self: 'a; | 372 | Self: 'a; |
| 345 | 373 | ||
| @@ -349,7 +377,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 349 | } | 377 | } |
| 350 | 378 | ||
| 351 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> { | 379 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> { |
| 352 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 380 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 353 | where | 381 | where |
| 354 | Self: 'a; | 382 | Self: 'a; |
| 355 | 383 | ||
| @@ -357,7 +385,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, | |||
| 357 | self.inner.inner_write(buf) | 385 | self.inner.inner_write(buf) |
| 358 | } | 386 | } |
| 359 | 387 | ||
| 360 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 388 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 361 | where | 389 | where |
| 362 | Self: 'a; | 390 | Self: 'a; |
| 363 | 391 | ||
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index a152a0c15..dee466b21 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | ||
| 3 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::task::Poll; | ||
| 4 | 6 | ||
| 7 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 8 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | 10 | ||
| 7 | use crate::dma::NoDma; | 11 | use crate::dma::NoDma; |
| @@ -10,6 +14,7 @@ use crate::gpio::sealed::AFType; | |||
| 10 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | 14 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; |
| 11 | #[cfg(not(any(lpuart_v1, lpuart_v2)))] | 15 | #[cfg(not(any(lpuart_v1, lpuart_v2)))] |
| 12 | use crate::pac::usart::{regs, vals, Usart as Regs}; | 16 | use crate::pac::usart::{regs, vals, Usart as Regs}; |
| 17 | use crate::time::Hertz; | ||
| 13 | use crate::{peripherals, Peripheral}; | 18 | use crate::{peripherals, Peripheral}; |
| 14 | 19 | ||
| 15 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 20 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| @@ -44,6 +49,10 @@ pub struct Config { | |||
| 44 | pub data_bits: DataBits, | 49 | pub data_bits: DataBits, |
| 45 | pub stop_bits: StopBits, | 50 | pub stop_bits: StopBits, |
| 46 | pub parity: Parity, | 51 | pub parity: Parity, |
| 52 | /// if true, on read-like method, if there is a latent error pending, | ||
| 53 | /// read will abort, the error reported and cleared | ||
| 54 | /// if false, the error is ignored and cleared | ||
| 55 | pub detect_previous_overrun: bool, | ||
| 47 | } | 56 | } |
| 48 | 57 | ||
| 49 | impl Default for Config { | 58 | impl Default for Config { |
| @@ -53,6 +62,8 @@ impl Default for Config { | |||
| 53 | data_bits: DataBits::DataBits8, | 62 | data_bits: DataBits::DataBits8, |
| 54 | stop_bits: StopBits::STOP1, | 63 | stop_bits: StopBits::STOP1, |
| 55 | parity: Parity::ParityNone, | 64 | parity: Parity::ParityNone, |
| 65 | // historical behavior | ||
| 66 | detect_previous_overrun: false, | ||
| 56 | } | 67 | } |
| 57 | } | 68 | } |
| 58 | } | 69 | } |
| @@ -70,10 +81,11 @@ pub enum Error { | |||
| 70 | Overrun, | 81 | Overrun, |
| 71 | /// Parity check error | 82 | /// Parity check error |
| 72 | Parity, | 83 | Parity, |
| 84 | /// Buffer too large for DMA | ||
| 85 | BufferTooLong, | ||
| 73 | } | 86 | } |
| 74 | 87 | ||
| 75 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 88 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { |
| 76 | phantom: PhantomData<&'d mut T>, | ||
| 77 | tx: UartTx<'d, T, TxDma>, | 89 | tx: UartTx<'d, T, TxDma>, |
| 78 | rx: UartRx<'d, T, RxDma>, | 90 | rx: UartRx<'d, T, RxDma>, |
| 79 | } | 91 | } |
| @@ -84,8 +96,9 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | |||
| 84 | } | 96 | } |
| 85 | 97 | ||
| 86 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 98 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { |
| 87 | phantom: PhantomData<&'d mut T>, | 99 | _peri: PeripheralRef<'d, T>, |
| 88 | rx_dma: PeripheralRef<'d, RxDma>, | 100 | rx_dma: PeripheralRef<'d, RxDma>, |
| 101 | detect_previous_overrun: bool, | ||
| 89 | } | 102 | } |
| 90 | 103 | ||
| 91 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | 104 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { |
| @@ -135,10 +148,112 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 135 | } | 148 | } |
| 136 | 149 | ||
| 137 | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | 150 | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { |
| 138 | fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self { | 151 | /// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power |
| 152 | pub fn new( | ||
| 153 | peri: impl Peripheral<P = T> + 'd, | ||
| 154 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 155 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 156 | rx_dma: impl Peripheral<P = RxDma> + 'd, | ||
| 157 | config: Config, | ||
| 158 | ) -> Self { | ||
| 159 | into_ref!(peri, irq, rx, rx_dma); | ||
| 160 | |||
| 161 | T::enable(); | ||
| 162 | T::reset(); | ||
| 163 | |||
| 164 | let r = T::regs(); | ||
| 165 | |||
| 166 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 167 | |||
| 168 | unsafe { | ||
| 169 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 170 | |||
| 171 | r.cr2().write(|_w| {}); | ||
| 172 | r.cr3().write(|w| { | ||
| 173 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 174 | w.set_eie(true); | ||
| 175 | }); | ||
| 176 | r.cr1().write(|w| { | ||
| 177 | // enable uart | ||
| 178 | w.set_ue(true); | ||
| 179 | // enable receiver | ||
| 180 | w.set_re(true); | ||
| 181 | // configure word size | ||
| 182 | w.set_m0(if config.parity != Parity::ParityNone { | ||
| 183 | vals::M0::BIT9 | ||
| 184 | } else { | ||
| 185 | vals::M0::BIT8 | ||
| 186 | }); | ||
| 187 | // configure parity | ||
| 188 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 189 | w.set_ps(match config.parity { | ||
| 190 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 191 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 192 | _ => vals::Ps::EVEN, | ||
| 193 | }); | ||
| 194 | }); | ||
| 195 | } | ||
| 196 | |||
| 197 | irq.set_handler(Self::on_interrupt); | ||
| 198 | irq.unpend(); | ||
| 199 | irq.enable(); | ||
| 200 | |||
| 201 | // create state once! | ||
| 202 | let _s = T::state(); | ||
| 203 | |||
| 139 | Self { | 204 | Self { |
| 205 | _peri: peri, | ||
| 140 | rx_dma, | 206 | rx_dma, |
| 141 | phantom: PhantomData, | 207 | detect_previous_overrun: config.detect_previous_overrun, |
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | fn on_interrupt(_: *mut ()) { | ||
| 212 | let r = T::regs(); | ||
| 213 | let s = T::state(); | ||
| 214 | |||
| 215 | let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; | ||
| 216 | |||
| 217 | let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); | ||
| 218 | |||
| 219 | if has_errors { | ||
| 220 | // clear all interrupts and DMA Rx Request | ||
| 221 | unsafe { | ||
| 222 | r.cr1().modify(|w| { | ||
| 223 | // disable RXNE interrupt | ||
| 224 | w.set_rxneie(false); | ||
| 225 | // disable parity interrupt | ||
| 226 | w.set_peie(false); | ||
| 227 | // disable idle line interrupt | ||
| 228 | w.set_idleie(false); | ||
| 229 | }); | ||
| 230 | r.cr3().modify(|w| { | ||
| 231 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 232 | w.set_eie(false); | ||
| 233 | // disable DMA Rx Request | ||
| 234 | w.set_dmar(false); | ||
| 235 | }); | ||
| 236 | } | ||
| 237 | |||
| 238 | compiler_fence(Ordering::SeqCst); | ||
| 239 | |||
| 240 | s.rx_waker.wake(); | ||
| 241 | } else if cr1.idleie() && sr.idle() { | ||
| 242 | // IDLE detected: no more data will come | ||
| 243 | unsafe { | ||
| 244 | r.cr1().modify(|w| { | ||
| 245 | // disable idle line detection | ||
| 246 | w.set_idleie(false); | ||
| 247 | }); | ||
| 248 | |||
| 249 | r.cr3().modify(|w| { | ||
| 250 | // disable DMA Rx Request | ||
| 251 | w.set_dmar(false); | ||
| 252 | }); | ||
| 253 | } | ||
| 254 | compiler_fence(Ordering::SeqCst); | ||
| 255 | |||
| 256 | s.rx_waker.wake(); | ||
| 142 | } | 257 | } |
| 143 | } | 258 | } |
| 144 | 259 | ||
| @@ -146,17 +261,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 146 | where | 261 | where |
| 147 | RxDma: crate::usart::RxDma<T>, | 262 | RxDma: crate::usart::RxDma<T>, |
| 148 | { | 263 | { |
| 149 | let ch = &mut self.rx_dma; | 264 | self.inner_read(buffer, false).await?; |
| 150 | let request = ch.request(); | 265 | |
| 151 | unsafe { | ||
| 152 | T::regs().cr3().modify(|reg| { | ||
| 153 | reg.set_dmar(true); | ||
| 154 | }); | ||
| 155 | } | ||
| 156 | // If we don't assign future to a variable, the data register pointer | ||
| 157 | // is held across an await and makes the future non-Send. | ||
| 158 | let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer); | ||
| 159 | transfer.await; | ||
| 160 | Ok(()) | 266 | Ok(()) |
| 161 | } | 267 | } |
| 162 | 268 | ||
| @@ -211,35 +317,259 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 211 | } | 317 | } |
| 212 | Ok(()) | 318 | Ok(()) |
| 213 | } | 319 | } |
| 320 | |||
| 321 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||
| 322 | where | ||
| 323 | RxDma: crate::usart::RxDma<T>, | ||
| 324 | { | ||
| 325 | self.inner_read(buffer, true).await | ||
| 326 | } | ||
| 327 | |||
| 328 | async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> | ||
| 329 | where | ||
| 330 | RxDma: crate::usart::RxDma<T>, | ||
| 331 | { | ||
| 332 | if buffer.is_empty() { | ||
| 333 | return Ok(0); | ||
| 334 | } else if buffer.len() > 0xFFFF { | ||
| 335 | return Err(Error::BufferTooLong); | ||
| 336 | } | ||
| 337 | |||
| 338 | let r = T::regs(); | ||
| 339 | |||
| 340 | let buffer_len = buffer.len(); | ||
| 341 | |||
| 342 | let ch = &mut self.rx_dma; | ||
| 343 | let request = ch.request(); | ||
| 344 | |||
| 345 | // SAFETY: The only way we might have a problem is using split rx and tx | ||
| 346 | // here we only modify or read Rx related flags, interrupts and DMA channel | ||
| 347 | unsafe { | ||
| 348 | // Start USART DMA | ||
| 349 | // will not do anything yet because DMAR is not yet set | ||
| 350 | ch.start_read(request, rdr(r), buffer, Default::default()); | ||
| 351 | |||
| 352 | // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer | ||
| 353 | if !self.detect_previous_overrun { | ||
| 354 | let sr = sr(r).read(); | ||
| 355 | // This read also clears the error and idle interrupt flags on v1. | ||
| 356 | rdr(r).read_volatile(); | ||
| 357 | clear_interrupt_flags(r, sr); | ||
| 358 | } | ||
| 359 | |||
| 360 | r.cr1().modify(|w| { | ||
| 361 | // disable RXNE interrupt | ||
| 362 | w.set_rxneie(false); | ||
| 363 | // enable parity interrupt if not ParityNone | ||
| 364 | w.set_peie(w.pce()); | ||
| 365 | }); | ||
| 366 | |||
| 367 | r.cr3().modify(|w| { | ||
| 368 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 369 | w.set_eie(true); | ||
| 370 | // enable DMA Rx Request | ||
| 371 | w.set_dmar(true); | ||
| 372 | }); | ||
| 373 | |||
| 374 | compiler_fence(Ordering::SeqCst); | ||
| 375 | |||
| 376 | // In case of errors already pending when reception started, interrupts may have already been raised | ||
| 377 | // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||
| 378 | // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||
| 379 | |||
| 380 | let cr3 = r.cr3().read(); | ||
| 381 | |||
| 382 | if !cr3.dmar() { | ||
| 383 | // something went wrong | ||
| 384 | // because the only way to get this flag cleared is to have an interrupt | ||
| 385 | |||
| 386 | // abort DMA transfer | ||
| 387 | ch.request_stop(); | ||
| 388 | while ch.is_running() {} | ||
| 389 | |||
| 390 | let sr = sr(r).read(); | ||
| 391 | // This read also clears the error and idle interrupt flags on v1. | ||
| 392 | rdr(r).read_volatile(); | ||
| 393 | clear_interrupt_flags(r, sr); | ||
| 394 | |||
| 395 | if sr.pe() { | ||
| 396 | return Err(Error::Parity); | ||
| 397 | } | ||
| 398 | if sr.fe() { | ||
| 399 | return Err(Error::Framing); | ||
| 400 | } | ||
| 401 | if sr.ne() { | ||
| 402 | return Err(Error::Noise); | ||
| 403 | } | ||
| 404 | if sr.ore() { | ||
| 405 | return Err(Error::Overrun); | ||
| 406 | } | ||
| 407 | |||
| 408 | unreachable!(); | ||
| 409 | } | ||
| 410 | |||
| 411 | // clear idle flag | ||
| 412 | if enable_idle_line_detection { | ||
| 413 | let sr = sr(r).read(); | ||
| 414 | // This read also clears the error and idle interrupt flags on v1. | ||
| 415 | rdr(r).read_volatile(); | ||
| 416 | clear_interrupt_flags(r, sr); | ||
| 417 | |||
| 418 | // enable idle interrupt | ||
| 419 | r.cr1().modify(|w| { | ||
| 420 | w.set_idleie(true); | ||
| 421 | }); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | compiler_fence(Ordering::SeqCst); | ||
| 426 | |||
| 427 | let res = poll_fn(move |cx| { | ||
| 428 | let s = T::state(); | ||
| 429 | |||
| 430 | ch.set_waker(cx.waker()); | ||
| 431 | s.rx_waker.register(cx.waker()); | ||
| 432 | |||
| 433 | // SAFETY: read only and we only use Rx related flags | ||
| 434 | let sr = unsafe { sr(r).read() }; | ||
| 435 | |||
| 436 | // SAFETY: only clears Rx related flags | ||
| 437 | unsafe { | ||
| 438 | // This read also clears the error and idle interrupt flags on v1. | ||
| 439 | rdr(r).read_volatile(); | ||
| 440 | clear_interrupt_flags(r, sr); | ||
| 441 | } | ||
| 442 | |||
| 443 | compiler_fence(Ordering::SeqCst); | ||
| 444 | |||
| 445 | let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); | ||
| 446 | |||
| 447 | if has_errors { | ||
| 448 | // all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler | ||
| 449 | |||
| 450 | // stop dma transfer | ||
| 451 | ch.request_stop(); | ||
| 452 | while ch.is_running() {} | ||
| 453 | |||
| 454 | if sr.pe() { | ||
| 455 | return Poll::Ready(Err(Error::Parity)); | ||
| 456 | } | ||
| 457 | if sr.fe() { | ||
| 458 | return Poll::Ready(Err(Error::Framing)); | ||
| 459 | } | ||
| 460 | if sr.ne() { | ||
| 461 | return Poll::Ready(Err(Error::Noise)); | ||
| 462 | } | ||
| 463 | if sr.ore() { | ||
| 464 | return Poll::Ready(Err(Error::Overrun)); | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | if sr.idle() { | ||
| 469 | // Idle line | ||
| 470 | |||
| 471 | // stop dma transfer | ||
| 472 | ch.request_stop(); | ||
| 473 | while ch.is_running() {} | ||
| 474 | |||
| 475 | let n = buffer_len - (ch.remaining_transfers() as usize); | ||
| 476 | |||
| 477 | return Poll::Ready(Ok(n)); | ||
| 478 | } else if !ch.is_running() { | ||
| 479 | // DMA complete | ||
| 480 | return Poll::Ready(Ok(buffer_len)); | ||
| 481 | } | ||
| 482 | |||
| 483 | Poll::Pending | ||
| 484 | }) | ||
| 485 | .await; | ||
| 486 | |||
| 487 | // clear all interrupts and DMA Rx Request | ||
| 488 | // SAFETY: only clears Rx related flags | ||
| 489 | unsafe { | ||
| 490 | r.cr1().modify(|w| { | ||
| 491 | // disable RXNE interrupt | ||
| 492 | w.set_rxneie(false); | ||
| 493 | // disable parity interrupt | ||
| 494 | w.set_peie(false); | ||
| 495 | // disable idle line interrupt | ||
| 496 | w.set_idleie(false); | ||
| 497 | }); | ||
| 498 | r.cr3().modify(|w| { | ||
| 499 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 500 | w.set_eie(false); | ||
| 501 | // disable DMA Rx Request | ||
| 502 | w.set_dmar(false); | ||
| 503 | }); | ||
| 504 | } | ||
| 505 | |||
| 506 | res | ||
| 507 | } | ||
| 214 | } | 508 | } |
| 215 | 509 | ||
| 216 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | 510 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { |
| 217 | pub fn new( | 511 | pub fn new( |
| 218 | _inner: impl Peripheral<P = T> + 'd, | 512 | peri: impl Peripheral<P = T> + 'd, |
| 219 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 513 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 220 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 514 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 515 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 221 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 516 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 222 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 517 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 223 | config: Config, | 518 | config: Config, |
| 224 | ) -> Self { | 519 | ) -> Self { |
| 225 | into_ref!(_inner, rx, tx, tx_dma, rx_dma); | 520 | T::enable(); |
| 521 | T::reset(); | ||
| 522 | |||
| 523 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) | ||
| 524 | } | ||
| 525 | |||
| 526 | pub fn new_with_rtscts( | ||
| 527 | peri: impl Peripheral<P = T> + 'd, | ||
| 528 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 529 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 530 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 531 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | ||
| 532 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | ||
| 533 | tx_dma: impl Peripheral<P = TxDma> + 'd, | ||
| 534 | rx_dma: impl Peripheral<P = RxDma> + 'd, | ||
| 535 | config: Config, | ||
| 536 | ) -> Self { | ||
| 537 | into_ref!(cts, rts); | ||
| 226 | 538 | ||
| 227 | T::enable(); | 539 | T::enable(); |
| 228 | T::reset(); | 540 | T::reset(); |
| 229 | let pclk_freq = T::frequency(); | ||
| 230 | 541 | ||
| 231 | // TODO: better calculation, including error checking and OVER8 if possible. | 542 | unsafe { |
| 232 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER; | 543 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); |
| 544 | cts.set_as_af(cts.af_num(), AFType::Input); | ||
| 545 | T::regs().cr3().write(|w| { | ||
| 546 | w.set_rtse(true); | ||
| 547 | w.set_ctse(true); | ||
| 548 | }); | ||
| 549 | } | ||
| 550 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) | ||
| 551 | } | ||
| 552 | |||
| 553 | fn new_inner( | ||
| 554 | peri: impl Peripheral<P = T> + 'd, | ||
| 555 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 556 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 557 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 558 | tx_dma: impl Peripheral<P = TxDma> + 'd, | ||
| 559 | rx_dma: impl Peripheral<P = RxDma> + 'd, | ||
| 560 | config: Config, | ||
| 561 | ) -> Self { | ||
| 562 | into_ref!(peri, rx, tx, irq, tx_dma, rx_dma); | ||
| 233 | 563 | ||
| 234 | let r = T::regs(); | 564 | let r = T::regs(); |
| 235 | 565 | ||
| 566 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 567 | |||
| 236 | unsafe { | 568 | unsafe { |
| 237 | rx.set_as_af(rx.af_num(), AFType::Input); | 569 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 238 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 570 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 239 | 571 | ||
| 240 | r.cr2().write(|_w| {}); | 572 | r.cr2().write(|_w| {}); |
| 241 | r.cr3().write(|_w| {}); | ||
| 242 | r.brr().write_value(regs::Brr(div)); | ||
| 243 | r.cr1().write(|w| { | 573 | r.cr1().write(|w| { |
| 244 | w.set_ue(true); | 574 | w.set_ue(true); |
| 245 | w.set_te(true); | 575 | w.set_te(true); |
| @@ -258,10 +588,20 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 258 | }); | 588 | }); |
| 259 | } | 589 | } |
| 260 | 590 | ||
| 591 | irq.set_handler(UartRx::<T, RxDma>::on_interrupt); | ||
| 592 | irq.unpend(); | ||
| 593 | irq.enable(); | ||
| 594 | |||
| 595 | // create state once! | ||
| 596 | let _s = T::state(); | ||
| 597 | |||
| 261 | Self { | 598 | Self { |
| 262 | tx: UartTx::new(tx_dma), | 599 | tx: UartTx::new(tx_dma), |
| 263 | rx: UartRx::new(rx_dma), | 600 | rx: UartRx { |
| 264 | phantom: PhantomData {}, | 601 | _peri: peri, |
| 602 | rx_dma, | ||
| 603 | detect_previous_overrun: config.detect_previous_overrun, | ||
| 604 | }, | ||
| 265 | } | 605 | } |
| 266 | } | 606 | } |
| 267 | 607 | ||
| @@ -295,6 +635,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 295 | self.rx.blocking_read(buffer) | 635 | self.rx.blocking_read(buffer) |
| 296 | } | 636 | } |
| 297 | 637 | ||
| 638 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||
| 639 | where | ||
| 640 | RxDma: crate::usart::RxDma<T>, | ||
| 641 | { | ||
| 642 | self.rx.read_until_idle(buffer).await | ||
| 643 | } | ||
| 644 | |||
| 298 | /// Split the Uart into a transmitter and receiver, which is | 645 | /// Split the Uart into a transmitter and receiver, which is |
| 299 | /// particuarly useful when having two tasks correlating to | 646 | /// particuarly useful when having two tasks correlating to |
| 300 | /// transmitting and receiving. | 647 | /// transmitting and receiving. |
| @@ -303,6 +650,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 303 | } | 650 | } |
| 304 | } | 651 | } |
| 305 | 652 | ||
| 653 | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) { | ||
| 654 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 655 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; | ||
| 656 | |||
| 657 | unsafe { | ||
| 658 | r.brr().write_value(regs::Brr(div)); | ||
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 306 | mod eh02 { | 662 | mod eh02 { |
| 307 | use super::*; | 663 | use super::*; |
| 308 | 664 | ||
| @@ -352,6 +708,7 @@ mod eh1 { | |||
| 352 | Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, | 708 | Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, |
| 353 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, | 709 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, |
| 354 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, | 710 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, |
| 711 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | ||
| 355 | } | 712 | } |
| 356 | } | 713 | } |
| 357 | } | 714 | } |
| @@ -536,13 +893,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | |||
| 536 | } | 893 | } |
| 537 | 894 | ||
| 538 | pub(crate) mod sealed { | 895 | pub(crate) mod sealed { |
| 896 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 897 | |||
| 539 | use super::*; | 898 | use super::*; |
| 540 | 899 | ||
| 900 | pub struct State { | ||
| 901 | pub rx_waker: AtomicWaker, | ||
| 902 | pub tx_waker: AtomicWaker, | ||
| 903 | } | ||
| 904 | |||
| 905 | impl State { | ||
| 906 | pub const fn new() -> Self { | ||
| 907 | Self { | ||
| 908 | rx_waker: AtomicWaker::new(), | ||
| 909 | tx_waker: AtomicWaker::new(), | ||
| 910 | } | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 541 | pub trait BasicInstance: crate::rcc::RccPeripheral { | 914 | pub trait BasicInstance: crate::rcc::RccPeripheral { |
| 542 | const MULTIPLIER: u32; | 915 | const MULTIPLIER: u32; |
| 543 | type Interrupt: crate::interrupt::Interrupt; | 916 | type Interrupt: crate::interrupt::Interrupt; |
| 544 | 917 | ||
| 545 | fn regs() -> Regs; | 918 | fn regs() -> Regs; |
| 919 | fn state() -> &'static State; | ||
| 546 | } | 920 | } |
| 547 | 921 | ||
| 548 | pub trait FullInstance: BasicInstance { | 922 | pub trait FullInstance: BasicInstance { |
| @@ -550,7 +924,7 @@ pub(crate) mod sealed { | |||
| 550 | } | 924 | } |
| 551 | } | 925 | } |
| 552 | 926 | ||
| 553 | pub trait BasicInstance: sealed::BasicInstance {} | 927 | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} |
| 554 | 928 | ||
| 555 | pub trait FullInstance: sealed::FullInstance {} | 929 | pub trait FullInstance: sealed::FullInstance {} |
| 556 | 930 | ||
| @@ -572,6 +946,11 @@ macro_rules! impl_lpuart { | |||
| 572 | fn regs() -> Regs { | 946 | fn regs() -> Regs { |
| 573 | Regs(crate::pac::$inst.0) | 947 | Regs(crate::pac::$inst.0) |
| 574 | } | 948 | } |
| 949 | |||
| 950 | fn state() -> &'static crate::usart::sealed::State { | ||
| 951 | static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); | ||
| 952 | &STATE | ||
| 953 | } | ||
| 575 | } | 954 | } |
| 576 | 955 | ||
| 577 | impl BasicInstance for peripherals::$inst {} | 956 | impl BasicInstance for peripherals::$inst {} |
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 584d5ba9f..b7fe1643c 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml | |||
| @@ -19,6 +19,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/ | |||
| 19 | features = ["nightly"] | 19 | features = ["nightly"] |
| 20 | target = "thumbv7em-none-eabi" | 20 | target = "thumbv7em-none-eabi" |
| 21 | 21 | ||
| 22 | [package.metadata.docs.rs] | ||
| 23 | features = ["nightly"] | ||
| 24 | |||
| 22 | [features] | 25 | [features] |
| 23 | nightly = ["embedded-io/async"] | 26 | nightly = ["embedded-io/async"] |
| 24 | std = [] | 27 | std = [] |
| @@ -32,7 +35,7 @@ atomic-polyfill = "1.0.1" | |||
| 32 | critical-section = "1.1" | 35 | critical-section = "1.1" |
| 33 | heapless = "0.7.5" | 36 | heapless = "0.7.5" |
| 34 | cfg-if = "1.0.0" | 37 | cfg-if = "1.0.0" |
| 35 | embedded-io = "0.3.0" | 38 | embedded-io = "0.3.1" |
| 36 | 39 | ||
| 37 | [dev-dependencies] | 40 | [dev-dependencies] |
| 38 | futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } | 41 | futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } |
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index 7d64b648e..cd577f34f 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs | |||
| @@ -361,7 +361,7 @@ mod io_impls { | |||
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Pipe<M, N> { | 363 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Pipe<M, N> { |
| 364 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 364 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 365 | where | 365 | where |
| 366 | Self: 'a; | 366 | Self: 'a; |
| 367 | 367 | ||
| @@ -371,7 +371,7 @@ mod io_impls { | |||
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Pipe<M, N> { | 373 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Pipe<M, N> { |
| 374 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 374 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 375 | where | 375 | where |
| 376 | Self: 'a; | 376 | Self: 'a; |
| 377 | 377 | ||
| @@ -379,7 +379,7 @@ mod io_impls { | |||
| 379 | Pipe::write(self, buf).map(Ok) | 379 | Pipe::write(self, buf).map(Ok) |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 382 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 383 | where | 383 | where |
| 384 | Self: 'a; | 384 | Self: 'a; |
| 385 | 385 | ||
| @@ -393,7 +393,7 @@ mod io_impls { | |||
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for &Pipe<M, N> { | 395 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for &Pipe<M, N> { |
| 396 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 396 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 397 | where | 397 | where |
| 398 | Self: 'a; | 398 | Self: 'a; |
| 399 | 399 | ||
| @@ -403,7 +403,7 @@ mod io_impls { | |||
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for &Pipe<M, N> { | 405 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for &Pipe<M, N> { |
| 406 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 406 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 407 | where | 407 | where |
| 408 | Self: 'a; | 408 | Self: 'a; |
| 409 | 409 | ||
| @@ -411,7 +411,7 @@ mod io_impls { | |||
| 411 | Pipe::write(self, buf).map(Ok) | 411 | Pipe::write(self, buf).map(Ok) |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 414 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 415 | where | 415 | where |
| 416 | Self: 'a; | 416 | Self: 'a; |
| 417 | 417 | ||
| @@ -425,7 +425,7 @@ mod io_impls { | |||
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Reader<'_, M, N> { | 427 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Reader<'_, M, N> { |
| 428 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 428 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 429 | where | 429 | where |
| 430 | Self: 'a; | 430 | Self: 'a; |
| 431 | 431 | ||
| @@ -439,7 +439,7 @@ mod io_impls { | |||
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Writer<'_, M, N> { | 441 | impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Writer<'_, M, N> { |
| 442 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 442 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a |
| 443 | where | 443 | where |
| 444 | Self: 'a; | 444 | Self: 'a; |
| 445 | 445 | ||
| @@ -447,7 +447,7 @@ mod io_impls { | |||
| 447 | Writer::write(self, buf).map(Ok) | 447 | Writer::write(self, buf).map(Ok) |
| 448 | } | 448 | } |
| 449 | 449 | ||
| 450 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 450 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a |
| 451 | where | 451 | where |
| 452 | Self: 'a; | 452 | Self: 'a; |
| 453 | 453 | ||
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index c51a71d01..9487003cc 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml | |||
| @@ -2,8 +2,16 @@ | |||
| 2 | name = "embassy-time" | 2 | name = "embassy-time" |
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | description = "Instant and Duration for embedded no-std systems, with async timer support" | ||
| 6 | repository = "https://github.com/embassy-rs/embassy" | ||
| 7 | readme = "README.md" | ||
| 5 | license = "MIT OR Apache-2.0" | 8 | license = "MIT OR Apache-2.0" |
| 6 | 9 | categories = [ | |
| 10 | "embedded", | ||
| 11 | "no-std", | ||
| 12 | "concurrency", | ||
| 13 | "asynchronous", | ||
| 14 | ] | ||
| 7 | 15 | ||
| 8 | [package.metadata.embassy_docs] | 16 | [package.metadata.embassy_docs] |
| 9 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/" | 17 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/" |
| @@ -11,6 +19,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time/ | |||
| 11 | features = ["nightly", "defmt", "unstable-traits", "std"] | 19 | features = ["nightly", "defmt", "unstable-traits", "std"] |
| 12 | target = "x86_64-unknown-linux-gnu" | 20 | target = "x86_64-unknown-linux-gnu" |
| 13 | 21 | ||
| 22 | [package.metadata.docs.rs] | ||
| 23 | features = ["nightly", "defmt", "unstable-traits", "std"] | ||
| 24 | |||
| 14 | [features] | 25 | [features] |
| 15 | std = ["tick-hz-1_000_000"] | 26 | std = ["tick-hz-1_000_000"] |
| 16 | wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] | 27 | wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] |
| @@ -26,6 +37,22 @@ unstable-traits = ["embedded-hal-1"] | |||
| 26 | # To use this you must have a time driver provided. | 37 | # To use this you must have a time driver provided. |
| 27 | defmt-timestamp-uptime = ["defmt"] | 38 | defmt-timestamp-uptime = ["defmt"] |
| 28 | 39 | ||
| 40 | # Create a global, generic queue that can be used with any executor | ||
| 41 | # To use this you must have a time driver provided. | ||
| 42 | generic-queue = [] | ||
| 43 | |||
| 44 | # Set the number of timers for the generic queue. | ||
| 45 | # | ||
| 46 | # At most 1 `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. | ||
| 47 | # | ||
| 48 | # When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the | ||
| 49 | # end user to pick. | ||
| 50 | generic-queue-8 = ["generic-queue"] | ||
| 51 | generic-queue-16 = ["generic-queue"] | ||
| 52 | generic-queue-32 = ["generic-queue"] | ||
| 53 | generic-queue-64 = ["generic-queue"] | ||
| 54 | generic-queue-128 = ["generic-queue"] | ||
| 55 | |||
| 29 | # Set the `embassy_time` tick rate. | 56 | # Set the `embassy_time` tick rate. |
| 30 | # | 57 | # |
| 31 | # At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. | 58 | # At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. |
| @@ -107,15 +134,21 @@ log = { version = "0.4.14", optional = true } | |||
| 107 | 134 | ||
| 108 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } | 135 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } |
| 109 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 136 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 110 | embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true} | 137 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} |
| 111 | 138 | ||
| 112 | futures-util = { version = "0.3.17", default-features = false } | 139 | futures-util = { version = "0.3.17", default-features = false } |
| 113 | embassy-macros = { version = "0.1.0", path = "../embassy-macros"} | 140 | embassy-sync = { version = "0.1", path = "../embassy-sync" } |
| 114 | atomic-polyfill = "1.0.1" | 141 | atomic-polyfill = "1.0.1" |
| 115 | critical-section = "1.1" | 142 | critical-section = "1.1" |
| 116 | cfg-if = "1.0.0" | 143 | cfg-if = "1.0.0" |
| 144 | heapless = "0.7" | ||
| 117 | 145 | ||
| 118 | # WASM dependencies | 146 | # WASM dependencies |
| 119 | wasm-bindgen = { version = "0.2.81", optional = true } | 147 | wasm-bindgen = { version = "0.2.81", optional = true } |
| 120 | js-sys = { version = "0.3", optional = true } | 148 | js-sys = { version = "0.3", optional = true } |
| 121 | wasm-timer = { version = "0.2.5", optional = true } | 149 | wasm-timer = { version = "0.2.5", optional = true } |
| 150 | |||
| 151 | [dev-dependencies] | ||
| 152 | serial_test = "0.9" | ||
| 153 | critical-section = { version = "1.1", features = ["std"] } | ||
| 154 | |||
diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 79ae14b91..5c2ad3b23 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs | |||
| @@ -105,20 +105,21 @@ pub trait Driver: Send + Sync + 'static { | |||
| 105 | /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm | 105 | /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm |
| 106 | /// timestamp, the provided callback function will be called. | 106 | /// timestamp, the provided callback function will be called. |
| 107 | /// | 107 | /// |
| 108 | /// If `timestamp` is already in the past, the alarm callback must be immediately fired. | 108 | /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. |
| 109 | /// In this case, it is allowed (but not mandatory) to call the alarm callback synchronously from `set_alarm`. | 109 | /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, |
| 110 | /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. | ||
| 110 | /// | 111 | /// |
| 111 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. | 112 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. |
| 112 | /// | 113 | /// |
| 113 | /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. | 114 | /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. |
| 114 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64); | 115 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | extern "Rust" { | 118 | extern "Rust" { |
| 118 | fn _embassy_time_now() -> u64; | 119 | fn _embassy_time_now() -> u64; |
| 119 | fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>; | 120 | fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>; |
| 120 | fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); | 121 | fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); |
| 121 | fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64); | 122 | fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | /// See [`Driver::now`] | 125 | /// See [`Driver::now`] |
| @@ -139,7 +140,7 @@ pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ( | |||
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | /// See [`Driver::set_alarm`] | 142 | /// See [`Driver::set_alarm`] |
| 142 | pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) { | 143 | pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool { |
| 143 | unsafe { _embassy_time_set_alarm(alarm, timestamp) } | 144 | unsafe { _embassy_time_set_alarm(alarm, timestamp) } |
| 144 | } | 145 | } |
| 145 | 146 | ||
| @@ -167,7 +168,7 @@ macro_rules! time_driver_impl { | |||
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | #[no_mangle] | 170 | #[no_mangle] |
| 170 | fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) { | 171 | fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) -> bool { |
| 171 | <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp) | 172 | <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp) |
| 172 | } | 173 | } |
| 173 | }; | 174 | }; |
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 2ddb2e604..fc7fd1979 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs | |||
| @@ -127,12 +127,14 @@ impl Driver for TimeDriver { | |||
| 127 | alarm.ctx = ctx; | 127 | alarm.ctx = ctx; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 130 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 131 | self.init(); | 131 | self.init(); |
| 132 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 132 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); |
| 133 | let alarm = &mut alarms[alarm.id() as usize]; | 133 | let alarm = &mut alarms[alarm.id() as usize]; |
| 134 | alarm.timestamp = timestamp; | 134 | alarm.timestamp = timestamp; |
| 135 | unsafe { self.signaler.as_ref() }.signal(); | 135 | unsafe { self.signaler.as_ref() }.signal(); |
| 136 | |||
| 137 | true | ||
| 136 | } | 138 | } |
| 137 | } | 139 | } |
| 138 | 140 | ||
diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index e4497e6a2..63d049897 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs | |||
| @@ -90,15 +90,23 @@ impl Driver for TimeDriver { | |||
| 90 | })); | 90 | })); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 93 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 94 | self.init(); | 94 | self.init(); |
| 95 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 95 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); |
| 96 | let alarm = &mut alarms[alarm.id() as usize]; | 96 | let alarm = &mut alarms[alarm.id() as usize]; |
| 97 | let timeout = (timestamp - self.now()) as u32; | ||
| 98 | if let Some(token) = alarm.token { | 97 | if let Some(token) = alarm.token { |
| 99 | clearTimeout(token); | 98 | clearTimeout(token); |
| 100 | } | 99 | } |
| 101 | alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000)); | 100 | |
| 101 | let now = self.now(); | ||
| 102 | if timestamp <= now { | ||
| 103 | false | ||
| 104 | } else { | ||
| 105 | let timeout = (timestamp - now) as u32; | ||
| 106 | alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000)); | ||
| 107 | |||
| 108 | true | ||
| 109 | } | ||
| 102 | } | 110 | } |
| 103 | } | 111 | } |
| 104 | 112 | ||
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 4edc883fe..586aa28de 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] | 1 | #![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)] |
| 2 | #![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] | 2 | #![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] |
| 3 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 4 | #![allow(clippy::new_without_default)] | 4 | #![allow(clippy::new_without_default)] |
| @@ -11,6 +11,7 @@ mod delay; | |||
| 11 | pub mod driver; | 11 | pub mod driver; |
| 12 | mod duration; | 12 | mod duration; |
| 13 | mod instant; | 13 | mod instant; |
| 14 | pub mod queue; | ||
| 14 | mod tick; | 15 | mod tick; |
| 15 | mod timer; | 16 | mod timer; |
| 16 | 17 | ||
| @@ -18,6 +19,8 @@ mod timer; | |||
| 18 | mod driver_std; | 19 | mod driver_std; |
| 19 | #[cfg(feature = "wasm")] | 20 | #[cfg(feature = "wasm")] |
| 20 | mod driver_wasm; | 21 | mod driver_wasm; |
| 22 | #[cfg(feature = "generic-queue")] | ||
| 23 | mod queue_generic; | ||
| 21 | 24 | ||
| 22 | pub use delay::{block_for, Delay}; | 25 | pub use delay::{block_for, Delay}; |
| 23 | pub use duration::Duration; | 26 | pub use duration::Duration; |
diff --git a/embassy-time/src/queue.rs b/embassy-time/src/queue.rs new file mode 100644 index 000000000..c6f8b440a --- /dev/null +++ b/embassy-time/src/queue.rs | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | //! Timer queue implementation | ||
| 2 | //! | ||
| 3 | //! This module defines the interface a timer queue needs to implement to power the `embassy_time` module. | ||
| 4 | //! | ||
| 5 | //! # Implementing a timer queue | ||
| 6 | //! | ||
| 7 | //! - Define a struct `MyTimerQueue` | ||
| 8 | //! - Implement [`TimerQueue`] for it | ||
| 9 | //! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl). | ||
| 10 | //! | ||
| 11 | //! # Linkage details | ||
| 12 | //! | ||
| 13 | //! Check the documentation of the [`driver`](crate::driver) module for more information. | ||
| 14 | //! | ||
| 15 | //! Similarly to driver, if there is none or multiple timer queues in the crate tree, linking will fail. | ||
| 16 | //! | ||
| 17 | //! # Example | ||
| 18 | //! | ||
| 19 | //! ``` | ||
| 20 | //! use core::task::Waker; | ||
| 21 | //! | ||
| 22 | //! use embassy_time::Instant; | ||
| 23 | //! use embassy_time::queue::{TimerQueue}; | ||
| 24 | //! | ||
| 25 | //! struct MyTimerQueue{}; // not public! | ||
| 26 | //! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); | ||
| 27 | //! | ||
| 28 | //! impl TimerQueue for MyTimerQueue { | ||
| 29 | //! fn schedule_wake(&'static self, at: Instant, waker: &Waker) { | ||
| 30 | //! todo!() | ||
| 31 | //! } | ||
| 32 | //! } | ||
| 33 | //! ``` | ||
| 34 | use core::task::Waker; | ||
| 35 | |||
| 36 | use crate::Instant; | ||
| 37 | |||
| 38 | /// Timer queue | ||
| 39 | pub trait TimerQueue { | ||
| 40 | /// Schedules a waker in the queue to be awoken at moment `at`. | ||
| 41 | /// If this moment is in the past, the waker might be awoken immediately. | ||
| 42 | fn schedule_wake(&'static self, at: Instant, waker: &Waker); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Set the TimerQueue implementation. | ||
| 46 | /// | ||
| 47 | /// See the module documentation for an example. | ||
| 48 | #[macro_export] | ||
| 49 | macro_rules! timer_queue_impl { | ||
| 50 | (static $name:ident: $t: ty = $val:expr) => { | ||
| 51 | static $name: $t = $val; | ||
| 52 | |||
| 53 | #[no_mangle] | ||
| 54 | fn _embassy_time_schedule_wake(at: $crate::Instant, waker: &core::task::Waker) { | ||
| 55 | <$t as $crate::queue::TimerQueue>::schedule_wake(&$name, at, waker); | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | } | ||
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs new file mode 100644 index 000000000..20ae7e6cc --- /dev/null +++ b/embassy-time/src/queue_generic.rs | |||
| @@ -0,0 +1,449 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | use core::cmp::{min, Ordering}; | ||
| 3 | use core::task::Waker; | ||
| 4 | |||
| 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 6 | use embassy_sync::blocking_mutex::Mutex; | ||
| 7 | use heapless::Vec; | ||
| 8 | |||
| 9 | use crate::driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle}; | ||
| 10 | use crate::queue::TimerQueue; | ||
| 11 | use crate::Instant; | ||
| 12 | |||
| 13 | #[cfg(feature = "generic-queue-8")] | ||
| 14 | const QUEUE_SIZE: usize = 8; | ||
| 15 | #[cfg(feature = "generic-queue-16")] | ||
| 16 | const QUEUE_SIZE: usize = 16; | ||
| 17 | #[cfg(feature = "generic-queue-32")] | ||
| 18 | const QUEUE_SIZE: usize = 32; | ||
| 19 | #[cfg(feature = "generic-queue-64")] | ||
| 20 | const QUEUE_SIZE: usize = 32; | ||
| 21 | #[cfg(feature = "generic-queue-128")] | ||
| 22 | const QUEUE_SIZE: usize = 128; | ||
| 23 | #[cfg(not(any( | ||
| 24 | feature = "generic-queue-8", | ||
| 25 | feature = "generic-queue-16", | ||
| 26 | feature = "generic-queue-32", | ||
| 27 | feature = "generic-queue-64", | ||
| 28 | feature = "generic-queue-128" | ||
| 29 | )))] | ||
| 30 | const QUEUE_SIZE: usize = 64; | ||
| 31 | |||
| 32 | #[derive(Debug)] | ||
| 33 | struct Timer { | ||
| 34 | at: Instant, | ||
| 35 | waker: Waker, | ||
| 36 | } | ||
| 37 | |||
| 38 | impl PartialEq for Timer { | ||
| 39 | fn eq(&self, other: &Self) -> bool { | ||
| 40 | self.at == other.at | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | impl Eq for Timer {} | ||
| 45 | |||
| 46 | impl PartialOrd for Timer { | ||
| 47 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 48 | self.at.partial_cmp(&other.at) | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | impl Ord for Timer { | ||
| 53 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 54 | self.at.cmp(&other.at) | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | struct InnerQueue { | ||
| 59 | queue: Vec<Timer, QUEUE_SIZE>, | ||
| 60 | alarm: AlarmHandle, | ||
| 61 | } | ||
| 62 | |||
| 63 | impl InnerQueue { | ||
| 64 | fn schedule_wake(&mut self, at: Instant, waker: &Waker) { | ||
| 65 | self.queue | ||
| 66 | .iter_mut() | ||
| 67 | .find(|timer| timer.waker.will_wake(waker)) | ||
| 68 | .map(|mut timer| { | ||
| 69 | timer.at = min(timer.at, at); | ||
| 70 | }) | ||
| 71 | .unwrap_or_else(|| { | ||
| 72 | let mut timer = Timer { | ||
| 73 | waker: waker.clone(), | ||
| 74 | at, | ||
| 75 | }; | ||
| 76 | |||
| 77 | loop { | ||
| 78 | match self.queue.push(timer) { | ||
| 79 | Ok(()) => break, | ||
| 80 | Err(e) => timer = e, | ||
| 81 | } | ||
| 82 | |||
| 83 | self.queue.pop().unwrap().waker.wake(); | ||
| 84 | } | ||
| 85 | }); | ||
| 86 | |||
| 87 | // Don't wait for the alarm callback to trigger and directly | ||
| 88 | // dispatch all timers that are already due | ||
| 89 | // | ||
| 90 | // Then update the alarm if necessary | ||
| 91 | self.dispatch(); | ||
| 92 | } | ||
| 93 | |||
| 94 | fn dispatch(&mut self) { | ||
| 95 | loop { | ||
| 96 | let now = Instant::now(); | ||
| 97 | |||
| 98 | let mut next_alarm = Instant::MAX; | ||
| 99 | |||
| 100 | let mut i = 0; | ||
| 101 | while i < self.queue.len() { | ||
| 102 | let timer = &self.queue[i]; | ||
| 103 | if timer.at <= now { | ||
| 104 | let timer = self.queue.swap_remove(i); | ||
| 105 | timer.waker.wake(); | ||
| 106 | } else { | ||
| 107 | next_alarm = min(next_alarm, timer.at); | ||
| 108 | i += 1; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | if self.update_alarm(next_alarm) { | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | fn update_alarm(&mut self, next_alarm: Instant) -> bool { | ||
| 119 | if next_alarm == Instant::MAX { | ||
| 120 | true | ||
| 121 | } else { | ||
| 122 | set_alarm(self.alarm, next_alarm.as_ticks()) | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | fn handle_alarm(&mut self) { | ||
| 127 | self.dispatch(); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | struct Queue { | ||
| 132 | inner: Mutex<CriticalSectionRawMutex, RefCell<Option<InnerQueue>>>, | ||
| 133 | } | ||
| 134 | |||
| 135 | impl Queue { | ||
| 136 | const fn new() -> Self { | ||
| 137 | Self { | ||
| 138 | inner: Mutex::new(RefCell::new(None)), | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | fn schedule_wake(&'static self, at: Instant, waker: &Waker) { | ||
| 143 | self.inner.lock(|inner| { | ||
| 144 | let mut inner = inner.borrow_mut(); | ||
| 145 | |||
| 146 | if inner.is_none() {} | ||
| 147 | |||
| 148 | inner | ||
| 149 | .get_or_insert_with(|| { | ||
| 150 | let handle = unsafe { allocate_alarm() }.unwrap(); | ||
| 151 | set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _); | ||
| 152 | InnerQueue { | ||
| 153 | queue: Vec::new(), | ||
| 154 | alarm: handle, | ||
| 155 | } | ||
| 156 | }) | ||
| 157 | .schedule_wake(at, waker) | ||
| 158 | }); | ||
| 159 | } | ||
| 160 | |||
| 161 | fn handle_alarm(&self) { | ||
| 162 | self.inner | ||
| 163 | .lock(|inner| inner.borrow_mut().as_mut().unwrap().handle_alarm()); | ||
| 164 | } | ||
| 165 | |||
| 166 | fn handle_alarm_callback(ctx: *mut ()) { | ||
| 167 | unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm(); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | impl TimerQueue for Queue { | ||
| 172 | fn schedule_wake(&'static self, at: Instant, waker: &Waker) { | ||
| 173 | Queue::schedule_wake(self, at, waker); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | crate::timer_queue_impl!(static QUEUE: Queue = Queue::new()); | ||
| 178 | |||
| 179 | #[cfg(test)] | ||
| 180 | mod tests { | ||
| 181 | use core::cell::Cell; | ||
| 182 | use core::task::{RawWaker, RawWakerVTable, Waker}; | ||
| 183 | use std::rc::Rc; | ||
| 184 | use std::sync::Mutex; | ||
| 185 | |||
| 186 | use serial_test::serial; | ||
| 187 | |||
| 188 | use super::InnerQueue; | ||
| 189 | use crate::driver::{AlarmHandle, Driver}; | ||
| 190 | use crate::queue_generic::QUEUE; | ||
| 191 | use crate::Instant; | ||
| 192 | |||
| 193 | struct InnerTestDriver { | ||
| 194 | now: u64, | ||
| 195 | alarm: u64, | ||
| 196 | callback: fn(*mut ()), | ||
| 197 | ctx: *mut (), | ||
| 198 | } | ||
| 199 | |||
| 200 | impl InnerTestDriver { | ||
| 201 | const fn new() -> Self { | ||
| 202 | Self { | ||
| 203 | now: 0, | ||
| 204 | alarm: u64::MAX, | ||
| 205 | callback: Self::noop, | ||
| 206 | ctx: core::ptr::null_mut(), | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | fn noop(_ctx: *mut ()) {} | ||
| 211 | } | ||
| 212 | |||
| 213 | unsafe impl Send for InnerTestDriver {} | ||
| 214 | |||
| 215 | struct TestDriver(Mutex<InnerTestDriver>); | ||
| 216 | |||
| 217 | impl TestDriver { | ||
| 218 | const fn new() -> Self { | ||
| 219 | Self(Mutex::new(InnerTestDriver::new())) | ||
| 220 | } | ||
| 221 | |||
| 222 | fn reset(&self) { | ||
| 223 | *self.0.lock().unwrap() = InnerTestDriver::new(); | ||
| 224 | } | ||
| 225 | |||
| 226 | fn set_now(&self, now: u64) { | ||
| 227 | let notify = { | ||
| 228 | let mut inner = self.0.lock().unwrap(); | ||
| 229 | |||
| 230 | if inner.now < now { | ||
| 231 | inner.now = now; | ||
| 232 | |||
| 233 | if inner.alarm <= now { | ||
| 234 | inner.alarm = u64::MAX; | ||
| 235 | |||
| 236 | Some((inner.callback, inner.ctx)) | ||
| 237 | } else { | ||
| 238 | None | ||
| 239 | } | ||
| 240 | } else { | ||
| 241 | panic!("Going back in time?"); | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | |||
| 245 | if let Some((callback, ctx)) = notify { | ||
| 246 | (callback)(ctx); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | impl Driver for TestDriver { | ||
| 252 | fn now(&self) -> u64 { | ||
| 253 | self.0.lock().unwrap().now | ||
| 254 | } | ||
| 255 | |||
| 256 | unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { | ||
| 257 | Some(AlarmHandle::new(0)) | ||
| 258 | } | ||
| 259 | |||
| 260 | fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { | ||
| 261 | let mut inner = self.0.lock().unwrap(); | ||
| 262 | |||
| 263 | inner.callback = callback; | ||
| 264 | inner.ctx = ctx; | ||
| 265 | } | ||
| 266 | |||
| 267 | fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { | ||
| 268 | let mut inner = self.0.lock().unwrap(); | ||
| 269 | |||
| 270 | if timestamp <= inner.now { | ||
| 271 | false | ||
| 272 | } else { | ||
| 273 | inner.alarm = timestamp; | ||
| 274 | true | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | struct TestWaker { | ||
| 280 | pub awoken: Rc<Cell<bool>>, | ||
| 281 | pub waker: Waker, | ||
| 282 | } | ||
| 283 | |||
| 284 | impl TestWaker { | ||
| 285 | fn new() -> Self { | ||
| 286 | let flag = Rc::new(Cell::new(false)); | ||
| 287 | |||
| 288 | const VTABLE: RawWakerVTable = RawWakerVTable::new( | ||
| 289 | |data: *const ()| { | ||
| 290 | unsafe { | ||
| 291 | Rc::increment_strong_count(data as *const Cell<bool>); | ||
| 292 | } | ||
| 293 | |||
| 294 | RawWaker::new(data as _, &VTABLE) | ||
| 295 | }, | ||
| 296 | |data: *const ()| unsafe { | ||
| 297 | let data = data as *const Cell<bool>; | ||
| 298 | data.as_ref().unwrap().set(true); | ||
| 299 | Rc::decrement_strong_count(data); | ||
| 300 | }, | ||
| 301 | |data: *const ()| unsafe { | ||
| 302 | (data as *const Cell<bool>).as_ref().unwrap().set(true); | ||
| 303 | }, | ||
| 304 | |data: *const ()| unsafe { | ||
| 305 | Rc::decrement_strong_count(data); | ||
| 306 | }, | ||
| 307 | ); | ||
| 308 | |||
| 309 | let raw = RawWaker::new(Rc::into_raw(flag.clone()) as _, &VTABLE); | ||
| 310 | |||
| 311 | Self { | ||
| 312 | awoken: flag.clone(), | ||
| 313 | waker: unsafe { Waker::from_raw(raw) }, | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | crate::time_driver_impl!(static DRIVER: TestDriver = TestDriver::new()); | ||
| 319 | |||
| 320 | fn setup() { | ||
| 321 | DRIVER.reset(); | ||
| 322 | |||
| 323 | QUEUE.inner.lock(|inner| { | ||
| 324 | *inner.borrow_mut() = InnerQueue::new(); | ||
| 325 | }); | ||
| 326 | } | ||
| 327 | |||
| 328 | fn queue_len() -> usize { | ||
| 329 | QUEUE.inner.lock(|inner| inner.borrow().queue.iter().count()) | ||
| 330 | } | ||
| 331 | |||
| 332 | #[test] | ||
| 333 | #[serial] | ||
| 334 | fn test_schedule() { | ||
| 335 | setup(); | ||
| 336 | |||
| 337 | assert_eq!(queue_len(), 0); | ||
| 338 | |||
| 339 | let waker = TestWaker::new(); | ||
| 340 | |||
| 341 | QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker); | ||
| 342 | |||
| 343 | assert!(!waker.awoken.get()); | ||
| 344 | assert_eq!(queue_len(), 1); | ||
| 345 | } | ||
| 346 | |||
| 347 | #[test] | ||
| 348 | #[serial] | ||
| 349 | fn test_schedule_same() { | ||
| 350 | setup(); | ||
| 351 | |||
| 352 | let waker = TestWaker::new(); | ||
| 353 | |||
| 354 | QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker); | ||
| 355 | |||
| 356 | assert_eq!(queue_len(), 1); | ||
| 357 | |||
| 358 | QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker); | ||
| 359 | |||
| 360 | assert_eq!(queue_len(), 1); | ||
| 361 | |||
| 362 | QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker); | ||
| 363 | |||
| 364 | assert_eq!(queue_len(), 1); | ||
| 365 | |||
| 366 | let waker2 = TestWaker::new(); | ||
| 367 | |||
| 368 | QUEUE.schedule_wake(Instant::from_secs(100), &waker2.waker); | ||
| 369 | |||
| 370 | assert_eq!(queue_len(), 2); | ||
| 371 | } | ||
| 372 | |||
| 373 | #[test] | ||
| 374 | #[serial] | ||
| 375 | fn test_trigger() { | ||
| 376 | setup(); | ||
| 377 | |||
| 378 | let waker = TestWaker::new(); | ||
| 379 | |||
| 380 | QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker); | ||
| 381 | |||
| 382 | assert!(!waker.awoken.get()); | ||
| 383 | |||
| 384 | DRIVER.set_now(Instant::from_secs(99).as_ticks()); | ||
| 385 | |||
| 386 | assert!(!waker.awoken.get()); | ||
| 387 | |||
| 388 | assert_eq!(queue_len(), 1); | ||
| 389 | |||
| 390 | DRIVER.set_now(Instant::from_secs(100).as_ticks()); | ||
| 391 | |||
| 392 | assert!(waker.awoken.get()); | ||
| 393 | |||
| 394 | assert_eq!(queue_len(), 0); | ||
| 395 | } | ||
| 396 | |||
| 397 | #[test] | ||
| 398 | #[serial] | ||
| 399 | fn test_immediate_trigger() { | ||
| 400 | setup(); | ||
| 401 | |||
| 402 | let waker = TestWaker::new(); | ||
| 403 | |||
| 404 | QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker); | ||
| 405 | |||
| 406 | DRIVER.set_now(Instant::from_secs(50).as_ticks()); | ||
| 407 | |||
| 408 | let waker2 = TestWaker::new(); | ||
| 409 | |||
| 410 | QUEUE.schedule_wake(Instant::from_secs(40), &waker2.waker); | ||
| 411 | |||
| 412 | assert!(!waker.awoken.get()); | ||
| 413 | assert!(waker2.awoken.get()); | ||
| 414 | assert_eq!(queue_len(), 1); | ||
| 415 | } | ||
| 416 | |||
| 417 | #[test] | ||
| 418 | #[serial] | ||
| 419 | fn test_queue_overflow() { | ||
| 420 | setup(); | ||
| 421 | |||
| 422 | for i in 1..super::QUEUE_SIZE { | ||
| 423 | let waker = TestWaker::new(); | ||
| 424 | |||
| 425 | QUEUE.schedule_wake(Instant::from_secs(310), &waker.waker); | ||
| 426 | |||
| 427 | assert_eq!(queue_len(), i); | ||
| 428 | assert!(!waker.awoken.get()); | ||
| 429 | } | ||
| 430 | |||
| 431 | let first_waker = TestWaker::new(); | ||
| 432 | |||
| 433 | QUEUE.schedule_wake(Instant::from_secs(300), &first_waker.waker); | ||
| 434 | |||
| 435 | assert_eq!(queue_len(), super::QUEUE_SIZE); | ||
| 436 | assert!(!first_waker.awoken.get()); | ||
| 437 | |||
| 438 | let second_waker = TestWaker::new(); | ||
| 439 | |||
| 440 | QUEUE.schedule_wake(Instant::from_secs(305), &second_waker.waker); | ||
| 441 | |||
| 442 | assert_eq!(queue_len(), super::QUEUE_SIZE); | ||
| 443 | assert!(first_waker.awoken.get()); | ||
| 444 | |||
| 445 | QUEUE.schedule_wake(Instant::from_secs(320), &TestWaker::new().waker); | ||
| 446 | assert_eq!(queue_len(), super::QUEUE_SIZE); | ||
| 447 | assert!(second_waker.awoken.get()); | ||
| 448 | } | ||
| 449 | } | ||
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 6949042e2..c633f82f5 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -17,7 +17,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de | |||
| 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } | 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } |
| 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } |
| 20 | embedded-io = "0.3.0" | 20 | embedded-io = "0.3.1" |
| 21 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } | 21 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } |
| 22 | 22 | ||
| 23 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } | 23 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } |
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 38355bbf8..31f688305 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -28,8 +28,8 @@ display-interface = "0.4.1" | |||
| 28 | byte-slice-cast = { version = "1.2.0", default-features = false } | 28 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 29 | 29 | ||
| 30 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 30 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 31 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 31 | embedded-hal-async = { version = "0.1.0-alpha.3" } |
| 32 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } | 32 | embedded-io = { version = "0.3.1", features = ["async", "defmt"] } |
| 33 | embedded-storage = { version = "0.3" } | 33 | embedded-storage = { version = "0.3" } |
| 34 | static_cell = "1.0.0" | 34 | static_cell = "1.0.0" |
| 35 | 35 | ||
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index b9bd1e718..790258382 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml | |||
| @@ -9,7 +9,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["lo | |||
| 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } | 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } |
| 11 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } | 11 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } |
| 12 | embedded-io = { version = "0.3.0", features = ["async", "std", "futures"] } | 12 | embedded-io = { version = "0.3.1", features = ["async", "std", "futures"] } |
| 13 | critical-section = { version = "1.1", features = ["std"] } | 13 | critical-section = { version = "1.1", features = ["std"] } |
| 14 | 14 | ||
| 15 | async-io = "1.6.0" | 15 | async-io = "1.6.0" |
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 2d6b4a0e9..ed59e2799 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs | |||
| @@ -16,11 +16,19 @@ async fn main(_spawner: Spawner) { | |||
| 16 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 16 | let mut adc = Adc::new(p.ADC1, &mut Delay); |
| 17 | let mut pin = p.PB1; | 17 | let mut pin = p.PB1; |
| 18 | 18 | ||
| 19 | let mut vref = adc.enable_vref(&mut Delay); | 19 | let mut vrefint = adc.enable_vref(&mut Delay); |
| 20 | adc.calibrate(&mut vref); | 20 | let vrefint_sample = adc.read(&mut vrefint); |
| 21 | let convert_to_millivolts = |sample| { | ||
| 22 | // From http://www.st.com/resource/en/datasheet/CD00161566.pdf | ||
| 23 | // 5.3.4 Embedded reference voltage | ||
| 24 | const VREFINT_MV: u32 = 1200; // mV | ||
| 25 | |||
| 26 | (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 | ||
| 27 | }; | ||
| 28 | |||
| 21 | loop { | 29 | loop { |
| 22 | let v = adc.read(&mut pin); | 30 | let v = adc.read(&mut pin); |
| 23 | info!("--> {} - {} mV", v, adc.to_millivolts(v)); | 31 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); |
| 24 | Timer::after(Duration::from_millis(100)).await; | 32 | Timer::after(Duration::from_millis(100)).await; |
| 25 | } | 33 | } |
| 26 | } | 34 | } |
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 3bc5a287f..47121acf1 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); | 21 | let irq = interrupt::take!(USART1); |
| 22 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 6d4f09fba..b05457eaa 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -17,7 +17,7 @@ defmt-rtt = "0.3" | |||
| 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | embedded-io = "0.3.0" | 20 | embedded-io = "0.3.1" |
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 23 | heapless = { version = "0.7.5", default-features = false } | 23 | heapless = { version = "0.7.5", default-features = false } |
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 1d030f7dc..1c9a0b35d 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs | |||
| @@ -24,19 +24,44 @@ async fn main(_spawner: Spawner) { | |||
| 24 | // Startup delay can be combined to the maximum of either | 24 | // Startup delay can be combined to the maximum of either |
| 25 | delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); | 25 | delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); |
| 26 | 26 | ||
| 27 | let vrefint_sample = adc.read_internal(&mut vrefint); | ||
| 28 | |||
| 29 | let convert_to_millivolts = |sample| { | ||
| 30 | // From http://www.st.com/resource/en/datasheet/DM00071990.pdf | ||
| 31 | // 6.3.24 Reference voltage | ||
| 32 | const VREFINT_MV: u32 = 1210; // mV | ||
| 33 | |||
| 34 | (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 | ||
| 35 | }; | ||
| 36 | |||
| 37 | let convert_to_celcius = |sample| { | ||
| 38 | // From http://www.st.com/resource/en/datasheet/DM00071990.pdf | ||
| 39 | // 6.3.22 Temperature sensor characteristics | ||
| 40 | const V25: i32 = 760; // mV | ||
| 41 | const AVG_SLOPE: f32 = 2.5; // mV/C | ||
| 42 | |||
| 43 | let sample_mv = convert_to_millivolts(sample) as i32; | ||
| 44 | |||
| 45 | (sample_mv - V25) as f32 / AVG_SLOPE + 25.0 | ||
| 46 | }; | ||
| 47 | |||
| 48 | info!("VrefInt: {}", vrefint_sample); | ||
| 49 | const MAX_ADC_SAMPLE: u16 = (1 << 12) - 1; | ||
| 50 | info!("VCCA: {} mV", convert_to_millivolts(MAX_ADC_SAMPLE)); | ||
| 51 | |||
| 27 | loop { | 52 | loop { |
| 28 | // Read pin | 53 | // Read pin |
| 29 | let v = adc.read(&mut pin); | 54 | let v = adc.read(&mut pin); |
| 30 | info!("PC1: {} ({} mV)", v, adc.to_millivolts(v)); | 55 | info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); |
| 31 | 56 | ||
| 32 | // Read internal temperature | 57 | // Read internal temperature |
| 33 | let v = adc.read_internal(&mut temp); | 58 | let v = adc.read_internal(&mut temp); |
| 34 | let celcius = Temperature::to_celcius(adc.to_millivolts(v)); | 59 | let celcius = convert_to_celcius(v); |
| 35 | info!("Internal temp: {} ({} C)", v, celcius); | 60 | info!("Internal temp: {} ({} C)", v, celcius); |
| 36 | 61 | ||
| 37 | // Read internal voltage reference | 62 | // Read internal voltage reference |
| 38 | let v = adc.read_internal(&mut vrefint); | 63 | let v = adc.read_internal(&mut vrefint); |
| 39 | info!("VrefInt: {} ({} mV)", v, adc.to_millivolts(v)); | 64 | info!("VrefInt: {}", v); |
| 40 | 65 | ||
| 41 | Timer::after(Duration::from_millis(100)).await; | 66 | Timer::after(Duration::from_millis(100)).await; |
| 42 | } | 67 | } |
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs new file mode 100644 index 000000000..6e51c211d --- /dev/null +++ b/examples/stm32f4/src/bin/i2c.rs | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 9 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::time::Hertz; | ||
| 11 | use embassy_time::Duration; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | const ADDRESS: u8 = 0x5F; | ||
| 15 | const WHOAMI: u8 = 0x0F; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) -> ! { | ||
| 19 | info!("Hello world!"); | ||
| 20 | let p = embassy_stm32::init(Default::default()); | ||
| 21 | |||
| 22 | let irq = interrupt::take!(I2C2_EV); | ||
| 23 | let mut i2c = I2c::new( | ||
| 24 | p.I2C2, | ||
| 25 | p.PB10, | ||
| 26 | p.PB11, | ||
| 27 | irq, | ||
| 28 | NoDma, | ||
| 29 | NoDma, | ||
| 30 | Hertz(100_000), | ||
| 31 | Default::default(), | ||
| 32 | ); | ||
| 33 | |||
| 34 | // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. | ||
| 35 | // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. | ||
| 36 | let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); | ||
| 37 | |||
| 38 | let mut data = [0u8; 1]; | ||
| 39 | |||
| 40 | match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 41 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 42 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 43 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 44 | } | ||
| 45 | } | ||
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 90ad882b8..8f41bb6c4 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | use cortex_m_rt::entry; | 5 | use cortex_m_rt::entry; |
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_stm32::dma::NoDma; | 7 | use embassy_stm32::dma::NoDma; |
| 8 | use embassy_stm32::interrupt; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| @@ -15,7 +16,8 @@ fn main() -> ! { | |||
| 15 | let p = embassy_stm32::init(Default::default()); | 16 | let p = embassy_stm32::init(Default::default()); |
| 16 | 17 | ||
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); | 19 | let irq = interrupt::take!(USART3); |
| 20 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config); | ||
| 19 | 21 | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 22 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 21 | info!("wrote Hello, starting echo"); | 23 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index 7bcecbd26..dd171fe13 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 9 | use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; |
| 10 | use embedded_io::asynch::BufRead; | 9 | use embedded_io::asynch::BufRead; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| @@ -16,13 +15,21 @@ async fn main(_spawner: Spawner) { | |||
| 16 | info!("Hello World!"); | 15 | info!("Hello World!"); |
| 17 | 16 | ||
| 18 | let config = Config::default(); | 17 | let config = Config::default(); |
| 19 | let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); | ||
| 20 | 18 | ||
| 21 | let mut state = State::new(); | 19 | let mut state = State::new(); |
| 22 | let irq = interrupt::take!(USART3); | 20 | let irq = interrupt::take!(USART3); |
| 23 | let mut tx_buf = [0u8; 32]; | 21 | let mut tx_buf = [0u8; 32]; |
| 24 | let mut rx_buf = [0u8; 32]; | 22 | let mut rx_buf = [0u8; 32]; |
| 25 | let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); | 23 | let mut buf_usart = BufferedUart::new( |
| 24 | &mut state, | ||
| 25 | p.USART3, | ||
| 26 | p.PD9, | ||
| 27 | p.PD8, | ||
| 28 | irq, | ||
| 29 | &mut tx_buf, | ||
| 30 | &mut rx_buf, | ||
| 31 | config, | ||
| 32 | ); | ||
| 26 | 33 | ||
| 27 | loop { | 34 | loop { |
| 28 | let buf = buf_usart.fill_buf().await.unwrap(); | 35 | let buf = buf_usart.fill_buf().await.unwrap(); |
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index bb41b8b4f..78baeaa0d 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); | 21 | let irq = interrupt::take!(USART3); |
| 22 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index dad92c0fc..b14afd2fe 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml | |||
| @@ -10,7 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } |
| 13 | embedded-io = { version = "0.3.0", features = ["async"] } | 13 | embedded-io = { version = "0.3.1", features = ["async"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.3" |
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index 80fad8c41..70b3b2a75 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs | |||
| @@ -16,9 +16,19 @@ async fn main(_spawner: Spawner) { | |||
| 16 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 16 | let mut adc = Adc::new(p.ADC1, &mut Delay); |
| 17 | let mut pin = p.PA3; | 17 | let mut pin = p.PA3; |
| 18 | 18 | ||
| 19 | let mut vrefint = adc.enable_vrefint(); | ||
| 20 | let vrefint_sample = adc.read_internal(&mut vrefint); | ||
| 21 | let convert_to_millivolts = |sample| { | ||
| 22 | // From http://www.st.com/resource/en/datasheet/DM00273119.pdf | ||
| 23 | // 6.3.27 Reference voltage | ||
| 24 | const VREFINT_MV: u32 = 1210; // mV | ||
| 25 | |||
| 26 | (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 | ||
| 27 | }; | ||
| 28 | |||
| 19 | loop { | 29 | loop { |
| 20 | let v = adc.read(&mut pin); | 30 | let v = adc.read(&mut pin); |
| 21 | info!("--> {} - {} mV", v, adc.to_millivolts(v)); | 31 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); |
| 22 | Timer::after(Duration::from_millis(100)).await; | 32 | Timer::after(Duration::from_millis(100)).await; |
| 23 | } | 33 | } |
| 24 | } | 34 | } |
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index 07270479c..4827c52ae 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 15 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 16 | let p = embassy_stm32::init(Default::default()); | 17 | let p = embassy_stm32::init(Default::default()); |
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); | 19 | let irq = interrupt::take!(UART7); |
| 20 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config); | ||
| 19 | 21 | ||
| 20 | for n in 0u32.. { | 22 | for n in 0u32.. { |
| 21 | let mut s: String<128> = String::new(); | 23 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 1a05b9ecb..0dccff6e8 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml | |||
| @@ -10,7 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } |
| 13 | embedded-io = { version = "0.3.0", features = ["async"] } | 13 | embedded-io = { version = "0.3.1", features = ["async"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.3" |
| @@ -19,7 +19,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | |||
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 20 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 22 | embedded-hal-async = { version = "=0.1.0-alpha.2" } | 22 | embedded-hal-async = { version = "=0.1.0-alpha.3" } |
| 23 | embedded-nal-async = "0.2.0" | 23 | embedded-nal-async = "0.2.0" |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs new file mode 100644 index 000000000..d44319ae6 --- /dev/null +++ b/examples/stm32h7/src/bin/i2c.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_time::Duration; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | const ADDRESS: u8 = 0x5F; | ||
| 14 | const WHOAMI: u8 = 0x0F; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) -> ! { | ||
| 18 | info!("Hello world!"); | ||
| 19 | let p = embassy_stm32::init(Default::default()); | ||
| 20 | |||
| 21 | let irq = interrupt::take!(I2C2_EV); | ||
| 22 | let mut i2c = I2c::new( | ||
| 23 | p.I2C2, | ||
| 24 | p.PB10, | ||
| 25 | p.PB11, | ||
| 26 | irq, | ||
| 27 | p.DMA1_CH4, | ||
| 28 | p.DMA1_CH5, | ||
| 29 | Hertz(100_000), | ||
| 30 | Default::default(), | ||
| 31 | ); | ||
| 32 | |||
| 33 | // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. | ||
| 34 | // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. | ||
| 35 | let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); | ||
| 36 | |||
| 37 | let mut data = [0u8; 1]; | ||
| 38 | |||
| 39 | match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 40 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 41 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 42 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 43 | } | ||
| 44 | } | ||
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index 87c2b1253..405f18ec7 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs | |||
| @@ -6,6 +6,7 @@ use cortex_m_rt::entry; | |||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Executor; | 7 | use embassy_executor::Executor; |
| 8 | use embassy_stm32::dma::NoDma; | 8 | use embassy_stm32::dma::NoDma; |
| 9 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 10 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use static_cell::StaticCell; | 11 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -15,7 +16,8 @@ async fn main_task() { | |||
| 15 | let p = embassy_stm32::init(Default::default()); | 16 | let p = embassy_stm32::init(Default::default()); |
| 16 | 17 | ||
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); | 19 | let irq = interrupt::take!(UART7); |
| 20 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); | ||
| 19 | 21 | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 22 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 21 | info!("wrote Hello, starting echo"); | 23 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index 3adffcbeb..6e3491e55 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs | |||
| @@ -8,6 +8,7 @@ use cortex_m_rt::entry; | |||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::dma::NoDma; | 10 | use embassy_stm32::dma::NoDma; |
| 11 | use embassy_stm32::interrupt; | ||
| 11 | use embassy_stm32::usart::{Config, Uart}; | 12 | use embassy_stm32::usart::{Config, Uart}; |
| 12 | use heapless::String; | 13 | use heapless::String; |
| 13 | use static_cell::StaticCell; | 14 | use static_cell::StaticCell; |
| @@ -18,7 +19,8 @@ async fn main_task() { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init(Default::default()); |
| 19 | 20 | ||
| 20 | let config = Config::default(); | 21 | let config = Config::default(); |
| 21 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); | 22 | let irq = interrupt::take!(UART7); |
| 23 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config); | ||
| 22 | 24 | ||
| 23 | for n in 0u32.. { | 25 | for n in 0u32.. { |
| 24 | let mut s: String<128> = String::new(); | 26 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index df2b600f8..f97176ecb 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | 7 | use embassy_stm32::dma::NoDma; |
| 8 | use embassy_stm32::interrupt; | ||
| 8 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | 9 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; |
| 9 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 10 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 11 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| @@ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! { | |||
| 31 | info!("Hello World!"); | 32 | info!("Hello World!"); |
| 32 | 33 | ||
| 33 | let config = Config::default(); | 34 | let config = Config::default(); |
| 34 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); | 35 | let irq = interrupt::take!(UART7); |
| 36 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config); | ||
| 35 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); | 37 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); |
| 36 | 38 | ||
| 37 | let (mut tx, rx) = usart.split(); | 39 | let (mut tx, rx) = usart.split(); |
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 7e1120f48..8b00773be 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -22,7 +22,7 @@ defmt = "0.3" | |||
| 22 | defmt-rtt = "0.3" | 22 | defmt-rtt = "0.3" |
| 23 | 23 | ||
| 24 | embedded-storage = "0.3.0" | 24 | embedded-storage = "0.3.0" |
| 25 | embedded-io = "0.3.0" | 25 | embedded-io = "0.3.1" |
| 26 | 26 | ||
| 27 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 27 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 28 | cortex-m-rt = "0.7.0" | 28 | cortex-m-rt = "0.7.0" |
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index 66657d0f0..c307f857a 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs | |||
| @@ -4,13 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::interrupt; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 10 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 12 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_stm32::init(Default::default()); | 13 | let p = embassy_stm32::init(Default::default()); |
| 13 | let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default()); | 14 | let irq = interrupt::take!(USART1); |
| 15 | let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default()); | ||
| 14 | 16 | ||
| 15 | usart.write(b"Hello Embassy World!\r\n").await.unwrap(); | 17 | usart.write(b"Hello Embassy World!\r\n").await.unwrap(); |
| 16 | info!("wrote Hello, starting echo"); | 18 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 0e2237388..8e84cd092 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 9 | use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; |
| 10 | use embedded_io::asynch::{Read, Write}; | 9 | use embedded_io::asynch::{Read, Write}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| @@ -21,15 +20,18 @@ async fn main(_spawner: Spawner) { | |||
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.baudrate = 9600; | 21 | config.baudrate = 9600; |
| 23 | 22 | ||
| 24 | let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); | ||
| 25 | let mut state = State::new(); | 23 | let mut state = State::new(); |
| 24 | let irq = interrupt::take!(USART2); | ||
| 26 | let mut usart = unsafe { | 25 | let mut usart = unsafe { |
| 27 | BufferedUart::new( | 26 | BufferedUart::new( |
| 28 | &mut state, | 27 | &mut state, |
| 29 | usart, | 28 | p.USART2, |
| 30 | interrupt::take!(USART2), | 29 | p.PA3, |
| 30 | p.PA2, | ||
| 31 | irq, | ||
| 31 | &mut TX_BUFFER, | 32 | &mut TX_BUFFER, |
| 32 | &mut RX_BUFFER, | 33 | &mut RX_BUFFER, |
| 34 | config, | ||
| 33 | ) | 35 | ) |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 657605ebe..83d456b26 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml | |||
| @@ -20,7 +20,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | |||
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 23 | embedded-hal-async = { version = "=0.1.0-alpha.2" } | 23 | embedded-hal-async = { version = "=0.1.0-alpha.3" } |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 26 | heapless = { version = "0.7.5", default-features = false } | 26 | heapless = { version = "0.7.5", default-features = false } |
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 4a4b46c53..7d874d9d7 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::dma::NoDma; |
| 7 | use embassy_stm32::interrupt; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| @@ -14,7 +15,8 @@ fn main() -> ! { | |||
| 14 | let p = embassy_stm32::init(Default::default()); | 15 | let p = embassy_stm32::init(Default::default()); |
| 15 | 16 | ||
| 16 | let config = Config::default(); | 17 | let config = Config::default(); |
| 17 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); | 18 | let irq = interrupt::take!(UART4); |
| 19 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config); | ||
| 18 | 20 | ||
| 19 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 21 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 20 | info!("wrote Hello, starting echo"); | 22 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 728906897..452bede30 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); | 21 | let irq = interrupt::take!(UART4); |
| 22 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 63eac3ed2..848723f8b 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml | |||
| @@ -26,5 +26,5 @@ embedded-hal = "0.2.6" | |||
| 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 27 | heapless = { version = "0.7.5", default-features = false } | 27 | heapless = { version = "0.7.5", default-features = false } |
| 28 | rand_core = { version = "0.6.3", default-features = false } | 28 | rand_core = { version = "0.6.3", default-features = false } |
| 29 | embedded-io = { version = "0.3.0", features = ["async"] } | 29 | embedded-io = { version = "0.3.1", features = ["async"] } |
| 30 | static_cell = "1.0" | 30 | static_cell = "1.0" |
diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1ec19e58b..c05aac3fc 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | # Before upgrading check that everything is available on all tier1 targets here: | 1 | # Before upgrading check that everything is available on all tier1 targets here: |
| 2 | # https://rust-lang.github.io/rustup-components-history | 2 | # https://rust-lang.github.io/rustup-components-history |
| 3 | [toolchain] | 3 | [toolchain] |
| 4 | channel = "nightly-2022-09-22" | 4 | channel = "nightly-2022-10-25" |
| 5 | components = [ "rust-src", "rustfmt" ] | 5 | components = [ "rust-src", "rustfmt" ] |
| 6 | targets = [ | 6 | targets = [ |
| 7 | "thumbv7em-none-eabi", | 7 | "thumbv7em-none-eabi", |
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 48c88e85b..069b7fb8c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -18,10 +18,10 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | |||
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 21 | embedded-hal-async = { version = "=0.1.0-alpha.2" } | 21 | embedded-hal-async = { version = "=0.1.0-alpha.3" } |
| 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 24 | embedded-io = { version = "0.3.0", features = ["async"] } | 24 | embedded-io = { version = "0.3.1", features = ["async"] } |
| 25 | embedded-storage = { version = "0.3" } | 25 | embedded-storage = { version = "0.3" } |
| 26 | 26 | ||
| 27 | [profile.dev] | 27 | [profile.dev] |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bebbf557e..602c1fb57 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -26,7 +26,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | |||
| 26 | cortex-m-rt = "0.7.0" | 26 | cortex-m-rt = "0.7.0" |
| 27 | embedded-hal = "0.2.6" | 27 | embedded-hal = "0.2.6" |
| 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 29 | embedded-hal-async = { version = "=0.1.0-alpha.2" } | 29 | embedded-hal-async = { version = "=0.1.0-alpha.3" } |
| 30 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 30 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 31 | 31 | ||
| 32 | [profile.dev] | 32 | [profile.dev] |
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 7673bfe6d..af55867f2 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs | |||
| @@ -7,6 +7,7 @@ mod example_common; | |||
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use example_common::*; | 12 | use example_common::*; |
| 12 | 13 | ||
| @@ -18,22 +19,22 @@ async fn main(_spawner: Spawner) { | |||
| 18 | // Arduino pins D0 and D1 | 19 | // Arduino pins D0 and D1 |
| 19 | // They're connected together with a 1K resistor. | 20 | // They're connected together with a 1K resistor. |
| 20 | #[cfg(feature = "stm32f103c8")] | 21 | #[cfg(feature = "stm32f103c8")] |
| 21 | let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); | 22 | let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); |
| 22 | #[cfg(feature = "stm32g491re")] | 23 | #[cfg(feature = "stm32g491re")] |
| 23 | let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); | 24 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 24 | #[cfg(feature = "stm32g071rb")] | 25 | #[cfg(feature = "stm32g071rb")] |
| 25 | let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); | 26 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 26 | #[cfg(feature = "stm32f429zi")] | 27 | #[cfg(feature = "stm32f429zi")] |
| 27 | let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6); | 28 | let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); |
| 28 | #[cfg(feature = "stm32wb55rg")] | 29 | #[cfg(feature = "stm32wb55rg")] |
| 29 | let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1); | 30 | let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); |
| 30 | #[cfg(feature = "stm32h755zi")] | 31 | #[cfg(feature = "stm32h755zi")] |
| 31 | let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); | 32 | let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); |
| 32 | #[cfg(feature = "stm32u585ai")] | 33 | #[cfg(feature = "stm32u585ai")] |
| 33 | let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); | 34 | let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); |
| 34 | 35 | ||
| 35 | let config = Config::default(); | 36 | let config = Config::default(); |
| 36 | let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); | 37 | let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); |
| 37 | 38 | ||
| 38 | // We can't send too many bytes, they have to fit in the FIFO. | 39 | // We can't send too many bytes, they have to fit in the FIFO. |
| 39 | // This is because we aren't sending+receiving at the same time. | 40 | // This is because we aren't sending+receiving at the same time. |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index e0389446f..d12605a9a 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | mod example_common; | 6 | mod example_common; |
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 10 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use example_common::*; | 11 | use example_common::*; |
| 11 | 12 | ||
| @@ -17,22 +18,53 @@ async fn main(_spawner: Spawner) { | |||
| 17 | // Arduino pins D0 and D1 | 18 | // Arduino pins D0 and D1 |
| 18 | // They're connected together with a 1K resistor. | 19 | // They're connected together with a 1K resistor. |
| 19 | #[cfg(feature = "stm32f103c8")] | 20 | #[cfg(feature = "stm32f103c8")] |
| 20 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); | 21 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 22 | p.PA9, | ||
| 23 | p.PA10, | ||
| 24 | p.USART1, | ||
| 25 | interrupt::take!(USART1), | ||
| 26 | p.DMA1_CH4, | ||
| 27 | p.DMA1_CH5, | ||
| 28 | ); | ||
| 21 | #[cfg(feature = "stm32g491re")] | 29 | #[cfg(feature = "stm32g491re")] |
| 22 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); | 30 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 31 | (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||
| 23 | #[cfg(feature = "stm32g071rb")] | 32 | #[cfg(feature = "stm32g071rb")] |
| 24 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); | 33 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 34 | (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||
| 25 | #[cfg(feature = "stm32f429zi")] | 35 | #[cfg(feature = "stm32f429zi")] |
| 26 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); | 36 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 37 | p.PG14, | ||
| 38 | p.PG9, | ||
| 39 | p.USART6, | ||
| 40 | interrupt::take!(USART6), | ||
| 41 | p.DMA2_CH6, | ||
| 42 | p.DMA2_CH1, | ||
| 43 | ); | ||
| 27 | #[cfg(feature = "stm32wb55rg")] | 44 | #[cfg(feature = "stm32wb55rg")] |
| 28 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); | 45 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 46 | p.PA2, | ||
| 47 | p.PA3, | ||
| 48 | p.LPUART1, | ||
| 49 | interrupt::take!(LPUART1), | ||
| 50 | p.DMA1_CH1, | ||
| 51 | p.DMA1_CH2, | ||
| 52 | ); | ||
| 29 | #[cfg(feature = "stm32h755zi")] | 53 | #[cfg(feature = "stm32h755zi")] |
| 30 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 54 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 55 | (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); | ||
| 31 | #[cfg(feature = "stm32u585ai")] | 56 | #[cfg(feature = "stm32u585ai")] |
| 32 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); | 57 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 58 | p.PD8, | ||
| 59 | p.PD9, | ||
| 60 | p.USART3, | ||
| 61 | interrupt::take!(USART3), | ||
| 62 | p.GPDMA1_CH0, | ||
| 63 | p.GPDMA1_CH1, | ||
| 64 | ); | ||
| 33 | 65 | ||
| 34 | let config = Config::default(); | 66 | let config = Config::default(); |
| 35 | let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); | 67 | let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); |
| 36 | 68 | ||
| 37 | // We can't send too many bytes, they have to fit in the FIFO. | 69 | // We can't send too many bytes, they have to fit in the FIFO. |
| 38 | // This is because we aren't sending+receiving at the same time. | 70 | // This is because we aren't sending+receiving at the same time. |
