diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index d9d15b004..0dc09e18d 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -304,7 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// `mark_booted`. pub async fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned).await?; - Ok(State::from(&self.aligned)) + Ok(State::from(&self.aligned[..STATE::WRITE_SIZE])) } /// Mark to trigger firmware swap on next boot. diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 2f2aeda76..e8134c6a9 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::{Span, TokenStream}; @@ -11,6 +13,9 @@ use crate::util::*; struct Args { #[darling(default)] pool_size: Option, + /// Use this to override the `embassy_executor` crate path. Defaults to `::embassy_executor`. + #[darling(default)] + embassy_executor: Option, } pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { @@ -42,6 +47,10 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { lit: Lit::Int(LitInt::new("1", Span::call_site())), })); + let embassy_executor = args + .embassy_executor + .unwrap_or(Expr::Verbatim(TokenStream::from_str("::embassy_executor").unwrap())); + if f.sig.asyncness.is_none() { error(&mut errors, &f.sig, "task functions must be async"); } @@ -131,13 +140,13 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { } const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); + static POOL: #embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = #embassy_executor::raw::TaskPool::new(); unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } }; #[cfg(not(feature = "nightly"))] let mut task_outer_body = quote! { const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); + static POOL: #embassy_executor::_export::TaskPoolRef = #embassy_executor::_export::TaskPoolRef::new(); unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } }; @@ -146,7 +155,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { if !errors.is_empty() { task_outer_body = quote! { #![allow(unused_variables, unreachable_code)] - let _x: ::embassy_executor::SpawnToken<()> = ::core::todo!(); + let _x: #embassy_executor::SpawnToken<()> = ::core::todo!(); _x }; } @@ -164,7 +173,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { #task_inner #(#task_outer_attrs)* - #visibility fn #task_ident #generics (#fargs) -> ::embassy_executor::SpawnToken #where_clause{ + #visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken #where_clause{ #task_outer_body } diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 07a0c8886..98356c1ba 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -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"} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 60cdc38c6..80d08f7f5 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -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>, ch: &mut ch::Runner) { 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(()) } diff --git a/embassy-net/src/driver_util.rs b/embassy-net/src/driver_util.rs index f51641425..536f4c3d9 100644 --- a/embassy-net/src/driver_util.rs +++ b/embassy-net/src/driver_util.rs @@ -84,7 +84,7 @@ where { self.0.consume(|buf| { #[cfg(feature = "packet-trace")] - trace!("rx: {:?}", buf); + trace!("embassy device rx: {:02x}", buf); f(buf) }) } @@ -105,7 +105,7 @@ where self.0.consume(len, |buf| { let r = f(buf); #[cfg(feature = "packet-trace")] - trace!("tx: {:?}", buf); + trace!("embassy device tx: {:02x}", buf); r }) } diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index a7b7efa87..ec7f10fdd 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -33,14 +33,14 @@ pub use embassy_net_driver as driver; use embassy_net_driver::{Driver, LinkState}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; -#[allow(unused_imports)] use heapless::Vec; #[cfg(feature = "dns")] pub use smoltcp::config::DNS_MAX_SERVER_COUNT; #[cfg(feature = "multicast")] pub use smoltcp::iface::MulticastError; -#[allow(unused_imports)] -use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; +#[cfg(any(feature = "dns", feature = "dhcpv4"))] +use smoltcp::iface::SocketHandle; +use smoltcp::iface::{Interface, SocketSet, SocketStorage}; use smoltcp::phy::Medium; #[cfg(feature = "dhcpv4")] use smoltcp::socket::dhcpv4::{self, RetryConfig}; @@ -379,11 +379,11 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddres impl<'d> Stack<'d> { fn with(&self, f: impl FnOnce(&Inner) -> R) -> R { - f(&*self.inner.borrow()) + f(&self.inner.borrow()) } fn with_mut(&self, f: impl FnOnce(&mut Inner) -> R) -> R { - f(&mut *self.inner.borrow_mut()) + f(&mut self.inner.borrow_mut()) } /// Get the hardware address of the network interface. @@ -391,12 +391,12 @@ impl<'d> Stack<'d> { self.with(|i| i.hardware_address) } - /// Get whether the link is up. + /// Check whether the link is up. pub fn is_link_up(&self) -> bool { self.with(|i| i.link_up) } - /// Get whether the network stack has a valid IP configuration. + /// Check whether the network stack has a valid IP configuration. /// This is true if the network stack has a static IP configuration or if DHCP has completed pub fn is_config_up(&self) -> bool { let v4_up; @@ -642,7 +642,7 @@ impl<'d> Stack<'d> { } impl Inner { - #[allow(clippy::absurd_extreme_comparisons, dead_code)] + #[allow(clippy::absurd_extreme_comparisons)] pub fn get_local_port(&mut self) -> u16 { let res = self.next_local_port; self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; @@ -732,7 +732,7 @@ impl Inner { debug!(" Default gateway: {:?}", config.gateway); unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok()); - gateway_v4 = config.gateway.into(); + gateway_v4 = config.gateway; #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); @@ -831,22 +831,19 @@ impl Inner { self.state_waker.wake(); } - #[allow(unused_mut)] - let mut apply_config = false; - #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { let socket = self.sockets.get_mut::(dhcp_handle); - if self.link_up { + let configure = if self.link_up { if old_link_up != self.link_up { socket.reset(); } match socket.poll() { - None => {} + None => false, Some(dhcpv4::Event::Deconfigured) => { self.static_v4 = None; - apply_config = true; + true } Some(dhcpv4::Event::Configured(config)) => { self.static_v4 = Some(StaticConfigV4 { @@ -854,20 +851,21 @@ impl Inner { gateway: config.router, dns_servers: config.dns_servers, }); - apply_config = true; + true } } } else if old_link_up { socket.reset(); self.static_v4 = None; - apply_config = true; + true + } else { + false + }; + if configure { + self.apply_static_config() } } - if apply_config { - self.apply_static_config(); - } - if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) { let t = pin!(Timer::at(instant_from_smoltcp(poll_at))); if t.poll(cx).is_ready() { diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index ace325a46..a88bcc458 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -8,7 +8,7 @@ use embassy_net_driver::Driver; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::raw; pub use smoltcp::socket::raw::PacketMetadata; -use smoltcp::wire::{IpProtocol, IpVersion}; +pub use smoltcp::wire::{IpProtocol, IpVersion}; use crate::Stack; @@ -62,6 +62,14 @@ impl<'a> RawSocket<'a> { }) } + /// Wait until the socket becomes readable. + /// + /// A socket is readable when a packet has been received, or when there are queued packets in + /// the buffer. + pub async fn wait_recv_ready(&self) { + poll_fn(move |cx| self.poll_recv_ready(cx)).await + } + /// Receive a datagram. /// /// This method will wait until a datagram is received. @@ -69,6 +77,24 @@ impl<'a> RawSocket<'a> { poll_fn(move |cx| self.poll_recv(buf, cx)).await } + /// Wait until a datagram can be read. + /// + /// When no datagram is readable, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will return `Poll::Ready`. + pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_recv() { + Poll::Ready(()) + } else { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Receive a datagram. /// /// When no datagram is available, this method will return `Poll::Pending` and @@ -85,6 +111,33 @@ impl<'a> RawSocket<'a> { }) } + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when there is space in the buffer, from initial memory or after + /// dispatching datagrams on a full buffer. + pub async fn wait_send_ready(&self) { + poll_fn(move |cx| self.poll_send_ready(cx)).await + } + + /// Wait until a datagram can be sent. + /// + /// When no datagram can be sent (i.e. the buffer is full), this method will return + /// `Poll::Pending` and register the current task to be notified when + /// space is freed in the buffer after a datagram has been dispatched. + /// + /// When a datagram can be sent, this method will return `Poll::Ready`. + pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_send() { + Poll::Ready(()) + } else { + // socket buffer is full wait until a datagram has been dispatched + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Send a datagram. /// /// This method will wait until the datagram has been sent.` diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index a00ced8f4..32d374064 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -73,6 +73,16 @@ pub struct TcpWriter<'a> { } impl<'a> TcpReader<'a> { + /// Wait until the socket becomes readable. + /// + /// A socket becomes readable when the receive half of the full-duplex connection is open + /// (see [`may_recv()`](TcpSocket::may_recv)), and there is some pending data in the receive buffer. + /// + /// This is the equivalent of [read](#method.read), without buffering any data. + pub async fn wait_read_ready(&self) { + poll_fn(move |cx| self.io.poll_read_ready(cx)).await + } + /// Read data from the socket. /// /// Returns how many bytes were read, or an error. If no data is available, it waits @@ -115,6 +125,16 @@ impl<'a> TcpReader<'a> { } impl<'a> TcpWriter<'a> { + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when the transmit half of the full-duplex connection is open + /// (see [`may_send()`](TcpSocket::may_send)), and the transmit buffer is not full. + /// + /// This is the equivalent of [write](#method.write), without sending any data. + pub async fn wait_write_ready(&self) { + poll_fn(move |cx| self.io.poll_write_ready(cx)).await + } + /// Write data to the socket. /// /// Returns how many bytes were written, or an error. If the socket is not ready to @@ -166,7 +186,7 @@ impl<'a> TcpSocket<'a> { }); Self { - io: TcpIo { stack: stack, handle }, + io: TcpIo { stack, handle }, } } @@ -786,7 +806,7 @@ pub mod client { }; let remote_endpoint = (addr, remote.port()); let mut socket = TcpConnection::new(self.stack, self.state)?; - socket.socket.set_timeout(self.socket_timeout.clone()); + socket.socket.set_timeout(self.socket_timeout); socket .socket .connect(remote_endpoint) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 3e66d6886..24a3db91d 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -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 } @@ -161,16 +150,3 @@ embedded-storage = "0.3.1" 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 } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 6d39597c6..b55e70a36 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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() } diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index cc1cbc8a0..95fa926c3 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index b51b0c93e..fc8db856c 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 273098d9b..11a8b4dde 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 9bce38636..077a36e31 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 2acae2c8f..6ee16706d 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 94b373ab3..4a7a29229 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 09cde1ac1..6d70b763f 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 0f3d1b250..b6afbf213 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -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; diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 584f6e43c..43588eef3 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -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, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index d772c9a49..00ff5fea6 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -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, diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index b53510118..b89570dcd 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -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, diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index 8107ca175..dba3d1ef5 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -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, diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index 204446d29..7f9abdac4 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -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

