Rebase on master
This commit is contained in:
		@@ -20,7 +20,7 @@ nightly = ["embedded-hal-async", "embedded-storage-async"]
 | 
			
		||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 | 
			
		||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true }
 | 
			
		||||
embedded-storage = "0.3.0"
 | 
			
		||||
embedded-storage-async = { version = "0.3.0", optional = true }
 | 
			
		||||
nb = "1.0.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -354,46 +354,54 @@ impl Executor {
 | 
			
		||||
    /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
 | 
			
		||||
    /// no `poll()` already running.
 | 
			
		||||
    pub unsafe fn poll(&'static self) {
 | 
			
		||||
        #[cfg(feature = "integrated-timers")]
 | 
			
		||||
        self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task));
 | 
			
		||||
        loop {
 | 
			
		||||
            #[cfg(feature = "integrated-timers")]
 | 
			
		||||
            self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task));
 | 
			
		||||
 | 
			
		||||
        self.run_queue.dequeue_all(|p| {
 | 
			
		||||
            let task = p.as_ref();
 | 
			
		||||
            self.run_queue.dequeue_all(|p| {
 | 
			
		||||
                let task = p.as_ref();
 | 
			
		||||
 | 
			
		||||
                #[cfg(feature = "integrated-timers")]
 | 
			
		||||
                task.expires_at.set(Instant::MAX);
 | 
			
		||||
 | 
			
		||||
                let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
 | 
			
		||||
                if state & STATE_SPAWNED == 0 {
 | 
			
		||||
                    // If task is not running, ignore it. This can happen in the following scenario:
 | 
			
		||||
                    //   - Task gets dequeued, poll starts
 | 
			
		||||
                    //   - While task is being polled, it gets woken. It gets placed in the queue.
 | 
			
		||||
                    //   - Task poll finishes, returning done=true
 | 
			
		||||
                    //   - RUNNING bit is cleared, but the task is already in the queue.
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                #[cfg(feature = "rtos-trace")]
 | 
			
		||||
                trace::task_exec_begin(p.as_ptr() as u32);
 | 
			
		||||
 | 
			
		||||
                // Run the task
 | 
			
		||||
                task.poll_fn.read()(p as _);
 | 
			
		||||
 | 
			
		||||
                #[cfg(feature = "rtos-trace")]
 | 
			
		||||
                trace::task_exec_end();
 | 
			
		||||
 | 
			
		||||
                // Enqueue or update into timer_queue
 | 
			
		||||
                #[cfg(feature = "integrated-timers")]
 | 
			
		||||
                self.timer_queue.update(p);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            #[cfg(feature = "integrated-timers")]
 | 
			
		||||
            task.expires_at.set(Instant::MAX);
 | 
			
		||||
 | 
			
		||||
            let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
 | 
			
		||||
            if state & STATE_SPAWNED == 0 {
 | 
			
		||||
                // If task is not running, ignore it. This can happen in the following scenario:
 | 
			
		||||
                //   - Task gets dequeued, poll starts
 | 
			
		||||
                //   - While task is being polled, it gets woken. It gets placed in the queue.
 | 
			
		||||
                //   - Task poll finishes, returning done=true
 | 
			
		||||
                //   - RUNNING bit is cleared, but the task is already in the queue.
 | 
			
		||||
                return;
 | 
			
		||||
            {
 | 
			
		||||
                // If this is already in the past, set_alarm might return false
 | 
			
		||||
                // In that case do another poll loop iteration.
 | 
			
		||||
                let next_expiration = self.timer_queue.next_expiration();
 | 
			
		||||
                if driver::set_alarm(self.alarm, next_expiration.as_ticks()) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[cfg(feature = "rtos-trace")]
 | 
			
		||||
            trace::task_exec_begin(p.as_ptr() as u32);
 | 
			
		||||
 | 
			
		||||
            // Run the task
 | 
			
		||||
            task.poll_fn.read()(p as _);
 | 
			
		||||
 | 
			
		||||
            #[cfg(feature = "rtos-trace")]
 | 
			
		||||
            trace::task_exec_end();
 | 
			
		||||
 | 
			
		||||
            // Enqueue or update into timer_queue
 | 
			
		||||
            #[cfg(feature = "integrated-timers")]
 | 
			
		||||
            self.timer_queue.update(p);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        #[cfg(feature = "integrated-timers")]
 | 
			
		||||
        {
 | 
			
		||||
            // If this is already in the past, set_alarm will immediately trigger the alarm.
 | 
			
		||||
            // This will cause `signal_fn` to be called, which will cause `poll()` to be called again,
 | 
			
		||||
            // so we immediately do another poll loop iteration.
 | 
			
		||||
            let next_expiration = self.timer_queue.next_expiration();
 | 
			
		||||
            driver::set_alarm(self.alarm, next_expiration.as_ticks());
 | 
			
		||||
            #[cfg(not(feature = "integrated-timers"))]
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[cfg(feature = "rtos-trace")]
 | 
			
		||||
@@ -436,14 +444,21 @@ pub unsafe fn wake_task(task: NonNull<TaskHeader>) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "integrated-timers")]
 | 
			
		||||
#[no_mangle]
 | 
			
		||||
unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) {
 | 
			
		||||
    let task = waker::task_from_waker(waker);
 | 
			
		||||
    let task = task.as_ref();
 | 
			
		||||
    let expires_at = task.expires_at.get();
 | 
			
		||||
    task.expires_at.set(expires_at.min(at));
 | 
			
		||||
struct TimerQueue;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "integrated-timers")]
 | 
			
		||||
impl embassy_time::queue::TimerQueue for TimerQueue {
 | 
			
		||||
    fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) {
 | 
			
		||||
        let task = waker::task_from_waker(waker);
 | 
			
		||||
        let task = unsafe { task.as_ref() };
 | 
			
		||||
        let expires_at = task.expires_at.get();
 | 
			
		||||
        task.expires_at.set(expires_at.min(at));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "integrated-timers")]
 | 
			
		||||
embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "rtos-trace")]
 | 
			
		||||
impl rtos_trace::RtosTraceOSCallbacks for Executor {
 | 
			
		||||
    fn task_list() {
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ embassy-time = { version = "0.1.0", path = "../embassy-time" }
 | 
			
		||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 | 
			
		||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3" }
 | 
			
		||||
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false }
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
 | 
			
		||||
embedded-hal = { version = "0.2", features = ["unproven"] }
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ log = { version = "0.4.14", optional = true }
 | 
			
		||||
 | 
			
		||||
embassy-time = { version = "0.1.0", path = "../embassy-time" }
 | 
			
		||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 | 
			
		||||
embedded-io = { version = "0.3.0", optional = true }
 | 
			
		||||
embedded-io = { version = "0.3.1", optional = true }
 | 
			
		||||
 | 
			
		||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
 | 
			
		||||
heapless = { version = "0.7.5", default-features = false }
 | 
			
		||||
 
 | 
			
		||||
@@ -292,7 +292,7 @@ mod embedded_io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'d> embedded_io::asynch::Read for TcpSocket<'d> {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -302,7 +302,7 @@ mod embedded_io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'d> embedded_io::asynch::Write for TcpSocket<'d> {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +310,7 @@ mod embedded_io_impls {
 | 
			
		||||
            self.io.write(buf)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -324,7 +324,7 @@ mod embedded_io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'d> embedded_io::asynch::Read for TcpReader<'d> {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -338,7 +338,7 @@ mod embedded_io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'d> embedded_io::asynch::Write for TcpWriter<'d> {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -346,7 +346,7 @@ mod embedded_io_impls {
 | 
			
		||||
            self.io.write(buf)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -445,7 +445,7 @@ pub mod client {
 | 
			
		||||
    impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read
 | 
			
		||||
        for TcpConnection<'d, N, TX_SZ, RX_SZ>
 | 
			
		||||
    {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -457,7 +457,7 @@ pub mod client {
 | 
			
		||||
    impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write
 | 
			
		||||
        for TcpConnection<'d, N, TX_SZ, RX_SZ>
 | 
			
		||||
    {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -465,7 +465,7 @@ pub mod client {
 | 
			
		||||
            self.socket.write(buf)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -75,8 +75,8 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
 | 
			
		||||
 | 
			
		||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true}
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"], optional = true }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true}
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"], optional = true }
 | 
			
		||||
 | 
			
		||||
defmt = { version = "0.3", optional = true }
 | 
			
		||||
log = { version = "0.4.14", optional = true }
 | 
			
		||||
@@ -90,13 +90,13 @@ embedded-storage = "0.3.0"
 | 
			
		||||
embedded-storage-async = { version = "0.3.0", optional = true }
 | 
			
		||||
cfg-if = "1.0.0"
 | 
			
		||||
 | 
			
		||||
nrf52805-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52810-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52811-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52820-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52832-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52833-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52840-pac  = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf5340-app-pac = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf5340-net-pac = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf9160-pac = { version = "0.11.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52805-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52810-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52811-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52820-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52832-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52833-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf52840-pac  = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf5340-app-pac = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf5340-net-pac = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
nrf9160-pac = { version = "0.12.0", optional = true, features = [ "rt" ] }
 | 
			
		||||
 
 | 
			
		||||
@@ -341,7 +341,7 @@ impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -351,7 +351,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for Buffe
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -361,7 +361,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read f
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -375,7 +375,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for Bu
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -389,7 +389,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRea
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -397,7 +397,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for Buff
 | 
			
		||||
        self.inner_write(buf)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -407,7 +407,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for Buff
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -415,7 +415,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write
 | 
			
		||||
        self.inner.inner_write(buf)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -193,8 +193,8 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -211,14 +211,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -212,14 +212,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -225,14 +225,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -271,14 +271,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -276,14 +276,14 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => static);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => static);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_02, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_03, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_28, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_29, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -458,14 +458,14 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable);
 | 
			
		||||
impl_ppi_channel!(PPI_CH30, 30 => configurable);
 | 
			
		||||
impl_ppi_channel!(PPI_CH31, 31 => configurable);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_13, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_14, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_15, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_16, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_17, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_18, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_19, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_20, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_13, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_14, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_15, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_16, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_17, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_18, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_19, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_20, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -339,14 +339,14 @@ impl_ppi_channel!(PPI_CH13, 13 => configurable);
 | 
			
		||||
impl_ppi_channel!(PPI_CH14, 14 => configurable);
 | 
			
		||||
impl_ppi_channel!(PPI_CH15, 15 => configurable);
 | 
			
		||||
 | 
			
		||||
impl_saadc_input!(P0_13, ANALOGINPUT0);
 | 
			
		||||
impl_saadc_input!(P0_14, ANALOGINPUT1);
 | 
			
		||||
impl_saadc_input!(P0_15, ANALOGINPUT2);
 | 
			
		||||
impl_saadc_input!(P0_16, ANALOGINPUT3);
 | 
			
		||||
impl_saadc_input!(P0_17, ANALOGINPUT4);
 | 
			
		||||
impl_saadc_input!(P0_18, ANALOGINPUT5);
 | 
			
		||||
impl_saadc_input!(P0_19, ANALOGINPUT6);
 | 
			
		||||
impl_saadc_input!(P0_20, ANALOGINPUT7);
 | 
			
		||||
impl_saadc_input!(P0_13, ANALOG_INPUT0);
 | 
			
		||||
impl_saadc_input!(P0_14, ANALOG_INPUT1);
 | 
			
		||||
impl_saadc_input!(P0_15, ANALOG_INPUT2);
 | 
			
		||||
impl_saadc_input!(P0_16, ANALOG_INPUT3);
 | 
			
		||||
impl_saadc_input!(P0_17, ANALOG_INPUT4);
 | 
			
		||||
impl_saadc_input!(P0_18, ANALOG_INPUT5);
 | 
			
		||||
impl_saadc_input!(P0_19, ANALOG_INPUT6);
 | 
			
		||||
impl_saadc_input!(P0_20, ANALOG_INPUT7);
 | 
			
		||||
 | 
			
		||||
pub mod irqs {
 | 
			
		||||
    use embassy_cortex_m::interrupt::_export::declare;
 | 
			
		||||
 
 | 
			
		||||
@@ -243,22 +243,25 @@ impl Driver for RtcDriver {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
        critical_section::with(|cs| {
 | 
			
		||||
            let n = alarm.id() as _;
 | 
			
		||||
            let alarm = self.get_alarm(cs, alarm);
 | 
			
		||||
            alarm.timestamp.set(timestamp);
 | 
			
		||||
 | 
			
		||||
            let t = self.now();
 | 
			
		||||
 | 
			
		||||
            // If alarm timestamp has passed, trigger it instantly.
 | 
			
		||||
            if timestamp <= t {
 | 
			
		||||
                self.trigger_alarm(n, cs);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let r = rtc();
 | 
			
		||||
 | 
			
		||||
            let t = self.now();
 | 
			
		||||
            if timestamp <= t {
 | 
			
		||||
                // If alarm timestamp has passed the alarm will not fire.
 | 
			
		||||
                // Disarm the alarm and return `false` to indicate that.
 | 
			
		||||
                r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
 | 
			
		||||
 | 
			
		||||
                alarm.timestamp.set(u64::MAX);
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If it hasn't triggered yet, setup it in the compare channel.
 | 
			
		||||
 | 
			
		||||
            // Write the CC value regardless of whether we're going to enable it now or not.
 | 
			
		||||
@@ -287,6 +290,8 @@ impl Driver for RtcDriver {
 | 
			
		||||
                // It will be setup later by `next_period`.
 | 
			
		||||
                r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            true
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -313,7 +313,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .await;
 | 
			
		||||
            regs.eventcause.write(|w| w.ready().set_bit()); // Write 1 to clear.
 | 
			
		||||
            regs.eventcause.write(|w| w.ready().clear_bit_by_one());
 | 
			
		||||
 | 
			
		||||
            errata::post_enable();
 | 
			
		||||
 | 
			
		||||
@@ -367,24 +367,24 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
 | 
			
		||||
            let r = regs.eventcause.read();
 | 
			
		||||
 | 
			
		||||
            if r.isooutcrc().bit() {
 | 
			
		||||
                regs.eventcause.write(|w| w.isooutcrc().set_bit());
 | 
			
		||||
                regs.eventcause.write(|w| w.isooutcrc().detected());
 | 
			
		||||
                trace!("USB event: isooutcrc");
 | 
			
		||||
            }
 | 
			
		||||
            if r.usbwuallowed().bit() {
 | 
			
		||||
                regs.eventcause.write(|w| w.usbwuallowed().set_bit());
 | 
			
		||||
                regs.eventcause.write(|w| w.usbwuallowed().allowed());
 | 
			
		||||
                trace!("USB event: usbwuallowed");
 | 
			
		||||
            }
 | 
			
		||||
            if r.suspend().bit() {
 | 
			
		||||
                regs.eventcause.write(|w| w.suspend().set_bit());
 | 
			
		||||
                regs.eventcause.write(|w| w.suspend().detected());
 | 
			
		||||
                regs.lowpower.write(|w| w.lowpower().low_power());
 | 
			
		||||
                return Poll::Ready(Event::Suspend);
 | 
			
		||||
            }
 | 
			
		||||
            if r.resume().bit() {
 | 
			
		||||
                regs.eventcause.write(|w| w.resume().set_bit());
 | 
			
		||||
                regs.eventcause.write(|w| w.resume().detected());
 | 
			
		||||
                return Poll::Ready(Event::Resume);
 | 
			
		||||
            }
 | 
			
		||||
            if r.ready().bit() {
 | 
			
		||||
                regs.eventcause.write(|w| w.ready().set_bit());
 | 
			
		||||
                regs.eventcause.write(|w| w.ready().ready());
 | 
			
		||||
                trace!("USB event: ready");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -512,7 +512,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
 | 
			
		||||
                    } else if r.resume().bit() {
 | 
			
		||||
                        Poll::Ready(())
 | 
			
		||||
                    } else if r.usbwuallowed().bit() {
 | 
			
		||||
                        regs.eventcause.write(|w| w.usbwuallowed().set_bit());
 | 
			
		||||
                        regs.eventcause.write(|w| w.usbwuallowed().allowed());
 | 
			
		||||
 | 
			
		||||
                        regs.dpdmvalue.write(|w| w.state().resume());
 | 
			
		||||
                        regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit());
 | 
			
		||||
 
 | 
			
		||||
@@ -53,13 +53,13 @@ cortex-m = "0.7.6"
 | 
			
		||||
critical-section = "1.1"
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
chrono = { version = "0.4", default-features = false, optional = true }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"], optional = true }
 | 
			
		||||
embedded-storage = { version = "0.3" }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"], optional = true }
 | 
			
		||||
 | 
			
		||||
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
 | 
			
		||||
#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
 | 
			
		||||
 | 
			
		||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true}
 | 
			
		||||
embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ impl Driver for TimerDriver {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
        let n = alarm.id() as usize;
 | 
			
		||||
        critical_section::with(|cs| {
 | 
			
		||||
            let alarm = &self.alarms.borrow(cs)[n];
 | 
			
		||||
@@ -81,11 +81,16 @@ impl Driver for TimerDriver {
 | 
			
		||||
            unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
 | 
			
		||||
 | 
			
		||||
            let now = self.now();
 | 
			
		||||
 | 
			
		||||
            // If alarm timestamp has passed, trigger it instantly.
 | 
			
		||||
            // This disarms it.
 | 
			
		||||
            if timestamp <= now {
 | 
			
		||||
                self.trigger_alarm(n, cs);
 | 
			
		||||
                // If alarm timestamp has passed the alarm will not fire.
 | 
			
		||||
                // Disarm the alarm and return `false` to indicate that.
 | 
			
		||||
                unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
 | 
			
		||||
 | 
			
		||||
                alarm.timestamp.set(u64::MAX);
 | 
			
		||||
 | 
			
		||||
                false
 | 
			
		||||
            } else {
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -355,7 +355,7 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -376,7 +376,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -397,7 +397,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -419,7 +419,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -441,7 +441,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -455,7 +455,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -465,7 +465,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -479,7 +479,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T>
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
 | 
			
		||||
 | 
			
		||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true}
 | 
			
		||||
embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
 | 
			
		||||
 | 
			
		||||
embedded-storage = "0.3.0"
 | 
			
		||||
@@ -67,7 +67,7 @@ nb = "1.0.0"
 | 
			
		||||
stm32-fmc = "0.2.4"
 | 
			
		||||
seq-macro = "0.3.0"
 | 
			
		||||
cfg-if = "1.0.0"
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"], optional = true }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"], optional = true }
 | 
			
		||||
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
proc-macro2 = "1.0.36"
 | 
			
		||||
@@ -82,9 +82,12 @@ memory-x = ["stm32-metapac/memory-x"]
 | 
			
		||||
subghz = []
 | 
			
		||||
exti = []
 | 
			
		||||
 | 
			
		||||
# Enables additional driver features that depend on embassy-time
 | 
			
		||||
time = ["dep:embassy-time"]
 | 
			
		||||
 | 
			
		||||
# Features starting with `_` are for internal use only. They're not intended
 | 
			
		||||
# to be enabled by other crates, and are not covered by semver guarantees.
 | 
			
		||||
_time-driver = ["dep:embassy-time"]
 | 
			
		||||
_time-driver = ["time"]
 | 
			
		||||
time-driver-any = ["_time-driver"]
 | 
			
		||||
time-driver-tim2 = ["_time-driver"]
 | 
			
		||||
time-driver-tim3 = ["_time-driver"]
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,6 @@ pub use sample_time::SampleTime;
 | 
			
		||||
 | 
			
		||||
pub struct Adc<'d, T: Instance> {
 | 
			
		||||
    sample_time: SampleTime,
 | 
			
		||||
    calibrated_vdda: u32,
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +121,6 @@ impl<'d, T: Instance> Adc<'d, T> {
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            sample_time: Default::default(),
 | 
			
		||||
            calibrated_vdda: VDDA_CALIB_MV,
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -162,29 +160,10 @@ impl<'d, T: Instance> Adc<'d, T> {
 | 
			
		||||
        Temperature {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Calculates the system VDDA by sampling the internal VREF channel and comparing
 | 
			
		||||
    /// to the expected value. If the chip's VDDA is not stable, run this before each ADC
 | 
			
		||||
    /// conversion.
 | 
			
		||||
    pub fn calibrate(&mut self, vref: &mut Vref) -> u32 {
 | 
			
		||||
        let old_sample_time = self.sample_time;
 | 
			
		||||
        self.sample_time = SampleTime::Cycles239_5;
 | 
			
		||||
 | 
			
		||||
        let vref_samp = self.read(vref);
 | 
			
		||||
        self.sample_time = old_sample_time;
 | 
			
		||||
 | 
			
		||||
        self.calibrated_vdda = (ADC_MAX * VREF_INT) / u32::from(vref_samp);
 | 
			
		||||
        self.calibrated_vdda
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_sample_time(&mut self, sample_time: SampleTime) {
 | 
			
		||||
        self.sample_time = sample_time;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Convert a measurement to millivolts
 | 
			
		||||
    pub fn to_millivolts(&self, sample: u16) -> u16 {
 | 
			
		||||
        ((u32::from(sample) * self.calibrated_vdda) / ADC_MAX) as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Perform a single conversion.
 | 
			
		||||
    fn convert(&mut self) -> u16 {
 | 
			
		||||
        unsafe {
 | 
			
		||||
 
 | 
			
		||||
@@ -80,15 +80,6 @@ impl super::sealed::InternalChannel<ADC1> for Temperature {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Temperature {
 | 
			
		||||
    /// Converts temperature sensor reading in millivolts to degrees celcius
 | 
			
		||||
    pub fn to_celcius(sample_mv: u16) -> f32 {
 | 
			
		||||
        // From 6.3.22 Temperature sensor characteristics
 | 
			
		||||
        const V25: i32 = 760; // mV
 | 
			
		||||
        const AVG_SLOPE: f32 = 2.5; // mV/C
 | 
			
		||||
 | 
			
		||||
        (sample_mv as i32 - V25) as f32 / AVG_SLOPE + 25.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Time needed for temperature sensor readings to stabilize
 | 
			
		||||
    pub fn start_time_us() -> u32 {
 | 
			
		||||
        10
 | 
			
		||||
@@ -172,7 +163,6 @@ impl Prescaler {
 | 
			
		||||
 | 
			
		||||
pub struct Adc<'d, T: Instance> {
 | 
			
		||||
    sample_time: SampleTime,
 | 
			
		||||
    vref_mv: u32,
 | 
			
		||||
    resolution: Resolution,
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
}
 | 
			
		||||
@@ -200,7 +190,6 @@ where
 | 
			
		||||
        Self {
 | 
			
		||||
            sample_time: Default::default(),
 | 
			
		||||
            resolution: Resolution::default(),
 | 
			
		||||
            vref_mv: VREF_DEFAULT_MV,
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -213,18 +202,6 @@ where
 | 
			
		||||
        self.resolution = resolution;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
 | 
			
		||||
    pub fn set_vref_mv(&mut self, vref_mv: u32) {
 | 
			
		||||
        self.vref_mv = vref_mv;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Convert a measurement to millivolts
 | 
			
		||||
    pub fn to_millivolts(&self, sample: u16) -> u16 {
 | 
			
		||||
        ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Enables internal voltage reference and returns [VrefInt], which can be used in
 | 
			
		||||
    /// [Adc::read_internal()] to perform conversion.
 | 
			
		||||
    pub fn enable_vrefint(&self) -> VrefInt {
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,6 @@ pub use sample_time::SampleTime;
 | 
			
		||||
 | 
			
		||||
pub struct Adc<'d, T: Instance> {
 | 
			
		||||
    sample_time: SampleTime,
 | 
			
		||||
    vref_mv: u32,
 | 
			
		||||
    resolution: Resolution,
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
}
 | 
			
		||||
@@ -244,7 +243,6 @@ impl<'d, T: Instance> Adc<'d, T> {
 | 
			
		||||
        Self {
 | 
			
		||||
            sample_time: Default::default(),
 | 
			
		||||
            resolution: Resolution::default(),
 | 
			
		||||
            vref_mv: VREF_DEFAULT_MV,
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -285,31 +283,6 @@ impl<'d, T: Instance> Adc<'d, T> {
 | 
			
		||||
        Vbat {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Calculates the system VDDA by sampling the internal VREFINT channel and comparing
 | 
			
		||||
    /// the result with the value stored at the factory. If the chip's VDDA is not stable, run
 | 
			
		||||
    /// this before each ADC conversion.
 | 
			
		||||
    #[cfg(not(stm32g0))] // TODO is this supposed to be public?
 | 
			
		||||
    #[allow(unused)] // TODO is this supposed to be public?
 | 
			
		||||
    fn calibrate(&mut self, vrefint: &mut VrefInt) {
 | 
			
		||||
        #[cfg(stm32l5)]
 | 
			
		||||
        let vrefint_cal: u32 = todo!();
 | 
			
		||||
        #[cfg(not(stm32l5))]
 | 
			
		||||
        let vrefint_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() };
 | 
			
		||||
        let old_sample_time = self.sample_time;
 | 
			
		||||
 | 
			
		||||
        // "Table 24. Embedded internal voltage reference" states that the sample time needs to be
 | 
			
		||||
        // at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving
 | 
			
		||||
        // some headroom.
 | 
			
		||||
        self.sample_time = SampleTime::Cycles640_5;
 | 
			
		||||
 | 
			
		||||
        // This can't actually fail, it's just in a result to satisfy hal trait
 | 
			
		||||
        let vrefint_samp = self.read(vrefint);
 | 
			
		||||
 | 
			
		||||
        self.sample_time = old_sample_time;
 | 
			
		||||
 | 
			
		||||
        self.vref_mv = (VREF_CALIB_MV * u32::from(vrefint_cal)) / u32::from(vrefint_samp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_sample_time(&mut self, sample_time: SampleTime) {
 | 
			
		||||
        self.sample_time = sample_time;
 | 
			
		||||
    }
 | 
			
		||||
@@ -318,18 +291,6 @@ impl<'d, T: Instance> Adc<'d, T> {
 | 
			
		||||
        self.resolution = resolution;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
 | 
			
		||||
    pub fn set_vref_mv(&mut self, vref_mv: u32) {
 | 
			
		||||
        self.vref_mv = vref_mv;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Convert a measurement to millivolts
 | 
			
		||||
    pub fn to_millivolts(&self, sample: u16) -> u16 {
 | 
			
		||||
        ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    /// Convert a raw sample from the `Temperature` to deg C
 | 
			
		||||
    pub fn to_degrees_centigrade(sample: u16) -> f32 {
 | 
			
		||||
 
 | 
			
		||||
@@ -314,7 +314,6 @@ impl Prescaler {
 | 
			
		||||
 | 
			
		||||
pub struct Adc<'d, T: Instance> {
 | 
			
		||||
    sample_time: SampleTime,
 | 
			
		||||
    vref_mv: u32,
 | 
			
		||||
    resolution: Resolution,
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
}
 | 
			
		||||
@@ -352,7 +351,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
 | 
			
		||||
 | 
			
		||||
        let mut s = Self {
 | 
			
		||||
            sample_time: Default::default(),
 | 
			
		||||
            vref_mv: VREF_DEFAULT_MV,
 | 
			
		||||
            resolution: Resolution::default(),
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
        };
 | 
			
		||||
@@ -459,18 +457,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
 | 
			
		||||
        self.resolution = resolution;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
 | 
			
		||||
    pub fn set_vref_mv(&mut self, vref_mv: u32) {
 | 
			
		||||
        self.vref_mv = vref_mv;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Convert a measurement to millivolts
 | 
			
		||||
    pub fn to_millivolts(&self, sample: u16) -> u16 {
 | 
			
		||||
        ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Perform a single conversion.
 | 
			
		||||
    fn convert(&mut self) -> u16 {
 | 
			
		||||
        unsafe {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,11 @@ use crate::interrupt::Interrupt;
 | 
			
		||||
mod _version;
 | 
			
		||||
pub use _version::*;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "time")]
 | 
			
		||||
mod timeout;
 | 
			
		||||
#[cfg(feature = "time")]
 | 
			
		||||
pub use timeout::*;
 | 
			
		||||
 | 
			
		||||
use crate::peripherals;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										142
									
								
								embassy-stm32/src/i2c/timeout.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								embassy-stm32/src/i2c/timeout.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
			
		||||
use embassy_time::{Duration, Instant};
 | 
			
		||||
 | 
			
		||||
use super::{Error, I2c, Instance};
 | 
			
		||||
 | 
			
		||||
/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
 | 
			
		||||
///
 | 
			
		||||
/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
 | 
			
		||||
/// A regular [I2c] would freeze until condition is removed.
 | 
			
		||||
pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> {
 | 
			
		||||
    i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>,
 | 
			
		||||
    timeout: Duration,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
 | 
			
		||||
    let deadline = Instant::now() + timeout;
 | 
			
		||||
    move || {
 | 
			
		||||
        if Instant::now() > deadline {
 | 
			
		||||
            Err(Error::Timeout)
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
 | 
			
		||||
        Self { i2c, timeout }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking read with a custom timeout
 | 
			
		||||
    pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> {
 | 
			
		||||
        self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
 | 
			
		||||
    pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_read_timeout(addr, buffer, self.timeout)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking write with a custom timeout
 | 
			
		||||
    pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> {
 | 
			
		||||
        self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
 | 
			
		||||
    pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_timeout(addr, bytes, self.timeout)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking write-read with a custom timeout
 | 
			
		||||
    pub fn blocking_write_read_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        addr: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        timeout: Duration,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        self.i2c
 | 
			
		||||
            .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
 | 
			
		||||
    pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    type Error = Error;
 | 
			
		||||
 | 
			
		||||
    fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
 | 
			
		||||
        self.blocking_read(addr, buffer)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    type Error = Error;
 | 
			
		||||
 | 
			
		||||
    fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
 | 
			
		||||
        self.blocking_write(addr, bytes)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    type Error = Error;
 | 
			
		||||
 | 
			
		||||
    fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
 | 
			
		||||
        self.blocking_write_read(addr, bytes, buffer)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "unstable-traits")]
 | 
			
		||||
mod eh1 {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        type Error = Error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
 | 
			
		||||
            self.blocking_read(address, buffer)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
 | 
			
		||||
            self.blocking_write(address, buffer)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
 | 
			
		||||
        where
 | 
			
		||||
            B: IntoIterator<Item = u8>,
 | 
			
		||||
        {
 | 
			
		||||
            todo!();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error>
 | 
			
		||||
        where
 | 
			
		||||
            B: IntoIterator<Item = u8>,
 | 
			
		||||
        {
 | 
			
		||||
            todo!();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
 | 
			
		||||
            self.blocking_write_read(address, wr_buffer, rd_buffer)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn transaction<'a>(
 | 
			
		||||
            &mut self,
 | 
			
		||||
            _address: u8,
 | 
			
		||||
            _operations: &mut [embedded_hal_1::i2c::Operation<'a>],
 | 
			
		||||
        ) -> Result<(), Self::Error> {
 | 
			
		||||
            todo!();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
 | 
			
		||||
        where
 | 
			
		||||
            O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
 | 
			
		||||
        {
 | 
			
		||||
            todo!();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
use core::marker::PhantomData;
 | 
			
		||||
 | 
			
		||||
use embassy_embedded_hal::SetConfig;
 | 
			
		||||
use embassy_hal_common::into_ref;
 | 
			
		||||
use embassy_hal_common::{into_ref, PeripheralRef};
 | 
			
		||||
 | 
			
		||||
use crate::dma::NoDma;
 | 
			
		||||
use crate::gpio::sealed::AFType;
 | 
			
		||||
use crate::gpio::Pull;
 | 
			
		||||
use crate::i2c::{Error, Instance, SclPin, SdaPin};
 | 
			
		||||
@@ -34,19 +35,26 @@ impl State {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct I2c<'d, T: Instance> {
 | 
			
		||||
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    tx_dma: PeripheralRef<'d, TXDMA>,
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    rx_dma: PeripheralRef<'d, RXDMA>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        _peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        scl: impl Peripheral<P = impl SclPin<T>> + 'd,
 | 
			
		||||
        sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
 | 
			
		||||
        _irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        tx_dma: impl Peripheral<P = TXDMA> + 'd,
 | 
			
		||||
        rx_dma: impl Peripheral<P = RXDMA> + 'd,
 | 
			
		||||
        freq: Hertz,
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        into_ref!(scl, sda);
 | 
			
		||||
        into_ref!(scl, sda, tx_dma, rx_dma);
 | 
			
		||||
 | 
			
		||||
        T::enable();
 | 
			
		||||
        T::reset();
 | 
			
		||||
@@ -99,7 +107,11 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Self { phantom: PhantomData }
 | 
			
		||||
        Self {
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
            tx_dma,
 | 
			
		||||
            rx_dma,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
 | 
			
		||||
@@ -141,7 +153,12 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
        Ok(sr1)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
 | 
			
		||||
    unsafe fn write_bytes(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        addr: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        // Send a START condition
 | 
			
		||||
 | 
			
		||||
        T::regs().cr1().modify(|reg| {
 | 
			
		||||
@@ -149,7 +166,9 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Wait until START condition was generated
 | 
			
		||||
        while !self.check_and_clear_error_flags()?.start() {}
 | 
			
		||||
        while !self.check_and_clear_error_flags()?.start() {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Also wait until signalled we're master and everything is waiting for us
 | 
			
		||||
        while {
 | 
			
		||||
@@ -157,7 +176,9 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
 | 
			
		||||
            let sr2 = T::regs().sr2().read();
 | 
			
		||||
            !sr2.msl() && !sr2.busy()
 | 
			
		||||
        } {}
 | 
			
		||||
        } {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set up current address, we're trying to talk to
 | 
			
		||||
        T::regs().dr().write(|reg| reg.set_dr(addr << 1));
 | 
			
		||||
@@ -165,26 +186,30 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
        // Wait until address was sent
 | 
			
		||||
        // Wait for the address to be acknowledged
 | 
			
		||||
        // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
 | 
			
		||||
        while !self.check_and_clear_error_flags()?.addr() {}
 | 
			
		||||
        while !self.check_and_clear_error_flags()?.addr() {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Clear condition by reading SR2
 | 
			
		||||
        let _ = T::regs().sr2().read();
 | 
			
		||||
 | 
			
		||||
        // Send bytes
 | 
			
		||||
        for c in bytes {
 | 
			
		||||
            self.send_byte(*c)?;
 | 
			
		||||
            self.send_byte(*c, &check_timeout)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fallthrough is success
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> {
 | 
			
		||||
    unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
 | 
			
		||||
        // Wait until we're ready for sending
 | 
			
		||||
        while {
 | 
			
		||||
            // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
 | 
			
		||||
            !self.check_and_clear_error_flags()?.txe()
 | 
			
		||||
        } {}
 | 
			
		||||
        } {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Push out a byte of data
 | 
			
		||||
        T::regs().dr().write(|reg| reg.set_dr(byte));
 | 
			
		||||
@@ -193,24 +218,33 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
        while {
 | 
			
		||||
            // Check for any potential error conditions.
 | 
			
		||||
            !self.check_and_clear_error_flags()?.btf()
 | 
			
		||||
        } {}
 | 
			
		||||
        } {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn recv_byte(&self) -> Result<u8, Error> {
 | 
			
		||||
    unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
 | 
			
		||||
        while {
 | 
			
		||||
            // Check for any potential error conditions.
 | 
			
		||||
            self.check_and_clear_error_flags()?;
 | 
			
		||||
 | 
			
		||||
            !T::regs().sr1().read().rxne()
 | 
			
		||||
        } {}
 | 
			
		||||
        } {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let value = T::regs().dr().read().dr();
 | 
			
		||||
        Ok(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
    pub fn blocking_read_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        addr: u8,
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        if let Some((last, buffer)) = buffer.split_last_mut() {
 | 
			
		||||
            // Send a START condition and set ACK bit
 | 
			
		||||
            unsafe {
 | 
			
		||||
@@ -221,27 +255,33 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Wait until START condition was generated
 | 
			
		||||
            while unsafe { !T::regs().sr1().read().start() } {}
 | 
			
		||||
            while unsafe { !self.check_and_clear_error_flags()?.start() } {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Also wait until signalled we're master and everything is waiting for us
 | 
			
		||||
            while {
 | 
			
		||||
                let sr2 = unsafe { T::regs().sr2().read() };
 | 
			
		||||
                !sr2.msl() && !sr2.busy()
 | 
			
		||||
            } {}
 | 
			
		||||
            } {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set up current address, we're trying to talk to
 | 
			
		||||
            unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) }
 | 
			
		||||
 | 
			
		||||
            // Wait until address was sent
 | 
			
		||||
            // Wait for the address to be acknowledged
 | 
			
		||||
            while unsafe { !self.check_and_clear_error_flags()?.addr() } {}
 | 
			
		||||
            while unsafe { !self.check_and_clear_error_flags()?.addr() } {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Clear condition by reading SR2
 | 
			
		||||
            let _ = unsafe { T::regs().sr2().read() };
 | 
			
		||||
 | 
			
		||||
            // Receive bytes into buffer
 | 
			
		||||
            for c in buffer {
 | 
			
		||||
                *c = unsafe { self.recv_byte()? };
 | 
			
		||||
                *c = unsafe { self.recv_byte(&check_timeout)? };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Prepare to send NACK then STOP after next byte
 | 
			
		||||
@@ -253,10 +293,12 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Receive last byte
 | 
			
		||||
            *last = unsafe { self.recv_byte()? };
 | 
			
		||||
            *last = unsafe { self.recv_byte(&check_timeout)? };
 | 
			
		||||
 | 
			
		||||
            // Wait for the STOP to be sent.
 | 
			
		||||
            while unsafe { T::regs().cr1().read().stop() } {}
 | 
			
		||||
            while unsafe { T::regs().cr1().read().stop() } {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Fallthrough is success
 | 
			
		||||
            Ok(())
 | 
			
		||||
@@ -265,25 +307,50 @@ impl<'d, T: Instance> I2c<'d, T> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
 | 
			
		||||
    pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_read_timeout(addr, buffer, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        addr: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            self.write_bytes(addr, bytes)?;
 | 
			
		||||
            self.write_bytes(addr, bytes, &check_timeout)?;
 | 
			
		||||
            // Send a STOP condition
 | 
			
		||||
            T::regs().cr1().modify(|reg| reg.set_stop(true));
 | 
			
		||||
            // Wait for STOP condition to transmit.
 | 
			
		||||
            while T::regs().cr1().read().stop() {}
 | 
			
		||||
            while T::regs().cr1().read().stop() {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Fallthrough is success
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        unsafe { self.write_bytes(addr, bytes)? };
 | 
			
		||||
        self.blocking_read(addr, buffer)?;
 | 
			
		||||
    pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_timeout(addr, bytes, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_read_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        addr: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        unsafe { self.write_bytes(addr, bytes, &check_timeout)? };
 | 
			
		||||
        self.blocking_read_timeout(addr, buffer, &check_timeout)?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
 | 
			
		||||
 
 | 
			
		||||
@@ -147,14 +147,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) {
 | 
			
		||||
    unsafe fn master_read(
 | 
			
		||||
        address: u8,
 | 
			
		||||
        length: usize,
 | 
			
		||||
        stop: Stop,
 | 
			
		||||
        reload: bool,
 | 
			
		||||
        restart: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        assert!(length < 256);
 | 
			
		||||
 | 
			
		||||
        if !restart {
 | 
			
		||||
            // Wait for any previous address sequence to end
 | 
			
		||||
            // automatically. This could be up to 50% of a bus
 | 
			
		||||
            // cycle (ie. up to 0.5/freq)
 | 
			
		||||
            while T::regs().cr2().read().start() {}
 | 
			
		||||
            while T::regs().cr2().read().start() {
 | 
			
		||||
                check_timeout()?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set START and prepare to receive bytes into
 | 
			
		||||
@@ -176,15 +185,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            w.set_autoend(stop.autoend());
 | 
			
		||||
            w.set_reload(reload);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) {
 | 
			
		||||
    unsafe fn master_write(
 | 
			
		||||
        address: u8,
 | 
			
		||||
        length: usize,
 | 
			
		||||
        stop: Stop,
 | 
			
		||||
        reload: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        assert!(length < 256);
 | 
			
		||||
 | 
			
		||||
        // Wait for any previous address sequence to end
 | 
			
		||||
        // automatically. This could be up to 50% of a bus
 | 
			
		||||
        // cycle (ie. up to 0.5/freq)
 | 
			
		||||
        while T::regs().cr2().read().start() {}
 | 
			
		||||
        while T::regs().cr2().read().start() {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let reload = if reload {
 | 
			
		||||
            i2c::vals::Reload::NOTCOMPLETED
 | 
			
		||||
@@ -204,12 +223,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            w.set_autoend(stop.autoend());
 | 
			
		||||
            w.set_reload(reload);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe fn master_continue(length: usize, reload: bool) {
 | 
			
		||||
    unsafe fn master_continue(
 | 
			
		||||
        length: usize,
 | 
			
		||||
        reload: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        assert!(length < 256 && length > 0);
 | 
			
		||||
 | 
			
		||||
        while !T::regs().isr().read().tcr() {}
 | 
			
		||||
        while !T::regs().isr().read().tcr() {
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let reload = if reload {
 | 
			
		||||
            i2c::vals::Reload::NOTCOMPLETED
 | 
			
		||||
@@ -221,6 +248,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            w.set_nbytes(length as u8);
 | 
			
		||||
            w.set_reload(reload);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn flush_txdr(&self) {
 | 
			
		||||
@@ -243,7 +272,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        //}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn wait_txe(&self) -> Result<(), Error> {
 | 
			
		||||
    fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
 | 
			
		||||
        loop {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                let isr = T::regs().isr().read();
 | 
			
		||||
@@ -261,10 +290,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                    return Err(Error::Nack);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn wait_rxne(&self) -> Result<(), Error> {
 | 
			
		||||
    fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
 | 
			
		||||
        loop {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                let isr = T::regs().isr().read();
 | 
			
		||||
@@ -282,10 +313,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                    return Err(Error::Nack);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn wait_tc(&self) -> Result<(), Error> {
 | 
			
		||||
    fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
 | 
			
		||||
        loop {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                let isr = T::regs().isr().read();
 | 
			
		||||
@@ -303,10 +336,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                    return Err(Error::Nack);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            check_timeout()?;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> {
 | 
			
		||||
    fn read_internal(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        restart: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        let completed_chunks = buffer.len() / 255;
 | 
			
		||||
        let total_chunks = if completed_chunks * 255 == buffer.len() {
 | 
			
		||||
            completed_chunks
 | 
			
		||||
@@ -322,20 +363,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                Stop::Automatic,
 | 
			
		||||
                last_chunk_idx != 0,
 | 
			
		||||
                restart,
 | 
			
		||||
            );
 | 
			
		||||
                &check_timeout,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (number, chunk) in buffer.chunks_mut(255).enumerate() {
 | 
			
		||||
            if number != 0 {
 | 
			
		||||
                // NOTE(unsafe) We have &mut self
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    Self::master_continue(chunk.len(), number != last_chunk_idx);
 | 
			
		||||
                    Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for byte in chunk {
 | 
			
		||||
                // Wait until we have received something
 | 
			
		||||
                self.wait_rxne()?;
 | 
			
		||||
                self.wait_rxne(&check_timeout)?;
 | 
			
		||||
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    *byte = T::regs().rxdr().read().rxdata();
 | 
			
		||||
@@ -345,7 +387,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
 | 
			
		||||
    fn write_internal(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        send_stop: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        let completed_chunks = bytes.len() / 255;
 | 
			
		||||
        let total_chunks = if completed_chunks * 255 == bytes.len() {
 | 
			
		||||
            completed_chunks
 | 
			
		||||
@@ -359,14 +407,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        // ST SAD+W
 | 
			
		||||
        // NOTE(unsafe) We have &mut self
 | 
			
		||||
        unsafe {
 | 
			
		||||
            Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0);
 | 
			
		||||
            Self::master_write(
 | 
			
		||||
                address,
 | 
			
		||||
                bytes.len().min(255),
 | 
			
		||||
                Stop::Software,
 | 
			
		||||
                last_chunk_idx != 0,
 | 
			
		||||
                &check_timeout,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (number, chunk) in bytes.chunks(255).enumerate() {
 | 
			
		||||
            if number != 0 {
 | 
			
		||||
                // NOTE(unsafe) We have &mut self
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    Self::master_continue(chunk.len(), number != last_chunk_idx);
 | 
			
		||||
                    Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -374,7 +428,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                // Wait until we are allowed to send data
 | 
			
		||||
                // (START has been ACKed or last byte when
 | 
			
		||||
                // through)
 | 
			
		||||
                self.wait_txe()?;
 | 
			
		||||
                self.wait_txe(&check_timeout)?;
 | 
			
		||||
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    T::regs().txdr().write(|w| w.set_txdata(*byte));
 | 
			
		||||
@@ -382,7 +436,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Wait until the write finishes
 | 
			
		||||
        self.wait_tc()?;
 | 
			
		||||
        self.wait_tc(&check_timeout)?;
 | 
			
		||||
 | 
			
		||||
        if send_stop {
 | 
			
		||||
            self.master_stop();
 | 
			
		||||
@@ -396,6 +450,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        first_slice: bool,
 | 
			
		||||
        last_slice: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error>
 | 
			
		||||
    where
 | 
			
		||||
        TXDMA: crate::i2c::TxDma<T>,
 | 
			
		||||
@@ -447,11 +502,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                    total_len.min(255),
 | 
			
		||||
                    Stop::Software,
 | 
			
		||||
                    (total_chunks != 1) || !last_slice,
 | 
			
		||||
                );
 | 
			
		||||
                    &check_timeout,
 | 
			
		||||
                )?;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice);
 | 
			
		||||
                Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?;
 | 
			
		||||
                T::regs().cr1().modify(|w| w.set_tcie(true));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -461,32 +517,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
 | 
			
		||||
 | 
			
		||||
            if chunks_transferred == total_chunks {
 | 
			
		||||
                return Poll::Ready(());
 | 
			
		||||
                return Poll::Ready(Ok(()));
 | 
			
		||||
            } else if chunks_transferred != 0 {
 | 
			
		||||
                remaining_len = remaining_len.saturating_sub(255);
 | 
			
		||||
                let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice;
 | 
			
		||||
 | 
			
		||||
                // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    Self::master_continue(remaining_len.min(255), !last_piece);
 | 
			
		||||
                    if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
 | 
			
		||||
                        return Poll::Ready(Err(e));
 | 
			
		||||
                    }
 | 
			
		||||
                    T::regs().cr1().modify(|w| w.set_tcie(true));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
        dma_transfer.await;
 | 
			
		||||
 | 
			
		||||
        if last_slice {
 | 
			
		||||
            // This should be done already
 | 
			
		||||
            self.wait_tc()?;
 | 
			
		||||
            self.wait_tc(&check_timeout)?;
 | 
			
		||||
            self.master_stop();
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error>
 | 
			
		||||
    async fn read_dma_internal(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        restart: bool,
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error>
 | 
			
		||||
    where
 | 
			
		||||
        RXDMA: crate::i2c::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
@@ -527,7 +591,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
 | 
			
		||||
        // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
 | 
			
		||||
        unsafe {
 | 
			
		||||
            Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart);
 | 
			
		||||
            Self::master_read(
 | 
			
		||||
                address,
 | 
			
		||||
                total_len.min(255),
 | 
			
		||||
                Stop::Software,
 | 
			
		||||
                total_chunks != 1,
 | 
			
		||||
                restart,
 | 
			
		||||
                &check_timeout,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        poll_fn(|cx| {
 | 
			
		||||
@@ -535,25 +606,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
 | 
			
		||||
 | 
			
		||||
            if chunks_transferred == total_chunks {
 | 
			
		||||
                return Poll::Ready(());
 | 
			
		||||
                return Poll::Ready(Ok(()));
 | 
			
		||||
            } else if chunks_transferred != 0 {
 | 
			
		||||
                remaining_len = remaining_len.saturating_sub(255);
 | 
			
		||||
                let last_piece = chunks_transferred + 1 == total_chunks;
 | 
			
		||||
 | 
			
		||||
                // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    Self::master_continue(remaining_len.min(255), !last_piece);
 | 
			
		||||
                    if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
 | 
			
		||||
                        return Poll::Ready(Err(e));
 | 
			
		||||
                    }
 | 
			
		||||
                    T::regs().cr1().modify(|w| w.set_tcie(true));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
        dma_transfer.await;
 | 
			
		||||
 | 
			
		||||
        // This should be done already
 | 
			
		||||
        self.wait_tc()?;
 | 
			
		||||
        self.wait_tc(&check_timeout)?;
 | 
			
		||||
        self.master_stop();
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
@@ -566,9 +639,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        TXDMA: crate::i2c::TxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        if bytes.is_empty() {
 | 
			
		||||
            self.write_internal(address, bytes, true)
 | 
			
		||||
            self.write_internal(address, bytes, true, || Ok(()))
 | 
			
		||||
        } else {
 | 
			
		||||
            self.write_dma_internal(address, bytes, true, true).await
 | 
			
		||||
            self.write_dma_internal(address, bytes, true, true, || Ok(())).await
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -587,7 +660,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            let next = iter.next();
 | 
			
		||||
            let is_last = next.is_none();
 | 
			
		||||
 | 
			
		||||
            self.write_dma_internal(address, c, first, is_last).await?;
 | 
			
		||||
            self.write_dma_internal(address, c, first, is_last, || Ok(())).await?;
 | 
			
		||||
            first = false;
 | 
			
		||||
            current = next;
 | 
			
		||||
        }
 | 
			
		||||
@@ -599,9 +672,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        RXDMA: crate::i2c::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        if buffer.is_empty() {
 | 
			
		||||
            self.read_internal(address, buffer, false)
 | 
			
		||||
            self.read_internal(address, buffer, false, || Ok(()))
 | 
			
		||||
        } else {
 | 
			
		||||
            self.read_dma_internal(address, buffer, false).await
 | 
			
		||||
            self.read_dma_internal(address, buffer, false, || Ok(())).await
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -611,15 +684,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
        RXDMA: super::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        if bytes.is_empty() {
 | 
			
		||||
            self.write_internal(address, bytes, false)?;
 | 
			
		||||
            self.write_internal(address, bytes, false, || Ok(()))?;
 | 
			
		||||
        } else {
 | 
			
		||||
            self.write_dma_internal(address, bytes, true, true).await?;
 | 
			
		||||
            self.write_dma_internal(address, bytes, true, true, || Ok(())).await?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if buffer.is_empty() {
 | 
			
		||||
            self.read_internal(address, buffer, true)?;
 | 
			
		||||
            self.read_internal(address, buffer, true, || Ok(()))?;
 | 
			
		||||
        } else {
 | 
			
		||||
            self.read_dma_internal(address, buffer, true).await?;
 | 
			
		||||
            self.read_dma_internal(address, buffer, true, || Ok(())).await?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
@@ -628,22 +701,55 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
    // =========================
 | 
			
		||||
    //  Blocking public API
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.read_internal(address, buffer, false)
 | 
			
		||||
    pub fn blocking_read_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        self.read_internal(address, buffer, false, &check_timeout)
 | 
			
		||||
        // Automatic Stop
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_read_timeout(address, buffer, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        self.write_internal(address, bytes, true, &check_timeout)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
 | 
			
		||||
        self.write_internal(address, bytes, true)
 | 
			
		||||
        self.blocking_write_timeout(address, bytes, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.write_internal(address, bytes, false)?;
 | 
			
		||||
        self.read_internal(address, buffer, true)
 | 
			
		||||
    pub fn blocking_write_read_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        bytes: &[u8],
 | 
			
		||||
        buffer: &mut [u8],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        self.write_internal(address, bytes, false, &check_timeout)?;
 | 
			
		||||
        self.read_internal(address, buffer, true, &check_timeout)
 | 
			
		||||
        // Automatic Stop
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
 | 
			
		||||
    pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_read_timeout(address, bytes, buffer, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_vectored_timeout(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        address: u8,
 | 
			
		||||
        bytes: &[&[u8]],
 | 
			
		||||
        check_timeout: impl Fn() -> Result<(), Error>,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        if bytes.is_empty() {
 | 
			
		||||
            return Err(Error::ZeroLengthTransfer);
 | 
			
		||||
        }
 | 
			
		||||
@@ -657,7 +763,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                first_length.min(255),
 | 
			
		||||
                Stop::Software,
 | 
			
		||||
                (first_length > 255) || (last_slice_index != 0),
 | 
			
		||||
            );
 | 
			
		||||
                &check_timeout,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (idx, slice) in bytes.iter().enumerate() {
 | 
			
		||||
@@ -673,7 +780,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            if idx != 0 {
 | 
			
		||||
                // NOTE(unsafe) We have &mut self
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255));
 | 
			
		||||
                    Self::master_continue(
 | 
			
		||||
                        slice_len.min(255),
 | 
			
		||||
                        (idx != last_slice_index) || (slice_len > 255),
 | 
			
		||||
                        &check_timeout,
 | 
			
		||||
                    )?;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -681,7 +792,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                if number != 0 {
 | 
			
		||||
                    // NOTE(unsafe) We have &mut self
 | 
			
		||||
                    unsafe {
 | 
			
		||||
                        Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index));
 | 
			
		||||
                        Self::master_continue(
 | 
			
		||||
                            chunk.len(),
 | 
			
		||||
                            (number != last_chunk_idx) || (idx != last_slice_index),
 | 
			
		||||
                            &check_timeout,
 | 
			
		||||
                        )?;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -689,7 +804,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
                    // Wait until we are allowed to send data
 | 
			
		||||
                    // (START has been ACKed or last byte when
 | 
			
		||||
                    // through)
 | 
			
		||||
                    self.wait_txe()?;
 | 
			
		||||
                    self.wait_txe(&check_timeout)?;
 | 
			
		||||
 | 
			
		||||
                    // Put byte on the wire
 | 
			
		||||
                    //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
 | 
			
		||||
@@ -700,11 +815,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Wait until the write finishes
 | 
			
		||||
        self.wait_tc()?;
 | 
			
		||||
        self.wait_tc(&check_timeout)?;
 | 
			
		||||
        self.master_stop();
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
 | 
			
		||||
        self.blocking_write_vectored_timeout(address, bytes, || Ok(()))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod eh02 {
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ pub mod sdmmc;
 | 
			
		||||
pub mod spi;
 | 
			
		||||
#[cfg(usart)]
 | 
			
		||||
pub mod usart;
 | 
			
		||||
#[cfg(usb)]
 | 
			
		||||
#[cfg(all(usb, feature = "time"))]
 | 
			
		||||
pub mod usb;
 | 
			
		||||
#[cfg(any(otgfs, otghs))]
 | 
			
		||||
pub mod usb_otg;
 | 
			
		||||
 
 | 
			
		||||
@@ -1534,14 +1534,14 @@ mod sdmmc_rs {
 | 
			
		||||
 | 
			
		||||
    impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
 | 
			
		||||
        type Error = Error;
 | 
			
		||||
        type ReadFuture<'a>
 | 
			
		||||
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a,
 | 
			
		||||
        = impl Future<Output = Result<(), Self::Error>> + 'a;
 | 
			
		||||
        type WriteFuture<'a>
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a,
 | 
			
		||||
        = impl Future<Output = Result<(), Self::Error>> + 'a;
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
        fn read<'a>(
 | 
			
		||||
            &'a mut self,
 | 
			
		||||
 
 | 
			
		||||
@@ -439,6 +439,7 @@ impl From<Timeout> for [u8; 3] {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "time")]
 | 
			
		||||
impl From<Timeout> for embassy_time::Duration {
 | 
			
		||||
    fn from(to: Timeout) -> Self {
 | 
			
		||||
        embassy_time::Duration::from_micros(to.as_micros().into())
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ impl From<RampTime> for core::time::Duration {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "time")]
 | 
			
		||||
impl From<RampTime> for embassy_time::Duration {
 | 
			
		||||
    fn from(rt: RampTime) -> Self {
 | 
			
		||||
        match rt {
 | 
			
		||||
 
 | 
			
		||||
@@ -292,19 +292,23 @@ impl Driver for RtcDriver {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
        critical_section::with(|cs| {
 | 
			
		||||
            let r = T::regs_gp16();
 | 
			
		||||
 | 
			
		||||
            let n = alarm.id() as _;
 | 
			
		||||
            let n = alarm.id() as usize;
 | 
			
		||||
            let alarm = self.get_alarm(cs, alarm);
 | 
			
		||||
            alarm.timestamp.set(timestamp);
 | 
			
		||||
 | 
			
		||||
            let t = self.now();
 | 
			
		||||
            if timestamp <= t {
 | 
			
		||||
                // If alarm timestamp has passed the alarm will not fire.
 | 
			
		||||
                // Disarm the alarm and return `false` to indicate that.
 | 
			
		||||
                unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) };
 | 
			
		||||
                self.trigger_alarm(n, cs);
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
                alarm.timestamp.set(u64::MAX);
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let safe_timestamp = timestamp.max(t + 3);
 | 
			
		||||
@@ -317,6 +321,8 @@ impl Driver for RtcDriver {
 | 
			
		||||
            let diff = timestamp - t;
 | 
			
		||||
            // NOTE(unsafe) We're in a critical section
 | 
			
		||||
            unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
 | 
			
		||||
 | 
			
		||||
            true
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,16 +46,44 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {}
 | 
			
		||||
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        state: &'d mut State<'d, T>,
 | 
			
		||||
        _uart: Uart<'d, T, NoDma, NoDma>,
 | 
			
		||||
        _peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
        tx: impl Peripheral<P = impl TxPin<T>> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        tx_buffer: &'d mut [u8],
 | 
			
		||||
        rx_buffer: &'d mut [u8],
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> BufferedUart<'d, T> {
 | 
			
		||||
        into_ref!(irq);
 | 
			
		||||
        into_ref!(_peri, rx, tx, irq);
 | 
			
		||||
 | 
			
		||||
        T::enable();
 | 
			
		||||
        T::reset();
 | 
			
		||||
 | 
			
		||||
        let r = T::regs();
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER);
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            r.cr1().modify(|w| {
 | 
			
		||||
            rx.set_as_af(rx.af_num(), AFType::Input);
 | 
			
		||||
            tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
 | 
			
		||||
            r.cr2().write(|_w| {});
 | 
			
		||||
            r.cr3().write(|_w| {});
 | 
			
		||||
            r.cr1().write(|w| {
 | 
			
		||||
                w.set_ue(true);
 | 
			
		||||
                w.set_te(true);
 | 
			
		||||
                w.set_re(true);
 | 
			
		||||
                w.set_m0(if config.parity != Parity::ParityNone {
 | 
			
		||||
                    vals::M0::BIT9
 | 
			
		||||
                } else {
 | 
			
		||||
                    vals::M0::BIT8
 | 
			
		||||
                });
 | 
			
		||||
                w.set_pce(config.parity != Parity::ParityNone);
 | 
			
		||||
                w.set_ps(match config.parity {
 | 
			
		||||
                    Parity::ParityOdd => vals::Ps::ODD,
 | 
			
		||||
                    Parity::ParityEven => vals::Ps::EVEN,
 | 
			
		||||
                    _ => vals::Ps::EVEN,
 | 
			
		||||
                });
 | 
			
		||||
                w.set_rxneie(true);
 | 
			
		||||
                w.set_idleie(true);
 | 
			
		||||
            });
 | 
			
		||||
@@ -283,7 +311,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -293,7 +321,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> {
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -303,7 +331,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -317,7 +345,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> {
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
 | 
			
		||||
    type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -331,7 +359,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -339,7 +367,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
        self.inner_write(buf)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -349,7 +377,7 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> {
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
    type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -357,7 +385,7 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u,
 | 
			
		||||
        self.inner.inner_write(buf)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
    type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
    where
 | 
			
		||||
        Self: 'a;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,11 @@
 | 
			
		||||
#![macro_use]
 | 
			
		||||
 | 
			
		||||
use core::future::poll_fn;
 | 
			
		||||
use core::marker::PhantomData;
 | 
			
		||||
use core::task::Poll;
 | 
			
		||||
 | 
			
		||||
use atomic_polyfill::{compiler_fence, Ordering};
 | 
			
		||||
use embassy_cortex_m::interrupt::InterruptExt;
 | 
			
		||||
use embassy_hal_common::{into_ref, PeripheralRef};
 | 
			
		||||
 | 
			
		||||
use crate::dma::NoDma;
 | 
			
		||||
@@ -10,6 +14,7 @@ use crate::gpio::sealed::AFType;
 | 
			
		||||
use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
 | 
			
		||||
#[cfg(not(any(lpuart_v1, lpuart_v2)))]
 | 
			
		||||
use crate::pac::usart::{regs, vals, Usart as Regs};
 | 
			
		||||
use crate::time::Hertz;
 | 
			
		||||
use crate::{peripherals, Peripheral};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 | 
			
		||||
@@ -44,6 +49,10 @@ pub struct Config {
 | 
			
		||||
    pub data_bits: DataBits,
 | 
			
		||||
    pub stop_bits: StopBits,
 | 
			
		||||
    pub parity: Parity,
 | 
			
		||||
    /// if true, on read-like method, if there is a latent error pending,
 | 
			
		||||
    /// read will abort, the error reported and cleared
 | 
			
		||||
    /// if false, the error is ignored and cleared
 | 
			
		||||
    pub detect_previous_overrun: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Config {
 | 
			
		||||
@@ -53,6 +62,8 @@ impl Default for Config {
 | 
			
		||||
            data_bits: DataBits::DataBits8,
 | 
			
		||||
            stop_bits: StopBits::STOP1,
 | 
			
		||||
            parity: Parity::ParityNone,
 | 
			
		||||
            // historical behavior
 | 
			
		||||
            detect_previous_overrun: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -70,10 +81,11 @@ pub enum Error {
 | 
			
		||||
    Overrun,
 | 
			
		||||
    /// Parity check error
 | 
			
		||||
    Parity,
 | 
			
		||||
    /// Buffer too large for DMA
 | 
			
		||||
    BufferTooLong,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
    tx: UartTx<'d, T, TxDma>,
 | 
			
		||||
    rx: UartRx<'d, T, RxDma>,
 | 
			
		||||
}
 | 
			
		||||
@@ -84,8 +96,9 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
 | 
			
		||||
    phantom: PhantomData<&'d mut T>,
 | 
			
		||||
    _peri: PeripheralRef<'d, T>,
 | 
			
		||||
    rx_dma: PeripheralRef<'d, RxDma>,
 | 
			
		||||
    detect_previous_overrun: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
 | 
			
		||||
@@ -135,10 +148,112 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
 | 
			
		||||
    fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self {
 | 
			
		||||
    /// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
        rx_dma: impl Peripheral<P = RxDma> + 'd,
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        into_ref!(peri, irq, rx, rx_dma);
 | 
			
		||||
 | 
			
		||||
        T::enable();
 | 
			
		||||
        T::reset();
 | 
			
		||||
 | 
			
		||||
        let r = T::regs();
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER);
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            rx.set_as_af(rx.af_num(), AFType::Input);
 | 
			
		||||
 | 
			
		||||
            r.cr2().write(|_w| {});
 | 
			
		||||
            r.cr3().write(|w| {
 | 
			
		||||
                // enable Error Interrupt: (Frame error, Noise error, Overrun error)
 | 
			
		||||
                w.set_eie(true);
 | 
			
		||||
            });
 | 
			
		||||
            r.cr1().write(|w| {
 | 
			
		||||
                // enable uart
 | 
			
		||||
                w.set_ue(true);
 | 
			
		||||
                // enable receiver
 | 
			
		||||
                w.set_re(true);
 | 
			
		||||
                // configure word size
 | 
			
		||||
                w.set_m0(if config.parity != Parity::ParityNone {
 | 
			
		||||
                    vals::M0::BIT9
 | 
			
		||||
                } else {
 | 
			
		||||
                    vals::M0::BIT8
 | 
			
		||||
                });
 | 
			
		||||
                // configure parity
 | 
			
		||||
                w.set_pce(config.parity != Parity::ParityNone);
 | 
			
		||||
                w.set_ps(match config.parity {
 | 
			
		||||
                    Parity::ParityOdd => vals::Ps::ODD,
 | 
			
		||||
                    Parity::ParityEven => vals::Ps::EVEN,
 | 
			
		||||
                    _ => vals::Ps::EVEN,
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        irq.set_handler(Self::on_interrupt);
 | 
			
		||||
        irq.unpend();
 | 
			
		||||
        irq.enable();
 | 
			
		||||
 | 
			
		||||
        // create state once!
 | 
			
		||||
        let _s = T::state();
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            _peri: peri,
 | 
			
		||||
            rx_dma,
 | 
			
		||||
            phantom: PhantomData,
 | 
			
		||||
            detect_previous_overrun: config.detect_previous_overrun,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn on_interrupt(_: *mut ()) {
 | 
			
		||||
        let r = T::regs();
 | 
			
		||||
        let s = T::state();
 | 
			
		||||
 | 
			
		||||
        let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
 | 
			
		||||
 | 
			
		||||
        let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
 | 
			
		||||
 | 
			
		||||
        if has_errors {
 | 
			
		||||
            // clear all interrupts and DMA Rx Request
 | 
			
		||||
            unsafe {
 | 
			
		||||
                r.cr1().modify(|w| {
 | 
			
		||||
                    // disable RXNE interrupt
 | 
			
		||||
                    w.set_rxneie(false);
 | 
			
		||||
                    // disable parity interrupt
 | 
			
		||||
                    w.set_peie(false);
 | 
			
		||||
                    // disable idle line interrupt
 | 
			
		||||
                    w.set_idleie(false);
 | 
			
		||||
                });
 | 
			
		||||
                r.cr3().modify(|w| {
 | 
			
		||||
                    // disable Error Interrupt: (Frame error, Noise error, Overrun error)
 | 
			
		||||
                    w.set_eie(false);
 | 
			
		||||
                    // disable DMA Rx Request
 | 
			
		||||
                    w.set_dmar(false);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
            s.rx_waker.wake();
 | 
			
		||||
        } else if cr1.idleie() && sr.idle() {
 | 
			
		||||
            // IDLE detected: no more data will come
 | 
			
		||||
            unsafe {
 | 
			
		||||
                r.cr1().modify(|w| {
 | 
			
		||||
                    // disable idle line detection
 | 
			
		||||
                    w.set_idleie(false);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                r.cr3().modify(|w| {
 | 
			
		||||
                    // disable DMA Rx Request
 | 
			
		||||
                    w.set_dmar(false);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
            s.rx_waker.wake();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -146,17 +261,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
 | 
			
		||||
    where
 | 
			
		||||
        RxDma: crate::usart::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        let ch = &mut self.rx_dma;
 | 
			
		||||
        let request = ch.request();
 | 
			
		||||
        unsafe {
 | 
			
		||||
            T::regs().cr3().modify(|reg| {
 | 
			
		||||
                reg.set_dmar(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        // If we don't assign future to a variable, the data register pointer
 | 
			
		||||
        // is held across an await and makes the future non-Send.
 | 
			
		||||
        let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer);
 | 
			
		||||
        transfer.await;
 | 
			
		||||
        self.inner_read(buffer, false).await?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -211,35 +317,259 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
 | 
			
		||||
    where
 | 
			
		||||
        RxDma: crate::usart::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        self.inner_read(buffer, true).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error>
 | 
			
		||||
    where
 | 
			
		||||
        RxDma: crate::usart::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        if buffer.is_empty() {
 | 
			
		||||
            return Ok(0);
 | 
			
		||||
        } else if buffer.len() > 0xFFFF {
 | 
			
		||||
            return Err(Error::BufferTooLong);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let r = T::regs();
 | 
			
		||||
 | 
			
		||||
        let buffer_len = buffer.len();
 | 
			
		||||
 | 
			
		||||
        let ch = &mut self.rx_dma;
 | 
			
		||||
        let request = ch.request();
 | 
			
		||||
 | 
			
		||||
        // SAFETY: The only way we might have a problem is using split rx and tx
 | 
			
		||||
        // here we only modify or read Rx related flags, interrupts and DMA channel
 | 
			
		||||
        unsafe {
 | 
			
		||||
            // Start USART DMA
 | 
			
		||||
            // will not do anything yet because DMAR is not yet set
 | 
			
		||||
            ch.start_read(request, rdr(r), buffer, Default::default());
 | 
			
		||||
 | 
			
		||||
            // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
 | 
			
		||||
            if !self.detect_previous_overrun {
 | 
			
		||||
                let sr = sr(r).read();
 | 
			
		||||
                // This read also clears the error and idle interrupt flags on v1.
 | 
			
		||||
                rdr(r).read_volatile();
 | 
			
		||||
                clear_interrupt_flags(r, sr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            r.cr1().modify(|w| {
 | 
			
		||||
                // disable RXNE interrupt
 | 
			
		||||
                w.set_rxneie(false);
 | 
			
		||||
                // enable parity interrupt if not ParityNone
 | 
			
		||||
                w.set_peie(w.pce());
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            r.cr3().modify(|w| {
 | 
			
		||||
                // enable Error Interrupt: (Frame error, Noise error, Overrun error)
 | 
			
		||||
                w.set_eie(true);
 | 
			
		||||
                // enable DMA Rx Request
 | 
			
		||||
                w.set_dmar(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
            // In case of errors already pending when reception started, interrupts may have already been raised
 | 
			
		||||
            // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
 | 
			
		||||
            // have been disabled in interrupt handler and DMA Rx Request has been disabled.
 | 
			
		||||
 | 
			
		||||
            let cr3 = r.cr3().read();
 | 
			
		||||
 | 
			
		||||
            if !cr3.dmar() {
 | 
			
		||||
                // something went wrong
 | 
			
		||||
                // because the only way to get this flag cleared is to have an interrupt
 | 
			
		||||
 | 
			
		||||
                // abort DMA transfer
 | 
			
		||||
                ch.request_stop();
 | 
			
		||||
                while ch.is_running() {}
 | 
			
		||||
 | 
			
		||||
                let sr = sr(r).read();
 | 
			
		||||
                // This read also clears the error and idle interrupt flags on v1.
 | 
			
		||||
                rdr(r).read_volatile();
 | 
			
		||||
                clear_interrupt_flags(r, sr);
 | 
			
		||||
 | 
			
		||||
                if sr.pe() {
 | 
			
		||||
                    return Err(Error::Parity);
 | 
			
		||||
                }
 | 
			
		||||
                if sr.fe() {
 | 
			
		||||
                    return Err(Error::Framing);
 | 
			
		||||
                }
 | 
			
		||||
                if sr.ne() {
 | 
			
		||||
                    return Err(Error::Noise);
 | 
			
		||||
                }
 | 
			
		||||
                if sr.ore() {
 | 
			
		||||
                    return Err(Error::Overrun);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                unreachable!();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // clear idle flag
 | 
			
		||||
            if enable_idle_line_detection {
 | 
			
		||||
                let sr = sr(r).read();
 | 
			
		||||
                // This read also clears the error and idle interrupt flags on v1.
 | 
			
		||||
                rdr(r).read_volatile();
 | 
			
		||||
                clear_interrupt_flags(r, sr);
 | 
			
		||||
 | 
			
		||||
                // enable idle interrupt
 | 
			
		||||
                r.cr1().modify(|w| {
 | 
			
		||||
                    w.set_idleie(true);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
        let res = poll_fn(move |cx| {
 | 
			
		||||
            let s = T::state();
 | 
			
		||||
 | 
			
		||||
            ch.set_waker(cx.waker());
 | 
			
		||||
            s.rx_waker.register(cx.waker());
 | 
			
		||||
 | 
			
		||||
            // SAFETY: read only and we only use Rx related flags
 | 
			
		||||
            let sr = unsafe { sr(r).read() };
 | 
			
		||||
 | 
			
		||||
            // SAFETY: only clears Rx related flags
 | 
			
		||||
            unsafe {
 | 
			
		||||
                // This read also clears the error and idle interrupt flags on v1.
 | 
			
		||||
                rdr(r).read_volatile();
 | 
			
		||||
                clear_interrupt_flags(r, sr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
            let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
 | 
			
		||||
 | 
			
		||||
            if has_errors {
 | 
			
		||||
                // all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler
 | 
			
		||||
 | 
			
		||||
                // stop dma transfer
 | 
			
		||||
                ch.request_stop();
 | 
			
		||||
                while ch.is_running() {}
 | 
			
		||||
 | 
			
		||||
                if sr.pe() {
 | 
			
		||||
                    return Poll::Ready(Err(Error::Parity));
 | 
			
		||||
                }
 | 
			
		||||
                if sr.fe() {
 | 
			
		||||
                    return Poll::Ready(Err(Error::Framing));
 | 
			
		||||
                }
 | 
			
		||||
                if sr.ne() {
 | 
			
		||||
                    return Poll::Ready(Err(Error::Noise));
 | 
			
		||||
                }
 | 
			
		||||
                if sr.ore() {
 | 
			
		||||
                    return Poll::Ready(Err(Error::Overrun));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if sr.idle() {
 | 
			
		||||
                // Idle line
 | 
			
		||||
 | 
			
		||||
                // stop dma transfer
 | 
			
		||||
                ch.request_stop();
 | 
			
		||||
                while ch.is_running() {}
 | 
			
		||||
 | 
			
		||||
                let n = buffer_len - (ch.remaining_transfers() as usize);
 | 
			
		||||
 | 
			
		||||
                return Poll::Ready(Ok(n));
 | 
			
		||||
            } else if !ch.is_running() {
 | 
			
		||||
                // DMA complete
 | 
			
		||||
                return Poll::Ready(Ok(buffer_len));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
 | 
			
		||||
        // clear all interrupts and DMA Rx Request
 | 
			
		||||
        // SAFETY: only clears Rx related flags
 | 
			
		||||
        unsafe {
 | 
			
		||||
            r.cr1().modify(|w| {
 | 
			
		||||
                // disable RXNE interrupt
 | 
			
		||||
                w.set_rxneie(false);
 | 
			
		||||
                // disable parity interrupt
 | 
			
		||||
                w.set_peie(false);
 | 
			
		||||
                // disable idle line interrupt
 | 
			
		||||
                w.set_idleie(false);
 | 
			
		||||
            });
 | 
			
		||||
            r.cr3().modify(|w| {
 | 
			
		||||
                // disable Error Interrupt: (Frame error, Noise error, Overrun error)
 | 
			
		||||
                w.set_eie(false);
 | 
			
		||||
                // disable DMA Rx Request
 | 
			
		||||
                w.set_dmar(false);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        res
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        _inner: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
        tx: impl Peripheral<P = impl TxPin<T>> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        tx_dma: impl Peripheral<P = TxDma> + 'd,
 | 
			
		||||
        rx_dma: impl Peripheral<P = RxDma> + 'd,
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        into_ref!(_inner, rx, tx, tx_dma, rx_dma);
 | 
			
		||||
        T::enable();
 | 
			
		||||
        T::reset();
 | 
			
		||||
 | 
			
		||||
        Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_with_rtscts(
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
        tx: impl Peripheral<P = impl TxPin<T>> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
 | 
			
		||||
        cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
 | 
			
		||||
        tx_dma: impl Peripheral<P = TxDma> + 'd,
 | 
			
		||||
        rx_dma: impl Peripheral<P = RxDma> + 'd,
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        into_ref!(cts, rts);
 | 
			
		||||
 | 
			
		||||
        T::enable();
 | 
			
		||||
        T::reset();
 | 
			
		||||
        let pclk_freq = T::frequency();
 | 
			
		||||
 | 
			
		||||
        // TODO: better calculation, including error checking and OVER8 if possible.
 | 
			
		||||
        let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER;
 | 
			
		||||
        unsafe {
 | 
			
		||||
            rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
 | 
			
		||||
            cts.set_as_af(cts.af_num(), AFType::Input);
 | 
			
		||||
            T::regs().cr3().write(|w| {
 | 
			
		||||
                w.set_rtse(true);
 | 
			
		||||
                w.set_ctse(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new_inner(
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
        tx: impl Peripheral<P = impl TxPin<T>> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        tx_dma: impl Peripheral<P = TxDma> + 'd,
 | 
			
		||||
        rx_dma: impl Peripheral<P = RxDma> + 'd,
 | 
			
		||||
        config: Config,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        into_ref!(peri, rx, tx, irq, tx_dma, rx_dma);
 | 
			
		||||
 | 
			
		||||
        let r = T::regs();
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER);
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            rx.set_as_af(rx.af_num(), AFType::Input);
 | 
			
		||||
            tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
 | 
			
		||||
            r.cr2().write(|_w| {});
 | 
			
		||||
            r.cr3().write(|_w| {});
 | 
			
		||||
            r.brr().write_value(regs::Brr(div));
 | 
			
		||||
            r.cr1().write(|w| {
 | 
			
		||||
                w.set_ue(true);
 | 
			
		||||
                w.set_te(true);
 | 
			
		||||
@@ -258,10 +588,20 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
 | 
			
		||||
        irq.unpend();
 | 
			
		||||
        irq.enable();
 | 
			
		||||
 | 
			
		||||
        // create state once!
 | 
			
		||||
        let _s = T::state();
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            tx: UartTx::new(tx_dma),
 | 
			
		||||
            rx: UartRx::new(rx_dma),
 | 
			
		||||
            phantom: PhantomData {},
 | 
			
		||||
            rx: UartRx {
 | 
			
		||||
                _peri: peri,
 | 
			
		||||
                rx_dma,
 | 
			
		||||
                detect_previous_overrun: config.detect_previous_overrun,
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -295,6 +635,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
        self.rx.blocking_read(buffer)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
 | 
			
		||||
    where
 | 
			
		||||
        RxDma: crate::usart::RxDma<T>,
 | 
			
		||||
    {
 | 
			
		||||
        self.rx.read_until_idle(buffer).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Split the Uart into a transmitter and receiver, which is
 | 
			
		||||
    /// particuarly useful when having two tasks correlating to
 | 
			
		||||
    /// transmitting and receiving.
 | 
			
		||||
@@ -303,6 +650,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) {
 | 
			
		||||
    // TODO: better calculation, including error checking and OVER8 if possible.
 | 
			
		||||
    let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
 | 
			
		||||
 | 
			
		||||
    unsafe {
 | 
			
		||||
        r.brr().write_value(regs::Brr(div));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod eh02 {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
@@ -352,6 +708,7 @@ mod eh1 {
 | 
			
		||||
                Self::Noise => embedded_hal_1::serial::ErrorKind::Noise,
 | 
			
		||||
                Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun,
 | 
			
		||||
                Self::Parity => embedded_hal_1::serial::ErrorKind::Parity,
 | 
			
		||||
                Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -536,13 +893,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) mod sealed {
 | 
			
		||||
    use embassy_sync::waitqueue::AtomicWaker;
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    pub struct State {
 | 
			
		||||
        pub rx_waker: AtomicWaker,
 | 
			
		||||
        pub tx_waker: AtomicWaker,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl State {
 | 
			
		||||
        pub const fn new() -> Self {
 | 
			
		||||
            Self {
 | 
			
		||||
                rx_waker: AtomicWaker::new(),
 | 
			
		||||
                tx_waker: AtomicWaker::new(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub trait BasicInstance: crate::rcc::RccPeripheral {
 | 
			
		||||
        const MULTIPLIER: u32;
 | 
			
		||||
        type Interrupt: crate::interrupt::Interrupt;
 | 
			
		||||
 | 
			
		||||
        fn regs() -> Regs;
 | 
			
		||||
        fn state() -> &'static State;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub trait FullInstance: BasicInstance {
 | 
			
		||||
@@ -550,7 +924,7 @@ pub(crate) mod sealed {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait BasicInstance: sealed::BasicInstance {}
 | 
			
		||||
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
 | 
			
		||||
 | 
			
		||||
pub trait FullInstance: sealed::FullInstance {}
 | 
			
		||||
 | 
			
		||||
@@ -572,6 +946,11 @@ macro_rules! impl_lpuart {
 | 
			
		||||
            fn regs() -> Regs {
 | 
			
		||||
                Regs(crate::pac::$inst.0)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn state() -> &'static crate::usart::sealed::State {
 | 
			
		||||
                static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new();
 | 
			
		||||
                &STATE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl BasicInstance for peripherals::$inst {}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/
 | 
			
		||||
features = ["nightly"]
 | 
			
		||||
target = "thumbv7em-none-eabi"
 | 
			
		||||
 | 
			
		||||
[package.metadata.docs.rs]
 | 
			
		||||
features = ["nightly"]
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
nightly = ["embedded-io/async"]
 | 
			
		||||
std = []
 | 
			
		||||
@@ -32,7 +35,7 @@ atomic-polyfill = "1.0.1"
 | 
			
		||||
critical-section = "1.1"
 | 
			
		||||
heapless = "0.7.5"
 | 
			
		||||
cfg-if = "1.0.0"
 | 
			
		||||
embedded-io = "0.3.0"
 | 
			
		||||
embedded-io = "0.3.1"
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
futures-executor = { version = "0.3.17", features = [ "thread-pool" ] }
 | 
			
		||||
 
 | 
			
		||||
@@ -361,7 +361,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Pipe<M, N> {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -371,7 +371,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Pipe<M, N> {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -379,7 +379,7 @@ mod io_impls {
 | 
			
		||||
            Pipe::write(self, buf).map(Ok)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -393,7 +393,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for &Pipe<M, N> {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -403,7 +403,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for &Pipe<M, N> {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -411,7 +411,7 @@ mod io_impls {
 | 
			
		||||
            Pipe::write(self, buf).map(Ok)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -425,7 +425,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Reader<'_, M, N> {
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -439,7 +439,7 @@ mod io_impls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Writer<'_, M, N> {
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
 | 
			
		||||
        type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
@@ -447,7 +447,7 @@ mod io_impls {
 | 
			
		||||
            Writer::write(self, buf).map(Ok)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
 | 
			
		||||
        type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
 | 
			
		||||
        where
 | 
			
		||||
            Self: 'a;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,16 @@
 | 
			
		||||
name = "embassy-time"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
description = "Instant and Duration for embedded no-std systems, with async timer support"
 | 
			
		||||
repository = "https://github.com/embassy-rs/embassy"
 | 
			
		||||
readme = "README.md"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
 | 
			
		||||
categories = [
 | 
			
		||||
    "embedded",
 | 
			
		||||
    "no-std",
 | 
			
		||||
    "concurrency",
 | 
			
		||||
    "asynchronous",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[package.metadata.embassy_docs]
 | 
			
		||||
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/
 | 
			
		||||
features = ["nightly", "defmt", "unstable-traits", "std"]
 | 
			
		||||
target = "x86_64-unknown-linux-gnu"
 | 
			
		||||
 | 
			
		||||
[package.metadata.docs.rs]
 | 
			
		||||
features = ["nightly", "defmt", "unstable-traits", "std"]
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
std = ["tick-hz-1_000_000"]
 | 
			
		||||
wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
 | 
			
		||||
@@ -26,6 +37,22 @@ unstable-traits = ["embedded-hal-1"]
 | 
			
		||||
# To use this you must have a time driver provided.
 | 
			
		||||
defmt-timestamp-uptime = ["defmt"]
 | 
			
		||||
 | 
			
		||||
# Create a global, generic queue that can be used with any executor
 | 
			
		||||
# To use this you must have a time driver provided.
 | 
			
		||||
generic-queue = []
 | 
			
		||||
 | 
			
		||||
# Set the number of timers for the generic queue.
 | 
			
		||||
#
 | 
			
		||||
# At most 1 `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
 | 
			
		||||
# 
 | 
			
		||||
# When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the
 | 
			
		||||
# end user to pick.
 | 
			
		||||
generic-queue-8 = ["generic-queue"]
 | 
			
		||||
generic-queue-16 = ["generic-queue"]
 | 
			
		||||
generic-queue-32 = ["generic-queue"]
 | 
			
		||||
generic-queue-64 = ["generic-queue"]
 | 
			
		||||
generic-queue-128 = ["generic-queue"]
 | 
			
		||||
 | 
			
		||||
# Set the `embassy_time` tick rate.
 | 
			
		||||
#
 | 
			
		||||
# 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 }
 | 
			
		||||
 | 
			
		||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true}
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true}
 | 
			
		||||
 | 
			
		||||
futures-util = { version = "0.3.17", default-features = false }
 | 
			
		||||
embassy-macros  = { version = "0.1.0", path = "../embassy-macros"}
 | 
			
		||||
embassy-sync = { version = "0.1", path = "../embassy-sync" }
 | 
			
		||||
atomic-polyfill = "1.0.1"
 | 
			
		||||
critical-section = "1.1"
 | 
			
		||||
cfg-if = "1.0.0"
 | 
			
		||||
heapless = "0.7"
 | 
			
		||||
 | 
			
		||||
# WASM dependencies
 | 
			
		||||
wasm-bindgen = { version = "0.2.81", optional = true }
 | 
			
		||||
js-sys = { version = "0.3", optional = true }
 | 
			
		||||
wasm-timer = { version = "0.2.5", optional = true }
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
serial_test = "0.9"
 | 
			
		||||
critical-section = { version = "1.1", features = ["std"] }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -105,20 +105,21 @@ pub trait Driver: Send + Sync + 'static {
 | 
			
		||||
    /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm
 | 
			
		||||
    /// timestamp, the provided callback function will be called.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If `timestamp` is already in the past, the alarm callback must be immediately fired.
 | 
			
		||||
    /// In this case, it is allowed (but not mandatory) to call the alarm callback synchronously from `set_alarm`.
 | 
			
		||||
    /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
 | 
			
		||||
    /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
 | 
			
		||||
    /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
 | 
			
		||||
    ///
 | 
			
		||||
    /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any.
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64);
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "Rust" {
 | 
			
		||||
    fn _embassy_time_now() -> u64;
 | 
			
		||||
    fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>;
 | 
			
		||||
    fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
 | 
			
		||||
    fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64);
 | 
			
		||||
    fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// See [`Driver::now`]
 | 
			
		||||
@@ -139,7 +140,7 @@ pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut (
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// See [`Driver::set_alarm`]
 | 
			
		||||
pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
    unsafe { _embassy_time_set_alarm(alarm, timestamp) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -167,7 +168,7 @@ macro_rules! time_driver_impl {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) {
 | 
			
		||||
        fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
            <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -127,12 +127,14 @@ impl Driver for TimeDriver {
 | 
			
		||||
        alarm.ctx = ctx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
        self.init();
 | 
			
		||||
        let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
 | 
			
		||||
        let alarm = &mut alarms[alarm.id() as usize];
 | 
			
		||||
        alarm.timestamp = timestamp;
 | 
			
		||||
        unsafe { self.signaler.as_ref() }.signal();
 | 
			
		||||
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -90,15 +90,23 @@ impl Driver for TimeDriver {
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
 | 
			
		||||
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
        self.init();
 | 
			
		||||
        let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
 | 
			
		||||
        let alarm = &mut alarms[alarm.id() as usize];
 | 
			
		||||
        let timeout = (timestamp - self.now()) as u32;
 | 
			
		||||
        if let Some(token) = alarm.token {
 | 
			
		||||
            clearTimeout(token);
 | 
			
		||||
        }
 | 
			
		||||
        alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000));
 | 
			
		||||
 | 
			
		||||
        let now = self.now();
 | 
			
		||||
        if timestamp <= now {
 | 
			
		||||
            false
 | 
			
		||||
        } else {
 | 
			
		||||
            let timeout = (timestamp - now) as u32;
 | 
			
		||||
            alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000));
 | 
			
		||||
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
 | 
			
		||||
#![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)]
 | 
			
		||||
#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
 | 
			
		||||
#![doc = include_str!("../README.md")]
 | 
			
		||||
#![allow(clippy::new_without_default)]
 | 
			
		||||
@@ -11,6 +11,7 @@ mod delay;
 | 
			
		||||
pub mod driver;
 | 
			
		||||
mod duration;
 | 
			
		||||
mod instant;
 | 
			
		||||
pub mod queue;
 | 
			
		||||
mod tick;
 | 
			
		||||
mod timer;
 | 
			
		||||
 | 
			
		||||
@@ -18,6 +19,8 @@ mod timer;
 | 
			
		||||
mod driver_std;
 | 
			
		||||
#[cfg(feature = "wasm")]
 | 
			
		||||
mod driver_wasm;
 | 
			
		||||
#[cfg(feature = "generic-queue")]
 | 
			
		||||
mod queue_generic;
 | 
			
		||||
 | 
			
		||||
pub use delay::{block_for, Delay};
 | 
			
		||||
pub use duration::Duration;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								embassy-time/src/queue.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								embassy-time/src/queue.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
//! Timer queue implementation
 | 
			
		||||
//!
 | 
			
		||||
//! This module defines the interface a timer queue needs to implement to power the `embassy_time` module.
 | 
			
		||||
//!
 | 
			
		||||
//! # Implementing a timer queue
 | 
			
		||||
//!
 | 
			
		||||
//! - Define a struct `MyTimerQueue`
 | 
			
		||||
//! - Implement [`TimerQueue`] for it
 | 
			
		||||
//! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl).
 | 
			
		||||
//!
 | 
			
		||||
//! # Linkage details
 | 
			
		||||
//!
 | 
			
		||||
//! Check the documentation of the [`driver`](crate::driver) module for more information.
 | 
			
		||||
//!
 | 
			
		||||
//! Similarly to driver, if there is none or multiple timer queues in the crate tree, linking will fail.
 | 
			
		||||
//!
 | 
			
		||||
//! # Example
 | 
			
		||||
//!
 | 
			
		||||
//! ```
 | 
			
		||||
//! use core::task::Waker;
 | 
			
		||||
//!
 | 
			
		||||
//! use embassy_time::Instant;
 | 
			
		||||
//! use embassy_time::queue::{TimerQueue};
 | 
			
		||||
//!
 | 
			
		||||
//! struct MyTimerQueue{}; // not public!
 | 
			
		||||
//! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
 | 
			
		||||
//!
 | 
			
		||||
//! impl TimerQueue for MyTimerQueue {
 | 
			
		||||
//!     fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
 | 
			
		||||
//!         todo!()
 | 
			
		||||
//!     }
 | 
			
		||||
//! }
 | 
			
		||||
//! ```
 | 
			
		||||
use core::task::Waker;
 | 
			
		||||
 | 
			
		||||
use crate::Instant;
 | 
			
		||||
 | 
			
		||||
/// Timer queue
 | 
			
		||||
pub trait TimerQueue {
 | 
			
		||||
    /// Schedules a waker in the queue to be awoken at moment `at`.
 | 
			
		||||
    /// If this moment is in the past, the waker might be awoken immediately.
 | 
			
		||||
    fn schedule_wake(&'static self, at: Instant, waker: &Waker);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Set the TimerQueue implementation.
 | 
			
		||||
///
 | 
			
		||||
/// See the module documentation for an example.
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! timer_queue_impl {
 | 
			
		||||
    (static $name:ident: $t: ty = $val:expr) => {
 | 
			
		||||
        static $name: $t = $val;
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        fn _embassy_time_schedule_wake(at: $crate::Instant, waker: &core::task::Waker) {
 | 
			
		||||
            <$t as $crate::queue::TimerQueue>::schedule_wake(&$name, at, waker);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										449
									
								
								embassy-time/src/queue_generic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										449
									
								
								embassy-time/src/queue_generic.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,449 @@
 | 
			
		||||
use core::cell::RefCell;
 | 
			
		||||
use core::cmp::{min, Ordering};
 | 
			
		||||
use core::task::Waker;
 | 
			
		||||
 | 
			
		||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 | 
			
		||||
use embassy_sync::blocking_mutex::Mutex;
 | 
			
		||||
use heapless::Vec;
 | 
			
		||||
 | 
			
		||||
use crate::driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
 | 
			
		||||
use crate::queue::TimerQueue;
 | 
			
		||||
use crate::Instant;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "generic-queue-8")]
 | 
			
		||||
const QUEUE_SIZE: usize = 8;
 | 
			
		||||
#[cfg(feature = "generic-queue-16")]
 | 
			
		||||
const QUEUE_SIZE: usize = 16;
 | 
			
		||||
#[cfg(feature = "generic-queue-32")]
 | 
			
		||||
const QUEUE_SIZE: usize = 32;
 | 
			
		||||
#[cfg(feature = "generic-queue-64")]
 | 
			
		||||
const QUEUE_SIZE: usize = 32;
 | 
			
		||||
#[cfg(feature = "generic-queue-128")]
 | 
			
		||||
const QUEUE_SIZE: usize = 128;
 | 
			
		||||
#[cfg(not(any(
 | 
			
		||||
    feature = "generic-queue-8",
 | 
			
		||||
    feature = "generic-queue-16",
 | 
			
		||||
    feature = "generic-queue-32",
 | 
			
		||||
    feature = "generic-queue-64",
 | 
			
		||||
    feature = "generic-queue-128"
 | 
			
		||||
)))]
 | 
			
		||||
const QUEUE_SIZE: usize = 64;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Timer {
 | 
			
		||||
    at: Instant,
 | 
			
		||||
    waker: Waker,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialEq for Timer {
 | 
			
		||||
    fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
        self.at == other.at
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Eq for Timer {}
 | 
			
		||||
 | 
			
		||||
impl PartialOrd for Timer {
 | 
			
		||||
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 | 
			
		||||
        self.at.partial_cmp(&other.at)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Ord for Timer {
 | 
			
		||||
    fn cmp(&self, other: &Self) -> Ordering {
 | 
			
		||||
        self.at.cmp(&other.at)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct InnerQueue {
 | 
			
		||||
    queue: Vec<Timer, QUEUE_SIZE>,
 | 
			
		||||
    alarm: AlarmHandle,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl InnerQueue {
 | 
			
		||||
    fn schedule_wake(&mut self, at: Instant, waker: &Waker) {
 | 
			
		||||
        self.queue
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find(|timer| timer.waker.will_wake(waker))
 | 
			
		||||
            .map(|mut timer| {
 | 
			
		||||
                timer.at = min(timer.at, at);
 | 
			
		||||
            })
 | 
			
		||||
            .unwrap_or_else(|| {
 | 
			
		||||
                let mut timer = Timer {
 | 
			
		||||
                    waker: waker.clone(),
 | 
			
		||||
                    at,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                loop {
 | 
			
		||||
                    match self.queue.push(timer) {
 | 
			
		||||
                        Ok(()) => break,
 | 
			
		||||
                        Err(e) => timer = e,
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    self.queue.pop().unwrap().waker.wake();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // Don't wait for the alarm callback to trigger and directly
 | 
			
		||||
        // dispatch all timers that are already due
 | 
			
		||||
        //
 | 
			
		||||
        // Then update the alarm if necessary
 | 
			
		||||
        self.dispatch();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn dispatch(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let now = Instant::now();
 | 
			
		||||
 | 
			
		||||
            let mut next_alarm = Instant::MAX;
 | 
			
		||||
 | 
			
		||||
            let mut i = 0;
 | 
			
		||||
            while i < self.queue.len() {
 | 
			
		||||
                let timer = &self.queue[i];
 | 
			
		||||
                if timer.at <= now {
 | 
			
		||||
                    let timer = self.queue.swap_remove(i);
 | 
			
		||||
                    timer.waker.wake();
 | 
			
		||||
                } else {
 | 
			
		||||
                    next_alarm = min(next_alarm, timer.at);
 | 
			
		||||
                    i += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if self.update_alarm(next_alarm) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn update_alarm(&mut self, next_alarm: Instant) -> bool {
 | 
			
		||||
        if next_alarm == Instant::MAX {
 | 
			
		||||
            true
 | 
			
		||||
        } else {
 | 
			
		||||
            set_alarm(self.alarm, next_alarm.as_ticks())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handle_alarm(&mut self) {
 | 
			
		||||
        self.dispatch();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Queue {
 | 
			
		||||
    inner: Mutex<CriticalSectionRawMutex, RefCell<Option<InnerQueue>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Queue {
 | 
			
		||||
    const fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: Mutex::new(RefCell::new(None)),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
 | 
			
		||||
        self.inner.lock(|inner| {
 | 
			
		||||
            let mut inner = inner.borrow_mut();
 | 
			
		||||
 | 
			
		||||
            if inner.is_none() {}
 | 
			
		||||
 | 
			
		||||
            inner
 | 
			
		||||
                .get_or_insert_with(|| {
 | 
			
		||||
                    let handle = unsafe { allocate_alarm() }.unwrap();
 | 
			
		||||
                    set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _);
 | 
			
		||||
                    InnerQueue {
 | 
			
		||||
                        queue: Vec::new(),
 | 
			
		||||
                        alarm: handle,
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
                .schedule_wake(at, waker)
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handle_alarm(&self) {
 | 
			
		||||
        self.inner
 | 
			
		||||
            .lock(|inner| inner.borrow_mut().as_mut().unwrap().handle_alarm());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handle_alarm_callback(ctx: *mut ()) {
 | 
			
		||||
        unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TimerQueue for Queue {
 | 
			
		||||
    fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
 | 
			
		||||
        Queue::schedule_wake(self, at, waker);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
crate::timer_queue_impl!(static QUEUE: Queue = Queue::new());
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use core::cell::Cell;
 | 
			
		||||
    use core::task::{RawWaker, RawWakerVTable, Waker};
 | 
			
		||||
    use std::rc::Rc;
 | 
			
		||||
    use std::sync::Mutex;
 | 
			
		||||
 | 
			
		||||
    use serial_test::serial;
 | 
			
		||||
 | 
			
		||||
    use super::InnerQueue;
 | 
			
		||||
    use crate::driver::{AlarmHandle, Driver};
 | 
			
		||||
    use crate::queue_generic::QUEUE;
 | 
			
		||||
    use crate::Instant;
 | 
			
		||||
 | 
			
		||||
    struct InnerTestDriver {
 | 
			
		||||
        now: u64,
 | 
			
		||||
        alarm: u64,
 | 
			
		||||
        callback: fn(*mut ()),
 | 
			
		||||
        ctx: *mut (),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl InnerTestDriver {
 | 
			
		||||
        const fn new() -> Self {
 | 
			
		||||
            Self {
 | 
			
		||||
                now: 0,
 | 
			
		||||
                alarm: u64::MAX,
 | 
			
		||||
                callback: Self::noop,
 | 
			
		||||
                ctx: core::ptr::null_mut(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn noop(_ctx: *mut ()) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsafe impl Send for InnerTestDriver {}
 | 
			
		||||
 | 
			
		||||
    struct TestDriver(Mutex<InnerTestDriver>);
 | 
			
		||||
 | 
			
		||||
    impl TestDriver {
 | 
			
		||||
        const fn new() -> Self {
 | 
			
		||||
            Self(Mutex::new(InnerTestDriver::new()))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn reset(&self) {
 | 
			
		||||
            *self.0.lock().unwrap() = InnerTestDriver::new();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn set_now(&self, now: u64) {
 | 
			
		||||
            let notify = {
 | 
			
		||||
                let mut inner = self.0.lock().unwrap();
 | 
			
		||||
 | 
			
		||||
                if inner.now < now {
 | 
			
		||||
                    inner.now = now;
 | 
			
		||||
 | 
			
		||||
                    if inner.alarm <= now {
 | 
			
		||||
                        inner.alarm = u64::MAX;
 | 
			
		||||
 | 
			
		||||
                        Some((inner.callback, inner.ctx))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        None
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    panic!("Going back in time?");
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if let Some((callback, ctx)) = notify {
 | 
			
		||||
                (callback)(ctx);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Driver for TestDriver {
 | 
			
		||||
        fn now(&self) -> u64 {
 | 
			
		||||
            self.0.lock().unwrap().now
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
 | 
			
		||||
            Some(AlarmHandle::new(0))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
 | 
			
		||||
            let mut inner = self.0.lock().unwrap();
 | 
			
		||||
 | 
			
		||||
            inner.callback = callback;
 | 
			
		||||
            inner.ctx = ctx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool {
 | 
			
		||||
            let mut inner = self.0.lock().unwrap();
 | 
			
		||||
 | 
			
		||||
            if timestamp <= inner.now {
 | 
			
		||||
                false
 | 
			
		||||
            } else {
 | 
			
		||||
                inner.alarm = timestamp;
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct TestWaker {
 | 
			
		||||
        pub awoken: Rc<Cell<bool>>,
 | 
			
		||||
        pub waker: Waker,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl TestWaker {
 | 
			
		||||
        fn new() -> Self {
 | 
			
		||||
            let flag = Rc::new(Cell::new(false));
 | 
			
		||||
 | 
			
		||||
            const VTABLE: RawWakerVTable = RawWakerVTable::new(
 | 
			
		||||
                |data: *const ()| {
 | 
			
		||||
                    unsafe {
 | 
			
		||||
                        Rc::increment_strong_count(data as *const Cell<bool>);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    RawWaker::new(data as _, &VTABLE)
 | 
			
		||||
                },
 | 
			
		||||
                |data: *const ()| unsafe {
 | 
			
		||||
                    let data = data as *const Cell<bool>;
 | 
			
		||||
                    data.as_ref().unwrap().set(true);
 | 
			
		||||
                    Rc::decrement_strong_count(data);
 | 
			
		||||
                },
 | 
			
		||||
                |data: *const ()| unsafe {
 | 
			
		||||
                    (data as *const Cell<bool>).as_ref().unwrap().set(true);
 | 
			
		||||
                },
 | 
			
		||||
                |data: *const ()| unsafe {
 | 
			
		||||
                    Rc::decrement_strong_count(data);
 | 
			
		||||
                },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let raw = RawWaker::new(Rc::into_raw(flag.clone()) as _, &VTABLE);
 | 
			
		||||
 | 
			
		||||
            Self {
 | 
			
		||||
                awoken: flag.clone(),
 | 
			
		||||
                waker: unsafe { Waker::from_raw(raw) },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    crate::time_driver_impl!(static DRIVER: TestDriver = TestDriver::new());
 | 
			
		||||
 | 
			
		||||
    fn setup() {
 | 
			
		||||
        DRIVER.reset();
 | 
			
		||||
 | 
			
		||||
        QUEUE.inner.lock(|inner| {
 | 
			
		||||
            *inner.borrow_mut() = InnerQueue::new();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn queue_len() -> usize {
 | 
			
		||||
        QUEUE.inner.lock(|inner| inner.borrow().queue.iter().count())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[serial]
 | 
			
		||||
    fn test_schedule() {
 | 
			
		||||
        setup();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 0);
 | 
			
		||||
 | 
			
		||||
        let waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert!(!waker.awoken.get());
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[serial]
 | 
			
		||||
    fn test_schedule_same() {
 | 
			
		||||
        setup();
 | 
			
		||||
 | 
			
		||||
        let waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
 | 
			
		||||
        let waker2 = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(100), &waker2.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[serial]
 | 
			
		||||
    fn test_trigger() {
 | 
			
		||||
        setup();
 | 
			
		||||
 | 
			
		||||
        let waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert!(!waker.awoken.get());
 | 
			
		||||
 | 
			
		||||
        DRIVER.set_now(Instant::from_secs(99).as_ticks());
 | 
			
		||||
 | 
			
		||||
        assert!(!waker.awoken.get());
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
 | 
			
		||||
        DRIVER.set_now(Instant::from_secs(100).as_ticks());
 | 
			
		||||
 | 
			
		||||
        assert!(waker.awoken.get());
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[serial]
 | 
			
		||||
    fn test_immediate_trigger() {
 | 
			
		||||
        setup();
 | 
			
		||||
 | 
			
		||||
        let waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
 | 
			
		||||
 | 
			
		||||
        DRIVER.set_now(Instant::from_secs(50).as_ticks());
 | 
			
		||||
 | 
			
		||||
        let waker2 = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(40), &waker2.waker);
 | 
			
		||||
 | 
			
		||||
        assert!(!waker.awoken.get());
 | 
			
		||||
        assert!(waker2.awoken.get());
 | 
			
		||||
        assert_eq!(queue_len(), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[serial]
 | 
			
		||||
    fn test_queue_overflow() {
 | 
			
		||||
        setup();
 | 
			
		||||
 | 
			
		||||
        for i in 1..super::QUEUE_SIZE {
 | 
			
		||||
            let waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
            QUEUE.schedule_wake(Instant::from_secs(310), &waker.waker);
 | 
			
		||||
 | 
			
		||||
            assert_eq!(queue_len(), i);
 | 
			
		||||
            assert!(!waker.awoken.get());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let first_waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(300), &first_waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), super::QUEUE_SIZE);
 | 
			
		||||
        assert!(!first_waker.awoken.get());
 | 
			
		||||
 | 
			
		||||
        let second_waker = TestWaker::new();
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(305), &second_waker.waker);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(queue_len(), super::QUEUE_SIZE);
 | 
			
		||||
        assert!(first_waker.awoken.get());
 | 
			
		||||
 | 
			
		||||
        QUEUE.schedule_wake(Instant::from_secs(320), &TestWaker::new().waker);
 | 
			
		||||
        assert_eq!(queue_len(), super::QUEUE_SIZE);
 | 
			
		||||
        assert!(second_waker.awoken.get());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
 | 
			
		||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
 | 
			
		||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
 | 
			
		||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
 | 
			
		||||
embedded-io = "0.3.0"
 | 
			
		||||
embedded-io = "0.3.1"
 | 
			
		||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
 | 
			
		||||
 | 
			
		||||
lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true }
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@ display-interface = "0.4.1"
 | 
			
		||||
byte-slice-cast = { version = "1.2.0", default-features = false }
 | 
			
		||||
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "0.1.0-alpha.1" }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
 | 
			
		||||
embedded-hal-async = { version = "0.1.0-alpha.3" }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async", "defmt"] }
 | 
			
		||||
embedded-storage = { version = "0.3" }
 | 
			
		||||
static_cell = "1.0.0"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["lo
 | 
			
		||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
 | 
			
		||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
 | 
			
		||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async", "std", "futures"] }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async", "std", "futures"] }
 | 
			
		||||
critical-section = { version = "1.1", features = ["std"] }
 | 
			
		||||
 | 
			
		||||
async-io = "1.6.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,19 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    let mut adc = Adc::new(p.ADC1, &mut Delay);
 | 
			
		||||
    let mut pin = p.PB1;
 | 
			
		||||
 | 
			
		||||
    let mut vref = adc.enable_vref(&mut Delay);
 | 
			
		||||
    adc.calibrate(&mut vref);
 | 
			
		||||
    let mut vrefint = adc.enable_vref(&mut Delay);
 | 
			
		||||
    let vrefint_sample = adc.read(&mut vrefint);
 | 
			
		||||
    let convert_to_millivolts = |sample| {
 | 
			
		||||
        // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
 | 
			
		||||
        // 5.3.4 Embedded reference voltage
 | 
			
		||||
        const VREFINT_MV: u32 = 1200; // mV
 | 
			
		||||
 | 
			
		||||
        (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        let v = adc.read(&mut pin);
 | 
			
		||||
        info!("--> {} - {} mV", v, adc.to_millivolts(v));
 | 
			
		||||
        info!("--> {} - {} mV", v, convert_to_millivolts(v));
 | 
			
		||||
        Timer::after(Duration::from_millis(100)).await;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ use core::fmt::Write;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use heapless::String;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(USART1);
 | 
			
		||||
    let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    for n in 0u32.. {
 | 
			
		||||
        let mut s: String<128> = String::new();
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ defmt-rtt = "0.3"
 | 
			
		||||
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
embedded-hal = "0.2.6"
 | 
			
		||||
embedded-io = "0.3.0"
 | 
			
		||||
embedded-io = "0.3.1"
 | 
			
		||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
heapless = { version = "0.7.5", default-features = false }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,19 +24,44 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    // Startup delay can be combined to the maximum of either
 | 
			
		||||
    delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
 | 
			
		||||
 | 
			
		||||
    let vrefint_sample = adc.read_internal(&mut vrefint);
 | 
			
		||||
 | 
			
		||||
    let convert_to_millivolts = |sample| {
 | 
			
		||||
        // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
 | 
			
		||||
        // 6.3.24 Reference voltage
 | 
			
		||||
        const VREFINT_MV: u32 = 1210; // mV
 | 
			
		||||
 | 
			
		||||
        (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let convert_to_celcius = |sample| {
 | 
			
		||||
        // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
 | 
			
		||||
        // 6.3.22 Temperature sensor characteristics
 | 
			
		||||
        const V25: i32 = 760; // mV
 | 
			
		||||
        const AVG_SLOPE: f32 = 2.5; // mV/C
 | 
			
		||||
 | 
			
		||||
        let sample_mv = convert_to_millivolts(sample) as i32;
 | 
			
		||||
 | 
			
		||||
        (sample_mv - V25) as f32 / AVG_SLOPE + 25.0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    info!("VrefInt: {}", vrefint_sample);
 | 
			
		||||
    const MAX_ADC_SAMPLE: u16 = (1 << 12) - 1;
 | 
			
		||||
    info!("VCCA: {} mV", convert_to_millivolts(MAX_ADC_SAMPLE));
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        // Read pin
 | 
			
		||||
        let v = adc.read(&mut pin);
 | 
			
		||||
        info!("PC1: {} ({} mV)", v, adc.to_millivolts(v));
 | 
			
		||||
        info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
 | 
			
		||||
 | 
			
		||||
        // Read internal temperature
 | 
			
		||||
        let v = adc.read_internal(&mut temp);
 | 
			
		||||
        let celcius = Temperature::to_celcius(adc.to_millivolts(v));
 | 
			
		||||
        let celcius = convert_to_celcius(v);
 | 
			
		||||
        info!("Internal temp: {} ({} C)", v, celcius);
 | 
			
		||||
 | 
			
		||||
        // Read internal voltage reference
 | 
			
		||||
        let v = adc.read_internal(&mut vrefint);
 | 
			
		||||
        info!("VrefInt: {} ({} mV)", v, adc.to_millivolts(v));
 | 
			
		||||
        info!("VrefInt: {}", v);
 | 
			
		||||
 | 
			
		||||
        Timer::after(Duration::from_millis(100)).await;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								examples/stm32f4/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								examples/stm32f4/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::time::Hertz;
 | 
			
		||||
use embassy_time::Duration;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
const ADDRESS: u8 = 0x5F;
 | 
			
		||||
const WHOAMI: u8 = 0x0F;
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) -> ! {
 | 
			
		||||
    info!("Hello world!");
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let irq = interrupt::take!(I2C2_EV);
 | 
			
		||||
    let mut i2c = I2c::new(
 | 
			
		||||
        p.I2C2,
 | 
			
		||||
        p.PB10,
 | 
			
		||||
        p.PB11,
 | 
			
		||||
        irq,
 | 
			
		||||
        NoDma,
 | 
			
		||||
        NoDma,
 | 
			
		||||
        Hertz(100_000),
 | 
			
		||||
        Default::default(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
 | 
			
		||||
    // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
 | 
			
		||||
    let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
 | 
			
		||||
 | 
			
		||||
    let mut data = [0u8; 1];
 | 
			
		||||
 | 
			
		||||
    match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
 | 
			
		||||
        Ok(()) => info!("Whoami: {}", data[0]),
 | 
			
		||||
        Err(Error::Timeout) => error!("Operation timed out"),
 | 
			
		||||
        Err(e) => error!("I2c Error: {:?}", e),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
use cortex_m_rt::entry;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
@@ -15,7 +16,8 @@ fn main() -> ! {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(USART3);
 | 
			
		||||
    let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
 | 
			
		||||
    info!("wrote Hello, starting echo");
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,8 @@
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{BufferedUart, Config, State, Uart};
 | 
			
		||||
use embassy_stm32::usart::{BufferedUart, Config, State};
 | 
			
		||||
use embedded_io::asynch::BufRead;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
@@ -16,13 +15,21 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    let mut state = State::new();
 | 
			
		||||
    let irq = interrupt::take!(USART3);
 | 
			
		||||
    let mut tx_buf = [0u8; 32];
 | 
			
		||||
    let mut rx_buf = [0u8; 32];
 | 
			
		||||
    let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf);
 | 
			
		||||
    let mut buf_usart = BufferedUart::new(
 | 
			
		||||
        &mut state,
 | 
			
		||||
        p.USART3,
 | 
			
		||||
        p.PD9,
 | 
			
		||||
        p.PD8,
 | 
			
		||||
        irq,
 | 
			
		||||
        &mut tx_buf,
 | 
			
		||||
        &mut rx_buf,
 | 
			
		||||
        config,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        let buf = buf_usart.fill_buf().await.unwrap();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ use core::fmt::Write;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use heapless::String;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(USART3);
 | 
			
		||||
    let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    for n in 0u32.. {
 | 
			
		||||
        let mut s: String<128> = String::new();
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 | 
			
		||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
 | 
			
		||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"]  }
 | 
			
		||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"] }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"] }
 | 
			
		||||
 | 
			
		||||
defmt = "0.3"
 | 
			
		||||
defmt-rtt = "0.3"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,19 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    let mut adc = Adc::new(p.ADC1, &mut Delay);
 | 
			
		||||
    let mut pin = p.PA3;
 | 
			
		||||
 | 
			
		||||
    let mut vrefint = adc.enable_vrefint();
 | 
			
		||||
    let vrefint_sample = adc.read_internal(&mut vrefint);
 | 
			
		||||
    let convert_to_millivolts = |sample| {
 | 
			
		||||
        // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
 | 
			
		||||
        // 6.3.27 Reference voltage
 | 
			
		||||
        const VREFINT_MV: u32 = 1210; // mV
 | 
			
		||||
 | 
			
		||||
        (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        let v = adc.read(&mut pin);
 | 
			
		||||
        info!("--> {} - {} mV", v, adc.to_millivolts(v));
 | 
			
		||||
        info!("--> {} - {} mV", v, convert_to_millivolts(v));
 | 
			
		||||
        Timer::after(Duration::from_millis(100)).await;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ use core::fmt::Write;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use heapless::String;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
@@ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
async fn main(_spawner: Spawner) {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(UART7);
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    for n in 0u32.. {
 | 
			
		||||
        let mut s: String<128> = String::new();
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 | 
			
		||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
 | 
			
		||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
 | 
			
		||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"] }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"] }
 | 
			
		||||
 | 
			
		||||
defmt = "0.3"
 | 
			
		||||
defmt-rtt = "0.3"
 | 
			
		||||
@@ -19,7 +19,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
embedded-hal = "0.2.6"
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3" }
 | 
			
		||||
embedded-nal-async = "0.2.0"
 | 
			
		||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								examples/stm32h7/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								examples/stm32h7/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::time::Hertz;
 | 
			
		||||
use embassy_time::Duration;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
const ADDRESS: u8 = 0x5F;
 | 
			
		||||
const WHOAMI: u8 = 0x0F;
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) -> ! {
 | 
			
		||||
    info!("Hello world!");
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let irq = interrupt::take!(I2C2_EV);
 | 
			
		||||
    let mut i2c = I2c::new(
 | 
			
		||||
        p.I2C2,
 | 
			
		||||
        p.PB10,
 | 
			
		||||
        p.PB11,
 | 
			
		||||
        irq,
 | 
			
		||||
        p.DMA1_CH4,
 | 
			
		||||
        p.DMA1_CH5,
 | 
			
		||||
        Hertz(100_000),
 | 
			
		||||
        Default::default(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
 | 
			
		||||
    // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
 | 
			
		||||
    let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
 | 
			
		||||
 | 
			
		||||
    let mut data = [0u8; 1];
 | 
			
		||||
 | 
			
		||||
    match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
 | 
			
		||||
        Ok(()) => info!("Whoami: {}", data[0]),
 | 
			
		||||
        Err(Error::Timeout) => error!("Operation timed out"),
 | 
			
		||||
        Err(e) => error!("I2c Error: {:?}", e),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,7 @@ use cortex_m_rt::entry;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Executor;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use static_cell::StaticCell;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
@@ -15,7 +16,8 @@ async fn main_task() {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(UART7);
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
 | 
			
		||||
    info!("wrote Hello, starting echo");
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ use cortex_m_rt::entry;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Executor;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use heapless::String;
 | 
			
		||||
use static_cell::StaticCell;
 | 
			
		||||
@@ -18,7 +19,8 @@ async fn main_task() {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(UART7);
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    for n in 0u32.. {
 | 
			
		||||
        let mut s: String<128> = String::new();
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::peripherals::{DMA1_CH1, UART7};
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart, UartRx};
 | 
			
		||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 | 
			
		||||
@@ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config);
 | 
			
		||||
    let irq = interrupt::take!(UART7);
 | 
			
		||||
    let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config);
 | 
			
		||||
    unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
 | 
			
		||||
 | 
			
		||||
    let (mut tx, rx) = usart.split();
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ defmt = "0.3"
 | 
			
		||||
defmt-rtt = "0.3"
 | 
			
		||||
 | 
			
		||||
embedded-storage = "0.3.0"
 | 
			
		||||
embedded-io = "0.3.0"
 | 
			
		||||
embedded-io = "0.3.1"
 | 
			
		||||
 | 
			
		||||
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,15 @@
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
    let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default());
 | 
			
		||||
    let irq = interrupt::take!(USART1);
 | 
			
		||||
    let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default());
 | 
			
		||||
 | 
			
		||||
    usart.write(b"Hello Embassy World!\r\n").await.unwrap();
 | 
			
		||||
    info!("wrote Hello, starting echo");
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,8 @@
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{BufferedUart, Config, State, Uart};
 | 
			
		||||
use embassy_stm32::usart::{BufferedUart, Config, State};
 | 
			
		||||
use embedded_io::asynch::{Read, Write};
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
@@ -21,15 +20,18 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    let mut config = Config::default();
 | 
			
		||||
    config.baudrate = 9600;
 | 
			
		||||
 | 
			
		||||
    let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config);
 | 
			
		||||
    let mut state = State::new();
 | 
			
		||||
    let irq = interrupt::take!(USART2);
 | 
			
		||||
    let mut usart = unsafe {
 | 
			
		||||
        BufferedUart::new(
 | 
			
		||||
            &mut state,
 | 
			
		||||
            usart,
 | 
			
		||||
            interrupt::take!(USART2),
 | 
			
		||||
            p.USART2,
 | 
			
		||||
            p.PA3,
 | 
			
		||||
            p.PA2,
 | 
			
		||||
            irq,
 | 
			
		||||
            &mut TX_BUFFER,
 | 
			
		||||
            &mut RX_BUFFER,
 | 
			
		||||
            config,
 | 
			
		||||
        )
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
embedded-hal = "0.2.6"
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3" }
 | 
			
		||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
heapless = { version = "0.7.5", default-features = false }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +15,8 @@ fn main() -> ! {
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(UART4);
 | 
			
		||||
    let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
 | 
			
		||||
    info!("wrote Hello, starting echo");
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ use core::fmt::Write;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use heapless::String;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config);
 | 
			
		||||
    let irq = interrupt::take!(UART4);
 | 
			
		||||
    let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    for n in 0u32.. {
 | 
			
		||||
        let mut s: String<128> = String::new();
 | 
			
		||||
 
 | 
			
		||||
@@ -26,5 +26,5 @@ embedded-hal = "0.2.6"
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
heapless = { version = "0.7.5", default-features = false }
 | 
			
		||||
rand_core = { version = "0.6.3", default-features = false }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"] }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"] }
 | 
			
		||||
static_cell = "1.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# Before upgrading check that everything is available on all tier1 targets here:
 | 
			
		||||
# https://rust-lang.github.io/rustup-components-history
 | 
			
		||||
[toolchain]
 | 
			
		||||
channel = "nightly-2022-09-22"
 | 
			
		||||
channel = "nightly-2022-10-25"
 | 
			
		||||
components = [ "rust-src", "rustfmt" ]
 | 
			
		||||
targets = [
 | 
			
		||||
    "thumbv7em-none-eabi",
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,10 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
embedded-hal = "0.2.6"
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3" }
 | 
			
		||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
 | 
			
		||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
			
		||||
embedded-io = { version = "0.3.0", features = ["async"] }
 | 
			
		||||
embedded-io = { version = "0.3.1", features = ["async"] }
 | 
			
		||||
embedded-storage = { version = "0.3" }
 | 
			
		||||
 | 
			
		||||
[profile.dev]
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 | 
			
		||||
cortex-m-rt = "0.7.0"
 | 
			
		||||
embedded-hal = "0.2.6"
 | 
			
		||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.2" }
 | 
			
		||||
embedded-hal-async = { version = "=0.1.0-alpha.3" }
 | 
			
		||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
 | 
			
		||||
 | 
			
		||||
[profile.dev]
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ mod example_common;
 | 
			
		||||
use defmt::assert_eq;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use example_common::*;
 | 
			
		||||
 | 
			
		||||
@@ -18,22 +19,22 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    // Arduino pins D0 and D1
 | 
			
		||||
    // They're connected together with a 1K resistor.
 | 
			
		||||
    #[cfg(feature = "stm32f103c8")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32g491re")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32g071rb")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32f429zi")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
 | 
			
		||||
    #[cfg(feature = "stm32wb55rg")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
 | 
			
		||||
    #[cfg(feature = "stm32h755zi")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32u585ai")]
 | 
			
		||||
    let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3);
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config);
 | 
			
		||||
    let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
    // We can't send too many bytes, they have to fit in the FIFO.
 | 
			
		||||
    // This is because we aren't sending+receiving at the same time.
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
mod example_common;
 | 
			
		||||
use defmt::assert_eq;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use example_common::*;
 | 
			
		||||
 | 
			
		||||
@@ -17,22 +18,53 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    // Arduino pins D0 and D1
 | 
			
		||||
    // They're connected together with a 1K resistor.
 | 
			
		||||
    #[cfg(feature = "stm32f103c8")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) = (
 | 
			
		||||
        p.PA9,
 | 
			
		||||
        p.PA10,
 | 
			
		||||
        p.USART1,
 | 
			
		||||
        interrupt::take!(USART1),
 | 
			
		||||
        p.DMA1_CH4,
 | 
			
		||||
        p.DMA1_CH5,
 | 
			
		||||
    );
 | 
			
		||||
    #[cfg(feature = "stm32g491re")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) =
 | 
			
		||||
        (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2);
 | 
			
		||||
    #[cfg(feature = "stm32g071rb")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) =
 | 
			
		||||
        (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2);
 | 
			
		||||
    #[cfg(feature = "stm32f429zi")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) = (
 | 
			
		||||
        p.PG14,
 | 
			
		||||
        p.PG9,
 | 
			
		||||
        p.USART6,
 | 
			
		||||
        interrupt::take!(USART6),
 | 
			
		||||
        p.DMA2_CH6,
 | 
			
		||||
        p.DMA2_CH1,
 | 
			
		||||
    );
 | 
			
		||||
    #[cfg(feature = "stm32wb55rg")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) = (
 | 
			
		||||
        p.PA2,
 | 
			
		||||
        p.PA3,
 | 
			
		||||
        p.LPUART1,
 | 
			
		||||
        interrupt::take!(LPUART1),
 | 
			
		||||
        p.DMA1_CH1,
 | 
			
		||||
        p.DMA1_CH2,
 | 
			
		||||
    );
 | 
			
		||||
    #[cfg(feature = "stm32h755zi")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) =
 | 
			
		||||
        (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1);
 | 
			
		||||
    #[cfg(feature = "stm32u585ai")]
 | 
			
		||||
    let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1);
 | 
			
		||||
    let (tx, rx, usart, irq, tx_dma, rx_dma) = (
 | 
			
		||||
        p.PD8,
 | 
			
		||||
        p.PD9,
 | 
			
		||||
        p.USART3,
 | 
			
		||||
        interrupt::take!(USART3),
 | 
			
		||||
        p.GPDMA1_CH0,
 | 
			
		||||
        p.GPDMA1_CH1,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config);
 | 
			
		||||
    let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config);
 | 
			
		||||
 | 
			
		||||
    // We can't send too many bytes, they have to fit in the FIFO.
 | 
			
		||||
    // This is because we aren't sending+receiving at the same time.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user