Merge pull request #3498 from embassy-rs/nrf-pac
nrf: port to chiptool-based `nrf-pac`.
This commit is contained in:
		
						commit
						3d8e987bf3
					
				| @ -17,7 +17,8 @@ log = [ "dep:log" ] | ||||
| defmt = { version = "0.3", optional = true } | ||||
| log = { version = "0.4.14", optional = true } | ||||
| 
 | ||||
| nrf9160-pac = { version = "0.12.0" } | ||||
| nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } | ||||
| cortex-m = "0.7.7" | ||||
| 
 | ||||
| embassy-time = { version = "0.3.1", path = "../embassy-time" } | ||||
| embassy-sync = { version = "0.6.0", path = "../embassy-sync"} | ||||
|  | ||||
| @ -17,12 +17,12 @@ use core::slice; | ||||
| use core::sync::atomic::{compiler_fence, fence, Ordering}; | ||||
| use core::task::{Poll, Waker}; | ||||
| 
 | ||||
| use cortex_m::peripheral::NVIC; | ||||
| use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||||
| use embassy_sync::pipe; | ||||
| use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; | ||||
| use heapless::Vec; | ||||
| use pac::NVIC; | ||||
| use {embassy_net_driver_channel as ch, nrf9160_pac as pac}; | ||||
| use {embassy_net_driver_channel as ch, nrf_pac as pac}; | ||||
| 
 | ||||
| const RX_SIZE: usize = 8 * 1024; | ||||
| const TRACE_SIZE: usize = 16 * 1024; | ||||
| @ -38,11 +38,9 @@ static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| 
 | ||||
| /// Call this function on IPC IRQ
 | ||||
| pub fn on_ipc_irq() { | ||||
|     let ipc = unsafe { &*pac::IPC_NS::ptr() }; | ||||
| 
 | ||||
|     trace!("irq"); | ||||
| 
 | ||||
|     ipc.inten.write(|w| w); | ||||
|     pac::IPC_NS.inten().write(|_| ()); | ||||
|     WAKER.wake(); | ||||
| } | ||||
| 
 | ||||
| @ -135,22 +133,21 @@ async fn new_internal<'a>( | ||||
|         "shmem must be in the lower 128kb of RAM" | ||||
|     ); | ||||
| 
 | ||||
|     let spu = unsafe { &*pac::SPU_S::ptr() }; | ||||
|     let spu = pac::SPU_S; | ||||
|     debug!("Setting IPC RAM as nonsecure..."); | ||||
|     let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; | ||||
|     let region_end = region_start + shmem_len / SPU_REGION_SIZE; | ||||
|     for i in region_start..region_end { | ||||
|         spu.ramregion[i].perm.write(|w| { | ||||
|             w.execute().set_bit(); | ||||
|             w.write().set_bit(); | ||||
|             w.read().set_bit(); | ||||
|             w.secattr().clear_bit(); | ||||
|             w.lock().clear_bit(); | ||||
|             w | ||||
|         spu.ramregion(i).perm().write(|w| { | ||||
|             w.set_execute(true); | ||||
|             w.set_write(true); | ||||
|             w.set_read(true); | ||||
|             w.set_secattr(false); | ||||
|             w.set_lock(false); | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     spu.periphid[42].perm.write(|w| w.secattr().non_secure()); | ||||
|     spu.periphid(42).perm().write(|w| w.set_secattr(false)); | ||||
| 
 | ||||
|     let mut alloc = Allocator { | ||||
|         start: shmem_ptr, | ||||
| @ -158,8 +155,8 @@ async fn new_internal<'a>( | ||||
|         _phantom: PhantomData, | ||||
|     }; | ||||
| 
 | ||||
|     let ipc = unsafe { &*pac::IPC_NS::ptr() }; | ||||
|     let power = unsafe { &*pac::POWER_S::ptr() }; | ||||
|     let ipc = pac::IPC_NS; | ||||
|     let power = pac::POWER_S; | ||||
| 
 | ||||
|     let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); | ||||
|     let rx = alloc.alloc_bytes(RX_SIZE); | ||||
| @ -177,20 +174,20 @@ async fn new_internal<'a>( | ||||
|     cb.trace.base = trace.as_mut_ptr() as _; | ||||
|     cb.trace.size = TRACE_SIZE; | ||||
| 
 | ||||
|     ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) }); | ||||
|     ipc.gpmem[1].write(|w| unsafe { w.bits(0) }); | ||||
|     ipc.gpmem(0).write_value(cb as *mut _ as u32); | ||||
|     ipc.gpmem(1).write_value(0); | ||||
| 
 | ||||
|     // connect task/event i to channel i
 | ||||
|     for i in 0..8 { | ||||
|         ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) }); | ||||
|         ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) }); | ||||
|         ipc.send_cnf(i).write(|w| w.0 = 1 << i); | ||||
|         ipc.receive_cnf(i).write(|w| w.0 = 1 << i); | ||||
|     } | ||||
| 
 | ||||
|     compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|     // POWER.LTEMODEM.STARTN = 0
 | ||||
|     // The reg is missing in the PAC??
 | ||||
|     let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) }; | ||||
|     let startn = unsafe { (power.as_ptr() as *mut u32).add(0x610 / 4) }; | ||||
|     unsafe { startn.write_volatile(0) } | ||||
| 
 | ||||
|     unsafe { NVIC::unmask(pac::Interrupt::IPC) }; | ||||
| @ -322,15 +319,15 @@ struct StateInner { | ||||
| impl StateInner { | ||||
|     fn poll(&mut self, trace_writer: &mut Option<TraceWriter<'_>>, ch: &mut ch::Runner<MTU>) { | ||||
|         trace!("poll!"); | ||||
|         let ipc = unsafe { &*pac::IPC_NS::ptr() }; | ||||
|         let ipc = pac::IPC_NS; | ||||
| 
 | ||||
|         if ipc.events_receive[0].read().bits() != 0 { | ||||
|             ipc.events_receive[0].reset(); | ||||
|         if ipc.events_receive(0).read() != 0 { | ||||
|             ipc.events_receive(0).write_value(0); | ||||
|             trace!("ipc 0"); | ||||
|         } | ||||
| 
 | ||||
|         if ipc.events_receive[2].read().bits() != 0 { | ||||
|             ipc.events_receive[2].reset(); | ||||
|         if ipc.events_receive(2).read() != 0 { | ||||
|             ipc.events_receive(2).write_value(0); | ||||
|             trace!("ipc 2"); | ||||
| 
 | ||||
|             if !self.init { | ||||
| @ -353,8 +350,8 @@ impl StateInner { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if ipc.events_receive[4].read().bits() != 0 { | ||||
|             ipc.events_receive[4].reset(); | ||||
|         if ipc.events_receive(4).read() != 0 { | ||||
|             ipc.events_receive(4).write_value(0); | ||||
|             trace!("ipc 4"); | ||||
| 
 | ||||
|             loop { | ||||
| @ -368,13 +365,13 @@ impl StateInner { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if ipc.events_receive[6].read().bits() != 0 { | ||||
|             ipc.events_receive[6].reset(); | ||||
|         if ipc.events_receive(6).read() != 0 { | ||||
|             ipc.events_receive(6).write_value(0); | ||||
|             trace!("ipc 6"); | ||||
|         } | ||||
| 
 | ||||
|         if ipc.events_receive[7].read().bits() != 0 { | ||||
|             ipc.events_receive[7].reset(); | ||||
|         if ipc.events_receive(7).read() != 0 { | ||||
|             ipc.events_receive(7).write_value(0); | ||||
|             trace!("ipc 7: trace"); | ||||
| 
 | ||||
|             let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() }; | ||||
| @ -437,13 +434,12 @@ impl StateInner { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ipc.intenset.write(|w| { | ||||
|             w.receive0().set_bit(); | ||||
|             w.receive2().set_bit(); | ||||
|             w.receive4().set_bit(); | ||||
|             w.receive6().set_bit(); | ||||
|             w.receive7().set_bit(); | ||||
|             w | ||||
|         ipc.intenset().write(|w| { | ||||
|             w.set_receive0(true); | ||||
|             w.set_receive2(true); | ||||
|             w.set_receive4(true); | ||||
|             w.set_receive6(true); | ||||
|             w.set_receive7(true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -546,8 +542,8 @@ impl StateInner { | ||||
|         unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) } | ||||
|         self.tx_seq_no = self.tx_seq_no.wrapping_add(1); | ||||
| 
 | ||||
|         let ipc = unsafe { &*pac::IPC_NS::ptr() }; | ||||
|         ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); | ||||
|         let ipc = pac::IPC_NS; | ||||
|         ipc.tasks_send(ipc_ch).write_value(1); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s | ||||
| 
 | ||||
| features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] | ||||
| flavors = [ | ||||
|     { regex_feature = "nrf51", target = "thumbv6m-none-eabi" }, | ||||
|     { regex_feature = "_nrf51", target = "thumbv6m-none-eabi" }, | ||||
|     { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, | ||||
|     { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, | ||||
|     { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, | ||||
| @ -28,20 +28,7 @@ rustdoc-args = ["--cfg", "docsrs"] | ||||
| [features] | ||||
| default = ["rt"] | ||||
| ## Cortex-M runtime (enabled by default) | ||||
| rt = [ | ||||
|     "nrf51-pac?/rt", | ||||
|     "nrf52805-pac?/rt", | ||||
|     "nrf52810-pac?/rt", | ||||
|     "nrf52811-pac?/rt", | ||||
|     "nrf52820-pac?/rt", | ||||
|     "nrf52832-pac?/rt", | ||||
|     "nrf52833-pac?/rt", | ||||
|     "nrf52840-pac?/rt", | ||||
|     "nrf5340-app-pac?/rt", | ||||
|     "nrf5340-net-pac?/rt", | ||||
|     "nrf9160-pac?/rt", | ||||
|     "nrf9120-pac?/rt", | ||||
| ] | ||||
| rt = ["nrf-pac/rt"] | ||||
| 
 | ||||
| ## Enable features requiring `embassy-time` | ||||
| time = ["dep:embassy-time"] | ||||
| @ -75,21 +62,21 @@ qspi-multiwrite-flash = [] | ||||
| 
 | ||||
| #! ### Chip selection features | ||||
| ## nRF51 | ||||
| nrf51 = ["nrf51-pac", "_nrf51"] | ||||
| nrf51 = ["nrf-pac/nrf51", "_nrf51"] | ||||
| ## nRF52805 | ||||
| nrf52805 = ["nrf52805-pac", "_nrf52"] | ||||
| nrf52805 = ["nrf-pac/nrf52805", "_nrf52"] | ||||
| ## nRF52810 | ||||
| nrf52810 = ["nrf52810-pac", "_nrf52"] | ||||
| nrf52810 = ["nrf-pac/nrf52810", "_nrf52"] | ||||
| ## nRF52811 | ||||
| nrf52811 = ["nrf52811-pac", "_nrf52"] | ||||
| nrf52811 = ["nrf-pac/nrf52811", "_nrf52"] | ||||
| ## nRF52820 | ||||
| nrf52820 = ["nrf52820-pac", "_nrf52"] | ||||
| nrf52820 = ["nrf-pac/nrf52820", "_nrf52"] | ||||
| ## nRF52832 | ||||
| nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] | ||||
| nrf52832 = ["nrf-pac/nrf52832", "_nrf52", "_nrf52832_anomaly_109"] | ||||
| ## nRF52833 | ||||
| nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] | ||||
| nrf52833 = ["nrf-pac/nrf52833", "_nrf52", "_gpio-p1"] | ||||
| ## nRF52840 | ||||
| nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] | ||||
| nrf52840 = ["nrf-pac/nrf52840", "_nrf52", "_gpio-p1"] | ||||
| ## nRF5340 application core in Secure mode | ||||
| nrf5340-app-s = ["_nrf5340-app", "_s"] | ||||
| ## nRF5340 application core in Non-Secure mode | ||||
| @ -113,11 +100,11 @@ nrf9161-ns = ["nrf9120-ns"] | ||||
| # 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. | ||||
| 
 | ||||
| _nrf5340-app = ["_nrf5340", "nrf5340-app-pac"] | ||||
| _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] | ||||
| _nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] | ||||
| _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] | ||||
| _nrf5340 = ["_gpio-p1", "_dppi"] | ||||
| _nrf9160 = ["nrf9160-pac", "_dppi"] | ||||
| _nrf9120 = ["nrf9120-pac", "_dppi"] | ||||
| _nrf9160 = ["nrf-pac/nrf9160", "_dppi"] | ||||
| _nrf9120 = ["nrf-pac/nrf9120", "_dppi"] | ||||
| _nrf52 = ["_ppi"] | ||||
| _nrf51 = ["_ppi"] | ||||
| _nrf91 = [] | ||||
| @ -149,6 +136,8 @@ embedded-hal-async = { version = "1.0" } | ||||
| embedded-io = { version = "0.6.0" } | ||||
| embedded-io-async = { version = "0.6.1" } | ||||
| 
 | ||||
| nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } | ||||
| 
 | ||||
| defmt = { version = "0.3", optional = true } | ||||
| bitflags = "2.4.2" | ||||
| log = { version = "0.4.14", optional = true } | ||||
| @ -162,15 +151,3 @@ embedded-storage-async = "0.4.1" | ||||
| cfg-if = "1.0.0" | ||||
| document-features = "0.2.7" | ||||
| 
 | ||||
| nrf51-pac = { version = "0.12.0", optional = true } | ||||
| nrf52805-pac = { version = "0.12.0", optional = true } | ||||
| nrf52810-pac = { version = "0.12.0", optional = true } | ||||
| nrf52811-pac = { version = "0.12.0", optional = true } | ||||
| nrf52820-pac = { version = "0.12.0", optional = true } | ||||
| nrf52832-pac = { version = "0.12.0", optional = true } | ||||
| nrf52833-pac = { version = "0.12.0", optional = true } | ||||
| nrf52840-pac = { version = "0.12.0", optional = true } | ||||
| nrf5340-app-pac = { version = "0.12.0", optional = true } | ||||
| nrf5340-net-pac = { version = "0.12.0", optional = true } | ||||
| nrf9160-pac = { version = "0.12.0", optional = true } | ||||
| nrf9120-pac = { version = "0.12.0", optional = true } | ||||
|  | ||||
| @ -17,16 +17,17 @@ use core::task::Poll; | ||||
| 
 | ||||
| use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use pac::uarte::vals; | ||||
| // Re-export SVD variants to allow user to directly set values
 | ||||
| pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | ||||
| pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; | ||||
| 
 | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin}; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::ppi::{ | ||||
|     self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, | ||||
| }; | ||||
| use crate::timer::{Instance as TimerInstance, Timer}; | ||||
| use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; | ||||
| use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance}; | ||||
| use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; | ||||
| 
 | ||||
| pub(crate) struct State { | ||||
| @ -79,57 +80,57 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
|             let buf_len = s.rx_buf.len(); | ||||
|             let half_len = buf_len / 2; | ||||
| 
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 let errs = r.errorsrc.read(); | ||||
|                 r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 let errs = r.errorsrc().read(); | ||||
|                 r.errorsrc().write_value(errs); | ||||
| 
 | ||||
|                 if errs.overrun().bit() { | ||||
|                 if errs.overrun() { | ||||
|                     panic!("BufferedUarte overrun"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Received some bytes, wake task.
 | ||||
|             if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { | ||||
|                 r.intenclr.write(|w| w.rxdrdy().clear()); | ||||
|                 r.events_rxdrdy.reset(); | ||||
|             if r.inten().read().rxdrdy() && r.events_rxdrdy().read() != 0 { | ||||
|                 r.intenclr().write(|w| w.set_rxdrdy(true)); | ||||
|                 r.events_rxdrdy().write_value(0); | ||||
|                 ss.rx_waker.wake(); | ||||
|             } | ||||
| 
 | ||||
|             if r.events_endrx.read().bits() != 0 { | ||||
|             if r.events_endrx().read() != 0 { | ||||
|                 //trace!("  irq_rx: endrx");
 | ||||
|                 r.events_endrx.reset(); | ||||
|                 r.events_endrx().write_value(0); | ||||
| 
 | ||||
|                 let val = s.rx_ended_count.load(Ordering::Relaxed); | ||||
|                 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); | ||||
|             } | ||||
| 
 | ||||
|             if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) { | ||||
|             if r.events_rxstarted().read() != 0 || !s.rx_started.load(Ordering::Relaxed) { | ||||
|                 //trace!("  irq_rx: rxstarted");
 | ||||
|                 let (ptr, len) = rx.push_buf(); | ||||
|                 if len >= half_len { | ||||
|                     r.events_rxstarted.reset(); | ||||
|                     r.events_rxstarted().write_value(0); | ||||
| 
 | ||||
|                     //trace!("  irq_rx: starting second {:?}", half_len);
 | ||||
| 
 | ||||
|                     // Set up the DMA read
 | ||||
|                     r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|                     r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); | ||||
|                     r.rxd().ptr().write_value(ptr as u32); | ||||
|                     r.rxd().maxcnt().write(|w| w.set_maxcnt(half_len as _)); | ||||
| 
 | ||||
|                     let chn = s.rx_ppi_ch.load(Ordering::Relaxed); | ||||
| 
 | ||||
|                     // Enable endrx -> startrx PPI channel.
 | ||||
|                     // From this point on, if endrx happens, startrx is automatically fired.
 | ||||
|                     ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); | ||||
|                     ppi::regs().chenset().write(|w| w.0 = 1 << chn); | ||||
| 
 | ||||
|                     // It is possible that endrx happened BEFORE enabling the PPI. In this case
 | ||||
|                     // the PPI channel doesn't trigger, and we'd hang. We have to detect this
 | ||||
|                     // and manually start.
 | ||||
| 
 | ||||
|                     // check again in case endrx has happened between the last check and now.
 | ||||
|                     if r.events_endrx.read().bits() != 0 { | ||||
|                     if r.events_endrx().read() != 0 { | ||||
|                         //trace!("  irq_rx: endrx");
 | ||||
|                         r.events_endrx.reset(); | ||||
|                         r.events_endrx().write_value(0); | ||||
| 
 | ||||
|                         let val = s.rx_ended_count.load(Ordering::Relaxed); | ||||
|                         s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); | ||||
| @ -144,7 +145,7 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
| 
 | ||||
|                     // Check if the PPI channel is still enabled. The PPI channel disables itself
 | ||||
|                     // when it fires, so if it's still enabled it hasn't fired.
 | ||||
|                     let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0; | ||||
|                     let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _); | ||||
| 
 | ||||
|                     // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed.
 | ||||
|                     // this condition also naturally matches if `!started`, needed to kickstart the DMA.
 | ||||
| @ -152,10 +153,10 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
|                         //trace!("manually starting.");
 | ||||
| 
 | ||||
|                         // disable the ppi ch, it's of no use anymore.
 | ||||
|                         ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) }); | ||||
|                         ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true)); | ||||
| 
 | ||||
|                         // manually start
 | ||||
|                         r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|                         r.tasks_startrx().write_value(1); | ||||
|                     } | ||||
| 
 | ||||
|                     rx.push_done(half_len); | ||||
| @ -164,7 +165,7 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
|                     s.rx_started.store(true, Ordering::Relaxed); | ||||
|                 } else { | ||||
|                     //trace!("  irq_rx: rxstarted no buf");
 | ||||
|                     r.intenclr.write(|w| w.rxstarted().clear()); | ||||
|                     r.intenclr().write(|w| w.set_rxstarted(true)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -173,8 +174,8 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
| 
 | ||||
|         if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { | ||||
|             // TX end
 | ||||
|             if r.events_endtx.read().bits() != 0 { | ||||
|                 r.events_endtx.reset(); | ||||
|             if r.events_endtx().read() != 0 { | ||||
|                 r.events_endtx().write_value(0); | ||||
| 
 | ||||
|                 let n = s.tx_count.load(Ordering::Relaxed); | ||||
|                 //trace!("  irq_tx: endtx {:?}", n);
 | ||||
| @ -192,11 +193,11 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt | ||||
|                     s.tx_count.store(len, Ordering::Relaxed); | ||||
| 
 | ||||
|                     // Set up the DMA write
 | ||||
|                     r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|                     r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|                     r.txd().ptr().write_value(ptr as u32); | ||||
|                     r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|                     // Start UARTE Transmit transaction
 | ||||
|                     r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_starttx().write_value(1); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -308,7 +309,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | ||||
|         let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); | ||||
|         let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); | ||||
| 
 | ||||
|         U::regs().enable.write(|w| w.enable().enabled()); | ||||
|         U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
|         U::Interrupt::pend(); | ||||
|         unsafe { U::Interrupt::enable() }; | ||||
| 
 | ||||
| @ -320,7 +321,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | ||||
|     /// Adjust the baud rate to the provided value.
 | ||||
|     pub fn set_baudrate(&mut self, baudrate: Baudrate) { | ||||
|         let r = U::regs(); | ||||
|         r.baudrate.write(|w| w.baudrate().variant(baudrate)); | ||||
|         r.baudrate().write(|w| w.set_baudrate(baudrate)); | ||||
|     } | ||||
| 
 | ||||
|     /// Split the UART in reader and writer parts.
 | ||||
| @ -415,7 +416,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { | ||||
| 
 | ||||
|         let this = Self::new_innerer(peri, txd, cts, tx_buffer); | ||||
| 
 | ||||
|         U::regs().enable.write(|w| w.enable().enabled()); | ||||
|         U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
|         U::Interrupt::pend(); | ||||
|         unsafe { U::Interrupt::enable() }; | ||||
| 
 | ||||
| @ -432,14 +433,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { | ||||
|     ) -> Self { | ||||
|         let r = U::regs(); | ||||
| 
 | ||||
|         txd.set_high(); | ||||
|         txd.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &cts { | ||||
|             pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||||
|         configure_tx_pins(r, txd, cts); | ||||
| 
 | ||||
|         // Initialize state
 | ||||
|         let s = U::buffered_state(); | ||||
| @ -447,12 +441,11 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { | ||||
|         let len = tx_buffer.len(); | ||||
|         unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; | ||||
| 
 | ||||
|         r.events_txstarted.reset(); | ||||
|         r.events_txstarted().write_value(0); | ||||
| 
 | ||||
|         // Enable interrupts
 | ||||
|         r.intenset.write(|w| { | ||||
|             w.endtx().set(); | ||||
|             w | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_endtx(true); | ||||
|         }); | ||||
| 
 | ||||
|         Self { _peri: peri } | ||||
| @ -532,15 +525,14 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = U::regs(); | ||||
| 
 | ||||
|         r.intenclr.write(|w| { | ||||
|             w.txdrdy().set_bit(); | ||||
|             w.txstarted().set_bit(); | ||||
|             w.txstopped().set_bit(); | ||||
|             w | ||||
|         r.intenclr().write(|w| { | ||||
|             w.set_txdrdy(true); | ||||
|             w.set_txstarted(true); | ||||
|             w.set_txstopped(true); | ||||
|         }); | ||||
|         r.events_txstopped.reset(); | ||||
|         r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||||
|         while r.events_txstopped.read().bits() == 0 {} | ||||
|         r.events_txstopped().write_value(0); | ||||
|         r.tasks_stoptx().write_value(1); | ||||
|         while r.events_txstopped().read() == 0 {} | ||||
| 
 | ||||
|         let s = U::buffered_state(); | ||||
|         unsafe { s.tx_buf.deinit() } | ||||
| @ -639,7 +631,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
| 
 | ||||
|         let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); | ||||
| 
 | ||||
|         U::regs().enable.write(|w| w.enable().enabled()); | ||||
|         U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
|         U::Interrupt::pend(); | ||||
|         unsafe { U::Interrupt::enable() }; | ||||
| 
 | ||||
| @ -663,14 +655,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
| 
 | ||||
|         let r = U::regs(); | ||||
| 
 | ||||
|         rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &rts { | ||||
|             pin.set_high(); | ||||
|             pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|         configure_rx_pins(r, rxd, rts); | ||||
| 
 | ||||
|         // Initialize state
 | ||||
|         let s = U::buffered_state(); | ||||
| @ -681,20 +666,19 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
|         unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; | ||||
| 
 | ||||
|         // clear errors
 | ||||
|         let errors = r.errorsrc.read().bits(); | ||||
|         r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||||
|         let errors = r.errorsrc().read(); | ||||
|         r.errorsrc().write_value(errors); | ||||
| 
 | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_rxstarted().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         r.events_endrx().write_value(0); | ||||
| 
 | ||||
|         // Enable interrupts
 | ||||
|         r.intenset.write(|w| { | ||||
|             w.endtx().set(); | ||||
|             w.rxstarted().set(); | ||||
|             w.error().set(); | ||||
|             w.endrx().set(); | ||||
|             w | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_endtx(true); | ||||
|             w.set_rxstarted(true); | ||||
|             w.set_error(true); | ||||
|             w.set_endrx(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Configure byte counter.
 | ||||
| @ -704,15 +688,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
|         timer.clear(); | ||||
|         timer.start(); | ||||
| 
 | ||||
|         let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); | ||||
|         let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); | ||||
|         ppi_ch1.enable(); | ||||
| 
 | ||||
|         s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); | ||||
|         let mut ppi_group = PpiGroup::new(ppi_group); | ||||
|         let mut ppi_ch2 = Ppi::new_one_to_two( | ||||
|             ppi_ch2, | ||||
|             Event::from_reg(&r.events_endrx), | ||||
|             Task::from_reg(&r.tasks_startrx), | ||||
|             Event::from_reg(r.events_endrx()), | ||||
|             Task::from_reg(r.tasks_startrx()), | ||||
|             ppi_group.task_disable_all(), | ||||
|         ); | ||||
|         ppi_ch2.disable(); | ||||
| @ -747,8 +731,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
|             let ss = U::state(); | ||||
| 
 | ||||
|             // Read the RXDRDY counter.
 | ||||
|             T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); | ||||
|             let mut end = T::regs().cc[0].read().bits() as usize; | ||||
|             T::regs().tasks_capture(0).write_value(1); | ||||
|             let mut end = T::regs().cc(0).read() as usize; | ||||
|             //trace!("  rxdrdy count = {:?}", end);
 | ||||
| 
 | ||||
|             // We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
 | ||||
| @ -769,7 +753,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
|             if start == end { | ||||
|                 //trace!("  empty");
 | ||||
|                 ss.rx_waker.register(cx.waker()); | ||||
|                 r.intenset.write(|w| w.rxdrdy().set_bit()); | ||||
|                 r.intenset().write(|w| w.set_rxdrdy(true)); | ||||
|                 return Poll::Pending; | ||||
|             } | ||||
| 
 | ||||
| @ -799,7 +783,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { | ||||
|         let s = U::buffered_state(); | ||||
|         let mut rx = unsafe { s.rx_buf.reader() }; | ||||
|         rx.pop_done(amt); | ||||
|         U::regs().intenset.write(|w| w.rxstarted().set()); | ||||
|         U::regs().intenset().write(|w| w.set_rxstarted(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// we are ready to read if there is data in the buffer
 | ||||
| @ -817,15 +801,14 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> | ||||
| 
 | ||||
|         self.timer.stop(); | ||||
| 
 | ||||
|         r.intenclr.write(|w| { | ||||
|             w.rxdrdy().set_bit(); | ||||
|             w.rxstarted().set_bit(); | ||||
|             w.rxto().set_bit(); | ||||
|             w | ||||
|         r.intenclr().write(|w| { | ||||
|             w.set_rxdrdy(true); | ||||
|             w.set_rxstarted(true); | ||||
|             w.set_rxto(true); | ||||
|         }); | ||||
|         r.events_rxto.reset(); | ||||
|         r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|         while r.events_rxto.read().bits() == 0 {} | ||||
|         r.events_rxto().write_value(0); | ||||
|         r.tasks_stoprx().write_value(1); | ||||
|         while r.events_rxto().read() == 0 {} | ||||
| 
 | ||||
|         let s = U::buffered_state(); | ||||
|         unsafe { s.rx_buf.deinit() } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf51_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52805_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52810_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52811_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52820_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52832_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52833_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| pub use nrf52840_pac as pac; | ||||
| pub use nrf_pac as pac; | ||||
| 
 | ||||
| /// The maximum buffer size that the EasyDMA can send/recv in one operation.
 | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | ||||
|  | ||||
| @ -5,16 +5,17 @@ pub mod pac { | ||||
|     // The nRF5340 has a secure and non-secure (NS) mode.
 | ||||
|     // To avoid cfg spam, we remove _ns or _s suffixes here.
 | ||||
| 
 | ||||
|     pub use nrf5340_app_pac::NVIC_PRIO_BITS; | ||||
|     #[cfg(feature="rt")] | ||||
|     pub use nrf_pac::NVIC_PRIO_BITS; | ||||
|     pub use nrf_pac::{common, shared}; | ||||
| 
 | ||||
|     #[cfg(feature="rt")] | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf5340_app_pac::interrupt; | ||||
|     pub use nrf_pac::interrupt; | ||||
| 
 | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf5340_app_pac::{ | ||||
|     pub use nrf_pac::{ | ||||
|         Interrupt, | ||||
|         Peripherals, | ||||
| 
 | ||||
|         cache_s as cache, | ||||
|         cachedata_s as cachedata, | ||||
| @ -26,11 +27,11 @@ pub mod pac { | ||||
|         ctrlap_ns as ctrlap, | ||||
|         dcnf_ns as dcnf, | ||||
|         dppic_ns as dppic, | ||||
|         egu0_ns as egu0, | ||||
|         egu_ns as egu, | ||||
|         ficr_s as ficr, | ||||
|         fpu_ns as fpu, | ||||
|         gpiote0_s as gpiote, | ||||
|         i2s0_ns as i2s0, | ||||
|         gpiote_s as gpiote, | ||||
|         i2s_ns as i2s, | ||||
|         ipc_ns as ipc, | ||||
|         kmu_ns as kmu, | ||||
|         lpcomp_ns as lpcomp, | ||||
| @ -38,36 +39,36 @@ pub mod pac { | ||||
|         nfct_ns as nfct, | ||||
|         nvmc_ns as nvmc, | ||||
|         oscillators_ns as oscillators, | ||||
|         p0_ns as p0, | ||||
|         pdm0_ns as pdm, | ||||
|         gpio_ns as gpio, | ||||
|         pdm_ns as pdm, | ||||
|         power_ns as power, | ||||
|         pwm0_ns as pwm0, | ||||
|         qdec0_ns as qdec, | ||||
|         pwm_ns as pwm, | ||||
|         qdec_ns as qdec, | ||||
|         qspi_ns as qspi, | ||||
|         regulators_ns as regulators, | ||||
|         reset_ns as reset, | ||||
|         rtc0_ns as rtc0, | ||||
|         rtc_ns as rtc, | ||||
|         saadc_ns as saadc, | ||||
|         spim0_ns as spim0, | ||||
|         spis0_ns as spis0, | ||||
|         spim_ns as spim, | ||||
|         spis_ns as spis, | ||||
|         spu_s as spu, | ||||
|         tad_s as tad, | ||||
|         timer0_ns as timer0, | ||||
|         twim0_ns as twim0, | ||||
|         twis0_ns as twis0, | ||||
|         uarte0_ns as uarte0, | ||||
|         timer_ns as timer, | ||||
|         twim_ns as twim, | ||||
|         twis_ns as twis, | ||||
|         uarte_ns as uarte, | ||||
|         uicr_s as uicr, | ||||
|         usbd_ns as usbd, | ||||
|         usbregulator_ns as usbregulator, | ||||
|         vmc_ns as vmc, | ||||
|         wdt0_ns as wdt0, | ||||
|         wdt_ns as wdt, | ||||
|     }; | ||||
|     
 | ||||
|     /// Non-Secure mode (NS) peripherals
 | ||||
|     pub mod ns { | ||||
|         #[cfg(feature = "nrf5340-app-ns")] | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf5340_app_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CLOCK_NS as CLOCK, | ||||
|             COMP_NS as COMP, | ||||
|             CTRLAP_NS as CTRLAP, | ||||
| @ -141,7 +142,7 @@ pub mod pac { | ||||
|     pub mod s { | ||||
|         #[cfg(feature = "nrf5340-app-s")] | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf5340_app_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CACHEDATA_S as CACHEDATA, | ||||
|             CACHEINFO_S as CACHEINFO, | ||||
|             CACHE_S as CACHE, | ||||
|  | ||||
| @ -5,16 +5,17 @@ pub mod pac { | ||||
|     // The nRF5340 has a secure and non-secure (NS) mode.
 | ||||
|     // To avoid cfg spam, we remove _ns or _s suffixes here.
 | ||||
| 
 | ||||
|     pub use nrf5340_net_pac::NVIC_PRIO_BITS; | ||||
|     #[cfg(feature="rt")] | ||||
|     pub use nrf_pac::NVIC_PRIO_BITS; | ||||
|     pub use nrf_pac::{common, shared}; | ||||
| 
 | ||||
|     #[cfg(feature="rt")] | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf5340_net_pac::interrupt; | ||||
|     pub use nrf_pac::interrupt; | ||||
| 
 | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf5340_net_pac::{ | ||||
|     pub use nrf_pac::{ | ||||
|         Interrupt, | ||||
|         Peripherals, | ||||
| 
 | ||||
|         aar_ns as aar, | ||||
|         acl_ns as acl, | ||||
| @ -26,25 +27,25 @@ pub mod pac { | ||||
|         dcnf_ns as dcnf, | ||||
|         dppic_ns as dppic, | ||||
|         ecb_ns as ecb, | ||||
|         egu0_ns as egu0, | ||||
|         egu_ns as egu, | ||||
|         ficr_ns as ficr, | ||||
|         gpiote_ns as gpiote, | ||||
|         ipc_ns as ipc, | ||||
|         nvmc_ns as nvmc, | ||||
|         p0_ns as p0, | ||||
|         gpio_ns as gpio, | ||||
|         power_ns as power, | ||||
|         radio_ns as radio, | ||||
|         reset_ns as reset, | ||||
|         rng_ns as rng, | ||||
|         rtc0_ns as rtc0, | ||||
|         spim0_ns as spim0, | ||||
|         spis0_ns as spis0, | ||||
|         swi0_ns as swi0, | ||||
|         rtc_ns as rtc, | ||||
|         spim_ns as spim, | ||||
|         spis_ns as spis, | ||||
|         swi_ns as swi, | ||||
|         temp_ns as temp, | ||||
|         timer0_ns as timer0, | ||||
|         twim0_ns as twim0, | ||||
|         twis0_ns as twis0, | ||||
|         uarte0_ns as uarte0, | ||||
|         timer_ns as timer, | ||||
|         twim_ns as twim, | ||||
|         twis_ns as twis, | ||||
|         uarte_ns as uarte, | ||||
|         uicr_ns as uicr, | ||||
|         vmc_ns as vmc, | ||||
|         vreqctrl_ns as vreqctrl, | ||||
| @ -54,25 +55,17 @@ pub mod pac { | ||||
|         ACL_NS as ACL, | ||||
|         APPMUTEX_NS as APPMUTEX, | ||||
|         APPMUTEX_S as APPMUTEX_S, | ||||
|         CBP as CBP, | ||||
|         CCM_NS as CCM, | ||||
|         CLOCK_NS as CLOCK, | ||||
|         CPUID as CPUID, | ||||
|         CTI_NS as CTI, | ||||
|         CTRLAP_NS as CTRLAP, | ||||
|         DCB as DCB, | ||||
|         DCNF_NS as DCNF, | ||||
|         DPPIC_NS as DPPIC, | ||||
|         DWT as DWT, | ||||
|         ECB_NS as ECB, | ||||
|         EGU0_NS as EGU0, | ||||
|         FICR_NS as FICR, | ||||
|         FPB as FPB, | ||||
|         GPIOTE_NS as GPIOTE, | ||||
|         IPC_NS as IPC, | ||||
|         ITM as ITM, | ||||
|         MPU as MPU, | ||||
|         NVIC as NVIC, | ||||
|         NVMC_NS as NVMC, | ||||
|         P0_NS as P0, | ||||
|         P1_NS as P1, | ||||
| @ -82,19 +75,16 @@ pub mod pac { | ||||
|         RNG_NS as RNG, | ||||
|         RTC0_NS as RTC0, | ||||
|         RTC1_NS as RTC1, | ||||
|         SCB as SCB, | ||||
|         SPIM0_NS as SPIM0, | ||||
|         SPIS0_NS as SPIS0, | ||||
|         SWI0_NS as SWI0, | ||||
|         SWI1_NS as SWI1, | ||||
|         SWI2_NS as SWI2, | ||||
|         SWI3_NS as SWI3, | ||||
|         SYST as SYST, | ||||
|         TEMP_NS as TEMP, | ||||
|         TIMER0_NS as TIMER0, | ||||
|         TIMER1_NS as TIMER1, | ||||
|         TIMER2_NS as TIMER2, | ||||
|         TPIU as TPIU, | ||||
|         TWIM0_NS as TWIM0, | ||||
|         TWIS0_NS as TWIS0, | ||||
|         UARTE0_NS as UARTE0, | ||||
|  | ||||
| @ -5,14 +5,16 @@ pub mod pac { | ||||
|     // The nRF9120 has a secure and non-secure (NS) mode.
 | ||||
|     // To avoid cfg spam, we remove _ns or _s suffixes here.
 | ||||
| 
 | ||||
|     pub use nrf9120_pac::NVIC_PRIO_BITS; | ||||
|     #[cfg(feature="rt")] | ||||
|     pub use nrf_pac::NVIC_PRIO_BITS; | ||||
|     pub use nrf_pac::{common, shared}; | ||||
| 
 | ||||
|     #[cfg(feature="rt")] | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf9120_pac::interrupt; | ||||
|     pub use nrf_pac::interrupt; | ||||
| 
 | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf9120_pac::{ | ||||
|     pub use nrf_pac::{ | ||||
|         Interrupt, | ||||
| 
 | ||||
|         cc_host_rgf_s as cc_host_rgf, | ||||
| @ -20,29 +22,29 @@ pub mod pac { | ||||
|         cryptocell_s as cryptocell, | ||||
|         ctrl_ap_peri_s as ctrl_ap_peri, | ||||
|         dppic_ns as dppic, | ||||
|         egu0_ns as egu0, | ||||
|         egu_ns as egu, | ||||
|         ficr_s as ficr, | ||||
|         fpu_ns as fpu, | ||||
|         gpiote0_s as gpiote, | ||||
|         gpiote_s as gpiote, | ||||
|         i2s_ns as i2s, | ||||
|         ipc_ns as ipc, | ||||
|         kmu_ns as kmu, | ||||
|         nvmc_ns as nvmc, | ||||
|         p0_ns as p0, | ||||
|         gpio_ns as gpio, | ||||
|         pdm_ns as pdm, | ||||
|         power_ns as power, | ||||
|         pwm0_ns as pwm0, | ||||
|         pwm_ns as pwm, | ||||
|         regulators_ns as regulators, | ||||
|         rtc0_ns as rtc0, | ||||
|         rtc_ns as rtc, | ||||
|         saadc_ns as saadc, | ||||
|         spim0_ns as spim0, | ||||
|         spis0_ns as spis0, | ||||
|         spim_ns as spim, | ||||
|         spis_ns as spis, | ||||
|         spu_s as spu, | ||||
|         tad_s as tad, | ||||
|         timer0_ns as timer0, | ||||
|         twim0_ns as twim0, | ||||
|         twis0_ns as twis0, | ||||
|         uarte0_ns as uarte0, | ||||
|         timer_ns as timer, | ||||
|         twim_ns as twim, | ||||
|         twis_ns as twis, | ||||
|         uarte_ns as uarte, | ||||
|         uicr_s as uicr, | ||||
|         vmc_ns as vmc, | ||||
|         wdt_ns as wdt, | ||||
| @ -51,7 +53,7 @@ pub mod pac { | ||||
|     /// Non-Secure mode (NS) peripherals
 | ||||
|     pub mod ns { | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf9120_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CLOCK_NS as CLOCK, | ||||
|             DPPIC_NS as DPPIC, | ||||
|             EGU0_NS as EGU0, | ||||
| @ -108,7 +110,7 @@ pub mod pac { | ||||
|     /// Secure mode (S) peripherals
 | ||||
|     pub mod s { | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf9120_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CC_HOST_RGF_S as CC_HOST_RGF, | ||||
|             CLOCK_S as CLOCK, | ||||
|             CRYPTOCELL_S as CRYPTOCELL, | ||||
| @ -121,7 +123,7 @@ pub mod pac { | ||||
|             EGU4_S as EGU4, | ||||
|             EGU5_S as EGU5, | ||||
|             FICR_S as FICR, | ||||
|             FPU as FPU, | ||||
|             FPU_NS as FPU, | ||||
|             GPIOTE0_S as GPIOTE0, | ||||
|             I2S_S as I2S, | ||||
|             IPC_S as IPC, | ||||
|  | ||||
| @ -5,14 +5,16 @@ pub mod pac { | ||||
|     // The nRF9160 has a secure and non-secure (NS) mode.
 | ||||
|     // To avoid cfg spam, we remove _ns or _s suffixes here.
 | ||||
| 
 | ||||
|     pub use nrf9160_pac::NVIC_PRIO_BITS; | ||||
|     #[cfg(feature="rt")] | ||||
|     pub use nrf_pac::NVIC_PRIO_BITS; | ||||
|     pub use nrf_pac::{common, shared}; | ||||
| 
 | ||||
|     #[cfg(feature="rt")] | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf9160_pac::interrupt; | ||||
|     pub use nrf_pac::interrupt; | ||||
| 
 | ||||
|     #[doc(no_inline)] | ||||
|     pub use nrf9160_pac::{ | ||||
|     pub use nrf_pac::{ | ||||
|         Interrupt, | ||||
| 
 | ||||
|         cc_host_rgf_s as cc_host_rgf, | ||||
| @ -20,29 +22,29 @@ pub mod pac { | ||||
|         cryptocell_s as cryptocell, | ||||
|         ctrl_ap_peri_s as ctrl_ap_peri, | ||||
|         dppic_ns as dppic, | ||||
|         egu0_ns as egu0, | ||||
|         egu_ns as egu, | ||||
|         ficr_s as ficr, | ||||
|         fpu_ns as fpu, | ||||
|         gpiote0_s as gpiote, | ||||
|         gpiote_s as gpiote, | ||||
|         i2s_ns as i2s, | ||||
|         ipc_ns as ipc, | ||||
|         kmu_ns as kmu, | ||||
|         nvmc_ns as nvmc, | ||||
|         p0_ns as p0, | ||||
|         gpio_ns as gpio, | ||||
|         pdm_ns as pdm, | ||||
|         power_ns as power, | ||||
|         pwm0_ns as pwm0, | ||||
|         pwm_ns as pwm, | ||||
|         regulators_ns as regulators, | ||||
|         rtc0_ns as rtc0, | ||||
|         rtc_ns as rtc, | ||||
|         saadc_ns as saadc, | ||||
|         spim0_ns as spim0, | ||||
|         spis0_ns as spis0, | ||||
|         spim_ns as spim, | ||||
|         spis_ns as spis, | ||||
|         spu_s as spu, | ||||
|         tad_s as tad, | ||||
|         timer0_ns as timer0, | ||||
|         twim0_ns as twim0, | ||||
|         twis0_ns as twis0, | ||||
|         uarte0_ns as uarte0, | ||||
|         timer_ns as timer, | ||||
|         twim_ns as twim, | ||||
|         twis_ns as twis, | ||||
|         uarte_ns as uarte, | ||||
|         uicr_s as uicr, | ||||
|         vmc_ns as vmc, | ||||
|         wdt_ns as wdt, | ||||
| @ -51,7 +53,7 @@ pub mod pac { | ||||
|     /// Non-Secure mode (NS) peripherals
 | ||||
|     pub mod ns { | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf9160_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CLOCK_NS as CLOCK, | ||||
|             DPPIC_NS as DPPIC, | ||||
|             EGU0_NS as EGU0, | ||||
| @ -108,7 +110,7 @@ pub mod pac { | ||||
|     /// Secure mode (S) peripherals
 | ||||
|     pub mod s { | ||||
|         #[doc(no_inline)] | ||||
|         pub use nrf9160_pac::{ | ||||
|         pub use nrf_pac::{ | ||||
|             CC_HOST_RGF_S as CC_HOST_RGF, | ||||
|             CLOCK_S as CLOCK, | ||||
|             CRYPTOCELL_S as CRYPTOCELL, | ||||
|  | ||||
| @ -34,7 +34,7 @@ impl<'d, T: Instance> Egu<'d, T> { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::egu0::RegisterBlock; | ||||
|     fn regs() -> pac::egu::Egu; | ||||
| } | ||||
| 
 | ||||
| /// Basic Egu instance.
 | ||||
| @ -47,8 +47,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_egu { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::egu::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::egu0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::egu::Egu { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|         } | ||||
|         impl crate::egu::Instance for peripherals::$type { | ||||
| @ -68,32 +68,26 @@ impl<'d, T: Instance> Trigger<'d, T> { | ||||
|     pub fn task(&self) -> Task<'d> { | ||||
|         let nr = self.number as usize; | ||||
|         let regs = T::regs(); | ||||
|         Task::from_reg(®s.tasks_trigger[nr]) | ||||
|         Task::from_reg(regs.tasks_trigger(nr)) | ||||
|     } | ||||
| 
 | ||||
|     /// Get event for this trigger to use with PPI.
 | ||||
|     pub fn event(&self) -> Event<'d> { | ||||
|         let nr = self.number as usize; | ||||
|         let regs = T::regs(); | ||||
|         Event::from_reg(®s.events_triggered[nr]) | ||||
|         Event::from_reg(regs.events_triggered(nr)) | ||||
|     } | ||||
| 
 | ||||
|     /// Enable interrupts for this trigger
 | ||||
|     pub fn enable_interrupt(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.intenset | ||||
|                 .modify(|r, w| w.bits(r.bits() | (1 << self.number as usize))) | ||||
|         }; | ||||
|         regs.intenset().modify(|w| w.set_triggered(self.number as usize, true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Enable interrupts for this trigger
 | ||||
|     pub fn disable_interrupt(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.intenclr | ||||
|                 .modify(|r, w| w.bits(r.bits() | (1 << self.number as usize))) | ||||
|         }; | ||||
|         regs.intenset().modify(|w| w.set_triggered(self.number as usize, false)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -7,14 +7,11 @@ use core::hint::unreachable_unchecked; | ||||
| use cfg_if::cfg_if; | ||||
| use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | ||||
| 
 | ||||
| #[cfg(feature = "nrf51")] | ||||
| use crate::pac::common::{Reg, RW}; | ||||
| use crate::pac::gpio; | ||||
| #[cfg(feature = "nrf51")] | ||||
| use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A}; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| use crate::pac::p0 as gpio; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; | ||||
| use crate::pac::gpio::vals; | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| use crate::pac::shared::{regs::Psel, vals::Connect}; | ||||
| use crate::{pac, Peripheral}; | ||||
| 
 | ||||
| /// A GPIO port with up to 32 pins.
 | ||||
| @ -103,7 +100,7 @@ impl From<Level> for bool { | ||||
| } | ||||
| 
 | ||||
| /// Drive strength settings for an output pin.
 | ||||
| // These numbers match DRIVE_A exactly so hopefully the compiler will unify them.
 | ||||
| // These numbers match vals::Drive exactly so hopefully the compiler will unify them.
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq)] | ||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||
| #[repr(u8)] | ||||
| @ -188,24 +185,24 @@ impl<'d> Output<'d> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn convert_drive(drive: OutputDrive) -> DRIVE_A { | ||||
| pub(crate) fn convert_drive(drive: OutputDrive) -> vals::Drive { | ||||
|     match drive { | ||||
|         OutputDrive::Standard => DRIVE_A::S0S1, | ||||
|         OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, | ||||
|         OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, | ||||
|         OutputDrive::HighDrive => DRIVE_A::H0H1, | ||||
|         OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, | ||||
|         OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, | ||||
|         OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, | ||||
|         OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, | ||||
|         OutputDrive::Standard => vals::Drive::S0S1, | ||||
|         OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1, | ||||
|         OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1, | ||||
|         OutputDrive::HighDrive => vals::Drive::H0H1, | ||||
|         OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1, | ||||
|         OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1, | ||||
|         OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1, | ||||
|         OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn convert_pull(pull: Pull) -> PULL_A { | ||||
| fn convert_pull(pull: Pull) -> vals::Pull { | ||||
|     match pull { | ||||
|         Pull::None => PULL_A::DISABLED, | ||||
|         Pull::Up => PULL_A::PULLUP, | ||||
|         Pull::Down => PULL_A::PULLDOWN, | ||||
|         Pull::None => vals::Pull::DISABLED, | ||||
|         Pull::Up => vals::Pull::PULLUP, | ||||
|         Pull::Down => vals::Pull::PULLDOWN, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -234,12 +231,11 @@ impl<'d> Flex<'d> { | ||||
|     #[inline] | ||||
|     pub fn set_as_input(&mut self, pull: Pull) { | ||||
|         self.pin.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             w.pull().variant(convert_pull(pull)); | ||||
|             w.drive().s0s1(); | ||||
|             w.sense().disabled(); | ||||
|             w | ||||
|             w.set_dir(vals::Dir::INPUT); | ||||
|             w.set_input(vals::Input::CONNECT); | ||||
|             w.set_pull(convert_pull(pull)); | ||||
|             w.set_drive(vals::Drive::S0S1); | ||||
|             w.set_sense(vals::Sense::DISABLED); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -250,12 +246,11 @@ impl<'d> Flex<'d> { | ||||
|     #[inline] | ||||
|     pub fn set_as_output(&mut self, drive: OutputDrive) { | ||||
|         self.pin.conf().write(|w| { | ||||
|             w.dir().output(); | ||||
|             w.input().disconnect(); | ||||
|             w.pull().disabled(); | ||||
|             w.drive().variant(convert_drive(drive)); | ||||
|             w.sense().disabled(); | ||||
|             w | ||||
|             w.set_dir(vals::Dir::OUTPUT); | ||||
|             w.set_input(vals::Input::DISCONNECT); | ||||
|             w.set_pull(vals::Pull::DISABLED); | ||||
|             w.set_drive(convert_drive(drive)); | ||||
|             w.set_sense(vals::Sense::DISABLED); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -271,31 +266,30 @@ impl<'d> Flex<'d> { | ||||
|     #[inline] | ||||
|     pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) { | ||||
|         self.pin.conf().write(|w| { | ||||
|             w.dir().output(); | ||||
|             w.input().connect(); | ||||
|             w.pull().variant(convert_pull(pull)); | ||||
|             w.drive().variant(convert_drive(drive)); | ||||
|             w.sense().disabled(); | ||||
|             w | ||||
|             w.set_dir(vals::Dir::OUTPUT); | ||||
|             w.set_input(vals::Input::CONNECT); | ||||
|             w.set_pull(convert_pull(pull)); | ||||
|             w.set_drive(convert_drive(drive)); | ||||
|             w.set_sense(vals::Sense::DISABLED); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /// Put the pin into disconnected mode.
 | ||||
|     #[inline] | ||||
|     pub fn set_as_disconnected(&mut self) { | ||||
|         self.pin.conf().reset(); | ||||
|         self.pin.conf().write(|_| ()); | ||||
|     } | ||||
| 
 | ||||
|     /// Get whether the pin input level is high.
 | ||||
|     #[inline] | ||||
|     pub fn is_high(&self) -> bool { | ||||
|         !self.is_low() | ||||
|         self.pin.block().in_().read().pin(self.pin.pin() as _) | ||||
|     } | ||||
| 
 | ||||
|     /// Get whether the pin input level is low.
 | ||||
|     #[inline] | ||||
|     pub fn is_low(&self) -> bool { | ||||
|         self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 | ||||
|         !self.is_high() | ||||
|     } | ||||
| 
 | ||||
|     /// Get the pin input level.
 | ||||
| @ -338,13 +332,13 @@ impl<'d> Flex<'d> { | ||||
|     /// Get whether the output level is set to high.
 | ||||
|     #[inline] | ||||
|     pub fn is_set_high(&self) -> bool { | ||||
|         !self.is_set_low() | ||||
|         self.pin.block().out().read().pin(self.pin.pin() as _) | ||||
|     } | ||||
| 
 | ||||
|     /// Get whether the output level is set to low.
 | ||||
|     #[inline] | ||||
|     pub fn is_set_low(&self) -> bool { | ||||
|         self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 | ||||
|         !self.is_set_high() | ||||
|     } | ||||
| 
 | ||||
|     /// Get the current output level.
 | ||||
| @ -356,7 +350,7 @@ impl<'d> Flex<'d> { | ||||
| 
 | ||||
| impl<'d> Drop for Flex<'d> { | ||||
|     fn drop(&mut self) { | ||||
|         self.pin.conf().reset(); | ||||
|         self.pin.conf().write(|_| ()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -375,35 +369,33 @@ pub(crate) trait SealedPin { | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn block(&self) -> &gpio::RegisterBlock { | ||||
|         unsafe { | ||||
|             match self.pin_port() / 32 { | ||||
|                 #[cfg(feature = "nrf51")] | ||||
|                 0 => &*pac::GPIO::ptr(), | ||||
|                 #[cfg(not(feature = "nrf51"))] | ||||
|                 0 => &*pac::P0::ptr(), | ||||
|                 #[cfg(feature = "_gpio-p1")] | ||||
|                 1 => &*pac::P1::ptr(), | ||||
|                 _ => unreachable_unchecked(), | ||||
|             } | ||||
|     fn block(&self) -> gpio::Gpio { | ||||
|         match self.pin_port() / 32 { | ||||
|             #[cfg(feature = "_nrf51")] | ||||
|             0 => pac::GPIO, | ||||
|             #[cfg(not(feature = "_nrf51"))] | ||||
|             0 => pac::P0, | ||||
|             #[cfg(feature = "_gpio-p1")] | ||||
|             1 => pac::P1, | ||||
|             _ => unsafe { unreachable_unchecked() }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn conf(&self) -> &gpio::PIN_CNF { | ||||
|         &self.block().pin_cnf[self._pin() as usize] | ||||
|     fn conf(&self) -> Reg<gpio::regs::PinCnf, RW> { | ||||
|         self.block().pin_cnf(self._pin() as usize) | ||||
|     } | ||||
| 
 | ||||
|     /// Set the output as high.
 | ||||
|     #[inline] | ||||
|     fn set_high(&self) { | ||||
|         unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) } | ||||
|         self.block().outset().write(|w| w.set_pin(self._pin() as _, true)) | ||||
|     } | ||||
| 
 | ||||
|     /// Set the output as low.
 | ||||
|     #[inline] | ||||
|     fn set_low(&self) { | ||||
|         unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) } | ||||
|         self.block().outclr().write(|w| w.set_pin(self._pin() as _, true)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -429,8 +421,9 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static | ||||
| 
 | ||||
|     /// Peripheral port register value
 | ||||
|     #[inline] | ||||
|     fn psel_bits(&self) -> u32 { | ||||
|         self.pin_port() as u32 | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     fn psel_bits(&self) -> pac::shared::regs::Psel { | ||||
|         pac::shared::regs::Psel(self.pin_port() as u32) | ||||
|     } | ||||
| 
 | ||||
|     /// Convert from concrete pin type PX_XX to type erased `AnyPin`.
 | ||||
| @ -471,26 +464,30 @@ impl SealedPin for AnyPin { | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub(crate) trait PselBits { | ||||
|     fn psel_bits(&self) -> u32; | ||||
|     fn psel_bits(&self) -> pac::shared::regs::Psel; | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> { | ||||
|     #[inline] | ||||
|     fn psel_bits(&self) -> u32 { | ||||
|     fn psel_bits(&self) -> pac::shared::regs::Psel { | ||||
|         match self { | ||||
|             Some(pin) => pin.psel_bits(), | ||||
|             None => 1u32 << 31, | ||||
|             None => DISCONNECTED, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub(crate) const DISCONNECTED: Psel = Psel(1 << 31); | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| #[allow(dead_code)] | ||||
| pub(crate) fn deconfigure_pin(psel_bits: u32) { | ||||
|     if psel_bits & 0x8000_0000 != 0 { | ||||
| pub(crate) fn deconfigure_pin(psel: Psel) { | ||||
|     if psel.connect() == Connect::DISCONNECTED { | ||||
|         return; | ||||
|     } | ||||
|     unsafe { AnyPin::steal(psel_bits as _).conf().reset() } | ||||
|     unsafe { AnyPin::steal(psel.0 as _).conf().write(|_| ()) } | ||||
| } | ||||
| 
 | ||||
| // ====================
 | ||||
|  | ||||
| @ -9,10 +9,14 @@ use embassy_sync::waitqueue::AtomicWaker; | ||||
| 
 | ||||
| use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; | ||||
| use crate::interrupt::InterruptExt; | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| use crate::pac::gpio::vals::Detectmode; | ||||
| use crate::pac::gpio::vals::Sense; | ||||
| use crate::pac::gpiote::vals::{Mode, Outinit, Polarity}; | ||||
| use crate::ppi::{Event, Task}; | ||||
| use crate::{interrupt, pac, peripherals}; | ||||
| 
 | ||||
| #[cfg(feature = "nrf51")] | ||||
| #[cfg(feature = "_nrf51")] | ||||
| /// Amount of GPIOTE channels in the chip.
 | ||||
| const CHANNEL_COUNT: usize = 4; | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| @ -51,14 +55,14 @@ pub enum OutputChannelPolarity { | ||||
|     Toggle, | ||||
| } | ||||
| 
 | ||||
| fn regs() -> &'static pac::gpiote::RegisterBlock { | ||||
| fn regs() -> pac::gpiote::Gpiote { | ||||
|     cfg_if::cfg_if! { | ||||
|         if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] { | ||||
|             unsafe { &*pac::GPIOTE0::ptr() } | ||||
|             pac::GPIOTE0 | ||||
|         } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] { | ||||
|             unsafe { &*pac::GPIOTE1::ptr() } | ||||
|             pac::GPIOTE1 | ||||
|         } else { | ||||
|             unsafe { &*pac::GPIOTE::ptr() } | ||||
|             pac::GPIOTE | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -68,15 +72,15 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     { | ||||
|         #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | ||||
|         let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; | ||||
|         let ports = &[pac::P0, pac::P1]; | ||||
|         #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] | ||||
|         let ports = unsafe { &[&*pac::P0::ptr()] }; | ||||
|         let ports = &[pac::P0]; | ||||
| 
 | ||||
|         for &p in ports { | ||||
|             // Enable latched detection
 | ||||
|             p.detectmode.write(|w| w.detectmode().ldetect()); | ||||
|             p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); | ||||
|             // Clear latch
 | ||||
|             p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) | ||||
|             p.latch().write(|w| w.0 = 0xFFFFFFFF) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -93,7 +97,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | ||||
|     unsafe { irq.enable() }; | ||||
| 
 | ||||
|     let g = regs(); | ||||
|     g.intenset.write(|w| w.port().set()); | ||||
|     g.intenset().write(|w| w.set_port(true)); | ||||
| } | ||||
| 
 | ||||
| #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] | ||||
| @ -121,47 +125,47 @@ unsafe fn handle_gpiote_interrupt() { | ||||
|     let g = regs(); | ||||
| 
 | ||||
|     for i in 0..CHANNEL_COUNT { | ||||
|         if g.events_in[i].read().bits() != 0 { | ||||
|             g.intenclr.write(|w| w.bits(1 << i)); | ||||
|         if g.events_in(i).read() != 0 { | ||||
|             g.intenclr().write(|w| w.0 = 1 << i); | ||||
|             CHANNEL_WAKERS[i].wake(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if g.events_port.read().bits() != 0 { | ||||
|         g.events_port.write(|w| w); | ||||
|     if g.events_port().read() != 0 { | ||||
|         g.events_port().write_value(0); | ||||
| 
 | ||||
|         #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | ||||
|         let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; | ||||
|         let ports = &[pac::P0, pac::P1]; | ||||
|         #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] | ||||
|         let ports = &[&*pac::P0::ptr()]; | ||||
|         let ports = &[pac::P0]; | ||||
|         #[cfg(feature = "_nrf51")] | ||||
|         let ports = unsafe { &[&*pac::GPIO::ptr()] }; | ||||
|         let ports = &[pac::GPIO]; | ||||
| 
 | ||||
|         #[cfg(feature = "_nrf51")] | ||||
|         for (port, &p) in ports.iter().enumerate() { | ||||
|             let inp = p.in_.read().bits(); | ||||
|             let inp = p.in_().read(); | ||||
|             for pin in 0..32 { | ||||
|                 let fired = match p.pin_cnf[pin as usize].read().sense().variant() { | ||||
|                     Some(pac::gpio::pin_cnf::SENSE_A::HIGH) => inp & (1 << pin) != 0, | ||||
|                     Some(pac::gpio::pin_cnf::SENSE_A::LOW) => inp & (1 << pin) == 0, | ||||
|                 let fired = match p.pin_cnf(pin as usize).read().sense() { | ||||
|                     Sense::HIGH => inp.pin(pin), | ||||
|                     Sense::LOW => !inp.pin(pin), | ||||
|                     _ => false, | ||||
|                 }; | ||||
| 
 | ||||
|                 if fired { | ||||
|                     PORT_WAKERS[port * 32 + pin as usize].wake(); | ||||
|                     p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); | ||||
|                     p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[cfg(not(feature = "_nrf51"))] | ||||
|         for (port, &p) in ports.iter().enumerate() { | ||||
|             let bits = p.latch.read().bits(); | ||||
|             let bits = p.latch().read().0; | ||||
|             for pin in BitIter(bits) { | ||||
|                 p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); | ||||
|                 p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); | ||||
|                 PORT_WAKERS[port * 32 + pin as usize].wake(); | ||||
|             } | ||||
|             p.latch.write(|w| w.bits(bits)); | ||||
|             p.latch().write(|w| w.0 = bits); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -194,8 +198,8 @@ impl<'d> Drop for InputChannel<'d> { | ||||
|     fn drop(&mut self) { | ||||
|         let g = regs(); | ||||
|         let num = self.ch.number(); | ||||
|         g.config[num].write(|w| w.mode().disabled()); | ||||
|         g.intenclr.write(|w| unsafe { w.bits(1 << num) }); | ||||
|         g.config(num).write(|w| w.set_mode(Mode::DISABLED)); | ||||
|         g.intenclr().write(|w| w.0 = 1 << num); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -207,22 +211,23 @@ impl<'d> InputChannel<'d> { | ||||
|         let g = regs(); | ||||
|         let num = ch.number(); | ||||
| 
 | ||||
|         g.config[num].write(|w| { | ||||
|         g.config(num).write(|w| { | ||||
|             w.set_mode(Mode::EVENT); | ||||
|             match polarity { | ||||
|                 InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), | ||||
|                 InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), | ||||
|                 InputChannelPolarity::None => w.mode().event().polarity().none(), | ||||
|                 InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), | ||||
|                 InputChannelPolarity::HiToLo => w.set_polarity(Polarity::HI_TO_LO), | ||||
|                 InputChannelPolarity::LoToHi => w.set_polarity(Polarity::LO_TO_HI), | ||||
|                 InputChannelPolarity::None => w.set_polarity(Polarity::NONE), | ||||
|                 InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), | ||||
|             }; | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | ||||
|             w.port().bit(match pin.pin.pin.port() { | ||||
|             w.set_port(match pin.pin.pin.port() { | ||||
|                 crate::gpio::Port::Port0 => false, | ||||
|                 crate::gpio::Port::Port1 => true, | ||||
|             }); | ||||
|             unsafe { w.psel().bits(pin.pin.pin.pin()) } | ||||
|             w.set_psel(pin.pin.pin.pin()); | ||||
|         }); | ||||
| 
 | ||||
|         g.events_in[num].reset(); | ||||
|         g.events_in(num).write_value(0); | ||||
| 
 | ||||
|         InputChannel { ch: ch.map_into(), pin } | ||||
|     } | ||||
| @ -233,13 +238,13 @@ impl<'d> InputChannel<'d> { | ||||
|         let num = self.ch.number(); | ||||
| 
 | ||||
|         // Enable interrupt
 | ||||
|         g.events_in[num].reset(); | ||||
|         g.intenset.write(|w| unsafe { w.bits(1 << num) }); | ||||
|         g.events_in(num).write_value(0); | ||||
|         g.intenset().write(|w| w.0 = 1 << num); | ||||
| 
 | ||||
|         poll_fn(|cx| { | ||||
|             CHANNEL_WAKERS[num].register(cx.waker()); | ||||
| 
 | ||||
|             if g.events_in[num].read().bits() != 0 { | ||||
|             if g.events_in(num).read() != 0 { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @ -251,7 +256,7 @@ impl<'d> InputChannel<'d> { | ||||
|     /// Returns the IN event, for use with PPI.
 | ||||
|     pub fn event_in(&self) -> Event<'d> { | ||||
|         let g = regs(); | ||||
|         Event::from_reg(&g.events_in[self.ch.number()]) | ||||
|         Event::from_reg(g.events_in(self.ch.number())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -265,8 +270,8 @@ impl<'d> Drop for OutputChannel<'d> { | ||||
|     fn drop(&mut self) { | ||||
|         let g = regs(); | ||||
|         let num = self.ch.number(); | ||||
|         g.config[num].write(|w| w.mode().disabled()); | ||||
|         g.intenclr.write(|w| unsafe { w.bits(1 << num) }); | ||||
|         g.config(num).write(|w| w.set_mode(Mode::DISABLED)); | ||||
|         g.intenclr().write(|w| w.0 = 1 << num); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -277,23 +282,23 @@ impl<'d> OutputChannel<'d> { | ||||
|         let g = regs(); | ||||
|         let num = ch.number(); | ||||
| 
 | ||||
|         g.config[num].write(|w| { | ||||
|             w.mode().task(); | ||||
|         g.config(num).write(|w| { | ||||
|             w.set_mode(Mode::TASK); | ||||
|             match pin.is_set_high() { | ||||
|                 true => w.outinit().high(), | ||||
|                 false => w.outinit().low(), | ||||
|                 true => w.set_outinit(Outinit::HIGH), | ||||
|                 false => w.set_outinit(Outinit::LOW), | ||||
|             }; | ||||
|             match polarity { | ||||
|                 OutputChannelPolarity::Set => w.polarity().lo_to_hi(), | ||||
|                 OutputChannelPolarity::Clear => w.polarity().hi_to_lo(), | ||||
|                 OutputChannelPolarity::Toggle => w.polarity().toggle(), | ||||
|                 OutputChannelPolarity::Set => w.set_polarity(Polarity::HI_TO_LO), | ||||
|                 OutputChannelPolarity::Clear => w.set_polarity(Polarity::LO_TO_HI), | ||||
|                 OutputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), | ||||
|             }; | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | ||||
|             w.port().bit(match pin.pin.pin.port() { | ||||
|             w.set_port(match pin.pin.pin.port() { | ||||
|                 crate::gpio::Port::Port0 => false, | ||||
|                 crate::gpio::Port::Port1 => true, | ||||
|             }); | ||||
|             unsafe { w.psel().bits(pin.pin.pin.pin()) } | ||||
|             w.set_psel(pin.pin.pin.pin()); | ||||
|         }); | ||||
| 
 | ||||
|         OutputChannel { | ||||
| @ -305,41 +310,41 @@ impl<'d> OutputChannel<'d> { | ||||
|     /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle).
 | ||||
|     pub fn out(&self) { | ||||
|         let g = regs(); | ||||
|         g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); | ||||
|         g.tasks_out(self.ch.number()).write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Triggers the SET task (set associated pin high).
 | ||||
|     #[cfg(not(feature = "nrf51"))] | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     pub fn set(&self) { | ||||
|         let g = regs(); | ||||
|         g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); | ||||
|         g.tasks_set(self.ch.number()).write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Triggers the CLEAR task (set associated pin low).
 | ||||
|     #[cfg(not(feature = "nrf51"))] | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     pub fn clear(&self) { | ||||
|         let g = regs(); | ||||
|         g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) }); | ||||
|         g.tasks_clr(self.ch.number()).write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the OUT task, for use with PPI.
 | ||||
|     pub fn task_out(&self) -> Task<'d> { | ||||
|         let g = regs(); | ||||
|         Task::from_reg(&g.tasks_out[self.ch.number()]) | ||||
|         Task::from_reg(g.tasks_out(self.ch.number())) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the CLR task, for use with PPI.
 | ||||
|     #[cfg(not(feature = "nrf51"))] | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     pub fn task_clr(&self) -> Task<'d> { | ||||
|         let g = regs(); | ||||
|         Task::from_reg(&g.tasks_clr[self.ch.number()]) | ||||
|         Task::from_reg(g.tasks_clr(self.ch.number())) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the SET task, for use with PPI.
 | ||||
|     #[cfg(not(feature = "nrf51"))] | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     pub fn task_set(&self) -> Task<'d> { | ||||
|         let g = regs(); | ||||
|         Task::from_reg(&g.tasks_set[self.ch.number()]) | ||||
|         Task::from_reg(g.tasks_set(self.ch.number())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -362,7 +367,7 @@ impl<'a> Unpin for PortInputFuture<'a> {} | ||||
| 
 | ||||
| impl<'a> Drop for PortInputFuture<'a> { | ||||
|     fn drop(&mut self) { | ||||
|         self.pin.conf().modify(|_, w| w.sense().disabled()); | ||||
|         self.pin.conf().modify(|w| w.set_sense(Sense::DISABLED)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -372,7 +377,7 @@ impl<'a> Future for PortInputFuture<'a> { | ||||
|     fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||||
|         PORT_WAKERS[self.pin.pin_port() as usize].register(cx.waker()); | ||||
| 
 | ||||
|         if self.pin.conf().read().sense().is_disabled() { | ||||
|         if self.pin.conf().read().sense() == Sense::DISABLED { | ||||
|             Poll::Ready(()) | ||||
|         } else { | ||||
|             Poll::Pending | ||||
| @ -410,13 +415,13 @@ impl<'d> Input<'d> { | ||||
| impl<'d> Flex<'d> { | ||||
|     /// Wait until the pin is high. If it is already high, return immediately.
 | ||||
|     pub async fn wait_for_high(&mut self) { | ||||
|         self.pin.conf().modify(|_, w| w.sense().high()); | ||||
|         self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); | ||||
|         PortInputFuture::new(&mut self.pin).await | ||||
|     } | ||||
| 
 | ||||
|     /// Wait until the pin is low. If it is already low, return immediately.
 | ||||
|     pub async fn wait_for_low(&mut self) { | ||||
|         self.pin.conf().modify(|_, w| w.sense().low()); | ||||
|         self.pin.conf().modify(|w| w.set_sense(Sense::LOW)); | ||||
|         PortInputFuture::new(&mut self.pin).await | ||||
|     } | ||||
| 
 | ||||
| @ -435,9 +440,9 @@ impl<'d> Flex<'d> { | ||||
|     /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
 | ||||
|     pub async fn wait_for_any_edge(&mut self) { | ||||
|         if self.is_high() { | ||||
|             self.pin.conf().modify(|_, w| w.sense().low()); | ||||
|             self.pin.conf().modify(|w| w.set_sense(Sense::LOW)); | ||||
|         } else { | ||||
|             self.pin.conf().modify(|_, w| w.sense().high()); | ||||
|             self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); | ||||
|         } | ||||
|         PortInputFuture::new(&mut self.pin).await | ||||
|     } | ||||
| @ -504,13 +509,13 @@ impl_channel!(GPIOTE_CH0, 0); | ||||
| impl_channel!(GPIOTE_CH1, 1); | ||||
| impl_channel!(GPIOTE_CH2, 2); | ||||
| impl_channel!(GPIOTE_CH3, 3); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_channel!(GPIOTE_CH4, 4); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_channel!(GPIOTE_CH5, 5); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_channel!(GPIOTE_CH6, 6); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_channel!(GPIOTE_CH7, 7); | ||||
| 
 | ||||
| // ====================
 | ||||
|  | ||||
| @ -13,11 +13,11 @@ use embassy_hal_internal::drop::OnDrop; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| 
 | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::i2s::RegisterBlock; | ||||
| use crate::pac::i2s::vals; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{interrupt, Peripheral, EASY_DMA_SIZE}; | ||||
| use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; | ||||
| 
 | ||||
| /// Type alias for `MultiBuffering` with 2 buffers.
 | ||||
| pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; | ||||
| @ -117,9 +117,20 @@ pub enum MckFreq { | ||||
| } | ||||
| 
 | ||||
| impl MckFreq { | ||||
|     const REGISTER_VALUES: &'static [u32] = &[ | ||||
|         0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000, | ||||
|         0x08000000, 0x06000000, 0x04100000, 0x020C0000, | ||||
|     const REGISTER_VALUES: &'static [vals::Mckfreq] = &[ | ||||
|         vals::Mckfreq::_32MDIV8, | ||||
|         vals::Mckfreq::_32MDIV10, | ||||
|         vals::Mckfreq::_32MDIV11, | ||||
|         vals::Mckfreq::_32MDIV15, | ||||
|         vals::Mckfreq::_32MDIV16, | ||||
|         vals::Mckfreq::_32MDIV21, | ||||
|         vals::Mckfreq::_32MDIV23, | ||||
|         vals::Mckfreq::_32MDIV30, | ||||
|         vals::Mckfreq::_32MDIV31, | ||||
|         vals::Mckfreq::_32MDIV32, | ||||
|         vals::Mckfreq::_32MDIV42, | ||||
|         vals::Mckfreq::_32MDIV63, | ||||
|         vals::Mckfreq::_32MDIV125, | ||||
|     ]; | ||||
| 
 | ||||
|     const FREQUENCIES: &'static [u32] = &[ | ||||
| @ -128,7 +139,7 @@ impl MckFreq { | ||||
|     ]; | ||||
| 
 | ||||
|     /// Return the value that needs to be written to the register.
 | ||||
|     pub fn to_register_value(&self) -> u32 { | ||||
|     pub fn to_register_value(&self) -> vals::Mckfreq { | ||||
|         Self::REGISTER_VALUES[usize::from(*self)] | ||||
|     } | ||||
| 
 | ||||
| @ -174,8 +185,8 @@ impl Ratio { | ||||
|     const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512]; | ||||
| 
 | ||||
|     /// Return the value that needs to be written to the register.
 | ||||
|     pub fn to_register_value(&self) -> u8 { | ||||
|         usize::from(*self) as u8 | ||||
|     pub fn to_register_value(&self) -> vals::Ratio { | ||||
|         vals::Ratio::from_bits(*self as u8) | ||||
|     } | ||||
| 
 | ||||
|     /// Return the divisor for this ratio
 | ||||
| @ -304,9 +315,9 @@ pub enum SampleWidth { | ||||
|     _24bit, | ||||
| } | ||||
| 
 | ||||
| impl From<SampleWidth> for u8 { | ||||
| impl From<SampleWidth> for vals::Swidth { | ||||
|     fn from(variant: SampleWidth) -> Self { | ||||
|         variant as _ | ||||
|         vals::Swidth::from_bits(variant as u8) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -319,11 +330,11 @@ pub enum Align { | ||||
|     Right, | ||||
| } | ||||
| 
 | ||||
| impl From<Align> for bool { | ||||
| impl From<Align> for vals::Align { | ||||
|     fn from(variant: Align) -> Self { | ||||
|         match variant { | ||||
|             Align::Left => false, | ||||
|             Align::Right => true, | ||||
|             Align::Left => vals::Align::LEFT, | ||||
|             Align::Right => vals::Align::RIGHT, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -337,11 +348,11 @@ pub enum Format { | ||||
|     Aligned, | ||||
| } | ||||
| 
 | ||||
| impl From<Format> for bool { | ||||
| impl From<Format> for vals::Format { | ||||
|     fn from(variant: Format) -> Self { | ||||
|         match variant { | ||||
|             Format::I2S => false, | ||||
|             Format::Aligned => true, | ||||
|             Format::I2S => vals::Format::I2S, | ||||
|             Format::Aligned => vals::Format::ALIGNED, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -357,9 +368,9 @@ pub enum Channels { | ||||
|     MonoRight, | ||||
| } | ||||
| 
 | ||||
| impl From<Channels> for u8 { | ||||
| impl From<Channels> for vals::Channels { | ||||
|     fn from(variant: Channels) -> Self { | ||||
|         variant as _ | ||||
|         vals::Channels::from_bits(variant as u8) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -506,61 +517,32 @@ impl<'d, T: Instance> I2S<'d, T> { | ||||
|     } | ||||
| 
 | ||||
|     fn apply_config(&self) { | ||||
|         let c = &T::regs().config; | ||||
|         let c = T::regs().config(); | ||||
|         match &self.master_clock { | ||||
|             Some(MasterClock { freq, ratio }) => { | ||||
|                 c.mode.write(|w| w.mode().master()); | ||||
|                 c.mcken.write(|w| w.mcken().enabled()); | ||||
|                 c.mckfreq | ||||
|                     .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) }); | ||||
|                 c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) }); | ||||
|                 c.mode().write(|w| w.set_mode(vals::Mode::MASTER)); | ||||
|                 c.mcken().write(|w| w.set_mcken(true)); | ||||
|                 c.mckfreq().write(|w| w.set_mckfreq(freq.to_register_value())); | ||||
|                 c.ratio().write(|w| w.set_ratio(ratio.to_register_value())); | ||||
|             } | ||||
|             None => { | ||||
|                 c.mode.write(|w| w.mode().slave()); | ||||
|                 c.mode().write(|w| w.set_mode(vals::Mode::SLAVE)); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         c.swidth | ||||
|             .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) }); | ||||
|         c.align.write(|w| w.align().bit(self.config.align.into())); | ||||
|         c.format.write(|w| w.format().bit(self.config.format.into())); | ||||
|         c.channels | ||||
|             .write(|w| unsafe { w.channels().bits(self.config.channels.into()) }); | ||||
|         c.swidth().write(|w| w.set_swidth(self.config.sample_width.into())); | ||||
|         c.align().write(|w| w.set_align(self.config.align.into())); | ||||
|         c.format().write(|w| w.set_format(self.config.format.into())); | ||||
|         c.channels().write(|w| w.set_channels(self.config.channels.into())); | ||||
|     } | ||||
| 
 | ||||
|     fn select_pins(&self) { | ||||
|         let psel = &T::regs().psel; | ||||
| 
 | ||||
|         if let Some(mck) = &self.mck { | ||||
|             psel.mck.write(|w| { | ||||
|                 unsafe { w.bits(mck.psel_bits()) }; | ||||
|                 w.connect().connected() | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         psel.sck.write(|w| { | ||||
|             unsafe { w.bits(self.sck.psel_bits()) }; | ||||
|             w.connect().connected() | ||||
|         }); | ||||
| 
 | ||||
|         psel.lrck.write(|w| { | ||||
|             unsafe { w.bits(self.lrck.psel_bits()) }; | ||||
|             w.connect().connected() | ||||
|         }); | ||||
| 
 | ||||
|         if let Some(sdin) = &self.sdin { | ||||
|             psel.sdin.write(|w| { | ||||
|                 unsafe { w.bits(sdin.psel_bits()) }; | ||||
|                 w.connect().connected() | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         if let Some(sdout) = &self.sdout { | ||||
|             psel.sdout.write(|w| { | ||||
|                 unsafe { w.bits(sdout.psel_bits()) }; | ||||
|                 w.connect().connected() | ||||
|             }); | ||||
|         } | ||||
|         let psel = T::regs().psel(); | ||||
|         psel.mck().write_value(self.mck.psel_bits()); | ||||
|         psel.sck().write_value(self.sck.psel_bits()); | ||||
|         psel.lrck().write_value(self.lrck.psel_bits()); | ||||
|         psel.sdin().write_value(self.sdin.psel_bits()); | ||||
|         psel.sdout().write_value(self.sdout.psel_bits()); | ||||
|     } | ||||
| 
 | ||||
|     fn setup_interrupt(&self) { | ||||
| @ -888,7 +870,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr | ||||
| } | ||||
| 
 | ||||
| /// Helper encapsulating common I2S device operations.
 | ||||
| struct Device<T>(&'static RegisterBlock, PhantomData<T>); | ||||
| struct Device<T>(pac::i2s::I2s, PhantomData<T>); | ||||
| 
 | ||||
| impl<T: Instance> Device<T> { | ||||
|     fn new() -> Self { | ||||
| @ -898,132 +880,132 @@ impl<T: Instance> Device<T> { | ||||
|     #[inline(always)] | ||||
|     pub fn enable(&self) { | ||||
|         trace!("ENABLED"); | ||||
|         self.0.enable.write(|w| w.enable().enabled()); | ||||
|         self.0.enable().write(|w| w.set_enable(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     pub fn disable(&self) { | ||||
|         trace!("DISABLED"); | ||||
|         self.0.enable.write(|w| w.enable().disabled()); | ||||
|         self.0.enable().write(|w| w.set_enable(false)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn enable_tx(&self) { | ||||
|         trace!("TX ENABLED"); | ||||
|         self.0.config.txen.write(|w| w.txen().enabled()); | ||||
|         self.0.config().txen().write(|w| w.set_txen(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn disable_tx(&self) { | ||||
|         trace!("TX DISABLED"); | ||||
|         self.0.config.txen.write(|w| w.txen().disabled()); | ||||
|         self.0.config().txen().write(|w| w.set_txen(false)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn enable_rx(&self) { | ||||
|         trace!("RX ENABLED"); | ||||
|         self.0.config.rxen.write(|w| w.rxen().enabled()); | ||||
|         self.0.config().rxen().write(|w| w.set_rxen(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn disable_rx(&self) { | ||||
|         trace!("RX DISABLED"); | ||||
|         self.0.config.rxen.write(|w| w.rxen().disabled()); | ||||
|         self.0.config().rxen().write(|w| w.set_rxen(false)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn start(&self) { | ||||
|         trace!("START"); | ||||
|         self.0.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         self.0.tasks_start().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn stop(&self) { | ||||
|         self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|         self.0.tasks_stop().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn is_stopped(&self) -> bool { | ||||
|         self.0.events_stopped.read().bits() != 0 | ||||
|         self.0.events_stopped().read() != 0 | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn reset_stopped_event(&self) { | ||||
|         trace!("STOPPED EVENT: Reset"); | ||||
|         self.0.events_stopped.reset(); | ||||
|         self.0.events_stopped().write_value(0); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn disable_stopped_interrupt(&self) { | ||||
|         trace!("STOPPED INTERRUPT: Disabled"); | ||||
|         self.0.intenclr.write(|w| w.stopped().clear()); | ||||
|         self.0.intenclr().write(|w| w.set_stopped(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn enable_stopped_interrupt(&self) { | ||||
|         trace!("STOPPED INTERRUPT: Enabled"); | ||||
|         self.0.intenset.write(|w| w.stopped().set()); | ||||
|         self.0.intenset().write(|w| w.set_stopped(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn reset_tx_ptr_event(&self) { | ||||
|         trace!("TX PTR EVENT: Reset"); | ||||
|         self.0.events_txptrupd.reset(); | ||||
|         self.0.events_txptrupd().write_value(0); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn reset_rx_ptr_event(&self) { | ||||
|         trace!("RX PTR EVENT: Reset"); | ||||
|         self.0.events_rxptrupd.reset(); | ||||
|         self.0.events_rxptrupd().write_value(0); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn disable_tx_ptr_interrupt(&self) { | ||||
|         trace!("TX PTR INTERRUPT: Disabled"); | ||||
|         self.0.intenclr.write(|w| w.txptrupd().clear()); | ||||
|         self.0.intenclr().write(|w| w.set_txptrupd(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn disable_rx_ptr_interrupt(&self) { | ||||
|         trace!("RX PTR INTERRUPT: Disabled"); | ||||
|         self.0.intenclr.write(|w| w.rxptrupd().clear()); | ||||
|         self.0.intenclr().write(|w| w.set_rxptrupd(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn enable_tx_ptr_interrupt(&self) { | ||||
|         trace!("TX PTR INTERRUPT: Enabled"); | ||||
|         self.0.intenset.write(|w| w.txptrupd().set()); | ||||
|         self.0.intenset().write(|w| w.set_txptrupd(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn enable_rx_ptr_interrupt(&self) { | ||||
|         trace!("RX PTR INTERRUPT: Enabled"); | ||||
|         self.0.intenset.write(|w| w.rxptrupd().set()); | ||||
|         self.0.intenset().write(|w| w.set_rxptrupd(true)); | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn is_tx_ptr_updated(&self) -> bool { | ||||
|         self.0.events_txptrupd.read().bits() != 0 | ||||
|         self.0.events_txptrupd().read() != 0 | ||||
|     } | ||||
| 
 | ||||
|     #[inline(always)] | ||||
|     fn is_rx_ptr_updated(&self) -> bool { | ||||
|         self.0.events_rxptrupd.read().bits() != 0 | ||||
|         self.0.events_rxptrupd().read() != 0 | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { | ||||
|         let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; | ||||
|         self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||||
|         self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||||
|         self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt); | ||||
|         self.0.txd().ptr().write_value(ptr); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { | ||||
|         let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; | ||||
|         self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||||
|         self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||||
|         self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt); | ||||
|         self.0.rxd().ptr().write_value(ptr); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| @ -1160,7 +1142,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::i2s::RegisterBlock; | ||||
|     fn regs() -> pac::i2s::I2s; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -1174,8 +1156,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_i2s { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::i2s::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::i2s::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::i2s::I2s { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::i2s::State { | ||||
|                 static STATE: crate::i2s::State = crate::i2s::State::new(); | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | ||||
| 
 | ||||
| #[cfg(not(any(
 | ||||
|     feature = "nrf51", | ||||
|     feature = "_nrf51", | ||||
|     feature = "nrf52805", | ||||
|     feature = "nrf52810", | ||||
|     feature = "nrf52811", | ||||
| @ -68,7 +68,7 @@ pub(crate) mod util; | ||||
| #[cfg(feature = "_time-driver")] | ||||
| mod time_driver; | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod buffered_uarte; | ||||
| pub mod gpio; | ||||
| #[cfg(feature = "gpiote")] | ||||
| @ -78,7 +78,7 @@ pub mod gpiote; | ||||
| #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] | ||||
| pub mod radio; | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod egu; | ||||
| #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] | ||||
| pub mod i2s; | ||||
| @ -95,32 +95,32 @@ pub mod nvmc; | ||||
| pub mod pdm; | ||||
| pub mod ppi; | ||||
| #[cfg(not(any(
 | ||||
|     feature = "nrf51", | ||||
|     feature = "_nrf51", | ||||
|     feature = "nrf52805", | ||||
|     feature = "nrf52820", | ||||
|     feature = "_nrf5340-net" | ||||
| )))] | ||||
| pub mod pwm; | ||||
| #[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))] | ||||
| #[cfg(not(any(feature = "_nrf51", feature = "_nrf91", feature = "_nrf5340-net")))] | ||||
| pub mod qdec; | ||||
| #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] | ||||
| pub mod qspi; | ||||
| #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] | ||||
| pub mod rng; | ||||
| #[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] | ||||
| #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] | ||||
| pub mod saadc; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod spim; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod spis; | ||||
| #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] | ||||
| pub mod temp; | ||||
| pub mod timer; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod twim; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod twis; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| pub mod uarte; | ||||
| #[cfg(any(
 | ||||
|     feature = "_nrf5340-app", | ||||
| @ -133,7 +133,7 @@ pub mod usb; | ||||
| pub mod wdt; | ||||
| 
 | ||||
| // This mod MUST go last, so that it sees all the `impl_foo!` macros
 | ||||
| #[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")] | ||||
| #[cfg_attr(feature = "_nrf51", path = "chips/nrf51.rs")] | ||||
| #[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] | ||||
| #[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")] | ||||
| #[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")] | ||||
| @ -216,6 +216,7 @@ pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; | ||||
| pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||||
| 
 | ||||
| pub use crate::chip::interrupt; | ||||
| #[cfg(feature = "rt")] | ||||
| pub use crate::pac::NVIC_PRIO_BITS; | ||||
| 
 | ||||
| pub mod config { | ||||
| @ -405,7 +406,7 @@ mod consts { | ||||
|     pub const APPROTECT_DISABLED: u32 = 0x0000_005a; | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||
| enum WriteResult { | ||||
| @ -417,12 +418,12 @@ enum WriteResult { | ||||
|     Failed, | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { | ||||
|     uicr_write_masked(address, value, 0xFFFF_FFFF) | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { | ||||
|     let curr_val = address.read_volatile(); | ||||
|     if curr_val & mask == value & mask { | ||||
| @ -434,13 +435,13 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe | ||||
|         return WriteResult::Failed; | ||||
|     } | ||||
| 
 | ||||
|     let nvmc = &*pac::NVMC::ptr(); | ||||
|     nvmc.config.write(|w| w.wen().wen()); | ||||
|     while nvmc.ready.read().ready().is_busy() {} | ||||
|     let nvmc = pac::NVMC; | ||||
|     nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN)); | ||||
|     while !nvmc.ready().read().ready() {} | ||||
|     address.write_volatile(value | !mask); | ||||
|     while nvmc.ready.read().ready().is_busy() {} | ||||
|     nvmc.config.reset(); | ||||
|     while nvmc.ready.read().ready().is_busy() {} | ||||
|     while !nvmc.ready().read().ready() {} | ||||
|     nvmc.config().write(|_| {}); | ||||
|     while !nvmc.ready().read().ready() {} | ||||
| 
 | ||||
|     WriteResult::Written | ||||
| } | ||||
| @ -459,7 +460,7 @@ pub fn init(config: config::Config) -> Peripherals { | ||||
|     let mut needs_reset = false; | ||||
| 
 | ||||
|     // Setup debug protection.
 | ||||
|     #[cfg(not(feature = "nrf51"))] | ||||
|     #[cfg(not(feature = "_nrf51"))] | ||||
|     match config.debug { | ||||
|         config::Debug::Allowed => { | ||||
|             #[cfg(feature = "_nrf52")] | ||||
| @ -486,17 +487,17 @@ pub fn init(config: config::Config) -> Peripherals { | ||||
| 
 | ||||
|             #[cfg(feature = "_nrf5340")] | ||||
|             unsafe { | ||||
|                 let p = &*pac::CTRLAP::ptr(); | ||||
|                 let p = pac::CTRLAP; | ||||
| 
 | ||||
|                 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | ||||
|                 needs_reset |= res == WriteResult::Written; | ||||
|                 p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | ||||
|                 p.approtect().disable().write_value(consts::APPROTECT_DISABLED); | ||||
| 
 | ||||
|                 #[cfg(feature = "_nrf5340-app")] | ||||
|                 { | ||||
|                     let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); | ||||
|                     needs_reset |= res == WriteResult::Written; | ||||
|                     p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | ||||
|                     p.secureapprotect().disable().write_value(consts::APPROTECT_DISABLED); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| @ -576,85 +577,79 @@ pub fn init(config: config::Config) -> Peripherals { | ||||
|         cortex_m::peripheral::SCB::sys_reset(); | ||||
|     } | ||||
| 
 | ||||
|     let r = unsafe { &*pac::CLOCK::ptr() }; | ||||
|     let r = pac::CLOCK; | ||||
| 
 | ||||
|     // Start HFCLK.
 | ||||
|     match config.hfclk_source { | ||||
|         config::HfclkSource::Internal => {} | ||||
|         config::HfclkSource::ExternalXtal => { | ||||
|             // Datasheet says this is likely to take 0.36ms
 | ||||
|             r.events_hfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|             r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|             while r.events_hfclkstarted.read().bits() == 0 {} | ||||
|             r.events_hfclkstarted().write_value(0); | ||||
|             r.tasks_hfclkstart().write_value(1); | ||||
|             while r.events_hfclkstarted().read() == 0 {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Configure LFCLK.
 | ||||
|     #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))] | ||||
|     #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91")))] | ||||
|     match config.lfclk_source { | ||||
|         config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), | ||||
|         config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), | ||||
| 
 | ||||
|         config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().xtal()), | ||||
| 
 | ||||
|         config::LfclkSource::ExternalLowSwing => r.lfclksrc.write(|w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().disabled(); | ||||
|             w | ||||
|         config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::RC)), | ||||
|         config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::SYNTH)), | ||||
|         config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::XTAL)), | ||||
|         config::LfclkSource::ExternalLowSwing => r.lfclksrc().write(|w| { | ||||
|             w.set_src(pac::clock::vals::Lfclksrc::XTAL); | ||||
|             w.set_external(true); | ||||
|             w.set_bypass(false); | ||||
|         }), | ||||
|         config::LfclkSource::ExternalFullSwing => r.lfclksrc.write(|w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().enabled(); | ||||
|             w | ||||
|         config::LfclkSource::ExternalFullSwing => r.lfclksrc().write(|w| { | ||||
|             w.set_src(pac::clock::vals::Lfclksrc::XTAL); | ||||
|             w.set_external(true); | ||||
|             w.set_bypass(true); | ||||
|         }), | ||||
|     } | ||||
|     #[cfg(feature = "_nrf91")] | ||||
|     match config.lfclk_source { | ||||
|         config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()), | ||||
|         config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()), | ||||
|         config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), | ||||
|         config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)), | ||||
|     } | ||||
| 
 | ||||
|     // Start LFCLK.
 | ||||
|     // Datasheet says this could take 100us from synth source
 | ||||
|     // 600us from rc source, 0.25s from an external source.
 | ||||
|     r.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|     r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while r.events_lfclkstarted.read().bits() == 0 {} | ||||
|     r.events_lfclkstarted().write_value(0); | ||||
|     r.tasks_lfclkstart().write_value(1); | ||||
|     while r.events_lfclkstarted().read() == 0 {} | ||||
| 
 | ||||
|     #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] | ||||
|     { | ||||
|         // Setup DCDCs.
 | ||||
|         let pwr = unsafe { &*pac::POWER::ptr() }; | ||||
|         #[cfg(feature = "nrf52840")] | ||||
|         if config.dcdc.reg0 { | ||||
|             pwr.dcdcen0.write(|w| w.dcdcen().set_bit()); | ||||
|             pac::POWER.dcdcen0().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|         if config.dcdc.reg1 { | ||||
|             pwr.dcdcen.write(|w| w.dcdcen().set_bit()); | ||||
|             pac::POWER.dcdcen().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|     } | ||||
|     #[cfg(feature = "_nrf91")] | ||||
|     { | ||||
|         // Setup DCDC.
 | ||||
|         let reg = unsafe { &*pac::REGULATORS::ptr() }; | ||||
|         if config.dcdc.regmain { | ||||
|             reg.dcdcen.write(|w| w.dcdcen().set_bit()); | ||||
|             pac::REGULATORS.dcdcen().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|     } | ||||
|     #[cfg(feature = "_nrf5340-app")] | ||||
|     { | ||||
|         // Setup DCDC.
 | ||||
|         let reg = unsafe { &*pac::REGULATORS::ptr() }; | ||||
|         let reg = pac::REGULATORS; | ||||
|         if config.dcdc.regh { | ||||
|             reg.vregh.dcdcen.write(|w| w.dcdcen().set_bit()); | ||||
|             reg.vregh().dcdcen().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|         if config.dcdc.regmain { | ||||
|             reg.vregmain.dcdcen.write(|w| w.dcdcen().set_bit()); | ||||
|             reg.vregmain().dcdcen().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|         if config.dcdc.regradio { | ||||
|             reg.vregradio.dcdcen.write(|w| w.dcdcen().set_bit()); | ||||
|             reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -668,9 +663,10 @@ pub fn init(config: config::Config) -> Peripherals { | ||||
| 
 | ||||
|     // Disable UARTE (enabled by default for some reason)
 | ||||
|     #[cfg(feature = "_nrf91")] | ||||
|     unsafe { | ||||
|         (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); | ||||
|         (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); | ||||
|     { | ||||
|         use pac::uarte::vals::Enable; | ||||
|         pac::UARTE0.enable().write(|w| w.set_enable(Enable::DISABLED)); | ||||
|         pac::UARTE1.enable().write(|w| w.set_enable(Enable::DISABLED)); | ||||
|     } | ||||
| 
 | ||||
|     peripherals | ||||
|  | ||||
| @ -7,6 +7,7 @@ use embedded_storage::nor_flash::{ | ||||
|     ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, | ||||
| }; | ||||
| 
 | ||||
| use crate::pac::nvmc::vals; | ||||
| use crate::peripherals::NVMC; | ||||
| use crate::{pac, Peripheral}; | ||||
| 
 | ||||
| @ -51,13 +52,13 @@ impl<'d> Nvmc<'d> { | ||||
|         Self { _p } | ||||
|     } | ||||
| 
 | ||||
|     fn regs() -> &'static pac::nvmc::RegisterBlock { | ||||
|         unsafe { &*pac::NVMC::ptr() } | ||||
|     fn regs() -> pac::nvmc::Nvmc { | ||||
|         pac::NVMC | ||||
|     } | ||||
| 
 | ||||
|     fn wait_ready(&mut self) { | ||||
|         let p = Self::regs(); | ||||
|         while p.ready.read().ready().is_busy() {} | ||||
|         while !p.ready().read().ready() {} | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] | ||||
| @ -68,12 +69,12 @@ impl<'d> Nvmc<'d> { | ||||
|     #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] | ||||
|     fn wait_ready_write(&mut self) { | ||||
|         let p = Self::regs(); | ||||
|         while p.readynext.read().readynext().is_busy() {} | ||||
|         while !p.readynext().read().readynext() {} | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] | ||||
|     fn erase_page(&mut self, page_addr: u32) { | ||||
|         Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) }); | ||||
|         Self::regs().erasepage().write_value(page_addr); | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] | ||||
| @ -86,23 +87,23 @@ impl<'d> Nvmc<'d> { | ||||
| 
 | ||||
|     fn enable_erase(&self) { | ||||
|         #[cfg(not(feature = "_ns"))] | ||||
|         Self::regs().config.write(|w| w.wen().een()); | ||||
|         Self::regs().config().write(|w| w.set_wen(vals::Wen::EEN)); | ||||
|         #[cfg(feature = "_ns")] | ||||
|         Self::regs().configns.write(|w| w.wen().een()); | ||||
|         Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::EEN)); | ||||
|     } | ||||
| 
 | ||||
|     fn enable_read(&self) { | ||||
|         #[cfg(not(feature = "_ns"))] | ||||
|         Self::regs().config.write(|w| w.wen().ren()); | ||||
|         Self::regs().config().write(|w| w.set_wen(vals::Wen::REN)); | ||||
|         #[cfg(feature = "_ns")] | ||||
|         Self::regs().configns.write(|w| w.wen().ren()); | ||||
|         Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::REN)); | ||||
|     } | ||||
| 
 | ||||
|     fn enable_write(&self) { | ||||
|         #[cfg(not(feature = "_ns"))] | ||||
|         Self::regs().config.write(|w| w.wen().wen()); | ||||
|         Self::regs().config().write(|w| w.set_wen(vals::Wen::WEN)); | ||||
|         #[cfg(feature = "_ns")] | ||||
|         Self::regs().configns.write(|w| w.wen().wen()); | ||||
|         Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::WEN)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -13,18 +13,19 @@ use embassy_sync::waitqueue::AtomicWaker; | ||||
| use fixed::types::I7F1; | ||||
| 
 | ||||
| use crate::chip::EASY_DMA_SIZE; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin}; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; | ||||
| pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::pdm::vals; | ||||
| pub use crate::pac::pdm::vals::Freq as Frequency; | ||||
| #[cfg(any(
 | ||||
|     feature = "nrf52840", | ||||
|     feature = "nrf52833", | ||||
|     feature = "_nrf5340-app", | ||||
|     feature = "_nrf91", | ||||
| ))] | ||||
| pub use crate::pac::pdm::ratio::RATIO_A as Ratio; | ||||
| use crate::{interrupt, Peripheral}; | ||||
| pub use crate::pac::pdm::vals::Ratio; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| /// Interrupt handler
 | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
| @ -35,16 +36,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         if r.events_end().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.started().clear()); | ||||
|         if r.events_started().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_started(true)); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.stopped().clear()); | ||||
|         if r.events_stopped().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_stopped(true)); | ||||
|         } | ||||
| 
 | ||||
|         T::state().waker.wake(); | ||||
| @ -109,50 +110,47 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // setup gpio pins
 | ||||
|         din.conf().write(|w| w.input().set_bit()); | ||||
|         r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); | ||||
|         din.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); | ||||
|         r.psel().din().write_value(din.psel_bits()); | ||||
|         clk.set_low(); | ||||
|         clk.conf().write(|w| w.dir().output()); | ||||
|         r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); | ||||
|         clk.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); | ||||
|         r.psel().clk().write_value(clk.psel_bits()); | ||||
| 
 | ||||
|         // configure
 | ||||
|         r.pdmclkctrl.write(|w| w.freq().variant(config.frequency)); | ||||
|         r.pdmclkctrl().write(|w| w.set_freq(config.frequency)); | ||||
|         #[cfg(any(
 | ||||
|             feature = "nrf52840", | ||||
|             feature = "nrf52833", | ||||
|             feature = "_nrf5340-app", | ||||
|             feature = "_nrf91", | ||||
|         ))] | ||||
|         r.ratio.write(|w| w.ratio().variant(config.ratio)); | ||||
|         r.mode.write(|w| { | ||||
|             w.operation().variant(config.operation_mode.into()); | ||||
|             w.edge().variant(config.edge.into()); | ||||
|             w | ||||
|         r.ratio().write(|w| w.set_ratio(config.ratio)); | ||||
|         r.mode().write(|w| { | ||||
|             w.set_operation(config.operation_mode.into()); | ||||
|             w.set_edge(config.edge.into()); | ||||
|         }); | ||||
| 
 | ||||
|         Self::_set_gain(r, config.gain_left, config.gain_right); | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0x003F_FFFF); | ||||
| 
 | ||||
|         // IRQ
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| 
 | ||||
|         r.enable.write(|w| w.enable().set_bit()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         Self { _peri: pdm } | ||||
|     } | ||||
| 
 | ||||
|     fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { | ||||
|         let gain_to_bits = |gain: I7F1| -> u8 { | ||||
|             let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50); | ||||
|             unsafe { core::mem::transmute(gain) } | ||||
|     fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) { | ||||
|         let gain_to_bits = |gain: I7F1| -> vals::Gain { | ||||
|             let gain: i8 = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50); | ||||
|             vals::Gain::from_bits(gain as u8) | ||||
|         }; | ||||
|         let gain_left = gain_to_bits(gain_left); | ||||
|         let gain_right = gain_to_bits(gain_right); | ||||
|         r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) }); | ||||
|         r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); | ||||
|         r.gainl().write(|w| w.set_gainl(gain_to_bits(gain_left))); | ||||
|         r.gainr().write(|w| w.set_gainr(gain_to_bits(gain_right))); | ||||
|     } | ||||
| 
 | ||||
|     /// Adjust the gain of the PDM microphone on the fly
 | ||||
| @ -166,21 +164,17 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // start dummy sampling because microphone needs some setup time
 | ||||
|         r.sample | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | ||||
|         r.sample | ||||
|             .maxcnt | ||||
|             .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||||
|         r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); | ||||
|         r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); | ||||
| 
 | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Stop sampling microphone data inta a dummy buffer
 | ||||
|     pub async fn stop(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|         r.events_started.reset(); | ||||
|         r.tasks_stop().write_value(1); | ||||
|         r.events_started().write_value(0); | ||||
|     } | ||||
| 
 | ||||
|     /// Sample data into the given buffer
 | ||||
| @ -194,41 +188,33 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         if r.events_started.read().bits() == 0 { | ||||
|         if r.events_started().read() == 0 { | ||||
|             return Err(Error::NotRunning); | ||||
|         } | ||||
| 
 | ||||
|         let drop = OnDrop::new(move || { | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             r.events_stopped.reset(); | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
|             r.events_stopped().write_value(0); | ||||
| 
 | ||||
|             // reset to dummy buffer
 | ||||
|             r.sample | ||||
|                 .ptr | ||||
|                 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | ||||
|             r.sample | ||||
|                 .maxcnt | ||||
|                 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||||
|             r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); | ||||
|             r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); | ||||
| 
 | ||||
|             while r.events_stopped.read().bits() == 0 {} | ||||
|             while r.events_stopped().read() == 0 {} | ||||
|         }); | ||||
| 
 | ||||
|         // setup user buffer
 | ||||
|         let ptr = buffer.as_ptr(); | ||||
|         let len = buffer.len(); | ||||
|         r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); | ||||
|         r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); | ||||
|         r.sample().ptr().write_value(ptr as u32); | ||||
|         r.sample().maxcnt().write(|w| w.set_buffsize(len as _)); | ||||
| 
 | ||||
|         // wait till the current sample is finished and the user buffer sample is started
 | ||||
|         Self::wait_for_sample().await; | ||||
| 
 | ||||
|         // reset the buffer back to the dummy buffer
 | ||||
|         r.sample | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | ||||
|         r.sample | ||||
|             .maxcnt | ||||
|             .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||||
|         r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); | ||||
|         r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); | ||||
| 
 | ||||
|         // wait till the user buffer is sampled
 | ||||
|         Self::wait_for_sample().await; | ||||
| @ -241,14 +227,14 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
|     async fn wait_for_sample() { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.events_end.reset(); | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
|         r.events_end().write_value(0); | ||||
|         r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         poll_fn(|cx| { | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|             if r.events_end().read() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -279,40 +265,37 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
|     { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|         if r.events_started().read() != 0 { | ||||
|             return Err(Error::AlreadyRunning); | ||||
|         } | ||||
| 
 | ||||
|         r.sample | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) }); | ||||
|         r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) }); | ||||
|         r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32); | ||||
|         r.sample().maxcnt().write(|w| w.set_buffsize(N as _)); | ||||
| 
 | ||||
|         // Reset and enable the events
 | ||||
|         r.events_end.reset(); | ||||
|         r.events_started.reset(); | ||||
|         r.events_stopped.reset(); | ||||
|         r.intenset.write(|w| { | ||||
|             w.end().set(); | ||||
|             w.started().set(); | ||||
|             w.stopped().set(); | ||||
|             w | ||||
|         r.events_end().write_value(0); | ||||
|         r.events_started().write_value(0); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_end(true); | ||||
|             w.set_started(true); | ||||
|             w.set_stopped(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Don't reorder the start event before the previous writes. Hopefully self
 | ||||
|         // wouldn't happen anyway
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start().write_value(1); | ||||
| 
 | ||||
|         let mut current_buffer = 0; | ||||
| 
 | ||||
|         let mut done = false; | ||||
| 
 | ||||
|         let drop = OnDrop::new(|| { | ||||
|             r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_stop().write_value(1); | ||||
|             // N.B. It would be better if this were async, but Drop only support sync code
 | ||||
|             while r.events_stopped.read().bits() != 0 {} | ||||
|             while r.events_stopped().read() != 0 {} | ||||
|         }); | ||||
| 
 | ||||
|         // Wait for events and complete when the sampler indicates it has had enough
 | ||||
| @ -321,11 +304,11 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
| 
 | ||||
|             T::state().waker.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|             if r.events_end().read() != 0 { | ||||
|                 compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|                 r.events_end.reset(); | ||||
|                 r.intenset.write(|w| w.end().set()); | ||||
|                 r.events_end().write_value(0); | ||||
|                 r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|                 if !done { | ||||
|                     // Discard the last buffer after the user requested a stop
 | ||||
| @ -333,23 +316,21 @@ impl<'d, T: Instance> Pdm<'d, T> { | ||||
|                         let next_buffer = 1 - current_buffer; | ||||
|                         current_buffer = next_buffer; | ||||
|                     } else { | ||||
|                         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                         r.tasks_stop().write_value(1); | ||||
|                         done = true; | ||||
|                     }; | ||||
|                 }; | ||||
|             } | ||||
| 
 | ||||
|             if r.events_started.read().bits() != 0 { | ||||
|                 r.events_started.reset(); | ||||
|                 r.intenset.write(|w| w.started().set()); | ||||
|             if r.events_started().read() != 0 { | ||||
|                 r.events_started().write_value(0); | ||||
|                 r.intenset().write(|w| w.set_started(true)); | ||||
| 
 | ||||
|                 let next_buffer = 1 - current_buffer; | ||||
|                 r.sample | ||||
|                     .ptr | ||||
|                     .write(|w| unsafe { w.sampleptr().bits(bufs[next_buffer].as_mut_ptr() as u32) }); | ||||
|                 r.sample().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32); | ||||
|             } | ||||
| 
 | ||||
|             if r.events_stopped.read().bits() != 0 { | ||||
|             if r.events_stopped().read() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| 
 | ||||
| @ -411,11 +392,11 @@ pub enum OperationMode { | ||||
|     Stereo, | ||||
| } | ||||
| 
 | ||||
| impl From<OperationMode> for OPERATION_A { | ||||
| impl From<OperationMode> for vals::Operation { | ||||
|     fn from(mode: OperationMode) -> Self { | ||||
|         match mode { | ||||
|             OperationMode::Mono => OPERATION_A::MONO, | ||||
|             OperationMode::Stereo => OPERATION_A::STEREO, | ||||
|             OperationMode::Mono => vals::Operation::MONO, | ||||
|             OperationMode::Stereo => vals::Operation::STEREO, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -429,11 +410,11 @@ pub enum Edge { | ||||
|     LeftFalling, | ||||
| } | ||||
| 
 | ||||
| impl From<Edge> for EDGE_A { | ||||
| impl From<Edge> for vals::Edge { | ||||
|     fn from(edge: Edge) -> Self { | ||||
|         match edge { | ||||
|             Edge::LeftRising => EDGE_A::LEFT_RISING, | ||||
|             Edge::LeftFalling => EDGE_A::LEFT_FALLING, | ||||
|             Edge::LeftRising => vals::Edge::LEFT_RISING, | ||||
|             Edge::LeftFalling => vals::Edge::LEFT_FALLING, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -442,12 +423,12 @@ impl<'d, T: Instance> Drop for Pdm<'d, T> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_stop().write_value(1); | ||||
| 
 | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(false)); | ||||
| 
 | ||||
|         r.psel.din.reset(); | ||||
|         r.psel.clk.reset(); | ||||
|         r.psel().din().write_value(DISCONNECTED); | ||||
|         r.psel().clk().write_value(DISCONNECTED); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -465,7 +446,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::pdm::RegisterBlock; | ||||
|     fn regs() -> crate::pac::pdm::Pdm; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -479,8 +460,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_pdm { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::pdm::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::pdm::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> crate::pac::pdm::Pdm { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::pdm::State { | ||||
|                 static STATE: crate::pdm::State = crate::pdm::State::new(); | ||||
|  | ||||
| @ -6,8 +6,8 @@ use crate::{pac, Peripheral}; | ||||
| const DPPI_ENABLE_BIT: u32 = 0x8000_0000; | ||||
| const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; | ||||
| 
 | ||||
| pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock { | ||||
|     unsafe { &*pac::DPPIC::ptr() } | ||||
| pub(crate) fn regs() -> pac::dppic::Dppic { | ||||
|     pac::DPPIC | ||||
| } | ||||
| 
 | ||||
| impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { | ||||
| @ -57,13 +57,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, | ||||
|     /// Enables the channel.
 | ||||
|     pub fn enable(&mut self) { | ||||
|         let n = self.ch.number(); | ||||
|         regs().chenset.write(|w| unsafe { w.bits(1 << n) }); | ||||
|         regs().chenset().write(|w| w.0 = 1 << n); | ||||
|     } | ||||
| 
 | ||||
|     /// Disables the channel.
 | ||||
|     pub fn disable(&mut self) { | ||||
|         let n = self.ch.number(); | ||||
|         regs().chenclr.write(|w| unsafe { w.bits(1 << n) }); | ||||
|         regs().chenclr().write(|w| w.0 = 1 << n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -20,6 +20,7 @@ use core::ptr::NonNull; | ||||
| 
 | ||||
| use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | ||||
| 
 | ||||
| use crate::pac::common::{Reg, RW, W}; | ||||
| use crate::{peripherals, Peripheral}; | ||||
| 
 | ||||
| #[cfg_attr(feature = "_dppi", path = "dppi.rs")] | ||||
| @ -50,7 +51,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { | ||||
| 
 | ||||
|         let r = regs(); | ||||
|         let n = g.number(); | ||||
|         r.chg[n].write(|w| unsafe { w.bits(0) }); | ||||
|         r.chg(n).write(|_| ()); | ||||
| 
 | ||||
|         Self { g } | ||||
|     } | ||||
| @ -65,7 +66,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { | ||||
|         let r = regs(); | ||||
|         let ng = self.g.number(); | ||||
|         let nc = ch.ch.number(); | ||||
|         r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) }); | ||||
|         r.chg(ng).modify(|w| w.set_ch(nc, true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Remove a PPI channel from this group.
 | ||||
| @ -78,19 +79,19 @@ impl<'d, G: Group> PpiGroup<'d, G> { | ||||
|         let r = regs(); | ||||
|         let ng = self.g.number(); | ||||
|         let nc = ch.ch.number(); | ||||
|         r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) }); | ||||
|         r.chg(ng).modify(|w| w.set_ch(nc, false)); | ||||
|     } | ||||
| 
 | ||||
|     /// Enable all the channels in this group.
 | ||||
|     pub fn enable_all(&mut self) { | ||||
|         let n = self.g.number(); | ||||
|         regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) }); | ||||
|         regs().tasks_chg(n).en().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Disable all the channels in this group.
 | ||||
|     pub fn disable_all(&mut self) { | ||||
|         let n = self.g.number(); | ||||
|         regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) }); | ||||
|         regs().tasks_chg(n).dis().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     /// Get a reference to the "enable all" task.
 | ||||
| @ -98,7 +99,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { | ||||
|     /// When triggered, it will enable all the channels in this group.
 | ||||
|     pub fn task_enable_all(&self) -> Task<'d> { | ||||
|         let n = self.g.number(); | ||||
|         Task::from_reg(®s().tasks_chg[n].en) | ||||
|         Task::from_reg(regs().tasks_chg(n).en()) | ||||
|     } | ||||
| 
 | ||||
|     /// Get a reference to the "disable all" task.
 | ||||
| @ -106,7 +107,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { | ||||
|     /// When triggered, it will disable all the channels in this group.
 | ||||
|     pub fn task_disable_all(&self) -> Task<'d> { | ||||
|         let n = self.g.number(); | ||||
|         Task::from_reg(®s().tasks_chg[n].dis) | ||||
|         Task::from_reg(regs().tasks_chg(n).dis()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -114,7 +115,7 @@ impl<'d, G: Group> Drop for PpiGroup<'d, G> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = regs(); | ||||
|         let n = self.g.number(); | ||||
|         r.chg[n].write(|w| unsafe { w.bits(0) }); | ||||
|         r.chg(n).write(|_| ()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -143,11 +144,8 @@ impl<'d> Task<'d> { | ||||
|         unsafe { self.0.as_ptr().write_volatile(1) }; | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn from_reg<T>(reg: &T) -> Self { | ||||
|         Self( | ||||
|             unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, | ||||
|             PhantomData, | ||||
|         ) | ||||
|     pub(crate) fn from_reg(reg: Reg<u32, W>) -> Self { | ||||
|         Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData) | ||||
|     } | ||||
| 
 | ||||
|     /// Address of subscription register for this task.
 | ||||
| @ -178,11 +176,8 @@ impl<'d> Event<'d> { | ||||
|         Self(ptr, PhantomData) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn from_reg<T>(reg: &'d T) -> Self { | ||||
|         Self( | ||||
|             unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, | ||||
|             PhantomData, | ||||
|         ) | ||||
|     pub(crate) fn from_reg(reg: Reg<u32, RW>) -> Self { | ||||
|         Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData) | ||||
|     } | ||||
| 
 | ||||
|     /// Describes whether this Event is currently in a triggered state.
 | ||||
| @ -284,7 +279,7 @@ impl ConfigurableChannel for AnyConfigurableChannel { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| macro_rules! impl_ppi_channel { | ||||
|     ($type:ident, $number:expr) => { | ||||
|         impl crate::ppi::SealedChannel for peripherals::$type {} | ||||
| @ -366,7 +361,7 @@ impl_group!(PPI_GROUP0, 0); | ||||
| impl_group!(PPI_GROUP1, 1); | ||||
| impl_group!(PPI_GROUP2, 2); | ||||
| impl_group!(PPI_GROUP3, 3); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_group!(PPI_GROUP4, 4); | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| impl_group!(PPI_GROUP5, 5); | ||||
|  | ||||
| @ -14,11 +14,11 @@ impl<'d> Event<'d> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock { | ||||
|     unsafe { &*pac::PPI::ptr() } | ||||
| pub(crate) fn regs() -> pac::ppi::Ppi { | ||||
|     pac::PPI | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
 | ||||
| #[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task
 | ||||
| impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { | ||||
|     /// Configure PPI channel to trigger `task`.
 | ||||
|     pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self { | ||||
| @ -26,7 +26,7 @@ impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { | ||||
| 
 | ||||
|         let r = regs(); | ||||
|         let n = ch.number(); | ||||
|         r.fork[n].tep.write(|w| unsafe { w.bits(task.reg_val()) }); | ||||
|         r.fork(n).tep().write_value(task.reg_val()); | ||||
| 
 | ||||
|         Self { ch } | ||||
|     } | ||||
| @ -39,14 +39,14 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { | ||||
| 
 | ||||
|         let r = regs(); | ||||
|         let n = ch.number(); | ||||
|         r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) }); | ||||
|         r.ch[n].tep.write(|w| unsafe { w.bits(task.reg_val()) }); | ||||
|         r.ch(n).eep().write_value(event.reg_val()); | ||||
|         r.ch(n).tep().write_value(task.reg_val()); | ||||
| 
 | ||||
|         Self { ch } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
 | ||||
| #[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task
 | ||||
| impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { | ||||
|     /// Configure PPI channel to trigger both `task1` and `task2` on `event`.
 | ||||
|     pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { | ||||
| @ -54,9 +54,9 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { | ||||
| 
 | ||||
|         let r = regs(); | ||||
|         let n = ch.number(); | ||||
|         r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) }); | ||||
|         r.ch[n].tep.write(|w| unsafe { w.bits(task1.reg_val()) }); | ||||
|         r.fork[n].tep.write(|w| unsafe { w.bits(task2.reg_val()) }); | ||||
|         r.ch(n).eep().write_value(event.reg_val()); | ||||
|         r.ch(n).tep().write_value(task1.reg_val()); | ||||
|         r.fork(n).tep().write_value(task2.reg_val()); | ||||
| 
 | ||||
|         Self { ch } | ||||
|     } | ||||
| @ -66,13 +66,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, | ||||
|     /// Enables the channel.
 | ||||
|     pub fn enable(&mut self) { | ||||
|         let n = self.ch.number(); | ||||
|         regs().chenset.write(|w| unsafe { w.bits(1 << n) }); | ||||
|         regs().chenset().write(|w| w.set_ch(n, true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Disables the channel.
 | ||||
|     pub fn disable(&mut self) { | ||||
|         let n = self.ch.number(); | ||||
|         regs().chenclr.write(|w| unsafe { w.bits(1 << n) }); | ||||
|         regs().chenclr().write(|w| w.set_ch(n, true)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -82,9 +82,9 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for | ||||
| 
 | ||||
|         let r = regs(); | ||||
|         let n = self.ch.number(); | ||||
|         r.ch[n].eep.write(|w| unsafe { w.bits(0) }); | ||||
|         r.ch[n].tep.write(|w| unsafe { w.bits(0) }); | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         r.fork[n].tep.write(|w| unsafe { w.bits(0) }); | ||||
|         r.ch(n).eep().write_value(0); | ||||
|         r.ch(n).tep().write_value(0); | ||||
|         #[cfg(not(feature = "_nrf51"))] | ||||
|         r.fork(n).tep().write_value(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,9 @@ use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| 
 | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| 
 | ||||
| use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; | ||||
| use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::pwm::vals; | ||||
| use crate::ppi::{Event, Task}; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| @ -128,52 +130,61 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
| 
 | ||||
|         if let Some(pin) = &ch0 { | ||||
|             pin.set_low(); | ||||
|             pin.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.ch0_drive))); | ||||
|             pin.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.ch0_drive)); | ||||
|             }); | ||||
|         } | ||||
|         if let Some(pin) = &ch1 { | ||||
|             pin.set_low(); | ||||
|             pin.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.ch1_drive))); | ||||
|             pin.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.ch1_drive)); | ||||
|             }); | ||||
|         } | ||||
|         if let Some(pin) = &ch2 { | ||||
|             pin.set_low(); | ||||
|             pin.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.ch2_drive))); | ||||
|             pin.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.ch2_drive)); | ||||
|             }); | ||||
|         } | ||||
|         if let Some(pin) = &ch3 { | ||||
|             pin.set_low(); | ||||
|             pin.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.ch3_drive))); | ||||
|             pin.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.ch3_drive)); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) }); | ||||
|         r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) }); | ||||
|         r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) }); | ||||
|         r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) }); | ||||
|         r.psel().out(0).write_value(ch0.psel_bits()); | ||||
|         r.psel().out(1).write_value(ch1.psel_bits()); | ||||
|         r.psel().out(2).write_value(ch2.psel_bits()); | ||||
|         r.psel().out(3).write_value(ch3.psel_bits()); | ||||
| 
 | ||||
|         // Disable all interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.shorts.reset(); | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_loopsdone.reset(); | ||||
|         r.events_seqend[0].reset(); | ||||
|         r.events_seqend[1].reset(); | ||||
|         r.events_pwmperiodend.reset(); | ||||
|         r.events_seqstarted[0].reset(); | ||||
|         r.events_seqstarted[1].reset(); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
|         r.shorts().write(|_| ()); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.events_loopsdone().write_value(0); | ||||
|         r.events_seqend(0).write_value(0); | ||||
|         r.events_seqend(1).write_value(0); | ||||
|         r.events_pwmperiodend().write_value(0); | ||||
|         r.events_seqstarted(0).write_value(0); | ||||
|         r.events_seqstarted(1).write_value(0); | ||||
| 
 | ||||
|         r.decoder.write(|w| { | ||||
|             w.load().bits(config.sequence_load as u8); | ||||
|             w.mode().refresh_count() | ||||
|         r.decoder().write(|w| { | ||||
|             w.set_load(vals::Load::from_bits(config.sequence_load as u8)); | ||||
|             w.set_mode(vals::Mode::REFRESH_COUNT); | ||||
|         }); | ||||
| 
 | ||||
|         r.mode.write(|w| match config.counter_mode { | ||||
|             CounterMode::UpAndDown => w.updown().up_and_down(), | ||||
|             CounterMode::Up => w.updown().up(), | ||||
|         r.mode().write(|w| match config.counter_mode { | ||||
|             CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN), | ||||
|             CounterMode::Up => w.set_updown(vals::Updown::UP), | ||||
|         }); | ||||
|         r.prescaler.write(|w| w.prescaler().bits(config.prescaler as u8)); | ||||
|         r.countertop.write(|w| unsafe { w.countertop().bits(config.max_duty) }); | ||||
|         r.prescaler() | ||||
|             .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); | ||||
|         r.countertop().write(|w| w.set_countertop(config.max_duty)); | ||||
| 
 | ||||
|         Ok(Self { | ||||
|             _peri: _pwm, | ||||
| @ -189,7 +200,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_stopped(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_stopped) | ||||
|         Event::from_reg(r.events_stopped()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `LoopsDone` event endpoint for PPI.
 | ||||
| @ -197,7 +208,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_loops_done(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_loopsdone) | ||||
|         Event::from_reg(r.events_loopsdone()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
 | ||||
| @ -205,7 +216,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_pwm_period_end(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_pwmperiodend) | ||||
|         Event::from_reg(r.events_pwmperiodend()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq0 End` event endpoint for PPI.
 | ||||
| @ -213,7 +224,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_seq_end(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_seqend[0]) | ||||
|         Event::from_reg(r.events_seqend(0)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq1 End` event endpoint for PPI.
 | ||||
| @ -221,7 +232,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_seq1_end(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_seqend[1]) | ||||
|         Event::from_reg(r.events_seqend(1)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq0 Started` event endpoint for PPI.
 | ||||
| @ -229,7 +240,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_seq0_started(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_seqstarted[0]) | ||||
|         Event::from_reg(r.events_seqstarted(0)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq1 Started` event endpoint for PPI.
 | ||||
| @ -237,7 +248,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub fn event_seq1_started(&self) -> Event<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Event::from_reg(&r.events_seqstarted[1]) | ||||
|         Event::from_reg(r.events_seqstarted(1)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq0 Start` task endpoint for PPI.
 | ||||
| @ -248,7 +259,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub unsafe fn task_start_seq0(&self) -> Task<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Task::from_reg(&r.tasks_seqstart[0]) | ||||
|         Task::from_reg(r.tasks_seqstart(0)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Seq1 Started` task endpoint for PPI.
 | ||||
| @ -259,7 +270,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub unsafe fn task_start_seq1(&self) -> Task<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Task::from_reg(&r.tasks_seqstart[1]) | ||||
|         Task::from_reg(r.tasks_seqstart(1)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `NextStep` task endpoint for PPI.
 | ||||
| @ -270,7 +281,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub unsafe fn task_next_step(&self) -> Task<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Task::from_reg(&r.tasks_nextstep) | ||||
|         Task::from_reg(r.tasks_nextstep()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns reference to `Stop` task endpoint for PPI.
 | ||||
| @ -281,7 +292,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | ||||
|     pub unsafe fn task_stop(&self) -> Task<'d> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         Task::from_reg(&r.tasks_stop) | ||||
|         Task::from_reg(r.tasks_stop()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -291,23 +302,23 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> { | ||||
| 
 | ||||
|         if let Some(pin) = &self.ch0 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[0].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(0).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch1 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[1].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(1).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch2 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[2].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(2).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch3 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[3].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(3).write_value(DISCONNECTED); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -463,21 +474,17 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.seq0.refresh.write(|w| unsafe { w.bits(sequence0.config.refresh) }); | ||||
|         r.seq0.enddelay.write(|w| unsafe { w.bits(sequence0.config.end_delay) }); | ||||
|         r.seq0.ptr.write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) }); | ||||
|         r.seq0.cnt.write(|w| unsafe { w.bits(sequence0.words.len() as u32) }); | ||||
|         r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh); | ||||
|         r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay); | ||||
|         r.seq(0).ptr().write_value(sequence0.words.as_ptr() as u32); | ||||
|         r.seq(0).cnt().write(|w| w.0 = sequence0.words.len() as u32); | ||||
| 
 | ||||
|         r.seq1.refresh.write(|w| unsafe { w.bits(alt_sequence.config.refresh) }); | ||||
|         r.seq1 | ||||
|             .enddelay | ||||
|             .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) }); | ||||
|         r.seq1 | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) }); | ||||
|         r.seq1.cnt.write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) }); | ||||
|         r.seq(1).refresh().write(|w| w.0 = alt_sequence.config.refresh); | ||||
|         r.seq(1).enddelay().write(|w| w.0 = alt_sequence.config.end_delay); | ||||
|         r.seq(1).ptr().write_value(alt_sequence.words.as_ptr() as u32); | ||||
|         r.seq(1).cnt().write(|w| w.0 = alt_sequence.words.len() as u32); | ||||
| 
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         // defensive before seqstart
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| @ -486,18 +493,17 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { | ||||
| 
 | ||||
|         match times { | ||||
|             // just the one time, no loop count
 | ||||
|             SequenceMode::Loop(n) => { | ||||
|                 r.loop_.write(|w| unsafe { w.cnt().bits(n) }); | ||||
|             SequenceMode::Loop(_) => { | ||||
|                 r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); | ||||
|             } | ||||
|             // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
 | ||||
|             SequenceMode::Infinite => { | ||||
|                 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) }); | ||||
|                 r.shorts.write(|w| w.loopsdone_seqstart0().enabled()); | ||||
|                 r.loop_().write(|w| w.set_cnt(vals::LoopCnt::from_bits(1))); | ||||
|                 r.shorts().write(|w| w.set_loopsdone_seqstart0(true)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // tasks_seqstart() doesn't exist in all svds so write its bit instead
 | ||||
|         r.tasks_seqstart[seqstart_index].write(|w| unsafe { w.bits(0x01) }); | ||||
|         r.tasks_seqstart(seqstart_index).write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -509,14 +515,12 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { | ||||
|     pub fn stop(&self) { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.shorts.reset(); | ||||
|         r.shorts().write(|_| ()); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         // tasks_stop() doesn't exist in all svds so write its bit instead
 | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); | ||||
| 
 | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.tasks_stop().write_value(1); | ||||
|         r.enable().write(|w| w.set_enable(false)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -672,29 +676,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         if let Some(pin) = &ch0 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { | ||||
|             if let Some(pin) = ch { | ||||
|                 pin.set_low(); | ||||
|                 pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); | ||||
|             } | ||||
|             r.psel().out(i).write_value(ch0.psel_bits()); | ||||
|         } | ||||
|         if let Some(pin) = &ch1 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         if let Some(pin) = &ch2 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         if let Some(pin) = &ch3 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
| 
 | ||||
|         // if NoPin provided writes disconnected (top bit 1) 0x80000000 else
 | ||||
|         // writes pin number ex 13 (0x0D) which is connected (top bit 0)
 | ||||
|         r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) }); | ||||
|         r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) }); | ||||
|         r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) }); | ||||
|         r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) }); | ||||
| 
 | ||||
|         let pwm = Self { | ||||
|             _peri: _pwm, | ||||
| @ -706,26 +694,25 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|         }; | ||||
| 
 | ||||
|         // Disable all interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.shorts.reset(); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
|         r.shorts().write(|_| ()); | ||||
| 
 | ||||
|         // Enable
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         r.seq0.ptr.write(|w| unsafe { w.bits((pwm.duty).as_ptr() as u32) }); | ||||
|         r.seq(0).ptr().write_value((pwm.duty).as_ptr() as u32); | ||||
|         r.seq(0).cnt().write(|w| w.0 = 4); | ||||
|         r.seq(0).refresh().write(|w| w.0 = 0); | ||||
|         r.seq(0).enddelay().write(|w| w.0 = 0); | ||||
| 
 | ||||
|         r.seq0.cnt.write(|w| unsafe { w.bits(4) }); | ||||
|         r.seq0.refresh.write(|w| unsafe { w.bits(0) }); | ||||
|         r.seq0.enddelay.write(|w| unsafe { w.bits(0) }); | ||||
| 
 | ||||
|         r.decoder.write(|w| { | ||||
|             w.load().individual(); | ||||
|             w.mode().refresh_count() | ||||
|         r.decoder().write(|w| { | ||||
|             w.set_load(vals::Load::INDIVIDUAL); | ||||
|             w.set_mode(vals::Mode::REFRESH_COUNT); | ||||
|         }); | ||||
|         r.mode.write(|w| w.updown().up()); | ||||
|         r.prescaler.write(|w| w.prescaler().div_16()); | ||||
|         r.countertop.write(|w| unsafe { w.countertop().bits(1000) }); | ||||
|         r.loop_.write(|w| w.cnt().disabled()); | ||||
|         r.mode().write(|w| w.set_updown(vals::Updown::UP)); | ||||
|         r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); | ||||
|         r.countertop().write(|w| w.set_countertop(1000)); | ||||
|         r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); | ||||
| 
 | ||||
|         pwm | ||||
|     } | ||||
| @ -734,21 +721,21 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     #[inline(always)] | ||||
|     pub fn is_enabled(&self) -> bool { | ||||
|         let r = T::regs(); | ||||
|         r.enable.read().enable().bit_is_set() | ||||
|         r.enable().read().enable() | ||||
|     } | ||||
| 
 | ||||
|     /// Enables the PWM generator.
 | ||||
|     #[inline(always)] | ||||
|     pub fn enable(&self) { | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin.
 | ||||
|     #[inline(always)] | ||||
|     pub fn disable(&self) { | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(false)); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the current duty of the channel
 | ||||
| @ -763,33 +750,35 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|         self.duty[channel] = duty & 0x7FFF; | ||||
| 
 | ||||
|         // reload ptr in case self was moved
 | ||||
|         r.seq0.ptr.write(|w| unsafe { w.bits((self.duty).as_ptr() as u32) }); | ||||
|         r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); | ||||
| 
 | ||||
|         // defensive before seqstart
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.events_seqend[0].reset(); | ||||
|         r.events_seqend(0).write_value(0); | ||||
| 
 | ||||
|         // tasks_seqstart() doesn't exist in all svds so write its bit instead
 | ||||
|         r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_seqstart(0).write_value(1); | ||||
| 
 | ||||
|         // defensive wait until waveform is loaded after seqstart so set_duty
 | ||||
|         // can't be called again while dma is still reading
 | ||||
|         if self.is_enabled() { | ||||
|             while r.events_seqend[0].read().bits() == 0 {} | ||||
|             while r.events_seqend(0).read() == 0 {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the PWM clock prescaler.
 | ||||
|     #[inline(always)] | ||||
|     pub fn set_prescaler(&self, div: Prescaler) { | ||||
|         T::regs().prescaler.write(|w| w.prescaler().bits(div as u8)); | ||||
|         T::regs() | ||||
|             .prescaler() | ||||
|             .write(|w| w.set_prescaler(vals::Prescaler::from_bits(div as u8))); | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the PWM clock prescaler.
 | ||||
|     #[inline(always)] | ||||
|     pub fn prescaler(&self) -> Prescaler { | ||||
|         match T::regs().prescaler.read().prescaler().bits() { | ||||
|         match T::regs().prescaler().read().prescaler().to_bits() { | ||||
|             0 => Prescaler::Div1, | ||||
|             1 => Prescaler::Div2, | ||||
|             2 => Prescaler::Div4, | ||||
| @ -805,15 +794,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     /// Sets the maximum duty cycle value.
 | ||||
|     #[inline(always)] | ||||
|     pub fn set_max_duty(&self, duty: u16) { | ||||
|         T::regs() | ||||
|             .countertop | ||||
|             .write(|w| unsafe { w.countertop().bits(duty.min(32767u16)) }); | ||||
|         T::regs().countertop().write(|w| w.set_countertop(duty.min(32767u16))); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the maximum duty cycle value.
 | ||||
|     #[inline(always)] | ||||
|     pub fn max_duty(&self) -> u16 { | ||||
|         T::regs().countertop.read().countertop().bits() | ||||
|         T::regs().countertop().read().countertop() | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the PWM output frequency.
 | ||||
| @ -836,7 +823,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     #[inline(always)] | ||||
|     pub fn set_ch0_drive(&self, drive: OutputDrive) { | ||||
|         if let Some(pin) = &self.ch0 { | ||||
|             pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); | ||||
|             pin.conf().modify(|w| w.set_drive(convert_drive(drive))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -844,7 +831,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     #[inline(always)] | ||||
|     pub fn set_ch1_drive(&self, drive: OutputDrive) { | ||||
|         if let Some(pin) = &self.ch1 { | ||||
|             pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); | ||||
|             pin.conf().modify(|w| w.set_drive(convert_drive(drive))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -852,7 +839,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     #[inline(always)] | ||||
|     pub fn set_ch2_drive(&self, drive: OutputDrive) { | ||||
|         if let Some(pin) = &self.ch2 { | ||||
|             pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); | ||||
|             pin.conf().modify(|w| w.set_drive(convert_drive(drive))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -860,7 +847,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { | ||||
|     #[inline(always)] | ||||
|     pub fn set_ch3_drive(&self, drive: OutputDrive) { | ||||
|         if let Some(pin) = &self.ch3 { | ||||
|             pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); | ||||
|             pin.conf().modify(|w| w.set_drive(convert_drive(drive))); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -873,29 +860,29 @@ impl<'a, T: Instance> Drop for SimplePwm<'a, T> { | ||||
| 
 | ||||
|         if let Some(pin) = &self.ch0 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[0].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(0).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch1 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[1].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(1).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch2 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[2].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(2).write_value(DISCONNECTED); | ||||
|         } | ||||
|         if let Some(pin) = &self.ch3 { | ||||
|             pin.set_low(); | ||||
|             pin.conf().reset(); | ||||
|             r.psel.out[3].reset(); | ||||
|             pin.conf().write(|_| ()); | ||||
|             r.psel().out(3).write_value(DISCONNECTED); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::pwm0::RegisterBlock; | ||||
|     fn regs() -> pac::pwm::Pwm; | ||||
| } | ||||
| 
 | ||||
| /// PWM peripheral instance.
 | ||||
| @ -908,8 +895,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static { | ||||
| macro_rules! impl_pwm { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::pwm::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::pwm0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::pwm::Pwm { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|         } | ||||
|         impl crate::pwm::Instance for peripherals::$type { | ||||
|  | ||||
| @ -11,7 +11,9 @@ use embassy_sync::waitqueue::AtomicWaker; | ||||
| 
 | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::{interrupt, Peripheral}; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::qdec::vals; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| /// Quadrature decoder driver.
 | ||||
| pub struct Qdec<'d, T: Instance> { | ||||
| @ -52,7 +54,7 @@ pub struct InterruptHandler<T: Instance> { | ||||
| 
 | ||||
| impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         T::regs().intenclr.write(|w| w.reportrdy().clear()); | ||||
|         T::regs().intenclr().write(|w| w.set_reportrdy(true)); | ||||
|         T::state().waker.wake(); | ||||
|     } | ||||
| } | ||||
| @ -93,54 +95,59 @@ impl<'d, T: Instance> Qdec<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Select pins.
 | ||||
|         a.conf().write(|w| w.input().connect().pull().pullup()); | ||||
|         b.conf().write(|w| w.input().connect().pull().pullup()); | ||||
|         r.psel.a.write(|w| unsafe { w.bits(a.psel_bits()) }); | ||||
|         r.psel.b.write(|w| unsafe { w.bits(b.psel_bits()) }); | ||||
|         a.conf().write(|w| { | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_pull(gpiovals::Pull::PULLUP); | ||||
|         }); | ||||
|         b.conf().write(|w| { | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_pull(gpiovals::Pull::PULLUP); | ||||
|         }); | ||||
|         r.psel().a().write_value(a.psel_bits()); | ||||
|         r.psel().b().write_value(b.psel_bits()); | ||||
|         if let Some(led_pin) = &led { | ||||
|             led_pin.conf().write(|w| w.dir().output()); | ||||
|             r.psel.led.write(|w| unsafe { w.bits(led_pin.psel_bits()) }); | ||||
|             led_pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); | ||||
|             r.psel().led().write_value(led_pin.psel_bits()); | ||||
|         } | ||||
| 
 | ||||
|         // Enables/disable input debounce filters
 | ||||
|         r.dbfen.write(|w| match config.debounce { | ||||
|             true => w.dbfen().enabled(), | ||||
|             false => w.dbfen().disabled(), | ||||
|         r.dbfen().write(|w| match config.debounce { | ||||
|             true => w.set_dbfen(true), | ||||
|             false => w.set_dbfen(false), | ||||
|         }); | ||||
| 
 | ||||
|         // Set LED output pin polarity
 | ||||
|         r.ledpol.write(|w| match config.led_polarity { | ||||
|             LedPolarity::ActiveHigh => w.ledpol().active_high(), | ||||
|             LedPolarity::ActiveLow => w.ledpol().active_low(), | ||||
|         r.ledpol().write(|w| match config.led_polarity { | ||||
|             LedPolarity::ActiveHigh => w.set_ledpol(vals::Ledpol::ACTIVE_HIGH), | ||||
|             LedPolarity::ActiveLow => w.set_ledpol(vals::Ledpol::ACTIVE_LOW), | ||||
|         }); | ||||
| 
 | ||||
|         // Set time period the LED is switched ON prior to sampling (0..511 us).
 | ||||
|         r.ledpre | ||||
|             .write(|w| unsafe { w.ledpre().bits(config.led_pre_usecs.min(511)) }); | ||||
|         r.ledpre().write(|w| w.set_ledpre(config.led_pre_usecs.min(511))); | ||||
| 
 | ||||
|         // Set sample period
 | ||||
|         r.sampleper.write(|w| match config.period { | ||||
|             SamplePeriod::_128us => w.sampleper()._128us(), | ||||
|             SamplePeriod::_256us => w.sampleper()._256us(), | ||||
|             SamplePeriod::_512us => w.sampleper()._512us(), | ||||
|             SamplePeriod::_1024us => w.sampleper()._1024us(), | ||||
|             SamplePeriod::_2048us => w.sampleper()._2048us(), | ||||
|             SamplePeriod::_4096us => w.sampleper()._4096us(), | ||||
|             SamplePeriod::_8192us => w.sampleper()._8192us(), | ||||
|             SamplePeriod::_16384us => w.sampleper()._16384us(), | ||||
|             SamplePeriod::_32ms => w.sampleper()._32ms(), | ||||
|             SamplePeriod::_65ms => w.sampleper()._65ms(), | ||||
|             SamplePeriod::_131ms => w.sampleper()._131ms(), | ||||
|         r.sampleper().write(|w| match config.period { | ||||
|             SamplePeriod::_128us => w.set_sampleper(vals::Sampleper::_128US), | ||||
|             SamplePeriod::_256us => w.set_sampleper(vals::Sampleper::_256US), | ||||
|             SamplePeriod::_512us => w.set_sampleper(vals::Sampleper::_512US), | ||||
|             SamplePeriod::_1024us => w.set_sampleper(vals::Sampleper::_1024US), | ||||
|             SamplePeriod::_2048us => w.set_sampleper(vals::Sampleper::_2048US), | ||||
|             SamplePeriod::_4096us => w.set_sampleper(vals::Sampleper::_4096US), | ||||
|             SamplePeriod::_8192us => w.set_sampleper(vals::Sampleper::_8192US), | ||||
|             SamplePeriod::_16384us => w.set_sampleper(vals::Sampleper::_16384US), | ||||
|             SamplePeriod::_32ms => w.set_sampleper(vals::Sampleper::_32MS), | ||||
|             SamplePeriod::_65ms => w.set_sampleper(vals::Sampleper::_65MS), | ||||
|             SamplePeriod::_131ms => w.set_sampleper(vals::Sampleper::_131MS), | ||||
|         }); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| 
 | ||||
|         // Enable peripheral
 | ||||
|         r.enable.write(|w| w.enable().set_bit()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         // Start sampling
 | ||||
|         unsafe { r.tasks_start.write(|w| w.bits(1)) }; | ||||
|         r.tasks_start().write_value(1); | ||||
| 
 | ||||
|         Self { _p: p } | ||||
|     } | ||||
| @ -169,16 +176,16 @@ impl<'d, T: Instance> Qdec<'d, T> { | ||||
|     /// ```
 | ||||
|     pub async fn read(&mut self) -> i16 { | ||||
|         let t = T::regs(); | ||||
|         t.intenset.write(|w| w.reportrdy().set()); | ||||
|         unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; | ||||
|         t.intenset().write(|w| w.set_reportrdy(true)); | ||||
|         t.tasks_readclracc().write_value(1); | ||||
| 
 | ||||
|         poll_fn(|cx| { | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if t.events_reportrdy.read().bits() == 0 { | ||||
|             if t.events_reportrdy().read() == 0 { | ||||
|                 Poll::Pending | ||||
|             } else { | ||||
|                 t.events_reportrdy.reset(); | ||||
|                 let acc = t.accread.read().bits(); | ||||
|                 t.events_reportrdy().write_value(0); | ||||
|                 let acc = t.accread().read(); | ||||
|                 Poll::Ready(acc as i16) | ||||
|             } | ||||
|         }) | ||||
| @ -259,7 +266,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::qdec::RegisterBlock; | ||||
|     fn regs() -> pac::qdec::Qdec; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -273,8 +280,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_qdec { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qdec::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::qdec::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::qdec::Qdec { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::qdec::State { | ||||
|                 static STATE: crate::qdec::State = crate::qdec::State::new(); | ||||
|  | ||||
| @ -14,11 +14,12 @@ use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashEr | ||||
| 
 | ||||
| use crate::gpio::{self, Pin as GpioPin}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| pub use crate::pac::qspi::ifconfig0::{ | ||||
|     ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::qspi::vals; | ||||
| pub use crate::pac::qspi::vals::{ | ||||
|     Addrmode as AddressMode, Ppsize as WritePageSize, Readoc as ReadOpcode, Spimode as SpiMode, Writeoc as WriteOpcode, | ||||
| }; | ||||
| pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; | ||||
| use crate::{interrupt, Peripheral}; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| /// Deep power-down config.
 | ||||
| pub struct DeepPowerDownConfig { | ||||
| @ -129,9 +130,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         if r.events_ready.read().bits() != 0 { | ||||
|         if r.events_ready().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.ready().clear()); | ||||
|             r.intenclr().write(|w| w.set_ready(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -164,13 +165,12 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|             ($pin:ident) => { | ||||
|                 $pin.set_high(); | ||||
|                 $pin.conf().write(|w| { | ||||
|                     w.dir().output(); | ||||
|                     w.drive().h0h1(); | ||||
|                     w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                     w.set_drive(gpiovals::Drive::H0H1); | ||||
|                     #[cfg(all(feature = "_nrf5340", feature = "_s"))] | ||||
|                     w.mcusel().peripheral(); | ||||
|                     w | ||||
|                     w.set_mcusel(gpiovals::Mcusel::PERIPHERAL); | ||||
|                 }); | ||||
|                 r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) }); | ||||
|                 r.psel().$pin().write_value($pin.psel_bits()); | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
| @ -181,46 +181,39 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         config_pin!(io2); | ||||
|         config_pin!(io3); | ||||
| 
 | ||||
|         r.ifconfig0.write(|w| { | ||||
|             w.addrmode().variant(config.address_mode); | ||||
|             w.dpmenable().bit(config.deep_power_down.is_some()); | ||||
|             w.ppsize().variant(config.write_page_size); | ||||
|             w.readoc().variant(config.read_opcode); | ||||
|             w.writeoc().variant(config.write_opcode); | ||||
|             w | ||||
|         r.ifconfig0().write(|w| { | ||||
|             w.set_addrmode(config.address_mode); | ||||
|             w.set_dpmenable(config.deep_power_down.is_some()); | ||||
|             w.set_ppsize(config.write_page_size); | ||||
|             w.set_readoc(config.read_opcode); | ||||
|             w.set_writeoc(config.write_opcode); | ||||
|         }); | ||||
| 
 | ||||
|         if let Some(dpd) = &config.deep_power_down { | ||||
|             r.dpmdur.write(|w| unsafe { | ||||
|                 w.enter().bits(dpd.enter_time); | ||||
|                 w.exit().bits(dpd.exit_time); | ||||
|                 w | ||||
|             r.dpmdur().write(|w| { | ||||
|                 w.set_enter(dpd.enter_time); | ||||
|                 w.set_exit(dpd.exit_time); | ||||
|             }) | ||||
|         } | ||||
| 
 | ||||
|         r.ifconfig1.write(|w| unsafe { | ||||
|             w.sckdelay().bits(config.sck_delay); | ||||
|             w.dpmen().exit(); | ||||
|             w.spimode().variant(config.spi_mode); | ||||
|             w.sckfreq().bits(config.frequency as u8); | ||||
|             w | ||||
|         r.ifconfig1().write(|w| { | ||||
|             w.set_sckdelay(config.sck_delay); | ||||
|             w.set_dpmen(false); | ||||
|             w.set_spimode(config.spi_mode); | ||||
|             w.set_sckfreq(config.frequency as u8); | ||||
|         }); | ||||
| 
 | ||||
|         r.iftiming.write(|w| unsafe { | ||||
|             w.rxdelay().bits(config.rx_delay & 0b111); | ||||
|             w | ||||
|         r.iftiming().write(|w| { | ||||
|             w.set_rxdelay(config.rx_delay & 0b111); | ||||
|         }); | ||||
| 
 | ||||
|         r.xipoffset.write(|w| unsafe { | ||||
|             w.xipoffset().bits(config.xip_offset); | ||||
|             w | ||||
|         }); | ||||
|         r.xipoffset().write_value(config.xip_offset); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| 
 | ||||
|         // Enable it
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         let res = Self { | ||||
|             _peri: qspi, | ||||
| @ -228,10 +221,10 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|             capacity: config.capacity, | ||||
|         }; | ||||
| 
 | ||||
|         r.events_ready.reset(); | ||||
|         r.intenset.write(|w| w.ready().set()); | ||||
|         r.events_ready().write_value(0); | ||||
|         r.intenset().write(|w| w.set_ready(true)); | ||||
| 
 | ||||
|         r.tasks_activate.write(|w| w.tasks_activate().bit(true)); | ||||
|         r.tasks_activate().write_value(1); | ||||
| 
 | ||||
|         Self::blocking_wait_ready(); | ||||
| 
 | ||||
| @ -284,22 +277,21 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         } | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
|         r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); | ||||
|         r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); | ||||
|         r.cinstrdat0().write(|w| w.0 = dat0); | ||||
|         r.cinstrdat1().write(|w| w.0 = dat1); | ||||
| 
 | ||||
|         r.events_ready.reset(); | ||||
|         r.intenset.write(|w| w.ready().set()); | ||||
|         r.events_ready().write_value(0); | ||||
|         r.intenset().write(|w| w.set_ready(true)); | ||||
| 
 | ||||
|         r.cinstrconf.write(|w| { | ||||
|             let w = unsafe { w.opcode().bits(opcode) }; | ||||
|             let w = unsafe { w.length().bits(len + 1) }; | ||||
|             let w = w.lio2().bit(true); | ||||
|             let w = w.lio3().bit(true); | ||||
|             let w = w.wipwait().bit(true); | ||||
|             let w = w.wren().bit(true); | ||||
|             let w = w.lfen().bit(false); | ||||
|             let w = w.lfstop().bit(false); | ||||
|             w | ||||
|         r.cinstrconf().write(|w| { | ||||
|             w.set_opcode(opcode); | ||||
|             w.set_length(vals::Length::from_bits(len + 1)); | ||||
|             w.set_lio2(true); | ||||
|             w.set_lio3(true); | ||||
|             w.set_wipwait(true); | ||||
|             w.set_wren(true); | ||||
|             w.set_lfen(false); | ||||
|             w.set_lfstop(false); | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -307,8 +299,8 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|     fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         let dat0 = r.cinstrdat0.read().bits(); | ||||
|         let dat1 = r.cinstrdat1.read().bits(); | ||||
|         let dat0 = r.cinstrdat0().read().0; | ||||
|         let dat1 = r.cinstrdat1().read().0; | ||||
|         for i in 0..4 { | ||||
|             if i < resp.len() { | ||||
|                 resp[i] = (dat0 >> (i * 8)) as u8; | ||||
| @ -327,7 +319,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|             let r = T::regs(); | ||||
|             let s = T::state(); | ||||
|             s.waker.register(cx.waker()); | ||||
|             if r.events_ready.read().bits() != 0 { | ||||
|             if r.events_ready().read() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -338,7 +330,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|     fn blocking_wait_ready() { | ||||
|         loop { | ||||
|             let r = T::regs(); | ||||
|             if r.events_ready.read().bits() != 0 { | ||||
|             if r.events_ready().read() != 0 { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| @ -352,13 +344,13 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.read.src.write(|w| unsafe { w.src().bits(address) }); | ||||
|         r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); | ||||
|         r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||||
|         r.read().src().write_value(address); | ||||
|         r.read().dst().write_value(data.as_ptr() as u32); | ||||
|         r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); | ||||
| 
 | ||||
|         r.events_ready.reset(); | ||||
|         r.intenset.write(|w| w.ready().set()); | ||||
|         r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); | ||||
|         r.events_ready().write_value(0); | ||||
|         r.intenset().write(|w| w.set_ready(true)); | ||||
|         r.tasks_readstart().write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -370,13 +362,13 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         assert_eq!(address % 4, 0); | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
|         r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); | ||||
|         r.write.dst.write(|w| unsafe { w.dst().bits(address) }); | ||||
|         r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | ||||
|         r.write().src().write_value(data.as_ptr() as u32); | ||||
|         r.write().dst().write_value(address); | ||||
|         r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); | ||||
| 
 | ||||
|         r.events_ready.reset(); | ||||
|         r.intenset.write(|w| w.ready().set()); | ||||
|         r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); | ||||
|         r.events_ready().write_value(0); | ||||
|         r.intenset().write(|w| w.set_ready(true)); | ||||
|         r.tasks_writestart().write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -386,12 +378,12 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         assert_eq!(address % 4096, 0); | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
|         r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); | ||||
|         r.erase.len.write(|w| w.len()._4kb()); | ||||
|         r.erase().ptr().write_value(address); | ||||
|         r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); | ||||
| 
 | ||||
|         r.events_ready.reset(); | ||||
|         r.intenset.write(|w| w.ready().set()); | ||||
|         r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); | ||||
|         r.events_ready().write_value(0); | ||||
|         r.intenset().write(|w| w.set_ready(true)); | ||||
|         r.tasks_erasestart().write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -538,12 +530,12 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { | ||||
|         if self.dpm_enabled { | ||||
|             trace!("qspi: doing deep powerdown..."); | ||||
| 
 | ||||
|             r.ifconfig1.modify(|_, w| w.dpmen().enter()); | ||||
|             r.ifconfig1().modify(|w| w.set_dpmen(true)); | ||||
| 
 | ||||
|             // Wait for DPM enter.
 | ||||
|             // Unfortunately we must spin. There's no way to do this interrupt-driven.
 | ||||
|             // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:)
 | ||||
|             while r.status.read().dpm().is_disabled() {} | ||||
|             while !r.status().read().dpm() {} | ||||
| 
 | ||||
|             // Wait MORE for DPM enter.
 | ||||
|             // I have absolutely no idea why, but the wait above is not enough :'(
 | ||||
| @ -552,23 +544,23 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { | ||||
|         } | ||||
| 
 | ||||
|         // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it.
 | ||||
|         r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit()); | ||||
|         r.tasks_deactivate().write_value(1); | ||||
| 
 | ||||
|         // Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7
 | ||||
|         // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate,
 | ||||
|         // so we only do the second one here.
 | ||||
|         unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } | ||||
| 
 | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(false)); | ||||
| 
 | ||||
|         // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
 | ||||
|         // leaving it floating, the flash chip might read it as zero which would cause it to
 | ||||
|         // spuriously exit DPM.
 | ||||
|         gpio::deconfigure_pin(r.psel.sck.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.io0.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.io1.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.io2.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.io3.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().sck().read()); | ||||
|         gpio::deconfigure_pin(r.psel().io0().read()); | ||||
|         gpio::deconfigure_pin(r.psel().io1().read()); | ||||
|         gpio::deconfigure_pin(r.psel().io2().read()); | ||||
|         gpio::deconfigure_pin(r.psel().io3().read()); | ||||
| 
 | ||||
|         trace!("qspi: dropped"); | ||||
|     } | ||||
| @ -667,7 +659,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::qspi::RegisterBlock; | ||||
|     fn regs() -> pac::qspi::Qspi; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -681,8 +673,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_qspi { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qspi::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::qspi::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::qspi::Qspi { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::qspi::State { | ||||
|                 static STATE: crate::qspi::State = crate::qspi::State::new(); | ||||
|  | ||||
| @ -6,11 +6,12 @@ use core::task::Poll; | ||||
| 
 | ||||
| use embassy_hal_internal::drop::OnDrop; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| pub use pac::radio::mode::MODE_A as Mode; | ||||
| #[cfg(not(feature = "nrf51"))] | ||||
| use pac::radio::pcnf0::PLEN_A as PreambleLength; | ||||
| pub use pac::radio::vals::Mode; | ||||
| #[cfg(not(feature = "_nrf51"))] | ||||
| use pac::radio::vals::Plen as PreambleLength; | ||||
| 
 | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::radio::vals; | ||||
| use crate::radio::*; | ||||
| pub use crate::radio::{Error, TxPower}; | ||||
| use crate::util::slice_in_ram_or; | ||||
| @ -30,69 +31,63 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.pcnf1.write(|w| unsafe { | ||||
|         r.pcnf1().write(|w| { | ||||
|             // It is 0 bytes long in a standard BLE packet
 | ||||
|             w.statlen() | ||||
|                 .bits(0) | ||||
|                 // MaxLen configures the maximum packet payload plus add-on size in
 | ||||
|                 // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
 | ||||
|                 // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
 | ||||
|                 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
 | ||||
|                 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
 | ||||
|                 //
 | ||||
|                 // To simplify the implementation, It is setted as the maximum value
 | ||||
|                 // and the length of the packet is controlled only by the LENGTH field in the packet
 | ||||
|                 .maxlen() | ||||
|                 .bits(255) | ||||
|                 // Configure the length of the address field in the packet
 | ||||
|                 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
 | ||||
|                 // The base address is truncated from the least significant byte if the BALEN is less than 4
 | ||||
|                 //
 | ||||
|                 // BLE address is always 4 bytes long
 | ||||
|                 .balen() | ||||
|                 .bits(3) // 3 bytes base address (+ 1 prefix);
 | ||||
|                 // Configure the endianess
 | ||||
|                 // For BLE is always little endian (LSB first)
 | ||||
|                 .endian() | ||||
|                 .little() | ||||
|                 // Data whitening is used to avoid long sequences of zeros or
 | ||||
|                 // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
 | ||||
|                 // The whitener and de-whitener are defined the same way,
 | ||||
|                 // using a 7-bit linear feedback shift register with the
 | ||||
|                 // polynomial x7 + x4 + 1.
 | ||||
|                 //
 | ||||
|                 // In BLE Whitening shall be applied on the PDU and CRC of all
 | ||||
|                 // Link Layer packets and is performed after the CRC generation
 | ||||
|                 // in the transmitter. No other parts of the packets are whitened.
 | ||||
|                 // De-whitening is performed before the CRC checking in the receiver
 | ||||
|                 // Before whitening or de-whitening, the shift register should be
 | ||||
|                 // initialized based on the channel index.
 | ||||
|                 .whiteen() | ||||
|                 .set_bit() | ||||
|             w.set_statlen(0); | ||||
|             // MaxLen configures the maximum packet payload plus add-on size in
 | ||||
|             // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
 | ||||
|             // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
 | ||||
|             // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
 | ||||
|             // packet larger than MAXLEN, the payload will be truncated at MAXLEN
 | ||||
|             //
 | ||||
|             // To simplify the implementation, It is setted as the maximum value
 | ||||
|             // and the length of the packet is controlled only by the LENGTH field in the packet
 | ||||
|             w.set_maxlen(255); | ||||
|             // Configure the length of the address field in the packet
 | ||||
|             // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
 | ||||
|             // The base address is truncated from the least significant byte if the BALEN is less than 4
 | ||||
|             //
 | ||||
|             // BLE address is always 4 bytes long
 | ||||
|             w.set_balen(3); // 3 bytes base address (+ 1 prefix);
 | ||||
|                             // Configure the endianess
 | ||||
|                             // For BLE is always little endian (LSB first)
 | ||||
|             w.set_endian(vals::Endian::LITTLE); | ||||
|             // Data whitening is used to avoid long sequences of zeros or
 | ||||
|             // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
 | ||||
|             // The whitener and de-whitener are defined the same way,
 | ||||
|             // using a 7-bit linear feedback shift register with the
 | ||||
|             // polynomial x7 + x4 + 1.
 | ||||
|             //
 | ||||
|             // In BLE Whitening shall be applied on the PDU and CRC of all
 | ||||
|             // Link Layer packets and is performed after the CRC generation
 | ||||
|             // in the transmitter. No other parts of the packets are whitened.
 | ||||
|             // De-whitening is performed before the CRC checking in the receiver
 | ||||
|             // Before whitening or de-whitening, the shift register should be
 | ||||
|             // initialized based on the channel index.
 | ||||
|             w.set_whiteen(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Configure CRC
 | ||||
|         r.crccnf.write(|w| { | ||||
|         r.crccnf().write(|w| { | ||||
|             // In BLE the CRC shall be calculated on the PDU of all Link Layer
 | ||||
|             // packets (even if the packet is encrypted).
 | ||||
|             // It skips the address field
 | ||||
|             w.skipaddr() | ||||
|                 .skip() | ||||
|                 // In BLE  24-bit CRC = 3 bytes
 | ||||
|                 .len() | ||||
|                 .three() | ||||
|             w.set_skipaddr(vals::Skipaddr::SKIP); | ||||
|             // In BLE  24-bit CRC = 3 bytes
 | ||||
|             w.set_len(vals::Len::THREE); | ||||
|         }); | ||||
| 
 | ||||
|         // Ch map between 2400 MHZ .. 2500 MHz
 | ||||
|         // All modes use this range
 | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         r.frequency.write(|w| w.map().default()); | ||||
|         #[cfg(not(feature = "_nrf51"))] | ||||
|         r.frequency().write(|w| w.set_map(vals::Map::DEFAULT)); | ||||
| 
 | ||||
|         // Configure shortcuts to simplify and speed up sending and receiving packets.
 | ||||
|         r.shorts.write(|w| { | ||||
|         r.shorts().write(|w| { | ||||
|             // start transmission/recv immediately after ramp-up
 | ||||
|             // disable radio when transmission/recv is done
 | ||||
|             w.ready_start().enabled().end_disable().enabled() | ||||
|             w.set_ready_start(true); | ||||
|             w.set_end_disable(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Enable NVIC interrupt
 | ||||
| @ -113,11 +108,11 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         assert!(self.state() == RadioState::DISABLED); | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
|         r.mode.write(|w| w.mode().variant(mode)); | ||||
|         r.mode().write(|w| w.set_mode(mode)); | ||||
| 
 | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         r.pcnf0.write(|w| { | ||||
|             w.plen().variant(match mode { | ||||
|         #[cfg(not(feature = "_nrf51"))] | ||||
|         r.pcnf0().write(|w| { | ||||
|             w.set_plen(match mode { | ||||
|                 Mode::BLE_1MBIT => PreambleLength::_8BIT, | ||||
|                 Mode::BLE_2MBIT => PreambleLength::_16BIT, | ||||
|                 #[cfg(any(
 | ||||
| @ -147,18 +142,14 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|             true => 8, | ||||
|         }; | ||||
| 
 | ||||
|         r.pcnf0.write(|w| unsafe { | ||||
|             w | ||||
|                 // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
 | ||||
|                 .s0len() | ||||
|                 .set_bit() | ||||
|                 // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
 | ||||
|                 // and also be used to know how many bytes to read/write from/to the buffer
 | ||||
|                 .lflen() | ||||
|                 .bits(8) | ||||
|                 // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
 | ||||
|                 .s1len() | ||||
|                 .bits(s1len) | ||||
|         r.pcnf0().write(|w| { | ||||
|             // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
 | ||||
|             w.set_s0len(true); | ||||
|             // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
 | ||||
|             // and also be used to know how many bytes to read/write from/to the buffer
 | ||||
|             w.set_lflen(0); | ||||
|             // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
 | ||||
|             w.set_s1len(s1len); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -172,7 +163,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); | ||||
|         r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init)); | ||||
|     } | ||||
| 
 | ||||
|     /// Set the central frequency to be used
 | ||||
| @ -185,8 +176,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.frequency | ||||
|             .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) }); | ||||
|         r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8)); | ||||
|     } | ||||
| 
 | ||||
|     /// Set the acess address
 | ||||
| @ -204,31 +194,25 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         // The byte ordering on air is always least significant byte first for the address
 | ||||
|         // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
 | ||||
|         // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
 | ||||
|         r.prefix0 | ||||
|             .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) }); | ||||
|         r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8)); | ||||
| 
 | ||||
|         // The base address is truncated from the least significant byte (because the BALEN is less than 4)
 | ||||
|         // So it shifts the address to the right
 | ||||
|         r.base0.write(|w| unsafe { w.bits(access_address << 8) }); | ||||
|         r.base0().write_value(access_address << 8); | ||||
| 
 | ||||
|         // Don't match tx address
 | ||||
|         r.txaddress.write(|w| unsafe { w.txaddress().bits(0) }); | ||||
|         r.txaddress().write(|w| w.set_txaddress(0)); | ||||
| 
 | ||||
|         // Match on logical address
 | ||||
|         // This config only filter the packets by the address,
 | ||||
|         // so only packages send to the previous address
 | ||||
|         // will finish the reception (TODO: check the explanation)
 | ||||
|         r.rxaddresses.write(|w| { | ||||
|             w.addr0() | ||||
|                 .enabled() | ||||
|                 .addr1() | ||||
|                 .enabled() | ||||
|                 .addr2() | ||||
|                 .enabled() | ||||
|                 .addr3() | ||||
|                 .enabled() | ||||
|                 .addr4() | ||||
|                 .enabled() | ||||
|         r.rxaddresses().write(|w| { | ||||
|             w.set_addr0(true); | ||||
|             w.set_addr1(true); | ||||
|             w.set_addr2(true); | ||||
|             w.set_addr3(true); | ||||
|             w.set_addr4(true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -241,7 +225,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.crcpoly.write(|w| unsafe { | ||||
|         r.crcpoly().write(|w| { | ||||
|             // Configure the CRC polynomial
 | ||||
|             // Each term in the CRC polynomial is mapped to a bit in this
 | ||||
|             // register which index corresponds to the term's exponent.
 | ||||
| @ -249,7 +233,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|             // 1, and bit number 0 of the register content is ignored by
 | ||||
|             // the hardware. The following example is for an 8 bit CRC
 | ||||
|             // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
 | ||||
|             w.crcpoly().bits(crc_poly & 0xFFFFFF) | ||||
|             w.set_crcpoly(crc_poly & 0xFFFFFF) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -263,7 +247,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); | ||||
|         r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF)); | ||||
|     } | ||||
| 
 | ||||
|     /// Set the radio tx power
 | ||||
| @ -274,7 +258,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.txpower.write(|w| w.txpower().variant(tx_power)); | ||||
|         r.txpower().write(|w| w.set_txpower(tx_power)); | ||||
|     } | ||||
| 
 | ||||
|     /// Set buffer to read/write
 | ||||
| @ -294,7 +278,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         let ptr = buffer.as_ptr(); | ||||
| 
 | ||||
|         // Configure the payload
 | ||||
|         r.packetptr.write(|w| unsafe { w.bits(ptr as u32) }); | ||||
|         r.packetptr().write_value(ptr as u32); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -310,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|             // Initialize the transmission
 | ||||
|             // trace!("txen");
 | ||||
| 
 | ||||
|             r.tasks_txen.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_txen().write_value(1); | ||||
|         }) | ||||
|         .await; | ||||
| 
 | ||||
| @ -327,7 +311,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         self.trigger_and_wait_end(move || { | ||||
|             // Initialize the transmission
 | ||||
|             // trace!("rxen");
 | ||||
|             r.tasks_rxen.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_rxen().write_value(1); | ||||
|         }) | ||||
|         .await; | ||||
| 
 | ||||
| @ -344,21 +328,21 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         let drop = OnDrop::new(|| { | ||||
|             trace!("radio drop: stopping"); | ||||
| 
 | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|             r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_stop().write_value(1); | ||||
| 
 | ||||
|             r.events_end.reset(); | ||||
|             r.events_end().write_value(0); | ||||
| 
 | ||||
|             trace!("radio drop: stopped"); | ||||
|         }); | ||||
| 
 | ||||
|         // trace!("radio:enable interrupt");
 | ||||
|         // Clear some remnant side-effects (TODO: check if this is necessary)
 | ||||
|         r.events_end.reset(); | ||||
|         r.events_end().write_value(0); | ||||
| 
 | ||||
|         // Enable interrupt
 | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
|         r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
| @ -368,7 +352,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         // On poll check if interrupt happen
 | ||||
|         poll_fn(|cx| { | ||||
|             s.event_waker.register(cx.waker()); | ||||
|             if r.events_end.read().bits() == 1 { | ||||
|             if r.events_end().read() == 1 { | ||||
|                 // trace!("radio:end");
 | ||||
|                 return core::task::Poll::Ready(()); | ||||
|             } | ||||
| @ -377,7 +361,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         .await; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         r.events_end.reset(); // ACK
 | ||||
|         r.events_end().write_value(0); // ACK
 | ||||
| 
 | ||||
|         // Everthing ends fine, so it disable the drop
 | ||||
|         drop.defuse(); | ||||
| @ -392,15 +376,15 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         if self.state() != RadioState::DISABLED { | ||||
|             trace!("radio:disable"); | ||||
|             // Trigger the disable task
 | ||||
|             r.tasks_disable.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_disable().write_value(1); | ||||
| 
 | ||||
|             // Wait until the radio is disabled
 | ||||
|             while r.events_disabled.read().bits() == 0 {} | ||||
|             while r.events_disabled().read() == 0 {} | ||||
| 
 | ||||
|             compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|             // Acknowledge it
 | ||||
|             r.events_disabled.reset(); | ||||
|             r.events_disabled().write_value(0); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -9,6 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::interrupt::{self}; | ||||
| use crate::pac::radio::vals; | ||||
| use crate::Peripheral; | ||||
| 
 | ||||
| /// Default (IEEE compliant) Start of Frame Delimiter
 | ||||
| @ -47,58 +48,47 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Disable and enable to reset peripheral
 | ||||
|         r.power.write(|w| w.power().disabled()); | ||||
|         r.power.write(|w| w.power().enabled()); | ||||
|         r.power().write(|w| w.set_power(false)); | ||||
|         r.power().write(|w| w.set_power(true)); | ||||
| 
 | ||||
|         // Enable 802.15.4 mode
 | ||||
|         r.mode.write(|w| w.mode().ieee802154_250kbit()); | ||||
|         r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); | ||||
|         // Configure CRC skip address
 | ||||
|         r.crccnf.write(|w| w.len().two().skipaddr().ieee802154()); | ||||
|         unsafe { | ||||
|             // Configure CRC polynomial and init
 | ||||
|             r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021)); | ||||
|             r.crcinit.write(|w| w.crcinit().bits(0)); | ||||
|             r.pcnf0.write(|w| { | ||||
|                 // 8-bit on air length
 | ||||
|                 w.lflen() | ||||
|                     .bits(8) | ||||
|                     // Zero bytes S0 field length
 | ||||
|                     .s0len() | ||||
|                     .clear_bit() | ||||
|                     // Zero bytes S1 field length
 | ||||
|                     .s1len() | ||||
|                     .bits(0) | ||||
|                     // Do not include S1 field in RAM if S1 length > 0
 | ||||
|                     .s1incl() | ||||
|                     .clear_bit() | ||||
|                     // Zero code Indicator length
 | ||||
|                     .cilen() | ||||
|                     .bits(0) | ||||
|                     // 32-bit zero preamble
 | ||||
|                     .plen() | ||||
|                     ._32bit_zero() | ||||
|                     // Include CRC in length
 | ||||
|                     .crcinc() | ||||
|                     .include() | ||||
|             }); | ||||
|             r.pcnf1.write(|w| { | ||||
|                 // Maximum packet length
 | ||||
|                 w.maxlen() | ||||
|                     .bits(Packet::MAX_PSDU_LEN) | ||||
|                     // Zero static length
 | ||||
|                     .statlen() | ||||
|                     .bits(0) | ||||
|                     // Zero base address length
 | ||||
|                     .balen() | ||||
|                     .bits(0) | ||||
|                     // Little-endian
 | ||||
|                     .endian() | ||||
|                     .clear_bit() | ||||
|                     // Disable packet whitening
 | ||||
|                     .whiteen() | ||||
|                     .clear_bit() | ||||
|             }); | ||||
|         } | ||||
|         r.crccnf().write(|w| { | ||||
|             w.set_len(vals::Len::TWO); | ||||
|             w.set_skipaddr(vals::Skipaddr::IEEE802154); | ||||
|         }); | ||||
|         // Configure CRC polynomial and init
 | ||||
|         r.crcpoly().write(|w| w.set_crcpoly(0x0001_1021)); | ||||
|         r.crcinit().write(|w| w.set_crcinit(0)); | ||||
|         r.pcnf0().write(|w| { | ||||
|             // 8-bit on air length
 | ||||
|             w.set_lflen(8); | ||||
|             // Zero bytes S0 field length
 | ||||
|             w.set_s0len(false); | ||||
|             // Zero bytes S1 field length
 | ||||
|             w.set_s1len(0); | ||||
|             // Do not include S1 field in RAM if S1 length > 0
 | ||||
|             w.set_s1incl(vals::S1incl::AUTOMATIC); | ||||
|             // Zero code Indicator length
 | ||||
|             w.set_cilen(0); | ||||
|             // 32-bit zero preamble
 | ||||
|             w.set_plen(vals::Plen::_32BIT_ZERO); | ||||
|             // Include CRC in length
 | ||||
|             w.set_crcinc(vals::Crcinc::INCLUDE); | ||||
|         }); | ||||
|         r.pcnf1().write(|w| { | ||||
|             // Maximum packet length
 | ||||
|             w.set_maxlen(Packet::MAX_PSDU_LEN); | ||||
|             // Zero static length
 | ||||
|             w.set_statlen(0); | ||||
|             // Zero base address length
 | ||||
|             w.set_balen(0); | ||||
|             // Little-endian
 | ||||
|             w.set_endian(vals::Endian::LITTLE); | ||||
|             // Disable packet whitening
 | ||||
|             w.set_whiteen(false); | ||||
|         }); | ||||
| 
 | ||||
|         // Enable NVIC interrupt
 | ||||
|         T::Interrupt::unpend(); | ||||
| @ -125,8 +115,10 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         } | ||||
|         let frequency_offset = (channel - 10) * 5; | ||||
|         self.needs_enable = true; | ||||
|         r.frequency | ||||
|             .write(|w| unsafe { w.frequency().bits(frequency_offset).map().default() }); | ||||
|         r.frequency().write(|w| { | ||||
|             w.set_frequency(frequency_offset); | ||||
|             w.set_map(vals::Map::DEFAULT); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /// Changes the Clear Channel Assessment method
 | ||||
| @ -134,12 +126,14 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         self.needs_enable = true; | ||||
|         match cca { | ||||
|             Cca::CarrierSense => r.ccactrl.write(|w| w.ccamode().carrier_mode()), | ||||
|             Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)), | ||||
|             Cca::EnergyDetection { ed_threshold } => { | ||||
|                 // "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL
 | ||||
|                 // and writing the CCAEDTHRES field to a chosen value."
 | ||||
|                 r.ccactrl | ||||
|                     .write(|w| unsafe { w.ccamode().ed_mode().ccaedthres().bits(ed_threshold) }); | ||||
|                 r.ccactrl().write(|w| { | ||||
|                     w.set_ccamode(vals::Ccamode::ED_MODE); | ||||
|                     w.set_ccaedthres(ed_threshold); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -147,13 +141,13 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|     /// Changes the Start of Frame Delimiter (SFD)
 | ||||
|     pub fn set_sfd(&mut self, sfd: u8) { | ||||
|         let r = T::regs(); | ||||
|         r.sfd.write(|w| unsafe { w.sfd().bits(sfd) }); | ||||
|         r.sfd().write(|w| w.set_sfd(sfd)); | ||||
|     } | ||||
| 
 | ||||
|     /// Clear interrupts
 | ||||
|     pub fn clear_all_interrupts(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xffff_ffff) }); | ||||
|         r.intenclr().write(|w| w.0 = 0xffff_ffff); | ||||
|     } | ||||
| 
 | ||||
|     /// Changes the radio transmission power
 | ||||
| @ -163,43 +157,43 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         let tx_power: TxPower = match power { | ||||
|             #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] | ||||
|             8 => TxPower::POS8D_BM, | ||||
|             8 => TxPower::POS8_DBM, | ||||
|             #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] | ||||
|             7 => TxPower::POS7D_BM, | ||||
|             7 => TxPower::POS7_DBM, | ||||
|             #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] | ||||
|             6 => TxPower::POS6D_BM, | ||||
|             6 => TxPower::POS6_DBM, | ||||
|             #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] | ||||
|             5 => TxPower::POS5D_BM, | ||||
|             5 => TxPower::POS5_DBM, | ||||
|             #[cfg(not(feature = "_nrf5340-net"))] | ||||
|             4 => TxPower::POS4D_BM, | ||||
|             4 => TxPower::POS4_DBM, | ||||
|             #[cfg(not(feature = "_nrf5340-net"))] | ||||
|             3 => TxPower::POS3D_BM, | ||||
|             3 => TxPower::POS3_DBM, | ||||
|             #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] | ||||
|             2 => TxPower::POS2D_BM, | ||||
|             0 => TxPower::_0D_BM, | ||||
|             2 => TxPower::POS2_DBM, | ||||
|             0 => TxPower::_0_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -1 => TxPower::NEG1D_BM, | ||||
|             -1 => TxPower::NEG1_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -2 => TxPower::NEG2D_BM, | ||||
|             -2 => TxPower::NEG2_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -3 => TxPower::NEG3D_BM, | ||||
|             -4 => TxPower::NEG4D_BM, | ||||
|             -3 => TxPower::NEG3_DBM, | ||||
|             -4 => TxPower::NEG4_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -5 => TxPower::NEG5D_BM, | ||||
|             -5 => TxPower::NEG5_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -6 => TxPower::NEG6D_BM, | ||||
|             -6 => TxPower::NEG6_DBM, | ||||
|             #[cfg(feature = "_nrf5340-net")] | ||||
|             -7 => TxPower::NEG7D_BM, | ||||
|             -8 => TxPower::NEG8D_BM, | ||||
|             -12 => TxPower::NEG12D_BM, | ||||
|             -16 => TxPower::NEG16D_BM, | ||||
|             -20 => TxPower::NEG20D_BM, | ||||
|             -30 => TxPower::NEG30D_BM, | ||||
|             -40 => TxPower::NEG40D_BM, | ||||
|             -7 => TxPower::NEG7_DBM, | ||||
|             -8 => TxPower::NEG8_DBM, | ||||
|             -12 => TxPower::NEG12_DBM, | ||||
|             -16 => TxPower::NEG16_DBM, | ||||
|             -20 => TxPower::NEG20_DBM, | ||||
|             -30 => TxPower::NEG30_DBM, | ||||
|             -40 => TxPower::NEG40_DBM, | ||||
|             _ => panic!("Invalid transmission power value"), | ||||
|         }; | ||||
| 
 | ||||
|         r.txpower.write(|w| w.txpower().variant(tx_power)); | ||||
|         r.txpower().write(|w| w.set_txpower(tx_power)); | ||||
|     } | ||||
| 
 | ||||
|     /// Waits until the radio state matches the given `state`
 | ||||
| @ -221,7 +215,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|                 RadioState::DISABLED => return, | ||||
|                 // idle or ramping up
 | ||||
|                 RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => { | ||||
|                     r.tasks_disable.write(|w| w.tasks_disable().set_bit()); | ||||
|                     r.tasks_disable().write_value(1); | ||||
|                     self.wait_for_radio_state(RadioState::DISABLED); | ||||
|                     return; | ||||
|                 } | ||||
| @ -232,29 +226,30 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|                 } | ||||
|                 // cancel ongoing transfer or ongoing CCA
 | ||||
|                 RadioState::RX => { | ||||
|                     r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit()); | ||||
|                     r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||||
|                     r.tasks_ccastop().write_value(1); | ||||
|                     r.tasks_stop().write_value(1); | ||||
|                     self.wait_for_radio_state(RadioState::RX_IDLE); | ||||
|                 } | ||||
|                 RadioState::TX => { | ||||
|                     r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||||
|                     r.tasks_stop().write_value(1); | ||||
|                     self.wait_for_radio_state(RadioState::TX_IDLE); | ||||
|                 } | ||||
|                 _ => unreachable!(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn set_buffer(&mut self, buffer: &[u8]) { | ||||
|         let r = T::regs(); | ||||
|         r.packetptr.write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); | ||||
|         r.packetptr().write_value(buffer.as_ptr() as u32); | ||||
|     } | ||||
| 
 | ||||
|     /// Moves the radio to the RXIDLE state
 | ||||
|     fn receive_prepare(&mut self) { | ||||
|         // clear related events
 | ||||
|         T::regs().events_ccabusy.reset(); | ||||
|         T::regs().events_phyend.reset(); | ||||
|         // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
 | ||||
|         T::regs().events_ccabusy().write_value(0); | ||||
|         T::regs().events_phyend().write_value(0); | ||||
|         // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE
 | ||||
|         let disable = match self.state() { | ||||
|             RadioState::DISABLED => false, | ||||
|             RadioState::RX_IDLE => self.needs_enable, | ||||
| @ -279,7 +274,7 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         // The radio goes through following states when receiving a 802.15.4 packet
 | ||||
|         //
 | ||||
|         // enable RX → ramp up RX → RX idle → Receive → end (PHYEND)
 | ||||
|         r.shorts.write(|w| w.rxready_start().enabled()); | ||||
|         r.shorts().write(|w| w.set_rxready_start(true)); | ||||
| 
 | ||||
|         // set up RX buffer
 | ||||
|         self.set_buffer(packet.buffer.as_mut()); | ||||
| @ -289,17 +284,17 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         match self.state() { | ||||
|             // Re-start receiver
 | ||||
|             RadioState::RX_IDLE => r.tasks_start.write(|w| w.tasks_start().set_bit()), | ||||
|             RadioState::RX_IDLE => r.tasks_start().write_value(1), | ||||
|             // Enable receiver
 | ||||
|             _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), | ||||
|             _ => r.tasks_rxen().write_value(1), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Cancel receiving packet
 | ||||
|     fn receive_cancel() { | ||||
|         let r = T::regs(); | ||||
|         r.shorts.reset(); | ||||
|         r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||||
|         r.shorts().write(|_| {}); | ||||
|         r.tasks_stop().write_value(1); | ||||
|         loop { | ||||
|             match state(r) { | ||||
|                 RadioState::DISABLED | RadioState::RX_IDLE => break, | ||||
| @ -329,12 +324,12 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         core::future::poll_fn(|cx| { | ||||
|             s.event_waker.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_phyend.read().events_phyend().bit_is_set() { | ||||
|                 r.events_phyend.reset(); | ||||
|             if r.events_phyend().read() != 0 { | ||||
|                 r.events_phyend().write_value(0); | ||||
|                 trace!("RX done poll"); | ||||
|                 return Poll::Ready(()); | ||||
|             } else { | ||||
|                 r.intenset.write(|w| w.phyend().set()); | ||||
|                 r.intenset().write(|w| w.set_phyend(true)); | ||||
|             }; | ||||
| 
 | ||||
|             Poll::Pending | ||||
| @ -344,8 +339,8 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         dma_end_fence(); | ||||
|         dropper.defuse(); | ||||
| 
 | ||||
|         let crc = r.rxcrc.read().rxcrc().bits() as u16; | ||||
|         if r.crcstatus.read().crcstatus().bit_is_set() { | ||||
|         let crc = r.rxcrc().read().rxcrc() as u16; | ||||
|         if r.crcstatus().read().crcstatus() == vals::Crcstatus::CRCOK { | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(Error::CrcFailed(crc)) | ||||
| @ -387,17 +382,12 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
|         // CCA idle → enable TX → start TX → TX → end (PHYEND) → disabled
 | ||||
|         //
 | ||||
|         // CCA might end up in the event CCABUSY in which there will be no transmission
 | ||||
|         r.shorts.write(|w| { | ||||
|             w.rxready_ccastart() | ||||
|                 .enabled() | ||||
|                 .ccaidle_txen() | ||||
|                 .enabled() | ||||
|                 .txready_start() | ||||
|                 .enabled() | ||||
|                 .ccabusy_disable() | ||||
|                 .enabled() | ||||
|                 .phyend_disable() | ||||
|                 .enabled() | ||||
|         r.shorts().write(|w| { | ||||
|             w.set_rxready_ccastart(true); | ||||
|             w.set_ccaidle_txen(true); | ||||
|             w.set_txready_start(true); | ||||
|             w.set_ccabusy_disable(true); | ||||
|             w.set_phyend_disable(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Set transmission buffer
 | ||||
| @ -410,27 +400,30 @@ impl<'d, T: Instance> Radio<'d, T> { | ||||
| 
 | ||||
|         match self.state() { | ||||
|             // Re-start receiver
 | ||||
|             RadioState::RX_IDLE => r.tasks_ccastart.write(|w| w.tasks_ccastart().set_bit()), | ||||
|             RadioState::RX_IDLE => r.tasks_ccastart().write_value(1), | ||||
|             // Enable receiver
 | ||||
|             _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), | ||||
|             _ => r.tasks_rxen().write_value(1), | ||||
|         } | ||||
| 
 | ||||
|         self.clear_all_interrupts(); | ||||
|         let result = core::future::poll_fn(|cx| { | ||||
|             s.event_waker.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_phyend.read().events_phyend().bit_is_set() { | ||||
|                 r.events_phyend.reset(); | ||||
|                 r.events_ccabusy.reset(); | ||||
|             if r.events_phyend().read() != 0 { | ||||
|                 r.events_phyend().write_value(0); | ||||
|                 r.events_ccabusy().write_value(0); | ||||
|                 trace!("TX done poll"); | ||||
|                 return Poll::Ready(TransmitResult::Success); | ||||
|             } else if r.events_ccabusy.read().events_ccabusy().bit_is_set() { | ||||
|                 r.events_ccabusy.reset(); | ||||
|             } else if r.events_ccabusy().read() != 0 { | ||||
|                 r.events_ccabusy().write_value(0); | ||||
|                 trace!("TX no CCA"); | ||||
|                 return Poll::Ready(TransmitResult::ChannelInUse); | ||||
|             } | ||||
| 
 | ||||
|             r.intenset.write(|w| w.phyend().set().ccabusy().set()); | ||||
|             r.intenset().write(|w| { | ||||
|                 w.set_phyend(true); | ||||
|                 w.set_ccabusy(true); | ||||
|             }); | ||||
| 
 | ||||
|             Poll::Pending | ||||
|         }) | ||||
|  | ||||
| @ -20,8 +20,8 @@ pub mod ieee802154; | ||||
| use core::marker::PhantomData; | ||||
| 
 | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| use pac::radio::state::STATE_A as RadioState; | ||||
| pub use pac::radio::txpower::TXPOWER_A as TxPower; | ||||
| use pac::radio::vals::State as RadioState; | ||||
| pub use pac::radio::vals::Txpower as TxPower; | ||||
| 
 | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| @ -52,7 +52,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|         // clear all interrupts
 | ||||
|         r.intenclr.write(|w| w.bits(0xffff_ffff)); | ||||
|         r.intenclr().write(|w| w.0 = 0xffff_ffff); | ||||
|         s.event_waker.wake(); | ||||
|     } | ||||
| } | ||||
| @ -70,15 +70,15 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::radio::RegisterBlock; | ||||
|     fn regs() -> crate::pac::radio::Radio; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_radio { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::radio::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::radio::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> crate::pac::radio::Radio { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
| 
 | ||||
|             fn state() -> &'static crate::radio::State { | ||||
| @ -100,9 +100,6 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| } | ||||
| 
 | ||||
| /// Get the state of the radio
 | ||||
| pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState { | ||||
|     match radio.state.read().state().variant() { | ||||
|         Some(state) => state, | ||||
|         None => unreachable!(), | ||||
|     } | ||||
| pub(crate) fn state(radio: pac::radio::Radio) -> RadioState { | ||||
|     radio.state().read().state() | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::WakerRegistration; | ||||
| 
 | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::{interrupt, Peripheral}; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| /// Interrupt handler.
 | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
| @ -26,7 +26,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Clear the event.
 | ||||
|         r.events_valrdy.reset(); | ||||
|         r.events_valrdy().write_value(0); | ||||
| 
 | ||||
|         // Mutate the slice within a critical section,
 | ||||
|         // so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
 | ||||
| @ -40,7 +40,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|                 // The safety contract of `Rng::new` means that the future can't have been dropped
 | ||||
|                 // without calling its destructor.
 | ||||
|                 unsafe { | ||||
|                     *state.ptr = r.value.read().value().bits(); | ||||
|                     *state.ptr = r.value().read().value(); | ||||
|                     state.ptr = state.ptr.add(1); | ||||
|                 } | ||||
| 
 | ||||
| @ -84,19 +84,19 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
|     } | ||||
| 
 | ||||
|     fn stop(&self) { | ||||
|         T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_stop().write_value(1) | ||||
|     } | ||||
| 
 | ||||
|     fn start(&self) { | ||||
|         T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_start().write_value(1) | ||||
|     } | ||||
| 
 | ||||
|     fn enable_irq(&self) { | ||||
|         T::regs().intenset.write(|w| w.valrdy().set()); | ||||
|         T::regs().intenset().write(|w| w.set_valrdy(true)); | ||||
|     } | ||||
| 
 | ||||
|     fn disable_irq(&self) { | ||||
|         T::regs().intenclr.write(|w| w.valrdy().clear()); | ||||
|         T::regs().intenclr().write(|w| w.set_valrdy(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Enable or disable the RNG's bias correction.
 | ||||
| @ -106,7 +106,7 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
|     ///
 | ||||
|     /// Defaults to disabled.
 | ||||
|     pub fn set_bias_correction(&self, enable: bool) { | ||||
|         T::regs().config.write(|w| w.dercen().bit(enable)) | ||||
|         T::regs().config().write(|w| w.set_dercen(enable)) | ||||
|     } | ||||
| 
 | ||||
|     /// Fill the buffer with random bytes.
 | ||||
| @ -162,9 +162,9 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
| 
 | ||||
|         for byte in dest.iter_mut() { | ||||
|             let regs = T::regs(); | ||||
|             while regs.events_valrdy.read().bits() == 0 {} | ||||
|             regs.events_valrdy.reset(); | ||||
|             *byte = regs.value.read().value().bits(); | ||||
|             while regs.events_valrdy().read() == 0 {} | ||||
|             regs.events_valrdy().write_value(0); | ||||
|             *byte = regs.value().read().value(); | ||||
|         } | ||||
| 
 | ||||
|         self.stop(); | ||||
| @ -244,7 +244,7 @@ impl InnerState { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static crate::pac::rng::RegisterBlock; | ||||
|     fn regs() -> pac::rng::Rng; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -258,8 +258,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_rng { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::rng::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::rng::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> crate::pac::rng::Rng { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::rng::State { | ||||
|                 static STATE: crate::rng::State = crate::rng::State::new(); | ||||
|  | ||||
| @ -9,14 +9,10 @@ use core::task::Poll; | ||||
| use embassy_hal_internal::drop::OnDrop; | ||||
| use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| use pac::{saadc, SAADC}; | ||||
| use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A}; | ||||
| // We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same
 | ||||
| pub(crate) use saadc::ch::pselp::PSELP_A as InputChannel; | ||||
| use saadc::oversample::OVERSAMPLE_A; | ||||
| use saadc::resolution::VAL_A; | ||||
| pub(crate) use vals::Psel as InputChannel; | ||||
| 
 | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::pac::saadc::vals; | ||||
| use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | ||||
| use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||||
| use crate::{interrupt, pac, peripherals, Peripheral}; | ||||
| @ -34,20 +30,20 @@ pub struct InterruptHandler { | ||||
| 
 | ||||
| impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = unsafe { &*SAADC::ptr() }; | ||||
|         let r = pac::SAADC; | ||||
| 
 | ||||
|         if r.events_calibratedone.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.calibratedone().clear()); | ||||
|         if r.events_calibratedone().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_calibratedone(true)); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         if r.events_end().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.started().clear()); | ||||
|         if r.events_started().read() != 0 { | ||||
|             r.intenclr().write(|w| w.set_started(true)); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
| @ -150,44 +146,36 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|     ) -> Self { | ||||
|         into_ref!(saadc); | ||||
| 
 | ||||
|         let r = unsafe { &*SAADC::ptr() }; | ||||
|         let r = pac::SAADC; | ||||
| 
 | ||||
|         let Config { resolution, oversample } = config; | ||||
| 
 | ||||
|         // Configure channels
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.resolution.write(|w| w.val().variant(resolution.into())); | ||||
|         r.oversample.write(|w| w.oversample().variant(oversample.into())); | ||||
|         r.enable().write(|w| w.set_enable(true)); | ||||
|         r.resolution().write(|w| w.set_val(resolution.into())); | ||||
|         r.oversample().write(|w| w.set_oversample(oversample.into())); | ||||
| 
 | ||||
|         for (i, cc) in channel_configs.iter().enumerate() { | ||||
|             r.ch[i].pselp.write(|w| w.pselp().variant(cc.p_channel.channel())); | ||||
|             r.ch(i).pselp().write(|w| w.set_pselp(cc.p_channel.channel())); | ||||
|             if let Some(n_channel) = &cc.n_channel { | ||||
|                 r.ch[i] | ||||
|                     .pseln | ||||
|                     .write(|w| unsafe { w.pseln().bits(n_channel.channel() as u8) }); | ||||
|                 r.ch(i).pseln().write(|w| w.set_pseln(n_channel.channel())); | ||||
|             } | ||||
|             r.ch[i].config.write(|w| { | ||||
|                 w.refsel().variant(cc.reference.into()); | ||||
|                 w.gain().variant(cc.gain.into()); | ||||
|                 w.tacq().variant(cc.time.into()); | ||||
|                 if cc.n_channel.is_none() { | ||||
|                     w.mode().se(); | ||||
|                 } else { | ||||
|                     w.mode().diff(); | ||||
|                 } | ||||
|                 w.resp().variant(cc.resistor.into()); | ||||
|                 w.resn().bypass(); | ||||
|                 if !matches!(oversample, Oversample::BYPASS) { | ||||
|                     w.burst().enabled(); | ||||
|                 } else { | ||||
|                     w.burst().disabled(); | ||||
|                 } | ||||
|                 w | ||||
|             r.ch(i).config().write(|w| { | ||||
|                 w.set_refsel(cc.reference.into()); | ||||
|                 w.set_gain(cc.gain.into()); | ||||
|                 w.set_tacq(cc.time.into()); | ||||
|                 w.set_mode(match cc.n_channel { | ||||
|                     None => vals::ConfigMode::SE, | ||||
|                     Some(_) => vals::ConfigMode::DIFF, | ||||
|                 }); | ||||
|                 w.set_resp(cc.resistor.into()); | ||||
|                 w.set_resn(vals::Resn::BYPASS); | ||||
|                 w.set_burst(!matches!(oversample, Oversample::BYPASS)); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0x003F_FFFF); | ||||
| 
 | ||||
|         interrupt::SAADC.unpend(); | ||||
|         unsafe { interrupt::SAADC.enable() }; | ||||
| @ -195,8 +183,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         Self { _p: saadc } | ||||
|     } | ||||
| 
 | ||||
|     fn regs() -> &'static saadc::RegisterBlock { | ||||
|         unsafe { &*SAADC::ptr() } | ||||
|     fn regs() -> pac::saadc::Saadc { | ||||
|         pac::SAADC | ||||
|     } | ||||
| 
 | ||||
|     /// Perform SAADC calibration. Completes when done.
 | ||||
| @ -204,13 +192,13 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         let r = Self::regs(); | ||||
| 
 | ||||
|         // Reset and enable the end event
 | ||||
|         r.events_calibratedone.reset(); | ||||
|         r.intenset.write(|w| w.calibratedone().set()); | ||||
|         r.events_calibratedone().write_value(0); | ||||
|         r.intenset().write(|w| w.set_calibratedone(true)); | ||||
| 
 | ||||
|         // Order is important
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_calibrateoffset().write_value(1); | ||||
| 
 | ||||
|         // Wait for 'calibratedone' event.
 | ||||
|         poll_fn(|cx| { | ||||
| @ -218,8 +206,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
| 
 | ||||
|             WAKER.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_calibratedone.read().bits() != 0 { | ||||
|                 r.events_calibratedone.reset(); | ||||
|             if r.events_calibratedone().read() != 0 { | ||||
|                 r.events_calibratedone().write_value(0); | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| 
 | ||||
| @ -239,19 +227,19 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         let r = Self::regs(); | ||||
| 
 | ||||
|         // Set up the DMA
 | ||||
|         r.result.ptr.write(|w| unsafe { w.ptr().bits(buf.as_mut_ptr() as u32) }); | ||||
|         r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(N as _) }); | ||||
|         r.result().ptr().write_value(buf.as_mut_ptr() as u32); | ||||
|         r.result().maxcnt().write(|w| w.set_maxcnt(N as _)); | ||||
| 
 | ||||
|         // Reset and enable the end event
 | ||||
|         r.events_end.reset(); | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
|         r.events_end().write_value(0); | ||||
|         r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|         // Don't reorder the ADC start event before the previous writes. Hopefully self
 | ||||
|         // wouldn't happen anyway.
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_sample.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start().write_value(1); | ||||
|         r.tasks_sample().write_value(1); | ||||
| 
 | ||||
|         // Wait for 'end' event.
 | ||||
|         poll_fn(|cx| { | ||||
| @ -259,8 +247,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
| 
 | ||||
|             WAKER.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|                 r.events_end.reset(); | ||||
|             if r.events_end().read() != 0 { | ||||
|                 r.events_end().write_value(0); | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| 
 | ||||
| @ -311,8 +299,11 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         // We want the task start to effectively short with the last one ending so
 | ||||
|         // we don't miss any samples. It'd be great for the SAADC to offer a SHORTS
 | ||||
|         // register instead, but it doesn't, so we must use PPI.
 | ||||
|         let mut start_ppi = | ||||
|             Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_end), Task::from_reg(&r.tasks_start)); | ||||
|         let mut start_ppi = Ppi::new_one_to_one( | ||||
|             ppi_ch1, | ||||
|             Event::from_reg(r.events_end()), | ||||
|             Task::from_reg(r.tasks_start()), | ||||
|         ); | ||||
|         start_ppi.enable(); | ||||
| 
 | ||||
|         let timer = Timer::new(timer); | ||||
| @ -322,7 +313,7 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
| 
 | ||||
|         let timer_cc = timer.cc(0); | ||||
| 
 | ||||
|         let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample)); | ||||
|         let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(r.tasks_sample())); | ||||
| 
 | ||||
|         timer.start(); | ||||
| 
 | ||||
| @ -355,43 +346,37 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         // Establish mode and sample rate
 | ||||
|         match sample_rate_divisor { | ||||
|             Some(sr) => { | ||||
|                 r.samplerate.write(|w| unsafe { | ||||
|                     w.cc().bits(sr); | ||||
|                     w.mode().timers(); | ||||
|                     w | ||||
|                 r.samplerate().write(|w| { | ||||
|                     w.set_cc(sr); | ||||
|                     w.set_mode(vals::SamplerateMode::TIMERS); | ||||
|                 }); | ||||
|                 r.tasks_sample.write(|w| unsafe { w.bits(1) }); // Need to kick-start the internal timer
 | ||||
|                 r.tasks_sample().write_value(1); // Need to kick-start the internal timer
 | ||||
|             } | ||||
|             None => r.samplerate.write(|w| unsafe { | ||||
|                 w.cc().bits(0); | ||||
|                 w.mode().task(); | ||||
|                 w | ||||
|             None => r.samplerate().write(|w| { | ||||
|                 w.set_cc(0); | ||||
|                 w.set_mode(vals::SamplerateMode::TASK); | ||||
|             }), | ||||
|         } | ||||
| 
 | ||||
|         // Set up the initial DMA
 | ||||
|         r.result | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.ptr().bits(bufs[0].as_mut_ptr() as u32) }); | ||||
|         r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits((N0 * N) as _) }); | ||||
|         r.result().ptr().write_value(bufs[0].as_mut_ptr() as u32); | ||||
|         r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N) as _)); | ||||
| 
 | ||||
|         // Reset and enable the events
 | ||||
|         r.events_end.reset(); | ||||
|         r.events_started.reset(); | ||||
|         r.intenset.write(|w| { | ||||
|             w.end().set(); | ||||
|             w.started().set(); | ||||
|             w | ||||
|         r.events_end().write_value(0); | ||||
|         r.events_started().write_value(0); | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_end(true); | ||||
|             w.set_started(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Don't reorder the ADC start event before the previous writes. Hopefully self
 | ||||
|         // wouldn't happen anyway.
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start().write_value(1); | ||||
| 
 | ||||
|         let mut inited = false; | ||||
| 
 | ||||
|         let mut current_buffer = 0; | ||||
| 
 | ||||
|         // Wait for events and complete when the sampler indicates it has had enough.
 | ||||
| @ -400,11 +385,11 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
| 
 | ||||
|             WAKER.register(cx.waker()); | ||||
| 
 | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|             if r.events_end().read() != 0 { | ||||
|                 compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|                 r.events_end.reset(); | ||||
|                 r.intenset.write(|w| w.end().set()); | ||||
|                 r.events_end().write_value(0); | ||||
|                 r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|                 match callback(&bufs[current_buffer]) { | ||||
|                     CallbackResult::Continue => { | ||||
| @ -417,9 +402,9 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if r.events_started.read().bits() != 0 { | ||||
|                 r.events_started.reset(); | ||||
|                 r.intenset.write(|w| w.started().set()); | ||||
|             if r.events_started().read() != 0 { | ||||
|                 r.events_started().write_value(0); | ||||
|                 r.intenset().write(|w| w.set_started(true)); | ||||
| 
 | ||||
|                 if !inited { | ||||
|                     init(); | ||||
| @ -427,9 +412,7 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|                 } | ||||
| 
 | ||||
|                 let next_buffer = 1 - current_buffer; | ||||
|                 r.result | ||||
|                     .ptr | ||||
|                     .write(|w| unsafe { w.ptr().bits(bufs[next_buffer].as_mut_ptr() as u32) }); | ||||
|                 r.result().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32); | ||||
|             } | ||||
| 
 | ||||
|             Poll::Pending | ||||
| @ -447,11 +430,11 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.events_stopped.reset(); | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.tasks_stop().write_value(1); | ||||
| 
 | ||||
|         while r.events_stopped.read().bits() == 0 {} | ||||
|         r.events_stopped.reset(); | ||||
|         while r.events_stopped().read() == 0 {} | ||||
|         r.events_stopped().write_value(0); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -481,21 +464,21 @@ impl<'d> Saadc<'d, 1> { | ||||
| impl<'d, const N: usize> Drop for Saadc<'d, N> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = Self::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(false)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<Gain> for GAIN_A { | ||||
| impl From<Gain> for vals::Gain { | ||||
|     fn from(gain: Gain) -> Self { | ||||
|         match gain { | ||||
|             Gain::GAIN1_6 => GAIN_A::GAIN1_6, | ||||
|             Gain::GAIN1_5 => GAIN_A::GAIN1_5, | ||||
|             Gain::GAIN1_4 => GAIN_A::GAIN1_4, | ||||
|             Gain::GAIN1_3 => GAIN_A::GAIN1_3, | ||||
|             Gain::GAIN1_2 => GAIN_A::GAIN1_2, | ||||
|             Gain::GAIN1 => GAIN_A::GAIN1, | ||||
|             Gain::GAIN2 => GAIN_A::GAIN2, | ||||
|             Gain::GAIN4 => GAIN_A::GAIN4, | ||||
|             Gain::GAIN1_6 => vals::Gain::GAIN1_6, | ||||
|             Gain::GAIN1_5 => vals::Gain::GAIN1_5, | ||||
|             Gain::GAIN1_4 => vals::Gain::GAIN1_4, | ||||
|             Gain::GAIN1_3 => vals::Gain::GAIN1_3, | ||||
|             Gain::GAIN1_2 => vals::Gain::GAIN1_2, | ||||
|             Gain::GAIN1 => vals::Gain::GAIN1, | ||||
|             Gain::GAIN2 => vals::Gain::GAIN2, | ||||
|             Gain::GAIN4 => vals::Gain::GAIN4, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -522,11 +505,11 @@ pub enum Gain { | ||||
|     GAIN4 = 7, | ||||
| } | ||||
| 
 | ||||
| impl From<Reference> for REFSEL_A { | ||||
| impl From<Reference> for vals::Refsel { | ||||
|     fn from(reference: Reference) -> Self { | ||||
|         match reference { | ||||
|             Reference::INTERNAL => REFSEL_A::INTERNAL, | ||||
|             Reference::VDD1_4 => REFSEL_A::VDD1_4, | ||||
|             Reference::INTERNAL => vals::Refsel::INTERNAL, | ||||
|             Reference::VDD1_4 => vals::Refsel::VDD1_4, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -541,13 +524,13 @@ pub enum Reference { | ||||
|     VDD1_4 = 1, | ||||
| } | ||||
| 
 | ||||
| impl From<Resistor> for RESP_A { | ||||
| impl From<Resistor> for vals::Resp { | ||||
|     fn from(resistor: Resistor) -> Self { | ||||
|         match resistor { | ||||
|             Resistor::BYPASS => RESP_A::BYPASS, | ||||
|             Resistor::PULLDOWN => RESP_A::PULLDOWN, | ||||
|             Resistor::PULLUP => RESP_A::PULLUP, | ||||
|             Resistor::VDD1_2 => RESP_A::VDD1_2, | ||||
|             Resistor::BYPASS => vals::Resp::BYPASS, | ||||
|             Resistor::PULLDOWN => vals::Resp::PULLDOWN, | ||||
|             Resistor::PULLUP => vals::Resp::PULLUP, | ||||
|             Resistor::VDD1_2 => vals::Resp::VDD1_2, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -566,15 +549,15 @@ pub enum Resistor { | ||||
|     VDD1_2 = 3, | ||||
| } | ||||
| 
 | ||||
| impl From<Time> for TACQ_A { | ||||
| impl From<Time> for vals::Tacq { | ||||
|     fn from(time: Time) -> Self { | ||||
|         match time { | ||||
|             Time::_3US => TACQ_A::_3US, | ||||
|             Time::_5US => TACQ_A::_5US, | ||||
|             Time::_10US => TACQ_A::_10US, | ||||
|             Time::_15US => TACQ_A::_15US, | ||||
|             Time::_20US => TACQ_A::_20US, | ||||
|             Time::_40US => TACQ_A::_40US, | ||||
|             Time::_3US => vals::Tacq::_3US, | ||||
|             Time::_5US => vals::Tacq::_5US, | ||||
|             Time::_10US => vals::Tacq::_10US, | ||||
|             Time::_15US => vals::Tacq::_15US, | ||||
|             Time::_20US => vals::Tacq::_20US, | ||||
|             Time::_40US => vals::Tacq::_40US, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -597,18 +580,18 @@ pub enum Time { | ||||
|     _40US = 5, | ||||
| } | ||||
| 
 | ||||
| impl From<Oversample> for OVERSAMPLE_A { | ||||
| impl From<Oversample> for vals::Oversample { | ||||
|     fn from(oversample: Oversample) -> Self { | ||||
|         match oversample { | ||||
|             Oversample::BYPASS => OVERSAMPLE_A::BYPASS, | ||||
|             Oversample::OVER2X => OVERSAMPLE_A::OVER2X, | ||||
|             Oversample::OVER4X => OVERSAMPLE_A::OVER4X, | ||||
|             Oversample::OVER8X => OVERSAMPLE_A::OVER8X, | ||||
|             Oversample::OVER16X => OVERSAMPLE_A::OVER16X, | ||||
|             Oversample::OVER32X => OVERSAMPLE_A::OVER32X, | ||||
|             Oversample::OVER64X => OVERSAMPLE_A::OVER64X, | ||||
|             Oversample::OVER128X => OVERSAMPLE_A::OVER128X, | ||||
|             Oversample::OVER256X => OVERSAMPLE_A::OVER256X, | ||||
|             Oversample::BYPASS => vals::Oversample::BYPASS, | ||||
|             Oversample::OVER2X => vals::Oversample::OVER2X, | ||||
|             Oversample::OVER4X => vals::Oversample::OVER4X, | ||||
|             Oversample::OVER8X => vals::Oversample::OVER8X, | ||||
|             Oversample::OVER16X => vals::Oversample::OVER16X, | ||||
|             Oversample::OVER32X => vals::Oversample::OVER32X, | ||||
|             Oversample::OVER64X => vals::Oversample::OVER64X, | ||||
|             Oversample::OVER128X => vals::Oversample::OVER128X, | ||||
|             Oversample::OVER256X => vals::Oversample::OVER256X, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -637,13 +620,13 @@ pub enum Oversample { | ||||
|     OVER256X = 8, | ||||
| } | ||||
| 
 | ||||
| impl From<Resolution> for VAL_A { | ||||
| impl From<Resolution> for vals::Val { | ||||
|     fn from(resolution: Resolution) -> Self { | ||||
|         match resolution { | ||||
|             Resolution::_8BIT => VAL_A::_8BIT, | ||||
|             Resolution::_10BIT => VAL_A::_10BIT, | ||||
|             Resolution::_12BIT => VAL_A::_12BIT, | ||||
|             Resolution::_14BIT => VAL_A::_14BIT, | ||||
|             Resolution::_8BIT => vals::Val::_8BIT, | ||||
|             Resolution::_10BIT => vals::Val::_10BIT, | ||||
|             Resolution::_12BIT => vals::Val::_12BIT, | ||||
|             Resolution::_14BIT => vals::Val::_14BIT, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -726,7 +709,7 @@ impl_peripheral!(VddInput); | ||||
| #[cfg(not(feature = "_nrf91"))] | ||||
| impl_saadc_input!(@local, VddInput, VDD); | ||||
| #[cfg(feature = "_nrf91")] | ||||
| impl_saadc_input!(@local, VddInput, VDDGPIO); | ||||
| impl_saadc_input!(@local, VddInput, VDD_GPIO); | ||||
| 
 | ||||
| /// A dummy `Input` pin implementation for SAADC peripheral sampling from the
 | ||||
| /// VDDH / 5 voltage.
 | ||||
|  | ||||
| @ -13,12 +13,13 @@ use embassy_embedded_hal::SetConfig; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||||
| pub use pac::spim0::config::ORDER_A as BitOrder; | ||||
| pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | ||||
| pub use pac::spim::vals::{Frequency, Order as BitOrder}; | ||||
| 
 | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::spim::vals; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| @ -33,6 +34,7 @@ pub enum Error { | ||||
| 
 | ||||
| /// SPIM configuration.
 | ||||
| #[non_exhaustive] | ||||
| #[derive(Clone)] | ||||
| pub struct Config { | ||||
|     /// Frequency
 | ||||
|     pub frequency: Frequency, | ||||
| @ -54,9 +56,6 @@ pub struct Config { | ||||
| 
 | ||||
|     /// Drive strength for the MOSI line.
 | ||||
|     pub mosi_drive: OutputDrive, | ||||
| 
 | ||||
|     /// Drive strength for the MISO line.
 | ||||
|     pub miso_drive: OutputDrive, | ||||
| } | ||||
| 
 | ||||
| impl Default for Config { | ||||
| @ -68,7 +67,6 @@ impl Default for Config { | ||||
|             orc: 0x00, | ||||
|             sck_drive: OutputDrive::HighDrive, | ||||
|             mosi_drive: OutputDrive::HighDrive, | ||||
|             miso_drive: OutputDrive::HighDrive, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -87,15 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         { | ||||
|             // Ideally we should call this only during the first chunk transfer,
 | ||||
|             // but so far calling this every time doesn't seem to be causing any issues.
 | ||||
|             if r.events_started.read().bits() != 0 { | ||||
|             if r.events_started().read() != 0 { | ||||
|                 s.waker.wake(); | ||||
|                 r.intenclr.write(|w| w.started().clear()); | ||||
|                 r.intenclr().write(|w| w.set_started(true)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|         if r.events_end().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -173,16 +171,19 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
| 
 | ||||
|         // Configure pins
 | ||||
|         if let Some(sck) = &sck { | ||||
|             sck.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.sck_drive))); | ||||
|             sck.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.sck_drive)) | ||||
|             }); | ||||
|         } | ||||
|         if let Some(mosi) = &mosi { | ||||
|             mosi.conf() | ||||
|                 .write(|w| w.dir().output().drive().variant(convert_drive(config.mosi_drive))); | ||||
|             mosi.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.mosi_drive)) | ||||
|             }); | ||||
|         } | ||||
|         if let Some(miso) = &miso { | ||||
|             miso.conf() | ||||
|                 .write(|w| w.input().connect().drive().variant(convert_drive(config.miso_drive))); | ||||
|             miso.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); | ||||
|         } | ||||
| 
 | ||||
|         match config.mode.polarity { | ||||
| @ -205,12 +206,12 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         } | ||||
| 
 | ||||
|         // Select pins.
 | ||||
|         r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); | ||||
|         r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); | ||||
|         r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); | ||||
|         r.psel().sck().write_value(sck.psel_bits()); | ||||
|         r.psel().mosi().write_value(mosi.psel_bits()); | ||||
|         r.psel().miso().write_value(miso.psel_bits()); | ||||
| 
 | ||||
|         // Enable SPIM instance.
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let mut spim = Self { _p: spim }; | ||||
| 
 | ||||
| @ -218,7 +219,7 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         Self::set_config(&mut spim, &config).unwrap(); | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @ -241,13 +242,13 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
| 
 | ||||
|         // Set up the DMA read.
 | ||||
|         let (rx_ptr, rx_len) = xfer_params(rx as *mut u8 as _, rx.len() as _, offset, length); | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx_ptr) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); | ||||
|         r.rxd().ptr().write_value(rx_ptr); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(rx_len as _)); | ||||
| 
 | ||||
|         // Set up the DMA write.
 | ||||
|         let (tx_ptr, tx_len) = xfer_params(tx as *const u8 as _, tx.len() as _, offset, length); | ||||
|         r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx_ptr) }); | ||||
|         r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); | ||||
|         r.txd().ptr().write_value(tx_ptr); | ||||
|         r.txd().maxcnt().write(|w| w.set_maxcnt(tx_len as _)); | ||||
| 
 | ||||
|         /* | ||||
|         trace!("XFER: offset: {}, length: {}", offset, length); | ||||
| @ -259,26 +260,26 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         if offset == 0 { | ||||
|             let s = T::state(); | ||||
| 
 | ||||
|             r.events_started.reset(); | ||||
|             r.events_started().write_value(0); | ||||
| 
 | ||||
|             // Set rx/tx buffer lengths to 0...
 | ||||
|             r.txd.maxcnt.reset(); | ||||
|             r.rxd.maxcnt.reset(); | ||||
|             r.txd().maxcnt().write(|_| ()); | ||||
|             r.rxd().maxcnt().write(|_| ()); | ||||
| 
 | ||||
|             // ...and keep track of original buffer lengths...
 | ||||
|             s.tx.store(tx_len as _, Ordering::Relaxed); | ||||
|             s.rx.store(rx_len as _, Ordering::Relaxed); | ||||
| 
 | ||||
|             // ...signalling the start of the fake transfer.
 | ||||
|             r.intenset.write(|w| w.started().bit(true)); | ||||
|             r.intenset().write(|w| w.set_started(true)); | ||||
|         } | ||||
| 
 | ||||
|         // Reset and enable the event
 | ||||
|         r.events_end.reset(); | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
|         r.events_end().write_value(0); | ||||
|         r.intenset().write(|w| w.set_end(true)); | ||||
| 
 | ||||
|         // Start SPI transaction.
 | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     fn blocking_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { | ||||
| @ -290,7 +291,7 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         } | ||||
| 
 | ||||
|         // Wait for 'end' event.
 | ||||
|         while T::regs().events_end.read().bits() == 0 {} | ||||
|         while T::regs().events_end().read() == 0 {} | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|     } | ||||
| @ -338,7 +339,7 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         // Wait for 'end' event.
 | ||||
|         poll_fn(|cx| { | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if T::regs().events_end.read().bits() != 0 { | ||||
|             if T::regs().events_end().read() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| 
 | ||||
| @ -442,24 +443,20 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|     #[cfg(feature = "_nrf52832_anomaly_109")] | ||||
|     fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { | ||||
|         let r = T::regs(); | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|         if r.events_started().read() != 0 { | ||||
|             let s = T::state(); | ||||
| 
 | ||||
|             // Handle the first "fake" transmission
 | ||||
|             r.events_started.reset(); | ||||
|             r.events_end.reset(); | ||||
|             r.events_started().write_value(0); | ||||
|             r.events_end().write_value(0); | ||||
| 
 | ||||
|             // Update DMA registers with correct rx/tx buffer sizes
 | ||||
|             r.rxd | ||||
|                 .maxcnt | ||||
|                 .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); | ||||
|             r.txd | ||||
|                 .maxcnt | ||||
|                 .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); | ||||
|             r.rxd().maxcnt().write(|w| w.set_maxcnt(s.rx.load(Ordering::Relaxed))); | ||||
|             r.txd().maxcnt().write(|w| w.set_maxcnt(s.tx.load(Ordering::Relaxed))); | ||||
| 
 | ||||
|             r.intenset.write(|w| w.end().set()); | ||||
|             r.intenset().write(|w| w.set_end(true)); | ||||
|             // ... and start actual, hopefully glitch-free transmission
 | ||||
|             r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_start().write_value(1); | ||||
|             return Poll::Ready(()); | ||||
|         } | ||||
|         Poll::Pending | ||||
| @ -474,11 +471,11 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { | ||||
| 
 | ||||
|         // disable!
 | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
| 
 | ||||
|         gpio::deconfigure_pin(r.psel.sck.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.miso.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.mosi.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().sck().read()); | ||||
|         gpio::deconfigure_pin(r.psel().miso().read()); | ||||
|         gpio::deconfigure_pin(r.psel().mosi().read()); | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         T::Interrupt::disable(); | ||||
| @ -508,7 +505,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::spim0::RegisterBlock; | ||||
|     fn regs() -> pac::spim::Spim; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -522,8 +519,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static { | ||||
| macro_rules! impl_spim { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::spim::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::spim0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::spim::Spim { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::spim::State { | ||||
|                 static STATE: crate::spim::State = crate::spim::State::new(); | ||||
| @ -621,40 +618,35 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         // Configure mode.
 | ||||
|         let mode = config.mode; | ||||
|         r.config.write(|w| { | ||||
|         r.config().write(|w| { | ||||
|             w.set_order(config.bit_order); | ||||
|             match mode { | ||||
|                 MODE_0 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_high(); | ||||
|                     w.cpha().leading(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_HIGH); | ||||
|                     w.set_cpha(vals::Cpha::LEADING); | ||||
|                 } | ||||
|                 MODE_1 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_high(); | ||||
|                     w.cpha().trailing(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_HIGH); | ||||
|                     w.set_cpha(vals::Cpha::TRAILING); | ||||
|                 } | ||||
|                 MODE_2 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_low(); | ||||
|                     w.cpha().leading(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_LOW); | ||||
|                     w.set_cpha(vals::Cpha::LEADING); | ||||
|                 } | ||||
|                 MODE_3 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_low(); | ||||
|                     w.cpha().trailing(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_LOW); | ||||
|                     w.set_cpha(vals::Cpha::TRAILING); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             w | ||||
|         }); | ||||
| 
 | ||||
|         // Configure frequency.
 | ||||
|         let frequency = config.frequency; | ||||
|         r.frequency.write(|w| w.frequency().variant(frequency)); | ||||
|         r.frequency().write(|w| w.set_frequency(frequency)); | ||||
| 
 | ||||
|         // Set over-read character
 | ||||
|         let orc = config.orc; | ||||
|         r.orc.write(|w| unsafe { w.orc().bits(orc) }); | ||||
|         r.orc().write(|w| w.set_orc(orc)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -10,11 +10,13 @@ use embassy_embedded_hal::SetConfig; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||||
| pub use pac::spis0::config::ORDER_A as BitOrder; | ||||
| pub use pac::spis::vals::Order as BitOrder; | ||||
| 
 | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, SealedPin as _}; | ||||
| use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::spis::vals; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| @ -54,6 +56,9 @@ pub struct Config { | ||||
| 
 | ||||
|     /// Automatically make the firmware side acquire the semaphore on transfer end.
 | ||||
|     pub auto_acquire: bool, | ||||
| 
 | ||||
|     /// Drive strength for the MISO line.
 | ||||
|     pub miso_drive: OutputDrive, | ||||
| } | ||||
| 
 | ||||
| impl Default for Config { | ||||
| @ -64,6 +69,7 @@ impl Default for Config { | ||||
|             orc: 0x00, | ||||
|             def: 0x00, | ||||
|             auto_acquire: true, | ||||
|             miso_drive: OutputDrive::HighDrive, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -78,14 +84,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|         if r.events_end().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             r.intenclr().write(|w| w.set_end(true)); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_acquired.read().bits() != 0 { | ||||
|         if r.events_acquired().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.acquired().clear()); | ||||
|             r.intenclr().write(|w| w.set_acquired(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -184,23 +190,26 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Configure pins.
 | ||||
|         cs.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) }); | ||||
|         cs.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); | ||||
|         r.psel().csn().write_value(cs.psel_bits()); | ||||
|         if let Some(sck) = &sck { | ||||
|             sck.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|             r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); | ||||
|             sck.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); | ||||
|             r.psel().sck().write_value(sck.psel_bits()); | ||||
|         } | ||||
|         if let Some(mosi) = &mosi { | ||||
|             mosi.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|             r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); | ||||
|             mosi.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); | ||||
|             r.psel().mosi().write_value(mosi.psel_bits()); | ||||
|         } | ||||
|         if let Some(miso) = &miso { | ||||
|             miso.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|             r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); | ||||
|             miso.conf().write(|w| { | ||||
|                 w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|                 w.set_drive(convert_drive(config.miso_drive)) | ||||
|             }); | ||||
|             r.psel().miso().write_value(miso.psel_bits()); | ||||
|         } | ||||
| 
 | ||||
|         // Enable SPIS instance.
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let mut spis = Self { _p: spis }; | ||||
| 
 | ||||
| @ -208,7 +217,7 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         Self::set_config(&mut spis, &config).unwrap(); | ||||
| 
 | ||||
|         // Disable all events interrupts.
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @ -229,21 +238,21 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         if tx.len() > EASY_DMA_SIZE { | ||||
|             return Err(Error::TxBufferTooLong); | ||||
|         } | ||||
|         r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx as *const u8 as _) }); | ||||
|         r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); | ||||
|         r.txd().ptr().write_value(tx as *const u8 as _); | ||||
|         r.txd().maxcnt().write(|w| w.set_maxcnt(tx.len() as _)); | ||||
| 
 | ||||
|         // Set up the DMA read.
 | ||||
|         if rx.len() > EASY_DMA_SIZE { | ||||
|             return Err(Error::RxBufferTooLong); | ||||
|         } | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx as *mut u8 as _) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); | ||||
|         r.rxd().ptr().write_value(rx as *mut u8 as _); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(rx.len() as _)); | ||||
| 
 | ||||
|         // Reset end event.
 | ||||
|         r.events_end.reset(); | ||||
|         r.events_end().write_value(0); | ||||
| 
 | ||||
|         // Release the semaphore.
 | ||||
|         r.tasks_release.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_release().write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -253,20 +262,20 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Acquire semaphore.
 | ||||
|         if r.semstat.read().bits() != 1 { | ||||
|             r.events_acquired.reset(); | ||||
|             r.tasks_acquire.write(|w| unsafe { w.bits(1) }); | ||||
|         if r.semstat().read().0 != 1 { | ||||
|             r.events_acquired().write_value(0); | ||||
|             r.tasks_acquire().write_value(1); | ||||
|             // Wait until CPU has acquired the semaphore.
 | ||||
|             while r.semstat.read().bits() != 1 {} | ||||
|             while r.semstat().read().0 != 1 {} | ||||
|         } | ||||
| 
 | ||||
|         self.prepare(rx, tx)?; | ||||
| 
 | ||||
|         // Wait for 'end' event.
 | ||||
|         while r.events_end.read().bits() == 0 {} | ||||
|         while r.events_end().read() == 0 {} | ||||
| 
 | ||||
|         let n_rx = r.rxd.amount.read().bits() as usize; | ||||
|         let n_tx = r.txd.amount.read().bits() as usize; | ||||
|         let n_rx = r.rxd().amount().read().0 as usize; | ||||
|         let n_tx = r.txd().amount().read().0 as usize; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
| @ -291,22 +300,25 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         // Clear status register.
 | ||||
|         r.status.write(|w| w.overflow().clear().overread().clear()); | ||||
|         r.status().write(|w| { | ||||
|             w.set_overflow(true); | ||||
|             w.set_overread(true); | ||||
|         }); | ||||
| 
 | ||||
|         // Acquire semaphore.
 | ||||
|         if r.semstat.read().bits() != 1 { | ||||
|         if r.semstat().read().0 != 1 { | ||||
|             // Reset and enable the acquire event.
 | ||||
|             r.events_acquired.reset(); | ||||
|             r.intenset.write(|w| w.acquired().set()); | ||||
|             r.events_acquired().write_value(0); | ||||
|             r.intenset().write(|w| w.set_acquired(true)); | ||||
| 
 | ||||
|             // Request acquiring the SPIS semaphore.
 | ||||
|             r.tasks_acquire.write(|w| unsafe { w.bits(1) }); | ||||
|             r.tasks_acquire().write_value(1); | ||||
| 
 | ||||
|             // Wait until CPU has acquired the semaphore.
 | ||||
|             poll_fn(|cx| { | ||||
|                 s.waker.register(cx.waker()); | ||||
|                 if r.events_acquired.read().bits() == 1 { | ||||
|                     r.events_acquired.reset(); | ||||
|                 if r.events_acquired().read() == 1 { | ||||
|                     r.events_acquired().write_value(0); | ||||
|                     return Poll::Ready(()); | ||||
|                 } | ||||
|                 Poll::Pending | ||||
| @ -317,19 +329,19 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         self.prepare(rx, tx)?; | ||||
| 
 | ||||
|         // Wait for 'end' event.
 | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
|         r.intenset().write(|w| w.set_end(true)); | ||||
|         poll_fn(|cx| { | ||||
|             s.waker.register(cx.waker()); | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|                 r.events_end.reset(); | ||||
|             if r.events_end().read() != 0 { | ||||
|                 r.events_end().write_value(0); | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
|             Poll::Pending | ||||
|         }) | ||||
|         .await; | ||||
| 
 | ||||
|         let n_rx = r.rxd.amount.read().bits() as usize; | ||||
|         let n_tx = r.txd.amount.read().bits() as usize; | ||||
|         let n_rx = r.rxd().amount().read().0 as usize; | ||||
|         let n_tx = r.txd().amount().read().0 as usize; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
| @ -428,12 +440,12 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
| 
 | ||||
|     /// Checks if last transaction overread.
 | ||||
|     pub fn is_overread(&mut self) -> bool { | ||||
|         T::regs().status.read().overread().is_present() | ||||
|         T::regs().status().read().overread() | ||||
|     } | ||||
| 
 | ||||
|     /// Checks if last transaction overflowed.
 | ||||
|     pub fn is_overflow(&mut self) -> bool { | ||||
|         T::regs().status.read().overflow().is_present() | ||||
|         T::regs().status().read().overflow() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -443,12 +455,12 @@ impl<'d, T: Instance> Drop for Spis<'d, T> { | ||||
| 
 | ||||
|         // Disable
 | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
| 
 | ||||
|         gpio::deconfigure_pin(r.psel.sck.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.csn.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.miso.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.mosi.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().sck().read()); | ||||
|         gpio::deconfigure_pin(r.psel().csn().read()); | ||||
|         gpio::deconfigure_pin(r.psel().miso().read()); | ||||
|         gpio::deconfigure_pin(r.psel().mosi().read()); | ||||
| 
 | ||||
|         trace!("spis drop: done"); | ||||
|     } | ||||
| @ -467,7 +479,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::spis0::RegisterBlock; | ||||
|     fn regs() -> pac::spis::Spis; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -481,8 +493,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static { | ||||
| macro_rules! impl_spis { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::spis::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::spis0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::spis::Spis { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::spis::State { | ||||
|                 static STATE: crate::spis::State = crate::spis::State::new(); | ||||
| @ -504,44 +516,39 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         // Configure mode.
 | ||||
|         let mode = config.mode; | ||||
|         r.config.write(|w| { | ||||
|         r.config().write(|w| { | ||||
|             w.set_order(config.bit_order); | ||||
|             match mode { | ||||
|                 MODE_0 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_high(); | ||||
|                     w.cpha().leading(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_HIGH); | ||||
|                     w.set_cpha(vals::Cpha::LEADING); | ||||
|                 } | ||||
|                 MODE_1 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_high(); | ||||
|                     w.cpha().trailing(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_HIGH); | ||||
|                     w.set_cpha(vals::Cpha::TRAILING); | ||||
|                 } | ||||
|                 MODE_2 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_low(); | ||||
|                     w.cpha().leading(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_LOW); | ||||
|                     w.set_cpha(vals::Cpha::LEADING); | ||||
|                 } | ||||
|                 MODE_3 => { | ||||
|                     w.order().variant(config.bit_order); | ||||
|                     w.cpol().active_low(); | ||||
|                     w.cpha().trailing(); | ||||
|                     w.set_cpol(vals::Cpol::ACTIVE_LOW); | ||||
|                     w.set_cpha(vals::Cpha::TRAILING); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             w | ||||
|         }); | ||||
| 
 | ||||
|         // Set over-read character.
 | ||||
|         let orc = config.orc; | ||||
|         r.orc.write(|w| unsafe { w.orc().bits(orc) }); | ||||
|         r.orc().write(|w| w.set_orc(orc)); | ||||
| 
 | ||||
|         // Set default character.
 | ||||
|         let def = config.def; | ||||
|         r.def.write(|w| unsafe { w.def().bits(def) }); | ||||
|         r.def().write(|w| w.set_def(def)); | ||||
| 
 | ||||
|         // Configure auto-acquire on 'transfer end' event.
 | ||||
|         let auto_acquire = config.auto_acquire; | ||||
|         r.shorts.write(|w| w.end_acquire().bit(auto_acquire)); | ||||
|         r.shorts().write(|w| w.set_end_acquire(auto_acquire)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -19,8 +19,8 @@ pub struct InterruptHandler { | ||||
| 
 | ||||
| impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = unsafe { &*pac::TEMP::PTR }; | ||||
|         r.intenclr.write(|w| w.datardy().clear()); | ||||
|         let r = pac::TEMP; | ||||
|         r.intenclr().write(|w| w.set_datardy(true)); | ||||
|         WAKER.wake(); | ||||
|     } | ||||
| } | ||||
| @ -72,21 +72,21 @@ impl<'d> Temp<'d> { | ||||
|         // In case the future is dropped, stop the task and reset events.
 | ||||
|         let on_drop = OnDrop::new(|| { | ||||
|             let t = Self::regs(); | ||||
|             t.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             t.events_datardy.reset(); | ||||
|             t.tasks_stop().write_value(1); | ||||
|             t.events_datardy().write_value(0); | ||||
|         }); | ||||
| 
 | ||||
|         let t = Self::regs(); | ||||
|         t.intenset.write(|w| w.datardy().set()); | ||||
|         unsafe { t.tasks_start.write(|w| w.bits(1)) }; | ||||
|         t.intenset().write(|w| w.set_datardy(true)); | ||||
|         t.tasks_start().write_value(1); | ||||
| 
 | ||||
|         let value = poll_fn(|cx| { | ||||
|             WAKER.register(cx.waker()); | ||||
|             if t.events_datardy.read().bits() == 0 { | ||||
|             if t.events_datardy().read() == 0 { | ||||
|                 Poll::Pending | ||||
|             } else { | ||||
|                 t.events_datardy.reset(); | ||||
|                 let raw = t.temp.read().bits(); | ||||
|                 t.events_datardy().write_value(0); | ||||
|                 let raw = t.temp().read(); | ||||
|                 Poll::Ready(I30F2::from_bits(raw as i32)) | ||||
|             } | ||||
|         }) | ||||
| @ -95,7 +95,7 @@ impl<'d> Temp<'d> { | ||||
|         value | ||||
|     } | ||||
| 
 | ||||
|     fn regs() -> &'static pac::temp::RegisterBlock { | ||||
|         unsafe { &*pac::TEMP::ptr() } | ||||
|     fn regs() -> pac::temp::Temp { | ||||
|         pac::TEMP | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -10,8 +10,8 @@ use embassy_time_driver::{AlarmHandle, Driver}; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::{interrupt, pac}; | ||||
| 
 | ||||
| fn rtc() -> &'static pac::rtc0::RegisterBlock { | ||||
|     unsafe { &*pac::RTC1::ptr() } | ||||
| fn rtc() -> pac::rtc::Rtc { | ||||
|     pac::RTC1 | ||||
| } | ||||
| 
 | ||||
| /// Calculate the timestamp from the period count and the tick count.
 | ||||
| @ -128,19 +128,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | ||||
| impl RtcDriver { | ||||
|     fn init(&'static self, irq_prio: crate::interrupt::Priority) { | ||||
|         let r = rtc(); | ||||
|         r.cc[3].write(|w| unsafe { w.bits(0x800000) }); | ||||
|         r.cc(3).write(|w| w.set_compare(0x800000)); | ||||
| 
 | ||||
|         r.intenset.write(|w| { | ||||
|             let w = w.ovrflw().set(); | ||||
|             let w = w.compare3().set(); | ||||
|             w | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_ovrflw(true); | ||||
|             w.set_compare3(true); | ||||
|         }); | ||||
| 
 | ||||
|         r.tasks_clear.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_clear().write_value(1); | ||||
|         r.tasks_start().write_value(1); | ||||
| 
 | ||||
|         // Wait for clear
 | ||||
|         while r.counter.read().bits() != 0 {} | ||||
|         while r.counter().read().0 != 0 {} | ||||
| 
 | ||||
|         interrupt::RTC1.set_priority(irq_prio); | ||||
|         unsafe { interrupt::RTC1.enable() }; | ||||
| @ -148,19 +147,19 @@ impl RtcDriver { | ||||
| 
 | ||||
|     fn on_interrupt(&self) { | ||||
|         let r = rtc(); | ||||
|         if r.events_ovrflw.read().bits() == 1 { | ||||
|             r.events_ovrflw.write(|w| w); | ||||
|         if r.events_ovrflw().read() == 1 { | ||||
|             r.events_ovrflw().write_value(0); | ||||
|             self.next_period(); | ||||
|         } | ||||
| 
 | ||||
|         if r.events_compare[3].read().bits() == 1 { | ||||
|             r.events_compare[3].write(|w| w); | ||||
|         if r.events_compare(3).read() == 1 { | ||||
|             r.events_compare(3).write_value(0); | ||||
|             self.next_period(); | ||||
|         } | ||||
| 
 | ||||
|         for n in 0..ALARM_COUNT { | ||||
|             if r.events_compare[n].read().bits() == 1 { | ||||
|                 r.events_compare[n].write(|w| w); | ||||
|             if r.events_compare(n).read() == 1 { | ||||
|                 r.events_compare(n).write_value(0); | ||||
|                 critical_section::with(|cs| { | ||||
|                     self.trigger_alarm(n, cs); | ||||
|                 }) | ||||
| @ -181,7 +180,7 @@ impl RtcDriver { | ||||
| 
 | ||||
|                 if at < t + 0xc00000 { | ||||
|                     // just enable it. `set_alarm` has already set the correct CC val.
 | ||||
|                     r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); | ||||
|                     r.intenset().write(|w| w.0 = compare_n(n)); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
| @ -195,7 +194,7 @@ impl RtcDriver { | ||||
| 
 | ||||
|     fn trigger_alarm(&self, n: usize, cs: CriticalSection) { | ||||
|         let r = rtc(); | ||||
|         r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); | ||||
|         r.intenclr().write(|w| w.0 = compare_n(n)); | ||||
| 
 | ||||
|         let alarm = &self.alarms.borrow(cs)[n]; | ||||
|         alarm.timestamp.set(u64::MAX); | ||||
| @ -215,7 +214,7 @@ impl Driver for RtcDriver { | ||||
|         // `period` MUST be read before `counter`, see comment at the top for details.
 | ||||
|         let period = self.period.load(Ordering::Relaxed); | ||||
|         compiler_fence(Ordering::Acquire); | ||||
|         let counter = rtc().counter.read().bits(); | ||||
|         let counter = rtc().counter().read().0; | ||||
|         calc_now(period, counter) | ||||
|     } | ||||
| 
 | ||||
| @ -252,7 +251,7 @@ impl Driver for RtcDriver { | ||||
|             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)) }); | ||||
|                 r.intenclr().write(|w| w.0 = compare_n(n)); | ||||
| 
 | ||||
|                 alarm.timestamp.set(u64::MAX); | ||||
| 
 | ||||
| @ -277,15 +276,15 @@ impl Driver for RtcDriver { | ||||
|             // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
 | ||||
|             // and we don't do that here.
 | ||||
|             let safe_timestamp = timestamp.max(t + 3); | ||||
|             r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) }); | ||||
|             r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); | ||||
| 
 | ||||
|             let diff = timestamp - t; | ||||
|             if diff < 0xc00000 { | ||||
|                 r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); | ||||
|                 r.intenset().write(|w| w.0 = compare_n(n)); | ||||
|             } else { | ||||
|                 // If it's too far in the future, don't setup the compare channel yet.
 | ||||
|                 // It will be setup later by `next_period`.
 | ||||
|                 r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); | ||||
|                 r.intenclr().write(|w| w.0 = compare_n(n)); | ||||
|             } | ||||
| 
 | ||||
|             true | ||||
|  | ||||
| @ -8,13 +8,14 @@ | ||||
| 
 | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| 
 | ||||
| use crate::pac::timer::vals; | ||||
| use crate::ppi::{Event, Task}; | ||||
| use crate::{pac, Peripheral}; | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     /// The number of CC registers this instance has.
 | ||||
|     const CCS: usize; | ||||
|     fn regs() -> &'static pac::timer0::RegisterBlock; | ||||
|     fn regs() -> pac::timer::Timer; | ||||
| } | ||||
| 
 | ||||
| /// Basic Timer instance.
 | ||||
| @ -31,8 +32,8 @@ macro_rules! impl_timer { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { | ||||
|         impl crate::timer::SealedInstance for peripherals::$type { | ||||
|             const CCS: usize = $ccs; | ||||
|             fn regs() -> &'static pac::timer0::RegisterBlock { | ||||
|                 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | ||||
|             fn regs() -> pac::timer::Timer { | ||||
|                 unsafe { pac::timer::Timer::from_ptr(pac::$pac_type.as_ptr()) } | ||||
|             } | ||||
|         } | ||||
|         impl crate::timer::Instance for peripherals::$type { | ||||
| @ -114,19 +115,19 @@ impl<'d, T: Instance> Timer<'d, T> { | ||||
|         // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
 | ||||
|         this.stop(); | ||||
| 
 | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         if _is_counter { | ||||
|             regs.mode.write(|w| w.mode().low_power_counter()); | ||||
|         } else { | ||||
|             regs.mode.write(|w| w.mode().timer()); | ||||
|         } | ||||
| 
 | ||||
|         #[cfg(feature = "nrf51")] | ||||
|         regs.mode.write(|w| w.mode().timer()); | ||||
|         regs.mode().write(|w| { | ||||
|             w.set_mode(match _is_counter { | ||||
|                 #[cfg(not(feature = "_nrf51"))] | ||||
|                 true => vals::Mode::LOW_POWER_COUNTER, | ||||
|                 #[cfg(feature = "_nrf51")] | ||||
|                 true => vals::Mode::COUNTER, | ||||
|                 false => vals::Mode::TIMER, | ||||
|             }) | ||||
|         }); | ||||
| 
 | ||||
|         // Make the counter's max value as high as possible.
 | ||||
|         // TODO: is there a reason someone would want to set this lower?
 | ||||
|         regs.bitmode.write(|w| w.bitmode()._32bit()); | ||||
|         regs.bitmode().write(|w| w.set_bitmode(vals::Bitmode::_32BIT)); | ||||
| 
 | ||||
|         // Initialize the counter at 0.
 | ||||
|         this.clear(); | ||||
| @ -148,38 +149,38 @@ impl<'d, T: Instance> Timer<'d, T> { | ||||
| 
 | ||||
|     /// Starts the timer.
 | ||||
|     pub fn start(&self) { | ||||
|         T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_start().write_value(1) | ||||
|     } | ||||
| 
 | ||||
|     /// Stops the timer.
 | ||||
|     pub fn stop(&self) { | ||||
|         T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_stop().write_value(1) | ||||
|     } | ||||
| 
 | ||||
|     /// Reset the timer's counter to 0.
 | ||||
|     pub fn clear(&self) { | ||||
|         T::regs().tasks_clear.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_clear().write_value(1) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the START task, for use with PPI.
 | ||||
|     ///
 | ||||
|     /// When triggered, this task starts the timer.
 | ||||
|     pub fn task_start(&self) -> Task<'d> { | ||||
|         Task::from_reg(&T::regs().tasks_start) | ||||
|         Task::from_reg(T::regs().tasks_start()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the STOP task, for use with PPI.
 | ||||
|     ///
 | ||||
|     /// When triggered, this task stops the timer.
 | ||||
|     pub fn task_stop(&self) -> Task<'d> { | ||||
|         Task::from_reg(&T::regs().tasks_stop) | ||||
|         Task::from_reg(T::regs().tasks_stop()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the CLEAR task, for use with PPI.
 | ||||
|     ///
 | ||||
|     /// When triggered, this task resets the timer's counter to 0.
 | ||||
|     pub fn task_clear(&self) -> Task<'d> { | ||||
|         Task::from_reg(&T::regs().tasks_clear) | ||||
|         Task::from_reg(T::regs().tasks_clear()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the COUNT task, for use with PPI.
 | ||||
| @ -187,7 +188,7 @@ impl<'d, T: Instance> Timer<'d, T> { | ||||
|     /// When triggered, this task increments the timer's counter by 1.
 | ||||
|     /// Only works in counter mode.
 | ||||
|     pub fn task_count(&self) -> Task<'d> { | ||||
|         Task::from_reg(&T::regs().tasks_count) | ||||
|         Task::from_reg(T::regs().tasks_count()) | ||||
|     } | ||||
| 
 | ||||
|     /// Change the timer's frequency.
 | ||||
| @ -198,10 +199,10 @@ impl<'d, T: Instance> Timer<'d, T> { | ||||
|         self.stop(); | ||||
| 
 | ||||
|         T::regs() | ||||
|             .prescaler | ||||
|             .prescaler() | ||||
|             // SAFETY: `frequency` is a variant of `Frequency`,
 | ||||
|             // whose values are all in the range of 0-9 (the valid range of `prescaler`).
 | ||||
|             .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | ||||
|             .write(|w| w.set_prescaler(frequency as u8)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns this timer's `n`th CC register.
 | ||||
| @ -234,28 +235,19 @@ pub struct Cc<'d, T: Instance> { | ||||
| impl<'d, T: Instance> Cc<'d, T> { | ||||
|     /// Get the current value stored in the register.
 | ||||
|     pub fn read(&self) -> u32 { | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         return T::regs().cc[self.n].read().cc().bits(); | ||||
| 
 | ||||
|         #[cfg(feature = "nrf51")] | ||||
|         return T::regs().cc[self.n].read().bits(); | ||||
|         return T::regs().cc(self.n).read(); | ||||
|     } | ||||
| 
 | ||||
|     /// Set the value stored in the register.
 | ||||
|     ///
 | ||||
|     /// `event_compare` will fire when the timer's counter reaches this value.
 | ||||
|     pub fn write(&self, value: u32) { | ||||
|         // SAFETY: there are no invalid values for the CC register.
 | ||||
|         #[cfg(not(feature = "nrf51"))] | ||||
|         T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }); | ||||
| 
 | ||||
|         #[cfg(feature = "nrf51")] | ||||
|         T::regs().cc[self.n].write(|w| unsafe { w.bits(value) }); | ||||
|         T::regs().cc(self.n).write_value(value); | ||||
|     } | ||||
| 
 | ||||
|     /// Capture the current value of the timer's counter in this register, and return it.
 | ||||
|     pub fn capture(&self) -> u32 { | ||||
|         T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) }); | ||||
|         T::regs().tasks_capture(self.n).write_value(1); | ||||
|         self.read() | ||||
|     } | ||||
| 
 | ||||
| @ -263,14 +255,14 @@ impl<'d, T: Instance> Cc<'d, T> { | ||||
|     ///
 | ||||
|     /// When triggered, this task will capture the current value of the timer's counter in this register.
 | ||||
|     pub fn task_capture(&self) -> Task<'d> { | ||||
|         Task::from_reg(&T::regs().tasks_capture) | ||||
|         Task::from_reg(T::regs().tasks_capture(self.n)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns this CC register's COMPARE event, for use with PPI.
 | ||||
|     ///
 | ||||
|     /// This event will fire when the timer's counter reaches the value in this CC register.
 | ||||
|     pub fn event_compare(&self) -> Event<'d> { | ||||
|         Event::from_reg(&T::regs().events_compare[self.n]) | ||||
|         Event::from_reg(T::regs().events_compare(self.n)) | ||||
|     } | ||||
| 
 | ||||
|     /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
 | ||||
| @ -279,16 +271,12 @@ impl<'d, T: Instance> Cc<'d, T> { | ||||
|     ///
 | ||||
|     /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0.
 | ||||
|     pub fn short_compare_clear(&self) { | ||||
|         T::regs() | ||||
|             .shorts | ||||
|             .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) }) | ||||
|         T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true)) | ||||
|     } | ||||
| 
 | ||||
|     /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
 | ||||
|     pub fn unshort_compare_clear(&self) { | ||||
|         T::regs() | ||||
|             .shorts | ||||
|             .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) }) | ||||
|         T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false)) | ||||
|     } | ||||
| 
 | ||||
|     /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task.
 | ||||
| @ -297,15 +285,11 @@ impl<'d, T: Instance> Cc<'d, T> { | ||||
|     ///
 | ||||
|     /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up.
 | ||||
|     pub fn short_compare_stop(&self) { | ||||
|         T::regs() | ||||
|             .shorts | ||||
|             .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) }) | ||||
|         T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true)) | ||||
|     } | ||||
| 
 | ||||
|     /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task.
 | ||||
|     pub fn unshort_compare_stop(&self) { | ||||
|         T::regs() | ||||
|             .shorts | ||||
|             .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) }) | ||||
|         T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -15,24 +15,16 @@ use embassy_sync::waitqueue::AtomicWaker; | ||||
| #[cfg(feature = "time")] | ||||
| use embassy_time::{Duration, Instant}; | ||||
| use embedded_hal_1::i2c::Operation; | ||||
| pub use pac::twim::vals::Frequency; | ||||
| 
 | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::Pin as GpioPin; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::twim::vals; | ||||
| use crate::util::slice_in_ram; | ||||
| use crate::{gpio, interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| /// TWI frequency
 | ||||
| #[derive(Clone, Copy)] | ||||
| pub enum Frequency { | ||||
|     /// 100 kbps
 | ||||
|     K100 = 26738688, | ||||
|     /// 250 kbps
 | ||||
|     K250 = 67108864, | ||||
|     /// 400 kbps
 | ||||
|     K400 = 104857600, | ||||
| } | ||||
| 
 | ||||
| /// TWIM config.
 | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
| @ -105,17 +97,17 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         if r.events_suspended.read().bits() != 0 { | ||||
|         if r.events_suspended().read() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.suspended().clear()); | ||||
|             r.intenclr().write(|w| w.set_suspended(true)); | ||||
|         } | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|         if r.events_stopped().read() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.stopped().clear()); | ||||
|             r.intenclr().write(|w| w.set_stopped(true)); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|         if r.events_error().read() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.error().clear()); | ||||
|             r.intenclr().write(|w| w.set_error(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -140,38 +132,34 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|         // Configure pins
 | ||||
|         sda.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             if config.sda_high_drive { | ||||
|                 w.drive().h0d1(); | ||||
|             } else { | ||||
|                 w.drive().s0d1(); | ||||
|             } | ||||
|             w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_drive(match config.sda_high_drive { | ||||
|                 true => gpiovals::Drive::H0D1, | ||||
|                 false => gpiovals::Drive::S0D1, | ||||
|             }); | ||||
|             if config.sda_pullup { | ||||
|                 w.pull().pullup(); | ||||
|                 w.set_pull(gpiovals::Pull::PULLUP); | ||||
|             } | ||||
|             w | ||||
|         }); | ||||
|         scl.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             if config.scl_high_drive { | ||||
|                 w.drive().h0d1(); | ||||
|             } else { | ||||
|                 w.drive().s0d1(); | ||||
|             w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_drive(match config.scl_high_drive { | ||||
|                 true => gpiovals::Drive::H0D1, | ||||
|                 false => gpiovals::Drive::S0D1, | ||||
|             }); | ||||
|             if config.sda_pullup { | ||||
|                 w.set_pull(gpiovals::Pull::PULLUP); | ||||
|             } | ||||
|             if config.scl_pullup { | ||||
|                 w.pull().pullup(); | ||||
|             } | ||||
|             w | ||||
|         }); | ||||
| 
 | ||||
|         // Select pins.
 | ||||
|         r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); | ||||
|         r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); | ||||
|         r.psel().sda().write_value(sda.psel_bits()); | ||||
|         r.psel().scl().write_value(scl.psel_bits()); | ||||
| 
 | ||||
|         // Enable TWIM instance.
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let mut twim = Self { _p: twim }; | ||||
| 
 | ||||
| @ -179,7 +167,7 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|         Self::set_config(&mut twim, &config).unwrap(); | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @ -211,22 +199,18 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.txd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're
 | ||||
|             // waiting for the I2C transaction to end before this stack pointer
 | ||||
|             // becomes invalid, there's nothing wrong here.
 | ||||
|             //
 | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range
 | ||||
|             // of values.
 | ||||
|             w.ptr().bits(buffer.as_ptr() as u32)); | ||||
|         r.txd.maxcnt.write(|w| | ||||
|         // We're giving the register a pointer to the stack. Since we're
 | ||||
|         // waiting for the I2C transaction to end before this stack pointer
 | ||||
|         // becomes invalid, there's nothing wrong here.
 | ||||
|         r.txd().ptr().write_value(buffer.as_ptr() as u32); | ||||
|         r.txd().maxcnt().write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of
 | ||||
|             // accessing invalid memory. We have verified that the length of the
 | ||||
|             // buffer fits in an `u8`, so the cast to `u8` is also fine.
 | ||||
|             //
 | ||||
|             // The MAXCNT field is 8 bits wide and accepts the full range of
 | ||||
|             // values.
 | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|             w.set_maxcnt(buffer.len() as _)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -242,15 +226,11 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're
 | ||||
|             // waiting for the I2C transaction to end before this stack pointer
 | ||||
|             // becomes invalid, there's nothing wrong here.
 | ||||
|             //
 | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range
 | ||||
|             // of values.
 | ||||
|             w.ptr().bits(buffer.as_mut_ptr() as u32)); | ||||
|         r.rxd.maxcnt.write(|w| | ||||
|         // We're giving the register a pointer to the stack. Since we're
 | ||||
|         // waiting for the I2C transaction to end before this stack pointer
 | ||||
|         // becomes invalid, there's nothing wrong here.
 | ||||
|         r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32); | ||||
|         r.rxd().maxcnt().write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of
 | ||||
|             // accessing invalid memory. We have verified that the length of the
 | ||||
|             // buffer fits in an `u8`, so the cast to the type of maxcnt
 | ||||
| @ -260,29 +240,32 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|             // type than a u8, so we use a `_` cast rather than a `u8` cast.
 | ||||
|             // The MAXCNT field is thus at least 8 bits wide and accepts the
 | ||||
|             // full range of values that fit in a `u8`.
 | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|             w.set_maxcnt(buffer.len() as _)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn clear_errorsrc(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.errorsrc | ||||
|             .write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true)); | ||||
|         r.errorsrc().write(|w| { | ||||
|             w.set_anack(true); | ||||
|             w.set_dnack(true); | ||||
|             w.set_overrun(true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /// Get Error instance, if any occurred.
 | ||||
|     fn check_errorsrc(&self) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         let err = r.errorsrc.read(); | ||||
|         if err.anack().is_received() { | ||||
|         let err = r.errorsrc().read(); | ||||
|         if err.anack() { | ||||
|             return Err(Error::AddressNack); | ||||
|         } | ||||
|         if err.dnack().is_received() { | ||||
|         if err.dnack() { | ||||
|             return Err(Error::DataNack); | ||||
|         } | ||||
|         if err.overrun().is_received() { | ||||
|         if err.overrun() { | ||||
|             return Err(Error::Overrun); | ||||
|         } | ||||
|         Ok(()) | ||||
| @ -290,7 +273,7 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|     fn check_rx(&self, len: usize) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|         if r.rxd.amount.read().bits() != len as u32 { | ||||
|         if r.rxd().amount().read().0 != len as u32 { | ||||
|             Err(Error::Receive) | ||||
|         } else { | ||||
|             Ok(()) | ||||
| @ -299,7 +282,7 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|     fn check_tx(&self, len: usize) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|         if r.txd.amount.read().bits() != len as u32 { | ||||
|         if r.txd().amount().read().0 != len as u32 { | ||||
|             Err(Error::Transmit) | ||||
|         } else { | ||||
|             Ok(()) | ||||
| @ -310,14 +293,14 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|     fn blocking_wait(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_suspended.reset(); | ||||
|                 r.events_stopped.reset(); | ||||
|             if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { | ||||
|                 r.events_suspended().write_value(0); | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 break; | ||||
|             } | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -328,16 +311,16 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         let deadline = Instant::now() + timeout; | ||||
|         loop { | ||||
|             if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 break; | ||||
|             } | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|             } | ||||
|             if Instant::now() > deadline { | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Timeout); | ||||
|             } | ||||
|         } | ||||
| @ -352,16 +335,16 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|             let s = T::state(); | ||||
| 
 | ||||
|             s.end_waker.register(cx.waker()); | ||||
|             if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
| 
 | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| 
 | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|             } | ||||
| 
 | ||||
|             Poll::Pending | ||||
| @ -380,18 +363,25 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
| 
 | ||||
|         compiler_fence(SeqCst); | ||||
| 
 | ||||
|         r.address.write(|w| unsafe { w.address().bits(address) }); | ||||
|         r.address().write(|w| w.set_address(address)); | ||||
| 
 | ||||
|         r.events_suspended.reset(); | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_suspended().write_value(0); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         self.clear_errorsrc(); | ||||
| 
 | ||||
|         if inten { | ||||
|             r.intenset.write(|w| w.suspended().set().stopped().set().error().set()); | ||||
|             r.intenset().write(|w| { | ||||
|                 w.set_suspended(true); | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|         } else { | ||||
|             r.intenclr | ||||
|                 .write(|w| w.suspended().clear().stopped().clear().error().clear()); | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_suspended(true); | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         assert!(!operations.is_empty()); | ||||
| @ -408,26 +398,25 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|                     self.set_rx_buffer(rd_buffer)?; | ||||
|                 } | ||||
| 
 | ||||
|                 r.shorts.write(|w| { | ||||
|                     w.lastrx_starttx().enabled(); | ||||
|                 r.shorts().write(|w| { | ||||
|                     w.set_lastrx_starttx(true); | ||||
|                     if stop { | ||||
|                         w.lasttx_stop().enabled(); | ||||
|                         w.set_lasttx_stop(true); | ||||
|                     } else { | ||||
|                         w.lasttx_suspend().enabled(); | ||||
|                         w.set_lasttx_suspend(true); | ||||
|                     } | ||||
|                     w | ||||
|                 }); | ||||
| 
 | ||||
|                 // Start read+write operation.
 | ||||
|                 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_startrx().write_value(1); | ||||
|                 if last_op.is_some() { | ||||
|                     r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_resume().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 // TODO: Handle empty write buffer
 | ||||
|                 if rd_buffer.is_empty() { | ||||
|                     // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves.
 | ||||
|                     r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_starttx().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 Ok(2) | ||||
| @ -438,17 +427,17 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|                     self.set_rx_buffer(buffer)?; | ||||
|                 } | ||||
| 
 | ||||
|                 r.shorts.write(|w| w.lastrx_stop().enabled()); | ||||
|                 r.shorts().write(|w| w.set_lastrx_stop(true)); | ||||
| 
 | ||||
|                 // Start read operation.
 | ||||
|                 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_startrx().write_value(1); | ||||
|                 if last_op.is_some() { | ||||
|                     r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_resume().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 if buffer.is_empty() { | ||||
|                     // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves.
 | ||||
|                     r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_stop().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 Ok(1) | ||||
| @ -463,15 +452,14 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|                 } | ||||
| 
 | ||||
|                 // Start write+read operation.
 | ||||
|                 r.shorts.write(|w| { | ||||
|                     w.lasttx_startrx().enabled(); | ||||
|                     w.lastrx_stop().enabled(); | ||||
|                     w | ||||
|                 r.shorts().write(|w| { | ||||
|                     w.set_lasttx_startrx(true); | ||||
|                     w.set_lastrx_stop(true); | ||||
|                 }); | ||||
| 
 | ||||
|                 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_starttx().write_value(1); | ||||
|                 if last_op.is_some() { | ||||
|                     r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_resume().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 Ok(2) | ||||
| @ -485,26 +473,25 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|                 } | ||||
| 
 | ||||
|                 // Start write operation.
 | ||||
|                 r.shorts.write(|w| { | ||||
|                 r.shorts().write(|w| { | ||||
|                     if stop { | ||||
|                         w.lasttx_stop().enabled(); | ||||
|                         w.set_lasttx_stop(true); | ||||
|                     } else { | ||||
|                         w.lasttx_suspend().enabled(); | ||||
|                         w.set_lasttx_suspend(true); | ||||
|                     } | ||||
|                     w | ||||
|                 }); | ||||
| 
 | ||||
|                 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_starttx().write_value(1); | ||||
|                 if last_op.is_some() { | ||||
|                     r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||||
|                     r.tasks_resume().write_value(1); | ||||
|                 } | ||||
| 
 | ||||
|                 if buffer.is_empty() { | ||||
|                     // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves.
 | ||||
|                     if stop { | ||||
|                         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                         r.tasks_stop().write_value(1); | ||||
|                     } else { | ||||
|                         r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | ||||
|                         r.tasks_suspend().write_value(1); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
| @ -827,10 +814,10 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { | ||||
| 
 | ||||
|         // disable!
 | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
| 
 | ||||
|         gpio::deconfigure_pin(r.psel.sda.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.scl.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().sda().read()); | ||||
|         gpio::deconfigure_pin(r.psel().scl().read()); | ||||
| 
 | ||||
|         trace!("twim drop: done"); | ||||
|     } | ||||
| @ -849,7 +836,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::twim0::RegisterBlock; | ||||
|     fn regs() -> pac::twim::Twim; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -863,8 +850,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static { | ||||
| macro_rules! impl_twim { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::twim::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::twim0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::twim::Twim { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::twim::State { | ||||
|                 static STATE: crate::twim::State = crate::twim::State::new(); | ||||
| @ -948,8 +935,7 @@ impl<'d, T: Instance> SetConfig for Twim<'d, T> { | ||||
|     type ConfigError = (); | ||||
|     fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { | ||||
|         let r = T::regs(); | ||||
|         r.frequency | ||||
|             .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); | ||||
|         r.frequency().write(|w| w.set_frequency(config.frequency)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -16,6 +16,8 @@ use embassy_time::{Duration, Instant}; | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::Pin as GpioPin; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::twis::vals; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{gpio, interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| @ -119,17 +121,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { | ||||
|         if r.events_read().read() != 0 || r.events_write().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.read().clear().write().clear()); | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_read(true); | ||||
|                 w.set_write(true); | ||||
|             }); | ||||
|         } | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|         if r.events_stopped().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.stopped().clear()); | ||||
|             r.intenclr().write(|w| w.set_stopped(true)); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|         if r.events_error().read() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.error().clear()); | ||||
|             r.intenclr().write(|w| w.set_error(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -154,55 +159,51 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
| 
 | ||||
|         // Configure pins
 | ||||
|         sda.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             if config.sda_high_drive { | ||||
|                 w.drive().h0d1(); | ||||
|             } else { | ||||
|                 w.drive().s0d1(); | ||||
|             } | ||||
|             w.set_dir(gpiovals::Dir::INPUT); | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_drive(match config.sda_high_drive { | ||||
|                 true => gpiovals::Drive::H0D1, | ||||
|                 false => gpiovals::Drive::S0D1, | ||||
|             }); | ||||
|             if config.sda_pullup { | ||||
|                 w.pull().pullup(); | ||||
|                 w.set_pull(gpiovals::Pull::PULLUP); | ||||
|             } | ||||
|             w | ||||
|         }); | ||||
|         scl.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             if config.scl_high_drive { | ||||
|                 w.drive().h0d1(); | ||||
|             } else { | ||||
|                 w.drive().s0d1(); | ||||
|             w.set_dir(gpiovals::Dir::INPUT); | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_drive(match config.scl_high_drive { | ||||
|                 true => gpiovals::Drive::H0D1, | ||||
|                 false => gpiovals::Drive::S0D1, | ||||
|             }); | ||||
|             if config.sda_pullup { | ||||
|                 w.set_pull(gpiovals::Pull::PULLUP); | ||||
|             } | ||||
|             if config.scl_pullup { | ||||
|                 w.pull().pullup(); | ||||
|             } | ||||
|             w | ||||
|         }); | ||||
| 
 | ||||
|         // Select pins.
 | ||||
|         r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); | ||||
|         r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); | ||||
|         r.psel().sda().write_value(sda.psel_bits()); | ||||
|         r.psel().scl().write_value(scl.psel_bits()); | ||||
| 
 | ||||
|         // Enable TWIS instance.
 | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         // Disable all events interrupts
 | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|         r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
| 
 | ||||
|         // Set address
 | ||||
|         r.address[0].write(|w| unsafe { w.address().bits(config.address0) }); | ||||
|         r.config.write(|w| w.address0().enabled()); | ||||
|         r.address(0).write(|w| w.set_address(config.address0)); | ||||
|         r.config().write(|w| w.set_address0(true)); | ||||
|         if let Some(address1) = config.address1 { | ||||
|             r.address[1].write(|w| unsafe { w.address().bits(address1) }); | ||||
|             r.config.modify(|_r, w| w.address1().enabled()); | ||||
|             r.address(1).write(|w| w.set_address(address1)); | ||||
|             r.config().modify(|w| w.set_address1(true)); | ||||
|         } | ||||
| 
 | ||||
|         // Set over-read character
 | ||||
|         r.orc.write(|w| unsafe { w.orc().bits(config.orc) }); | ||||
|         r.orc().write(|w| w.set_orc(config.orc)); | ||||
| 
 | ||||
|         // Generate suspend on read event
 | ||||
|         r.shorts.write(|w| w.read_suspend().enabled()); | ||||
|         r.shorts().write(|w| w.set_read_suspend(true)); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @ -220,22 +221,18 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.txd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're
 | ||||
|             // waiting for the I2C transaction to end before this stack pointer
 | ||||
|             // becomes invalid, there's nothing wrong here.
 | ||||
|             //
 | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range
 | ||||
|             // of values.
 | ||||
|             w.ptr().bits(buffer.as_ptr() as u32)); | ||||
|         r.txd.maxcnt.write(|w| | ||||
|         // We're giving the register a pointer to the stack. Since we're
 | ||||
|         // waiting for the I2C transaction to end before this stack pointer
 | ||||
|         // becomes invalid, there's nothing wrong here.
 | ||||
|         r.txd().ptr().write_value(buffer.as_ptr() as u32); | ||||
|         r.txd().maxcnt().write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of
 | ||||
|             // accessing invalid memory. We have verified that the length of the
 | ||||
|             // buffer fits in an `u8`, so the cast to `u8` is also fine.
 | ||||
|             //
 | ||||
|             // The MAXCNT field is 8 bits wide and accepts the full range of
 | ||||
|             // values.
 | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|             w.set_maxcnt(buffer.len() as _)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -251,15 +248,11 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're
 | ||||
|             // waiting for the I2C transaction to end before this stack pointer
 | ||||
|             // becomes invalid, there's nothing wrong here.
 | ||||
|             //
 | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range
 | ||||
|             // of values.
 | ||||
|             w.ptr().bits(buffer.as_mut_ptr() as u32)); | ||||
|         r.rxd.maxcnt.write(|w| | ||||
|         // We're giving the register a pointer to the stack. Since we're
 | ||||
|         // waiting for the I2C transaction to end before this stack pointer
 | ||||
|         // becomes invalid, there's nothing wrong here.
 | ||||
|         r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32); | ||||
|         r.rxd().maxcnt().write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of
 | ||||
|             // accessing invalid memory. We have verified that the length of the
 | ||||
|             // buffer fits in an `u8`, so the cast to the type of maxcnt
 | ||||
| @ -269,48 +262,51 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|             // type than a u8, so we use a `_` cast rather than a `u8` cast.
 | ||||
|             // The MAXCNT field is thus at least 8 bits wide and accepts the
 | ||||
|             // full range of values that fit in a `u8`.
 | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|             w.set_maxcnt(buffer.len() as _)); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn clear_errorsrc(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.errorsrc | ||||
|             .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true)); | ||||
|         r.errorsrc().write(|w| { | ||||
|             w.set_overflow(true); | ||||
|             w.set_overread(true); | ||||
|             w.set_dnack(true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns matched address for latest command.
 | ||||
|     pub fn address_match(&self) -> u8 { | ||||
|         let r = T::regs(); | ||||
|         r.address[r.match_.read().bits() as usize].read().address().bits() | ||||
|         r.address(r.match_().read().0 as usize).read().address() | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the index of the address matched in the latest command.
 | ||||
|     pub fn address_match_index(&self) -> usize { | ||||
|         T::regs().match_.read().bits() as _ | ||||
|         T::regs().match_().read().0 as _ | ||||
|     } | ||||
| 
 | ||||
|     /// Wait for read, write, stop or error
 | ||||
|     fn blocking_listen_wait(&mut self) -> Result<Status, Error> { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 while r.events_stopped.read().bits() == 0 {} | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 while r.events_stopped().read() == 0 {} | ||||
|                 return Err(Error::Overflow); | ||||
|             } | ||||
|             if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return Err(Error::Bus); | ||||
|             } | ||||
|             if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|             if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 return Ok(Status::Read); | ||||
|             } | ||||
|             if r.events_write.read().bits() != 0 { | ||||
|                 r.events_write.reset(); | ||||
|             if r.events_write().read() != 0 { | ||||
|                 r.events_write().write_value(0); | ||||
|                 return Ok(Status::Write); | ||||
|             } | ||||
|         } | ||||
| @ -321,22 +317,22 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Overflow); | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return match status { | ||||
|                     Status::Read => Ok(Command::Read), | ||||
|                     Status::Write => { | ||||
|                         let n = r.rxd.amount.read().bits() as usize; | ||||
|                         let n = r.rxd().amount().read().0 as usize; | ||||
|                         Ok(Command::Write(n)) | ||||
|                     } | ||||
|                 }; | ||||
|             } else if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|                 let n = r.rxd.amount.read().bits() as usize; | ||||
|             } else if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 let n = r.rxd().amount().read().0 as usize; | ||||
|                 return Ok(Command::WriteRead(n)); | ||||
|             } | ||||
|         } | ||||
| @ -347,20 +343,20 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 let errorsrc = r.errorsrc.read(); | ||||
|                 if errorsrc.overread().is_detected() { | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 let errorsrc = r.errorsrc().read(); | ||||
|                 if errorsrc.overread() { | ||||
|                     return Err(Error::OverRead); | ||||
|                 } else if errorsrc.dnack().is_received() { | ||||
|                 } else if errorsrc.dnack() { | ||||
|                     return Err(Error::DataNack); | ||||
|                 } else { | ||||
|                     return Err(Error::Bus); | ||||
|                 } | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|                 let n = r.txd.amount.read().bits() as usize; | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 let n = r.txd().amount().read().0 as usize; | ||||
|                 return Ok(n); | ||||
|             } | ||||
|         } | ||||
| @ -373,23 +369,23 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         let deadline = Instant::now() + timeout; | ||||
|         loop { | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 let errorsrc = r.errorsrc.read(); | ||||
|                 if errorsrc.overread().is_detected() { | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 let errorsrc = r.errorsrc().read(); | ||||
|                 if errorsrc.overread() { | ||||
|                     return Err(Error::OverRead); | ||||
|                 } else if errorsrc.dnack().is_received() { | ||||
|                 } else if errorsrc.dnack() { | ||||
|                     return Err(Error::DataNack); | ||||
|                 } else { | ||||
|                     return Err(Error::Bus); | ||||
|                 } | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|                 let n = r.txd.amount.read().bits() as usize; | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 let n = r.txd().amount().read().0 as usize; | ||||
|                 return Ok(n); | ||||
|             } else if Instant::now() > deadline { | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Timeout); | ||||
|             } | ||||
|         } | ||||
| @ -401,26 +397,26 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         let deadline = Instant::now() + timeout; | ||||
|         loop { | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 while r.events_stopped.read().bits() == 0 {} | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 while r.events_stopped().read() == 0 {} | ||||
|                 return Err(Error::Overflow); | ||||
|             } | ||||
|             if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return Err(Error::Bus); | ||||
|             } | ||||
|             if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|             if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 return Ok(Status::Read); | ||||
|             } | ||||
|             if r.events_write.read().bits() != 0 { | ||||
|                 r.events_write.reset(); | ||||
|             if r.events_write().read() != 0 { | ||||
|                 r.events_write().write_value(0); | ||||
|                 return Ok(Status::Write); | ||||
|             } | ||||
|             if Instant::now() > deadline { | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Timeout); | ||||
|             } | ||||
|         } | ||||
| @ -433,25 +429,25 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         let deadline = Instant::now() + timeout; | ||||
|         loop { | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Overflow); | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return match status { | ||||
|                     Status::Read => Ok(Command::Read), | ||||
|                     Status::Write => { | ||||
|                         let n = r.rxd.amount.read().bits() as usize; | ||||
|                         let n = r.rxd().amount().read().0 as usize; | ||||
|                         Ok(Command::Write(n)) | ||||
|                     } | ||||
|                 }; | ||||
|             } else if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|                 let n = r.rxd.amount.read().bits() as usize; | ||||
|             } else if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 let n = r.rxd().amount().read().0 as usize; | ||||
|                 return Ok(Command::WriteRead(n)); | ||||
|             } else if Instant::now() > deadline { | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Err(Error::Timeout); | ||||
|             } | ||||
|         } | ||||
| @ -466,20 +462,20 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|             s.waker.register(cx.waker()); | ||||
| 
 | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|                 let errorsrc = r.errorsrc.read(); | ||||
|                 if errorsrc.overread().is_detected() { | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 let errorsrc = r.errorsrc().read(); | ||||
|                 if errorsrc.overread() { | ||||
|                     return Poll::Ready(Err(Error::OverRead)); | ||||
|                 } else if errorsrc.dnack().is_received() { | ||||
|                 } else if errorsrc.dnack() { | ||||
|                     return Poll::Ready(Err(Error::DataNack)); | ||||
|                 } else { | ||||
|                     return Poll::Ready(Err(Error::Bus)); | ||||
|                 } | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|                 let n = r.txd.amount.read().bits() as usize; | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 let n = r.txd().amount().read().0 as usize; | ||||
|                 return Poll::Ready(Ok(n)); | ||||
|             } | ||||
| 
 | ||||
| @ -496,18 +492,18 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|             s.waker.register(cx.waker()); | ||||
| 
 | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Poll::Ready(Err(Error::Overflow)); | ||||
|             } else if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|             } else if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 return Poll::Ready(Ok(Status::Read)); | ||||
|             } else if r.events_write.read().bits() != 0 { | ||||
|                 r.events_write.reset(); | ||||
|             } else if r.events_write().read() != 0 { | ||||
|                 r.events_write().write_value(0); | ||||
|                 return Poll::Ready(Ok(Status::Write)); | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return Poll::Ready(Err(Error::Bus)); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -523,22 +519,22 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|             s.waker.register(cx.waker()); | ||||
| 
 | ||||
|             // stop if an error occurred
 | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             if r.events_error().read() != 0 { | ||||
|                 r.events_error().write_value(0); | ||||
|                 r.tasks_stop().write_value(1); | ||||
|                 return Poll::Ready(Err(Error::Overflow)); | ||||
|             } else if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|             } else if r.events_stopped().read() != 0 { | ||||
|                 r.events_stopped().write_value(0); | ||||
|                 return match status { | ||||
|                     Status::Read => Poll::Ready(Ok(Command::Read)), | ||||
|                     Status::Write => { | ||||
|                         let n = r.rxd.amount.read().bits() as usize; | ||||
|                         let n = r.rxd().amount().read().0 as usize; | ||||
|                         Poll::Ready(Ok(Command::Write(n))) | ||||
|                     } | ||||
|                 }; | ||||
|             } else if r.events_read.read().bits() != 0 { | ||||
|                 r.events_read.reset(); | ||||
|                 let n = r.rxd.amount.read().bits() as usize; | ||||
|             } else if r.events_read().read() != 0 { | ||||
|                 r.events_read().write_value(0); | ||||
|                 let n = r.rxd().amount().read().0 as usize; | ||||
|                 return Poll::Ready(Ok(Command::WriteRead(n))); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -554,19 +550,25 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         unsafe { self.set_tx_buffer(buffer)? }; | ||||
| 
 | ||||
|         // Clear events
 | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         self.clear_errorsrc(); | ||||
| 
 | ||||
|         if inten { | ||||
|             r.intenset.write(|w| w.stopped().set().error().set()); | ||||
|             r.intenset().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|         } else { | ||||
|             r.intenclr.write(|w| w.stopped().clear().error().clear()); | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Start write operation.
 | ||||
|         r.tasks_preparetx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_preparetx().write_value(1); | ||||
|         r.tasks_resume().write_value(1); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| @ -591,22 +593,30 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         unsafe { self.set_rx_buffer(buffer)? }; | ||||
| 
 | ||||
|         // Clear events
 | ||||
|         r.events_read.reset(); | ||||
|         r.events_write.reset(); | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_read().write_value(0); | ||||
|         r.events_write().write_value(0); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         self.clear_errorsrc(); | ||||
| 
 | ||||
|         if inten { | ||||
|             r.intenset | ||||
|                 .write(|w| w.stopped().set().error().set().read().set().write().set()); | ||||
|             r.intenset().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|                 w.set_read(true); | ||||
|                 w.set_write(true); | ||||
|             }); | ||||
|         } else { | ||||
|             r.intenclr | ||||
|                 .write(|w| w.stopped().clear().error().clear().read().clear().write().clear()); | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|                 w.set_read(true); | ||||
|                 w.set_write(true); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Start read operation.
 | ||||
|         r.tasks_preparerx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_preparerx().write_value(1); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -616,16 +626,24 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         compiler_fence(SeqCst); | ||||
| 
 | ||||
|         // Clear events
 | ||||
|         r.events_read.reset(); | ||||
|         r.events_write.reset(); | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_read().write_value(0); | ||||
|         r.events_write().write_value(0); | ||||
|         r.events_stopped().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         self.clear_errorsrc(); | ||||
| 
 | ||||
|         if inten { | ||||
|             r.intenset.write(|w| w.stopped().set().error().set().read().set()); | ||||
|             r.intenset().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|                 w.set_read(true); | ||||
|             }); | ||||
|         } else { | ||||
|             r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear()); | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_stopped(true); | ||||
|                 w.set_error(true); | ||||
|                 w.set_read(true); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
| @ -745,10 +763,10 @@ impl<'a, T: Instance> Drop for Twis<'a, T> { | ||||
| 
 | ||||
|         // disable!
 | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
| 
 | ||||
|         gpio::deconfigure_pin(r.psel.sda.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.scl.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().sda().read()); | ||||
|         gpio::deconfigure_pin(r.psel().scl().read()); | ||||
| 
 | ||||
|         trace!("twis drop: done"); | ||||
|     } | ||||
| @ -767,7 +785,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::twis0::RegisterBlock; | ||||
|     fn regs() -> pac::twis::Twis; | ||||
|     fn state() -> &'static State; | ||||
| } | ||||
| 
 | ||||
| @ -781,8 +799,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static { | ||||
| macro_rules! impl_twis { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::twis::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::twis0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::twis::Twis { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::twis::State { | ||||
|                 static STATE: crate::twis::State = crate::twis::State::new(); | ||||
|  | ||||
| @ -21,13 +21,14 @@ use core::task::Poll; | ||||
| use embassy_hal_internal::drop::OnDrop; | ||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| use pac::uarte0::RegisterBlock; | ||||
| // Re-export SVD variants to allow user to directly set values.
 | ||||
| pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | ||||
| pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; | ||||
| 
 | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _}; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::gpio::vals as gpiovals; | ||||
| use crate::pac::uarte::vals; | ||||
| use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | ||||
| use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||||
| use crate::util::slice_in_ram_or; | ||||
| @ -54,7 +55,7 @@ impl Default for Config { | ||||
| 
 | ||||
| bitflags::bitflags! { | ||||
|     /// Error source flags
 | ||||
|     pub struct ErrorSource: u32 { | ||||
|     pub(crate) struct ErrorSource: u32 { | ||||
|         /// Buffer overrun
 | ||||
|         const OVERRUN = 0x01; | ||||
|         /// Parity error
 | ||||
| @ -112,20 +113,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
| 
 | ||||
|         let endrx = r.events_endrx.read().bits(); | ||||
|         let error = r.events_error.read().bits(); | ||||
|         let endrx = r.events_endrx().read(); | ||||
|         let error = r.events_error().read(); | ||||
|         if endrx != 0 || error != 0 { | ||||
|             s.rx_waker.wake(); | ||||
|             if endrx != 0 { | ||||
|                 r.intenclr.write(|w| w.endrx().clear()); | ||||
|                 r.intenclr().write(|w| w.set_endrx(true)); | ||||
|             } | ||||
|             if error != 0 { | ||||
|                 r.intenclr.write(|w| w.error().clear()); | ||||
|                 r.intenclr().write(|w| w.set_error(true)); | ||||
|             } | ||||
|         } | ||||
|         if r.events_endtx.read().bits() != 0 { | ||||
|         if r.events_endtx().read() != 0 { | ||||
|             s.tx_waker.wake(); | ||||
|             r.intenclr.write(|w| w.endtx().clear()); | ||||
|             r.intenclr().write(|w| w.set_endtx(true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -200,28 +201,12 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|             _ => panic!("RTS and CTS pins must be either both set or none set."), | ||||
|         }; | ||||
|         configure(r, config, hardware_flow_control); | ||||
| 
 | ||||
|         rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||||
| 
 | ||||
|         txd.set_high(); | ||||
|         txd.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &cts { | ||||
|             pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &rts { | ||||
|             pin.set_high(); | ||||
|             pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|         configure_rx_pins(r, rxd, rts); | ||||
|         configure_tx_pins(r, txd, cts); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let s = T::state(); | ||||
|         s.tx_rx_refcount.store(2, Ordering::Relaxed); | ||||
| @ -264,7 +249,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|     /// Return the endtx event for use with PPI
 | ||||
|     pub fn event_endtx(&self) -> Event { | ||||
|         let r = T::regs(); | ||||
|         Event::from_reg(&r.events_endtx) | ||||
|         Event::from_reg(r.events_endtx()) | ||||
|     } | ||||
| 
 | ||||
|     /// Read bytes until the buffer is filled.
 | ||||
| @ -298,27 +283,72 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { | ||||
|     r.config.write(|w| { | ||||
|         w.hwfc().bit(hardware_flow_control); | ||||
|         w.parity().variant(config.parity); | ||||
|         w | ||||
| pub(crate) fn configure_tx_pins( | ||||
|     r: pac::uarte::Uarte, | ||||
|     txd: PeripheralRef<'_, AnyPin>, | ||||
|     cts: Option<PeripheralRef<'_, AnyPin>>, | ||||
| ) { | ||||
|     txd.set_high(); | ||||
|     txd.conf().write(|w| { | ||||
|         w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|         w.set_input(gpiovals::Input::DISCONNECT); | ||||
|         w.set_drive(gpiovals::Drive::H0H1); | ||||
|     }); | ||||
|     r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | ||||
|     r.psel().txd().write_value(txd.psel_bits()); | ||||
| 
 | ||||
|     if let Some(pin) = &cts { | ||||
|         pin.conf().write(|w| { | ||||
|             w.set_dir(gpiovals::Dir::INPUT); | ||||
|             w.set_input(gpiovals::Input::CONNECT); | ||||
|             w.set_drive(gpiovals::Drive::H0H1); | ||||
|         }); | ||||
|     } | ||||
|     r.psel().cts().write_value(cts.psel_bits()); | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn configure_rx_pins( | ||||
|     r: pac::uarte::Uarte, | ||||
|     rxd: PeripheralRef<'_, AnyPin>, | ||||
|     rts: Option<PeripheralRef<'_, AnyPin>>, | ||||
| ) { | ||||
|     rxd.conf().write(|w| { | ||||
|         w.set_dir(gpiovals::Dir::INPUT); | ||||
|         w.set_input(gpiovals::Input::CONNECT); | ||||
|         w.set_drive(gpiovals::Drive::H0H1); | ||||
|     }); | ||||
|     r.psel().rxd().write_value(rxd.psel_bits()); | ||||
| 
 | ||||
|     if let Some(pin) = &rts { | ||||
|         pin.set_high(); | ||||
|         pin.conf().write(|w| { | ||||
|             w.set_dir(gpiovals::Dir::OUTPUT); | ||||
|             w.set_input(gpiovals::Input::DISCONNECT); | ||||
|             w.set_drive(gpiovals::Drive::H0H1); | ||||
|         }); | ||||
|     } | ||||
|     r.psel().rts().write_value(rts.psel_bits()); | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_control: bool) { | ||||
|     r.config().write(|w| { | ||||
|         w.set_hwfc(hardware_flow_control); | ||||
|         w.set_parity(config.parity); | ||||
|     }); | ||||
|     r.baudrate().write(|w| w.set_baudrate(config.baudrate)); | ||||
| 
 | ||||
|     // Disable all interrupts
 | ||||
|     r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|     r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | ||||
| 
 | ||||
|     // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was
 | ||||
|     // stopped midway or not.
 | ||||
|     r.events_rxstarted.reset(); | ||||
|     r.events_txstarted.reset(); | ||||
|     r.events_rxstarted().write_value(0); | ||||
|     r.events_txstarted().write_value(0); | ||||
| 
 | ||||
|     // reset all pins
 | ||||
|     r.psel.txd.write(|w| w.connect().disconnected()); | ||||
|     r.psel.rxd.write(|w| w.connect().disconnected()); | ||||
|     r.psel.cts.write(|w| w.connect().disconnected()); | ||||
|     r.psel.rts.write(|w| w.connect().disconnected()); | ||||
|     r.psel().txd().write_value(DISCONNECTED); | ||||
|     r.psel().rxd().write_value(DISCONNECTED); | ||||
|     r.psel().cts().write_value(DISCONNECTED); | ||||
|     r.psel().rts().write_value(DISCONNECTED); | ||||
| 
 | ||||
|     apply_workaround_for_enable_anomaly(r); | ||||
| } | ||||
| @ -356,19 +386,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         configure(r, config, cts.is_some()); | ||||
| 
 | ||||
|         txd.set_high(); | ||||
|         txd.conf().write(|w| w.dir().output().drive().s0s1()); | ||||
|         r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &cts { | ||||
|             pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||||
|         configure_tx_pins(r, txd, cts); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let s = T::state(); | ||||
|         s.tx_rx_refcount.store(1, Ordering::Relaxed); | ||||
| @ -410,29 +432,29 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
|         let drop = OnDrop::new(move || { | ||||
|             trace!("write drop: stopping"); | ||||
| 
 | ||||
|             r.intenclr.write(|w| w.endtx().clear()); | ||||
|             r.events_txstopped.reset(); | ||||
|             r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||||
|             r.intenclr().write(|w| w.set_endtx(true)); | ||||
|             r.events_txstopped().write_value(0); | ||||
|             r.tasks_stoptx().write_value(1); | ||||
| 
 | ||||
|             // TX is stopped almost instantly, spinning is fine.
 | ||||
|             while r.events_endtx.read().bits() == 0 {} | ||||
|             while r.events_endtx().read() == 0 {} | ||||
|             trace!("write drop: stopped"); | ||||
|         }); | ||||
| 
 | ||||
|         r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.txd().ptr().write_value(ptr as u32); | ||||
|         r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endtx.reset(); | ||||
|         r.intenset.write(|w| w.endtx().set()); | ||||
|         r.events_endtx().write_value(0); | ||||
|         r.intenset().write(|w| w.set_endtx(true)); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         trace!("starttx"); | ||||
|         r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_starttx().write_value(1); | ||||
| 
 | ||||
|         poll_fn(|cx| { | ||||
|             s.tx_waker.register(cx.waker()); | ||||
|             if r.events_endtx.read().bits() != 0 { | ||||
|             if r.events_endtx().read() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -440,7 +462,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
|         .await; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         r.events_txstarted.reset(); | ||||
|         r.events_txstarted().write_value(0); | ||||
|         drop.defuse(); | ||||
| 
 | ||||
|         Ok(()) | ||||
| @ -476,21 +498,21 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.txd().ptr().write_value(ptr as u32); | ||||
|         r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endtx.reset(); | ||||
|         r.intenclr.write(|w| w.endtx().clear()); | ||||
|         r.events_endtx().write_value(0); | ||||
|         r.intenclr().write(|w| w.set_endtx(true)); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         trace!("starttx"); | ||||
|         r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_starttx().write_value(1); | ||||
| 
 | ||||
|         while r.events_endtx.read().bits() == 0 {} | ||||
|         while r.events_endtx().read() == 0 {} | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         r.events_txstarted.reset(); | ||||
|         r.events_txstarted().write_value(0); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| @ -502,11 +524,11 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         let did_stoptx = r.events_txstarted.read().bits() != 0; | ||||
|         let did_stoptx = r.events_txstarted().read() != 0; | ||||
|         trace!("did_stoptx {}", did_stoptx); | ||||
| 
 | ||||
|         // Wait for txstopped, if needed.
 | ||||
|         while did_stoptx && r.events_txstopped.read().bits() == 0 {} | ||||
|         while did_stoptx && r.events_txstopped().read() == 0 {} | ||||
| 
 | ||||
|         let s = T::state(); | ||||
| 
 | ||||
| @ -541,9 +563,9 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|     /// Check for errors and clear the error register if an error occured.
 | ||||
|     fn check_and_clear_errors(&mut self) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|         let err_bits = r.errorsrc.read().bits(); | ||||
|         r.errorsrc.write(|w| unsafe { w.bits(err_bits) }); | ||||
|         ErrorSource::from_bits_truncate(err_bits).check() | ||||
|         let err_bits = r.errorsrc().read(); | ||||
|         r.errorsrc().write_value(err_bits); | ||||
|         ErrorSource::from_bits_truncate(err_bits.0).check() | ||||
|     } | ||||
| 
 | ||||
|     fn new_inner( | ||||
| @ -555,19 +577,11 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         configure(r, config, rts.is_some()); | ||||
| 
 | ||||
|         rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||||
| 
 | ||||
|         if let Some(pin) = &rts { | ||||
|             pin.set_high(); | ||||
|             pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|         configure_rx_pins(r, rxd, rts); | ||||
| 
 | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
| 
 | ||||
|         let s = T::state(); | ||||
|         s.tx_rx_refcount.store(1, Ordering::Relaxed); | ||||
| @ -594,8 +608,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         // We want to stop RX if line is idle for 2 bytes worth of time
 | ||||
|         // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
 | ||||
|         // This gives us the amount of 16M ticks for 20 bits.
 | ||||
|         let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||||
|         let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||||
|         let baudrate = r.baudrate().read().baudrate(); | ||||
|         let timeout = 0x8000_0000 / (baudrate.to_bits() / 40); | ||||
| 
 | ||||
|         timer.set_frequency(Frequency::F16MHz); | ||||
|         timer.cc(0).write(timeout); | ||||
| @ -604,7 +618,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
| 
 | ||||
|         let mut ppi_ch1 = Ppi::new_one_to_two( | ||||
|             ppi_ch1.map_into(), | ||||
|             Event::from_reg(&r.events_rxdrdy), | ||||
|             Event::from_reg(r.events_rxdrdy()), | ||||
|             timer.task_clear(), | ||||
|             timer.task_start(), | ||||
|         ); | ||||
| @ -613,7 +627,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         let mut ppi_ch2 = Ppi::new_one_to_one( | ||||
|             ppi_ch2.map_into(), | ||||
|             timer.cc(0).event_compare(), | ||||
|             Task::from_reg(&r.tasks_stoprx), | ||||
|             Task::from_reg(r.tasks_stoprx()), | ||||
|         ); | ||||
|         ppi_ch2.enable(); | ||||
| 
 | ||||
| @ -643,43 +657,42 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         let drop = OnDrop::new(move || { | ||||
|             trace!("read drop: stopping"); | ||||
| 
 | ||||
|             r.intenclr.write(|w| { | ||||
|                 w.endrx().clear(); | ||||
|                 w.error().clear() | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_endrx(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|             r.events_rxto.reset(); | ||||
|             r.events_error.reset(); | ||||
|             r.errorsrc.reset(); | ||||
|             r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|             r.events_rxto().write_value(0); | ||||
|             r.events_error().write_value(0); | ||||
|             r.tasks_stoprx().write_value(1); | ||||
| 
 | ||||
|             while r.events_endrx.read().bits() == 0 {} | ||||
|             while r.events_endrx().read() == 0 {} | ||||
| 
 | ||||
|             trace!("read drop: stopped"); | ||||
|         }); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.rxd().ptr().write_value(ptr as u32); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.intenset.write(|w| { | ||||
|             w.endrx().set(); | ||||
|             w.error().set() | ||||
|         r.events_endrx().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_endrx(true); | ||||
|             w.set_error(true); | ||||
|         }); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         trace!("startrx"); | ||||
|         r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_startrx().write_value(1); | ||||
| 
 | ||||
|         let result = poll_fn(|cx| { | ||||
|             s.rx_waker.register(cx.waker()); | ||||
| 
 | ||||
|             if let Err(e) = self.check_and_clear_errors() { | ||||
|                 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stoprx().write_value(1); | ||||
|                 return Poll::Ready(Err(e)); | ||||
|             } | ||||
|             if r.events_endrx.read().bits() != 0 { | ||||
|             if r.events_endrx().read() != 0 { | ||||
|                 return Poll::Ready(Ok(())); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @ -687,7 +700,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         .await; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_rxstarted().write_value(0); | ||||
|         drop.defuse(); | ||||
| 
 | ||||
|         result | ||||
| @ -707,25 +720,25 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.rxd().ptr().write_value(ptr as u32); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.intenclr.write(|w| { | ||||
|             w.endrx().clear(); | ||||
|             w.error().clear() | ||||
|         r.events_endrx().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         r.intenclr().write(|w| { | ||||
|             w.set_endrx(true); | ||||
|             w.set_error(true); | ||||
|         }); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         trace!("startrx"); | ||||
|         r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_startrx().write_value(1); | ||||
| 
 | ||||
|         while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} | ||||
|         while r.events_endrx().read() == 0 && r.events_error().read() == 0 {} | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_rxstarted().write_value(0); | ||||
| 
 | ||||
|         self.check_and_clear_errors() | ||||
|     } | ||||
| @ -737,11 +750,11 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { | ||||
| 
 | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         let did_stoprx = r.events_rxstarted.read().bits() != 0; | ||||
|         let did_stoprx = r.events_rxstarted().read() != 0; | ||||
|         trace!("did_stoprx {}", did_stoprx); | ||||
| 
 | ||||
|         // Wait for rxto, if needed.
 | ||||
|         while did_stoprx && r.events_rxto.read().bits() == 0 {} | ||||
|         while did_stoprx && r.events_rxto().read() == 0 {} | ||||
| 
 | ||||
|         let s = T::state(); | ||||
| 
 | ||||
| @ -794,39 +807,39 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { | ||||
|         let drop = OnDrop::new(|| { | ||||
|             self.timer.stop(); | ||||
| 
 | ||||
|             r.intenclr.write(|w| { | ||||
|                 w.endrx().clear(); | ||||
|                 w.error().clear() | ||||
|             r.intenclr().write(|w| { | ||||
|                 w.set_endrx(true); | ||||
|                 w.set_error(true); | ||||
|             }); | ||||
|             r.events_rxto.reset(); | ||||
|             r.events_error.reset(); | ||||
|             r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|             r.events_rxto().write_value(0); | ||||
|             r.events_error().write_value(0); | ||||
|             r.tasks_stoprx().write_value(1); | ||||
| 
 | ||||
|             while r.events_endrx.read().bits() == 0 {} | ||||
|             while r.events_endrx().read() == 0 {} | ||||
|         }); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.rxd().ptr().write_value(ptr as u32); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.intenset.write(|w| { | ||||
|             w.endrx().set(); | ||||
|             w.error().set() | ||||
|         r.events_endrx().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         r.intenset().write(|w| { | ||||
|             w.set_endrx(true); | ||||
|             w.set_error(true); | ||||
|         }); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_startrx().write_value(1); | ||||
| 
 | ||||
|         let result = poll_fn(|cx| { | ||||
|             s.rx_waker.register(cx.waker()); | ||||
| 
 | ||||
|             if let Err(e) = self.rx.check_and_clear_errors() { | ||||
|                 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|                 r.tasks_stoprx().write_value(1); | ||||
|                 return Poll::Ready(Err(e)); | ||||
|             } | ||||
|             if r.events_endrx.read().bits() != 0 { | ||||
|             if r.events_endrx().read() != 0 { | ||||
|                 return Poll::Ready(Ok(())); | ||||
|             } | ||||
| 
 | ||||
| @ -835,10 +848,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { | ||||
|         .await; | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         let n = r.rxd.amount.read().amount().bits() as usize; | ||||
|         let n = r.rxd().amount().read().0 as usize; | ||||
| 
 | ||||
|         self.timer.stop(); | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_rxstarted().write_value(0); | ||||
| 
 | ||||
|         drop.defuse(); | ||||
| 
 | ||||
| @ -863,56 +876,57 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { | ||||
| 
 | ||||
|         self.ppi_ch1.enable(); | ||||
| 
 | ||||
|         r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||||
|         r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||||
|         r.rxd().ptr().write_value(ptr as u32); | ||||
|         r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); | ||||
| 
 | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.intenclr.write(|w| { | ||||
|             w.endrx().clear(); | ||||
|             w.error().clear() | ||||
|         r.events_endrx().write_value(0); | ||||
|         r.events_error().write_value(0); | ||||
|         r.intenclr().write(|w| { | ||||
|             w.set_endrx(true); | ||||
|             w.set_error(true); | ||||
|         }); | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| 
 | ||||
|         r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_startrx().write_value(1); | ||||
| 
 | ||||
|         while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} | ||||
|         while r.events_endrx().read() == 0 && r.events_error().read() == 0 {} | ||||
| 
 | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         let n = r.rxd.amount.read().amount().bits() as usize; | ||||
|         let n = r.rxd().amount().read().0 as usize; | ||||
| 
 | ||||
|         self.timer.stop(); | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_rxstarted().write_value(0); | ||||
| 
 | ||||
|         self.rx.check_and_clear_errors().map(|_| n) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] | ||||
| pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | ||||
| pub(crate) fn apply_workaround_for_enable_anomaly(_r: pac::uarte::Uarte) { | ||||
|     // Do nothing
 | ||||
| } | ||||
| 
 | ||||
| #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] | ||||
| pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||||
| pub(crate) fn apply_workaround_for_enable_anomaly(r: pac::uarte::Uarte) { | ||||
|     // Apply workaround for anomalies:
 | ||||
|     // - nRF9160 - anomaly 23
 | ||||
|     // - nRF5340 - anomaly 44
 | ||||
|     let rxenable_reg: *const u32 = ((r as *const _ as usize) + 0x564) as *const u32; | ||||
|     let txenable_reg: *const u32 = ((r as *const _ as usize) + 0x568) as *const u32; | ||||
|     let rp = r.as_ptr() as *mut u32; | ||||
|     let rxenable_reg = unsafe { rp.add(0x564 / 4) }; | ||||
|     let txenable_reg = unsafe { rp.add(0x568 / 4) }; | ||||
| 
 | ||||
|     // NB Safety: This is taken from Nordic's driver -
 | ||||
|     // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
 | ||||
|     if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||||
|         r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.tasks_stoptx().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     // NB Safety: This is taken from Nordic's driver -
 | ||||
|     // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
 | ||||
|     if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|         r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); | ||||
|         r.tasks_stoprx().write_value(1); | ||||
| 
 | ||||
|         let mut workaround_succeded = false; | ||||
|         // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
 | ||||
| @ -933,23 +947,23 @@ pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Regist | ||||
|             panic!("Failed to apply workaround for UART"); | ||||
|         } | ||||
| 
 | ||||
|         let errors = r.errorsrc.read().bits(); | ||||
|         // NB Safety: safe to write back the bits we just read to clear them
 | ||||
|         r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         // write back the bits we just read to clear them
 | ||||
|         let errors = r.errorsrc().read(); | ||||
|         r.errorsrc().write_value(errors); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &State) { | ||||
| pub(crate) fn drop_tx_rx(r: pac::uarte::Uarte, s: &State) { | ||||
|     if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||||
|         // Finally we can disable, and we do so for the peripheral
 | ||||
|         // i.e. not just rx concerns.
 | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|         r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); | ||||
| 
 | ||||
|         gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||||
|         gpio::deconfigure_pin(r.psel().rxd().read()); | ||||
|         gpio::deconfigure_pin(r.psel().txd().read()); | ||||
|         gpio::deconfigure_pin(r.psel().rts().read()); | ||||
|         gpio::deconfigure_pin(r.psel().cts().read()); | ||||
| 
 | ||||
|         trace!("uarte tx and rx drop: done"); | ||||
|     } | ||||
| @ -971,7 +985,7 @@ impl State { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::uarte0::RegisterBlock; | ||||
|     fn regs() -> pac::uarte::Uarte; | ||||
|     fn state() -> &'static State; | ||||
|     fn buffered_state() -> &'static crate::buffered_uarte::State; | ||||
| } | ||||
| @ -986,8 +1000,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_uarte { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::uarte::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::uarte0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::uarte::Uarte { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|             fn state() -> &'static crate::uarte::State { | ||||
|                 static STATE: crate::uarte::State = crate::uarte::State::new(); | ||||
|  | ||||
| @ -15,10 +15,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| use embassy_usb_driver as driver; | ||||
| use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; | ||||
| use pac::usbd::RegisterBlock; | ||||
| 
 | ||||
| use self::vbus_detect::VbusDetect; | ||||
| use crate::interrupt::typelevel::Interrupt; | ||||
| use crate::pac::usbd::vals; | ||||
| use crate::util::slice_in_ram; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| 
 | ||||
| @ -38,19 +38,19 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|     unsafe fn on_interrupt() { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
|         if regs.events_usbreset.read().bits() != 0 { | ||||
|             regs.intenclr.write(|w| w.usbreset().clear()); | ||||
|         if regs.events_usbreset().read() != 0 { | ||||
|             regs.intenclr().write(|w| w.set_usbreset(true)); | ||||
|             BUS_WAKER.wake(); | ||||
|             EP0_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_ep0setup.read().bits() != 0 { | ||||
|             regs.intenclr.write(|w| w.ep0setup().clear()); | ||||
|         if regs.events_ep0setup().read() != 0 { | ||||
|             regs.intenclr().write(|w| w.set_ep0setup(true)); | ||||
|             EP0_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_ep0datadone.read().bits() != 0 { | ||||
|             regs.intenclr.write(|w| w.ep0datadone().clear()); | ||||
|         if regs.events_ep0datadone().read() != 0 { | ||||
|             regs.intenclr().write(|w| w.set_ep0datadone(true)); | ||||
|             EP0_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
| @ -63,22 +63,22 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         // Therefore, it's fine to clear just the event, and let main thread
 | ||||
|         // check the individual bits in EVENTCAUSE and EPDATASTATUS. It
 | ||||
|         // doesn't cause an infinite irq loop.
 | ||||
|         if regs.events_usbevent.read().bits() != 0 { | ||||
|             regs.events_usbevent.reset(); | ||||
|         if regs.events_usbevent().read() != 0 { | ||||
|             regs.events_usbevent().write_value(0); | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_epdata.read().bits() != 0 { | ||||
|             regs.events_epdata.reset(); | ||||
|         if regs.events_epdata().read() != 0 { | ||||
|             regs.events_epdata().write_value(0); | ||||
| 
 | ||||
|             let r = regs.epdatastatus.read().bits(); | ||||
|             regs.epdatastatus.write(|w| unsafe { w.bits(r) }); | ||||
|             READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel); | ||||
|             let r = regs.epdatastatus().read(); | ||||
|             regs.epdatastatus().write_value(r); | ||||
|             READY_ENDPOINTS.fetch_or(r.0, Ordering::AcqRel); | ||||
|             for i in 1..=7 { | ||||
|                 if r & In::mask(i) != 0 { | ||||
|                 if r.0 & In::mask(i) != 0 { | ||||
|                     In::waker(i).wake(); | ||||
|                 } | ||||
|                 if r & Out::mask(i) != 0 { | ||||
|                 if r.0 & Out::mask(i) != 0 { | ||||
|                     Out::waker(i).wake(); | ||||
|                 } | ||||
|             } | ||||
| @ -181,35 +181,34 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
| 
 | ||||
|         errata::pre_enable(); | ||||
| 
 | ||||
|         regs.enable.write(|w| w.enable().enabled()); | ||||
|         regs.enable().write(|w| w.set_enable(true)); | ||||
| 
 | ||||
|         // Wait until the peripheral is ready.
 | ||||
|         regs.intenset.write(|w| w.usbevent().set_bit()); | ||||
|         regs.intenset().write(|w| w.set_usbevent(true)); | ||||
|         poll_fn(|cx| { | ||||
|             BUS_WAKER.register(cx.waker()); | ||||
|             if regs.eventcause.read().ready().is_ready() { | ||||
|             if regs.eventcause().read().ready() { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await; | ||||
|         regs.eventcause.write(|w| w.ready().clear_bit_by_one()); | ||||
|         regs.eventcause().write(|w| w.set_ready(true)); | ||||
| 
 | ||||
|         errata::post_enable(); | ||||
| 
 | ||||
|         unsafe { NVIC::unmask(pac::Interrupt::USBD) }; | ||||
| 
 | ||||
|         regs.intenset.write(|w| { | ||||
|             w.usbreset().set_bit(); | ||||
|             w.usbevent().set_bit(); | ||||
|             w.epdata().set_bit(); | ||||
|             w | ||||
|         regs.intenset().write(|w| { | ||||
|             w.set_usbreset(true); | ||||
|             w.set_usbevent(true); | ||||
|             w.set_epdata(true); | ||||
|         }); | ||||
| 
 | ||||
|         if self.vbus_detect.wait_power_ready().await.is_ok() { | ||||
|             // Enable the USB pullup, allowing enumeration.
 | ||||
|             regs.usbpullup.write(|w| w.connect().enabled()); | ||||
|             regs.usbpullup().write(|w| w.set_connect(true)); | ||||
|             trace!("enabled"); | ||||
|         } else { | ||||
|             trace!("usb power not ready due to usb removal"); | ||||
| @ -218,7 +217,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
| 
 | ||||
|     async fn disable(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|         regs.enable.write(|x| x.enable().disabled()); | ||||
|         regs.enable().write(|x| x.set_enable(false)); | ||||
|     } | ||||
| 
 | ||||
|     async fn poll(&mut self) -> Event { | ||||
| @ -226,13 +225,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|             BUS_WAKER.register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
| 
 | ||||
|             if regs.events_usbreset.read().bits() != 0 { | ||||
|                 regs.events_usbreset.reset(); | ||||
|                 regs.intenset.write(|w| w.usbreset().set()); | ||||
|             if regs.events_usbreset().read() != 0 { | ||||
|                 regs.events_usbreset().write_value(0); | ||||
|                 regs.intenset().write(|w| w.set_usbreset(true)); | ||||
| 
 | ||||
|                 // Disable all endpoints except EP0
 | ||||
|                 regs.epinen.write(|w| unsafe { w.bits(0x01) }); | ||||
|                 regs.epouten.write(|w| unsafe { w.bits(0x01) }); | ||||
|                 regs.epinen().write(|w| w.0 = 0x01); | ||||
|                 regs.epouten().write(|w| w.0 = 0x01); | ||||
|                 READY_ENDPOINTS.store(In::mask(0), Ordering::Release); | ||||
|                 for i in 1..=7 { | ||||
|                     In::waker(i).wake(); | ||||
| @ -242,27 +241,27 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|                 return Poll::Ready(Event::Reset); | ||||
|             } | ||||
| 
 | ||||
|             let r = regs.eventcause.read(); | ||||
|             let r = regs.eventcause().read(); | ||||
| 
 | ||||
|             if r.isooutcrc().bit() { | ||||
|                 regs.eventcause.write(|w| w.isooutcrc().detected()); | ||||
|             if r.isooutcrc() { | ||||
|                 regs.eventcause().write(|w| w.set_isooutcrc(true)); | ||||
|                 trace!("USB event: isooutcrc"); | ||||
|             } | ||||
|             if r.usbwuallowed().bit() { | ||||
|                 regs.eventcause.write(|w| w.usbwuallowed().allowed()); | ||||
|             if r.usbwuallowed() { | ||||
|                 regs.eventcause().write(|w| w.set_usbwuallowed(true)); | ||||
|                 trace!("USB event: usbwuallowed"); | ||||
|             } | ||||
|             if r.suspend().bit() { | ||||
|                 regs.eventcause.write(|w| w.suspend().detected()); | ||||
|                 regs.lowpower.write(|w| w.lowpower().low_power()); | ||||
|             if r.suspend() { | ||||
|                 regs.eventcause().write(|w| w.set_suspend(true)); | ||||
|                 regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::LOW_POWER)); | ||||
|                 return Poll::Ready(Event::Suspend); | ||||
|             } | ||||
|             if r.resume().bit() { | ||||
|                 regs.eventcause.write(|w| w.resume().detected()); | ||||
|             if r.resume() { | ||||
|                 regs.eventcause().write(|w| w.set_resume(true)); | ||||
|                 return Poll::Ready(Event::Resume); | ||||
|             } | ||||
|             if r.ready().bit() { | ||||
|                 regs.eventcause.write(|w| w.ready().ready()); | ||||
|             if r.ready() { | ||||
|                 regs.eventcause().write(|w| w.set_ready(true)); | ||||
|                 trace!("USB event: ready"); | ||||
|             } | ||||
| 
 | ||||
| @ -284,16 +283,19 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
| 
 | ||||
|     fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             if ep_addr.index() == 0 { | ||||
|                 regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(stalled)); | ||||
|             } else { | ||||
|                 regs.epstall.write(|w| { | ||||
|                     w.ep().bits(ep_addr.index() as u8 & 0b111); | ||||
|                     w.io().bit(ep_addr.is_in()); | ||||
|                     w.stall().bit(stalled) | ||||
|                 }); | ||||
|         if ep_addr.index() == 0 { | ||||
|             if stalled { | ||||
|                 regs.tasks_ep0stall().write_value(1); | ||||
|             } | ||||
|         } else { | ||||
|             regs.epstall().write(|w| { | ||||
|                 w.set_ep(ep_addr.index() as u8 & 0b111); | ||||
|                 w.set_io(match ep_addr.direction() { | ||||
|                     Direction::In => vals::Io::IN, | ||||
|                     Direction::Out => vals::Io::OUT, | ||||
|                 }); | ||||
|                 w.set_stall(stalled); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -301,8 +303,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|         let regs = T::regs(); | ||||
|         let i = ep_addr.index(); | ||||
|         match ep_addr.direction() { | ||||
|             Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(), | ||||
|             Direction::In => regs.halted.epin[i].read().getstatus().is_halted(), | ||||
|             Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED, | ||||
|             Direction::In => regs.halted().epin(i).read().getstatus() == vals::Getstatus::HALTED, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -317,15 +319,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|         match ep_addr.direction() { | ||||
|             Direction::In => { | ||||
|                 let mut was_enabled = false; | ||||
|                 regs.epinen.modify(|r, w| { | ||||
|                     let mut bits = r.bits(); | ||||
|                     was_enabled = (bits & mask) != 0; | ||||
|                 regs.epinen().modify(|w| { | ||||
|                     was_enabled = (w.0 & mask) != 0; | ||||
|                     if enabled { | ||||
|                         bits |= mask | ||||
|                         w.0 |= mask | ||||
|                     } else { | ||||
|                         bits &= !mask | ||||
|                         w.0 &= !mask | ||||
|                     } | ||||
|                     unsafe { w.bits(bits) } | ||||
|                 }); | ||||
| 
 | ||||
|                 let ready_mask = In::mask(i); | ||||
| @ -340,15 +340,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|                 In::waker(i).wake(); | ||||
|             } | ||||
|             Direction::Out => { | ||||
|                 regs.epouten.modify(|r, w| { | ||||
|                     let mut bits = r.bits(); | ||||
|                     if enabled { | ||||
|                         bits |= mask | ||||
|                     } else { | ||||
|                         bits &= !mask | ||||
|                     } | ||||
|                     unsafe { w.bits(bits) } | ||||
|                 }); | ||||
|                 regs.epouten() | ||||
|                     .modify(|w| if enabled { w.0 |= mask } else { w.0 &= !mask }); | ||||
| 
 | ||||
|                 let ready_mask = Out::mask(i); | ||||
|                 if enabled { | ||||
| @ -356,7 +349,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|                     // peripheral will NAK all incoming packets) until we write a zero to the SIZE
 | ||||
|                     // register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the
 | ||||
|                     // SIZE register
 | ||||
|                     regs.size.epout[i].reset(); | ||||
|                     regs.size().epout(i).write(|_| ()); | ||||
|                 } else { | ||||
|                     READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel); | ||||
|                 } | ||||
| @ -370,25 +363,24 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|     async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
|         if regs.lowpower.read().lowpower().is_low_power() { | ||||
|         if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER { | ||||
|             errata::pre_wakeup(); | ||||
| 
 | ||||
|             regs.lowpower.write(|w| w.lowpower().force_normal()); | ||||
|             regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::FORCE_NORMAL)); | ||||
| 
 | ||||
|             poll_fn(|cx| { | ||||
|                 BUS_WAKER.register(cx.waker()); | ||||
|                 let regs = T::regs(); | ||||
|                 let r = regs.eventcause.read(); | ||||
|                 let r = regs.eventcause().read(); | ||||
| 
 | ||||
|                 if regs.events_usbreset.read().bits() != 0 { | ||||
|                 if regs.events_usbreset().read() != 0 { | ||||
|                     Poll::Ready(()) | ||||
|                 } else if r.resume().bit() { | ||||
|                 } else if r.resume() { | ||||
|                     Poll::Ready(()) | ||||
|                 } else if r.usbwuallowed().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()); | ||||
|                 } else if r.usbwuallowed() { | ||||
|                     regs.eventcause().write(|w| w.set_usbwuallowed(true)); | ||||
|                     regs.dpdmvalue().write(|w| w.set_state(vals::State::RESUME)); | ||||
|                     regs.tasks_dpdmdrive().write_value(1); | ||||
| 
 | ||||
|                     Poll::Ready(()) | ||||
|                 } else { | ||||
| @ -413,7 +405,7 @@ pub enum In {} | ||||
| trait EndpointDir { | ||||
|     fn waker(i: usize) -> &'static AtomicWaker; | ||||
|     fn mask(i: usize) -> u32; | ||||
|     fn is_enabled(regs: &RegisterBlock, i: usize) -> bool; | ||||
|     fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool; | ||||
| } | ||||
| 
 | ||||
| impl EndpointDir for In { | ||||
| @ -428,8 +420,8 @@ impl EndpointDir for In { | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { | ||||
|         (regs.epinen.read().bits() & (1 << i)) != 0 | ||||
|     fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool { | ||||
|         regs.epinen().read().in_(i) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -445,8 +437,8 @@ impl EndpointDir for Out { | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { | ||||
|         (regs.epouten.read().bits() & (1 << i)) != 0 | ||||
|     fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool { | ||||
|         regs.epouten().read().out(i) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -529,33 +521,23 @@ unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, Endpo | ||||
|     let regs = T::regs(); | ||||
| 
 | ||||
|     // Check that the packet fits into the buffer
 | ||||
|     let size = regs.size.epout[i].read().bits() as usize; | ||||
|     let size = regs.size().epout(i).read().0 as usize; | ||||
|     if size > buf.len() { | ||||
|         return Err(EndpointError::BufferOverflow); | ||||
|     } | ||||
| 
 | ||||
|     let epout = [ | ||||
|         ®s.epout0, | ||||
|         ®s.epout1, | ||||
|         ®s.epout2, | ||||
|         ®s.epout3, | ||||
|         ®s.epout4, | ||||
|         ®s.epout5, | ||||
|         ®s.epout6, | ||||
|         ®s.epout7, | ||||
|     ]; | ||||
|     epout[i].ptr.write(|w| w.bits(buf.as_ptr() as u32)); | ||||
|     regs.epout(i).ptr().write_value(buf.as_ptr() as u32); | ||||
|     // MAXCNT must match SIZE
 | ||||
|     epout[i].maxcnt.write(|w| w.bits(size as u32)); | ||||
|     regs.epout(i).maxcnt().write(|w| w.set_maxcnt(size as _)); | ||||
| 
 | ||||
|     dma_start(); | ||||
|     regs.events_endepout[i].reset(); | ||||
|     regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit()); | ||||
|     while regs.events_endepout[i].read().events_endepout().bit_is_clear() {} | ||||
|     regs.events_endepout[i].reset(); | ||||
|     regs.events_endepout(i).write_value(0); | ||||
|     regs.tasks_startepout(i).write_value(1); | ||||
|     while regs.events_endepout(i).read() == 0 {} | ||||
|     regs.events_endepout(i).write_value(0); | ||||
|     dma_end(); | ||||
| 
 | ||||
|     regs.size.epout[i].reset(); | ||||
|     regs.size().epout(i).write(|_| ()); | ||||
| 
 | ||||
|     Ok(size) | ||||
| } | ||||
| @ -574,27 +556,16 @@ unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) { | ||||
|         buf.as_ptr() | ||||
|     }; | ||||
| 
 | ||||
|     let epin = [ | ||||
|         ®s.epin0, | ||||
|         ®s.epin1, | ||||
|         ®s.epin2, | ||||
|         ®s.epin3, | ||||
|         ®s.epin4, | ||||
|         ®s.epin5, | ||||
|         ®s.epin6, | ||||
|         ®s.epin7, | ||||
|     ]; | ||||
| 
 | ||||
|     // Set the buffer length so the right number of bytes are transmitted.
 | ||||
|     // Safety: `buf.len()` has been checked to be <= the max buffer length.
 | ||||
|     epin[i].ptr.write(|w| w.bits(ptr as u32)); | ||||
|     epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8)); | ||||
|     regs.epin(i).ptr().write_value(ptr as u32); | ||||
|     regs.epin(i).maxcnt().write(|w| w.set_maxcnt(buf.len() as u8)); | ||||
| 
 | ||||
|     regs.events_endepin[i].reset(); | ||||
|     regs.events_endepin(i).write_value(0); | ||||
| 
 | ||||
|     dma_start(); | ||||
|     regs.tasks_startepin[i].write(|w| w.bits(1)); | ||||
|     while regs.events_endepin[i].read().bits() == 0 {} | ||||
|     regs.tasks_startepin(i).write_value(1); | ||||
|     while regs.events_endepin(i).read() == 0 {} | ||||
|     dma_end(); | ||||
| } | ||||
| 
 | ||||
| @ -637,14 +608,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
|         // Reset shorts
 | ||||
|         regs.shorts.write(|w| w); | ||||
|         regs.shorts().write(|_| ()); | ||||
| 
 | ||||
|         // Wait for SETUP packet
 | ||||
|         regs.intenset.write(|w| w.ep0setup().set()); | ||||
|         regs.intenset().write(|w| w.set_ep0setup(true)); | ||||
|         poll_fn(|cx| { | ||||
|             EP0_WAKER.register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if regs.events_ep0setup.read().bits() != 0 { | ||||
|             if regs.events_ep0setup().read() != 0 { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @ -652,17 +623,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         }) | ||||
|         .await; | ||||
| 
 | ||||
|         regs.events_ep0setup.reset(); | ||||
|         regs.events_ep0setup().write_value(0); | ||||
| 
 | ||||
|         let mut buf = [0; 8]; | ||||
|         buf[0] = regs.bmrequesttype.read().bits() as u8; | ||||
|         buf[1] = regs.brequest.read().brequest().bits(); | ||||
|         buf[2] = regs.wvaluel.read().wvaluel().bits(); | ||||
|         buf[3] = regs.wvalueh.read().wvalueh().bits(); | ||||
|         buf[4] = regs.windexl.read().windexl().bits(); | ||||
|         buf[5] = regs.windexh.read().windexh().bits(); | ||||
|         buf[6] = regs.wlengthl.read().wlengthl().bits(); | ||||
|         buf[7] = regs.wlengthh.read().wlengthh().bits(); | ||||
|         buf[0] = regs.bmrequesttype().read().0 as u8; | ||||
|         buf[1] = regs.brequest().read().0 as u8; | ||||
|         buf[2] = regs.wvaluel().read().0 as u8; | ||||
|         buf[3] = regs.wvalueh().read().0 as u8; | ||||
|         buf[4] = regs.windexl().read().0 as u8; | ||||
|         buf[5] = regs.windexh().read().0 as u8; | ||||
|         buf[6] = regs.wlengthl().read().0 as u8; | ||||
|         buf[7] = regs.wlengthh().read().0 as u8; | ||||
| 
 | ||||
|         buf | ||||
|     } | ||||
| @ -670,26 +641,26 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|     async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
|         regs.events_ep0datadone.reset(); | ||||
|         regs.events_ep0datadone().write_value(0); | ||||
| 
 | ||||
|         // This starts a RX on EP0. events_ep0datadone notifies when done.
 | ||||
|         regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit()); | ||||
|         regs.tasks_ep0rcvout().write_value(1); | ||||
| 
 | ||||
|         // Wait until ready
 | ||||
|         regs.intenset.write(|w| { | ||||
|             w.usbreset().set(); | ||||
|             w.ep0setup().set(); | ||||
|             w.ep0datadone().set() | ||||
|         regs.intenset().write(|w| { | ||||
|             w.set_usbreset(true); | ||||
|             w.set_ep0setup(true); | ||||
|             w.set_ep0datadone(true); | ||||
|         }); | ||||
|         poll_fn(|cx| { | ||||
|             EP0_WAKER.register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if regs.events_ep0datadone.read().bits() != 0 { | ||||
|             if regs.events_ep0datadone().read() != 0 { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if regs.events_usbreset.read().bits() != 0 { | ||||
|             } else if regs.events_usbreset().read() != 0 { | ||||
|                 trace!("aborted control data_out: usb reset"); | ||||
|                 Poll::Ready(Err(EndpointError::Disabled)) | ||||
|             } else if regs.events_ep0setup.read().bits() != 0 { | ||||
|             } else if regs.events_ep0setup().read() != 0 { | ||||
|                 trace!("aborted control data_out: received another SETUP"); | ||||
|                 Poll::Ready(Err(EndpointError::Disabled)) | ||||
|             } else { | ||||
| @ -703,29 +674,29 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
| 
 | ||||
|     async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { | ||||
|         let regs = T::regs(); | ||||
|         regs.events_ep0datadone.reset(); | ||||
|         regs.events_ep0datadone().write_value(0); | ||||
| 
 | ||||
|         regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last)); | ||||
|         regs.shorts().write(|w| w.set_ep0datadone_ep0status(last)); | ||||
| 
 | ||||
|         // This starts a TX on EP0. events_ep0datadone notifies when done.
 | ||||
|         unsafe { write_dma::<T>(0, buf) } | ||||
| 
 | ||||
|         regs.intenset.write(|w| { | ||||
|             w.usbreset().set(); | ||||
|             w.ep0setup().set(); | ||||
|             w.ep0datadone().set() | ||||
|         regs.intenset().write(|w| { | ||||
|             w.set_usbreset(true); | ||||
|             w.set_ep0setup(true); | ||||
|             w.set_ep0datadone(true); | ||||
|         }); | ||||
| 
 | ||||
|         poll_fn(|cx| { | ||||
|             cx.waker().wake_by_ref(); | ||||
|             EP0_WAKER.register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if regs.events_ep0datadone.read().bits() != 0 { | ||||
|             if regs.events_ep0datadone().read() != 0 { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if regs.events_usbreset.read().bits() != 0 { | ||||
|             } else if regs.events_usbreset().read() != 0 { | ||||
|                 trace!("aborted control data_in: usb reset"); | ||||
|                 Poll::Ready(Err(EndpointError::Disabled)) | ||||
|             } else if regs.events_ep0setup.read().bits() != 0 { | ||||
|             } else if regs.events_ep0setup().read() != 0 { | ||||
|                 trace!("aborted control data_in: received another SETUP"); | ||||
|                 Poll::Ready(Err(EndpointError::Disabled)) | ||||
|             } else { | ||||
| @ -737,12 +708,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
| 
 | ||||
|     async fn accept(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|         regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true)); | ||||
|         regs.tasks_ep0status().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     async fn reject(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|         regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); | ||||
|         regs.tasks_ep0stall().write_value(1); | ||||
|     } | ||||
| 
 | ||||
|     async fn accept_set_address(&mut self, _addr: u8) { | ||||
| @ -806,7 +777,7 @@ impl Allocator { | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     fn regs() -> &'static pac::usbd::RegisterBlock; | ||||
|     fn regs() -> pac::usbd::Usbd; | ||||
| } | ||||
| 
 | ||||
| /// USB peripheral instance.
 | ||||
| @ -819,8 +790,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { | ||||
| macro_rules! impl_usb { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::usb::SealedInstance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::usbd::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             fn regs() -> pac::usbd::Usbd { | ||||
|                 pac::$pac_type | ||||
|             } | ||||
|         } | ||||
|         impl crate::usb::Instance for peripherals::$type { | ||||
|  | ||||
| @ -34,9 +34,9 @@ type UsbRegIrq = interrupt::typelevel::POWER_CLOCK; | ||||
| type UsbRegIrq = interrupt::typelevel::USBREGULATOR; | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf5340"))] | ||||
| type UsbRegPeri = pac::POWER; | ||||
| const USB_REG_PERI: pac::power::Power = pac::POWER; | ||||
| #[cfg(feature = "_nrf5340")] | ||||
| type UsbRegPeri = pac::USBREGULATOR; | ||||
| const USB_REG_PERI: pac::usbregulator::Usbregulator = pac::USBREGULATOR; | ||||
| 
 | ||||
| /// Interrupt handler.
 | ||||
| pub struct InterruptHandler { | ||||
| @ -45,21 +45,21 @@ pub struct InterruptHandler { | ||||
| 
 | ||||
| impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|         let regs = USB_REG_PERI; | ||||
| 
 | ||||
|         if regs.events_usbdetected.read().bits() != 0 { | ||||
|             regs.events_usbdetected.reset(); | ||||
|         if regs.events_usbdetected().read() != 0 { | ||||
|             regs.events_usbdetected().write_value(0); | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_usbremoved.read().bits() != 0 { | ||||
|             regs.events_usbremoved.reset(); | ||||
|         if regs.events_usbremoved().read() != 0 { | ||||
|             regs.events_usbremoved().write_value(0); | ||||
|             BUS_WAKER.wake(); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_usbpwrrdy.read().bits() != 0 { | ||||
|             regs.events_usbpwrrdy.reset(); | ||||
|         if regs.events_usbpwrrdy().read() != 0 { | ||||
|             regs.events_usbpwrrdy().write_value(0); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
| @ -78,13 +78,16 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| impl HardwareVbusDetect { | ||||
|     /// Create a new `VbusDetectNative`.
 | ||||
|     pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|         let regs = USB_REG_PERI; | ||||
| 
 | ||||
|         UsbRegIrq::unpend(); | ||||
|         unsafe { UsbRegIrq::enable() }; | ||||
| 
 | ||||
|         regs.intenset | ||||
|             .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||||
|         regs.intenset().write(|w| { | ||||
|             w.set_usbdetected(true); | ||||
|             w.set_usbremoved(true); | ||||
|             w.set_usbpwrrdy(true); | ||||
|         }); | ||||
| 
 | ||||
|         Self { _private: () } | ||||
|     } | ||||
| @ -92,16 +95,16 @@ impl HardwareVbusDetect { | ||||
| 
 | ||||
| impl VbusDetect for HardwareVbusDetect { | ||||
|     fn is_usb_detected(&self) -> bool { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|         regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||||
|         let regs = USB_REG_PERI; | ||||
|         regs.usbregstatus().read().vbusdetect() | ||||
|     } | ||||
| 
 | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||||
|         poll_fn(move |cx| { | ||||
|             POWER_WAKER.register(cx.waker()); | ||||
|             let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|             let regs = USB_REG_PERI; | ||||
| 
 | ||||
|             if regs.usbregstatus.read().outputrdy().is_ready() { | ||||
|             if regs.usbregstatus().read().outputrdy() { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if !self.is_usb_detected() { | ||||
|                 Poll::Ready(Err(())) | ||||
|  | ||||
| @ -3,7 +3,8 @@ | ||||
| //! This HAL implements a basic watchdog timer with 1..=8 handles.
 | ||||
| //! Once the watchdog has been started, it cannot be stopped.
 | ||||
| 
 | ||||
| use crate::pac::WDT; | ||||
| use crate::pac::wdt::vals; | ||||
| pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; | ||||
| use crate::peripherals; | ||||
| 
 | ||||
| const MIN_TICKS: u32 = 15; | ||||
| @ -18,29 +19,29 @@ pub struct Config { | ||||
|     pub timeout_ticks: u32, | ||||
| 
 | ||||
|     /// Should the watchdog continue to count during sleep modes?
 | ||||
|     pub run_during_sleep: bool, | ||||
|     pub action_during_sleep: SleepConfig, | ||||
| 
 | ||||
|     /// Should the watchdog continue to count when the CPU is halted for debug?
 | ||||
|     pub run_during_debug_halt: bool, | ||||
|     pub action_during_debug_halt: HaltConfig, | ||||
| } | ||||
| 
 | ||||
| impl Config { | ||||
|     /// Create a config structure from the current configuration of the WDT
 | ||||
|     /// peripheral.
 | ||||
|     pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         let r = crate::pac::WDT; | ||||
| 
 | ||||
|         #[cfg(not(feature = "_nrf91"))] | ||||
|         let runstatus = r.runstatus.read().runstatus().bit(); | ||||
|         let runstatus = r.runstatus().read().runstatus(); | ||||
|         #[cfg(feature = "_nrf91")] | ||||
|         let runstatus = r.runstatus.read().runstatuswdt().bit(); | ||||
|         let runstatus = r.runstatus().read().runstatuswdt(); | ||||
| 
 | ||||
|         if runstatus { | ||||
|             let config = r.config.read(); | ||||
|             let config = r.config().read(); | ||||
|             Some(Self { | ||||
|                 timeout_ticks: r.crv.read().bits(), | ||||
|                 run_during_sleep: config.sleep().bit(), | ||||
|                 run_during_debug_halt: config.halt().bit(), | ||||
|                 timeout_ticks: r.crv().read(), | ||||
|                 action_during_sleep: config.sleep(), | ||||
|                 action_during_debug_halt: config.halt(), | ||||
|             }) | ||||
|         } else { | ||||
|             None | ||||
| @ -52,8 +53,8 @@ impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             timeout_ticks: 32768, // 1 second
 | ||||
|             run_during_debug_halt: true, | ||||
|             run_during_sleep: true, | ||||
|             action_during_debug_halt: HaltConfig::RUN, | ||||
|             action_during_sleep: SleepConfig::RUN, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -78,36 +79,35 @@ impl Watchdog { | ||||
|     ) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> { | ||||
|         assert!(N >= 1 && N <= 8); | ||||
| 
 | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         let r = crate::pac::WDT; | ||||
| 
 | ||||
|         let crv = config.timeout_ticks.max(MIN_TICKS); | ||||
|         let rren = (1u32 << N) - 1; | ||||
|         let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1); | ||||
| 
 | ||||
|         #[cfg(not(feature = "_nrf91"))] | ||||
|         let runstatus = r.runstatus.read().runstatus().bit(); | ||||
|         let runstatus = r.runstatus().read().runstatus(); | ||||
|         #[cfg(feature = "_nrf91")] | ||||
|         let runstatus = r.runstatus.read().runstatuswdt().bit(); | ||||
|         let runstatus = r.runstatus().read().runstatuswdt(); | ||||
| 
 | ||||
|         if runstatus { | ||||
|             let curr_config = r.config.read(); | ||||
|             if curr_config.halt().bit() != config.run_during_debug_halt | ||||
|                 || curr_config.sleep().bit() != config.run_during_sleep | ||||
|                 || r.crv.read().bits() != crv | ||||
|                 || r.rren.read().bits() != rren | ||||
|             let curr_config = r.config().read(); | ||||
|             if curr_config.halt() != config.action_during_debug_halt | ||||
|                 || curr_config.sleep() != config.action_during_sleep | ||||
|                 || r.crv().read() != crv | ||||
|                 || r.rren().read() != rren | ||||
|             { | ||||
|                 return Err(wdt); | ||||
|             } | ||||
|         } else { | ||||
|             r.config.write(|w| { | ||||
|                 w.sleep().bit(config.run_during_sleep); | ||||
|                 w.halt().bit(config.run_during_debug_halt); | ||||
|                 w | ||||
|             r.config().write(|w| { | ||||
|                 w.set_sleep(config.action_during_sleep); | ||||
|                 w.set_halt(config.action_during_debug_halt); | ||||
|             }); | ||||
|             r.intenset.write(|w| w.timeout().set_bit()); | ||||
|             r.intenset().write(|w| w.set_timeout(true)); | ||||
| 
 | ||||
|             r.crv.write(|w| unsafe { w.bits(crv) }); | ||||
|             r.rren.write(|w| unsafe { w.bits(rren) }); | ||||
|             r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|             r.crv().write_value(crv); | ||||
|             r.rren().write_value(rren); | ||||
|             r.tasks_start().write_value(1); | ||||
|         } | ||||
| 
 | ||||
|         let this = Self { _private: () }; | ||||
| @ -130,8 +130,7 @@ impl Watchdog { | ||||
|     /// interrupt has been enabled.
 | ||||
|     #[inline(always)] | ||||
|     pub fn enable_interrupt(&mut self) { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         r.intenset.write(|w| w.timeout().set_bit()); | ||||
|         crate::pac::WDT.intenset().write(|w| w.set_timeout(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Disable the watchdog interrupt.
 | ||||
| @ -139,8 +138,7 @@ impl Watchdog { | ||||
|     /// NOTE: This has no effect on the reset caused by the Watchdog.
 | ||||
|     #[inline(always)] | ||||
|     pub fn disable_interrupt(&mut self) { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         r.intenclr.write(|w| w.timeout().set_bit()); | ||||
|         crate::pac::WDT.intenclr().write(|w| w.set_timeout(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Is the watchdog still awaiting pets from any handle?
 | ||||
| @ -149,9 +147,9 @@ impl Watchdog { | ||||
|     /// handles to prevent a reset this time period.
 | ||||
|     #[inline(always)] | ||||
|     pub fn awaiting_pets(&self) -> bool { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         let enabled = r.rren.read().bits(); | ||||
|         let status = r.reqstatus.read().bits(); | ||||
|         let r = crate::pac::WDT; | ||||
|         let enabled = r.rren().read().0; | ||||
|         let status = r.reqstatus().read().0; | ||||
|         (status & enabled) == 0 | ||||
|     } | ||||
| } | ||||
| @ -170,16 +168,14 @@ impl WatchdogHandle { | ||||
|     /// prevent a reset from occurring.
 | ||||
|     #[inline] | ||||
|     pub fn pet(&mut self) { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         r.rr[self.index as usize].write(|w| w.rr().reload()); | ||||
|         let r = crate::pac::WDT; | ||||
|         r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD)); | ||||
|     } | ||||
| 
 | ||||
|     /// Has this handle been pet within the current window?
 | ||||
|     pub fn is_pet(&self) -> bool { | ||||
|         let r = unsafe { &*WDT::ptr() }; | ||||
|         let rd = r.reqstatus.read().bits(); | ||||
|         let idx = self.index as usize; | ||||
|         ((rd >> idx) & 0x1) == 0 | ||||
|         let r = crate::pac::WDT; | ||||
|         !r.reqstatus().read().rr(self.index as usize) | ||||
|     } | ||||
| 
 | ||||
|     /// Steal a watchdog handle by index.
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ use cortex_m_rt::{entry, exception}; | ||||
| use defmt_rtt as _; | ||||
| use embassy_boot_nrf::*; | ||||
| use embassy_nrf::nvmc::Nvmc; | ||||
| use embassy_nrf::wdt; | ||||
| use embassy_nrf::wdt::{self, HaltConfig, SleepConfig}; | ||||
| use embassy_sync::blocking_mutex::Mutex; | ||||
| 
 | ||||
| #[entry] | ||||
| @ -25,8 +25,8 @@ fn main() -> ! { | ||||
| 
 | ||||
|     let mut wdt_config = wdt::Config::default(); | ||||
|     wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
 | ||||
|     wdt_config.run_during_sleep = true; | ||||
|     wdt_config.run_during_debug_halt = false; | ||||
|     wdt_config.action_during_sleep = SleepConfig::RUN; | ||||
|     wdt_config.action_during_debug_halt = HaltConfig::PAUSE; | ||||
| 
 | ||||
|     let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); | ||||
|     let flash = Mutex::new(RefCell::new(flash)); | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| 
 | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_net::tcp::TcpSocket; | ||||
| @ -46,11 +44,10 @@ async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>> | ||||
| #[embassy_executor::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| use core::sync::atomic::{AtomicBool, Ordering}; | ||||
| 
 | ||||
| use defmt::*; | ||||
| @ -30,11 +29,10 @@ static SUSPENDED: AtomicBool = AtomicBool::new(false); | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| 
 | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| @ -24,11 +22,10 @@ bind_interrupts!(struct Irqs { | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| 
 | ||||
| use defmt::{info, panic}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| @ -22,11 +20,10 @@ bind_interrupts!(struct Irqs { | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| 
 | ||||
| use defmt::{info, panic, unwrap}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||||
| @ -39,11 +37,10 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) { | ||||
| #[embassy_executor::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| use core::mem; | ||||
| 
 | ||||
| use defmt::{info, panic}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| @ -27,11 +25,10 @@ const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321 | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | ||||
| 
 | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|     pac::CLOCK.tasks_hfclkstart().write_value(1); | ||||
|     while pac::CLOCK.events_hfclkstarted().read() != 1 {} | ||||
| 
 | ||||
|     // Create the driver, from the HAL.
 | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::gpio::{Input, Pull}; | ||||
| use embassy_nrf::wdt::{Config, Watchdog}; | ||||
| use embassy_nrf::wdt::{Config, HaltConfig, Watchdog}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
| 
 | ||||
| #[embassy_executor::main] | ||||
| @ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { | ||||
| 
 | ||||
|     // This is needed for `probe-rs run` to be able to catch the panic message
 | ||||
|     // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
 | ||||
|     config.run_during_debug_halt = false; | ||||
|     config.action_during_debug_halt = HaltConfig::PAUSE; | ||||
| 
 | ||||
|     let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) { | ||||
|         Ok(x) => x, | ||||
|  | ||||
| @ -86,6 +86,11 @@ name = "gpiote" | ||||
| path = "src/bin/gpiote.rs" | ||||
| required-features = [] | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "spim" | ||||
| path = "src/bin/spim.rs" | ||||
| required-features = [ "easydma",] | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "timer" | ||||
| path = "src/bin/timer.rs" | ||||
|  | ||||
| @ -50,15 +50,15 @@ async fn main(_spawner: Spawner) { | ||||
|     const NSPAM: usize = 17; | ||||
|     static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | ||||
|     let _spam = UarteTx::new(peri!(p, UART1), irqs!(UART1), peri!(p, PIN_A), config.clone()); | ||||
|     let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) }; | ||||
|     let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) }; | ||||
|     let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) }; | ||||
|     let spam_peri = pac::UARTE1; | ||||
|     let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(spam_peri.events_endtx().as_ptr())) }; | ||||
|     let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(spam_peri.tasks_starttx().as_ptr())) }; | ||||
|     let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task); | ||||
|     spam_ppi.enable(); | ||||
|     let p = (&raw mut TX_BUF) as *mut u8; | ||||
|     spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) }); | ||||
|     spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) }); | ||||
|     spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|     spam_peri.txd().ptr().write_value(p as u32); | ||||
|     spam_peri.txd().maxcnt().write(|w| w.set_maxcnt(NSPAM as _)); | ||||
|     spam_peri.tasks_starttx().write_value(1); | ||||
| 
 | ||||
|     let mut i = 0; | ||||
|     let mut total = 0; | ||||
|  | ||||
| @ -17,10 +17,12 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut output = Output::new(peri!(p, PIN_B), Level::Low, OutputDrive::Standard); | ||||
| 
 | ||||
|     output.set_low(); | ||||
|     assert!(output.is_set_low()); | ||||
|     Timer::after_millis(10).await; | ||||
|     assert!(input.is_low()); | ||||
| 
 | ||||
|     output.set_high(); | ||||
|     assert!(output.is_set_high()); | ||||
|     Timer::after_millis(10).await; | ||||
|     assert!(input.is_high()); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										42
									
								
								tests/nrf/src/bin/spim.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								tests/nrf/src/bin/spim.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| // required-features: easydma
 | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| 
 | ||||
| #[path = "../common.rs"] | ||||
| mod common; | ||||
| 
 | ||||
| use defmt::{assert_eq, *}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::spim::Spim; | ||||
| use embassy_nrf::{peripherals, spim}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
| 
 | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
|     let mut config = spim::Config::default(); | ||||
|     config.frequency = spim::Frequency::M1; | ||||
|     let mut spim = Spim::new( | ||||
|         &mut peri!(p, SPIM0), | ||||
|         irqs!(SPIM0), | ||||
|         &mut peri!(p, PIN_X), | ||||
|         &mut peri!(p, PIN_A), // MISO
 | ||||
|         &mut peri!(p, PIN_B), // MOSI
 | ||||
|         config.clone(), | ||||
|     ); | ||||
|     let data = [ | ||||
|         0x42, 0x43, 0x44, 0x45, 0x66, 0x12, 0x23, 0x34, 0x45, 0x19, 0x91, 0xaa, 0xff, 0xa5, 0x5a, 0x77, | ||||
|     ]; | ||||
|     let mut buf = [0u8; 16]; | ||||
| 
 | ||||
|     buf.fill(0); | ||||
|     spim.blocking_transfer(&mut buf, &data).unwrap(); | ||||
|     assert_eq!(data, buf); | ||||
| 
 | ||||
|     buf.fill(0); | ||||
|     spim.transfer(&mut buf, &data).await.unwrap(); | ||||
|     assert_eq!(data, buf); | ||||
| 
 | ||||
|     info!("Test OK"); | ||||
|     cortex_m::asm::bkpt(); | ||||
| } | ||||
| @ -52,51 +52,66 @@ define_peris!(PIN_A = P0_13, PIN_B = P0_14,); | ||||
| #[cfg(feature = "nrf52832")] | ||||
| define_peris!( | ||||
|     PIN_A = P0_11, PIN_B = P0_12, | ||||
|     PIN_X = P0_13, | ||||
|     UART0 = UARTE0, | ||||
|     SPIM0 = TWISPI0, | ||||
|     @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;}, | ||||
| ); | ||||
| 
 | ||||
| #[cfg(feature = "nrf52833")] | ||||
| define_peris!( | ||||
|     PIN_A = P1_01, PIN_B = P1_02, | ||||
|     PIN_X = P1_03, | ||||
|     UART0 = UARTE0, | ||||
|     UART1 = UARTE1, | ||||
|     SPIM0 = TWISPI0, | ||||
|     @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq UART1 = {UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;}, | ||||
|     @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler<peripherals::UARTE1>;}, | ||||
|     @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;}, | ||||
| ); | ||||
| 
 | ||||
| #[cfg(feature = "nrf52840")] | ||||
| define_peris!( | ||||
|     PIN_A = P1_02, PIN_B = P1_03, | ||||
|     PIN_X = P1_04, | ||||
|     UART0 = UARTE0, | ||||
|     UART1 = UARTE1, | ||||
|     SPIM0 = TWISPI0, | ||||
|     @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq UART1 = {UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;}, | ||||
|     @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;}, | ||||
|     @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler<peripherals::UARTE1>;}, | ||||
|     @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;}, | ||||
| ); | ||||
| 
 | ||||
| #[cfg(feature = "nrf5340")] | ||||
| define_peris!( | ||||
|     PIN_A = P1_08, PIN_B = P1_09, | ||||
|     PIN_X = P1_10, | ||||
|     UART0 = SERIAL0, | ||||
|     UART1 = SERIAL1, | ||||
|     SPIM0 = SERIAL0, | ||||
|     @irq UART0 = {SERIAL0 => uarte::InterruptHandler<peripherals::SERIAL0>;}, | ||||
|     @irq UART1 = {SERIAL1 => uarte::InterruptHandler<peripherals::SERIAL1>;}, | ||||
|     @irq UART0_BUFFERED = {SERIAL0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;}, | ||||
|     @irq UART1_BUFFERED = {SERIAL1 => buffered_uarte::InterruptHandler<peripherals::SERIAL1>;}, | ||||
|     @irq SPIM0 = {SERIAL0 => spim::InterruptHandler<peripherals::SERIAL0>;}, | ||||
| ); | ||||
| 
 | ||||
| #[cfg(feature = "nrf9160")] | ||||
| define_peris!( | ||||
|     PIN_A = P0_00, PIN_B = P0_01, | ||||
|     PIN_X = P0_02, | ||||
|     UART0 = SERIAL0, | ||||
|     UART1 = SERIAL1, | ||||
|     SPIM0 = SERIAL0, | ||||
|     @irq UART0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => uarte::InterruptHandler<peripherals::SERIAL0>;}, | ||||
|     @irq UART1 = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => uarte::InterruptHandler<peripherals::SERIAL1>;}, | ||||
|     @irq UART0_BUFFERED = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;}, | ||||
|     @irq UART1_BUFFERED = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => buffered_uarte::InterruptHandler<peripherals::SERIAL1>;}, | ||||
|     @irq SPIM0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => spim::InterruptHandler<peripherals::SERIAL0>;}, | ||||
| ); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user