+ 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)); } } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index dbc26ea3f..35b0f2e7b 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -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 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 { + 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

+ Into + 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> { #[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(|_| ()) } } // ==================== diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9d97c7be9..87bb405f4 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -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 { 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); // ==================== diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 5f565a9b7..384a1637b 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -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 = MultiBuffering; @@ -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 for u8 { +impl From 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 for bool { +impl From 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 for bool { +impl From 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 for u8 { +impl From 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(&'static RegisterBlock, PhantomData); +struct Device(pac::i2s::I2s, PhantomData); impl Device { fn new() -> Self { @@ -898,132 +880,132 @@ impl Device { #[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(&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(&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

+ 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(); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index bd53664a2..03d3ca5f7 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -11,7 +11,7 @@ #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] #[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 diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index 9b17e7da0..6973b4847 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -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)); } } diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 5160fe3c4..483d1a644 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -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 { @@ -35,16 +36,16 @@ impl interrupt::typelevel::Handler 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 for OPERATION_A { +impl From 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 for EDGE_A { +impl From 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

+ 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(); diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 0bc7f821e..3c7b96df7 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -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); } } diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 13f7dcc83..325e4ce00 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -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(reg: &T) -> Self { - Self( - unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, - PhantomData, - ) + pub(crate) fn from_reg(reg: Reg) -> 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(reg: &'d T) -> Self { - Self( - unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, - PhantomData, - ) + pub(crate) fn from_reg(reg: Reg) -> 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); diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 8ff52ece3..a1beb9dcd 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -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

+ '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

+ '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); } } diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 8e8f166d7..7f1f568f4 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -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,65 @@ 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_input(gpiovals::Input::DISCONNECT); + 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_input(gpiovals::Input::DISCONNECT); + 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_input(gpiovals::Input::DISCONNECT); + 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_input(gpiovals::Input::DISCONNECT); + 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 +204,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 +212,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 +220,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 +228,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 +236,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 +244,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 +252,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 +263,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 +274,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 +285,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 +296,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 +306,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 +478,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 +497,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 +519,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 +680,18 @@ 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()); - } - 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()); - } + for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { + if let Some(pin) = ch { + pin.set_low(); - // 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()) }); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + w.set_drive(gpiovals::Drive::S0S1); + }); + } + r.psel().out(i).write_value(ch.psel_bits()); + } let pwm = Self { _peri: _pwm, @@ -706,26 +703,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 +730,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 +759,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 +803,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 +832,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 +840,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 +848,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 +856,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 +869,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 +904,8 @@ pub trait Instance: Peripheral

+ 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 { diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 7409c9b1e..efd2a134c 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -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 { impl interrupt::typelevel::Handler for InterruptHandler { 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

+ 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(); diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index d40096edc..de9c268c1 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -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 interrupt::typelevel::Handler 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

+ 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(); diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 4f0b0641f..682ca1c79 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -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); } } } diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 298f8a574..083842f4a 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -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 }) diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 8edca1df2..251f37d3d 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -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 interrupt::typelevel::Handler 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

+ 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() } diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index ff61e08f3..7a98ab2fb 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -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 { @@ -26,7 +26,7 @@ impl interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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

+ 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(); diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index bbfa9b3b9..70bda9f70 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -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 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 for GAIN_A { +impl From 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 for REFSEL_A { +impl From 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 for RESP_A { +impl From 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

+ 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(()) } diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index e98b34369..a363e5909 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -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 interrupt::typelevel::Handler 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

+ 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(()) } diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index ed4a47713..1488c5c24 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -19,8 +19,8 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler 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 } } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 3407c9504..e39c4ed52 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -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 diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index ac5328ded..a9aeb40fa 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -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)) } } diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 187fce021..ebad39df2 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -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 interrupt::typelevel::Handler 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

+ 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(()) } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index f3eab008f..60de2ed9d 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -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 interrupt::typelevel::Handler 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 { 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

+ 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(); diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 4cf193617..2a59d029d 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -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 interrupt::typelevel::Handler 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>, +) { + 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>, +) { + 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

+ 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(); diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 8cbb1a350..52c9c532b 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -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 interrupt::typelevel::Handler 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 interrupt::typelevel::Handler 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(i: usize, buf: &mut [u8]) -> Result 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(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 { 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::(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

+ 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 { diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index a05e5aa52..7f816a5ad 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -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 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 + '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(())) diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index e4cfa3344..dfe6cbec3 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -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 { - 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. diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 72aa8f104..98f4f8943 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1054,9 +1054,17 @@ impl<'d, PIO: Instance> Common<'d, PIO> { pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); - #[cfg(feature = "_rp235x")] - pin.pad_ctrl().modify(|w| { + pin.pad_ctrl().write(|w| { + #[cfg(feature = "_rp235x")] w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + // TODO rp235x errata E9 recommends to not enable IE if we're not + // going to use input. Maybe add an API for the user to enable/disable this? + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); }); // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index c94e5e185..08f20924c 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1248,6 +1248,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, } } +impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf).map(|_| buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { fn read(&mut self) -> Result> { embedded_hal_02::serial::Read::read(&mut self.rx) @@ -1264,6 +1278,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> } } +impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf).map(|_| buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + trait SealedMode {} trait SealedInstance { diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 12d418414..0da8c374f 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -21,6 +21,10 @@ pub trait DmaCtrl { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Overrun, + /// the newly read DMA positions don't make sense compared to the previous + /// ones. This can usually only occur due to wrong Driver implementation, if + /// the driver author (or the user using raw metapac code) directly resets + /// the channel for instance. DmaUnsynced, } diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index b26f08cd9..9dd7f7d95 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -192,6 +192,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO: Carrier sense ? ECRSFD }); + // Disable multicast filter + mac.macpfr().modify(|w| w.set_pm(true)); + // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, // so the LR write must happen after the HR write. mac.maca0hr() diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 2be1a42b7..a779b8a09 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -112,10 +112,10 @@ pub enum StopMode { Stop2, } -#[cfg(any(stm32l4, stm32l5))] +#[cfg(any(stm32l4, stm32l5, stm32u5))] use stm32_metapac::pwr::vals::Lpms; -#[cfg(any(stm32l4, stm32l5))] +#[cfg(any(stm32l4, stm32l5, stm32u5))] impl Into for StopMode { fn into(self) -> Lpms { match self { @@ -184,7 +184,7 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { - #[cfg(any(stm32l4, stm32l5))] + #[cfg(any(stm32l4, stm32l5, stm32u5))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 4c5239971..e25c4f3fb 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -395,7 +395,10 @@ impl<'d, T: Instance> Ltdc<'d, T> { // framebuffer pitch and line length layer.cfblr().modify(|w| { w.set_cfbp(width * bytes_per_pixel); + #[cfg(not(stm32u5))] w.set_cfbll(width * bytes_per_pixel + 7); + #[cfg(stm32u5)] + w.set_cfbll(width * bytes_per_pixel + 3); }); // framebuffer line number diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 1dfd0e918..49836aa57 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -202,6 +202,21 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { } fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option) { + match (transaction.address, transaction.awidth) { + (Some(_), QspiWidth::NONE) => panic!("QSPI address can't be sent with an address width of NONE"), + (Some(_), _) => {} + (None, QspiWidth::NONE) => {} + (None, _) => panic!("QSPI address is not set, so the address width should be NONE"), + } + + match (data_len, transaction.dwidth) { + (Some(0), _) => panic!("QSPI data must be at least one byte"), + (Some(_), QspiWidth::NONE) => panic!("QSPI data can't be sent with a data width of NONE"), + (Some(_), _) => {} + (None, QspiWidth::NONE) => {} + (None, _) => panic!("QSPI data is empty, so the data width should be NONE"), + } + T::REGS.fcr().modify(|v| { v.set_csmf(true); v.set_ctcf(true); @@ -353,6 +368,21 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { /// Blocking read data, using DMA. pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { + let transfer = self.start_read_transfer(transaction, buf); + transfer.blocking_wait(); + } + + /// Async read data, using DMA. + pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { + let transfer = self.start_read_transfer(transaction, buf); + transfer.await; + } + + fn start_read_transfer<'a>( + &'a mut self, + transaction: TransferConfig, + buf: &'a mut [u8], + ) -> crate::dma::Transfer<'a> { self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); T::REGS.ccr().modify(|v| { @@ -373,12 +403,22 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); + transfer } /// Blocking write data, using DMA. pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { + let transfer = self.start_write_transfer(transaction, buf); + transfer.blocking_wait(); + } + + /// Async write data, using DMA. + pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { + let transfer = self.start_write_transfer(transaction, buf); + transfer.await; + } + + fn start_write_transfer<'a>(&'a mut self, transaction: TransferConfig, buf: &'a [u8]) -> crate::dma::Transfer<'a> { self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); T::REGS.ccr().modify(|v| { @@ -395,8 +435,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); + transfer } } diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index 875eaa639..bba359f31 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +79,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -219,12 +219,21 @@ impl Rtc { pub(crate) fn enable_wakeup_line(&self) { use crate::interrupt::typelevel::Interrupt; - use crate::pac::EXTI; ::WakeupInterrupt::unpend(); unsafe { ::WakeupInterrupt::enable() }; - EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + #[cfg(not(stm32u5))] + { + use crate::pac::EXTI; + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + } + #[cfg(stm32u5)] + { + use crate::pac::RCC; + RCC.srdamr().modify(|w| w.set_rtcapbamen(true)); + RCC.apb3smenr().modify(|w| w.set_rtcapbsmen(true)); + } } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index fe57cfe66..3722d11ab 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -285,6 +285,7 @@ trait SealedInstance { const BACKUP_REGISTER_COUNT: usize; #[cfg(feature = "low-power")] + #[cfg(not(stm32u5))] const EXTI_WAKEUP_LINE: usize; #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 02fd5272e..12cb10bc7 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -140,6 +140,8 @@ impl SealedInstance for crate::peripherals::RTC { } else if #[cfg(any(stm32l5, stm32h5))] { const EXTI_WAKEUP_LINE: usize = 17; type WakeupInterrupt = crate::interrupt::typelevel::RTC; + } else if #[cfg(stm32u5)] { + type WakeupInterrupt = crate::interrupt::typelevel::RTC; } ); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index eb2399d9c..a791ac2a9 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -5,6 +5,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; +use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; @@ -262,3 +263,20 @@ impl embedded_io_async::Read for RingBufferedUartRx<'_> { self.read(buf).await } } + +impl ReadReady for RingBufferedUartRx<'_> { + fn read_ready(&mut self) -> Result { + let len = self.ring_buf.len().map_err(|e| match e { + crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun, + crate::dma::ringbuffer::Error::DmaUnsynced => { + error!( + "Ringbuffer error: DmaUNsynced, driver implementation is + probably bugged please open an issue" + ); + // we report this as overrun since its recoverable in the same way + Self::Error::Overrun + } + })?; + Ok(len > 0) + } +} diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 8000a9dcb..12f40b9b9 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -109,12 +109,20 @@ pub trait Driver: Send + Sync + 'static { /// Try allocating an alarm handle. Returns None if no alarms left. /// Initially the alarm has no callback set, and a null `ctx` pointer. /// + /// The allocated alarm is a reusable resource and can be used multiple times. + /// Once the alarm has fired, it remains allocated and can be set again without needing + /// to be reallocated. + /// /// # Safety /// It is UB to make the alarm fire before setting a callback. unsafe fn allocate_alarm(&self) -> Option; /// Set the callback function to be called when the alarm triggers. /// The callback may be called from any context (interrupt or thread mode). + /// + /// The callback is maintained after the alarm has fired. Callers do not need + /// to set a callback again before setting another alarm, unless they want to + /// change the callback function or context. fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); /// Set an alarm at the given timestamp. diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 11188b4ef..29c102f10 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -3,6 +3,7 @@ #![warn(missing_docs)] use core::fmt::Write as _; +use core::future::Future; use embassy_futures::join::join; use embassy_sync::pipe::Pipe; @@ -13,6 +14,25 @@ use log::{Metadata, Record}; type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +/// A trait that can be implemented and then passed to the +pub trait ReceiverHandler { + /// Data comes in from the serial port with each command and runs this function + fn handle_data(&self, data: &[u8]) -> impl Future + Send; + + /// Create a new instance of the Handler + fn new() -> Self; +} + +/// Use this Handler if you don't wish to use any handler +pub struct DummyHandler; + +impl ReceiverHandler for DummyHandler { + async fn handle_data(&self, _data: &[u8]) {} + fn new() -> Self { + Self {} + } +} + /// The logger state containing buffers that must live as long as the USB peripheral. pub struct LoggerState<'d> { state: State<'d>, @@ -39,17 +59,19 @@ impl<'d> LoggerState<'d> { pub const MAX_PACKET_SIZE: u8 = 64; /// The logger handle, which contains a pipe with configurable size for buffering log messages. -pub struct UsbLogger { +pub struct UsbLogger { buffer: Pipe, custom_style: Option) -> ()>, + recieve_handler: Option, } -impl UsbLogger { +impl UsbLogger { /// Create a new logger instance. pub const fn new() -> Self { Self { buffer: Pipe::new(), custom_style: None, + recieve_handler: None, } } @@ -58,9 +80,15 @@ impl UsbLogger { Self { buffer: Pipe::new(), custom_style: Some(custom_style), + recieve_handler: None, } } + /// Add a command handler to the logger + pub fn with_handler(&mut self, handler: T) { + self.recieve_handler = Some(handler); + } + /// Run the USB logger using the state and USB driver. Never returns. pub async fn run<'d, D>(&'d self, state: &'d mut LoggerState<'d>, driver: D) -> ! where @@ -118,15 +146,22 @@ impl UsbLogger { } } }; - let discard_fut = async { - let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + let reciever_fut = async { + let mut reciever_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; receiver.wait_connection().await; loop { - let _ = receiver.read_packet(&mut discard_buf).await; + let n = receiver.read_packet(&mut reciever_buf).await.unwrap(); + match &self.recieve_handler { + Some(handler) => { + let data = &reciever_buf[..n]; + handler.handle_data(data).await; + } + None => (), + } } }; - join(log_fut, discard_fut).await; + join(log_fut, reciever_fut).await; } /// Creates the futures needed for the logger from a given class @@ -142,7 +177,7 @@ impl UsbLogger { } } -impl log::Log for UsbLogger { +impl log::Log for UsbLogger { fn enabled(&self, _metadata: &Metadata) -> bool { true } @@ -182,7 +217,7 @@ impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { /// Initialize and run the USB serial logger, never returns. /// -/// Arguments specify the buffer size, log level and the USB driver, respectively. +/// Arguments specify the buffer size, log level and the USB driver, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -196,17 +231,27 @@ impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { #[macro_export] macro_rules! run { ( $x:expr, $l:expr, $p:ident ) => { - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::new(); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; }; + + ( $x:expr, $l:expr, $p:ident, $h:ty ) => { + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = ::embassy_usb_logger::UsbLogger::new(); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; + } + }; } /// Initialize the USB serial logger from a serial class and return the future to run it. /// -/// Arguments specify the buffer size, log level and the serial class, respectively. +/// Arguments specify the buffer size, log level and the serial class, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -220,19 +265,29 @@ macro_rules! run { #[macro_export] macro_rules! with_class { ( $x:expr, $l:expr, $p:ident ) => {{ - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::new(); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } LOGGER.create_future_from_class($p) }}; + + ( $x:expr, $l:expr, $p:ident, $h:ty ) => {{ + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = ::embassy_usb_logger::UsbLogger::new(); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + LOGGER.create_future_from_class($p) + } + }}; } /// Initialize the USB serial logger from a serial class and return the future to run it. /// This version of the macro allows for a custom style function to be passed in. /// The custom style function will be called for each log record and is responsible for writing the log message to the buffer. /// -/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. +/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -250,10 +305,21 @@ macro_rules! with_class { #[macro_export] macro_rules! with_custom_style { ( $x:expr, $l:expr, $p:ident, $s:expr ) => {{ - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::with_custom_style($s); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::with_custom_style($s); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } LOGGER.create_future_from_class($p) }}; + + ( $x:expr, $l:expr, $p:ident, $s:expr, $h:ty ) => {{ + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = + ::embassy_usb_logger::UsbLogger::with_custom_style($s); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + LOGGER.create_future_from_class($p) + } + }}; } diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 67c700437..b849a0df3 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index b07adac1f..82364ded8 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index e33ee5866..3b752fd16 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 8076ac283..3f13a014e 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index 02048e692..30fe103ad 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 895cca8b9..05b5f0ec9 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index c6675a3d3..7c07158e0 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -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)); diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs index ede88cc26..0d9ee3cf8 100644 --- a/examples/nrf52840/src/bin/wdt.rs +++ b/examples/nrf52840/src/bin/wdt.rs @@ -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, diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 6a2c99716..b55b20c63 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -37,10 +37,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" panic-probe = { version = "0.3", features = ["print-defmt"] } -display-interface-spi = "0.4.1" -embedded-graphics = "0.7.1" -st7789 = "0.6.1" -display-interface = "0.4.1" +display-interface-spi = "0.5.0" +embedded-graphics = "0.8.1" +mipidsi = "0.8.0" +display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.4.0" heapless = "0.8" diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index e937b9d0a..dd114a4ae 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -9,11 +9,12 @@ use core::cell::RefCell; use defmt::*; +use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; -use embassy_rp::spi::{Blocking, Spi}; +use embassy_rp::spi::Spi; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Delay; @@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -use st7789::{Orientation, ST7789}; +use mipidsi::models::ST7789; +use mipidsi::options::{Orientation, Rotation}; +use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; -use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; @@ -58,7 +60,7 @@ async fn main(_spawner: Spawner) { touch_config.phase = spi::Phase::CaptureOnSecondTransition; touch_config.polarity = spi::Polarity::IdleHigh; - let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); + let spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); @@ -74,17 +76,15 @@ async fn main(_spawner: Spawner) { let _bl = Output::new(bl, Level::High); // display interface abstraction from SPI and DC - let di = SPIDeviceInterface::new(display_spi, dcx); - - // create driver - let mut display = ST7789::new(di, rst, 240, 320); - - // initialize - display.init(&mut Delay).unwrap(); - - // set default orientation - display.set_orientation(Orientation::Landscape).unwrap(); + let di = SPIInterface::new(display_spi, dcx); + // Define the display from the display interface and initialize it + let mut display = Builder::new(ST7789, di) + .display_size(240, 320) + .reset_pin(rst) + .orientation(Orientation::new().rotate(Rotation::Deg90)) + .init(&mut Delay) + .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); @@ -175,138 +175,3 @@ mod touch { } } } - -mod my_display_interface { - use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::SpiDevice; - - /// SPI display interface. - /// - /// This combines the SPI peripheral and a data/command pin - pub struct SPIDeviceInterface { - spi: SPI, - dc: DC, - } - - impl SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - /// Create new SPI interface for communciation with a display driver - pub fn new(spi: SPI, dc: DC) -> Self { - Self { spi, dc } - } - } - - impl WriteOnlyDataCommand for SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_low().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - - fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_high().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - } - - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { - match words { - DataFormat::U8(slice) => spi.write(slice), - DataFormat::U16(slice) => { - use byte_slice_cast::*; - spi.write(slice.as_byte_slice()) - } - DataFormat::U16LE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_le(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U16BE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_be(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U8Iter(iter) => { - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.into_iter() { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf)?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i])?; - } - - Ok(()) - } - DataFormat::U16LEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.map(u16::to_le) { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - DataFormat::U16BEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 64]; - let mut i = 0; - let len = buf.len(); - - for v in iter.map(u16::to_be) { - buf[i] = v; - i += 1; - - if i == len { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - _ => unimplemented!(), - } - } -} diff --git a/examples/rp/src/bin/usb_serial_with_handler.rs b/examples/rp/src/bin/usb_serial_with_handler.rs new file mode 100644 index 000000000..a9e65be70 --- /dev/null +++ b/examples/rp/src/bin/usb_serial_with_handler.rs @@ -0,0 +1,64 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates the possibility to send log::info/warn/error/debug! to USB serial port. + +#![no_std] +#![no_main] + +use core::str; + +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::rom_data::reset_to_usb_boot; +use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_time::Timer; +use embassy_usb_logger::ReceiverHandler; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +struct Handler; + +impl ReceiverHandler for Handler { + async fn handle_data(&self, data: &[u8]) { + if let Ok(data) = str::from_utf8(data) { + let data = data.trim(); + + // If you are using elf2uf2-term with the '-t' flag, then when closing the serial monitor, + // this will automatically put the pico into boot mode + if data == "q" || data == "elf2uf2-term" { + reset_to_usb_boot(0, 0); // Restart the chip + } else if data.eq_ignore_ascii_case("hello") { + log::info!("World!"); + } else { + log::info!("Recieved: {:?}", data); + } + } + } + + fn new() -> Self { + Self + } +} + +#[embassy_executor::task] +async fn logger_task(driver: Driver<'static, USB>) { + embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver, Handler); +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let driver = Driver::new(p.USB, Irqs); + spawner.spawn(logger_task(driver)).unwrap(); + + let mut counter = 0; + loop { + counter += 1; + log::info!("Tick {}", counter); + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 5527a1e0a..eec12a9ab 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -38,10 +38,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" panic-probe = { version = "0.3", features = ["print-defmt"] } -display-interface-spi = "0.4.1" -embedded-graphics = "0.7.1" -st7789 = "0.6.1" -display-interface = "0.4.1" +display-interface-spi = "0.5.0" +embedded-graphics = "0.8.1" +mipidsi = "0.8.0" +display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" heapless = "0.8" diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 195db5a97..6b7c0781f 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -1,4 +1,4 @@ -//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2350 chip. //! //! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch //! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8) @@ -9,6 +9,7 @@ use core::cell::RefCell; use defmt::*; +use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; @@ -25,14 +26,15 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -use st7789::{Orientation, ST7789}; +use mipidsi::models::ST7789; +use mipidsi::options::{Orientation, Rotation}; +use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; @@ -79,17 +81,15 @@ async fn main(_spawner: Spawner) { let _bl = Output::new(bl, Level::High); // display interface abstraction from SPI and DC - let di = SPIDeviceInterface::new(display_spi, dcx); - - // create driver - let mut display = ST7789::new(di, rst, 240, 320); - - // initialize - display.init(&mut Delay).unwrap(); - - // set default orientation - display.set_orientation(Orientation::Landscape).unwrap(); + let di = SPIInterface::new(display_spi, dcx); + // Define the display from the display interface and initialize it + let mut display = Builder::new(ST7789, di) + .display_size(240, 320) + .reset_pin(rst) + .orientation(Orientation::new().rotate(Rotation::Deg90)) + .init(&mut Delay) + .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); @@ -180,138 +180,3 @@ mod touch { } } } - -mod my_display_interface { - use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::SpiDevice; - - /// SPI display interface. - /// - /// This combines the SPI peripheral and a data/command pin - pub struct SPIDeviceInterface { - spi: SPI, - dc: DC, - } - - impl SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - /// Create new SPI interface for communciation with a display driver - pub fn new(spi: SPI, dc: DC) -> Self { - Self { spi, dc } - } - } - - impl WriteOnlyDataCommand for SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_low().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - - fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_high().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - } - - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { - match words { - DataFormat::U8(slice) => spi.write(slice), - DataFormat::U16(slice) => { - use byte_slice_cast::*; - spi.write(slice.as_byte_slice()) - } - DataFormat::U16LE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_le(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U16BE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_be(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U8Iter(iter) => { - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.into_iter() { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf)?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i])?; - } - - Ok(()) - } - DataFormat::U16LEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.map(u16::to_le) { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - DataFormat::U16BEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 64]; - let mut i = 0; - let len = buf.len(); - - for v in iter.map(u16::to_be) { - buf[i] = v; - i += 1; - - if i == len { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - _ => unimplemented!(), - } - } -} diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml index 36c5b63a6..bdbd86354 100644 --- a/examples/stm32u5/.cargo/config.toml +++ b/examples/stm32u5/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32U585AIIx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32U585AIIx" +# replace STM32U5G9ZJTxQ with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32U5G9ZJTxQ" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index ad7db4c32..8b576425c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -# Change stm32u585ai to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } +# Change stm32u5g9zj to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } @@ -21,6 +21,8 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } +embedded-graphics = { version = "0.8.1" } +tinybmp = { version = "0.6.0" } micromath = "2.0.0" diff --git a/examples/stm32u5/src/bin/ferris.bmp b/examples/stm32u5/src/bin/ferris.bmp new file mode 100644 index 000000000..7a222ab84 Binary files /dev/null and b/examples/stm32u5/src/bin/ferris.bmp differ diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs index 19a78eac9..d5f5d6f60 100644 --- a/examples/stm32u5/src/bin/i2c.rs +++ b/examples/stm32u5/src/bin/i2c.rs @@ -13,7 +13,7 @@ const WHOAMI: u8 = 0x0F; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default()); + let mut i2c = I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default()); let mut data = [0u8; 1]; unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs new file mode 100644 index 000000000..bd59a9148 --- /dev/null +++ b/examples/stm32u5/src/bin/ltdc.rs @@ -0,0 +1,461 @@ +#![no_std] +#![no_main] +#![macro_use] +#![allow(static_mut_refs)] + +/// This example was derived from examples\stm32h735\src\bin\ltdc.rs +/// It demonstrates the LTDC lcd display peripheral and was tested on an STM32U5G9J-DK2 demo board (embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ") +/// +use bouncy_box::BouncyBox; +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::{Duration, Timer}; +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::geometry::{OriginDimensions, Point, Size}; +use embedded_graphics::image::Image; +use embedded_graphics::pixelcolor::raw::RawU24; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::Rectangle; +use embedded_graphics::Pixel; +use heapless::{Entry, FnvIndexMap}; +use tinybmp::Bmp; +use {defmt_rtt as _, panic_probe as _}; + +const DISPLAY_WIDTH: usize = 800; +const DISPLAY_HEIGHT: usize = 480; +const MY_TASK_POOL_SIZE: usize = 2; + +// the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu +pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; +pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; + +bind_interrupts!(struct Irqs { + LTDC => ltdc::InterruptHandler; +}); + +const NUM_COLORS: usize = 256; + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = rcc_setup::stm32u5g9zj_init(); + + // enable ICACHE + embassy_stm32::pac::ICACHE.cr().write(|w| { + w.set_en(true); + }); + + // blink the led on another task + let led = Output::new(p.PD2, Level::High, Speed::Low); + unwrap!(spawner.spawn(led_task(led))); + + // numbers from STM32U5G9J-DK2.ioc + const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization + const RK050HR18H_HBP: u16 = 8; // Horizontal back porch + const RK050HR18H_HFP: u16 = 8; // Horizontal front porch + const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization + const RK050HR18H_VBP: u16 = 8; // Vertical back porch + const RK050HR18H_VFP: u16 = 8; // Vertical front porch + + // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization + let ltdc_config = LtdcConfiguration { + active_width: DISPLAY_WIDTH as _, + active_height: DISPLAY_HEIGHT as _, + h_back_porch: RK050HR18H_HBP, + h_front_porch: RK050HR18H_HFP, + v_back_porch: RK050HR18H_VBP, + v_front_porch: RK050HR18H_VFP, + h_sync: RK050HR18H_HSYNC, + v_sync: RK050HR18H_VSYNC, + h_sync_polarity: PolarityActive::ActiveHigh, + v_sync_polarity: PolarityActive::ActiveHigh, + data_enable_polarity: PolarityActive::ActiveHigh, + pixel_clock_polarity: PolarityEdge::RisingEdge, + }; + + info!("init ltdc"); + let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High); + let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High); + let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High); + let mut ltdc = Ltdc::new_with_pins( + p.LTDC, // PERIPHERAL + Irqs, // IRQS + p.PD3, // CLK + p.PE0, // HSYNC + p.PD13, // VSYNC + p.PB9, // B0 + p.PB2, // B1 + p.PD14, // B2 + p.PD15, // B3 + p.PD0, // B4 + p.PD1, // B5 + p.PE7, // B6 + p.PE8, // B7 + p.PC8, // G0 + p.PC9, // G1 + p.PE9, // G2 + p.PE10, // G3 + p.PE11, // G4 + p.PE12, // G5 + p.PE13, // G6 + p.PE14, // G7 + p.PC6, // R0 + p.PC7, // R1 + p.PE15, // R2 + p.PD8, // R3 + p.PD9, // R4 + p.PD10, // R5 + p.PD11, // R6 + p.PD12, // R7 + ); + ltdc.init(<dc_config); + ltdc_de.set_low(); + ltdc_bl_ctrl.set_high(); + ltdc_disp_ctrl.set_high(); + + // we only need to draw on one layer for this example (not to be confused with the double buffer) + info!("enable bottom layer"); + let layer_config = LtdcLayerConfig { + pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel + layer: LtdcLayer::Layer1, + window_x0: 0, + window_x1: DISPLAY_WIDTH as _, + window_y0: 0, + window_y1: DISPLAY_HEIGHT as _, + }; + + let ferris_bmp: Bmp = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap(); + let color_map = build_color_lookup_map(&ferris_bmp); + let clut = build_clut(&color_map); + + // enable the bottom layer with a 256 color lookup table + ltdc.init_layer(&layer_config, Some(&clut)); + + // Safety: the DoubleBuffer controls access to the statically allocated frame buffers + // and it is the only thing that mutates their content + let mut double_buffer = DoubleBuffer::new( + unsafe { FB1.as_mut() }, + unsafe { FB2.as_mut() }, + layer_config, + color_map, + ); + + // this allows us to perform some simple animation for every frame + let mut bouncy_box = BouncyBox::new( + ferris_bmp.bounding_box(), + Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)), + 2, + ); + + loop { + // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen + double_buffer.clear(); + let position = bouncy_box.next_point(); + let ferris = Image::new(&ferris_bmp, position); + unwrap!(ferris.draw(&mut double_buffer)); + + // perform async dma data transfer to the lcd screen + unwrap!(double_buffer.swap(&mut ltdc).await); + } +} + +/// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work. +fn build_color_lookup_map(bmp: &Bmp) -> FnvIndexMap { + let mut color_map: FnvIndexMap = heapless::FnvIndexMap::new(); + let mut counter: u8 = 0; + + // add black to position 0 + color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap(); + counter += 1; + + for Pixel(_point, color) in bmp.pixels() { + let raw = color.into_storage(); + if let Entry::Vacant(v) = color_map.entry(raw) { + v.insert(counter).expect("more than 256 colors detected"); + counter += 1; + } + } + color_map +} + +/// builds the color look-up table from the color map provided +fn build_clut(color_map: &FnvIndexMap) -> [ltdc::RgbColor; NUM_COLORS] { + let mut clut = [ltdc::RgbColor::default(); NUM_COLORS]; + for (color, index) in color_map.iter() { + let color = Rgb888::from(RawU24::new(*color)); + clut[*index as usize] = ltdc::RgbColor { + red: color.r(), + green: color.g(), + blue: color.b(), + }; + } + + clut +} + +#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)] +async fn led_task(mut led: Output<'static>) { + let mut counter = 0; + loop { + info!("blink: {}", counter); + counter += 1; + + // on + led.set_low(); + Timer::after(Duration::from_millis(50)).await; + + // off + led.set_high(); + Timer::after(Duration::from_millis(450)).await; + } +} + +pub type TargetPixelType = u8; + +// A simple double buffer +pub struct DoubleBuffer { + buf0: &'static mut [TargetPixelType], + buf1: &'static mut [TargetPixelType], + is_buf0: bool, + layer_config: LtdcLayerConfig, + color_map: FnvIndexMap, +} + +impl DoubleBuffer { + pub fn new( + buf0: &'static mut [TargetPixelType], + buf1: &'static mut [TargetPixelType], + layer_config: LtdcLayerConfig, + color_map: FnvIndexMap, + ) -> Self { + Self { + buf0, + buf1, + is_buf0: true, + layer_config, + color_map, + } + } + + pub fn current(&mut self) -> (&FnvIndexMap, &mut [TargetPixelType]) { + if self.is_buf0 { + (&self.color_map, self.buf0) + } else { + (&self.color_map, self.buf1) + } + } + + pub async fn swap(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> { + let (_, buf) = self.current(); + let frame_buffer = buf.as_ptr(); + self.is_buf0 = !self.is_buf0; + ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await + } + + /// Clears the buffer + pub fn clear(&mut self) { + let (color_map, buf) = self.current(); + let black = Rgb888::new(0, 0, 0).into_storage(); + let color_index = color_map.get(&black).expect("no black found in the color map"); + + for a in buf.iter_mut() { + *a = *color_index; // solid black + } + } +} + +// Implement DrawTarget for +impl DrawTarget for DoubleBuffer { + type Color = Rgb888; + type Error = (); + + /// Draw a pixel + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + let size = self.size(); + let width = size.width as i32; + let height = size.height as i32; + let (color_map, buf) = self.current(); + + for pixel in pixels { + let Pixel(point, color) = pixel; + + if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height { + let index = point.y * width + point.x; + let raw_color = color.into_storage(); + + match color_map.get(&raw_color) { + Some(x) => { + buf[index as usize] = *x; + } + None => panic!("color not found in color map: {}", raw_color), + }; + } else { + // Ignore invalid points + } + } + + Ok(()) + } +} + +impl OriginDimensions for DoubleBuffer { + /// Return the size of the display + fn size(&self) -> Size { + Size::new( + (self.layer_config.window_x1 - self.layer_config.window_x0) as _, + (self.layer_config.window_y1 - self.layer_config.window_y0) as _, + ) + } +} + +mod rcc_setup { + + use embassy_stm32::time::Hertz; + use embassy_stm32::{rcc, Config, Peripherals}; + + /// Sets up clocks for the stm32u5g9zj mcu + /// change this if you plan to use a different microcontroller + pub fn stm32u5g9zj_init() -> Peripherals { + // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator + let mut config = Config::default(); + config.rcc.hse = Some(rcc::Hse { + freq: Hertz(16_000_000), + mode: rcc::HseMode::Oscillator, + }); + config.rcc.pll1 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV1, + mul: rcc::PllMul::MUL10, + divp: None, + divq: None, + divr: Some(rcc::PllDiv::DIV1), + }); + config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz + config.rcc.pll3 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV4, // PLL_M + mul: rcc::PllMul::MUL125, // PLL_N + divp: None, + divq: None, + divr: Some(rcc::PllDiv::DIV20), + }); + config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz + embassy_stm32::init(config) + } +} + +mod bouncy_box { + use embedded_graphics::geometry::Point; + use embedded_graphics::primitives::Rectangle; + + enum Direction { + DownLeft, + DownRight, + UpLeft, + UpRight, + } + + pub struct BouncyBox { + direction: Direction, + child_rect: Rectangle, + parent_rect: Rectangle, + current_point: Point, + move_by: usize, + } + + // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box + impl BouncyBox { + pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self { + let center_box = parent_rect.center(); + let center_img = child_rect.center(); + let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2); + Self { + direction: Direction::DownRight, + child_rect, + parent_rect, + current_point, + move_by, + } + } + + pub fn next_point(&mut self) -> Point { + let direction = &self.direction; + let img_height = self.child_rect.size.height as i32; + let box_height = self.parent_rect.size.height as i32; + let img_width = self.child_rect.size.width as i32; + let box_width = self.parent_rect.size.width as i32; + let move_by = self.move_by as i32; + + match direction { + Direction::DownLeft => { + self.current_point.x -= move_by; + self.current_point.y += move_by; + + let x_out_of_bounds = self.current_point.x < 0; + let y_out_of_bounds = (self.current_point.y + img_height) > box_height; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpRight + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::DownRight + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpLeft + } + } + Direction::DownRight => { + self.current_point.x += move_by; + self.current_point.y += move_by; + + let x_out_of_bounds = (self.current_point.x + img_width) > box_width; + let y_out_of_bounds = (self.current_point.y + img_height) > box_height; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpLeft + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::DownLeft + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpRight + } + } + Direction::UpLeft => { + self.current_point.x -= move_by; + self.current_point.y -= move_by; + + let x_out_of_bounds = self.current_point.x < 0; + let y_out_of_bounds = self.current_point.y < 0; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownRight + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::UpRight + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownLeft + } + } + Direction::UpRight => { + self.current_point.x += move_by; + self.current_point.y -= move_by; + + let x_out_of_bounds = (self.current_point.x + img_width) > box_width; + let y_out_of_bounds = self.current_point.y < 0; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownLeft + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::UpLeft + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownRight + } + } + } + + self.current_point + } + } +} diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 4d56395da..4bb1a6079 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -13,7 +13,7 @@ use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { - OTG_FS => usb::InterruptHandler; + OTG_HS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) { // to enable vbus_detection to comply with the USB spec. If you enable it, the board // has to support it or USB won't work at all. See docs on `vbus_detection` for details. config.vbus_detection = false; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); + let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index acab9d615..d0c92e655 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-10-13" +channel = "nightly-2024-11-04" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index d36ab9c67..6a710f29d 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -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" diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index 45daaae0c..cf9ca50d2 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.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; diff --git a/tests/nrf/src/bin/gpio.rs b/tests/nrf/src/bin/gpio.rs index 9e809a694..4995d244c 100644 --- a/tests/nrf/src/bin/gpio.rs +++ b/tests/nrf/src/bin/gpio.rs @@ -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()); diff --git a/tests/nrf/src/bin/spim.rs b/tests/nrf/src/bin/spim.rs new file mode 100644 index 000000000..c2ec90b88 --- /dev/null +++ b/tests/nrf/src/bin/spim.rs @@ -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(); +} diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs index ff5299b0f..c588dabf5 100644 --- a/tests/nrf/src/common.rs +++ b/tests/nrf/src/common.rs @@ -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;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[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;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[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;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[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;}, @irq UART1 = {SERIAL1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {SERIAL0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {SERIAL1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SERIAL0 => spim::InterruptHandler;}, ); #[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;}, @irq UART1 = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => spim::InterruptHandler;}, );