mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 08:12:30 +00:00
Merge branch 'fix/bootloader-async-updater' into feature/embassy-at-cmux
This commit is contained in:
commit
1097197a4e
@ -304,7 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
|
||||
/// `mark_booted`.
|
||||
pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
|
||||
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.
|
||||
|
@ -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<syn::Expr>,
|
||||
/// Use this to override the `embassy_executor` crate path. Defaults to `::embassy_executor`.
|
||||
#[darling(default)]
|
||||
embassy_executor: Option<syn::Expr>,
|
||||
}
|
||||
|
||||
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<impl Sized> #where_clause{
|
||||
#visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{
|
||||
#task_outer_body
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,8 @@ log = [ "dep:log" ]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
nrf9160-pac = { version = "0.12.0" }
|
||||
nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" }
|
||||
cortex-m = "0.7.7"
|
||||
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||
|
@ -17,12 +17,12 @@ use core::slice;
|
||||
use core::sync::atomic::{compiler_fence, fence, Ordering};
|
||||
use core::task::{Poll, Waker};
|
||||
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::pipe;
|
||||
use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration};
|
||||
use heapless::Vec;
|
||||
use pac::NVIC;
|
||||
use {embassy_net_driver_channel as ch, nrf9160_pac as pac};
|
||||
use {embassy_net_driver_channel as ch, nrf_pac as pac};
|
||||
|
||||
const RX_SIZE: usize = 8 * 1024;
|
||||
const TRACE_SIZE: usize = 16 * 1024;
|
||||
@ -38,11 +38,9 @@ static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
/// Call this function on IPC IRQ
|
||||
pub fn on_ipc_irq() {
|
||||
let ipc = unsafe { &*pac::IPC_NS::ptr() };
|
||||
|
||||
trace!("irq");
|
||||
|
||||
ipc.inten.write(|w| w);
|
||||
pac::IPC_NS.inten().write(|_| ());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
@ -135,22 +133,21 @@ async fn new_internal<'a>(
|
||||
"shmem must be in the lower 128kb of RAM"
|
||||
);
|
||||
|
||||
let spu = unsafe { &*pac::SPU_S::ptr() };
|
||||
let spu = pac::SPU_S;
|
||||
debug!("Setting IPC RAM as nonsecure...");
|
||||
let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE;
|
||||
let region_end = region_start + shmem_len / SPU_REGION_SIZE;
|
||||
for i in region_start..region_end {
|
||||
spu.ramregion[i].perm.write(|w| {
|
||||
w.execute().set_bit();
|
||||
w.write().set_bit();
|
||||
w.read().set_bit();
|
||||
w.secattr().clear_bit();
|
||||
w.lock().clear_bit();
|
||||
w
|
||||
spu.ramregion(i).perm().write(|w| {
|
||||
w.set_execute(true);
|
||||
w.set_write(true);
|
||||
w.set_read(true);
|
||||
w.set_secattr(false);
|
||||
w.set_lock(false);
|
||||
})
|
||||
}
|
||||
|
||||
spu.periphid[42].perm.write(|w| w.secattr().non_secure());
|
||||
spu.periphid(42).perm().write(|w| w.set_secattr(false));
|
||||
|
||||
let mut alloc = Allocator {
|
||||
start: shmem_ptr,
|
||||
@ -158,8 +155,8 @@ async fn new_internal<'a>(
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
let ipc = unsafe { &*pac::IPC_NS::ptr() };
|
||||
let power = unsafe { &*pac::POWER_S::ptr() };
|
||||
let ipc = pac::IPC_NS;
|
||||
let power = pac::POWER_S;
|
||||
|
||||
let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() });
|
||||
let rx = alloc.alloc_bytes(RX_SIZE);
|
||||
@ -177,20 +174,20 @@ async fn new_internal<'a>(
|
||||
cb.trace.base = trace.as_mut_ptr() as _;
|
||||
cb.trace.size = TRACE_SIZE;
|
||||
|
||||
ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) });
|
||||
ipc.gpmem[1].write(|w| unsafe { w.bits(0) });
|
||||
ipc.gpmem(0).write_value(cb as *mut _ as u32);
|
||||
ipc.gpmem(1).write_value(0);
|
||||
|
||||
// connect task/event i to channel i
|
||||
for i in 0..8 {
|
||||
ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) });
|
||||
ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) });
|
||||
ipc.send_cnf(i).write(|w| w.0 = 1 << i);
|
||||
ipc.receive_cnf(i).write(|w| w.0 = 1 << i);
|
||||
}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
// POWER.LTEMODEM.STARTN = 0
|
||||
// The reg is missing in the PAC??
|
||||
let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) };
|
||||
let startn = unsafe { (power.as_ptr() as *mut u32).add(0x610 / 4) };
|
||||
unsafe { startn.write_volatile(0) }
|
||||
|
||||
unsafe { NVIC::unmask(pac::Interrupt::IPC) };
|
||||
@ -322,15 +319,15 @@ struct StateInner {
|
||||
impl StateInner {
|
||||
fn poll(&mut self, trace_writer: &mut Option<TraceWriter<'_>>, ch: &mut ch::Runner<MTU>) {
|
||||
trace!("poll!");
|
||||
let ipc = unsafe { &*pac::IPC_NS::ptr() };
|
||||
let ipc = pac::IPC_NS;
|
||||
|
||||
if ipc.events_receive[0].read().bits() != 0 {
|
||||
ipc.events_receive[0].reset();
|
||||
if ipc.events_receive(0).read() != 0 {
|
||||
ipc.events_receive(0).write_value(0);
|
||||
trace!("ipc 0");
|
||||
}
|
||||
|
||||
if ipc.events_receive[2].read().bits() != 0 {
|
||||
ipc.events_receive[2].reset();
|
||||
if ipc.events_receive(2).read() != 0 {
|
||||
ipc.events_receive(2).write_value(0);
|
||||
trace!("ipc 2");
|
||||
|
||||
if !self.init {
|
||||
@ -353,8 +350,8 @@ impl StateInner {
|
||||
}
|
||||
}
|
||||
|
||||
if ipc.events_receive[4].read().bits() != 0 {
|
||||
ipc.events_receive[4].reset();
|
||||
if ipc.events_receive(4).read() != 0 {
|
||||
ipc.events_receive(4).write_value(0);
|
||||
trace!("ipc 4");
|
||||
|
||||
loop {
|
||||
@ -368,13 +365,13 @@ impl StateInner {
|
||||
}
|
||||
}
|
||||
|
||||
if ipc.events_receive[6].read().bits() != 0 {
|
||||
ipc.events_receive[6].reset();
|
||||
if ipc.events_receive(6).read() != 0 {
|
||||
ipc.events_receive(6).write_value(0);
|
||||
trace!("ipc 6");
|
||||
}
|
||||
|
||||
if ipc.events_receive[7].read().bits() != 0 {
|
||||
ipc.events_receive[7].reset();
|
||||
if ipc.events_receive(7).read() != 0 {
|
||||
ipc.events_receive(7).write_value(0);
|
||||
trace!("ipc 7: trace");
|
||||
|
||||
let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() };
|
||||
@ -437,13 +434,12 @@ impl StateInner {
|
||||
}
|
||||
}
|
||||
|
||||
ipc.intenset.write(|w| {
|
||||
w.receive0().set_bit();
|
||||
w.receive2().set_bit();
|
||||
w.receive4().set_bit();
|
||||
w.receive6().set_bit();
|
||||
w.receive7().set_bit();
|
||||
w
|
||||
ipc.intenset().write(|w| {
|
||||
w.set_receive0(true);
|
||||
w.set_receive2(true);
|
||||
w.set_receive4(true);
|
||||
w.set_receive6(true);
|
||||
w.set_receive7(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -546,8 +542,8 @@ impl StateInner {
|
||||
unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) }
|
||||
self.tx_seq_no = self.tx_seq_no.wrapping_add(1);
|
||||
|
||||
let ipc = unsafe { &*pac::IPC_NS::ptr() };
|
||||
ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) });
|
||||
let ipc = pac::IPC_NS;
|
||||
ipc.tasks_send(ipc_ch).write_value(1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
@ -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<R>(&self, f: impl FnOnce(&Inner) -> R) -> R {
|
||||
f(&*self.inner.borrow())
|
||||
f(&self.inner.borrow())
|
||||
}
|
||||
|
||||
fn with_mut<R>(&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::<dhcpv4::Socket>(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() {
|
||||
|
@ -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.`
|
||||
|
@ -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)
|
||||
|
@ -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 }
|
||||
|
@ -17,16 +17,17 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use pac::uarte::vals;
|
||||
// Re-export SVD variants to allow user to directly set values
|
||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||
pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity};
|
||||
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin};
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::ppi::{
|
||||
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
|
||||
};
|
||||
use crate::timer::{Instance as TimerInstance, Timer};
|
||||
use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance};
|
||||
use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance};
|
||||
use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE};
|
||||
|
||||
pub(crate) struct State {
|
||||
@ -79,57 +80,57 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
let buf_len = s.rx_buf.len();
|
||||
let half_len = buf_len / 2;
|
||||
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
let errs = r.errorsrc.read();
|
||||
r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
let errs = r.errorsrc().read();
|
||||
r.errorsrc().write_value(errs);
|
||||
|
||||
if errs.overrun().bit() {
|
||||
if errs.overrun() {
|
||||
panic!("BufferedUarte overrun");
|
||||
}
|
||||
}
|
||||
|
||||
// Received some bytes, wake task.
|
||||
if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.rxdrdy().clear());
|
||||
r.events_rxdrdy.reset();
|
||||
if r.inten().read().rxdrdy() && r.events_rxdrdy().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_rxdrdy(true));
|
||||
r.events_rxdrdy().write_value(0);
|
||||
ss.rx_waker.wake();
|
||||
}
|
||||
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
if r.events_endrx().read() != 0 {
|
||||
//trace!(" irq_rx: endrx");
|
||||
r.events_endrx.reset();
|
||||
r.events_endrx().write_value(0);
|
||||
|
||||
let val = s.rx_ended_count.load(Ordering::Relaxed);
|
||||
s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
|
||||
}
|
||||
|
||||
if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) {
|
||||
if r.events_rxstarted().read() != 0 || !s.rx_started.load(Ordering::Relaxed) {
|
||||
//trace!(" irq_rx: rxstarted");
|
||||
let (ptr, len) = rx.push_buf();
|
||||
if len >= half_len {
|
||||
r.events_rxstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
|
||||
//trace!(" irq_rx: starting second {:?}", half_len);
|
||||
|
||||
// Set up the DMA read
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
|
||||
r.rxd().ptr().write_value(ptr as u32);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(half_len as _));
|
||||
|
||||
let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
|
||||
|
||||
// Enable endrx -> startrx PPI channel.
|
||||
// From this point on, if endrx happens, startrx is automatically fired.
|
||||
ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
|
||||
ppi::regs().chenset().write(|w| w.0 = 1 << chn);
|
||||
|
||||
// It is possible that endrx happened BEFORE enabling the PPI. In this case
|
||||
// the PPI channel doesn't trigger, and we'd hang. We have to detect this
|
||||
// and manually start.
|
||||
|
||||
// check again in case endrx has happened between the last check and now.
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
if r.events_endrx().read() != 0 {
|
||||
//trace!(" irq_rx: endrx");
|
||||
r.events_endrx.reset();
|
||||
r.events_endrx().write_value(0);
|
||||
|
||||
let val = s.rx_ended_count.load(Ordering::Relaxed);
|
||||
s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
|
||||
@ -144,7 +145,7 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
|
||||
// Check if the PPI channel is still enabled. The PPI channel disables itself
|
||||
// when it fires, so if it's still enabled it hasn't fired.
|
||||
let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0;
|
||||
let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _);
|
||||
|
||||
// if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed.
|
||||
// this condition also naturally matches if `!started`, needed to kickstart the DMA.
|
||||
@ -152,10 +153,10 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
//trace!("manually starting.");
|
||||
|
||||
// disable the ppi ch, it's of no use anymore.
|
||||
ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) });
|
||||
ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true));
|
||||
|
||||
// manually start
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
}
|
||||
|
||||
rx.push_done(half_len);
|
||||
@ -164,7 +165,7 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
s.rx_started.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
//trace!(" irq_rx: rxstarted no buf");
|
||||
r.intenclr.write(|w| w.rxstarted().clear());
|
||||
r.intenclr().write(|w| w.set_rxstarted(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -173,8 +174,8 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
|
||||
if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } {
|
||||
// TX end
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
r.events_endtx.reset();
|
||||
if r.events_endtx().read() != 0 {
|
||||
r.events_endtx().write_value(0);
|
||||
|
||||
let n = s.tx_count.load(Ordering::Relaxed);
|
||||
//trace!(" irq_tx: endtx {:?}", n);
|
||||
@ -192,11 +193,11 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
||||
s.tx_count.store(len, Ordering::Relaxed);
|
||||
|
||||
// Set up the DMA write
|
||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.txd().ptr().write_value(ptr as u32);
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
// Start UARTE Transmit transaction
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,7 +309,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer);
|
||||
let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
|
||||
|
||||
U::regs().enable.write(|w| w.enable().enabled());
|
||||
U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
U::Interrupt::pend();
|
||||
unsafe { U::Interrupt::enable() };
|
||||
|
||||
@ -320,7 +321,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
/// Adjust the baud rate to the provided value.
|
||||
pub fn set_baudrate(&mut self, baudrate: Baudrate) {
|
||||
let r = U::regs();
|
||||
r.baudrate.write(|w| w.baudrate().variant(baudrate));
|
||||
r.baudrate().write(|w| w.set_baudrate(baudrate));
|
||||
}
|
||||
|
||||
/// Split the UART in reader and writer parts.
|
||||
@ -415,7 +416,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
|
||||
|
||||
let this = Self::new_innerer(peri, txd, cts, tx_buffer);
|
||||
|
||||
U::regs().enable.write(|w| w.enable().enabled());
|
||||
U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
U::Interrupt::pend();
|
||||
unsafe { U::Interrupt::enable() };
|
||||
|
||||
@ -432,14 +433,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
|
||||
) -> Self {
|
||||
let r = U::regs();
|
||||
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
}
|
||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||
configure_tx_pins(r, txd, cts);
|
||||
|
||||
// Initialize state
|
||||
let s = U::buffered_state();
|
||||
@ -447,12 +441,11 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
|
||||
let len = tx_buffer.len();
|
||||
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
r.events_txstarted.reset();
|
||||
r.events_txstarted().write_value(0);
|
||||
|
||||
// Enable interrupts
|
||||
r.intenset.write(|w| {
|
||||
w.endtx().set();
|
||||
w
|
||||
r.intenset().write(|w| {
|
||||
w.set_endtx(true);
|
||||
});
|
||||
|
||||
Self { _peri: peri }
|
||||
@ -532,15 +525,14 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> {
|
||||
fn drop(&mut self) {
|
||||
let r = U::regs();
|
||||
|
||||
r.intenclr.write(|w| {
|
||||
w.txdrdy().set_bit();
|
||||
w.txstarted().set_bit();
|
||||
w.txstopped().set_bit();
|
||||
w
|
||||
r.intenclr().write(|w| {
|
||||
w.set_txdrdy(true);
|
||||
w.set_txstarted(true);
|
||||
w.set_txstopped(true);
|
||||
});
|
||||
r.events_txstopped.reset();
|
||||
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_txstopped.read().bits() == 0 {}
|
||||
r.events_txstopped().write_value(0);
|
||||
r.tasks_stoptx().write_value(1);
|
||||
while r.events_txstopped().read() == 0 {}
|
||||
|
||||
let s = U::buffered_state();
|
||||
unsafe { s.tx_buf.deinit() }
|
||||
@ -639,7 +631,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
|
||||
let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
|
||||
|
||||
U::regs().enable.write(|w| w.enable().enabled());
|
||||
U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
U::Interrupt::pend();
|
||||
unsafe { U::Interrupt::enable() };
|
||||
|
||||
@ -663,14 +655,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
|
||||
let r = U::regs();
|
||||
|
||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
configure_rx_pins(r, rxd, rts);
|
||||
|
||||
// Initialize state
|
||||
let s = U::buffered_state();
|
||||
@ -681,20 +666,19 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) };
|
||||
|
||||
// clear errors
|
||||
let errors = r.errorsrc.read().bits();
|
||||
r.errorsrc.write(|w| unsafe { w.bits(errors) });
|
||||
let errors = r.errorsrc().read();
|
||||
r.errorsrc().write_value(errors);
|
||||
|
||||
r.events_rxstarted.reset();
|
||||
r.events_error.reset();
|
||||
r.events_endrx.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.events_endrx().write_value(0);
|
||||
|
||||
// Enable interrupts
|
||||
r.intenset.write(|w| {
|
||||
w.endtx().set();
|
||||
w.rxstarted().set();
|
||||
w.error().set();
|
||||
w.endrx().set();
|
||||
w
|
||||
r.intenset().write(|w| {
|
||||
w.set_endtx(true);
|
||||
w.set_rxstarted(true);
|
||||
w.set_error(true);
|
||||
w.set_endrx(true);
|
||||
});
|
||||
|
||||
// Configure byte counter.
|
||||
@ -704,15 +688,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
timer.clear();
|
||||
timer.start();
|
||||
|
||||
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
|
||||
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count());
|
||||
ppi_ch1.enable();
|
||||
|
||||
s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed);
|
||||
let mut ppi_group = PpiGroup::new(ppi_group);
|
||||
let mut ppi_ch2 = Ppi::new_one_to_two(
|
||||
ppi_ch2,
|
||||
Event::from_reg(&r.events_endrx),
|
||||
Task::from_reg(&r.tasks_startrx),
|
||||
Event::from_reg(r.events_endrx()),
|
||||
Task::from_reg(r.tasks_startrx()),
|
||||
ppi_group.task_disable_all(),
|
||||
);
|
||||
ppi_ch2.disable();
|
||||
@ -747,8 +731,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
let ss = U::state();
|
||||
|
||||
// Read the RXDRDY counter.
|
||||
T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) });
|
||||
let mut end = T::regs().cc[0].read().bits() as usize;
|
||||
T::regs().tasks_capture(0).write_value(1);
|
||||
let mut end = T::regs().cc(0).read() as usize;
|
||||
//trace!(" rxdrdy count = {:?}", end);
|
||||
|
||||
// We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
|
||||
@ -769,7 +753,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
if start == end {
|
||||
//trace!(" empty");
|
||||
ss.rx_waker.register(cx.waker());
|
||||
r.intenset.write(|w| w.rxdrdy().set_bit());
|
||||
r.intenset().write(|w| w.set_rxdrdy(true));
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
@ -799,7 +783,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
let s = U::buffered_state();
|
||||
let mut rx = unsafe { s.rx_buf.reader() };
|
||||
rx.pop_done(amt);
|
||||
U::regs().intenset.write(|w| w.rxstarted().set());
|
||||
U::regs().intenset().write(|w| w.set_rxstarted(true));
|
||||
}
|
||||
|
||||
/// we are ready to read if there is data in the buffer
|
||||
@ -817,15 +801,14 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T>
|
||||
|
||||
self.timer.stop();
|
||||
|
||||
r.intenclr.write(|w| {
|
||||
w.rxdrdy().set_bit();
|
||||
w.rxstarted().set_bit();
|
||||
w.rxto().set_bit();
|
||||
w
|
||||
r.intenclr().write(|w| {
|
||||
w.set_rxdrdy(true);
|
||||
w.set_rxstarted(true);
|
||||
w.set_rxto(true);
|
||||
});
|
||||
r.events_rxto.reset();
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_rxto.read().bits() == 0 {}
|
||||
r.events_rxto().write_value(0);
|
||||
r.tasks_stoprx().write_value(1);
|
||||
while r.events_rxto().read() == 0 {}
|
||||
|
||||
let s = U::buffered_state();
|
||||
unsafe { s.rx_buf.deinit() }
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf51_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52805_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52810_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 10) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52811_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52820_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 15) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52832_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 8) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52833_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 16) - 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use nrf52840_pac as pac;
|
||||
pub use nrf_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 16) - 1;
|
||||
|
@ -5,16 +5,17 @@ pub mod pac {
|
||||
// The nRF5340 has a secure and non-secure (NS) mode.
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
||||
#[cfg(feature="rt")]
|
||||
pub use nrf_pac::NVIC_PRIO_BITS;
|
||||
pub use nrf_pac::{common, shared};
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::interrupt;
|
||||
pub use nrf_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
pub use nrf_pac::{
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
cache_s as cache,
|
||||
cachedata_s as cachedata,
|
||||
@ -26,11 +27,11 @@ pub mod pac {
|
||||
ctrlap_ns as ctrlap,
|
||||
dcnf_ns as dcnf,
|
||||
dppic_ns as dppic,
|
||||
egu0_ns as egu0,
|
||||
egu_ns as egu,
|
||||
ficr_s as ficr,
|
||||
fpu_ns as fpu,
|
||||
gpiote0_s as gpiote,
|
||||
i2s0_ns as i2s0,
|
||||
gpiote_s as gpiote,
|
||||
i2s_ns as i2s,
|
||||
ipc_ns as ipc,
|
||||
kmu_ns as kmu,
|
||||
lpcomp_ns as lpcomp,
|
||||
@ -38,36 +39,36 @@ pub mod pac {
|
||||
nfct_ns as nfct,
|
||||
nvmc_ns as nvmc,
|
||||
oscillators_ns as oscillators,
|
||||
p0_ns as p0,
|
||||
pdm0_ns as pdm,
|
||||
gpio_ns as gpio,
|
||||
pdm_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
qdec0_ns as qdec,
|
||||
pwm_ns as pwm,
|
||||
qdec_ns as qdec,
|
||||
qspi_ns as qspi,
|
||||
regulators_ns as regulators,
|
||||
reset_ns as reset,
|
||||
rtc0_ns as rtc0,
|
||||
rtc_ns as rtc,
|
||||
saadc_ns as saadc,
|
||||
spim0_ns as spim0,
|
||||
spis0_ns as spis0,
|
||||
spim_ns as spim,
|
||||
spis_ns as spis,
|
||||
spu_s as spu,
|
||||
tad_s as tad,
|
||||
timer0_ns as timer0,
|
||||
twim0_ns as twim0,
|
||||
twis0_ns as twis0,
|
||||
uarte0_ns as uarte0,
|
||||
timer_ns as timer,
|
||||
twim_ns as twim,
|
||||
twis_ns as twis,
|
||||
uarte_ns as uarte,
|
||||
uicr_s as uicr,
|
||||
usbd_ns as usbd,
|
||||
usbregulator_ns as usbregulator,
|
||||
vmc_ns as vmc,
|
||||
wdt0_ns as wdt0,
|
||||
wdt_ns as wdt,
|
||||
};
|
||||
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[cfg(feature = "nrf5340-app-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
pub use nrf_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
COMP_NS as COMP,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
@ -141,7 +142,7 @@ pub mod pac {
|
||||
pub mod s {
|
||||
#[cfg(feature = "nrf5340-app-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
pub use nrf_pac::{
|
||||
CACHEDATA_S as CACHEDATA,
|
||||
CACHEINFO_S as CACHEINFO,
|
||||
CACHE_S as CACHE,
|
||||
|
@ -5,16 +5,17 @@ pub mod pac {
|
||||
// The nRF5340 has a secure and non-secure (NS) mode.
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
||||
#[cfg(feature="rt")]
|
||||
pub use nrf_pac::NVIC_PRIO_BITS;
|
||||
pub use nrf_pac::{common, shared};
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::interrupt;
|
||||
pub use nrf_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::{
|
||||
pub use nrf_pac::{
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
aar_ns as aar,
|
||||
acl_ns as acl,
|
||||
@ -26,25 +27,25 @@ pub mod pac {
|
||||
dcnf_ns as dcnf,
|
||||
dppic_ns as dppic,
|
||||
ecb_ns as ecb,
|
||||
egu0_ns as egu0,
|
||||
egu_ns as egu,
|
||||
ficr_ns as ficr,
|
||||
gpiote_ns as gpiote,
|
||||
ipc_ns as ipc,
|
||||
nvmc_ns as nvmc,
|
||||
p0_ns as p0,
|
||||
gpio_ns as gpio,
|
||||
power_ns as power,
|
||||
radio_ns as radio,
|
||||
reset_ns as reset,
|
||||
rng_ns as rng,
|
||||
rtc0_ns as rtc0,
|
||||
spim0_ns as spim0,
|
||||
spis0_ns as spis0,
|
||||
swi0_ns as swi0,
|
||||
rtc_ns as rtc,
|
||||
spim_ns as spim,
|
||||
spis_ns as spis,
|
||||
swi_ns as swi,
|
||||
temp_ns as temp,
|
||||
timer0_ns as timer0,
|
||||
twim0_ns as twim0,
|
||||
twis0_ns as twis0,
|
||||
uarte0_ns as uarte0,
|
||||
timer_ns as timer,
|
||||
twim_ns as twim,
|
||||
twis_ns as twis,
|
||||
uarte_ns as uarte,
|
||||
uicr_ns as uicr,
|
||||
vmc_ns as vmc,
|
||||
vreqctrl_ns as vreqctrl,
|
||||
@ -54,25 +55,17 @@ pub mod pac {
|
||||
ACL_NS as ACL,
|
||||
APPMUTEX_NS as APPMUTEX,
|
||||
APPMUTEX_S as APPMUTEX_S,
|
||||
CBP as CBP,
|
||||
CCM_NS as CCM,
|
||||
CLOCK_NS as CLOCK,
|
||||
CPUID as CPUID,
|
||||
CTI_NS as CTI,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
DCB as DCB,
|
||||
DCNF_NS as DCNF,
|
||||
DPPIC_NS as DPPIC,
|
||||
DWT as DWT,
|
||||
ECB_NS as ECB,
|
||||
EGU0_NS as EGU0,
|
||||
FICR_NS as FICR,
|
||||
FPB as FPB,
|
||||
GPIOTE_NS as GPIOTE,
|
||||
IPC_NS as IPC,
|
||||
ITM as ITM,
|
||||
MPU as MPU,
|
||||
NVIC as NVIC,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
P1_NS as P1,
|
||||
@ -82,19 +75,16 @@ pub mod pac {
|
||||
RNG_NS as RNG,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SCB as SCB,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIS0_NS as SPIS0,
|
||||
SWI0_NS as SWI0,
|
||||
SWI1_NS as SWI1,
|
||||
SWI2_NS as SWI2,
|
||||
SWI3_NS as SWI3,
|
||||
SYST as SYST,
|
||||
TEMP_NS as TEMP,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TPIU as TPIU,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIS0_NS as TWIS0,
|
||||
UARTE0_NS as UARTE0,
|
||||
|
@ -5,14 +5,16 @@ pub mod pac {
|
||||
// The nRF9120 has a secure and non-secure (NS) mode.
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf9120_pac::NVIC_PRIO_BITS;
|
||||
#[cfg(feature="rt")]
|
||||
pub use nrf_pac::NVIC_PRIO_BITS;
|
||||
pub use nrf_pac::{common, shared};
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::interrupt;
|
||||
pub use nrf_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
pub use nrf_pac::{
|
||||
Interrupt,
|
||||
|
||||
cc_host_rgf_s as cc_host_rgf,
|
||||
@ -20,29 +22,29 @@ pub mod pac {
|
||||
cryptocell_s as cryptocell,
|
||||
ctrl_ap_peri_s as ctrl_ap_peri,
|
||||
dppic_ns as dppic,
|
||||
egu0_ns as egu0,
|
||||
egu_ns as egu,
|
||||
ficr_s as ficr,
|
||||
fpu_ns as fpu,
|
||||
gpiote0_s as gpiote,
|
||||
gpiote_s as gpiote,
|
||||
i2s_ns as i2s,
|
||||
ipc_ns as ipc,
|
||||
kmu_ns as kmu,
|
||||
nvmc_ns as nvmc,
|
||||
p0_ns as p0,
|
||||
gpio_ns as gpio,
|
||||
pdm_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
pwm_ns as pwm,
|
||||
regulators_ns as regulators,
|
||||
rtc0_ns as rtc0,
|
||||
rtc_ns as rtc,
|
||||
saadc_ns as saadc,
|
||||
spim0_ns as spim0,
|
||||
spis0_ns as spis0,
|
||||
spim_ns as spim,
|
||||
spis_ns as spis,
|
||||
spu_s as spu,
|
||||
tad_s as tad,
|
||||
timer0_ns as timer0,
|
||||
twim0_ns as twim0,
|
||||
twis0_ns as twis0,
|
||||
uarte0_ns as uarte0,
|
||||
timer_ns as timer,
|
||||
twim_ns as twim,
|
||||
twis_ns as twis,
|
||||
uarte_ns as uarte,
|
||||
uicr_s as uicr,
|
||||
vmc_ns as vmc,
|
||||
wdt_ns as wdt,
|
||||
@ -51,7 +53,7 @@ pub mod pac {
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
pub use nrf_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
@ -108,7 +110,7 @@ pub mod pac {
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
pub use nrf_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
@ -121,7 +123,7 @@ pub mod pac {
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU as FPU,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
|
@ -5,14 +5,16 @@ pub mod pac {
|
||||
// The nRF9160 has a secure and non-secure (NS) mode.
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf9160_pac::NVIC_PRIO_BITS;
|
||||
#[cfg(feature="rt")]
|
||||
pub use nrf_pac::NVIC_PRIO_BITS;
|
||||
pub use nrf_pac::{common, shared};
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::interrupt;
|
||||
pub use nrf_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
pub use nrf_pac::{
|
||||
Interrupt,
|
||||
|
||||
cc_host_rgf_s as cc_host_rgf,
|
||||
@ -20,29 +22,29 @@ pub mod pac {
|
||||
cryptocell_s as cryptocell,
|
||||
ctrl_ap_peri_s as ctrl_ap_peri,
|
||||
dppic_ns as dppic,
|
||||
egu0_ns as egu0,
|
||||
egu_ns as egu,
|
||||
ficr_s as ficr,
|
||||
fpu_ns as fpu,
|
||||
gpiote0_s as gpiote,
|
||||
gpiote_s as gpiote,
|
||||
i2s_ns as i2s,
|
||||
ipc_ns as ipc,
|
||||
kmu_ns as kmu,
|
||||
nvmc_ns as nvmc,
|
||||
p0_ns as p0,
|
||||
gpio_ns as gpio,
|
||||
pdm_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
pwm_ns as pwm,
|
||||
regulators_ns as regulators,
|
||||
rtc0_ns as rtc0,
|
||||
rtc_ns as rtc,
|
||||
saadc_ns as saadc,
|
||||
spim0_ns as spim0,
|
||||
spis0_ns as spis0,
|
||||
spim_ns as spim,
|
||||
spis_ns as spis,
|
||||
spu_s as spu,
|
||||
tad_s as tad,
|
||||
timer0_ns as timer0,
|
||||
twim0_ns as twim0,
|
||||
twis0_ns as twis0,
|
||||
uarte0_ns as uarte0,
|
||||
timer_ns as timer,
|
||||
twim_ns as twim,
|
||||
twis_ns as twis,
|
||||
uarte_ns as uarte,
|
||||
uicr_s as uicr,
|
||||
vmc_ns as vmc,
|
||||
wdt_ns as wdt,
|
||||
@ -51,7 +53,7 @@ pub mod pac {
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
pub use nrf_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
@ -108,7 +110,7 @@ pub mod pac {
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
pub use nrf_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
|
@ -34,7 +34,7 @@ impl<'d, T: Instance> Egu<'d, T> {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::egu0::RegisterBlock;
|
||||
fn regs() -> pac::egu::Egu;
|
||||
}
|
||||
|
||||
/// Basic Egu instance.
|
||||
@ -47,8 +47,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_egu {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::egu::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::egu0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::egu::Egu {
|
||||
pac::$pac_type
|
||||
}
|
||||
}
|
||||
impl crate::egu::Instance for peripherals::$type {
|
||||
@ -68,32 +68,26 @@ impl<'d, T: Instance> Trigger<'d, T> {
|
||||
pub fn task(&self) -> Task<'d> {
|
||||
let nr = self.number as usize;
|
||||
let regs = T::regs();
|
||||
Task::from_reg(®s.tasks_trigger[nr])
|
||||
Task::from_reg(regs.tasks_trigger(nr))
|
||||
}
|
||||
|
||||
/// Get event for this trigger to use with PPI.
|
||||
pub fn event(&self) -> Event<'d> {
|
||||
let nr = self.number as usize;
|
||||
let regs = T::regs();
|
||||
Event::from_reg(®s.events_triggered[nr])
|
||||
Event::from_reg(regs.events_triggered(nr))
|
||||
}
|
||||
|
||||
/// Enable interrupts for this trigger
|
||||
pub fn enable_interrupt(&mut self) {
|
||||
let regs = T::regs();
|
||||
unsafe {
|
||||
regs.intenset
|
||||
.modify(|r, w| w.bits(r.bits() | (1 << self.number as usize)))
|
||||
};
|
||||
regs.intenset().modify(|w| w.set_triggered(self.number as usize, true));
|
||||
}
|
||||
|
||||
/// Enable interrupts for this trigger
|
||||
pub fn disable_interrupt(&mut self) {
|
||||
let regs = T::regs();
|
||||
unsafe {
|
||||
regs.intenclr
|
||||
.modify(|r, w| w.bits(r.bits() | (1 << self.number as usize)))
|
||||
};
|
||||
regs.intenset().modify(|w| w.set_triggered(self.number as usize, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,11 @@ use core::hint::unreachable_unchecked;
|
||||
use cfg_if::cfg_if;
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::common::{Reg, RW};
|
||||
use crate::pac::gpio;
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A};
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0 as gpio;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A};
|
||||
use crate::pac::gpio::vals;
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
use crate::pac::shared::{regs::Psel, vals::Connect};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
/// A GPIO port with up to 32 pins.
|
||||
@ -103,7 +100,7 @@ impl From<Level> for bool {
|
||||
}
|
||||
|
||||
/// Drive strength settings for an output pin.
|
||||
// These numbers match DRIVE_A exactly so hopefully the compiler will unify them.
|
||||
// These numbers match vals::Drive exactly so hopefully the compiler will unify them.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
@ -188,24 +185,24 @@ impl<'d> Output<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn convert_drive(drive: OutputDrive) -> DRIVE_A {
|
||||
pub(crate) fn convert_drive(drive: OutputDrive) -> vals::Drive {
|
||||
match drive {
|
||||
OutputDrive::Standard => DRIVE_A::S0S1,
|
||||
OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
|
||||
OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1,
|
||||
OutputDrive::HighDrive => DRIVE_A::H0H1,
|
||||
OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1,
|
||||
OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1,
|
||||
OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1,
|
||||
OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1,
|
||||
OutputDrive::Standard => vals::Drive::S0S1,
|
||||
OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1,
|
||||
OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1,
|
||||
OutputDrive::HighDrive => vals::Drive::H0H1,
|
||||
OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1,
|
||||
OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1,
|
||||
OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1,
|
||||
OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_pull(pull: Pull) -> PULL_A {
|
||||
fn convert_pull(pull: Pull) -> vals::Pull {
|
||||
match pull {
|
||||
Pull::None => PULL_A::DISABLED,
|
||||
Pull::Up => PULL_A::PULLUP,
|
||||
Pull::Down => PULL_A::PULLDOWN,
|
||||
Pull::None => vals::Pull::DISABLED,
|
||||
Pull::Up => vals::Pull::PULLUP,
|
||||
Pull::Down => vals::Pull::PULLDOWN,
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,12 +231,11 @@ impl<'d> Flex<'d> {
|
||||
#[inline]
|
||||
pub fn set_as_input(&mut self, pull: Pull) {
|
||||
self.pin.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
w.pull().variant(convert_pull(pull));
|
||||
w.drive().s0s1();
|
||||
w.sense().disabled();
|
||||
w
|
||||
w.set_dir(vals::Dir::INPUT);
|
||||
w.set_input(vals::Input::CONNECT);
|
||||
w.set_pull(convert_pull(pull));
|
||||
w.set_drive(vals::Drive::S0S1);
|
||||
w.set_sense(vals::Sense::DISABLED);
|
||||
});
|
||||
}
|
||||
|
||||
@ -250,12 +246,11 @@ impl<'d> Flex<'d> {
|
||||
#[inline]
|
||||
pub fn set_as_output(&mut self, drive: OutputDrive) {
|
||||
self.pin.conf().write(|w| {
|
||||
w.dir().output();
|
||||
w.input().disconnect();
|
||||
w.pull().disabled();
|
||||
w.drive().variant(convert_drive(drive));
|
||||
w.sense().disabled();
|
||||
w
|
||||
w.set_dir(vals::Dir::OUTPUT);
|
||||
w.set_input(vals::Input::DISCONNECT);
|
||||
w.set_pull(vals::Pull::DISABLED);
|
||||
w.set_drive(convert_drive(drive));
|
||||
w.set_sense(vals::Sense::DISABLED);
|
||||
});
|
||||
}
|
||||
|
||||
@ -271,31 +266,30 @@ impl<'d> Flex<'d> {
|
||||
#[inline]
|
||||
pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) {
|
||||
self.pin.conf().write(|w| {
|
||||
w.dir().output();
|
||||
w.input().connect();
|
||||
w.pull().variant(convert_pull(pull));
|
||||
w.drive().variant(convert_drive(drive));
|
||||
w.sense().disabled();
|
||||
w
|
||||
w.set_dir(vals::Dir::OUTPUT);
|
||||
w.set_input(vals::Input::CONNECT);
|
||||
w.set_pull(convert_pull(pull));
|
||||
w.set_drive(convert_drive(drive));
|
||||
w.set_sense(vals::Sense::DISABLED);
|
||||
});
|
||||
}
|
||||
|
||||
/// Put the pin into disconnected mode.
|
||||
#[inline]
|
||||
pub fn set_as_disconnected(&mut self) {
|
||||
self.pin.conf().reset();
|
||||
self.pin.conf().write(|_| ());
|
||||
}
|
||||
|
||||
/// Get whether the pin input level is high.
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
!self.is_low()
|
||||
self.pin.block().in_().read().pin(self.pin.pin() as _)
|
||||
}
|
||||
|
||||
/// Get whether the pin input level is low.
|
||||
#[inline]
|
||||
pub fn is_low(&self) -> bool {
|
||||
self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
|
||||
!self.is_high()
|
||||
}
|
||||
|
||||
/// Get the pin input level.
|
||||
@ -338,13 +332,13 @@ impl<'d> Flex<'d> {
|
||||
/// Get whether the output level is set to high.
|
||||
#[inline]
|
||||
pub fn is_set_high(&self) -> bool {
|
||||
!self.is_set_low()
|
||||
self.pin.block().out().read().pin(self.pin.pin() as _)
|
||||
}
|
||||
|
||||
/// Get whether the output level is set to low.
|
||||
#[inline]
|
||||
pub fn is_set_low(&self) -> bool {
|
||||
self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0
|
||||
!self.is_set_high()
|
||||
}
|
||||
|
||||
/// Get the current output level.
|
||||
@ -356,7 +350,7 @@ impl<'d> Flex<'d> {
|
||||
|
||||
impl<'d> Drop for Flex<'d> {
|
||||
fn drop(&mut self) {
|
||||
self.pin.conf().reset();
|
||||
self.pin.conf().write(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,35 +369,33 @@ pub(crate) trait SealedPin {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn block(&self) -> &gpio::RegisterBlock {
|
||||
unsafe {
|
||||
match self.pin_port() / 32 {
|
||||
#[cfg(feature = "nrf51")]
|
||||
0 => &*pac::GPIO::ptr(),
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
0 => &*pac::P0::ptr(),
|
||||
#[cfg(feature = "_gpio-p1")]
|
||||
1 => &*pac::P1::ptr(),
|
||||
_ => unreachable_unchecked(),
|
||||
}
|
||||
fn block(&self) -> gpio::Gpio {
|
||||
match self.pin_port() / 32 {
|
||||
#[cfg(feature = "_nrf51")]
|
||||
0 => pac::GPIO,
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
0 => pac::P0,
|
||||
#[cfg(feature = "_gpio-p1")]
|
||||
1 => pac::P1,
|
||||
_ => unsafe { unreachable_unchecked() },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn conf(&self) -> &gpio::PIN_CNF {
|
||||
&self.block().pin_cnf[self._pin() as usize]
|
||||
fn conf(&self) -> Reg<gpio::regs::PinCnf, RW> {
|
||||
self.block().pin_cnf(self._pin() as usize)
|
||||
}
|
||||
|
||||
/// Set the output as high.
|
||||
#[inline]
|
||||
fn set_high(&self) {
|
||||
unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) }
|
||||
self.block().outset().write(|w| w.set_pin(self._pin() as _, true))
|
||||
}
|
||||
|
||||
/// Set the output as low.
|
||||
#[inline]
|
||||
fn set_low(&self) {
|
||||
unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) }
|
||||
self.block().outclr().write(|w| w.set_pin(self._pin() as _, true))
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,8 +421,9 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static
|
||||
|
||||
/// Peripheral port register value
|
||||
#[inline]
|
||||
fn psel_bits(&self) -> u32 {
|
||||
self.pin_port() as u32
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
fn psel_bits(&self) -> pac::shared::regs::Psel {
|
||||
pac::shared::regs::Psel(self.pin_port() as u32)
|
||||
}
|
||||
|
||||
/// Convert from concrete pin type PX_XX to type erased `AnyPin`.
|
||||
@ -471,26 +464,30 @@ impl SealedPin for AnyPin {
|
||||
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub(crate) trait PselBits {
|
||||
fn psel_bits(&self) -> u32;
|
||||
fn psel_bits(&self) -> pac::shared::regs::Psel;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> {
|
||||
#[inline]
|
||||
fn psel_bits(&self) -> u32 {
|
||||
fn psel_bits(&self) -> pac::shared::regs::Psel {
|
||||
match self {
|
||||
Some(pin) => pin.psel_bits(),
|
||||
None => 1u32 << 31,
|
||||
None => DISCONNECTED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub(crate) const DISCONNECTED: Psel = Psel(1 << 31);
|
||||
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn deconfigure_pin(psel_bits: u32) {
|
||||
if psel_bits & 0x8000_0000 != 0 {
|
||||
pub(crate) fn deconfigure_pin(psel: Psel) {
|
||||
if psel.connect() == Connect::DISCONNECTED {
|
||||
return;
|
||||
}
|
||||
unsafe { AnyPin::steal(psel_bits as _).conf().reset() }
|
||||
unsafe { AnyPin::steal(psel.0 as _).conf().write(|_| ()) }
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
@ -9,10 +9,14 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _};
|
||||
use crate::interrupt::InterruptExt;
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
use crate::pac::gpio::vals::Detectmode;
|
||||
use crate::pac::gpio::vals::Sense;
|
||||
use crate::pac::gpiote::vals::{Mode, Outinit, Polarity};
|
||||
use crate::ppi::{Event, Task};
|
||||
use crate::{interrupt, pac, peripherals};
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
#[cfg(feature = "_nrf51")]
|
||||
/// Amount of GPIOTE channels in the chip.
|
||||
const CHANNEL_COUNT: usize = 4;
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
@ -51,14 +55,14 @@ pub enum OutputChannelPolarity {
|
||||
Toggle,
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::gpiote::RegisterBlock {
|
||||
fn regs() -> pac::gpiote::Gpiote {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] {
|
||||
unsafe { &*pac::GPIOTE0::ptr() }
|
||||
pac::GPIOTE0
|
||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] {
|
||||
unsafe { &*pac::GPIOTE1::ptr() }
|
||||
pac::GPIOTE1
|
||||
} else {
|
||||
unsafe { &*pac::GPIOTE::ptr() }
|
||||
pac::GPIOTE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,15 +72,15 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
{
|
||||
#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))]
|
||||
let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
|
||||
let ports = &[pac::P0, pac::P1];
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))]
|
||||
let ports = unsafe { &[&*pac::P0::ptr()] };
|
||||
let ports = &[pac::P0];
|
||||
|
||||
for &p in ports {
|
||||
// Enable latched detection
|
||||
p.detectmode.write(|w| w.detectmode().ldetect());
|
||||
p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT));
|
||||
// Clear latch
|
||||
p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) })
|
||||
p.latch().write(|w| w.0 = 0xFFFFFFFF)
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +97,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
||||
unsafe { irq.enable() };
|
||||
|
||||
let g = regs();
|
||||
g.intenset.write(|w| w.port().set());
|
||||
g.intenset().write(|w| w.set_port(true));
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
|
||||
@ -121,47 +125,47 @@ unsafe fn handle_gpiote_interrupt() {
|
||||
let g = regs();
|
||||
|
||||
for i in 0..CHANNEL_COUNT {
|
||||
if g.events_in[i].read().bits() != 0 {
|
||||
g.intenclr.write(|w| w.bits(1 << i));
|
||||
if g.events_in(i).read() != 0 {
|
||||
g.intenclr().write(|w| w.0 = 1 << i);
|
||||
CHANNEL_WAKERS[i].wake();
|
||||
}
|
||||
}
|
||||
|
||||
if g.events_port.read().bits() != 0 {
|
||||
g.events_port.write(|w| w);
|
||||
if g.events_port().read() != 0 {
|
||||
g.events_port().write_value(0);
|
||||
|
||||
#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))]
|
||||
let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()];
|
||||
let ports = &[pac::P0, pac::P1];
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))]
|
||||
let ports = &[&*pac::P0::ptr()];
|
||||
let ports = &[pac::P0];
|
||||
#[cfg(feature = "_nrf51")]
|
||||
let ports = unsafe { &[&*pac::GPIO::ptr()] };
|
||||
let ports = &[pac::GPIO];
|
||||
|
||||
#[cfg(feature = "_nrf51")]
|
||||
for (port, &p) in ports.iter().enumerate() {
|
||||
let inp = p.in_.read().bits();
|
||||
let inp = p.in_().read();
|
||||
for pin in 0..32 {
|
||||
let fired = match p.pin_cnf[pin as usize].read().sense().variant() {
|
||||
Some(pac::gpio::pin_cnf::SENSE_A::HIGH) => inp & (1 << pin) != 0,
|
||||
Some(pac::gpio::pin_cnf::SENSE_A::LOW) => inp & (1 << pin) == 0,
|
||||
let fired = match p.pin_cnf(pin as usize).read().sense() {
|
||||
Sense::HIGH => inp.pin(pin),
|
||||
Sense::LOW => !inp.pin(pin),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if fired {
|
||||
PORT_WAKERS[port * 32 + pin as usize].wake();
|
||||
p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
|
||||
p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
for (port, &p) in ports.iter().enumerate() {
|
||||
let bits = p.latch.read().bits();
|
||||
let bits = p.latch().read().0;
|
||||
for pin in BitIter(bits) {
|
||||
p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
|
||||
p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED));
|
||||
PORT_WAKERS[port * 32 + pin as usize].wake();
|
||||
}
|
||||
p.latch.write(|w| w.bits(bits));
|
||||
p.latch().write(|w| w.0 = bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,8 +198,8 @@ impl<'d> Drop for InputChannel<'d> {
|
||||
fn drop(&mut self) {
|
||||
let g = regs();
|
||||
let num = self.ch.number();
|
||||
g.config[num].write(|w| w.mode().disabled());
|
||||
g.intenclr.write(|w| unsafe { w.bits(1 << num) });
|
||||
g.config(num).write(|w| w.set_mode(Mode::DISABLED));
|
||||
g.intenclr().write(|w| w.0 = 1 << num);
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,22 +211,23 @@ impl<'d> InputChannel<'d> {
|
||||
let g = regs();
|
||||
let num = ch.number();
|
||||
|
||||
g.config[num].write(|w| {
|
||||
g.config(num).write(|w| {
|
||||
w.set_mode(Mode::EVENT);
|
||||
match polarity {
|
||||
InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
|
||||
InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
|
||||
InputChannelPolarity::None => w.mode().event().polarity().none(),
|
||||
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
|
||||
InputChannelPolarity::HiToLo => w.set_polarity(Polarity::HI_TO_LO),
|
||||
InputChannelPolarity::LoToHi => w.set_polarity(Polarity::LO_TO_HI),
|
||||
InputChannelPolarity::None => w.set_polarity(Polarity::NONE),
|
||||
InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE),
|
||||
};
|
||||
#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))]
|
||||
w.port().bit(match pin.pin.pin.port() {
|
||||
w.set_port(match pin.pin.pin.port() {
|
||||
crate::gpio::Port::Port0 => false,
|
||||
crate::gpio::Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin.pin.pin()) }
|
||||
w.set_psel(pin.pin.pin.pin());
|
||||
});
|
||||
|
||||
g.events_in[num].reset();
|
||||
g.events_in(num).write_value(0);
|
||||
|
||||
InputChannel { ch: ch.map_into(), pin }
|
||||
}
|
||||
@ -233,13 +238,13 @@ impl<'d> InputChannel<'d> {
|
||||
let num = self.ch.number();
|
||||
|
||||
// Enable interrupt
|
||||
g.events_in[num].reset();
|
||||
g.intenset.write(|w| unsafe { w.bits(1 << num) });
|
||||
g.events_in(num).write_value(0);
|
||||
g.intenset().write(|w| w.0 = 1 << num);
|
||||
|
||||
poll_fn(|cx| {
|
||||
CHANNEL_WAKERS[num].register(cx.waker());
|
||||
|
||||
if g.events_in[num].read().bits() != 0 {
|
||||
if g.events_in(num).read() != 0 {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
@ -251,7 +256,7 @@ impl<'d> InputChannel<'d> {
|
||||
/// Returns the IN event, for use with PPI.
|
||||
pub fn event_in(&self) -> Event<'d> {
|
||||
let g = regs();
|
||||
Event::from_reg(&g.events_in[self.ch.number()])
|
||||
Event::from_reg(g.events_in(self.ch.number()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,8 +270,8 @@ impl<'d> Drop for OutputChannel<'d> {
|
||||
fn drop(&mut self) {
|
||||
let g = regs();
|
||||
let num = self.ch.number();
|
||||
g.config[num].write(|w| w.mode().disabled());
|
||||
g.intenclr.write(|w| unsafe { w.bits(1 << num) });
|
||||
g.config(num).write(|w| w.set_mode(Mode::DISABLED));
|
||||
g.intenclr().write(|w| w.0 = 1 << num);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,23 +282,23 @@ impl<'d> OutputChannel<'d> {
|
||||
let g = regs();
|
||||
let num = ch.number();
|
||||
|
||||
g.config[num].write(|w| {
|
||||
w.mode().task();
|
||||
g.config(num).write(|w| {
|
||||
w.set_mode(Mode::TASK);
|
||||
match pin.is_set_high() {
|
||||
true => w.outinit().high(),
|
||||
false => w.outinit().low(),
|
||||
true => w.set_outinit(Outinit::HIGH),
|
||||
false => w.set_outinit(Outinit::LOW),
|
||||
};
|
||||
match polarity {
|
||||
OutputChannelPolarity::Set => w.polarity().lo_to_hi(),
|
||||
OutputChannelPolarity::Clear => w.polarity().hi_to_lo(),
|
||||
OutputChannelPolarity::Toggle => w.polarity().toggle(),
|
||||
OutputChannelPolarity::Set => w.set_polarity(Polarity::HI_TO_LO),
|
||||
OutputChannelPolarity::Clear => w.set_polarity(Polarity::LO_TO_HI),
|
||||
OutputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE),
|
||||
};
|
||||
#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))]
|
||||
w.port().bit(match pin.pin.pin.port() {
|
||||
w.set_port(match pin.pin.pin.port() {
|
||||
crate::gpio::Port::Port0 => false,
|
||||
crate::gpio::Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin.pin.pin()) }
|
||||
w.set_psel(pin.pin.pin.pin());
|
||||
});
|
||||
|
||||
OutputChannel {
|
||||
@ -305,41 +310,41 @@ impl<'d> OutputChannel<'d> {
|
||||
/// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle).
|
||||
pub fn out(&self) {
|
||||
let g = regs();
|
||||
g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) });
|
||||
g.tasks_out(self.ch.number()).write_value(1);
|
||||
}
|
||||
|
||||
/// Triggers the SET task (set associated pin high).
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub fn set(&self) {
|
||||
let g = regs();
|
||||
g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) });
|
||||
g.tasks_set(self.ch.number()).write_value(1);
|
||||
}
|
||||
|
||||
/// Triggers the CLEAR task (set associated pin low).
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub fn clear(&self) {
|
||||
let g = regs();
|
||||
g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) });
|
||||
g.tasks_clr(self.ch.number()).write_value(1);
|
||||
}
|
||||
|
||||
/// Returns the OUT task, for use with PPI.
|
||||
pub fn task_out(&self) -> Task<'d> {
|
||||
let g = regs();
|
||||
Task::from_reg(&g.tasks_out[self.ch.number()])
|
||||
Task::from_reg(g.tasks_out(self.ch.number()))
|
||||
}
|
||||
|
||||
/// Returns the CLR task, for use with PPI.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub fn task_clr(&self) -> Task<'d> {
|
||||
let g = regs();
|
||||
Task::from_reg(&g.tasks_clr[self.ch.number()])
|
||||
Task::from_reg(g.tasks_clr(self.ch.number()))
|
||||
}
|
||||
|
||||
/// Returns the SET task, for use with PPI.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub fn task_set(&self) -> Task<'d> {
|
||||
let g = regs();
|
||||
Task::from_reg(&g.tasks_set[self.ch.number()])
|
||||
Task::from_reg(g.tasks_set(self.ch.number()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,7 +367,7 @@ impl<'a> Unpin for PortInputFuture<'a> {}
|
||||
|
||||
impl<'a> Drop for PortInputFuture<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.pin.conf().modify(|_, w| w.sense().disabled());
|
||||
self.pin.conf().modify(|w| w.set_sense(Sense::DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,7 +377,7 @@ impl<'a> Future for PortInputFuture<'a> {
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
PORT_WAKERS[self.pin.pin_port() as usize].register(cx.waker());
|
||||
|
||||
if self.pin.conf().read().sense().is_disabled() {
|
||||
if self.pin.conf().read().sense() == Sense::DISABLED {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
@ -410,13 +415,13 @@ impl<'d> Input<'d> {
|
||||
impl<'d> Flex<'d> {
|
||||
/// Wait until the pin is high. If it is already high, return immediately.
|
||||
pub async fn wait_for_high(&mut self) {
|
||||
self.pin.conf().modify(|_, w| w.sense().high());
|
||||
self.pin.conf().modify(|w| w.set_sense(Sense::HIGH));
|
||||
PortInputFuture::new(&mut self.pin).await
|
||||
}
|
||||
|
||||
/// Wait until the pin is low. If it is already low, return immediately.
|
||||
pub async fn wait_for_low(&mut self) {
|
||||
self.pin.conf().modify(|_, w| w.sense().low());
|
||||
self.pin.conf().modify(|w| w.set_sense(Sense::LOW));
|
||||
PortInputFuture::new(&mut self.pin).await
|
||||
}
|
||||
|
||||
@ -435,9 +440,9 @@ impl<'d> Flex<'d> {
|
||||
/// Wait for the pin to undergo any transition, i.e low to high OR high to low.
|
||||
pub async fn wait_for_any_edge(&mut self) {
|
||||
if self.is_high() {
|
||||
self.pin.conf().modify(|_, w| w.sense().low());
|
||||
self.pin.conf().modify(|w| w.set_sense(Sense::LOW));
|
||||
} else {
|
||||
self.pin.conf().modify(|_, w| w.sense().high());
|
||||
self.pin.conf().modify(|w| w.set_sense(Sense::HIGH));
|
||||
}
|
||||
PortInputFuture::new(&mut self.pin).await
|
||||
}
|
||||
@ -504,13 +509,13 @@ impl_channel!(GPIOTE_CH0, 0);
|
||||
impl_channel!(GPIOTE_CH1, 1);
|
||||
impl_channel!(GPIOTE_CH2, 2);
|
||||
impl_channel!(GPIOTE_CH3, 3);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_channel!(GPIOTE_CH4, 4);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_channel!(GPIOTE_CH5, 5);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_channel!(GPIOTE_CH6, 6);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_channel!(GPIOTE_CH7, 7);
|
||||
|
||||
// ====================
|
||||
|
@ -13,11 +13,11 @@ use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::i2s::RegisterBlock;
|
||||
use crate::pac::i2s::vals;
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{interrupt, Peripheral, EASY_DMA_SIZE};
|
||||
use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE};
|
||||
|
||||
/// Type alias for `MultiBuffering` with 2 buffers.
|
||||
pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
|
||||
@ -117,9 +117,20 @@ pub enum MckFreq {
|
||||
}
|
||||
|
||||
impl MckFreq {
|
||||
const REGISTER_VALUES: &'static [u32] = &[
|
||||
0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
|
||||
0x08000000, 0x06000000, 0x04100000, 0x020C0000,
|
||||
const REGISTER_VALUES: &'static [vals::Mckfreq] = &[
|
||||
vals::Mckfreq::_32MDIV8,
|
||||
vals::Mckfreq::_32MDIV10,
|
||||
vals::Mckfreq::_32MDIV11,
|
||||
vals::Mckfreq::_32MDIV15,
|
||||
vals::Mckfreq::_32MDIV16,
|
||||
vals::Mckfreq::_32MDIV21,
|
||||
vals::Mckfreq::_32MDIV23,
|
||||
vals::Mckfreq::_32MDIV30,
|
||||
vals::Mckfreq::_32MDIV31,
|
||||
vals::Mckfreq::_32MDIV32,
|
||||
vals::Mckfreq::_32MDIV42,
|
||||
vals::Mckfreq::_32MDIV63,
|
||||
vals::Mckfreq::_32MDIV125,
|
||||
];
|
||||
|
||||
const FREQUENCIES: &'static [u32] = &[
|
||||
@ -128,7 +139,7 @@ impl MckFreq {
|
||||
];
|
||||
|
||||
/// Return the value that needs to be written to the register.
|
||||
pub fn to_register_value(&self) -> u32 {
|
||||
pub fn to_register_value(&self) -> vals::Mckfreq {
|
||||
Self::REGISTER_VALUES[usize::from(*self)]
|
||||
}
|
||||
|
||||
@ -174,8 +185,8 @@ impl Ratio {
|
||||
const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
|
||||
|
||||
/// Return the value that needs to be written to the register.
|
||||
pub fn to_register_value(&self) -> u8 {
|
||||
usize::from(*self) as u8
|
||||
pub fn to_register_value(&self) -> vals::Ratio {
|
||||
vals::Ratio::from_bits(*self as u8)
|
||||
}
|
||||
|
||||
/// Return the divisor for this ratio
|
||||
@ -304,9 +315,9 @@ pub enum SampleWidth {
|
||||
_24bit,
|
||||
}
|
||||
|
||||
impl From<SampleWidth> for u8 {
|
||||
impl From<SampleWidth> for vals::Swidth {
|
||||
fn from(variant: SampleWidth) -> Self {
|
||||
variant as _
|
||||
vals::Swidth::from_bits(variant as u8)
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,11 +330,11 @@ pub enum Align {
|
||||
Right,
|
||||
}
|
||||
|
||||
impl From<Align> for bool {
|
||||
impl From<Align> for vals::Align {
|
||||
fn from(variant: Align) -> Self {
|
||||
match variant {
|
||||
Align::Left => false,
|
||||
Align::Right => true,
|
||||
Align::Left => vals::Align::LEFT,
|
||||
Align::Right => vals::Align::RIGHT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -337,11 +348,11 @@ pub enum Format {
|
||||
Aligned,
|
||||
}
|
||||
|
||||
impl From<Format> for bool {
|
||||
impl From<Format> for vals::Format {
|
||||
fn from(variant: Format) -> Self {
|
||||
match variant {
|
||||
Format::I2S => false,
|
||||
Format::Aligned => true,
|
||||
Format::I2S => vals::Format::I2S,
|
||||
Format::Aligned => vals::Format::ALIGNED,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,9 +368,9 @@ pub enum Channels {
|
||||
MonoRight,
|
||||
}
|
||||
|
||||
impl From<Channels> for u8 {
|
||||
impl From<Channels> for vals::Channels {
|
||||
fn from(variant: Channels) -> Self {
|
||||
variant as _
|
||||
vals::Channels::from_bits(variant as u8)
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,61 +517,32 @@ impl<'d, T: Instance> I2S<'d, T> {
|
||||
}
|
||||
|
||||
fn apply_config(&self) {
|
||||
let c = &T::regs().config;
|
||||
let c = T::regs().config();
|
||||
match &self.master_clock {
|
||||
Some(MasterClock { freq, ratio }) => {
|
||||
c.mode.write(|w| w.mode().master());
|
||||
c.mcken.write(|w| w.mcken().enabled());
|
||||
c.mckfreq
|
||||
.write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
|
||||
c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) });
|
||||
c.mode().write(|w| w.set_mode(vals::Mode::MASTER));
|
||||
c.mcken().write(|w| w.set_mcken(true));
|
||||
c.mckfreq().write(|w| w.set_mckfreq(freq.to_register_value()));
|
||||
c.ratio().write(|w| w.set_ratio(ratio.to_register_value()));
|
||||
}
|
||||
None => {
|
||||
c.mode.write(|w| w.mode().slave());
|
||||
c.mode().write(|w| w.set_mode(vals::Mode::SLAVE));
|
||||
}
|
||||
};
|
||||
|
||||
c.swidth
|
||||
.write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) });
|
||||
c.align.write(|w| w.align().bit(self.config.align.into()));
|
||||
c.format.write(|w| w.format().bit(self.config.format.into()));
|
||||
c.channels
|
||||
.write(|w| unsafe { w.channels().bits(self.config.channels.into()) });
|
||||
c.swidth().write(|w| w.set_swidth(self.config.sample_width.into()));
|
||||
c.align().write(|w| w.set_align(self.config.align.into()));
|
||||
c.format().write(|w| w.set_format(self.config.format.into()));
|
||||
c.channels().write(|w| w.set_channels(self.config.channels.into()));
|
||||
}
|
||||
|
||||
fn select_pins(&self) {
|
||||
let psel = &T::regs().psel;
|
||||
|
||||
if let Some(mck) = &self.mck {
|
||||
psel.mck.write(|w| {
|
||||
unsafe { w.bits(mck.psel_bits()) };
|
||||
w.connect().connected()
|
||||
});
|
||||
}
|
||||
|
||||
psel.sck.write(|w| {
|
||||
unsafe { w.bits(self.sck.psel_bits()) };
|
||||
w.connect().connected()
|
||||
});
|
||||
|
||||
psel.lrck.write(|w| {
|
||||
unsafe { w.bits(self.lrck.psel_bits()) };
|
||||
w.connect().connected()
|
||||
});
|
||||
|
||||
if let Some(sdin) = &self.sdin {
|
||||
psel.sdin.write(|w| {
|
||||
unsafe { w.bits(sdin.psel_bits()) };
|
||||
w.connect().connected()
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(sdout) = &self.sdout {
|
||||
psel.sdout.write(|w| {
|
||||
unsafe { w.bits(sdout.psel_bits()) };
|
||||
w.connect().connected()
|
||||
});
|
||||
}
|
||||
let psel = T::regs().psel();
|
||||
psel.mck().write_value(self.mck.psel_bits());
|
||||
psel.sck().write_value(self.sck.psel_bits());
|
||||
psel.lrck().write_value(self.lrck.psel_bits());
|
||||
psel.sdin().write_value(self.sdin.psel_bits());
|
||||
psel.sdout().write_value(self.sdout.psel_bits());
|
||||
}
|
||||
|
||||
fn setup_interrupt(&self) {
|
||||
@ -888,7 +870,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr
|
||||
}
|
||||
|
||||
/// Helper encapsulating common I2S device operations.
|
||||
struct Device<T>(&'static RegisterBlock, PhantomData<T>);
|
||||
struct Device<T>(pac::i2s::I2s, PhantomData<T>);
|
||||
|
||||
impl<T: Instance> Device<T> {
|
||||
fn new() -> Self {
|
||||
@ -898,132 +880,132 @@ impl<T: Instance> Device<T> {
|
||||
#[inline(always)]
|
||||
pub fn enable(&self) {
|
||||
trace!("ENABLED");
|
||||
self.0.enable.write(|w| w.enable().enabled());
|
||||
self.0.enable().write(|w| w.set_enable(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn disable(&self) {
|
||||
trace!("DISABLED");
|
||||
self.0.enable.write(|w| w.enable().disabled());
|
||||
self.0.enable().write(|w| w.set_enable(false));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enable_tx(&self) {
|
||||
trace!("TX ENABLED");
|
||||
self.0.config.txen.write(|w| w.txen().enabled());
|
||||
self.0.config().txen().write(|w| w.set_txen(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn disable_tx(&self) {
|
||||
trace!("TX DISABLED");
|
||||
self.0.config.txen.write(|w| w.txen().disabled());
|
||||
self.0.config().txen().write(|w| w.set_txen(false));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enable_rx(&self) {
|
||||
trace!("RX ENABLED");
|
||||
self.0.config.rxen.write(|w| w.rxen().enabled());
|
||||
self.0.config().rxen().write(|w| w.set_rxen(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn disable_rx(&self) {
|
||||
trace!("RX DISABLED");
|
||||
self.0.config.rxen.write(|w| w.rxen().disabled());
|
||||
self.0.config().rxen().write(|w| w.set_rxen(false));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn start(&self) {
|
||||
trace!("START");
|
||||
self.0.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
self.0.tasks_start().write_value(1);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn stop(&self) {
|
||||
self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
self.0.tasks_stop().write_value(1);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_stopped(&self) -> bool {
|
||||
self.0.events_stopped.read().bits() != 0
|
||||
self.0.events_stopped().read() != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn reset_stopped_event(&self) {
|
||||
trace!("STOPPED EVENT: Reset");
|
||||
self.0.events_stopped.reset();
|
||||
self.0.events_stopped().write_value(0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn disable_stopped_interrupt(&self) {
|
||||
trace!("STOPPED INTERRUPT: Disabled");
|
||||
self.0.intenclr.write(|w| w.stopped().clear());
|
||||
self.0.intenclr().write(|w| w.set_stopped(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enable_stopped_interrupt(&self) {
|
||||
trace!("STOPPED INTERRUPT: Enabled");
|
||||
self.0.intenset.write(|w| w.stopped().set());
|
||||
self.0.intenset().write(|w| w.set_stopped(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn reset_tx_ptr_event(&self) {
|
||||
trace!("TX PTR EVENT: Reset");
|
||||
self.0.events_txptrupd.reset();
|
||||
self.0.events_txptrupd().write_value(0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn reset_rx_ptr_event(&self) {
|
||||
trace!("RX PTR EVENT: Reset");
|
||||
self.0.events_rxptrupd.reset();
|
||||
self.0.events_rxptrupd().write_value(0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn disable_tx_ptr_interrupt(&self) {
|
||||
trace!("TX PTR INTERRUPT: Disabled");
|
||||
self.0.intenclr.write(|w| w.txptrupd().clear());
|
||||
self.0.intenclr().write(|w| w.set_txptrupd(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn disable_rx_ptr_interrupt(&self) {
|
||||
trace!("RX PTR INTERRUPT: Disabled");
|
||||
self.0.intenclr.write(|w| w.rxptrupd().clear());
|
||||
self.0.intenclr().write(|w| w.set_rxptrupd(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enable_tx_ptr_interrupt(&self) {
|
||||
trace!("TX PTR INTERRUPT: Enabled");
|
||||
self.0.intenset.write(|w| w.txptrupd().set());
|
||||
self.0.intenset().write(|w| w.set_txptrupd(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enable_rx_ptr_interrupt(&self) {
|
||||
trace!("RX PTR INTERRUPT: Enabled");
|
||||
self.0.intenset.write(|w| w.rxptrupd().set());
|
||||
self.0.intenset().write(|w| w.set_rxptrupd(true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_tx_ptr_updated(&self) -> bool {
|
||||
self.0.events_txptrupd.read().bits() != 0
|
||||
self.0.events_txptrupd().read() != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_rx_ptr_updated(&self) -> bool {
|
||||
self.0.events_rxptrupd.read().bits() != 0
|
||||
self.0.events_rxptrupd().read() != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
|
||||
let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
|
||||
self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
|
||||
self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
|
||||
self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt);
|
||||
self.0.txd().ptr().write_value(ptr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
|
||||
let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
|
||||
self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
|
||||
self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
|
||||
self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt);
|
||||
self.0.rxd().ptr().write_value(ptr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1160,7 +1142,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::i2s::RegisterBlock;
|
||||
fn regs() -> pac::i2s::I2s;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -1174,8 +1156,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_i2s {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::i2s::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::i2s::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::i2s::I2s {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::i2s::State {
|
||||
static STATE: crate::i2s::State = crate::i2s::State::new();
|
||||
|
@ -11,7 +11,7 @@
|
||||
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "nrf51",
|
||||
feature = "_nrf51",
|
||||
feature = "nrf52805",
|
||||
feature = "nrf52810",
|
||||
feature = "nrf52811",
|
||||
@ -68,7 +68,7 @@ pub(crate) mod util;
|
||||
#[cfg(feature = "_time-driver")]
|
||||
mod time_driver;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod buffered_uarte;
|
||||
pub mod gpio;
|
||||
#[cfg(feature = "gpiote")]
|
||||
@ -78,7 +78,7 @@ pub mod gpiote;
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
|
||||
pub mod radio;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod egu;
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
pub mod i2s;
|
||||
@ -95,32 +95,32 @@ pub mod nvmc;
|
||||
pub mod pdm;
|
||||
pub mod ppi;
|
||||
#[cfg(not(any(
|
||||
feature = "nrf51",
|
||||
feature = "_nrf51",
|
||||
feature = "nrf52805",
|
||||
feature = "nrf52820",
|
||||
feature = "_nrf5340-net"
|
||||
)))]
|
||||
pub mod pwm;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
|
||||
pub mod qdec;
|
||||
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
||||
pub mod qspi;
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod spim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod spis;
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
pub mod temp;
|
||||
pub mod timer;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod twim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod twis;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
pub mod uarte;
|
||||
#[cfg(any(
|
||||
feature = "_nrf5340-app",
|
||||
@ -133,7 +133,7 @@ pub mod usb;
|
||||
pub mod wdt;
|
||||
|
||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
|
||||
#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")]
|
||||
#[cfg_attr(feature = "_nrf51", path = "chips/nrf51.rs")]
|
||||
#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
|
||||
#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
|
||||
#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
|
||||
@ -216,6 +216,7 @@ pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
|
||||
pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
|
||||
pub use crate::chip::interrupt;
|
||||
#[cfg(feature = "rt")]
|
||||
pub use crate::pac::NVIC_PRIO_BITS;
|
||||
|
||||
pub mod config {
|
||||
@ -405,7 +406,7 @@ mod consts {
|
||||
pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum WriteResult {
|
||||
@ -417,12 +418,12 @@ enum WriteResult {
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
|
||||
uicr_write_masked(address, value, 0xFFFF_FFFF)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult {
|
||||
let curr_val = address.read_volatile();
|
||||
if curr_val & mask == value & mask {
|
||||
@ -434,13 +435,13 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe
|
||||
return WriteResult::Failed;
|
||||
}
|
||||
|
||||
let nvmc = &*pac::NVMC::ptr();
|
||||
nvmc.config.write(|w| w.wen().wen());
|
||||
while nvmc.ready.read().ready().is_busy() {}
|
||||
let nvmc = pac::NVMC;
|
||||
nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN));
|
||||
while !nvmc.ready().read().ready() {}
|
||||
address.write_volatile(value | !mask);
|
||||
while nvmc.ready.read().ready().is_busy() {}
|
||||
nvmc.config.reset();
|
||||
while nvmc.ready.read().ready().is_busy() {}
|
||||
while !nvmc.ready().read().ready() {}
|
||||
nvmc.config().write(|_| {});
|
||||
while !nvmc.ready().read().ready() {}
|
||||
|
||||
WriteResult::Written
|
||||
}
|
||||
@ -459,7 +460,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
let mut needs_reset = false;
|
||||
|
||||
// Setup debug protection.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
match config.debug {
|
||||
config::Debug::Allowed => {
|
||||
#[cfg(feature = "_nrf52")]
|
||||
@ -486,17 +487,17 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
unsafe {
|
||||
let p = &*pac::CTRLAP::ptr();
|
||||
let p = pac::CTRLAP;
|
||||
|
||||
let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
|
||||
needs_reset |= res == WriteResult::Written;
|
||||
p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED));
|
||||
p.approtect().disable().write_value(consts::APPROTECT_DISABLED);
|
||||
|
||||
#[cfg(feature = "_nrf5340-app")]
|
||||
{
|
||||
let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED);
|
||||
needs_reset |= res == WriteResult::Written;
|
||||
p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED));
|
||||
p.secureapprotect().disable().write_value(consts::APPROTECT_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,85 +577,79 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
cortex_m::peripheral::SCB::sys_reset();
|
||||
}
|
||||
|
||||
let r = unsafe { &*pac::CLOCK::ptr() };
|
||||
let r = pac::CLOCK;
|
||||
|
||||
// Start HFCLK.
|
||||
match config.hfclk_source {
|
||||
config::HfclkSource::Internal => {}
|
||||
config::HfclkSource::ExternalXtal => {
|
||||
// Datasheet says this is likely to take 0.36ms
|
||||
r.events_hfclkstarted.write(|w| unsafe { w.bits(0) });
|
||||
r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_hfclkstarted.read().bits() == 0 {}
|
||||
r.events_hfclkstarted().write_value(0);
|
||||
r.tasks_hfclkstart().write_value(1);
|
||||
while r.events_hfclkstarted().read() == 0 {}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure LFCLK.
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))]
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91")))]
|
||||
match config.lfclk_source {
|
||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
|
||||
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
|
||||
|
||||
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().xtal()),
|
||||
|
||||
config::LfclkSource::ExternalLowSwing => r.lfclksrc.write(|w| {
|
||||
w.src().xtal();
|
||||
w.external().enabled();
|
||||
w.bypass().disabled();
|
||||
w
|
||||
config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::RC)),
|
||||
config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::SYNTH)),
|
||||
config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::XTAL)),
|
||||
config::LfclkSource::ExternalLowSwing => r.lfclksrc().write(|w| {
|
||||
w.set_src(pac::clock::vals::Lfclksrc::XTAL);
|
||||
w.set_external(true);
|
||||
w.set_bypass(false);
|
||||
}),
|
||||
config::LfclkSource::ExternalFullSwing => r.lfclksrc.write(|w| {
|
||||
w.src().xtal();
|
||||
w.external().enabled();
|
||||
w.bypass().enabled();
|
||||
w
|
||||
config::LfclkSource::ExternalFullSwing => r.lfclksrc().write(|w| {
|
||||
w.set_src(pac::clock::vals::Lfclksrc::XTAL);
|
||||
w.set_external(true);
|
||||
w.set_bypass(true);
|
||||
}),
|
||||
}
|
||||
#[cfg(feature = "_nrf91")]
|
||||
match config.lfclk_source {
|
||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
|
||||
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
|
||||
config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)),
|
||||
config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)),
|
||||
}
|
||||
|
||||
// Start LFCLK.
|
||||
// Datasheet says this could take 100us from synth source
|
||||
// 600us from rc source, 0.25s from an external source.
|
||||
r.events_lfclkstarted.write(|w| unsafe { w.bits(0) });
|
||||
r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_lfclkstarted.read().bits() == 0 {}
|
||||
r.events_lfclkstarted().write_value(0);
|
||||
r.tasks_lfclkstart().write_value(1);
|
||||
while r.events_lfclkstarted().read() == 0 {}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
{
|
||||
// Setup DCDCs.
|
||||
let pwr = unsafe { &*pac::POWER::ptr() };
|
||||
#[cfg(feature = "nrf52840")]
|
||||
if config.dcdc.reg0 {
|
||||
pwr.dcdcen0.write(|w| w.dcdcen().set_bit());
|
||||
pac::POWER.dcdcen0().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
if config.dcdc.reg1 {
|
||||
pwr.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
pac::POWER.dcdcen().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "_nrf91")]
|
||||
{
|
||||
// Setup DCDC.
|
||||
let reg = unsafe { &*pac::REGULATORS::ptr() };
|
||||
if config.dcdc.regmain {
|
||||
reg.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
pac::REGULATORS.dcdcen().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "_nrf5340-app")]
|
||||
{
|
||||
// Setup DCDC.
|
||||
let reg = unsafe { &*pac::REGULATORS::ptr() };
|
||||
let reg = pac::REGULATORS;
|
||||
if config.dcdc.regh {
|
||||
reg.vregh.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
reg.vregh().dcdcen().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
if config.dcdc.regmain {
|
||||
reg.vregmain.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
reg.vregmain().dcdcen().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
if config.dcdc.regradio {
|
||||
reg.vregradio.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -668,9 +663,10 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
|
||||
// Disable UARTE (enabled by default for some reason)
|
||||
#[cfg(feature = "_nrf91")]
|
||||
unsafe {
|
||||
(*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
|
||||
(*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
|
||||
{
|
||||
use pac::uarte::vals::Enable;
|
||||
pac::UARTE0.enable().write(|w| w.set_enable(Enable::DISABLED));
|
||||
pac::UARTE1.enable().write(|w| w.set_enable(Enable::DISABLED));
|
||||
}
|
||||
|
||||
peripherals
|
||||
|
@ -7,6 +7,7 @@ use embedded_storage::nor_flash::{
|
||||
ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
|
||||
};
|
||||
|
||||
use crate::pac::nvmc::vals;
|
||||
use crate::peripherals::NVMC;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -51,13 +52,13 @@ impl<'d> Nvmc<'d> {
|
||||
Self { _p }
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::nvmc::RegisterBlock {
|
||||
unsafe { &*pac::NVMC::ptr() }
|
||||
fn regs() -> pac::nvmc::Nvmc {
|
||||
pac::NVMC
|
||||
}
|
||||
|
||||
fn wait_ready(&mut self) {
|
||||
let p = Self::regs();
|
||||
while p.ready.read().ready().is_busy() {}
|
||||
while !p.ready().read().ready() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||
@ -68,12 +69,12 @@ impl<'d> Nvmc<'d> {
|
||||
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||
fn wait_ready_write(&mut self) {
|
||||
let p = Self::regs();
|
||||
while p.readynext.read().readynext().is_busy() {}
|
||||
while !p.readynext().read().readynext() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||
fn erase_page(&mut self, page_addr: u32) {
|
||||
Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) });
|
||||
Self::regs().erasepage().write_value(page_addr);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||
@ -86,23 +87,23 @@ impl<'d> Nvmc<'d> {
|
||||
|
||||
fn enable_erase(&self) {
|
||||
#[cfg(not(feature = "_ns"))]
|
||||
Self::regs().config.write(|w| w.wen().een());
|
||||
Self::regs().config().write(|w| w.set_wen(vals::Wen::EEN));
|
||||
#[cfg(feature = "_ns")]
|
||||
Self::regs().configns.write(|w| w.wen().een());
|
||||
Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::EEN));
|
||||
}
|
||||
|
||||
fn enable_read(&self) {
|
||||
#[cfg(not(feature = "_ns"))]
|
||||
Self::regs().config.write(|w| w.wen().ren());
|
||||
Self::regs().config().write(|w| w.set_wen(vals::Wen::REN));
|
||||
#[cfg(feature = "_ns")]
|
||||
Self::regs().configns.write(|w| w.wen().ren());
|
||||
Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::REN));
|
||||
}
|
||||
|
||||
fn enable_write(&self) {
|
||||
#[cfg(not(feature = "_ns"))]
|
||||
Self::regs().config.write(|w| w.wen().wen());
|
||||
Self::regs().config().write(|w| w.set_wen(vals::Wen::WEN));
|
||||
#[cfg(feature = "_ns")]
|
||||
Self::regs().configns.write(|w| w.wen().wen());
|
||||
Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::WEN));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,18 +13,19 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
use fixed::types::I7F1;
|
||||
|
||||
use crate::chip::EASY_DMA_SIZE;
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin};
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::pdm::mode::{EDGE_A, OPERATION_A};
|
||||
pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::pdm::vals;
|
||||
pub use crate::pac::pdm::vals::Freq as Frequency;
|
||||
#[cfg(any(
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
|
||||
use crate::{interrupt, Peripheral};
|
||||
pub use crate::pac::pdm::vals::Ratio;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Interrupt handler
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
@ -35,16 +36,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
if r.events_end().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
if r.events_started().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_started(true));
|
||||
}
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
if r.events_stopped().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_stopped(true));
|
||||
}
|
||||
|
||||
T::state().waker.wake();
|
||||
@ -109,50 +110,47 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// setup gpio pins
|
||||
din.conf().write(|w| w.input().set_bit());
|
||||
r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) });
|
||||
din.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
|
||||
r.psel().din().write_value(din.psel_bits());
|
||||
clk.set_low();
|
||||
clk.conf().write(|w| w.dir().output());
|
||||
r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) });
|
||||
clk.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT));
|
||||
r.psel().clk().write_value(clk.psel_bits());
|
||||
|
||||
// configure
|
||||
r.pdmclkctrl.write(|w| w.freq().variant(config.frequency));
|
||||
r.pdmclkctrl().write(|w| w.set_freq(config.frequency));
|
||||
#[cfg(any(
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
r.ratio.write(|w| w.ratio().variant(config.ratio));
|
||||
r.mode.write(|w| {
|
||||
w.operation().variant(config.operation_mode.into());
|
||||
w.edge().variant(config.edge.into());
|
||||
w
|
||||
r.ratio().write(|w| w.set_ratio(config.ratio));
|
||||
r.mode().write(|w| {
|
||||
w.set_operation(config.operation_mode.into());
|
||||
w.set_edge(config.edge.into());
|
||||
});
|
||||
|
||||
Self::_set_gain(r, config.gain_left, config.gain_right);
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0x003F_FFFF);
|
||||
|
||||
// IRQ
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
r.enable.write(|w| w.enable().set_bit());
|
||||
r.enable().write(|w| w.set_enable(true));
|
||||
|
||||
Self { _peri: pdm }
|
||||
}
|
||||
|
||||
fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) {
|
||||
let gain_to_bits = |gain: I7F1| -> u8 {
|
||||
let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50);
|
||||
unsafe { core::mem::transmute(gain) }
|
||||
fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) {
|
||||
let gain_to_bits = |gain: I7F1| -> vals::Gain {
|
||||
let gain: i8 = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50);
|
||||
vals::Gain::from_bits(gain as u8)
|
||||
};
|
||||
let gain_left = gain_to_bits(gain_left);
|
||||
let gain_right = gain_to_bits(gain_right);
|
||||
r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) });
|
||||
r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) });
|
||||
r.gainl().write(|w| w.set_gainl(gain_to_bits(gain_left)));
|
||||
r.gainr().write(|w| w.set_gainr(gain_to_bits(gain_right)));
|
||||
}
|
||||
|
||||
/// Adjust the gain of the PDM microphone on the fly
|
||||
@ -166,21 +164,17 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// start dummy sampling because microphone needs some setup time
|
||||
r.sample
|
||||
.ptr
|
||||
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
|
||||
r.sample
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
|
||||
r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
|
||||
r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
|
||||
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
}
|
||||
|
||||
/// Stop sampling microphone data inta a dummy buffer
|
||||
pub async fn stop(&mut self) {
|
||||
let r = T::regs();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.events_started.reset();
|
||||
r.tasks_stop().write_value(1);
|
||||
r.events_started().write_value(0);
|
||||
}
|
||||
|
||||
/// Sample data into the given buffer
|
||||
@ -194,41 +188,33 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
if r.events_started.read().bits() == 0 {
|
||||
if r.events_started().read() == 0 {
|
||||
return Err(Error::NotRunning);
|
||||
}
|
||||
|
||||
let drop = OnDrop::new(move || {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
r.events_stopped.reset();
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
r.events_stopped().write_value(0);
|
||||
|
||||
// reset to dummy buffer
|
||||
r.sample
|
||||
.ptr
|
||||
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
|
||||
r.sample
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
|
||||
r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
|
||||
r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
|
||||
|
||||
while r.events_stopped.read().bits() == 0 {}
|
||||
while r.events_stopped().read() == 0 {}
|
||||
});
|
||||
|
||||
// setup user buffer
|
||||
let ptr = buffer.as_ptr();
|
||||
let len = buffer.len();
|
||||
r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) });
|
||||
r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) });
|
||||
r.sample().ptr().write_value(ptr as u32);
|
||||
r.sample().maxcnt().write(|w| w.set_buffsize(len as _));
|
||||
|
||||
// wait till the current sample is finished and the user buffer sample is started
|
||||
Self::wait_for_sample().await;
|
||||
|
||||
// reset the buffer back to the dummy buffer
|
||||
r.sample
|
||||
.ptr
|
||||
.write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
|
||||
r.sample
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
|
||||
r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
|
||||
r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
|
||||
|
||||
// wait till the user buffer is sampled
|
||||
Self::wait_for_sample().await;
|
||||
@ -241,14 +227,14 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
async fn wait_for_sample() {
|
||||
let r = T::regs();
|
||||
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.events_end().write_value(0);
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
poll_fn(|cx| {
|
||||
T::state().waker.register(cx.waker());
|
||||
if r.events_end.read().bits() != 0 {
|
||||
if r.events_end().read() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -279,40 +265,37 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
{
|
||||
let r = T::regs();
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
if r.events_started().read() != 0 {
|
||||
return Err(Error::AlreadyRunning);
|
||||
}
|
||||
|
||||
r.sample
|
||||
.ptr
|
||||
.write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) });
|
||||
r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) });
|
||||
r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32);
|
||||
r.sample().maxcnt().write(|w| w.set_buffsize(N as _));
|
||||
|
||||
// Reset and enable the events
|
||||
r.events_end.reset();
|
||||
r.events_started.reset();
|
||||
r.events_stopped.reset();
|
||||
r.intenset.write(|w| {
|
||||
w.end().set();
|
||||
w.started().set();
|
||||
w.stopped().set();
|
||||
w
|
||||
r.events_end().write_value(0);
|
||||
r.events_started().write_value(0);
|
||||
r.events_stopped().write_value(0);
|
||||
r.intenset().write(|w| {
|
||||
w.set_end(true);
|
||||
w.set_started(true);
|
||||
w.set_stopped(true);
|
||||
});
|
||||
|
||||
// Don't reorder the start event before the previous writes. Hopefully self
|
||||
// wouldn't happen anyway
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
|
||||
let mut current_buffer = 0;
|
||||
|
||||
let mut done = false;
|
||||
|
||||
let drop = OnDrop::new(|| {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
// N.B. It would be better if this were async, but Drop only support sync code
|
||||
while r.events_stopped.read().bits() != 0 {}
|
||||
while r.events_stopped().read() != 0 {}
|
||||
});
|
||||
|
||||
// Wait for events and complete when the sampler indicates it has had enough
|
||||
@ -321,11 +304,11 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
|
||||
T::state().waker.register(cx.waker());
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
if r.events_end().read() != 0 {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.events_end().write_value(0);
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
if !done {
|
||||
// Discard the last buffer after the user requested a stop
|
||||
@ -333,23 +316,21 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
let next_buffer = 1 - current_buffer;
|
||||
current_buffer = next_buffer;
|
||||
} else {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
done = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.events_started.reset();
|
||||
r.intenset.write(|w| w.started().set());
|
||||
if r.events_started().read() != 0 {
|
||||
r.events_started().write_value(0);
|
||||
r.intenset().write(|w| w.set_started(true));
|
||||
|
||||
let next_buffer = 1 - current_buffer;
|
||||
r.sample
|
||||
.ptr
|
||||
.write(|w| unsafe { w.sampleptr().bits(bufs[next_buffer].as_mut_ptr() as u32) });
|
||||
r.sample().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32);
|
||||
}
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_stopped().read() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -411,11 +392,11 @@ pub enum OperationMode {
|
||||
Stereo,
|
||||
}
|
||||
|
||||
impl From<OperationMode> for OPERATION_A {
|
||||
impl From<OperationMode> for vals::Operation {
|
||||
fn from(mode: OperationMode) -> Self {
|
||||
match mode {
|
||||
OperationMode::Mono => OPERATION_A::MONO,
|
||||
OperationMode::Stereo => OPERATION_A::STEREO,
|
||||
OperationMode::Mono => vals::Operation::MONO,
|
||||
OperationMode::Stereo => vals::Operation::STEREO,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -429,11 +410,11 @@ pub enum Edge {
|
||||
LeftFalling,
|
||||
}
|
||||
|
||||
impl From<Edge> for EDGE_A {
|
||||
impl From<Edge> for vals::Edge {
|
||||
fn from(edge: Edge) -> Self {
|
||||
match edge {
|
||||
Edge::LeftRising => EDGE_A::LEFT_RISING,
|
||||
Edge::LeftFalling => EDGE_A::LEFT_FALLING,
|
||||
Edge::LeftRising => vals::Edge::LEFT_RISING,
|
||||
Edge::LeftFalling => vals::Edge::LEFT_FALLING,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -442,12 +423,12 @@ impl<'d, T: Instance> Drop for Pdm<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
let r = T::regs();
|
||||
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(false));
|
||||
|
||||
r.psel.din.reset();
|
||||
r.psel.clk.reset();
|
||||
r.psel().din().write_value(DISCONNECTED);
|
||||
r.psel().clk().write_value(DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +446,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::pdm::RegisterBlock;
|
||||
fn regs() -> crate::pac::pdm::Pdm;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -479,8 +460,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_pdm {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::pdm::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::pdm::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> crate::pac::pdm::Pdm {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::pdm::State {
|
||||
static STATE: crate::pdm::State = crate::pdm::State::new();
|
||||
|
@ -6,8 +6,8 @@ use crate::{pac, Peripheral};
|
||||
const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
|
||||
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
|
||||
|
||||
pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
|
||||
unsafe { &*pac::DPPIC::ptr() }
|
||||
pub(crate) fn regs() -> pac::dppic::Dppic {
|
||||
pac::DPPIC
|
||||
}
|
||||
|
||||
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
|
||||
@ -57,13 +57,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d,
|
||||
/// Enables the channel.
|
||||
pub fn enable(&mut self) {
|
||||
let n = self.ch.number();
|
||||
regs().chenset.write(|w| unsafe { w.bits(1 << n) });
|
||||
regs().chenset().write(|w| w.0 = 1 << n);
|
||||
}
|
||||
|
||||
/// Disables the channel.
|
||||
pub fn disable(&mut self) {
|
||||
let n = self.ch.number();
|
||||
regs().chenclr.write(|w| unsafe { w.bits(1 << n) });
|
||||
regs().chenclr().write(|w| w.0 = 1 << n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ use core::ptr::NonNull;
|
||||
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::common::{Reg, RW, W};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
#[cfg_attr(feature = "_dppi", path = "dppi.rs")]
|
||||
@ -50,7 +51,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
|
||||
|
||||
let r = regs();
|
||||
let n = g.number();
|
||||
r.chg[n].write(|w| unsafe { w.bits(0) });
|
||||
r.chg(n).write(|_| ());
|
||||
|
||||
Self { g }
|
||||
}
|
||||
@ -65,7 +66,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
|
||||
let r = regs();
|
||||
let ng = self.g.number();
|
||||
let nc = ch.ch.number();
|
||||
r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) });
|
||||
r.chg(ng).modify(|w| w.set_ch(nc, true));
|
||||
}
|
||||
|
||||
/// Remove a PPI channel from this group.
|
||||
@ -78,19 +79,19 @@ impl<'d, G: Group> PpiGroup<'d, G> {
|
||||
let r = regs();
|
||||
let ng = self.g.number();
|
||||
let nc = ch.ch.number();
|
||||
r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) });
|
||||
r.chg(ng).modify(|w| w.set_ch(nc, false));
|
||||
}
|
||||
|
||||
/// Enable all the channels in this group.
|
||||
pub fn enable_all(&mut self) {
|
||||
let n = self.g.number();
|
||||
regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) });
|
||||
regs().tasks_chg(n).en().write_value(1);
|
||||
}
|
||||
|
||||
/// Disable all the channels in this group.
|
||||
pub fn disable_all(&mut self) {
|
||||
let n = self.g.number();
|
||||
regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) });
|
||||
regs().tasks_chg(n).dis().write_value(1);
|
||||
}
|
||||
|
||||
/// Get a reference to the "enable all" task.
|
||||
@ -98,7 +99,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
|
||||
/// When triggered, it will enable all the channels in this group.
|
||||
pub fn task_enable_all(&self) -> Task<'d> {
|
||||
let n = self.g.number();
|
||||
Task::from_reg(®s().tasks_chg[n].en)
|
||||
Task::from_reg(regs().tasks_chg(n).en())
|
||||
}
|
||||
|
||||
/// Get a reference to the "disable all" task.
|
||||
@ -106,7 +107,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
|
||||
/// When triggered, it will disable all the channels in this group.
|
||||
pub fn task_disable_all(&self) -> Task<'d> {
|
||||
let n = self.g.number();
|
||||
Task::from_reg(®s().tasks_chg[n].dis)
|
||||
Task::from_reg(regs().tasks_chg(n).dis())
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +115,7 @@ impl<'d, G: Group> Drop for PpiGroup<'d, G> {
|
||||
fn drop(&mut self) {
|
||||
let r = regs();
|
||||
let n = self.g.number();
|
||||
r.chg[n].write(|w| unsafe { w.bits(0) });
|
||||
r.chg(n).write(|_| ());
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,11 +144,8 @@ impl<'d> Task<'d> {
|
||||
unsafe { self.0.as_ptr().write_volatile(1) };
|
||||
}
|
||||
|
||||
pub(crate) fn from_reg<T>(reg: &T) -> Self {
|
||||
Self(
|
||||
unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
|
||||
PhantomData,
|
||||
)
|
||||
pub(crate) fn from_reg(reg: Reg<u32, W>) -> Self {
|
||||
Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData)
|
||||
}
|
||||
|
||||
/// Address of subscription register for this task.
|
||||
@ -178,11 +176,8 @@ impl<'d> Event<'d> {
|
||||
Self(ptr, PhantomData)
|
||||
}
|
||||
|
||||
pub(crate) fn from_reg<T>(reg: &'d T) -> Self {
|
||||
Self(
|
||||
unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
|
||||
PhantomData,
|
||||
)
|
||||
pub(crate) fn from_reg(reg: Reg<u32, RW>) -> Self {
|
||||
Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData)
|
||||
}
|
||||
|
||||
/// Describes whether this Event is currently in a triggered state.
|
||||
@ -284,7 +279,7 @@ impl ConfigurableChannel for AnyConfigurableChannel {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
macro_rules! impl_ppi_channel {
|
||||
($type:ident, $number:expr) => {
|
||||
impl crate::ppi::SealedChannel for peripherals::$type {}
|
||||
@ -366,7 +361,7 @@ impl_group!(PPI_GROUP0, 0);
|
||||
impl_group!(PPI_GROUP1, 1);
|
||||
impl_group!(PPI_GROUP2, 2);
|
||||
impl_group!(PPI_GROUP3, 3);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_group!(PPI_GROUP4, 4);
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
impl_group!(PPI_GROUP5, 5);
|
||||
|
@ -14,11 +14,11 @@ impl<'d> Event<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
unsafe { &*pac::PPI::ptr() }
|
||||
pub(crate) fn regs() -> pac::ppi::Ppi {
|
||||
pac::PPI
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
|
||||
#[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task
|
||||
impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
/// Configure PPI channel to trigger `task`.
|
||||
pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
|
||||
@ -26,7 +26,7 @@ impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
|
||||
let r = regs();
|
||||
let n = ch.number();
|
||||
r.fork[n].tep.write(|w| unsafe { w.bits(task.reg_val()) });
|
||||
r.fork(n).tep().write_value(task.reg_val());
|
||||
|
||||
Self { ch }
|
||||
}
|
||||
@ -39,14 +39,14 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
|
||||
|
||||
let r = regs();
|
||||
let n = ch.number();
|
||||
r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) });
|
||||
r.ch[n].tep.write(|w| unsafe { w.bits(task.reg_val()) });
|
||||
r.ch(n).eep().write_value(event.reg_val());
|
||||
r.ch(n).tep().write_value(task.reg_val());
|
||||
|
||||
Self { ch }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
|
||||
#[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task
|
||||
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
|
||||
/// Configure PPI channel to trigger both `task1` and `task2` on `event`.
|
||||
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self {
|
||||
@ -54,9 +54,9 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
|
||||
|
||||
let r = regs();
|
||||
let n = ch.number();
|
||||
r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) });
|
||||
r.ch[n].tep.write(|w| unsafe { w.bits(task1.reg_val()) });
|
||||
r.fork[n].tep.write(|w| unsafe { w.bits(task2.reg_val()) });
|
||||
r.ch(n).eep().write_value(event.reg_val());
|
||||
r.ch(n).tep().write_value(task1.reg_val());
|
||||
r.fork(n).tep().write_value(task2.reg_val());
|
||||
|
||||
Self { ch }
|
||||
}
|
||||
@ -66,13 +66,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d,
|
||||
/// Enables the channel.
|
||||
pub fn enable(&mut self) {
|
||||
let n = self.ch.number();
|
||||
regs().chenset.write(|w| unsafe { w.bits(1 << n) });
|
||||
regs().chenset().write(|w| w.set_ch(n, true));
|
||||
}
|
||||
|
||||
/// Disables the channel.
|
||||
pub fn disable(&mut self) {
|
||||
let n = self.ch.number();
|
||||
regs().chenclr.write(|w| unsafe { w.bits(1 << n) });
|
||||
regs().chenclr().write(|w| w.set_ch(n, true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,9 +82,9 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for
|
||||
|
||||
let r = regs();
|
||||
let n = self.ch.number();
|
||||
r.ch[n].eep.write(|w| unsafe { w.bits(0) });
|
||||
r.ch[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
r.fork[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
r.ch(n).eep().write_value(0);
|
||||
r.ch(n).tep().write_value(0);
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
r.fork(n).tep().write_value(0);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _};
|
||||
use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED};
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::pwm::vals;
|
||||
use crate::ppi::{Event, Task};
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
@ -128,52 +130,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<P = Self> + SealedInstance + 'static {
|
||||
macro_rules! impl_pwm {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::pwm::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::pwm0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::pwm::Pwm {
|
||||
pac::$pac_type
|
||||
}
|
||||
}
|
||||
impl crate::pwm::Instance for peripherals::$type {
|
||||
|
@ -11,7 +11,9 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::qdec::vals;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Quadrature decoder driver.
|
||||
pub struct Qdec<'d, T: Instance> {
|
||||
@ -52,7 +54,7 @@ pub struct InterruptHandler<T: Instance> {
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
T::regs().intenclr.write(|w| w.reportrdy().clear());
|
||||
T::regs().intenclr().write(|w| w.set_reportrdy(true));
|
||||
T::state().waker.wake();
|
||||
}
|
||||
}
|
||||
@ -93,54 +95,59 @@ impl<'d, T: Instance> Qdec<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// Select pins.
|
||||
a.conf().write(|w| w.input().connect().pull().pullup());
|
||||
b.conf().write(|w| w.input().connect().pull().pullup());
|
||||
r.psel.a.write(|w| unsafe { w.bits(a.psel_bits()) });
|
||||
r.psel.b.write(|w| unsafe { w.bits(b.psel_bits()) });
|
||||
a.conf().write(|w| {
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
});
|
||||
b.conf().write(|w| {
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
});
|
||||
r.psel().a().write_value(a.psel_bits());
|
||||
r.psel().b().write_value(b.psel_bits());
|
||||
if let Some(led_pin) = &led {
|
||||
led_pin.conf().write(|w| w.dir().output());
|
||||
r.psel.led.write(|w| unsafe { w.bits(led_pin.psel_bits()) });
|
||||
led_pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT));
|
||||
r.psel().led().write_value(led_pin.psel_bits());
|
||||
}
|
||||
|
||||
// Enables/disable input debounce filters
|
||||
r.dbfen.write(|w| match config.debounce {
|
||||
true => w.dbfen().enabled(),
|
||||
false => w.dbfen().disabled(),
|
||||
r.dbfen().write(|w| match config.debounce {
|
||||
true => w.set_dbfen(true),
|
||||
false => w.set_dbfen(false),
|
||||
});
|
||||
|
||||
// Set LED output pin polarity
|
||||
r.ledpol.write(|w| match config.led_polarity {
|
||||
LedPolarity::ActiveHigh => w.ledpol().active_high(),
|
||||
LedPolarity::ActiveLow => w.ledpol().active_low(),
|
||||
r.ledpol().write(|w| match config.led_polarity {
|
||||
LedPolarity::ActiveHigh => w.set_ledpol(vals::Ledpol::ACTIVE_HIGH),
|
||||
LedPolarity::ActiveLow => w.set_ledpol(vals::Ledpol::ACTIVE_LOW),
|
||||
});
|
||||
|
||||
// Set time period the LED is switched ON prior to sampling (0..511 us).
|
||||
r.ledpre
|
||||
.write(|w| unsafe { w.ledpre().bits(config.led_pre_usecs.min(511)) });
|
||||
r.ledpre().write(|w| w.set_ledpre(config.led_pre_usecs.min(511)));
|
||||
|
||||
// Set sample period
|
||||
r.sampleper.write(|w| match config.period {
|
||||
SamplePeriod::_128us => w.sampleper()._128us(),
|
||||
SamplePeriod::_256us => w.sampleper()._256us(),
|
||||
SamplePeriod::_512us => w.sampleper()._512us(),
|
||||
SamplePeriod::_1024us => w.sampleper()._1024us(),
|
||||
SamplePeriod::_2048us => w.sampleper()._2048us(),
|
||||
SamplePeriod::_4096us => w.sampleper()._4096us(),
|
||||
SamplePeriod::_8192us => w.sampleper()._8192us(),
|
||||
SamplePeriod::_16384us => w.sampleper()._16384us(),
|
||||
SamplePeriod::_32ms => w.sampleper()._32ms(),
|
||||
SamplePeriod::_65ms => w.sampleper()._65ms(),
|
||||
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
||||
r.sampleper().write(|w| match config.period {
|
||||
SamplePeriod::_128us => w.set_sampleper(vals::Sampleper::_128US),
|
||||
SamplePeriod::_256us => w.set_sampleper(vals::Sampleper::_256US),
|
||||
SamplePeriod::_512us => w.set_sampleper(vals::Sampleper::_512US),
|
||||
SamplePeriod::_1024us => w.set_sampleper(vals::Sampleper::_1024US),
|
||||
SamplePeriod::_2048us => w.set_sampleper(vals::Sampleper::_2048US),
|
||||
SamplePeriod::_4096us => w.set_sampleper(vals::Sampleper::_4096US),
|
||||
SamplePeriod::_8192us => w.set_sampleper(vals::Sampleper::_8192US),
|
||||
SamplePeriod::_16384us => w.set_sampleper(vals::Sampleper::_16384US),
|
||||
SamplePeriod::_32ms => w.set_sampleper(vals::Sampleper::_32MS),
|
||||
SamplePeriod::_65ms => w.set_sampleper(vals::Sampleper::_65MS),
|
||||
SamplePeriod::_131ms => w.set_sampleper(vals::Sampleper::_131MS),
|
||||
});
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
// Enable peripheral
|
||||
r.enable.write(|w| w.enable().set_bit());
|
||||
r.enable().write(|w| w.set_enable(true));
|
||||
|
||||
// Start sampling
|
||||
unsafe { r.tasks_start.write(|w| w.bits(1)) };
|
||||
r.tasks_start().write_value(1);
|
||||
|
||||
Self { _p: p }
|
||||
}
|
||||
@ -169,16 +176,16 @@ impl<'d, T: Instance> Qdec<'d, T> {
|
||||
/// ```
|
||||
pub async fn read(&mut self) -> i16 {
|
||||
let t = T::regs();
|
||||
t.intenset.write(|w| w.reportrdy().set());
|
||||
unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
|
||||
t.intenset().write(|w| w.set_reportrdy(true));
|
||||
t.tasks_readclracc().write_value(1);
|
||||
|
||||
poll_fn(|cx| {
|
||||
T::state().waker.register(cx.waker());
|
||||
if t.events_reportrdy.read().bits() == 0 {
|
||||
if t.events_reportrdy().read() == 0 {
|
||||
Poll::Pending
|
||||
} else {
|
||||
t.events_reportrdy.reset();
|
||||
let acc = t.accread.read().bits();
|
||||
t.events_reportrdy().write_value(0);
|
||||
let acc = t.accread().read();
|
||||
Poll::Ready(acc as i16)
|
||||
}
|
||||
})
|
||||
@ -259,7 +266,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock;
|
||||
fn regs() -> pac::qdec::Qdec;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -273,8 +280,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_qdec {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qdec::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::qdec::Qdec {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::qdec::State {
|
||||
static STATE: crate::qdec::State = crate::qdec::State::new();
|
||||
|
@ -14,11 +14,12 @@ use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashEr
|
||||
|
||||
use crate::gpio::{self, Pin as GpioPin};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
pub use crate::pac::qspi::ifconfig0::{
|
||||
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::qspi::vals;
|
||||
pub use crate::pac::qspi::vals::{
|
||||
Addrmode as AddressMode, Ppsize as WritePageSize, Readoc as ReadOpcode, Spimode as SpiMode, Writeoc as WriteOpcode,
|
||||
};
|
||||
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Deep power-down config.
|
||||
pub struct DeepPowerDownConfig {
|
||||
@ -129,9 +130,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
if r.events_ready().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.ready().clear());
|
||||
r.intenclr().write(|w| w.set_ready(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,13 +165,12 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
($pin:ident) => {
|
||||
$pin.set_high();
|
||||
$pin.conf().write(|w| {
|
||||
w.dir().output();
|
||||
w.drive().h0h1();
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_drive(gpiovals::Drive::H0H1);
|
||||
#[cfg(all(feature = "_nrf5340", feature = "_s"))]
|
||||
w.mcusel().peripheral();
|
||||
w
|
||||
w.set_mcusel(gpiovals::Mcusel::PERIPHERAL);
|
||||
});
|
||||
r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) });
|
||||
r.psel().$pin().write_value($pin.psel_bits());
|
||||
};
|
||||
}
|
||||
|
||||
@ -181,46 +181,39 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
config_pin!(io2);
|
||||
config_pin!(io3);
|
||||
|
||||
r.ifconfig0.write(|w| {
|
||||
w.addrmode().variant(config.address_mode);
|
||||
w.dpmenable().bit(config.deep_power_down.is_some());
|
||||
w.ppsize().variant(config.write_page_size);
|
||||
w.readoc().variant(config.read_opcode);
|
||||
w.writeoc().variant(config.write_opcode);
|
||||
w
|
||||
r.ifconfig0().write(|w| {
|
||||
w.set_addrmode(config.address_mode);
|
||||
w.set_dpmenable(config.deep_power_down.is_some());
|
||||
w.set_ppsize(config.write_page_size);
|
||||
w.set_readoc(config.read_opcode);
|
||||
w.set_writeoc(config.write_opcode);
|
||||
});
|
||||
|
||||
if let Some(dpd) = &config.deep_power_down {
|
||||
r.dpmdur.write(|w| unsafe {
|
||||
w.enter().bits(dpd.enter_time);
|
||||
w.exit().bits(dpd.exit_time);
|
||||
w
|
||||
r.dpmdur().write(|w| {
|
||||
w.set_enter(dpd.enter_time);
|
||||
w.set_exit(dpd.exit_time);
|
||||
})
|
||||
}
|
||||
|
||||
r.ifconfig1.write(|w| unsafe {
|
||||
w.sckdelay().bits(config.sck_delay);
|
||||
w.dpmen().exit();
|
||||
w.spimode().variant(config.spi_mode);
|
||||
w.sckfreq().bits(config.frequency as u8);
|
||||
w
|
||||
r.ifconfig1().write(|w| {
|
||||
w.set_sckdelay(config.sck_delay);
|
||||
w.set_dpmen(false);
|
||||
w.set_spimode(config.spi_mode);
|
||||
w.set_sckfreq(config.frequency as u8);
|
||||
});
|
||||
|
||||
r.iftiming.write(|w| unsafe {
|
||||
w.rxdelay().bits(config.rx_delay & 0b111);
|
||||
w
|
||||
r.iftiming().write(|w| {
|
||||
w.set_rxdelay(config.rx_delay & 0b111);
|
||||
});
|
||||
|
||||
r.xipoffset.write(|w| unsafe {
|
||||
w.xipoffset().bits(config.xip_offset);
|
||||
w
|
||||
});
|
||||
r.xipoffset().write_value(config.xip_offset);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
// Enable it
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(true));
|
||||
|
||||
let res = Self {
|
||||
_peri: qspi,
|
||||
@ -228,10 +221,10 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
capacity: config.capacity,
|
||||
};
|
||||
|
||||
r.events_ready.reset();
|
||||
r.intenset.write(|w| w.ready().set());
|
||||
r.events_ready().write_value(0);
|
||||
r.intenset().write(|w| w.set_ready(true));
|
||||
|
||||
r.tasks_activate.write(|w| w.tasks_activate().bit(true));
|
||||
r.tasks_activate().write_value(1);
|
||||
|
||||
Self::blocking_wait_ready();
|
||||
|
||||
@ -284,22 +277,21 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
}
|
||||
|
||||
let r = T::regs();
|
||||
r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
|
||||
r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
|
||||
r.cinstrdat0().write(|w| w.0 = dat0);
|
||||
r.cinstrdat1().write(|w| w.0 = dat1);
|
||||
|
||||
r.events_ready.reset();
|
||||
r.intenset.write(|w| w.ready().set());
|
||||
r.events_ready().write_value(0);
|
||||
r.intenset().write(|w| w.set_ready(true));
|
||||
|
||||
r.cinstrconf.write(|w| {
|
||||
let w = unsafe { w.opcode().bits(opcode) };
|
||||
let w = unsafe { w.length().bits(len + 1) };
|
||||
let w = w.lio2().bit(true);
|
||||
let w = w.lio3().bit(true);
|
||||
let w = w.wipwait().bit(true);
|
||||
let w = w.wren().bit(true);
|
||||
let w = w.lfen().bit(false);
|
||||
let w = w.lfstop().bit(false);
|
||||
w
|
||||
r.cinstrconf().write(|w| {
|
||||
w.set_opcode(opcode);
|
||||
w.set_length(vals::Length::from_bits(len + 1));
|
||||
w.set_lio2(true);
|
||||
w.set_lio3(true);
|
||||
w.set_wipwait(true);
|
||||
w.set_wren(true);
|
||||
w.set_lfen(false);
|
||||
w.set_lfstop(false);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@ -307,8 +299,8 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
let dat0 = r.cinstrdat0.read().bits();
|
||||
let dat1 = r.cinstrdat1.read().bits();
|
||||
let dat0 = r.cinstrdat0().read().0;
|
||||
let dat1 = r.cinstrdat1().read().0;
|
||||
for i in 0..4 {
|
||||
if i < resp.len() {
|
||||
resp[i] = (dat0 >> (i * 8)) as u8;
|
||||
@ -327,7 +319,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
s.waker.register(cx.waker());
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
if r.events_ready().read() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -338,7 +330,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
fn blocking_wait_ready() {
|
||||
loop {
|
||||
let r = T::regs();
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
if r.events_ready().read() != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -352,13 +344,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.read.src.write(|w| unsafe { w.src().bits(address) });
|
||||
r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
|
||||
r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
||||
r.read().src().write_value(address);
|
||||
r.read().dst().write_value(data.as_ptr() as u32);
|
||||
r.read().cnt().write(|w| w.set_cnt(data.len() as u32));
|
||||
|
||||
r.events_ready.reset();
|
||||
r.intenset.write(|w| w.ready().set());
|
||||
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
|
||||
r.events_ready().write_value(0);
|
||||
r.intenset().write(|w| w.set_ready(true));
|
||||
r.tasks_readstart().write_value(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -370,13 +362,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
assert_eq!(address % 4, 0);
|
||||
|
||||
let r = T::regs();
|
||||
r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
|
||||
r.write.dst.write(|w| unsafe { w.dst().bits(address) });
|
||||
r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
||||
r.write().src().write_value(data.as_ptr() as u32);
|
||||
r.write().dst().write_value(address);
|
||||
r.write().cnt().write(|w| w.set_cnt(data.len() as u32));
|
||||
|
||||
r.events_ready.reset();
|
||||
r.intenset.write(|w| w.ready().set());
|
||||
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
|
||||
r.events_ready().write_value(0);
|
||||
r.intenset().write(|w| w.set_ready(true));
|
||||
r.tasks_writestart().write_value(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -386,12 +378,12 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
assert_eq!(address % 4096, 0);
|
||||
|
||||
let r = T::regs();
|
||||
r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) });
|
||||
r.erase.len.write(|w| w.len()._4kb());
|
||||
r.erase().ptr().write_value(address);
|
||||
r.erase().len().write(|w| w.set_len(vals::Len::_4KB));
|
||||
|
||||
r.events_ready.reset();
|
||||
r.intenset.write(|w| w.ready().set());
|
||||
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
|
||||
r.events_ready().write_value(0);
|
||||
r.intenset().write(|w| w.set_ready(true));
|
||||
r.tasks_erasestart().write_value(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -538,12 +530,12 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||
if self.dpm_enabled {
|
||||
trace!("qspi: doing deep powerdown...");
|
||||
|
||||
r.ifconfig1.modify(|_, w| w.dpmen().enter());
|
||||
r.ifconfig1().modify(|w| w.set_dpmen(true));
|
||||
|
||||
// Wait for DPM enter.
|
||||
// Unfortunately we must spin. There's no way to do this interrupt-driven.
|
||||
// The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:)
|
||||
while r.status.read().dpm().is_disabled() {}
|
||||
while !r.status().read().dpm() {}
|
||||
|
||||
// Wait MORE for DPM enter.
|
||||
// I have absolutely no idea why, but the wait above is not enough :'(
|
||||
@ -552,23 +544,23 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||
}
|
||||
|
||||
// it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it.
|
||||
r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
|
||||
r.tasks_deactivate().write_value(1);
|
||||
|
||||
// Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7
|
||||
// Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate,
|
||||
// so we only do the second one here.
|
||||
unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) }
|
||||
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(false));
|
||||
|
||||
// Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
|
||||
// leaving it floating, the flash chip might read it as zero which would cause it to
|
||||
// spuriously exit DPM.
|
||||
gpio::deconfigure_pin(r.psel.sck.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.io0.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.io1.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.io2.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.io3.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().sck().read());
|
||||
gpio::deconfigure_pin(r.psel().io0().read());
|
||||
gpio::deconfigure_pin(r.psel().io1().read());
|
||||
gpio::deconfigure_pin(r.psel().io2().read());
|
||||
gpio::deconfigure_pin(r.psel().io3().read());
|
||||
|
||||
trace!("qspi: dropped");
|
||||
}
|
||||
@ -667,7 +659,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock;
|
||||
fn regs() -> pac::qspi::Qspi;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -681,8 +673,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_qspi {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qspi::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::qspi::Qspi {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::qspi::State {
|
||||
static STATE: crate::qspi::State = crate::qspi::State::new();
|
||||
|
@ -6,11 +6,12 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
pub use pac::radio::mode::MODE_A as Mode;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use pac::radio::pcnf0::PLEN_A as PreambleLength;
|
||||
pub use pac::radio::vals::Mode;
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
use pac::radio::vals::Plen as PreambleLength;
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::radio::vals;
|
||||
use crate::radio::*;
|
||||
pub use crate::radio::{Error, TxPower};
|
||||
use crate::util::slice_in_ram_or;
|
||||
@ -30,69 +31,63 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.pcnf1.write(|w| unsafe {
|
||||
r.pcnf1().write(|w| {
|
||||
// It is 0 bytes long in a standard BLE packet
|
||||
w.statlen()
|
||||
.bits(0)
|
||||
// MaxLen configures the maximum packet payload plus add-on size in
|
||||
// number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
|
||||
// that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
|
||||
// that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
|
||||
// packet larger than MAXLEN, the payload will be truncated at MAXLEN
|
||||
//
|
||||
// To simplify the implementation, It is setted as the maximum value
|
||||
// and the length of the packet is controlled only by the LENGTH field in the packet
|
||||
.maxlen()
|
||||
.bits(255)
|
||||
// Configure the length of the address field in the packet
|
||||
// The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
|
||||
// The base address is truncated from the least significant byte if the BALEN is less than 4
|
||||
//
|
||||
// BLE address is always 4 bytes long
|
||||
.balen()
|
||||
.bits(3) // 3 bytes base address (+ 1 prefix);
|
||||
// Configure the endianess
|
||||
// For BLE is always little endian (LSB first)
|
||||
.endian()
|
||||
.little()
|
||||
// Data whitening is used to avoid long sequences of zeros or
|
||||
// ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
|
||||
// The whitener and de-whitener are defined the same way,
|
||||
// using a 7-bit linear feedback shift register with the
|
||||
// polynomial x7 + x4 + 1.
|
||||
//
|
||||
// In BLE Whitening shall be applied on the PDU and CRC of all
|
||||
// Link Layer packets and is performed after the CRC generation
|
||||
// in the transmitter. No other parts of the packets are whitened.
|
||||
// De-whitening is performed before the CRC checking in the receiver
|
||||
// Before whitening or de-whitening, the shift register should be
|
||||
// initialized based on the channel index.
|
||||
.whiteen()
|
||||
.set_bit()
|
||||
w.set_statlen(0);
|
||||
// MaxLen configures the maximum packet payload plus add-on size in
|
||||
// number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
|
||||
// that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
|
||||
// that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
|
||||
// packet larger than MAXLEN, the payload will be truncated at MAXLEN
|
||||
//
|
||||
// To simplify the implementation, It is setted as the maximum value
|
||||
// and the length of the packet is controlled only by the LENGTH field in the packet
|
||||
w.set_maxlen(255);
|
||||
// Configure the length of the address field in the packet
|
||||
// The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
|
||||
// The base address is truncated from the least significant byte if the BALEN is less than 4
|
||||
//
|
||||
// BLE address is always 4 bytes long
|
||||
w.set_balen(3); // 3 bytes base address (+ 1 prefix);
|
||||
// Configure the endianess
|
||||
// For BLE is always little endian (LSB first)
|
||||
w.set_endian(vals::Endian::LITTLE);
|
||||
// Data whitening is used to avoid long sequences of zeros or
|
||||
// ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
|
||||
// The whitener and de-whitener are defined the same way,
|
||||
// using a 7-bit linear feedback shift register with the
|
||||
// polynomial x7 + x4 + 1.
|
||||
//
|
||||
// In BLE Whitening shall be applied on the PDU and CRC of all
|
||||
// Link Layer packets and is performed after the CRC generation
|
||||
// in the transmitter. No other parts of the packets are whitened.
|
||||
// De-whitening is performed before the CRC checking in the receiver
|
||||
// Before whitening or de-whitening, the shift register should be
|
||||
// initialized based on the channel index.
|
||||
w.set_whiteen(true);
|
||||
});
|
||||
|
||||
// Configure CRC
|
||||
r.crccnf.write(|w| {
|
||||
r.crccnf().write(|w| {
|
||||
// In BLE the CRC shall be calculated on the PDU of all Link Layer
|
||||
// packets (even if the packet is encrypted).
|
||||
// It skips the address field
|
||||
w.skipaddr()
|
||||
.skip()
|
||||
// In BLE 24-bit CRC = 3 bytes
|
||||
.len()
|
||||
.three()
|
||||
w.set_skipaddr(vals::Skipaddr::SKIP);
|
||||
// In BLE 24-bit CRC = 3 bytes
|
||||
w.set_len(vals::Len::THREE);
|
||||
});
|
||||
|
||||
// Ch map between 2400 MHZ .. 2500 MHz
|
||||
// All modes use this range
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
r.frequency.write(|w| w.map().default());
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
r.frequency().write(|w| w.set_map(vals::Map::DEFAULT));
|
||||
|
||||
// Configure shortcuts to simplify and speed up sending and receiving packets.
|
||||
r.shorts.write(|w| {
|
||||
r.shorts().write(|w| {
|
||||
// start transmission/recv immediately after ramp-up
|
||||
// disable radio when transmission/recv is done
|
||||
w.ready_start().enabled().end_disable().enabled()
|
||||
w.set_ready_start(true);
|
||||
w.set_end_disable(true);
|
||||
});
|
||||
|
||||
// Enable NVIC interrupt
|
||||
@ -113,11 +108,11 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
assert!(self.state() == RadioState::DISABLED);
|
||||
|
||||
let r = T::regs();
|
||||
r.mode.write(|w| w.mode().variant(mode));
|
||||
r.mode().write(|w| w.set_mode(mode));
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
r.pcnf0.write(|w| {
|
||||
w.plen().variant(match mode {
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
r.pcnf0().write(|w| {
|
||||
w.set_plen(match mode {
|
||||
Mode::BLE_1MBIT => PreambleLength::_8BIT,
|
||||
Mode::BLE_2MBIT => PreambleLength::_16BIT,
|
||||
#[cfg(any(
|
||||
@ -147,18 +142,14 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
true => 8,
|
||||
};
|
||||
|
||||
r.pcnf0.write(|w| unsafe {
|
||||
w
|
||||
// Configure S0 to 1 byte length, this will represent the Data/Adv header flags
|
||||
.s0len()
|
||||
.set_bit()
|
||||
// Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
|
||||
// and also be used to know how many bytes to read/write from/to the buffer
|
||||
.lflen()
|
||||
.bits(8)
|
||||
// Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
|
||||
.s1len()
|
||||
.bits(s1len)
|
||||
r.pcnf0().write(|w| {
|
||||
// Configure S0 to 1 byte length, this will represent the Data/Adv header flags
|
||||
w.set_s0len(true);
|
||||
// Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
|
||||
// and also be used to know how many bytes to read/write from/to the buffer
|
||||
w.set_lflen(0);
|
||||
// Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
|
||||
w.set_s1len(s1len);
|
||||
});
|
||||
}
|
||||
|
||||
@ -172,7 +163,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) });
|
||||
r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init));
|
||||
}
|
||||
|
||||
/// Set the central frequency to be used
|
||||
@ -185,8 +176,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.frequency
|
||||
.write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) });
|
||||
r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8));
|
||||
}
|
||||
|
||||
/// Set the acess address
|
||||
@ -204,31 +194,25 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// The byte ordering on air is always least significant byte first for the address
|
||||
// So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
|
||||
// The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
|
||||
r.prefix0
|
||||
.write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) });
|
||||
r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8));
|
||||
|
||||
// The base address is truncated from the least significant byte (because the BALEN is less than 4)
|
||||
// So it shifts the address to the right
|
||||
r.base0.write(|w| unsafe { w.bits(access_address << 8) });
|
||||
r.base0().write_value(access_address << 8);
|
||||
|
||||
// Don't match tx address
|
||||
r.txaddress.write(|w| unsafe { w.txaddress().bits(0) });
|
||||
r.txaddress().write(|w| w.set_txaddress(0));
|
||||
|
||||
// Match on logical address
|
||||
// This config only filter the packets by the address,
|
||||
// so only packages send to the previous address
|
||||
// will finish the reception (TODO: check the explanation)
|
||||
r.rxaddresses.write(|w| {
|
||||
w.addr0()
|
||||
.enabled()
|
||||
.addr1()
|
||||
.enabled()
|
||||
.addr2()
|
||||
.enabled()
|
||||
.addr3()
|
||||
.enabled()
|
||||
.addr4()
|
||||
.enabled()
|
||||
r.rxaddresses().write(|w| {
|
||||
w.set_addr0(true);
|
||||
w.set_addr1(true);
|
||||
w.set_addr2(true);
|
||||
w.set_addr3(true);
|
||||
w.set_addr4(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -241,7 +225,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.crcpoly.write(|w| unsafe {
|
||||
r.crcpoly().write(|w| {
|
||||
// Configure the CRC polynomial
|
||||
// Each term in the CRC polynomial is mapped to a bit in this
|
||||
// register which index corresponds to the term's exponent.
|
||||
@ -249,7 +233,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// 1, and bit number 0 of the register content is ignored by
|
||||
// the hardware. The following example is for an 8 bit CRC
|
||||
// polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
|
||||
w.crcpoly().bits(crc_poly & 0xFFFFFF)
|
||||
w.set_crcpoly(crc_poly & 0xFFFFFF)
|
||||
});
|
||||
}
|
||||
|
||||
@ -263,7 +247,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) });
|
||||
r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF));
|
||||
}
|
||||
|
||||
/// Set the radio tx power
|
||||
@ -274,7 +258,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.txpower.write(|w| w.txpower().variant(tx_power));
|
||||
r.txpower().write(|w| w.set_txpower(tx_power));
|
||||
}
|
||||
|
||||
/// Set buffer to read/write
|
||||
@ -294,7 +278,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
let ptr = buffer.as_ptr();
|
||||
|
||||
// Configure the payload
|
||||
r.packetptr.write(|w| unsafe { w.bits(ptr as u32) });
|
||||
r.packetptr().write_value(ptr as u32);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -310,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// Initialize the transmission
|
||||
// trace!("txen");
|
||||
|
||||
r.tasks_txen.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_txen().write_value(1);
|
||||
})
|
||||
.await;
|
||||
|
||||
@ -327,7 +311,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
self.trigger_and_wait_end(move || {
|
||||
// Initialize the transmission
|
||||
// trace!("rxen");
|
||||
r.tasks_rxen.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_rxen().write_value(1);
|
||||
})
|
||||
.await;
|
||||
|
||||
@ -344,21 +328,21 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
let drop = OnDrop::new(|| {
|
||||
trace!("radio drop: stopping");
|
||||
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
|
||||
r.events_end.reset();
|
||||
r.events_end().write_value(0);
|
||||
|
||||
trace!("radio drop: stopped");
|
||||
});
|
||||
|
||||
// trace!("radio:enable interrupt");
|
||||
// Clear some remnant side-effects (TODO: check if this is necessary)
|
||||
r.events_end.reset();
|
||||
r.events_end().write_value(0);
|
||||
|
||||
// Enable interrupt
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
@ -368,7 +352,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// On poll check if interrupt happen
|
||||
poll_fn(|cx| {
|
||||
s.event_waker.register(cx.waker());
|
||||
if r.events_end.read().bits() == 1 {
|
||||
if r.events_end().read() == 1 {
|
||||
// trace!("radio:end");
|
||||
return core::task::Poll::Ready(());
|
||||
}
|
||||
@ -377,7 +361,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
.await;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
r.events_end.reset(); // ACK
|
||||
r.events_end().write_value(0); // ACK
|
||||
|
||||
// Everthing ends fine, so it disable the drop
|
||||
drop.defuse();
|
||||
@ -392,15 +376,15 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
if self.state() != RadioState::DISABLED {
|
||||
trace!("radio:disable");
|
||||
// Trigger the disable task
|
||||
r.tasks_disable.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_disable().write_value(1);
|
||||
|
||||
// Wait until the radio is disabled
|
||||
while r.events_disabled.read().bits() == 0 {}
|
||||
while r.events_disabled().read() == 0 {}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
// Acknowledge it
|
||||
r.events_disabled.reset();
|
||||
r.events_disabled().write_value(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::interrupt::{self};
|
||||
use crate::pac::radio::vals;
|
||||
use crate::Peripheral;
|
||||
|
||||
/// Default (IEEE compliant) Start of Frame Delimiter
|
||||
@ -47,58 +48,47 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// Disable and enable to reset peripheral
|
||||
r.power.write(|w| w.power().disabled());
|
||||
r.power.write(|w| w.power().enabled());
|
||||
r.power().write(|w| w.set_power(false));
|
||||
r.power().write(|w| w.set_power(true));
|
||||
|
||||
// Enable 802.15.4 mode
|
||||
r.mode.write(|w| w.mode().ieee802154_250kbit());
|
||||
r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT));
|
||||
// Configure CRC skip address
|
||||
r.crccnf.write(|w| w.len().two().skipaddr().ieee802154());
|
||||
unsafe {
|
||||
// Configure CRC polynomial and init
|
||||
r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021));
|
||||
r.crcinit.write(|w| w.crcinit().bits(0));
|
||||
r.pcnf0.write(|w| {
|
||||
// 8-bit on air length
|
||||
w.lflen()
|
||||
.bits(8)
|
||||
// Zero bytes S0 field length
|
||||
.s0len()
|
||||
.clear_bit()
|
||||
// Zero bytes S1 field length
|
||||
.s1len()
|
||||
.bits(0)
|
||||
// Do not include S1 field in RAM if S1 length > 0
|
||||
.s1incl()
|
||||
.clear_bit()
|
||||
// Zero code Indicator length
|
||||
.cilen()
|
||||
.bits(0)
|
||||
// 32-bit zero preamble
|
||||
.plen()
|
||||
._32bit_zero()
|
||||
// Include CRC in length
|
||||
.crcinc()
|
||||
.include()
|
||||
});
|
||||
r.pcnf1.write(|w| {
|
||||
// Maximum packet length
|
||||
w.maxlen()
|
||||
.bits(Packet::MAX_PSDU_LEN)
|
||||
// Zero static length
|
||||
.statlen()
|
||||
.bits(0)
|
||||
// Zero base address length
|
||||
.balen()
|
||||
.bits(0)
|
||||
// Little-endian
|
||||
.endian()
|
||||
.clear_bit()
|
||||
// Disable packet whitening
|
||||
.whiteen()
|
||||
.clear_bit()
|
||||
});
|
||||
}
|
||||
r.crccnf().write(|w| {
|
||||
w.set_len(vals::Len::TWO);
|
||||
w.set_skipaddr(vals::Skipaddr::IEEE802154);
|
||||
});
|
||||
// Configure CRC polynomial and init
|
||||
r.crcpoly().write(|w| w.set_crcpoly(0x0001_1021));
|
||||
r.crcinit().write(|w| w.set_crcinit(0));
|
||||
r.pcnf0().write(|w| {
|
||||
// 8-bit on air length
|
||||
w.set_lflen(8);
|
||||
// Zero bytes S0 field length
|
||||
w.set_s0len(false);
|
||||
// Zero bytes S1 field length
|
||||
w.set_s1len(0);
|
||||
// Do not include S1 field in RAM if S1 length > 0
|
||||
w.set_s1incl(vals::S1incl::AUTOMATIC);
|
||||
// Zero code Indicator length
|
||||
w.set_cilen(0);
|
||||
// 32-bit zero preamble
|
||||
w.set_plen(vals::Plen::_32BIT_ZERO);
|
||||
// Include CRC in length
|
||||
w.set_crcinc(vals::Crcinc::INCLUDE);
|
||||
});
|
||||
r.pcnf1().write(|w| {
|
||||
// Maximum packet length
|
||||
w.set_maxlen(Packet::MAX_PSDU_LEN);
|
||||
// Zero static length
|
||||
w.set_statlen(0);
|
||||
// Zero base address length
|
||||
w.set_balen(0);
|
||||
// Little-endian
|
||||
w.set_endian(vals::Endian::LITTLE);
|
||||
// Disable packet whitening
|
||||
w.set_whiteen(false);
|
||||
});
|
||||
|
||||
// Enable NVIC interrupt
|
||||
T::Interrupt::unpend();
|
||||
@ -125,8 +115,10 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
}
|
||||
let frequency_offset = (channel - 10) * 5;
|
||||
self.needs_enable = true;
|
||||
r.frequency
|
||||
.write(|w| unsafe { w.frequency().bits(frequency_offset).map().default() });
|
||||
r.frequency().write(|w| {
|
||||
w.set_frequency(frequency_offset);
|
||||
w.set_map(vals::Map::DEFAULT);
|
||||
});
|
||||
}
|
||||
|
||||
/// Changes the Clear Channel Assessment method
|
||||
@ -134,12 +126,14 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
let r = T::regs();
|
||||
self.needs_enable = true;
|
||||
match cca {
|
||||
Cca::CarrierSense => r.ccactrl.write(|w| w.ccamode().carrier_mode()),
|
||||
Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)),
|
||||
Cca::EnergyDetection { ed_threshold } => {
|
||||
// "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL
|
||||
// and writing the CCAEDTHRES field to a chosen value."
|
||||
r.ccactrl
|
||||
.write(|w| unsafe { w.ccamode().ed_mode().ccaedthres().bits(ed_threshold) });
|
||||
r.ccactrl().write(|w| {
|
||||
w.set_ccamode(vals::Ccamode::ED_MODE);
|
||||
w.set_ccaedthres(ed_threshold);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,13 +141,13 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
/// Changes the Start of Frame Delimiter (SFD)
|
||||
pub fn set_sfd(&mut self, sfd: u8) {
|
||||
let r = T::regs();
|
||||
r.sfd.write(|w| unsafe { w.sfd().bits(sfd) });
|
||||
r.sfd().write(|w| w.set_sfd(sfd));
|
||||
}
|
||||
|
||||
/// Clear interrupts
|
||||
pub fn clear_all_interrupts(&mut self) {
|
||||
let r = T::regs();
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xffff_ffff) });
|
||||
r.intenclr().write(|w| w.0 = 0xffff_ffff);
|
||||
}
|
||||
|
||||
/// Changes the radio transmission power
|
||||
@ -163,43 +157,43 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
let tx_power: TxPower = match power {
|
||||
#[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
|
||||
8 => TxPower::POS8D_BM,
|
||||
8 => TxPower::POS8_DBM,
|
||||
#[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
|
||||
7 => TxPower::POS7D_BM,
|
||||
7 => TxPower::POS7_DBM,
|
||||
#[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
|
||||
6 => TxPower::POS6D_BM,
|
||||
6 => TxPower::POS6_DBM,
|
||||
#[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
|
||||
5 => TxPower::POS5D_BM,
|
||||
5 => TxPower::POS5_DBM,
|
||||
#[cfg(not(feature = "_nrf5340-net"))]
|
||||
4 => TxPower::POS4D_BM,
|
||||
4 => TxPower::POS4_DBM,
|
||||
#[cfg(not(feature = "_nrf5340-net"))]
|
||||
3 => TxPower::POS3D_BM,
|
||||
3 => TxPower::POS3_DBM,
|
||||
#[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
|
||||
2 => TxPower::POS2D_BM,
|
||||
0 => TxPower::_0D_BM,
|
||||
2 => TxPower::POS2_DBM,
|
||||
0 => TxPower::_0_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-1 => TxPower::NEG1D_BM,
|
||||
-1 => TxPower::NEG1_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-2 => TxPower::NEG2D_BM,
|
||||
-2 => TxPower::NEG2_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-3 => TxPower::NEG3D_BM,
|
||||
-4 => TxPower::NEG4D_BM,
|
||||
-3 => TxPower::NEG3_DBM,
|
||||
-4 => TxPower::NEG4_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-5 => TxPower::NEG5D_BM,
|
||||
-5 => TxPower::NEG5_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-6 => TxPower::NEG6D_BM,
|
||||
-6 => TxPower::NEG6_DBM,
|
||||
#[cfg(feature = "_nrf5340-net")]
|
||||
-7 => TxPower::NEG7D_BM,
|
||||
-8 => TxPower::NEG8D_BM,
|
||||
-12 => TxPower::NEG12D_BM,
|
||||
-16 => TxPower::NEG16D_BM,
|
||||
-20 => TxPower::NEG20D_BM,
|
||||
-30 => TxPower::NEG30D_BM,
|
||||
-40 => TxPower::NEG40D_BM,
|
||||
-7 => TxPower::NEG7_DBM,
|
||||
-8 => TxPower::NEG8_DBM,
|
||||
-12 => TxPower::NEG12_DBM,
|
||||
-16 => TxPower::NEG16_DBM,
|
||||
-20 => TxPower::NEG20_DBM,
|
||||
-30 => TxPower::NEG30_DBM,
|
||||
-40 => TxPower::NEG40_DBM,
|
||||
_ => panic!("Invalid transmission power value"),
|
||||
};
|
||||
|
||||
r.txpower.write(|w| w.txpower().variant(tx_power));
|
||||
r.txpower().write(|w| w.set_txpower(tx_power));
|
||||
}
|
||||
|
||||
/// Waits until the radio state matches the given `state`
|
||||
@ -221,7 +215,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
RadioState::DISABLED => return,
|
||||
// idle or ramping up
|
||||
RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => {
|
||||
r.tasks_disable.write(|w| w.tasks_disable().set_bit());
|
||||
r.tasks_disable().write_value(1);
|
||||
self.wait_for_radio_state(RadioState::DISABLED);
|
||||
return;
|
||||
}
|
||||
@ -232,29 +226,30 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
}
|
||||
// cancel ongoing transfer or ongoing CCA
|
||||
RadioState::RX => {
|
||||
r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit());
|
||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
||||
r.tasks_ccastop().write_value(1);
|
||||
r.tasks_stop().write_value(1);
|
||||
self.wait_for_radio_state(RadioState::RX_IDLE);
|
||||
}
|
||||
RadioState::TX => {
|
||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
||||
r.tasks_stop().write_value(1);
|
||||
self.wait_for_radio_state(RadioState::TX_IDLE);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_buffer(&mut self, buffer: &[u8]) {
|
||||
let r = T::regs();
|
||||
r.packetptr.write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
|
||||
r.packetptr().write_value(buffer.as_ptr() as u32);
|
||||
}
|
||||
|
||||
/// Moves the radio to the RXIDLE state
|
||||
fn receive_prepare(&mut self) {
|
||||
// clear related events
|
||||
T::regs().events_ccabusy.reset();
|
||||
T::regs().events_phyend.reset();
|
||||
// NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
|
||||
T::regs().events_ccabusy().write_value(0);
|
||||
T::regs().events_phyend().write_value(0);
|
||||
// NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE
|
||||
let disable = match self.state() {
|
||||
RadioState::DISABLED => false,
|
||||
RadioState::RX_IDLE => self.needs_enable,
|
||||
@ -279,7 +274,7 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// The radio goes through following states when receiving a 802.15.4 packet
|
||||
//
|
||||
// enable RX → ramp up RX → RX idle → Receive → end (PHYEND)
|
||||
r.shorts.write(|w| w.rxready_start().enabled());
|
||||
r.shorts().write(|w| w.set_rxready_start(true));
|
||||
|
||||
// set up RX buffer
|
||||
self.set_buffer(packet.buffer.as_mut());
|
||||
@ -289,17 +284,17 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
match self.state() {
|
||||
// Re-start receiver
|
||||
RadioState::RX_IDLE => r.tasks_start.write(|w| w.tasks_start().set_bit()),
|
||||
RadioState::RX_IDLE => r.tasks_start().write_value(1),
|
||||
// Enable receiver
|
||||
_ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()),
|
||||
_ => r.tasks_rxen().write_value(1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel receiving packet
|
||||
fn receive_cancel() {
|
||||
let r = T::regs();
|
||||
r.shorts.reset();
|
||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
||||
r.shorts().write(|_| {});
|
||||
r.tasks_stop().write_value(1);
|
||||
loop {
|
||||
match state(r) {
|
||||
RadioState::DISABLED | RadioState::RX_IDLE => break,
|
||||
@ -329,12 +324,12 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
core::future::poll_fn(|cx| {
|
||||
s.event_waker.register(cx.waker());
|
||||
|
||||
if r.events_phyend.read().events_phyend().bit_is_set() {
|
||||
r.events_phyend.reset();
|
||||
if r.events_phyend().read() != 0 {
|
||||
r.events_phyend().write_value(0);
|
||||
trace!("RX done poll");
|
||||
return Poll::Ready(());
|
||||
} else {
|
||||
r.intenset.write(|w| w.phyend().set());
|
||||
r.intenset().write(|w| w.set_phyend(true));
|
||||
};
|
||||
|
||||
Poll::Pending
|
||||
@ -344,8 +339,8 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
dma_end_fence();
|
||||
dropper.defuse();
|
||||
|
||||
let crc = r.rxcrc.read().rxcrc().bits() as u16;
|
||||
if r.crcstatus.read().crcstatus().bit_is_set() {
|
||||
let crc = r.rxcrc().read().rxcrc() as u16;
|
||||
if r.crcstatus().read().crcstatus() == vals::Crcstatus::CRCOK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CrcFailed(crc))
|
||||
@ -387,17 +382,12 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
// CCA idle → enable TX → start TX → TX → end (PHYEND) → disabled
|
||||
//
|
||||
// CCA might end up in the event CCABUSY in which there will be no transmission
|
||||
r.shorts.write(|w| {
|
||||
w.rxready_ccastart()
|
||||
.enabled()
|
||||
.ccaidle_txen()
|
||||
.enabled()
|
||||
.txready_start()
|
||||
.enabled()
|
||||
.ccabusy_disable()
|
||||
.enabled()
|
||||
.phyend_disable()
|
||||
.enabled()
|
||||
r.shorts().write(|w| {
|
||||
w.set_rxready_ccastart(true);
|
||||
w.set_ccaidle_txen(true);
|
||||
w.set_txready_start(true);
|
||||
w.set_ccabusy_disable(true);
|
||||
w.set_phyend_disable(true);
|
||||
});
|
||||
|
||||
// Set transmission buffer
|
||||
@ -410,27 +400,30 @@ impl<'d, T: Instance> Radio<'d, T> {
|
||||
|
||||
match self.state() {
|
||||
// Re-start receiver
|
||||
RadioState::RX_IDLE => r.tasks_ccastart.write(|w| w.tasks_ccastart().set_bit()),
|
||||
RadioState::RX_IDLE => r.tasks_ccastart().write_value(1),
|
||||
// Enable receiver
|
||||
_ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()),
|
||||
_ => r.tasks_rxen().write_value(1),
|
||||
}
|
||||
|
||||
self.clear_all_interrupts();
|
||||
let result = core::future::poll_fn(|cx| {
|
||||
s.event_waker.register(cx.waker());
|
||||
|
||||
if r.events_phyend.read().events_phyend().bit_is_set() {
|
||||
r.events_phyend.reset();
|
||||
r.events_ccabusy.reset();
|
||||
if r.events_phyend().read() != 0 {
|
||||
r.events_phyend().write_value(0);
|
||||
r.events_ccabusy().write_value(0);
|
||||
trace!("TX done poll");
|
||||
return Poll::Ready(TransmitResult::Success);
|
||||
} else if r.events_ccabusy.read().events_ccabusy().bit_is_set() {
|
||||
r.events_ccabusy.reset();
|
||||
} else if r.events_ccabusy().read() != 0 {
|
||||
r.events_ccabusy().write_value(0);
|
||||
trace!("TX no CCA");
|
||||
return Poll::Ready(TransmitResult::ChannelInUse);
|
||||
}
|
||||
|
||||
r.intenset.write(|w| w.phyend().set().ccabusy().set());
|
||||
r.intenset().write(|w| {
|
||||
w.set_phyend(true);
|
||||
w.set_ccabusy(true);
|
||||
});
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
|
@ -20,8 +20,8 @@ pub mod ieee802154;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::radio::state::STATE_A as RadioState;
|
||||
pub use pac::radio::txpower::TXPOWER_A as TxPower;
|
||||
use pac::radio::vals::State as RadioState;
|
||||
pub use pac::radio::vals::Txpower as TxPower;
|
||||
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
@ -52,7 +52,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
// clear all interrupts
|
||||
r.intenclr.write(|w| w.bits(0xffff_ffff));
|
||||
r.intenclr().write(|w| w.0 = 0xffff_ffff);
|
||||
s.event_waker.wake();
|
||||
}
|
||||
}
|
||||
@ -70,15 +70,15 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::radio::RegisterBlock;
|
||||
fn regs() -> crate::pac::radio::Radio;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
macro_rules! impl_radio {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::radio::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::radio::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> crate::pac::radio::Radio {
|
||||
pac::$pac_type
|
||||
}
|
||||
|
||||
fn state() -> &'static crate::radio::State {
|
||||
@ -100,9 +100,6 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
}
|
||||
|
||||
/// Get the state of the radio
|
||||
pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState {
|
||||
match radio.state.read().state().variant() {
|
||||
Some(state) => state,
|
||||
None => unreachable!(),
|
||||
}
|
||||
pub(crate) fn state(radio: pac::radio::Radio) -> RadioState {
|
||||
radio.state().read().state()
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
@ -26,7 +26,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
|
||||
// Clear the event.
|
||||
r.events_valrdy.reset();
|
||||
r.events_valrdy().write_value(0);
|
||||
|
||||
// Mutate the slice within a critical section,
|
||||
// so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
|
||||
@ -40,7 +40,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
// The safety contract of `Rng::new` means that the future can't have been dropped
|
||||
// without calling its destructor.
|
||||
unsafe {
|
||||
*state.ptr = r.value.read().value().bits();
|
||||
*state.ptr = r.value().read().value();
|
||||
state.ptr = state.ptr.add(1);
|
||||
}
|
||||
|
||||
@ -84,19 +84,19 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_stop().write_value(1)
|
||||
}
|
||||
|
||||
fn start(&self) {
|
||||
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_start().write_value(1)
|
||||
}
|
||||
|
||||
fn enable_irq(&self) {
|
||||
T::regs().intenset.write(|w| w.valrdy().set());
|
||||
T::regs().intenset().write(|w| w.set_valrdy(true));
|
||||
}
|
||||
|
||||
fn disable_irq(&self) {
|
||||
T::regs().intenclr.write(|w| w.valrdy().clear());
|
||||
T::regs().intenclr().write(|w| w.set_valrdy(true));
|
||||
}
|
||||
|
||||
/// Enable or disable the RNG's bias correction.
|
||||
@ -106,7 +106,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
///
|
||||
/// Defaults to disabled.
|
||||
pub fn set_bias_correction(&self, enable: bool) {
|
||||
T::regs().config.write(|w| w.dercen().bit(enable))
|
||||
T::regs().config().write(|w| w.set_dercen(enable))
|
||||
}
|
||||
|
||||
/// Fill the buffer with random bytes.
|
||||
@ -162,9 +162,9 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
|
||||
for byte in dest.iter_mut() {
|
||||
let regs = T::regs();
|
||||
while regs.events_valrdy.read().bits() == 0 {}
|
||||
regs.events_valrdy.reset();
|
||||
*byte = regs.value.read().value().bits();
|
||||
while regs.events_valrdy().read() == 0 {}
|
||||
regs.events_valrdy().write_value(0);
|
||||
*byte = regs.value().read().value();
|
||||
}
|
||||
|
||||
self.stop();
|
||||
@ -244,7 +244,7 @@ impl InnerState {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock;
|
||||
fn regs() -> pac::rng::Rng;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -258,8 +258,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_rng {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::rng::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> crate::pac::rng::Rng {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::rng::State {
|
||||
static STATE: crate::rng::State = crate::rng::State::new();
|
||||
|
@ -9,14 +9,10 @@ use core::task::Poll;
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::{saadc, SAADC};
|
||||
use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A};
|
||||
// We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same
|
||||
pub(crate) use saadc::ch::pselp::PSELP_A as InputChannel;
|
||||
use saadc::oversample::OVERSAMPLE_A;
|
||||
use saadc::resolution::VAL_A;
|
||||
pub(crate) use vals::Psel as InputChannel;
|
||||
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::pac::saadc::vals;
|
||||
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
@ -34,20 +30,20 @@ pub struct InterruptHandler {
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
let r = pac::SAADC;
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.calibratedone().clear());
|
||||
if r.events_calibratedone().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_calibratedone(true));
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
if r.events_end().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
if r.events_started().read() != 0 {
|
||||
r.intenclr().write(|w| w.set_started(true));
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
@ -150,44 +146,36 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
) -> Self {
|
||||
into_ref!(saadc);
|
||||
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
let r = pac::SAADC;
|
||||
|
||||
let Config { resolution, oversample } = config;
|
||||
|
||||
// Configure channels
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.resolution.write(|w| w.val().variant(resolution.into()));
|
||||
r.oversample.write(|w| w.oversample().variant(oversample.into()));
|
||||
r.enable().write(|w| w.set_enable(true));
|
||||
r.resolution().write(|w| w.set_val(resolution.into()));
|
||||
r.oversample().write(|w| w.set_oversample(oversample.into()));
|
||||
|
||||
for (i, cc) in channel_configs.iter().enumerate() {
|
||||
r.ch[i].pselp.write(|w| w.pselp().variant(cc.p_channel.channel()));
|
||||
r.ch(i).pselp().write(|w| w.set_pselp(cc.p_channel.channel()));
|
||||
if let Some(n_channel) = &cc.n_channel {
|
||||
r.ch[i]
|
||||
.pseln
|
||||
.write(|w| unsafe { w.pseln().bits(n_channel.channel() as u8) });
|
||||
r.ch(i).pseln().write(|w| w.set_pseln(n_channel.channel()));
|
||||
}
|
||||
r.ch[i].config.write(|w| {
|
||||
w.refsel().variant(cc.reference.into());
|
||||
w.gain().variant(cc.gain.into());
|
||||
w.tacq().variant(cc.time.into());
|
||||
if cc.n_channel.is_none() {
|
||||
w.mode().se();
|
||||
} else {
|
||||
w.mode().diff();
|
||||
}
|
||||
w.resp().variant(cc.resistor.into());
|
||||
w.resn().bypass();
|
||||
if !matches!(oversample, Oversample::BYPASS) {
|
||||
w.burst().enabled();
|
||||
} else {
|
||||
w.burst().disabled();
|
||||
}
|
||||
w
|
||||
r.ch(i).config().write(|w| {
|
||||
w.set_refsel(cc.reference.into());
|
||||
w.set_gain(cc.gain.into());
|
||||
w.set_tacq(cc.time.into());
|
||||
w.set_mode(match cc.n_channel {
|
||||
None => vals::ConfigMode::SE,
|
||||
Some(_) => vals::ConfigMode::DIFF,
|
||||
});
|
||||
w.set_resp(cc.resistor.into());
|
||||
w.set_resn(vals::Resn::BYPASS);
|
||||
w.set_burst(!matches!(oversample, Oversample::BYPASS));
|
||||
});
|
||||
}
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0x003F_FFFF);
|
||||
|
||||
interrupt::SAADC.unpend();
|
||||
unsafe { interrupt::SAADC.enable() };
|
||||
@ -195,8 +183,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
Self { _p: saadc }
|
||||
}
|
||||
|
||||
fn regs() -> &'static saadc::RegisterBlock {
|
||||
unsafe { &*SAADC::ptr() }
|
||||
fn regs() -> pac::saadc::Saadc {
|
||||
pac::SAADC
|
||||
}
|
||||
|
||||
/// Perform SAADC calibration. Completes when done.
|
||||
@ -204,13 +192,13 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
let r = Self::regs();
|
||||
|
||||
// Reset and enable the end event
|
||||
r.events_calibratedone.reset();
|
||||
r.intenset.write(|w| w.calibratedone().set());
|
||||
r.events_calibratedone().write_value(0);
|
||||
r.intenset().write(|w| w.set_calibratedone(true));
|
||||
|
||||
// Order is important
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_calibrateoffset().write_value(1);
|
||||
|
||||
// Wait for 'calibratedone' event.
|
||||
poll_fn(|cx| {
|
||||
@ -218,8 +206,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
|
||||
WAKER.register(cx.waker());
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.events_calibratedone.reset();
|
||||
if r.events_calibratedone().read() != 0 {
|
||||
r.events_calibratedone().write_value(0);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -239,19 +227,19 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
let r = Self::regs();
|
||||
|
||||
// Set up the DMA
|
||||
r.result.ptr.write(|w| unsafe { w.ptr().bits(buf.as_mut_ptr() as u32) });
|
||||
r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(N as _) });
|
||||
r.result().ptr().write_value(buf.as_mut_ptr() as u32);
|
||||
r.result().maxcnt().write(|w| w.set_maxcnt(N as _));
|
||||
|
||||
// Reset and enable the end event
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.events_end().write_value(0);
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
// Don't reorder the ADC start event before the previous writes. Hopefully self
|
||||
// wouldn't happen anyway.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_sample.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
r.tasks_sample().write_value(1);
|
||||
|
||||
// Wait for 'end' event.
|
||||
poll_fn(|cx| {
|
||||
@ -259,8 +247,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
|
||||
WAKER.register(cx.waker());
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.events_end.reset();
|
||||
if r.events_end().read() != 0 {
|
||||
r.events_end().write_value(0);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -311,8 +299,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
// We want the task start to effectively short with the last one ending so
|
||||
// we don't miss any samples. It'd be great for the SAADC to offer a SHORTS
|
||||
// register instead, but it doesn't, so we must use PPI.
|
||||
let mut start_ppi =
|
||||
Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_end), Task::from_reg(&r.tasks_start));
|
||||
let mut start_ppi = Ppi::new_one_to_one(
|
||||
ppi_ch1,
|
||||
Event::from_reg(r.events_end()),
|
||||
Task::from_reg(r.tasks_start()),
|
||||
);
|
||||
start_ppi.enable();
|
||||
|
||||
let timer = Timer::new(timer);
|
||||
@ -322,7 +313,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
|
||||
let timer_cc = timer.cc(0);
|
||||
|
||||
let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample));
|
||||
let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(r.tasks_sample()));
|
||||
|
||||
timer.start();
|
||||
|
||||
@ -355,43 +346,37 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
// Establish mode and sample rate
|
||||
match sample_rate_divisor {
|
||||
Some(sr) => {
|
||||
r.samplerate.write(|w| unsafe {
|
||||
w.cc().bits(sr);
|
||||
w.mode().timers();
|
||||
w
|
||||
r.samplerate().write(|w| {
|
||||
w.set_cc(sr);
|
||||
w.set_mode(vals::SamplerateMode::TIMERS);
|
||||
});
|
||||
r.tasks_sample.write(|w| unsafe { w.bits(1) }); // Need to kick-start the internal timer
|
||||
r.tasks_sample().write_value(1); // Need to kick-start the internal timer
|
||||
}
|
||||
None => r.samplerate.write(|w| unsafe {
|
||||
w.cc().bits(0);
|
||||
w.mode().task();
|
||||
w
|
||||
None => r.samplerate().write(|w| {
|
||||
w.set_cc(0);
|
||||
w.set_mode(vals::SamplerateMode::TASK);
|
||||
}),
|
||||
}
|
||||
|
||||
// Set up the initial DMA
|
||||
r.result
|
||||
.ptr
|
||||
.write(|w| unsafe { w.ptr().bits(bufs[0].as_mut_ptr() as u32) });
|
||||
r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits((N0 * N) as _) });
|
||||
r.result().ptr().write_value(bufs[0].as_mut_ptr() as u32);
|
||||
r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N) as _));
|
||||
|
||||
// Reset and enable the events
|
||||
r.events_end.reset();
|
||||
r.events_started.reset();
|
||||
r.intenset.write(|w| {
|
||||
w.end().set();
|
||||
w.started().set();
|
||||
w
|
||||
r.events_end().write_value(0);
|
||||
r.events_started().write_value(0);
|
||||
r.intenset().write(|w| {
|
||||
w.set_end(true);
|
||||
w.set_started(true);
|
||||
});
|
||||
|
||||
// Don't reorder the ADC start event before the previous writes. Hopefully self
|
||||
// wouldn't happen anyway.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
|
||||
let mut inited = false;
|
||||
|
||||
let mut current_buffer = 0;
|
||||
|
||||
// Wait for events and complete when the sampler indicates it has had enough.
|
||||
@ -400,11 +385,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
|
||||
WAKER.register(cx.waker());
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
if r.events_end().read() != 0 {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.events_end().write_value(0);
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
match callback(&bufs[current_buffer]) {
|
||||
CallbackResult::Continue => {
|
||||
@ -417,9 +402,9 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
}
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.events_started.reset();
|
||||
r.intenset.write(|w| w.started().set());
|
||||
if r.events_started().read() != 0 {
|
||||
r.events_started().write_value(0);
|
||||
r.intenset().write(|w| w.set_started(true));
|
||||
|
||||
if !inited {
|
||||
init();
|
||||
@ -427,9 +412,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
}
|
||||
|
||||
let next_buffer = 1 - current_buffer;
|
||||
r.result
|
||||
.ptr
|
||||
.write(|w| unsafe { w.ptr().bits(bufs[next_buffer].as_mut_ptr() as u32) });
|
||||
r.result().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
@ -447,11 +430,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.events_stopped.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.events_stopped().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
|
||||
while r.events_stopped.read().bits() == 0 {}
|
||||
r.events_stopped.reset();
|
||||
while r.events_stopped().read() == 0 {}
|
||||
r.events_stopped().write_value(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,21 +464,21 @@ impl<'d> Saadc<'d, 1> {
|
||||
impl<'d, const N: usize> Drop for Saadc<'d, N> {
|
||||
fn drop(&mut self) {
|
||||
let r = Self::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(false));
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Gain> for GAIN_A {
|
||||
impl From<Gain> for vals::Gain {
|
||||
fn from(gain: Gain) -> Self {
|
||||
match gain {
|
||||
Gain::GAIN1_6 => GAIN_A::GAIN1_6,
|
||||
Gain::GAIN1_5 => GAIN_A::GAIN1_5,
|
||||
Gain::GAIN1_4 => GAIN_A::GAIN1_4,
|
||||
Gain::GAIN1_3 => GAIN_A::GAIN1_3,
|
||||
Gain::GAIN1_2 => GAIN_A::GAIN1_2,
|
||||
Gain::GAIN1 => GAIN_A::GAIN1,
|
||||
Gain::GAIN2 => GAIN_A::GAIN2,
|
||||
Gain::GAIN4 => GAIN_A::GAIN4,
|
||||
Gain::GAIN1_6 => vals::Gain::GAIN1_6,
|
||||
Gain::GAIN1_5 => vals::Gain::GAIN1_5,
|
||||
Gain::GAIN1_4 => vals::Gain::GAIN1_4,
|
||||
Gain::GAIN1_3 => vals::Gain::GAIN1_3,
|
||||
Gain::GAIN1_2 => vals::Gain::GAIN1_2,
|
||||
Gain::GAIN1 => vals::Gain::GAIN1,
|
||||
Gain::GAIN2 => vals::Gain::GAIN2,
|
||||
Gain::GAIN4 => vals::Gain::GAIN4,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,11 +505,11 @@ pub enum Gain {
|
||||
GAIN4 = 7,
|
||||
}
|
||||
|
||||
impl From<Reference> for REFSEL_A {
|
||||
impl From<Reference> for vals::Refsel {
|
||||
fn from(reference: Reference) -> Self {
|
||||
match reference {
|
||||
Reference::INTERNAL => REFSEL_A::INTERNAL,
|
||||
Reference::VDD1_4 => REFSEL_A::VDD1_4,
|
||||
Reference::INTERNAL => vals::Refsel::INTERNAL,
|
||||
Reference::VDD1_4 => vals::Refsel::VDD1_4,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -541,13 +524,13 @@ pub enum Reference {
|
||||
VDD1_4 = 1,
|
||||
}
|
||||
|
||||
impl From<Resistor> for RESP_A {
|
||||
impl From<Resistor> for vals::Resp {
|
||||
fn from(resistor: Resistor) -> Self {
|
||||
match resistor {
|
||||
Resistor::BYPASS => RESP_A::BYPASS,
|
||||
Resistor::PULLDOWN => RESP_A::PULLDOWN,
|
||||
Resistor::PULLUP => RESP_A::PULLUP,
|
||||
Resistor::VDD1_2 => RESP_A::VDD1_2,
|
||||
Resistor::BYPASS => vals::Resp::BYPASS,
|
||||
Resistor::PULLDOWN => vals::Resp::PULLDOWN,
|
||||
Resistor::PULLUP => vals::Resp::PULLUP,
|
||||
Resistor::VDD1_2 => vals::Resp::VDD1_2,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,15 +549,15 @@ pub enum Resistor {
|
||||
VDD1_2 = 3,
|
||||
}
|
||||
|
||||
impl From<Time> for TACQ_A {
|
||||
impl From<Time> for vals::Tacq {
|
||||
fn from(time: Time) -> Self {
|
||||
match time {
|
||||
Time::_3US => TACQ_A::_3US,
|
||||
Time::_5US => TACQ_A::_5US,
|
||||
Time::_10US => TACQ_A::_10US,
|
||||
Time::_15US => TACQ_A::_15US,
|
||||
Time::_20US => TACQ_A::_20US,
|
||||
Time::_40US => TACQ_A::_40US,
|
||||
Time::_3US => vals::Tacq::_3US,
|
||||
Time::_5US => vals::Tacq::_5US,
|
||||
Time::_10US => vals::Tacq::_10US,
|
||||
Time::_15US => vals::Tacq::_15US,
|
||||
Time::_20US => vals::Tacq::_20US,
|
||||
Time::_40US => vals::Tacq::_40US,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -597,18 +580,18 @@ pub enum Time {
|
||||
_40US = 5,
|
||||
}
|
||||
|
||||
impl From<Oversample> for OVERSAMPLE_A {
|
||||
impl From<Oversample> for vals::Oversample {
|
||||
fn from(oversample: Oversample) -> Self {
|
||||
match oversample {
|
||||
Oversample::BYPASS => OVERSAMPLE_A::BYPASS,
|
||||
Oversample::OVER2X => OVERSAMPLE_A::OVER2X,
|
||||
Oversample::OVER4X => OVERSAMPLE_A::OVER4X,
|
||||
Oversample::OVER8X => OVERSAMPLE_A::OVER8X,
|
||||
Oversample::OVER16X => OVERSAMPLE_A::OVER16X,
|
||||
Oversample::OVER32X => OVERSAMPLE_A::OVER32X,
|
||||
Oversample::OVER64X => OVERSAMPLE_A::OVER64X,
|
||||
Oversample::OVER128X => OVERSAMPLE_A::OVER128X,
|
||||
Oversample::OVER256X => OVERSAMPLE_A::OVER256X,
|
||||
Oversample::BYPASS => vals::Oversample::BYPASS,
|
||||
Oversample::OVER2X => vals::Oversample::OVER2X,
|
||||
Oversample::OVER4X => vals::Oversample::OVER4X,
|
||||
Oversample::OVER8X => vals::Oversample::OVER8X,
|
||||
Oversample::OVER16X => vals::Oversample::OVER16X,
|
||||
Oversample::OVER32X => vals::Oversample::OVER32X,
|
||||
Oversample::OVER64X => vals::Oversample::OVER64X,
|
||||
Oversample::OVER128X => vals::Oversample::OVER128X,
|
||||
Oversample::OVER256X => vals::Oversample::OVER256X,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -637,13 +620,13 @@ pub enum Oversample {
|
||||
OVER256X = 8,
|
||||
}
|
||||
|
||||
impl From<Resolution> for VAL_A {
|
||||
impl From<Resolution> for vals::Val {
|
||||
fn from(resolution: Resolution) -> Self {
|
||||
match resolution {
|
||||
Resolution::_8BIT => VAL_A::_8BIT,
|
||||
Resolution::_10BIT => VAL_A::_10BIT,
|
||||
Resolution::_12BIT => VAL_A::_12BIT,
|
||||
Resolution::_14BIT => VAL_A::_14BIT,
|
||||
Resolution::_8BIT => vals::Val::_8BIT,
|
||||
Resolution::_10BIT => vals::Val::_10BIT,
|
||||
Resolution::_12BIT => vals::Val::_12BIT,
|
||||
Resolution::_14BIT => vals::Val::_14BIT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -726,7 +709,7 @@ impl_peripheral!(VddInput);
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
impl_saadc_input!(@local, VddInput, VDD);
|
||||
#[cfg(feature = "_nrf91")]
|
||||
impl_saadc_input!(@local, VddInput, VDDGPIO);
|
||||
impl_saadc_input!(@local, VddInput, VDD_GPIO);
|
||||
|
||||
/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
|
||||
/// VDDH / 5 voltage.
|
||||
|
@ -13,12 +13,13 @@ use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||
pub use pac::spim0::config::ORDER_A as BitOrder;
|
||||
pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
||||
pub use pac::spim::vals::{Frequency, Order as BitOrder};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::spim::vals;
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
@ -33,6 +34,7 @@ pub enum Error {
|
||||
|
||||
/// SPIM configuration.
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
/// Frequency
|
||||
pub frequency: Frequency,
|
||||
@ -54,9 +56,6 @@ pub struct Config {
|
||||
|
||||
/// Drive strength for the MOSI line.
|
||||
pub mosi_drive: OutputDrive,
|
||||
|
||||
/// Drive strength for the MISO line.
|
||||
pub miso_drive: OutputDrive,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -68,7 +67,6 @@ impl Default for Config {
|
||||
orc: 0x00,
|
||||
sck_drive: OutputDrive::HighDrive,
|
||||
mosi_drive: OutputDrive::HighDrive,
|
||||
miso_drive: OutputDrive::HighDrive,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,15 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
{
|
||||
// Ideally we should call this only during the first chunk transfer,
|
||||
// but so far calling this every time doesn't seem to be causing any issues.
|
||||
if r.events_started.read().bits() != 0 {
|
||||
if r.events_started().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
r.intenclr().write(|w| w.set_started(true));
|
||||
}
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
if r.events_end().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -173,16 +171,19 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
|
||||
// Configure pins
|
||||
if let Some(sck) = &sck {
|
||||
sck.conf()
|
||||
.write(|w| w.dir().output().drive().variant(convert_drive(config.sck_drive)));
|
||||
sck.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_drive(convert_drive(config.sck_drive))
|
||||
});
|
||||
}
|
||||
if let Some(mosi) = &mosi {
|
||||
mosi.conf()
|
||||
.write(|w| w.dir().output().drive().variant(convert_drive(config.mosi_drive)));
|
||||
mosi.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_drive(convert_drive(config.mosi_drive))
|
||||
});
|
||||
}
|
||||
if let Some(miso) = &miso {
|
||||
miso.conf()
|
||||
.write(|w| w.input().connect().drive().variant(convert_drive(config.miso_drive)));
|
||||
miso.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
|
||||
}
|
||||
|
||||
match config.mode.polarity {
|
||||
@ -205,12 +206,12 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
}
|
||||
|
||||
// Select pins.
|
||||
r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
|
||||
r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) });
|
||||
r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) });
|
||||
r.psel().sck().write_value(sck.psel_bits());
|
||||
r.psel().mosi().write_value(mosi.psel_bits());
|
||||
r.psel().miso().write_value(miso.psel_bits());
|
||||
|
||||
// Enable SPIM instance.
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let mut spim = Self { _p: spim };
|
||||
|
||||
@ -218,7 +219,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
Self::set_config(&mut spim, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
@ -241,13 +242,13 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
|
||||
// Set up the DMA read.
|
||||
let (rx_ptr, rx_len) = xfer_params(rx as *mut u8 as _, rx.len() as _, offset, length);
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx_ptr) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
|
||||
r.rxd().ptr().write_value(rx_ptr);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(rx_len as _));
|
||||
|
||||
// Set up the DMA write.
|
||||
let (tx_ptr, tx_len) = xfer_params(tx as *const u8 as _, tx.len() as _, offset, length);
|
||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx_ptr) });
|
||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) });
|
||||
r.txd().ptr().write_value(tx_ptr);
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(tx_len as _));
|
||||
|
||||
/*
|
||||
trace!("XFER: offset: {}, length: {}", offset, length);
|
||||
@ -259,26 +260,26 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
if offset == 0 {
|
||||
let s = T::state();
|
||||
|
||||
r.events_started.reset();
|
||||
r.events_started().write_value(0);
|
||||
|
||||
// Set rx/tx buffer lengths to 0...
|
||||
r.txd.maxcnt.reset();
|
||||
r.rxd.maxcnt.reset();
|
||||
r.txd().maxcnt().write(|_| ());
|
||||
r.rxd().maxcnt().write(|_| ());
|
||||
|
||||
// ...and keep track of original buffer lengths...
|
||||
s.tx.store(tx_len as _, Ordering::Relaxed);
|
||||
s.rx.store(rx_len as _, Ordering::Relaxed);
|
||||
|
||||
// ...signalling the start of the fake transfer.
|
||||
r.intenset.write(|w| w.started().bit(true));
|
||||
r.intenset().write(|w| w.set_started(true));
|
||||
}
|
||||
|
||||
// Reset and enable the event
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.events_end().write_value(0);
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
|
||||
// Start SPI transaction.
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
}
|
||||
|
||||
fn blocking_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
|
||||
@ -290,7 +291,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
}
|
||||
|
||||
// Wait for 'end' event.
|
||||
while T::regs().events_end.read().bits() == 0 {}
|
||||
while T::regs().events_end().read() == 0 {}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
@ -338,7 +339,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
// Wait for 'end' event.
|
||||
poll_fn(|cx| {
|
||||
T::state().waker.register(cx.waker());
|
||||
if T::regs().events_end.read().bits() != 0 {
|
||||
if T::regs().events_end().read() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -442,24 +443,20 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
|
||||
let r = T::regs();
|
||||
if r.events_started.read().bits() != 0 {
|
||||
if r.events_started().read() != 0 {
|
||||
let s = T::state();
|
||||
|
||||
// Handle the first "fake" transmission
|
||||
r.events_started.reset();
|
||||
r.events_end.reset();
|
||||
r.events_started().write_value(0);
|
||||
r.events_end().write_value(0);
|
||||
|
||||
// Update DMA registers with correct rx/tx buffer sizes
|
||||
r.rxd
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
|
||||
r.txd
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(s.rx.load(Ordering::Relaxed)));
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(s.tx.load(Ordering::Relaxed)));
|
||||
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
// ... and start actual, hopefully glitch-free transmission
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start().write_value(1);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -474,11 +471,11 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||
|
||||
// disable!
|
||||
let r = T::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
|
||||
gpio::deconfigure_pin(r.psel.sck.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.miso.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.mosi.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().sck().read());
|
||||
gpio::deconfigure_pin(r.psel().miso().read());
|
||||
gpio::deconfigure_pin(r.psel().mosi().read());
|
||||
|
||||
// Disable all events interrupts
|
||||
T::Interrupt::disable();
|
||||
@ -508,7 +505,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::spim0::RegisterBlock;
|
||||
fn regs() -> pac::spim::Spim;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -522,8 +519,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
|
||||
macro_rules! impl_spim {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::spim::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::spim0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::spim::Spim {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::spim::State {
|
||||
static STATE: crate::spim::State = crate::spim::State::new();
|
||||
@ -621,40 +618,35 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
||||
let r = T::regs();
|
||||
// Configure mode.
|
||||
let mode = config.mode;
|
||||
r.config.write(|w| {
|
||||
r.config().write(|w| {
|
||||
w.set_order(config.bit_order);
|
||||
match mode {
|
||||
MODE_0 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_high();
|
||||
w.cpha().leading();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_HIGH);
|
||||
w.set_cpha(vals::Cpha::LEADING);
|
||||
}
|
||||
MODE_1 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_high();
|
||||
w.cpha().trailing();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_HIGH);
|
||||
w.set_cpha(vals::Cpha::TRAILING);
|
||||
}
|
||||
MODE_2 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_low();
|
||||
w.cpha().leading();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_LOW);
|
||||
w.set_cpha(vals::Cpha::LEADING);
|
||||
}
|
||||
MODE_3 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_low();
|
||||
w.cpha().trailing();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_LOW);
|
||||
w.set_cpha(vals::Cpha::TRAILING);
|
||||
}
|
||||
}
|
||||
|
||||
w
|
||||
});
|
||||
|
||||
// Configure frequency.
|
||||
let frequency = config.frequency;
|
||||
r.frequency.write(|w| w.frequency().variant(frequency));
|
||||
r.frequency().write(|w| w.set_frequency(frequency));
|
||||
|
||||
// Set over-read character
|
||||
let orc = config.orc;
|
||||
r.orc.write(|w| unsafe { w.orc().bits(orc) });
|
||||
r.orc().write(|w| w.set_orc(orc));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -10,11 +10,13 @@ use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||
pub use pac::spis0::config::ORDER_A as BitOrder;
|
||||
pub use pac::spis::vals::Order as BitOrder;
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, SealedPin as _};
|
||||
use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::spis::vals;
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
@ -54,6 +56,9 @@ pub struct Config {
|
||||
|
||||
/// Automatically make the firmware side acquire the semaphore on transfer end.
|
||||
pub auto_acquire: bool,
|
||||
|
||||
/// Drive strength for the MISO line.
|
||||
pub miso_drive: OutputDrive,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -64,6 +69,7 @@ impl Default for Config {
|
||||
orc: 0x00,
|
||||
def: 0x00,
|
||||
auto_acquire: true,
|
||||
miso_drive: OutputDrive::HighDrive,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,14 +84,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
if r.events_end().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
r.intenclr().write(|w| w.set_end(true));
|
||||
}
|
||||
|
||||
if r.events_acquired.read().bits() != 0 {
|
||||
if r.events_acquired().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.acquired().clear());
|
||||
r.intenclr().write(|w| w.set_acquired(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,23 +190,26 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// Configure pins.
|
||||
cs.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) });
|
||||
cs.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
|
||||
r.psel().csn().write_value(cs.psel_bits());
|
||||
if let Some(sck) = &sck {
|
||||
sck.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
|
||||
sck.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
|
||||
r.psel().sck().write_value(sck.psel_bits());
|
||||
}
|
||||
if let Some(mosi) = &mosi {
|
||||
mosi.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) });
|
||||
mosi.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
|
||||
r.psel().mosi().write_value(mosi.psel_bits());
|
||||
}
|
||||
if let Some(miso) = &miso {
|
||||
miso.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) });
|
||||
miso.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_drive(convert_drive(config.miso_drive))
|
||||
});
|
||||
r.psel().miso().write_value(miso.psel_bits());
|
||||
}
|
||||
|
||||
// Enable SPIS instance.
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let mut spis = Self { _p: spis };
|
||||
|
||||
@ -208,7 +217,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
Self::set_config(&mut spis, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts.
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
@ -229,21 +238,21 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
if tx.len() > EASY_DMA_SIZE {
|
||||
return Err(Error::TxBufferTooLong);
|
||||
}
|
||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx as *const u8 as _) });
|
||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx.len() as _) });
|
||||
r.txd().ptr().write_value(tx as *const u8 as _);
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(tx.len() as _));
|
||||
|
||||
// Set up the DMA read.
|
||||
if rx.len() > EASY_DMA_SIZE {
|
||||
return Err(Error::RxBufferTooLong);
|
||||
}
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx as *mut u8 as _) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx.len() as _) });
|
||||
r.rxd().ptr().write_value(rx as *mut u8 as _);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(rx.len() as _));
|
||||
|
||||
// Reset end event.
|
||||
r.events_end.reset();
|
||||
r.events_end().write_value(0);
|
||||
|
||||
// Release the semaphore.
|
||||
r.tasks_release.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_release().write_value(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -253,20 +262,20 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
// Acquire semaphore.
|
||||
if r.semstat.read().bits() != 1 {
|
||||
r.events_acquired.reset();
|
||||
r.tasks_acquire.write(|w| unsafe { w.bits(1) });
|
||||
if r.semstat().read().0 != 1 {
|
||||
r.events_acquired().write_value(0);
|
||||
r.tasks_acquire().write_value(1);
|
||||
// Wait until CPU has acquired the semaphore.
|
||||
while r.semstat.read().bits() != 1 {}
|
||||
while r.semstat().read().0 != 1 {}
|
||||
}
|
||||
|
||||
self.prepare(rx, tx)?;
|
||||
|
||||
// Wait for 'end' event.
|
||||
while r.events_end.read().bits() == 0 {}
|
||||
while r.events_end().read() == 0 {}
|
||||
|
||||
let n_rx = r.rxd.amount.read().bits() as usize;
|
||||
let n_tx = r.txd.amount.read().bits() as usize;
|
||||
let n_rx = r.rxd().amount().read().0 as usize;
|
||||
let n_tx = r.txd().amount().read().0 as usize;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
@ -291,22 +300,25 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
let s = T::state();
|
||||
|
||||
// Clear status register.
|
||||
r.status.write(|w| w.overflow().clear().overread().clear());
|
||||
r.status().write(|w| {
|
||||
w.set_overflow(true);
|
||||
w.set_overread(true);
|
||||
});
|
||||
|
||||
// Acquire semaphore.
|
||||
if r.semstat.read().bits() != 1 {
|
||||
if r.semstat().read().0 != 1 {
|
||||
// Reset and enable the acquire event.
|
||||
r.events_acquired.reset();
|
||||
r.intenset.write(|w| w.acquired().set());
|
||||
r.events_acquired().write_value(0);
|
||||
r.intenset().write(|w| w.set_acquired(true));
|
||||
|
||||
// Request acquiring the SPIS semaphore.
|
||||
r.tasks_acquire.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_acquire().write_value(1);
|
||||
|
||||
// Wait until CPU has acquired the semaphore.
|
||||
poll_fn(|cx| {
|
||||
s.waker.register(cx.waker());
|
||||
if r.events_acquired.read().bits() == 1 {
|
||||
r.events_acquired.reset();
|
||||
if r.events_acquired().read() == 1 {
|
||||
r.events_acquired().write_value(0);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -317,19 +329,19 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
self.prepare(rx, tx)?;
|
||||
|
||||
// Wait for 'end' event.
|
||||
r.intenset.write(|w| w.end().set());
|
||||
r.intenset().write(|w| w.set_end(true));
|
||||
poll_fn(|cx| {
|
||||
s.waker.register(cx.waker());
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.events_end.reset();
|
||||
if r.events_end().read() != 0 {
|
||||
r.events_end().write_value(0);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
|
||||
let n_rx = r.rxd.amount.read().bits() as usize;
|
||||
let n_tx = r.txd.amount.read().bits() as usize;
|
||||
let n_rx = r.rxd().amount().read().0 as usize;
|
||||
let n_tx = r.txd().amount().read().0 as usize;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
@ -428,12 +440,12 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
|
||||
/// Checks if last transaction overread.
|
||||
pub fn is_overread(&mut self) -> bool {
|
||||
T::regs().status.read().overread().is_present()
|
||||
T::regs().status().read().overread()
|
||||
}
|
||||
|
||||
/// Checks if last transaction overflowed.
|
||||
pub fn is_overflow(&mut self) -> bool {
|
||||
T::regs().status.read().overflow().is_present()
|
||||
T::regs().status().read().overflow()
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,12 +455,12 @@ impl<'d, T: Instance> Drop for Spis<'d, T> {
|
||||
|
||||
// Disable
|
||||
let r = T::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
|
||||
gpio::deconfigure_pin(r.psel.sck.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.csn.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.miso.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.mosi.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().sck().read());
|
||||
gpio::deconfigure_pin(r.psel().csn().read());
|
||||
gpio::deconfigure_pin(r.psel().miso().read());
|
||||
gpio::deconfigure_pin(r.psel().mosi().read());
|
||||
|
||||
trace!("spis drop: done");
|
||||
}
|
||||
@ -467,7 +479,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::spis0::RegisterBlock;
|
||||
fn regs() -> pac::spis::Spis;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -481,8 +493,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
|
||||
macro_rules! impl_spis {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::spis::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::spis0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::spis::Spis {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::spis::State {
|
||||
static STATE: crate::spis::State = crate::spis::State::new();
|
||||
@ -504,44 +516,39 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> {
|
||||
let r = T::regs();
|
||||
// Configure mode.
|
||||
let mode = config.mode;
|
||||
r.config.write(|w| {
|
||||
r.config().write(|w| {
|
||||
w.set_order(config.bit_order);
|
||||
match mode {
|
||||
MODE_0 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_high();
|
||||
w.cpha().leading();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_HIGH);
|
||||
w.set_cpha(vals::Cpha::LEADING);
|
||||
}
|
||||
MODE_1 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_high();
|
||||
w.cpha().trailing();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_HIGH);
|
||||
w.set_cpha(vals::Cpha::TRAILING);
|
||||
}
|
||||
MODE_2 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_low();
|
||||
w.cpha().leading();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_LOW);
|
||||
w.set_cpha(vals::Cpha::LEADING);
|
||||
}
|
||||
MODE_3 => {
|
||||
w.order().variant(config.bit_order);
|
||||
w.cpol().active_low();
|
||||
w.cpha().trailing();
|
||||
w.set_cpol(vals::Cpol::ACTIVE_LOW);
|
||||
w.set_cpha(vals::Cpha::TRAILING);
|
||||
}
|
||||
}
|
||||
|
||||
w
|
||||
});
|
||||
|
||||
// Set over-read character.
|
||||
let orc = config.orc;
|
||||
r.orc.write(|w| unsafe { w.orc().bits(orc) });
|
||||
r.orc().write(|w| w.set_orc(orc));
|
||||
|
||||
// Set default character.
|
||||
let def = config.def;
|
||||
r.def.write(|w| unsafe { w.def().bits(def) });
|
||||
r.def().write(|w| w.set_def(def));
|
||||
|
||||
// Configure auto-acquire on 'transfer end' event.
|
||||
let auto_acquire = config.auto_acquire;
|
||||
r.shorts.write(|w| w.end_acquire().bit(auto_acquire));
|
||||
r.shorts().write(|w| w.set_end_acquire(auto_acquire));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ pub struct InterruptHandler {
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*pac::TEMP::PTR };
|
||||
r.intenclr.write(|w| w.datardy().clear());
|
||||
let r = pac::TEMP;
|
||||
r.intenclr().write(|w| w.set_datardy(true));
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
@ -72,21 +72,21 @@ impl<'d> Temp<'d> {
|
||||
// In case the future is dropped, stop the task and reset events.
|
||||
let on_drop = OnDrop::new(|| {
|
||||
let t = Self::regs();
|
||||
t.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
t.events_datardy.reset();
|
||||
t.tasks_stop().write_value(1);
|
||||
t.events_datardy().write_value(0);
|
||||
});
|
||||
|
||||
let t = Self::regs();
|
||||
t.intenset.write(|w| w.datardy().set());
|
||||
unsafe { t.tasks_start.write(|w| w.bits(1)) };
|
||||
t.intenset().write(|w| w.set_datardy(true));
|
||||
t.tasks_start().write_value(1);
|
||||
|
||||
let value = poll_fn(|cx| {
|
||||
WAKER.register(cx.waker());
|
||||
if t.events_datardy.read().bits() == 0 {
|
||||
if t.events_datardy().read() == 0 {
|
||||
Poll::Pending
|
||||
} else {
|
||||
t.events_datardy.reset();
|
||||
let raw = t.temp.read().bits();
|
||||
t.events_datardy().write_value(0);
|
||||
let raw = t.temp().read();
|
||||
Poll::Ready(I30F2::from_bits(raw as i32))
|
||||
}
|
||||
})
|
||||
@ -95,7 +95,7 @@ impl<'d> Temp<'d> {
|
||||
value
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::temp::RegisterBlock {
|
||||
unsafe { &*pac::TEMP::ptr() }
|
||||
fn regs() -> pac::temp::Temp {
|
||||
pac::TEMP
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ use embassy_time_driver::{AlarmHandle, Driver};
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::{interrupt, pac};
|
||||
|
||||
fn rtc() -> &'static pac::rtc0::RegisterBlock {
|
||||
unsafe { &*pac::RTC1::ptr() }
|
||||
fn rtc() -> pac::rtc::Rtc {
|
||||
pac::RTC1
|
||||
}
|
||||
|
||||
/// Calculate the timestamp from the period count and the tick count.
|
||||
@ -128,19 +128,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
impl RtcDriver {
|
||||
fn init(&'static self, irq_prio: crate::interrupt::Priority) {
|
||||
let r = rtc();
|
||||
r.cc[3].write(|w| unsafe { w.bits(0x800000) });
|
||||
r.cc(3).write(|w| w.set_compare(0x800000));
|
||||
|
||||
r.intenset.write(|w| {
|
||||
let w = w.ovrflw().set();
|
||||
let w = w.compare3().set();
|
||||
w
|
||||
r.intenset().write(|w| {
|
||||
w.set_ovrflw(true);
|
||||
w.set_compare3(true);
|
||||
});
|
||||
|
||||
r.tasks_clear.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_clear().write_value(1);
|
||||
r.tasks_start().write_value(1);
|
||||
|
||||
// Wait for clear
|
||||
while r.counter.read().bits() != 0 {}
|
||||
while r.counter().read().0 != 0 {}
|
||||
|
||||
interrupt::RTC1.set_priority(irq_prio);
|
||||
unsafe { interrupt::RTC1.enable() };
|
||||
@ -148,19 +147,19 @@ impl RtcDriver {
|
||||
|
||||
fn on_interrupt(&self) {
|
||||
let r = rtc();
|
||||
if r.events_ovrflw.read().bits() == 1 {
|
||||
r.events_ovrflw.write(|w| w);
|
||||
if r.events_ovrflw().read() == 1 {
|
||||
r.events_ovrflw().write_value(0);
|
||||
self.next_period();
|
||||
}
|
||||
|
||||
if r.events_compare[3].read().bits() == 1 {
|
||||
r.events_compare[3].write(|w| w);
|
||||
if r.events_compare(3).read() == 1 {
|
||||
r.events_compare(3).write_value(0);
|
||||
self.next_period();
|
||||
}
|
||||
|
||||
for n in 0..ALARM_COUNT {
|
||||
if r.events_compare[n].read().bits() == 1 {
|
||||
r.events_compare[n].write(|w| w);
|
||||
if r.events_compare(n).read() == 1 {
|
||||
r.events_compare(n).write_value(0);
|
||||
critical_section::with(|cs| {
|
||||
self.trigger_alarm(n, cs);
|
||||
})
|
||||
@ -181,7 +180,7 @@ impl RtcDriver {
|
||||
|
||||
if at < t + 0xc00000 {
|
||||
// just enable it. `set_alarm` has already set the correct CC val.
|
||||
r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
|
||||
r.intenset().write(|w| w.0 = compare_n(n));
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -195,7 +194,7 @@ impl RtcDriver {
|
||||
|
||||
fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
|
||||
let r = rtc();
|
||||
r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
|
||||
r.intenclr().write(|w| w.0 = compare_n(n));
|
||||
|
||||
let alarm = &self.alarms.borrow(cs)[n];
|
||||
alarm.timestamp.set(u64::MAX);
|
||||
@ -215,7 +214,7 @@ impl Driver for RtcDriver {
|
||||
// `period` MUST be read before `counter`, see comment at the top for details.
|
||||
let period = self.period.load(Ordering::Relaxed);
|
||||
compiler_fence(Ordering::Acquire);
|
||||
let counter = rtc().counter.read().bits();
|
||||
let counter = rtc().counter().read().0;
|
||||
calc_now(period, counter)
|
||||
}
|
||||
|
||||
@ -252,7 +251,7 @@ impl Driver for RtcDriver {
|
||||
if timestamp <= t {
|
||||
// If alarm timestamp has passed the alarm will not fire.
|
||||
// Disarm the alarm and return `false` to indicate that.
|
||||
r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
|
||||
r.intenclr().write(|w| w.0 = compare_n(n));
|
||||
|
||||
alarm.timestamp.set(u64::MAX);
|
||||
|
||||
@ -277,15 +276,15 @@ impl Driver for RtcDriver {
|
||||
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
|
||||
// and we don't do that here.
|
||||
let safe_timestamp = timestamp.max(t + 3);
|
||||
r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) });
|
||||
r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
|
||||
|
||||
let diff = timestamp - t;
|
||||
if diff < 0xc00000 {
|
||||
r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
|
||||
r.intenset().write(|w| w.0 = compare_n(n));
|
||||
} else {
|
||||
// If it's too far in the future, don't setup the compare channel yet.
|
||||
// It will be setup later by `next_period`.
|
||||
r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
|
||||
r.intenclr().write(|w| w.0 = compare_n(n));
|
||||
}
|
||||
|
||||
true
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::timer::vals;
|
||||
use crate::ppi::{Event, Task};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
/// The number of CC registers this instance has.
|
||||
const CCS: usize;
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock;
|
||||
fn regs() -> pac::timer::Timer;
|
||||
}
|
||||
|
||||
/// Basic Timer instance.
|
||||
@ -31,8 +32,8 @@ macro_rules! impl_timer {
|
||||
($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => {
|
||||
impl crate::timer::SealedInstance for peripherals::$type {
|
||||
const CCS: usize = $ccs;
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock {
|
||||
unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
|
||||
fn regs() -> pac::timer::Timer {
|
||||
unsafe { pac::timer::Timer::from_ptr(pac::$pac_type.as_ptr()) }
|
||||
}
|
||||
}
|
||||
impl crate::timer::Instance for peripherals::$type {
|
||||
@ -114,19 +115,19 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
||||
this.stop();
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
if _is_counter {
|
||||
regs.mode.write(|w| w.mode().low_power_counter());
|
||||
} else {
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
regs.mode().write(|w| {
|
||||
w.set_mode(match _is_counter {
|
||||
#[cfg(not(feature = "_nrf51"))]
|
||||
true => vals::Mode::LOW_POWER_COUNTER,
|
||||
#[cfg(feature = "_nrf51")]
|
||||
true => vals::Mode::COUNTER,
|
||||
false => vals::Mode::TIMER,
|
||||
})
|
||||
});
|
||||
|
||||
// Make the counter's max value as high as possible.
|
||||
// TODO: is there a reason someone would want to set this lower?
|
||||
regs.bitmode.write(|w| w.bitmode()._32bit());
|
||||
regs.bitmode().write(|w| w.set_bitmode(vals::Bitmode::_32BIT));
|
||||
|
||||
// Initialize the counter at 0.
|
||||
this.clear();
|
||||
@ -148,38 +149,38 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
|
||||
/// Starts the timer.
|
||||
pub fn start(&self) {
|
||||
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_start().write_value(1)
|
||||
}
|
||||
|
||||
/// Stops the timer.
|
||||
pub fn stop(&self) {
|
||||
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_stop().write_value(1)
|
||||
}
|
||||
|
||||
/// Reset the timer's counter to 0.
|
||||
pub fn clear(&self) {
|
||||
T::regs().tasks_clear.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_clear().write_value(1)
|
||||
}
|
||||
|
||||
/// Returns the START task, for use with PPI.
|
||||
///
|
||||
/// When triggered, this task starts the timer.
|
||||
pub fn task_start(&self) -> Task<'d> {
|
||||
Task::from_reg(&T::regs().tasks_start)
|
||||
Task::from_reg(T::regs().tasks_start())
|
||||
}
|
||||
|
||||
/// Returns the STOP task, for use with PPI.
|
||||
///
|
||||
/// When triggered, this task stops the timer.
|
||||
pub fn task_stop(&self) -> Task<'d> {
|
||||
Task::from_reg(&T::regs().tasks_stop)
|
||||
Task::from_reg(T::regs().tasks_stop())
|
||||
}
|
||||
|
||||
/// Returns the CLEAR task, for use with PPI.
|
||||
///
|
||||
/// When triggered, this task resets the timer's counter to 0.
|
||||
pub fn task_clear(&self) -> Task<'d> {
|
||||
Task::from_reg(&T::regs().tasks_clear)
|
||||
Task::from_reg(T::regs().tasks_clear())
|
||||
}
|
||||
|
||||
/// Returns the COUNT task, for use with PPI.
|
||||
@ -187,7 +188,7 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
/// When triggered, this task increments the timer's counter by 1.
|
||||
/// Only works in counter mode.
|
||||
pub fn task_count(&self) -> Task<'d> {
|
||||
Task::from_reg(&T::regs().tasks_count)
|
||||
Task::from_reg(T::regs().tasks_count())
|
||||
}
|
||||
|
||||
/// Change the timer's frequency.
|
||||
@ -198,10 +199,10 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
self.stop();
|
||||
|
||||
T::regs()
|
||||
.prescaler
|
||||
.prescaler()
|
||||
// SAFETY: `frequency` is a variant of `Frequency`,
|
||||
// whose values are all in the range of 0-9 (the valid range of `prescaler`).
|
||||
.write(|w| unsafe { w.prescaler().bits(frequency as u8) })
|
||||
.write(|w| w.set_prescaler(frequency as u8))
|
||||
}
|
||||
|
||||
/// Returns this timer's `n`th CC register.
|
||||
@ -234,28 +235,19 @@ pub struct Cc<'d, T: Instance> {
|
||||
impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// Get the current value stored in the register.
|
||||
pub fn read(&self) -> u32 {
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
return T::regs().cc[self.n].read().cc().bits();
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
return T::regs().cc[self.n].read().bits();
|
||||
return T::regs().cc(self.n).read();
|
||||
}
|
||||
|
||||
/// Set the value stored in the register.
|
||||
///
|
||||
/// `event_compare` will fire when the timer's counter reaches this value.
|
||||
pub fn write(&self, value: u32) {
|
||||
// SAFETY: there are no invalid values for the CC register.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) });
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.bits(value) });
|
||||
T::regs().cc(self.n).write_value(value);
|
||||
}
|
||||
|
||||
/// Capture the current value of the timer's counter in this register, and return it.
|
||||
pub fn capture(&self) -> u32 {
|
||||
T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) });
|
||||
T::regs().tasks_capture(self.n).write_value(1);
|
||||
self.read()
|
||||
}
|
||||
|
||||
@ -263,14 +255,14 @@ impl<'d, T: Instance> Cc<'d, T> {
|
||||
///
|
||||
/// When triggered, this task will capture the current value of the timer's counter in this register.
|
||||
pub fn task_capture(&self) -> Task<'d> {
|
||||
Task::from_reg(&T::regs().tasks_capture)
|
||||
Task::from_reg(T::regs().tasks_capture(self.n))
|
||||
}
|
||||
|
||||
/// Returns this CC register's COMPARE event, for use with PPI.
|
||||
///
|
||||
/// This event will fire when the timer's counter reaches the value in this CC register.
|
||||
pub fn event_compare(&self) -> Event<'d> {
|
||||
Event::from_reg(&T::regs().events_compare[self.n])
|
||||
Event::from_reg(T::regs().events_compare(self.n))
|
||||
}
|
||||
|
||||
/// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
|
||||
@ -279,16 +271,12 @@ impl<'d, T: Instance> Cc<'d, T> {
|
||||
///
|
||||
/// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0.
|
||||
pub fn short_compare_clear(&self) {
|
||||
T::regs()
|
||||
.shorts
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) })
|
||||
T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true))
|
||||
}
|
||||
|
||||
/// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
|
||||
pub fn unshort_compare_clear(&self) {
|
||||
T::regs()
|
||||
.shorts
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) })
|
||||
T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false))
|
||||
}
|
||||
|
||||
/// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task.
|
||||
@ -297,15 +285,11 @@ impl<'d, T: Instance> Cc<'d, T> {
|
||||
///
|
||||
/// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up.
|
||||
pub fn short_compare_stop(&self) {
|
||||
T::regs()
|
||||
.shorts
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) })
|
||||
T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true))
|
||||
}
|
||||
|
||||
/// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task.
|
||||
pub fn unshort_compare_stop(&self) {
|
||||
T::regs()
|
||||
.shorts
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) })
|
||||
T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false))
|
||||
}
|
||||
}
|
||||
|
@ -15,24 +15,16 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
#[cfg(feature = "time")]
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embedded_hal_1::i2c::Operation;
|
||||
pub use pac::twim::vals::Frequency;
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::twim::vals;
|
||||
use crate::util::slice_in_ram;
|
||||
use crate::{gpio, interrupt, pac, Peripheral};
|
||||
|
||||
/// TWI frequency
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Frequency {
|
||||
/// 100 kbps
|
||||
K100 = 26738688,
|
||||
/// 250 kbps
|
||||
K250 = 67108864,
|
||||
/// 400 kbps
|
||||
K400 = 104857600,
|
||||
}
|
||||
|
||||
/// TWIM config.
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -105,17 +97,17 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_suspended.read().bits() != 0 {
|
||||
if r.events_suspended().read() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.suspended().clear());
|
||||
r.intenclr().write(|w| w.set_suspended(true));
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_stopped().read() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
r.intenclr().write(|w| w.set_stopped(true));
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
if r.events_error().read() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
r.intenclr().write(|w| w.set_error(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,38 +132,34 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
// Configure pins
|
||||
sda.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
if config.sda_high_drive {
|
||||
w.drive().h0d1();
|
||||
} else {
|
||||
w.drive().s0d1();
|
||||
}
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(match config.sda_high_drive {
|
||||
true => gpiovals::Drive::H0D1,
|
||||
false => gpiovals::Drive::S0D1,
|
||||
});
|
||||
if config.sda_pullup {
|
||||
w.pull().pullup();
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
}
|
||||
w
|
||||
});
|
||||
scl.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
if config.scl_high_drive {
|
||||
w.drive().h0d1();
|
||||
} else {
|
||||
w.drive().s0d1();
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(match config.scl_high_drive {
|
||||
true => gpiovals::Drive::H0D1,
|
||||
false => gpiovals::Drive::S0D1,
|
||||
});
|
||||
if config.sda_pullup {
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
}
|
||||
if config.scl_pullup {
|
||||
w.pull().pullup();
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
// Select pins.
|
||||
r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) });
|
||||
r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) });
|
||||
r.psel().sda().write_value(sda.psel_bits());
|
||||
r.psel().scl().write_value(scl.psel_bits());
|
||||
|
||||
// Enable TWIM instance.
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let mut twim = Self { _p: twim };
|
||||
|
||||
@ -179,7 +167,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
Self::set_config(&mut twim, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
@ -211,22 +199,18 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.txd.ptr.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
//
|
||||
// The PTR field is a full 32 bits wide and accepts the full range
|
||||
// of values.
|
||||
w.ptr().bits(buffer.as_ptr() as u32));
|
||||
r.txd.maxcnt.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
r.txd().ptr().write_value(buffer.as_ptr() as u32);
|
||||
r.txd().maxcnt().write(|w|
|
||||
// We're giving it the length of the buffer, so no danger of
|
||||
// accessing invalid memory. We have verified that the length of the
|
||||
// buffer fits in an `u8`, so the cast to `u8` is also fine.
|
||||
//
|
||||
// The MAXCNT field is 8 bits wide and accepts the full range of
|
||||
// values.
|
||||
w.maxcnt().bits(buffer.len() as _));
|
||||
w.set_maxcnt(buffer.len() as _));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -242,15 +226,11 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.rxd.ptr.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
//
|
||||
// The PTR field is a full 32 bits wide and accepts the full range
|
||||
// of values.
|
||||
w.ptr().bits(buffer.as_mut_ptr() as u32));
|
||||
r.rxd.maxcnt.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32);
|
||||
r.rxd().maxcnt().write(|w|
|
||||
// We're giving it the length of the buffer, so no danger of
|
||||
// accessing invalid memory. We have verified that the length of the
|
||||
// buffer fits in an `u8`, so the cast to the type of maxcnt
|
||||
@ -260,29 +240,32 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
// type than a u8, so we use a `_` cast rather than a `u8` cast.
|
||||
// The MAXCNT field is thus at least 8 bits wide and accepts the
|
||||
// full range of values that fit in a `u8`.
|
||||
w.maxcnt().bits(buffer.len() as _));
|
||||
w.set_maxcnt(buffer.len() as _));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_errorsrc(&mut self) {
|
||||
let r = T::regs();
|
||||
r.errorsrc
|
||||
.write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true));
|
||||
r.errorsrc().write(|w| {
|
||||
w.set_anack(true);
|
||||
w.set_dnack(true);
|
||||
w.set_overrun(true);
|
||||
});
|
||||
}
|
||||
|
||||
/// Get Error instance, if any occurred.
|
||||
fn check_errorsrc(&self) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
let err = r.errorsrc.read();
|
||||
if err.anack().is_received() {
|
||||
let err = r.errorsrc().read();
|
||||
if err.anack() {
|
||||
return Err(Error::AddressNack);
|
||||
}
|
||||
if err.dnack().is_received() {
|
||||
if err.dnack() {
|
||||
return Err(Error::DataNack);
|
||||
}
|
||||
if err.overrun().is_received() {
|
||||
if err.overrun() {
|
||||
return Err(Error::Overrun);
|
||||
}
|
||||
Ok(())
|
||||
@ -290,7 +273,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
fn check_rx(&self, len: usize) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
if r.rxd.amount.read().bits() != len as u32 {
|
||||
if r.rxd().amount().read().0 != len as u32 {
|
||||
Err(Error::Receive)
|
||||
} else {
|
||||
Ok(())
|
||||
@ -299,7 +282,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
fn check_tx(&self, len: usize) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
if r.txd.amount.read().bits() != len as u32 {
|
||||
if r.txd().amount().read().0 != len as u32 {
|
||||
Err(Error::Transmit)
|
||||
} else {
|
||||
Ok(())
|
||||
@ -310,14 +293,14 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
fn blocking_wait(&mut self) {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_suspended.reset();
|
||||
r.events_stopped.reset();
|
||||
if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
|
||||
r.events_suspended().write_value(0);
|
||||
r.events_stopped().write_value(0);
|
||||
break;
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,16 +311,16 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
let r = T::regs();
|
||||
let deadline = Instant::now() + timeout;
|
||||
loop {
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
break;
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
}
|
||||
if Instant::now() > deadline {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Timeout);
|
||||
}
|
||||
}
|
||||
@ -352,16 +335,16 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
let s = T::state();
|
||||
|
||||
s.end_waker.register(cx.waker());
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
@ -380,18 +363,25 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
r.address().write(|w| w.set_address(address));
|
||||
|
||||
r.events_suspended.reset();
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_suspended().write_value(0);
|
||||
r.events_stopped().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.suspended().set().stopped().set().error().set());
|
||||
r.intenset().write(|w| {
|
||||
w.set_suspended(true);
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
} else {
|
||||
r.intenclr
|
||||
.write(|w| w.suspended().clear().stopped().clear().error().clear());
|
||||
r.intenclr().write(|w| {
|
||||
w.set_suspended(true);
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
}
|
||||
|
||||
assert!(!operations.is_empty());
|
||||
@ -408,26 +398,25 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
self.set_rx_buffer(rd_buffer)?;
|
||||
}
|
||||
|
||||
r.shorts.write(|w| {
|
||||
w.lastrx_starttx().enabled();
|
||||
r.shorts().write(|w| {
|
||||
w.set_lastrx_starttx(true);
|
||||
if stop {
|
||||
w.lasttx_stop().enabled();
|
||||
w.set_lasttx_stop(true);
|
||||
} else {
|
||||
w.lasttx_suspend().enabled();
|
||||
w.set_lasttx_suspend(true);
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
// Start read+write operation.
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_resume().write_value(1);
|
||||
}
|
||||
|
||||
// TODO: Handle empty write buffer
|
||||
if rd_buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves.
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
}
|
||||
|
||||
Ok(2)
|
||||
@ -438,17 +427,17 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
self.set_rx_buffer(buffer)?;
|
||||
}
|
||||
|
||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||
r.shorts().write(|w| w.set_lastrx_stop(true));
|
||||
|
||||
// Start read operation.
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_resume().write_value(1);
|
||||
}
|
||||
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves.
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
}
|
||||
|
||||
Ok(1)
|
||||
@ -463,15 +452,14 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
}
|
||||
|
||||
// Start write+read operation.
|
||||
r.shorts.write(|w| {
|
||||
w.lasttx_startrx().enabled();
|
||||
w.lastrx_stop().enabled();
|
||||
w
|
||||
r.shorts().write(|w| {
|
||||
w.set_lasttx_startrx(true);
|
||||
w.set_lastrx_stop(true);
|
||||
});
|
||||
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_resume().write_value(1);
|
||||
}
|
||||
|
||||
Ok(2)
|
||||
@ -485,26 +473,25 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
}
|
||||
|
||||
// Start write operation.
|
||||
r.shorts.write(|w| {
|
||||
r.shorts().write(|w| {
|
||||
if stop {
|
||||
w.lasttx_stop().enabled();
|
||||
w.set_lasttx_stop(true);
|
||||
} else {
|
||||
w.lasttx_suspend().enabled();
|
||||
w.set_lasttx_suspend(true);
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_resume().write_value(1);
|
||||
}
|
||||
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves.
|
||||
if stop {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
} else {
|
||||
r.tasks_suspend.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_suspend().write_value(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,10 +814,10 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||
|
||||
// disable!
|
||||
let r = T::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
|
||||
gpio::deconfigure_pin(r.psel.sda.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.scl.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().sda().read());
|
||||
gpio::deconfigure_pin(r.psel().scl().read());
|
||||
|
||||
trace!("twim drop: done");
|
||||
}
|
||||
@ -849,7 +836,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::twim0::RegisterBlock;
|
||||
fn regs() -> pac::twim::Twim;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -863,8 +850,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
|
||||
macro_rules! impl_twim {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::twim::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::twim0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::twim::Twim {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::twim::State {
|
||||
static STATE: crate::twim::State = crate::twim::State::new();
|
||||
@ -948,8 +935,7 @@ impl<'d, T: Instance> SetConfig for Twim<'d, T> {
|
||||
type ConfigError = ();
|
||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
|
||||
let r = T::regs();
|
||||
r.frequency
|
||||
.write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
|
||||
r.frequency().write(|w| w.set_frequency(config.frequency));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ use embassy_time::{Duration, Instant};
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::twis::vals;
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{gpio, interrupt, pac, Peripheral};
|
||||
|
||||
@ -119,17 +121,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
|
||||
if r.events_read().read() != 0 || r.events_write().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.read().clear().write().clear());
|
||||
r.intenclr().write(|w| {
|
||||
w.set_read(true);
|
||||
w.set_write(true);
|
||||
});
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_stopped().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.stopped().clear());
|
||||
r.intenclr().write(|w| w.set_stopped(true));
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
if r.events_error().read() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.error().clear());
|
||||
r.intenclr().write(|w| w.set_error(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,55 +159,51 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
|
||||
// Configure pins
|
||||
sda.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
if config.sda_high_drive {
|
||||
w.drive().h0d1();
|
||||
} else {
|
||||
w.drive().s0d1();
|
||||
}
|
||||
w.set_dir(gpiovals::Dir::INPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(match config.sda_high_drive {
|
||||
true => gpiovals::Drive::H0D1,
|
||||
false => gpiovals::Drive::S0D1,
|
||||
});
|
||||
if config.sda_pullup {
|
||||
w.pull().pullup();
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
}
|
||||
w
|
||||
});
|
||||
scl.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
if config.scl_high_drive {
|
||||
w.drive().h0d1();
|
||||
} else {
|
||||
w.drive().s0d1();
|
||||
w.set_dir(gpiovals::Dir::INPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(match config.scl_high_drive {
|
||||
true => gpiovals::Drive::H0D1,
|
||||
false => gpiovals::Drive::S0D1,
|
||||
});
|
||||
if config.sda_pullup {
|
||||
w.set_pull(gpiovals::Pull::PULLUP);
|
||||
}
|
||||
if config.scl_pullup {
|
||||
w.pull().pullup();
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
// Select pins.
|
||||
r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) });
|
||||
r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) });
|
||||
r.psel().sda().write_value(sda.psel_bits());
|
||||
r.psel().scl().write_value(scl.psel_bits());
|
||||
|
||||
// Enable TWIS instance.
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
|
||||
|
||||
// Set address
|
||||
r.address[0].write(|w| unsafe { w.address().bits(config.address0) });
|
||||
r.config.write(|w| w.address0().enabled());
|
||||
r.address(0).write(|w| w.set_address(config.address0));
|
||||
r.config().write(|w| w.set_address0(true));
|
||||
if let Some(address1) = config.address1 {
|
||||
r.address[1].write(|w| unsafe { w.address().bits(address1) });
|
||||
r.config.modify(|_r, w| w.address1().enabled());
|
||||
r.address(1).write(|w| w.set_address(address1));
|
||||
r.config().modify(|w| w.set_address1(true));
|
||||
}
|
||||
|
||||
// Set over-read character
|
||||
r.orc.write(|w| unsafe { w.orc().bits(config.orc) });
|
||||
r.orc().write(|w| w.set_orc(config.orc));
|
||||
|
||||
// Generate suspend on read event
|
||||
r.shorts.write(|w| w.read_suspend().enabled());
|
||||
r.shorts().write(|w| w.set_read_suspend(true));
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
@ -220,22 +221,18 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.txd.ptr.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
//
|
||||
// The PTR field is a full 32 bits wide and accepts the full range
|
||||
// of values.
|
||||
w.ptr().bits(buffer.as_ptr() as u32));
|
||||
r.txd.maxcnt.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
r.txd().ptr().write_value(buffer.as_ptr() as u32);
|
||||
r.txd().maxcnt().write(|w|
|
||||
// We're giving it the length of the buffer, so no danger of
|
||||
// accessing invalid memory. We have verified that the length of the
|
||||
// buffer fits in an `u8`, so the cast to `u8` is also fine.
|
||||
//
|
||||
// The MAXCNT field is 8 bits wide and accepts the full range of
|
||||
// values.
|
||||
w.maxcnt().bits(buffer.len() as _));
|
||||
w.set_maxcnt(buffer.len() as _));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -251,15 +248,11 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.rxd.ptr.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
//
|
||||
// The PTR field is a full 32 bits wide and accepts the full range
|
||||
// of values.
|
||||
w.ptr().bits(buffer.as_mut_ptr() as u32));
|
||||
r.rxd.maxcnt.write(|w|
|
||||
// We're giving the register a pointer to the stack. Since we're
|
||||
// waiting for the I2C transaction to end before this stack pointer
|
||||
// becomes invalid, there's nothing wrong here.
|
||||
r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32);
|
||||
r.rxd().maxcnt().write(|w|
|
||||
// We're giving it the length of the buffer, so no danger of
|
||||
// accessing invalid memory. We have verified that the length of the
|
||||
// buffer fits in an `u8`, so the cast to the type of maxcnt
|
||||
@ -269,48 +262,51 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
// type than a u8, so we use a `_` cast rather than a `u8` cast.
|
||||
// The MAXCNT field is thus at least 8 bits wide and accepts the
|
||||
// full range of values that fit in a `u8`.
|
||||
w.maxcnt().bits(buffer.len() as _));
|
||||
w.set_maxcnt(buffer.len() as _));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_errorsrc(&mut self) {
|
||||
let r = T::regs();
|
||||
r.errorsrc
|
||||
.write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true));
|
||||
r.errorsrc().write(|w| {
|
||||
w.set_overflow(true);
|
||||
w.set_overread(true);
|
||||
w.set_dnack(true);
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns matched address for latest command.
|
||||
pub fn address_match(&self) -> u8 {
|
||||
let r = T::regs();
|
||||
r.address[r.match_.read().bits() as usize].read().address().bits()
|
||||
r.address(r.match_().read().0 as usize).read().address()
|
||||
}
|
||||
|
||||
/// Returns the index of the address matched in the latest command.
|
||||
pub fn address_match_index(&self) -> usize {
|
||||
T::regs().match_.read().bits() as _
|
||||
T::regs().match_().read().0 as _
|
||||
}
|
||||
|
||||
/// Wait for read, write, stop or error
|
||||
fn blocking_listen_wait(&mut self) -> Result<Status, Error> {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_stopped.read().bits() == 0 {}
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
while r.events_stopped().read() == 0 {}
|
||||
return Err(Error::Overflow);
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return Err(Error::Bus);
|
||||
}
|
||||
if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
return Ok(Status::Read);
|
||||
}
|
||||
if r.events_write.read().bits() != 0 {
|
||||
r.events_write.reset();
|
||||
if r.events_write().read() != 0 {
|
||||
r.events_write().write_value(0);
|
||||
return Ok(Status::Write);
|
||||
}
|
||||
}
|
||||
@ -321,22 +317,22 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Overflow);
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return match status {
|
||||
Status::Read => Ok(Command::Read),
|
||||
Status::Write => {
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
Ok(Command::Write(n))
|
||||
}
|
||||
};
|
||||
} else if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
} else if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
return Ok(Command::WriteRead(n));
|
||||
}
|
||||
}
|
||||
@ -347,20 +343,20 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
let errorsrc = r.errorsrc.read();
|
||||
if errorsrc.overread().is_detected() {
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
let errorsrc = r.errorsrc().read();
|
||||
if errorsrc.overread() {
|
||||
return Err(Error::OverRead);
|
||||
} else if errorsrc.dnack().is_received() {
|
||||
} else if errorsrc.dnack() {
|
||||
return Err(Error::DataNack);
|
||||
} else {
|
||||
return Err(Error::Bus);
|
||||
}
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
let n = r.txd.amount.read().bits() as usize;
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
let n = r.txd().amount().read().0 as usize;
|
||||
return Ok(n);
|
||||
}
|
||||
}
|
||||
@ -373,23 +369,23 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
let deadline = Instant::now() + timeout;
|
||||
loop {
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
let errorsrc = r.errorsrc.read();
|
||||
if errorsrc.overread().is_detected() {
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
let errorsrc = r.errorsrc().read();
|
||||
if errorsrc.overread() {
|
||||
return Err(Error::OverRead);
|
||||
} else if errorsrc.dnack().is_received() {
|
||||
} else if errorsrc.dnack() {
|
||||
return Err(Error::DataNack);
|
||||
} else {
|
||||
return Err(Error::Bus);
|
||||
}
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
let n = r.txd.amount.read().bits() as usize;
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
let n = r.txd().amount().read().0 as usize;
|
||||
return Ok(n);
|
||||
} else if Instant::now() > deadline {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Timeout);
|
||||
}
|
||||
}
|
||||
@ -401,26 +397,26 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
let r = T::regs();
|
||||
let deadline = Instant::now() + timeout;
|
||||
loop {
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_stopped.read().bits() == 0 {}
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
while r.events_stopped().read() == 0 {}
|
||||
return Err(Error::Overflow);
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return Err(Error::Bus);
|
||||
}
|
||||
if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
return Ok(Status::Read);
|
||||
}
|
||||
if r.events_write.read().bits() != 0 {
|
||||
r.events_write.reset();
|
||||
if r.events_write().read() != 0 {
|
||||
r.events_write().write_value(0);
|
||||
return Ok(Status::Write);
|
||||
}
|
||||
if Instant::now() > deadline {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Timeout);
|
||||
}
|
||||
}
|
||||
@ -433,25 +429,25 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
let deadline = Instant::now() + timeout;
|
||||
loop {
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Overflow);
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return match status {
|
||||
Status::Read => Ok(Command::Read),
|
||||
Status::Write => {
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
Ok(Command::Write(n))
|
||||
}
|
||||
};
|
||||
} else if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
} else if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
return Ok(Command::WriteRead(n));
|
||||
} else if Instant::now() > deadline {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stop().write_value(1);
|
||||
return Err(Error::Timeout);
|
||||
}
|
||||
}
|
||||
@ -466,20 +462,20 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
let errorsrc = r.errorsrc.read();
|
||||
if errorsrc.overread().is_detected() {
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
let errorsrc = r.errorsrc().read();
|
||||
if errorsrc.overread() {
|
||||
return Poll::Ready(Err(Error::OverRead));
|
||||
} else if errorsrc.dnack().is_received() {
|
||||
} else if errorsrc.dnack() {
|
||||
return Poll::Ready(Err(Error::DataNack));
|
||||
} else {
|
||||
return Poll::Ready(Err(Error::Bus));
|
||||
}
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
let n = r.txd.amount.read().bits() as usize;
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
let n = r.txd().amount().read().0 as usize;
|
||||
return Poll::Ready(Ok(n));
|
||||
}
|
||||
|
||||
@ -496,18 +492,18 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
return Poll::Ready(Err(Error::Overflow));
|
||||
} else if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
} else if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
return Poll::Ready(Ok(Status::Read));
|
||||
} else if r.events_write.read().bits() != 0 {
|
||||
r.events_write.reset();
|
||||
} else if r.events_write().read() != 0 {
|
||||
r.events_write().write_value(0);
|
||||
return Poll::Ready(Ok(Status::Write));
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return Poll::Ready(Err(Error::Bus));
|
||||
}
|
||||
Poll::Pending
|
||||
@ -523,22 +519,22 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// stop if an error occurred
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
if r.events_error().read() != 0 {
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stop().write_value(1);
|
||||
return Poll::Ready(Err(Error::Overflow));
|
||||
} else if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
} else if r.events_stopped().read() != 0 {
|
||||
r.events_stopped().write_value(0);
|
||||
return match status {
|
||||
Status::Read => Poll::Ready(Ok(Command::Read)),
|
||||
Status::Write => {
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
Poll::Ready(Ok(Command::Write(n)))
|
||||
}
|
||||
};
|
||||
} else if r.events_read.read().bits() != 0 {
|
||||
r.events_read.reset();
|
||||
let n = r.rxd.amount.read().bits() as usize;
|
||||
} else if r.events_read().read() != 0 {
|
||||
r.events_read().write_value(0);
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
return Poll::Ready(Ok(Command::WriteRead(n)));
|
||||
}
|
||||
Poll::Pending
|
||||
@ -554,19 +550,25 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
unsafe { self.set_tx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_stopped().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.stopped().set().error().set());
|
||||
r.intenset().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
} else {
|
||||
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||
r.intenclr().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Start write operation.
|
||||
r.tasks_preparetx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_preparetx().write_value(1);
|
||||
r.tasks_resume().write_value(1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -591,22 +593,30 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
unsafe { self.set_rx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_read.reset();
|
||||
r.events_write.reset();
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_read().write_value(0);
|
||||
r.events_write().write_value(0);
|
||||
r.events_stopped().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset
|
||||
.write(|w| w.stopped().set().error().set().read().set().write().set());
|
||||
r.intenset().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
w.set_read(true);
|
||||
w.set_write(true);
|
||||
});
|
||||
} else {
|
||||
r.intenclr
|
||||
.write(|w| w.stopped().clear().error().clear().read().clear().write().clear());
|
||||
r.intenclr().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
w.set_read(true);
|
||||
w.set_write(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Start read operation.
|
||||
r.tasks_preparerx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_preparerx().write_value(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -616,16 +626,24 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
// Clear events
|
||||
r.events_read.reset();
|
||||
r.events_write.reset();
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_read().write_value(0);
|
||||
r.events_write().write_value(0);
|
||||
r.events_stopped().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.stopped().set().error().set().read().set());
|
||||
r.intenset().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
w.set_read(true);
|
||||
});
|
||||
} else {
|
||||
r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear());
|
||||
r.intenclr().write(|w| {
|
||||
w.set_stopped(true);
|
||||
w.set_error(true);
|
||||
w.set_read(true);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -745,10 +763,10 @@ impl<'a, T: Instance> Drop for Twis<'a, T> {
|
||||
|
||||
// disable!
|
||||
let r = T::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
|
||||
gpio::deconfigure_pin(r.psel.sda.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.scl.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().sda().read());
|
||||
gpio::deconfigure_pin(r.psel().scl().read());
|
||||
|
||||
trace!("twis drop: done");
|
||||
}
|
||||
@ -767,7 +785,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::twis0::RegisterBlock;
|
||||
fn regs() -> pac::twis::Twis;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
@ -781,8 +799,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
|
||||
macro_rules! impl_twis {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::twis::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::twis0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::twis::Twis {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::twis::State {
|
||||
static STATE: crate::twis::State = crate::twis::State::new();
|
||||
|
@ -21,13 +21,14 @@ use core::task::Poll;
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::uarte0::RegisterBlock;
|
||||
// Re-export SVD variants to allow user to directly set values.
|
||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||
pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _};
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::gpio::vals as gpiovals;
|
||||
use crate::pac::uarte::vals;
|
||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::util::slice_in_ram_or;
|
||||
@ -54,7 +55,7 @@ impl Default for Config {
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Error source flags
|
||||
pub struct ErrorSource: u32 {
|
||||
pub(crate) struct ErrorSource: u32 {
|
||||
/// Buffer overrun
|
||||
const OVERRUN = 0x01;
|
||||
/// Parity error
|
||||
@ -112,20 +113,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
let endrx = r.events_endrx.read().bits();
|
||||
let error = r.events_error.read().bits();
|
||||
let endrx = r.events_endrx().read();
|
||||
let error = r.events_error().read();
|
||||
if endrx != 0 || error != 0 {
|
||||
s.rx_waker.wake();
|
||||
if endrx != 0 {
|
||||
r.intenclr.write(|w| w.endrx().clear());
|
||||
r.intenclr().write(|w| w.set_endrx(true));
|
||||
}
|
||||
if error != 0 {
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
r.intenclr().write(|w| w.set_error(true));
|
||||
}
|
||||
}
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
if r.events_endtx().read() != 0 {
|
||||
s.tx_waker.wake();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
r.intenclr().write(|w| w.set_endtx(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -200,28 +201,12 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
_ => panic!("RTS and CTS pins must be either both set or none set."),
|
||||
};
|
||||
configure(r, config, hardware_flow_control);
|
||||
|
||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
}
|
||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
configure_rx_pins(r, rxd, rts);
|
||||
configure_tx_pins(r, txd, cts);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let s = T::state();
|
||||
s.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||
@ -264,7 +249,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
/// Return the endtx event for use with PPI
|
||||
pub fn event_endtx(&self) -> Event {
|
||||
let r = T::regs();
|
||||
Event::from_reg(&r.events_endtx)
|
||||
Event::from_reg(r.events_endtx())
|
||||
}
|
||||
|
||||
/// Read bytes until the buffer is filled.
|
||||
@ -298,27 +283,72 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) {
|
||||
r.config.write(|w| {
|
||||
w.hwfc().bit(hardware_flow_control);
|
||||
w.parity().variant(config.parity);
|
||||
w
|
||||
pub(crate) fn configure_tx_pins(
|
||||
r: pac::uarte::Uarte,
|
||||
txd: PeripheralRef<'_, AnyPin>,
|
||||
cts: Option<PeripheralRef<'_, AnyPin>>,
|
||||
) {
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_input(gpiovals::Input::DISCONNECT);
|
||||
w.set_drive(gpiovals::Drive::H0H1);
|
||||
});
|
||||
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
||||
r.psel().txd().write_value(txd.psel_bits());
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::INPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(gpiovals::Drive::H0H1);
|
||||
});
|
||||
}
|
||||
r.psel().cts().write_value(cts.psel_bits());
|
||||
}
|
||||
|
||||
pub(crate) fn configure_rx_pins(
|
||||
r: pac::uarte::Uarte,
|
||||
rxd: PeripheralRef<'_, AnyPin>,
|
||||
rts: Option<PeripheralRef<'_, AnyPin>>,
|
||||
) {
|
||||
rxd.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::INPUT);
|
||||
w.set_input(gpiovals::Input::CONNECT);
|
||||
w.set_drive(gpiovals::Drive::H0H1);
|
||||
});
|
||||
r.psel().rxd().write_value(rxd.psel_bits());
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| {
|
||||
w.set_dir(gpiovals::Dir::OUTPUT);
|
||||
w.set_input(gpiovals::Input::DISCONNECT);
|
||||
w.set_drive(gpiovals::Drive::H0H1);
|
||||
});
|
||||
}
|
||||
r.psel().rts().write_value(rts.psel_bits());
|
||||
}
|
||||
|
||||
pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_control: bool) {
|
||||
r.config().write(|w| {
|
||||
w.set_hwfc(hardware_flow_control);
|
||||
w.set_parity(config.parity);
|
||||
});
|
||||
r.baudrate().write(|w| w.set_baudrate(config.baudrate));
|
||||
|
||||
// Disable all interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
|
||||
|
||||
// Reset rxstarted, txstarted. These are used by drop to know whether a transfer was
|
||||
// stopped midway or not.
|
||||
r.events_rxstarted.reset();
|
||||
r.events_txstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
r.events_txstarted().write_value(0);
|
||||
|
||||
// reset all pins
|
||||
r.psel.txd.write(|w| w.connect().disconnected());
|
||||
r.psel.rxd.write(|w| w.connect().disconnected());
|
||||
r.psel.cts.write(|w| w.connect().disconnected());
|
||||
r.psel.rts.write(|w| w.connect().disconnected());
|
||||
r.psel().txd().write_value(DISCONNECTED);
|
||||
r.psel().rxd().write_value(DISCONNECTED);
|
||||
r.psel().cts().write_value(DISCONNECTED);
|
||||
r.psel().rts().write_value(DISCONNECTED);
|
||||
|
||||
apply_workaround_for_enable_anomaly(r);
|
||||
}
|
||||
@ -356,19 +386,11 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
configure(r, config, cts.is_some());
|
||||
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| w.dir().output().drive().s0s1());
|
||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
}
|
||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||
configure_tx_pins(r, txd, cts);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let s = T::state();
|
||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
@ -410,29 +432,29 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
let drop = OnDrop::new(move || {
|
||||
trace!("write drop: stopping");
|
||||
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
r.events_txstopped.reset();
|
||||
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
|
||||
r.intenclr().write(|w| w.set_endtx(true));
|
||||
r.events_txstopped().write_value(0);
|
||||
r.tasks_stoptx().write_value(1);
|
||||
|
||||
// TX is stopped almost instantly, spinning is fine.
|
||||
while r.events_endtx.read().bits() == 0 {}
|
||||
while r.events_endtx().read() == 0 {}
|
||||
trace!("write drop: stopped");
|
||||
});
|
||||
|
||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.txd().ptr().write_value(ptr as u32);
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endtx.reset();
|
||||
r.intenset.write(|w| w.endtx().set());
|
||||
r.events_endtx().write_value(0);
|
||||
r.intenset().write(|w| w.set_endtx(true));
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
trace!("starttx");
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
|
||||
poll_fn(|cx| {
|
||||
s.tx_waker.register(cx.waker());
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
if r.events_endtx().read() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -440,7 +462,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
.await;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
r.events_txstarted.reset();
|
||||
r.events_txstarted().write_value(0);
|
||||
drop.defuse();
|
||||
|
||||
Ok(())
|
||||
@ -476,21 +498,21 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.txd().ptr().write_value(ptr as u32);
|
||||
r.txd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endtx.reset();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
r.events_endtx().write_value(0);
|
||||
r.intenclr().write(|w| w.set_endtx(true));
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
trace!("starttx");
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_starttx().write_value(1);
|
||||
|
||||
while r.events_endtx.read().bits() == 0 {}
|
||||
while r.events_endtx().read() == 0 {}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
r.events_txstarted.reset();
|
||||
r.events_txstarted().write_value(0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -502,11 +524,11 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
let did_stoptx = r.events_txstarted.read().bits() != 0;
|
||||
let did_stoptx = r.events_txstarted().read() != 0;
|
||||
trace!("did_stoptx {}", did_stoptx);
|
||||
|
||||
// Wait for txstopped, if needed.
|
||||
while did_stoptx && r.events_txstopped.read().bits() == 0 {}
|
||||
while did_stoptx && r.events_txstopped().read() == 0 {}
|
||||
|
||||
let s = T::state();
|
||||
|
||||
@ -541,9 +563,9 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
/// Check for errors and clear the error register if an error occured.
|
||||
fn check_and_clear_errors(&mut self) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
let err_bits = r.errorsrc.read().bits();
|
||||
r.errorsrc.write(|w| unsafe { w.bits(err_bits) });
|
||||
ErrorSource::from_bits_truncate(err_bits).check()
|
||||
let err_bits = r.errorsrc().read();
|
||||
r.errorsrc().write_value(err_bits);
|
||||
ErrorSource::from_bits_truncate(err_bits.0).check()
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
@ -555,19 +577,11 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
let r = T::regs();
|
||||
|
||||
configure(r, config, rts.is_some());
|
||||
|
||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
configure_rx_pins(r, rxd, rts);
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
|
||||
let s = T::state();
|
||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
@ -594,8 +608,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
// We want to stop RX if line is idle for 2 bytes worth of time
|
||||
// That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
|
||||
// This gives us the amount of 16M ticks for 20 bits.
|
||||
let baudrate = r.baudrate.read().baudrate().variant().unwrap();
|
||||
let timeout = 0x8000_0000 / (baudrate as u32 / 40);
|
||||
let baudrate = r.baudrate().read().baudrate();
|
||||
let timeout = 0x8000_0000 / (baudrate.to_bits() / 40);
|
||||
|
||||
timer.set_frequency(Frequency::F16MHz);
|
||||
timer.cc(0).write(timeout);
|
||||
@ -604,7 +618,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
|
||||
let mut ppi_ch1 = Ppi::new_one_to_two(
|
||||
ppi_ch1.map_into(),
|
||||
Event::from_reg(&r.events_rxdrdy),
|
||||
Event::from_reg(r.events_rxdrdy()),
|
||||
timer.task_clear(),
|
||||
timer.task_start(),
|
||||
);
|
||||
@ -613,7 +627,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
let mut ppi_ch2 = Ppi::new_one_to_one(
|
||||
ppi_ch2.map_into(),
|
||||
timer.cc(0).event_compare(),
|
||||
Task::from_reg(&r.tasks_stoprx),
|
||||
Task::from_reg(r.tasks_stoprx()),
|
||||
);
|
||||
ppi_ch2.enable();
|
||||
|
||||
@ -643,43 +657,42 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
let drop = OnDrop::new(move || {
|
||||
trace!("read drop: stopping");
|
||||
|
||||
r.intenclr.write(|w| {
|
||||
w.endrx().clear();
|
||||
w.error().clear()
|
||||
r.intenclr().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
r.events_rxto.reset();
|
||||
r.events_error.reset();
|
||||
r.errorsrc.reset();
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
r.events_rxto().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stoprx().write_value(1);
|
||||
|
||||
while r.events_endrx.read().bits() == 0 {}
|
||||
while r.events_endrx().read() == 0 {}
|
||||
|
||||
trace!("read drop: stopped");
|
||||
});
|
||||
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.rxd().ptr().write_value(ptr as u32);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endrx.reset();
|
||||
r.events_error.reset();
|
||||
r.intenset.write(|w| {
|
||||
w.endrx().set();
|
||||
w.error().set()
|
||||
r.events_endrx().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.intenset().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
trace!("startrx");
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
|
||||
let result = poll_fn(|cx| {
|
||||
s.rx_waker.register(cx.waker());
|
||||
|
||||
if let Err(e) = self.check_and_clear_errors() {
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stoprx().write_value(1);
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
if r.events_endrx().read() != 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
Poll::Pending
|
||||
@ -687,7 +700,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
.await;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
r.events_rxstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
drop.defuse();
|
||||
|
||||
result
|
||||
@ -707,25 +720,25 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.rxd().ptr().write_value(ptr as u32);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endrx.reset();
|
||||
r.events_error.reset();
|
||||
r.intenclr.write(|w| {
|
||||
w.endrx().clear();
|
||||
w.error().clear()
|
||||
r.events_endrx().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.intenclr().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
trace!("startrx");
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
|
||||
while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
|
||||
while r.events_endrx().read() == 0 && r.events_error().read() == 0 {}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
r.events_rxstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
|
||||
self.check_and_clear_errors()
|
||||
}
|
||||
@ -737,11 +750,11 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
let did_stoprx = r.events_rxstarted.read().bits() != 0;
|
||||
let did_stoprx = r.events_rxstarted().read() != 0;
|
||||
trace!("did_stoprx {}", did_stoprx);
|
||||
|
||||
// Wait for rxto, if needed.
|
||||
while did_stoprx && r.events_rxto.read().bits() == 0 {}
|
||||
while did_stoprx && r.events_rxto().read() == 0 {}
|
||||
|
||||
let s = T::state();
|
||||
|
||||
@ -794,39 +807,39 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
|
||||
let drop = OnDrop::new(|| {
|
||||
self.timer.stop();
|
||||
|
||||
r.intenclr.write(|w| {
|
||||
w.endrx().clear();
|
||||
w.error().clear()
|
||||
r.intenclr().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
r.events_rxto.reset();
|
||||
r.events_error.reset();
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
r.events_rxto().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.tasks_stoprx().write_value(1);
|
||||
|
||||
while r.events_endrx.read().bits() == 0 {}
|
||||
while r.events_endrx().read() == 0 {}
|
||||
});
|
||||
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.rxd().ptr().write_value(ptr as u32);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endrx.reset();
|
||||
r.events_error.reset();
|
||||
r.intenset.write(|w| {
|
||||
w.endrx().set();
|
||||
w.error().set()
|
||||
r.events_endrx().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.intenset().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
|
||||
let result = poll_fn(|cx| {
|
||||
s.rx_waker.register(cx.waker());
|
||||
|
||||
if let Err(e) = self.rx.check_and_clear_errors() {
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stoprx().write_value(1);
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
if r.events_endrx().read() != 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
|
||||
@ -835,10 +848,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
|
||||
.await;
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let n = r.rxd.amount.read().amount().bits() as usize;
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
|
||||
self.timer.stop();
|
||||
r.events_rxstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
|
||||
drop.defuse();
|
||||
|
||||
@ -863,56 +876,57 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
|
||||
|
||||
self.ppi_ch1.enable();
|
||||
|
||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||
r.rxd().ptr().write_value(ptr as u32);
|
||||
r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _));
|
||||
|
||||
r.events_endrx.reset();
|
||||
r.events_error.reset();
|
||||
r.intenclr.write(|w| {
|
||||
w.endrx().clear();
|
||||
w.error().clear()
|
||||
r.events_endrx().write_value(0);
|
||||
r.events_error().write_value(0);
|
||||
r.intenclr().write(|w| {
|
||||
w.set_endrx(true);
|
||||
w.set_error(true);
|
||||
});
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_startrx().write_value(1);
|
||||
|
||||
while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
|
||||
while r.events_endrx().read() == 0 && r.events_error().read() == 0 {}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let n = r.rxd.amount.read().amount().bits() as usize;
|
||||
let n = r.rxd().amount().read().0 as usize;
|
||||
|
||||
self.timer.stop();
|
||||
r.events_rxstarted.reset();
|
||||
r.events_rxstarted().write_value(0);
|
||||
|
||||
self.rx.check_and_clear_errors().map(|_| n)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))]
|
||||
pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) {
|
||||
pub(crate) fn apply_workaround_for_enable_anomaly(_r: pac::uarte::Uarte) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))]
|
||||
pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) {
|
||||
pub(crate) fn apply_workaround_for_enable_anomaly(r: pac::uarte::Uarte) {
|
||||
// Apply workaround for anomalies:
|
||||
// - nRF9160 - anomaly 23
|
||||
// - nRF5340 - anomaly 44
|
||||
let rxenable_reg: *const u32 = ((r as *const _ as usize) + 0x564) as *const u32;
|
||||
let txenable_reg: *const u32 = ((r as *const _ as usize) + 0x568) as *const u32;
|
||||
let rp = r.as_ptr() as *mut u32;
|
||||
let rxenable_reg = unsafe { rp.add(0x564 / 4) };
|
||||
let txenable_reg = unsafe { rp.add(0x568 / 4) };
|
||||
|
||||
// NB Safety: This is taken from Nordic's driver -
|
||||
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
|
||||
if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 {
|
||||
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
|
||||
r.tasks_stoptx().write_value(1);
|
||||
}
|
||||
|
||||
// NB Safety: This is taken from Nordic's driver -
|
||||
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
|
||||
if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 {
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
|
||||
r.tasks_stoprx().write_value(1);
|
||||
|
||||
let mut workaround_succeded = false;
|
||||
// The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
|
||||
@ -933,23 +947,23 @@ pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Regist
|
||||
panic!("Failed to apply workaround for UART");
|
||||
}
|
||||
|
||||
let errors = r.errorsrc.read().bits();
|
||||
// NB Safety: safe to write back the bits we just read to clear them
|
||||
r.errorsrc.write(|w| unsafe { w.bits(errors) });
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
// write back the bits we just read to clear them
|
||||
let errors = r.errorsrc().read();
|
||||
r.errorsrc().write_value(errors);
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &State) {
|
||||
pub(crate) fn drop_tx_rx(r: pac::uarte::Uarte, s: &State) {
|
||||
if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
|
||||
// Finally we can disable, and we do so for the peripheral
|
||||
// i.e. not just rx concerns.
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
|
||||
|
||||
gpio::deconfigure_pin(r.psel.rxd.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.txd.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.rts.read().bits());
|
||||
gpio::deconfigure_pin(r.psel.cts.read().bits());
|
||||
gpio::deconfigure_pin(r.psel().rxd().read());
|
||||
gpio::deconfigure_pin(r.psel().txd().read());
|
||||
gpio::deconfigure_pin(r.psel().rts().read());
|
||||
gpio::deconfigure_pin(r.psel().cts().read());
|
||||
|
||||
trace!("uarte tx and rx drop: done");
|
||||
}
|
||||
@ -971,7 +985,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::uarte0::RegisterBlock;
|
||||
fn regs() -> pac::uarte::Uarte;
|
||||
fn state() -> &'static State;
|
||||
fn buffered_state() -> &'static crate::buffered_uarte::State;
|
||||
}
|
||||
@ -986,8 +1000,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_uarte {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::uarte::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::uarte0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::uarte::Uarte {
|
||||
pac::$pac_type
|
||||
}
|
||||
fn state() -> &'static crate::uarte::State {
|
||||
static STATE: crate::uarte::State = crate::uarte::State::new();
|
||||
|
@ -15,10 +15,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_usb_driver as driver;
|
||||
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
||||
use pac::usbd::RegisterBlock;
|
||||
|
||||
use self::vbus_detect::VbusDetect;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::usbd::vals;
|
||||
use crate::util::slice_in_ram;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
@ -38,19 +38,19 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = T::regs();
|
||||
|
||||
if regs.events_usbreset.read().bits() != 0 {
|
||||
regs.intenclr.write(|w| w.usbreset().clear());
|
||||
if regs.events_usbreset().read() != 0 {
|
||||
regs.intenclr().write(|w| w.set_usbreset(true));
|
||||
BUS_WAKER.wake();
|
||||
EP0_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_ep0setup.read().bits() != 0 {
|
||||
regs.intenclr.write(|w| w.ep0setup().clear());
|
||||
if regs.events_ep0setup().read() != 0 {
|
||||
regs.intenclr().write(|w| w.set_ep0setup(true));
|
||||
EP0_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_ep0datadone.read().bits() != 0 {
|
||||
regs.intenclr.write(|w| w.ep0datadone().clear());
|
||||
if regs.events_ep0datadone().read() != 0 {
|
||||
regs.intenclr().write(|w| w.set_ep0datadone(true));
|
||||
EP0_WAKER.wake();
|
||||
}
|
||||
|
||||
@ -63,22 +63,22 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
// Therefore, it's fine to clear just the event, and let main thread
|
||||
// check the individual bits in EVENTCAUSE and EPDATASTATUS. It
|
||||
// doesn't cause an infinite irq loop.
|
||||
if regs.events_usbevent.read().bits() != 0 {
|
||||
regs.events_usbevent.reset();
|
||||
if regs.events_usbevent().read() != 0 {
|
||||
regs.events_usbevent().write_value(0);
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_epdata.read().bits() != 0 {
|
||||
regs.events_epdata.reset();
|
||||
if regs.events_epdata().read() != 0 {
|
||||
regs.events_epdata().write_value(0);
|
||||
|
||||
let r = regs.epdatastatus.read().bits();
|
||||
regs.epdatastatus.write(|w| unsafe { w.bits(r) });
|
||||
READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel);
|
||||
let r = regs.epdatastatus().read();
|
||||
regs.epdatastatus().write_value(r);
|
||||
READY_ENDPOINTS.fetch_or(r.0, Ordering::AcqRel);
|
||||
for i in 1..=7 {
|
||||
if r & In::mask(i) != 0 {
|
||||
if r.0 & In::mask(i) != 0 {
|
||||
In::waker(i).wake();
|
||||
}
|
||||
if r & Out::mask(i) != 0 {
|
||||
if r.0 & Out::mask(i) != 0 {
|
||||
Out::waker(i).wake();
|
||||
}
|
||||
}
|
||||
@ -181,35 +181,34 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
|
||||
errata::pre_enable();
|
||||
|
||||
regs.enable.write(|w| w.enable().enabled());
|
||||
regs.enable().write(|w| w.set_enable(true));
|
||||
|
||||
// Wait until the peripheral is ready.
|
||||
regs.intenset.write(|w| w.usbevent().set_bit());
|
||||
regs.intenset().write(|w| w.set_usbevent(true));
|
||||
poll_fn(|cx| {
|
||||
BUS_WAKER.register(cx.waker());
|
||||
if regs.eventcause.read().ready().is_ready() {
|
||||
if regs.eventcause().read().ready() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
regs.eventcause.write(|w| w.ready().clear_bit_by_one());
|
||||
regs.eventcause().write(|w| w.set_ready(true));
|
||||
|
||||
errata::post_enable();
|
||||
|
||||
unsafe { NVIC::unmask(pac::Interrupt::USBD) };
|
||||
|
||||
regs.intenset.write(|w| {
|
||||
w.usbreset().set_bit();
|
||||
w.usbevent().set_bit();
|
||||
w.epdata().set_bit();
|
||||
w
|
||||
regs.intenset().write(|w| {
|
||||
w.set_usbreset(true);
|
||||
w.set_usbevent(true);
|
||||
w.set_epdata(true);
|
||||
});
|
||||
|
||||
if self.vbus_detect.wait_power_ready().await.is_ok() {
|
||||
// Enable the USB pullup, allowing enumeration.
|
||||
regs.usbpullup.write(|w| w.connect().enabled());
|
||||
regs.usbpullup().write(|w| w.set_connect(true));
|
||||
trace!("enabled");
|
||||
} else {
|
||||
trace!("usb power not ready due to usb removal");
|
||||
@ -218,7 +217,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
|
||||
async fn disable(&mut self) {
|
||||
let regs = T::regs();
|
||||
regs.enable.write(|x| x.enable().disabled());
|
||||
regs.enable().write(|x| x.set_enable(false));
|
||||
}
|
||||
|
||||
async fn poll(&mut self) -> Event {
|
||||
@ -226,13 +225,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
BUS_WAKER.register(cx.waker());
|
||||
let regs = T::regs();
|
||||
|
||||
if regs.events_usbreset.read().bits() != 0 {
|
||||
regs.events_usbreset.reset();
|
||||
regs.intenset.write(|w| w.usbreset().set());
|
||||
if regs.events_usbreset().read() != 0 {
|
||||
regs.events_usbreset().write_value(0);
|
||||
regs.intenset().write(|w| w.set_usbreset(true));
|
||||
|
||||
// Disable all endpoints except EP0
|
||||
regs.epinen.write(|w| unsafe { w.bits(0x01) });
|
||||
regs.epouten.write(|w| unsafe { w.bits(0x01) });
|
||||
regs.epinen().write(|w| w.0 = 0x01);
|
||||
regs.epouten().write(|w| w.0 = 0x01);
|
||||
READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
|
||||
for i in 1..=7 {
|
||||
In::waker(i).wake();
|
||||
@ -242,27 +241,27 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
return Poll::Ready(Event::Reset);
|
||||
}
|
||||
|
||||
let r = regs.eventcause.read();
|
||||
let r = regs.eventcause().read();
|
||||
|
||||
if r.isooutcrc().bit() {
|
||||
regs.eventcause.write(|w| w.isooutcrc().detected());
|
||||
if r.isooutcrc() {
|
||||
regs.eventcause().write(|w| w.set_isooutcrc(true));
|
||||
trace!("USB event: isooutcrc");
|
||||
}
|
||||
if r.usbwuallowed().bit() {
|
||||
regs.eventcause.write(|w| w.usbwuallowed().allowed());
|
||||
if r.usbwuallowed() {
|
||||
regs.eventcause().write(|w| w.set_usbwuallowed(true));
|
||||
trace!("USB event: usbwuallowed");
|
||||
}
|
||||
if r.suspend().bit() {
|
||||
regs.eventcause.write(|w| w.suspend().detected());
|
||||
regs.lowpower.write(|w| w.lowpower().low_power());
|
||||
if r.suspend() {
|
||||
regs.eventcause().write(|w| w.set_suspend(true));
|
||||
regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::LOW_POWER));
|
||||
return Poll::Ready(Event::Suspend);
|
||||
}
|
||||
if r.resume().bit() {
|
||||
regs.eventcause.write(|w| w.resume().detected());
|
||||
if r.resume() {
|
||||
regs.eventcause().write(|w| w.set_resume(true));
|
||||
return Poll::Ready(Event::Resume);
|
||||
}
|
||||
if r.ready().bit() {
|
||||
regs.eventcause.write(|w| w.ready().ready());
|
||||
if r.ready() {
|
||||
regs.eventcause().write(|w| w.set_ready(true));
|
||||
trace!("USB event: ready");
|
||||
}
|
||||
|
||||
@ -284,16 +283,19 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
|
||||
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
|
||||
let regs = T::regs();
|
||||
unsafe {
|
||||
if ep_addr.index() == 0 {
|
||||
regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(stalled));
|
||||
} else {
|
||||
regs.epstall.write(|w| {
|
||||
w.ep().bits(ep_addr.index() as u8 & 0b111);
|
||||
w.io().bit(ep_addr.is_in());
|
||||
w.stall().bit(stalled)
|
||||
});
|
||||
if ep_addr.index() == 0 {
|
||||
if stalled {
|
||||
regs.tasks_ep0stall().write_value(1);
|
||||
}
|
||||
} else {
|
||||
regs.epstall().write(|w| {
|
||||
w.set_ep(ep_addr.index() as u8 & 0b111);
|
||||
w.set_io(match ep_addr.direction() {
|
||||
Direction::In => vals::Io::IN,
|
||||
Direction::Out => vals::Io::OUT,
|
||||
});
|
||||
w.set_stall(stalled);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,8 +303,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
let regs = T::regs();
|
||||
let i = ep_addr.index();
|
||||
match ep_addr.direction() {
|
||||
Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(),
|
||||
Direction::In => regs.halted.epin[i].read().getstatus().is_halted(),
|
||||
Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED,
|
||||
Direction::In => regs.halted().epin(i).read().getstatus() == vals::Getstatus::HALTED,
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,15 +319,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
match ep_addr.direction() {
|
||||
Direction::In => {
|
||||
let mut was_enabled = false;
|
||||
regs.epinen.modify(|r, w| {
|
||||
let mut bits = r.bits();
|
||||
was_enabled = (bits & mask) != 0;
|
||||
regs.epinen().modify(|w| {
|
||||
was_enabled = (w.0 & mask) != 0;
|
||||
if enabled {
|
||||
bits |= mask
|
||||
w.0 |= mask
|
||||
} else {
|
||||
bits &= !mask
|
||||
w.0 &= !mask
|
||||
}
|
||||
unsafe { w.bits(bits) }
|
||||
});
|
||||
|
||||
let ready_mask = In::mask(i);
|
||||
@ -340,15 +340,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
In::waker(i).wake();
|
||||
}
|
||||
Direction::Out => {
|
||||
regs.epouten.modify(|r, w| {
|
||||
let mut bits = r.bits();
|
||||
if enabled {
|
||||
bits |= mask
|
||||
} else {
|
||||
bits &= !mask
|
||||
}
|
||||
unsafe { w.bits(bits) }
|
||||
});
|
||||
regs.epouten()
|
||||
.modify(|w| if enabled { w.0 |= mask } else { w.0 &= !mask });
|
||||
|
||||
let ready_mask = Out::mask(i);
|
||||
if enabled {
|
||||
@ -356,7 +349,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
// peripheral will NAK all incoming packets) until we write a zero to the SIZE
|
||||
// register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the
|
||||
// SIZE register
|
||||
regs.size.epout[i].reset();
|
||||
regs.size().epout(i).write(|_| ());
|
||||
} else {
|
||||
READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
|
||||
}
|
||||
@ -370,25 +363,24 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
|
||||
let regs = T::regs();
|
||||
|
||||
if regs.lowpower.read().lowpower().is_low_power() {
|
||||
if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER {
|
||||
errata::pre_wakeup();
|
||||
|
||||
regs.lowpower.write(|w| w.lowpower().force_normal());
|
||||
regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::FORCE_NORMAL));
|
||||
|
||||
poll_fn(|cx| {
|
||||
BUS_WAKER.register(cx.waker());
|
||||
let regs = T::regs();
|
||||
let r = regs.eventcause.read();
|
||||
let r = regs.eventcause().read();
|
||||
|
||||
if regs.events_usbreset.read().bits() != 0 {
|
||||
if regs.events_usbreset().read() != 0 {
|
||||
Poll::Ready(())
|
||||
} else if r.resume().bit() {
|
||||
} else if r.resume() {
|
||||
Poll::Ready(())
|
||||
} else if r.usbwuallowed().bit() {
|
||||
regs.eventcause.write(|w| w.usbwuallowed().allowed());
|
||||
|
||||
regs.dpdmvalue.write(|w| w.state().resume());
|
||||
regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit());
|
||||
} else if r.usbwuallowed() {
|
||||
regs.eventcause().write(|w| w.set_usbwuallowed(true));
|
||||
regs.dpdmvalue().write(|w| w.set_state(vals::State::RESUME));
|
||||
regs.tasks_dpdmdrive().write_value(1);
|
||||
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
@ -413,7 +405,7 @@ pub enum In {}
|
||||
trait EndpointDir {
|
||||
fn waker(i: usize) -> &'static AtomicWaker;
|
||||
fn mask(i: usize) -> u32;
|
||||
fn is_enabled(regs: &RegisterBlock, i: usize) -> bool;
|
||||
fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool;
|
||||
}
|
||||
|
||||
impl EndpointDir for In {
|
||||
@ -428,8 +420,8 @@ impl EndpointDir for In {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_enabled(regs: &RegisterBlock, i: usize) -> bool {
|
||||
(regs.epinen.read().bits() & (1 << i)) != 0
|
||||
fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool {
|
||||
regs.epinen().read().in_(i)
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,8 +437,8 @@ impl EndpointDir for Out {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_enabled(regs: &RegisterBlock, i: usize) -> bool {
|
||||
(regs.epouten.read().bits() & (1 << i)) != 0
|
||||
fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool {
|
||||
regs.epouten().read().out(i)
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,33 +521,23 @@ unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, Endpo
|
||||
let regs = T::regs();
|
||||
|
||||
// Check that the packet fits into the buffer
|
||||
let size = regs.size.epout[i].read().bits() as usize;
|
||||
let size = regs.size().epout(i).read().0 as usize;
|
||||
if size > buf.len() {
|
||||
return Err(EndpointError::BufferOverflow);
|
||||
}
|
||||
|
||||
let epout = [
|
||||
®s.epout0,
|
||||
®s.epout1,
|
||||
®s.epout2,
|
||||
®s.epout3,
|
||||
®s.epout4,
|
||||
®s.epout5,
|
||||
®s.epout6,
|
||||
®s.epout7,
|
||||
];
|
||||
epout[i].ptr.write(|w| w.bits(buf.as_ptr() as u32));
|
||||
regs.epout(i).ptr().write_value(buf.as_ptr() as u32);
|
||||
// MAXCNT must match SIZE
|
||||
epout[i].maxcnt.write(|w| w.bits(size as u32));
|
||||
regs.epout(i).maxcnt().write(|w| w.set_maxcnt(size as _));
|
||||
|
||||
dma_start();
|
||||
regs.events_endepout[i].reset();
|
||||
regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit());
|
||||
while regs.events_endepout[i].read().events_endepout().bit_is_clear() {}
|
||||
regs.events_endepout[i].reset();
|
||||
regs.events_endepout(i).write_value(0);
|
||||
regs.tasks_startepout(i).write_value(1);
|
||||
while regs.events_endepout(i).read() == 0 {}
|
||||
regs.events_endepout(i).write_value(0);
|
||||
dma_end();
|
||||
|
||||
regs.size.epout[i].reset();
|
||||
regs.size().epout(i).write(|_| ());
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
@ -574,27 +556,16 @@ unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) {
|
||||
buf.as_ptr()
|
||||
};
|
||||
|
||||
let epin = [
|
||||
®s.epin0,
|
||||
®s.epin1,
|
||||
®s.epin2,
|
||||
®s.epin3,
|
||||
®s.epin4,
|
||||
®s.epin5,
|
||||
®s.epin6,
|
||||
®s.epin7,
|
||||
];
|
||||
|
||||
// Set the buffer length so the right number of bytes are transmitted.
|
||||
// Safety: `buf.len()` has been checked to be <= the max buffer length.
|
||||
epin[i].ptr.write(|w| w.bits(ptr as u32));
|
||||
epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8));
|
||||
regs.epin(i).ptr().write_value(ptr as u32);
|
||||
regs.epin(i).maxcnt().write(|w| w.set_maxcnt(buf.len() as u8));
|
||||
|
||||
regs.events_endepin[i].reset();
|
||||
regs.events_endepin(i).write_value(0);
|
||||
|
||||
dma_start();
|
||||
regs.tasks_startepin[i].write(|w| w.bits(1));
|
||||
while regs.events_endepin[i].read().bits() == 0 {}
|
||||
regs.tasks_startepin(i).write_value(1);
|
||||
while regs.events_endepin(i).read() == 0 {}
|
||||
dma_end();
|
||||
}
|
||||
|
||||
@ -637,14 +608,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
let regs = T::regs();
|
||||
|
||||
// Reset shorts
|
||||
regs.shorts.write(|w| w);
|
||||
regs.shorts().write(|_| ());
|
||||
|
||||
// Wait for SETUP packet
|
||||
regs.intenset.write(|w| w.ep0setup().set());
|
||||
regs.intenset().write(|w| w.set_ep0setup(true));
|
||||
poll_fn(|cx| {
|
||||
EP0_WAKER.register(cx.waker());
|
||||
let regs = T::regs();
|
||||
if regs.events_ep0setup.read().bits() != 0 {
|
||||
if regs.events_ep0setup().read() != 0 {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
@ -652,17 +623,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
})
|
||||
.await;
|
||||
|
||||
regs.events_ep0setup.reset();
|
||||
regs.events_ep0setup().write_value(0);
|
||||
|
||||
let mut buf = [0; 8];
|
||||
buf[0] = regs.bmrequesttype.read().bits() as u8;
|
||||
buf[1] = regs.brequest.read().brequest().bits();
|
||||
buf[2] = regs.wvaluel.read().wvaluel().bits();
|
||||
buf[3] = regs.wvalueh.read().wvalueh().bits();
|
||||
buf[4] = regs.windexl.read().windexl().bits();
|
||||
buf[5] = regs.windexh.read().windexh().bits();
|
||||
buf[6] = regs.wlengthl.read().wlengthl().bits();
|
||||
buf[7] = regs.wlengthh.read().wlengthh().bits();
|
||||
buf[0] = regs.bmrequesttype().read().0 as u8;
|
||||
buf[1] = regs.brequest().read().0 as u8;
|
||||
buf[2] = regs.wvaluel().read().0 as u8;
|
||||
buf[3] = regs.wvalueh().read().0 as u8;
|
||||
buf[4] = regs.windexl().read().0 as u8;
|
||||
buf[5] = regs.windexh().read().0 as u8;
|
||||
buf[6] = regs.wlengthl().read().0 as u8;
|
||||
buf[7] = regs.wlengthh().read().0 as u8;
|
||||
|
||||
buf
|
||||
}
|
||||
@ -670,26 +641,26 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
|
||||
let regs = T::regs();
|
||||
|
||||
regs.events_ep0datadone.reset();
|
||||
regs.events_ep0datadone().write_value(0);
|
||||
|
||||
// This starts a RX on EP0. events_ep0datadone notifies when done.
|
||||
regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit());
|
||||
regs.tasks_ep0rcvout().write_value(1);
|
||||
|
||||
// Wait until ready
|
||||
regs.intenset.write(|w| {
|
||||
w.usbreset().set();
|
||||
w.ep0setup().set();
|
||||
w.ep0datadone().set()
|
||||
regs.intenset().write(|w| {
|
||||
w.set_usbreset(true);
|
||||
w.set_ep0setup(true);
|
||||
w.set_ep0datadone(true);
|
||||
});
|
||||
poll_fn(|cx| {
|
||||
EP0_WAKER.register(cx.waker());
|
||||
let regs = T::regs();
|
||||
if regs.events_ep0datadone.read().bits() != 0 {
|
||||
if regs.events_ep0datadone().read() != 0 {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if regs.events_usbreset.read().bits() != 0 {
|
||||
} else if regs.events_usbreset().read() != 0 {
|
||||
trace!("aborted control data_out: usb reset");
|
||||
Poll::Ready(Err(EndpointError::Disabled))
|
||||
} else if regs.events_ep0setup.read().bits() != 0 {
|
||||
} else if regs.events_ep0setup().read() != 0 {
|
||||
trace!("aborted control data_out: received another SETUP");
|
||||
Poll::Ready(Err(EndpointError::Disabled))
|
||||
} else {
|
||||
@ -703,29 +674,29 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
|
||||
async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
|
||||
let regs = T::regs();
|
||||
regs.events_ep0datadone.reset();
|
||||
regs.events_ep0datadone().write_value(0);
|
||||
|
||||
regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last));
|
||||
regs.shorts().write(|w| w.set_ep0datadone_ep0status(last));
|
||||
|
||||
// This starts a TX on EP0. events_ep0datadone notifies when done.
|
||||
unsafe { write_dma::<T>(0, buf) }
|
||||
|
||||
regs.intenset.write(|w| {
|
||||
w.usbreset().set();
|
||||
w.ep0setup().set();
|
||||
w.ep0datadone().set()
|
||||
regs.intenset().write(|w| {
|
||||
w.set_usbreset(true);
|
||||
w.set_ep0setup(true);
|
||||
w.set_ep0datadone(true);
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
cx.waker().wake_by_ref();
|
||||
EP0_WAKER.register(cx.waker());
|
||||
let regs = T::regs();
|
||||
if regs.events_ep0datadone.read().bits() != 0 {
|
||||
if regs.events_ep0datadone().read() != 0 {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if regs.events_usbreset.read().bits() != 0 {
|
||||
} else if regs.events_usbreset().read() != 0 {
|
||||
trace!("aborted control data_in: usb reset");
|
||||
Poll::Ready(Err(EndpointError::Disabled))
|
||||
} else if regs.events_ep0setup.read().bits() != 0 {
|
||||
} else if regs.events_ep0setup().read() != 0 {
|
||||
trace!("aborted control data_in: received another SETUP");
|
||||
Poll::Ready(Err(EndpointError::Disabled))
|
||||
} else {
|
||||
@ -737,12 +708,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
|
||||
async fn accept(&mut self) {
|
||||
let regs = T::regs();
|
||||
regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true));
|
||||
regs.tasks_ep0status().write_value(1);
|
||||
}
|
||||
|
||||
async fn reject(&mut self) {
|
||||
let regs = T::regs();
|
||||
regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true));
|
||||
regs.tasks_ep0stall().write_value(1);
|
||||
}
|
||||
|
||||
async fn accept_set_address(&mut self, _addr: u8) {
|
||||
@ -806,7 +777,7 @@ impl Allocator {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> &'static pac::usbd::RegisterBlock;
|
||||
fn regs() -> pac::usbd::Usbd;
|
||||
}
|
||||
|
||||
/// USB peripheral instance.
|
||||
@ -819,8 +790,8 @@ pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||
macro_rules! impl_usb {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::usb::SealedInstance for peripherals::$type {
|
||||
fn regs() -> &'static pac::usbd::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
fn regs() -> pac::usbd::Usbd {
|
||||
pac::$pac_type
|
||||
}
|
||||
}
|
||||
impl crate::usb::Instance for peripherals::$type {
|
||||
|
@ -34,9 +34,9 @@ type UsbRegIrq = interrupt::typelevel::POWER_CLOCK;
|
||||
type UsbRegIrq = interrupt::typelevel::USBREGULATOR;
|
||||
|
||||
#[cfg(not(feature = "_nrf5340"))]
|
||||
type UsbRegPeri = pac::POWER;
|
||||
const USB_REG_PERI: pac::power::Power = pac::POWER;
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
type UsbRegPeri = pac::USBREGULATOR;
|
||||
const USB_REG_PERI: pac::usbregulator::Usbregulator = pac::USBREGULATOR;
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
@ -45,21 +45,21 @@ pub struct InterruptHandler {
|
||||
|
||||
impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
let regs = USB_REG_PERI;
|
||||
|
||||
if regs.events_usbdetected.read().bits() != 0 {
|
||||
regs.events_usbdetected.reset();
|
||||
if regs.events_usbdetected().read() != 0 {
|
||||
regs.events_usbdetected().write_value(0);
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbremoved.read().bits() != 0 {
|
||||
regs.events_usbremoved.reset();
|
||||
if regs.events_usbremoved().read() != 0 {
|
||||
regs.events_usbremoved().write_value(0);
|
||||
BUS_WAKER.wake();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbpwrrdy.read().bits() != 0 {
|
||||
regs.events_usbpwrrdy.reset();
|
||||
if regs.events_usbpwrrdy().read() != 0 {
|
||||
regs.events_usbpwrrdy().write_value(0);
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
}
|
||||
@ -78,13 +78,16 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
impl HardwareVbusDetect {
|
||||
/// Create a new `VbusDetectNative`.
|
||||
pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
let regs = USB_REG_PERI;
|
||||
|
||||
UsbRegIrq::unpend();
|
||||
unsafe { UsbRegIrq::enable() };
|
||||
|
||||
regs.intenset
|
||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||
regs.intenset().write(|w| {
|
||||
w.set_usbdetected(true);
|
||||
w.set_usbremoved(true);
|
||||
w.set_usbpwrrdy(true);
|
||||
});
|
||||
|
||||
Self { _private: () }
|
||||
}
|
||||
@ -92,16 +95,16 @@ impl HardwareVbusDetect {
|
||||
|
||||
impl VbusDetect for HardwareVbusDetect {
|
||||
fn is_usb_detected(&self) -> bool {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
||||
let regs = USB_REG_PERI;
|
||||
regs.usbregstatus().read().vbusdetect()
|
||||
}
|
||||
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||
poll_fn(move |cx| {
|
||||
POWER_WAKER.register(cx.waker());
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
let regs = USB_REG_PERI;
|
||||
|
||||
if regs.usbregstatus.read().outputrdy().is_ready() {
|
||||
if regs.usbregstatus().read().outputrdy() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if !self.is_usb_detected() {
|
||||
Poll::Ready(Err(()))
|
||||
|
@ -3,7 +3,8 @@
|
||||
//! This HAL implements a basic watchdog timer with 1..=8 handles.
|
||||
//! Once the watchdog has been started, it cannot be stopped.
|
||||
|
||||
use crate::pac::WDT;
|
||||
use crate::pac::wdt::vals;
|
||||
pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig};
|
||||
use crate::peripherals;
|
||||
|
||||
const MIN_TICKS: u32 = 15;
|
||||
@ -18,29 +19,29 @@ pub struct Config {
|
||||
pub timeout_ticks: u32,
|
||||
|
||||
/// Should the watchdog continue to count during sleep modes?
|
||||
pub run_during_sleep: bool,
|
||||
pub action_during_sleep: SleepConfig,
|
||||
|
||||
/// Should the watchdog continue to count when the CPU is halted for debug?
|
||||
pub run_during_debug_halt: bool,
|
||||
pub action_during_debug_halt: HaltConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Create a config structure from the current configuration of the WDT
|
||||
/// peripheral.
|
||||
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
let r = crate::pac::WDT;
|
||||
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
let runstatus = r.runstatus.read().runstatus().bit();
|
||||
let runstatus = r.runstatus().read().runstatus();
|
||||
#[cfg(feature = "_nrf91")]
|
||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||
let runstatus = r.runstatus().read().runstatuswdt();
|
||||
|
||||
if runstatus {
|
||||
let config = r.config.read();
|
||||
let config = r.config().read();
|
||||
Some(Self {
|
||||
timeout_ticks: r.crv.read().bits(),
|
||||
run_during_sleep: config.sleep().bit(),
|
||||
run_during_debug_halt: config.halt().bit(),
|
||||
timeout_ticks: r.crv().read(),
|
||||
action_during_sleep: config.sleep(),
|
||||
action_during_debug_halt: config.halt(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -52,8 +53,8 @@ impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
timeout_ticks: 32768, // 1 second
|
||||
run_during_debug_halt: true,
|
||||
run_during_sleep: true,
|
||||
action_during_debug_halt: HaltConfig::RUN,
|
||||
action_during_sleep: SleepConfig::RUN,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,36 +79,35 @@ impl Watchdog {
|
||||
) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> {
|
||||
assert!(N >= 1 && N <= 8);
|
||||
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
let r = crate::pac::WDT;
|
||||
|
||||
let crv = config.timeout_ticks.max(MIN_TICKS);
|
||||
let rren = (1u32 << N) - 1;
|
||||
let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1);
|
||||
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
let runstatus = r.runstatus.read().runstatus().bit();
|
||||
let runstatus = r.runstatus().read().runstatus();
|
||||
#[cfg(feature = "_nrf91")]
|
||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||
let runstatus = r.runstatus().read().runstatuswdt();
|
||||
|
||||
if runstatus {
|
||||
let curr_config = r.config.read();
|
||||
if curr_config.halt().bit() != config.run_during_debug_halt
|
||||
|| curr_config.sleep().bit() != config.run_during_sleep
|
||||
|| r.crv.read().bits() != crv
|
||||
|| r.rren.read().bits() != rren
|
||||
let curr_config = r.config().read();
|
||||
if curr_config.halt() != config.action_during_debug_halt
|
||||
|| curr_config.sleep() != config.action_during_sleep
|
||||
|| r.crv().read() != crv
|
||||
|| r.rren().read() != rren
|
||||
{
|
||||
return Err(wdt);
|
||||
}
|
||||
} else {
|
||||
r.config.write(|w| {
|
||||
w.sleep().bit(config.run_during_sleep);
|
||||
w.halt().bit(config.run_during_debug_halt);
|
||||
w
|
||||
r.config().write(|w| {
|
||||
w.set_sleep(config.action_during_sleep);
|
||||
w.set_halt(config.action_during_debug_halt);
|
||||
});
|
||||
r.intenset.write(|w| w.timeout().set_bit());
|
||||
r.intenset().write(|w| w.set_timeout(true));
|
||||
|
||||
r.crv.write(|w| unsafe { w.bits(crv) });
|
||||
r.rren.write(|w| unsafe { w.bits(rren) });
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
r.crv().write_value(crv);
|
||||
r.rren().write_value(rren);
|
||||
r.tasks_start().write_value(1);
|
||||
}
|
||||
|
||||
let this = Self { _private: () };
|
||||
@ -130,8 +130,7 @@ impl Watchdog {
|
||||
/// interrupt has been enabled.
|
||||
#[inline(always)]
|
||||
pub fn enable_interrupt(&mut self) {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
r.intenset.write(|w| w.timeout().set_bit());
|
||||
crate::pac::WDT.intenset().write(|w| w.set_timeout(true));
|
||||
}
|
||||
|
||||
/// Disable the watchdog interrupt.
|
||||
@ -139,8 +138,7 @@ impl Watchdog {
|
||||
/// NOTE: This has no effect on the reset caused by the Watchdog.
|
||||
#[inline(always)]
|
||||
pub fn disable_interrupt(&mut self) {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
r.intenclr.write(|w| w.timeout().set_bit());
|
||||
crate::pac::WDT.intenclr().write(|w| w.set_timeout(true));
|
||||
}
|
||||
|
||||
/// Is the watchdog still awaiting pets from any handle?
|
||||
@ -149,9 +147,9 @@ impl Watchdog {
|
||||
/// handles to prevent a reset this time period.
|
||||
#[inline(always)]
|
||||
pub fn awaiting_pets(&self) -> bool {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
let enabled = r.rren.read().bits();
|
||||
let status = r.reqstatus.read().bits();
|
||||
let r = crate::pac::WDT;
|
||||
let enabled = r.rren().read().0;
|
||||
let status = r.reqstatus().read().0;
|
||||
(status & enabled) == 0
|
||||
}
|
||||
}
|
||||
@ -170,16 +168,14 @@ impl WatchdogHandle {
|
||||
/// prevent a reset from occurring.
|
||||
#[inline]
|
||||
pub fn pet(&mut self) {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
r.rr[self.index as usize].write(|w| w.rr().reload());
|
||||
let r = crate::pac::WDT;
|
||||
r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD));
|
||||
}
|
||||
|
||||
/// Has this handle been pet within the current window?
|
||||
pub fn is_pet(&self) -> bool {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
let rd = r.reqstatus.read().bits();
|
||||
let idx = self.index as usize;
|
||||
((rd >> idx) & 0x1) == 0
|
||||
let r = crate::pac::WDT;
|
||||
!r.reqstatus().read().rr(self.index as usize)
|
||||
}
|
||||
|
||||
/// Steal a watchdog handle by index.
|
||||
|
@ -1054,9 +1054,17 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
|
||||
pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + '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);
|
||||
|
@ -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<usize, Self::Error> {
|
||||
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<u8, nb::Error<Self::Error>> {
|
||||
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<usize, Self::Error> {
|
||||
self.blocking_write(buf).map(|_| buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.blocking_flush()
|
||||
}
|
||||
}
|
||||
|
||||
trait SealedMode {}
|
||||
|
||||
trait SealedInstance {
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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<Lpms> 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| {
|
||||
|
@ -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
|
||||
|
@ -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<usize>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
||||
fn from(val: WakeupPrescaler) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
@ -79,7 +79,7 @@ impl From<WakeupPrescaler> 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<crate::pac::rtc::vals::Wucksel> 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;
|
||||
|
||||
<RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
|
||||
unsafe { <RTC as crate::rtc::SealedInstance>::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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")]
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -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<bool, Self::Error> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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<AlarmHandle>;
|
||||
|
||||
/// 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.
|
||||
|
@ -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<Output = ()> + 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<const N: usize> {
|
||||
pub struct UsbLogger<const N: usize, T: ReceiverHandler + Send + Sync> {
|
||||
buffer: Pipe<CS, N>,
|
||||
custom_style: Option<fn(&Record, &mut Writer<'_, N>) -> ()>,
|
||||
recieve_handler: Option<T>,
|
||||
}
|
||||
|
||||
impl<const N: usize> UsbLogger<N> {
|
||||
impl<const N: usize, T: ReceiverHandler + Send + Sync> UsbLogger<N, T> {
|
||||
/// 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<const N: usize> UsbLogger<N> {
|
||||
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<const N: usize> UsbLogger<N> {
|
||||
}
|
||||
}
|
||||
};
|
||||
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<const N: usize> UsbLogger<N> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> log::Log for UsbLogger<N> {
|
||||
impl<const N: usize, T: ReceiverHandler + Send + Sync> log::Log for UsbLogger<N, T> {
|
||||
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)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use cortex_m_rt::{entry, exception};
|
||||
use defmt_rtt as _;
|
||||
use embassy_boot_nrf::*;
|
||||
use embassy_nrf::nvmc::Nvmc;
|
||||
use embassy_nrf::wdt;
|
||||
use embassy_nrf::wdt::{self, HaltConfig, SleepConfig};
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
|
||||
#[entry]
|
||||
@ -25,8 +25,8 @@ fn main() -> ! {
|
||||
|
||||
let mut wdt_config = wdt::Config::default();
|
||||
wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
|
||||
wdt_config.run_during_sleep = true;
|
||||
wdt_config.run_during_debug_halt = false;
|
||||
wdt_config.action_during_sleep = SleepConfig::RUN;
|
||||
wdt_config.action_during_debug_halt = HaltConfig::PAUSE;
|
||||
|
||||
let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
|
||||
let flash = Mutex::new(RefCell::new(flash));
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
@ -46,11 +44,10 @@ async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -1,7 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use defmt::*;
|
||||
@ -30,11 +29,10 @@ static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
@ -24,11 +22,10 @@ bind_interrupts!(struct Irqs {
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
@ -22,11 +20,10 @@ bind_interrupts!(struct Irqs {
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use defmt::{info, panic, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
@ -39,11 +37,10 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) {
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
@ -27,11 +25,10 @@ const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
pac::CLOCK.tasks_hfclkstart().write_value(1);
|
||||
while pac::CLOCK.events_hfclkstarted().read() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
@ -4,7 +4,7 @@
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Input, Pull};
|
||||
use embassy_nrf::wdt::{Config, Watchdog};
|
||||
use embassy_nrf::wdt::{Config, HaltConfig, Watchdog};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
// This is needed for `probe-rs run` to be able to catch the panic message
|
||||
// in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
|
||||
config.run_during_debug_halt = false;
|
||||
config.action_during_debug_halt = HaltConfig::PAUSE;
|
||||
|
||||
let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) {
|
||||
Ok(x) => x,
|
||||
|
@ -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"
|
||||
|
@ -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<NoopRawMutex, _> = 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, DC> {
|
||||
spi: SPI,
|
||||
dc: DC,
|
||||
}
|
||||
|
||||
impl<SPI, DC> SPIDeviceInterface<SPI, DC>
|
||||
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<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
|
||||
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<T: SpiDevice>(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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
64
examples/rp/src/bin/usb_serial_with_handler.rs
Normal file
64
examples/rp/src/bin/usb_serial_with_handler.rs
Normal file
@ -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<USB>;
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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, DC> {
|
||||
spi: SPI,
|
||||
dc: DC,
|
||||
}
|
||||
|
||||
impl<SPI, DC> SPIDeviceInterface<SPI, DC>
|
||||
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<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
|
||||
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<T: SpiDevice>(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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
BIN
examples/stm32u5/src/bin/ferris.bmp
Normal file
BIN
examples/stm32u5/src/bin/ferris.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
@ -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));
|
||||
|
461
examples/stm32u5/src/bin/ltdc.rs
Normal file
461
examples/stm32u5/src/bin/ltdc.rs
Normal file
@ -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<peripherals::LTDC>;
|
||||
});
|
||||
|
||||
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<Rgb888> = 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<Rgb888>) -> FnvIndexMap<u32, u8, NUM_COLORS> {
|
||||
let mut color_map: FnvIndexMap<u32, u8, NUM_COLORS> = 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<u32, u8, NUM_COLORS>) -> [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<u32, u8, NUM_COLORS>,
|
||||
}
|
||||
|
||||
impl DoubleBuffer {
|
||||
pub fn new(
|
||||
buf0: &'static mut [TargetPixelType],
|
||||
buf1: &'static mut [TargetPixelType],
|
||||
layer_config: LtdcLayerConfig,
|
||||
color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
|
||||
) -> Self {
|
||||
Self {
|
||||
buf0,
|
||||
buf1,
|
||||
is_buf0: true,
|
||||
layer_config,
|
||||
color_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current(&mut self) -> (&FnvIndexMap<u32, u8, NUM_COLORS>, &mut [TargetPixelType]) {
|
||||
if self.is_buf0 {
|
||||
(&self.color_map, self.buf0)
|
||||
} else {
|
||||
(&self.color_map, self.buf1)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn swap<T: ltdc::Instance>(&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<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ use embassy_usb::Builder;
|
||||
use panic_probe as _;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
|
||||
OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
|
||||
});
|
||||
|
||||
#[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);
|
||||
|
@ -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",
|
||||
|
@ -86,6 +86,11 @@ name = "gpiote"
|
||||
path = "src/bin/gpiote.rs"
|
||||
required-features = []
|
||||
|
||||
[[bin]]
|
||||
name = "spim"
|
||||
path = "src/bin/spim.rs"
|
||||
required-features = [ "easydma",]
|
||||
|
||||
[[bin]]
|
||||
name = "timer"
|
||||
path = "src/bin/timer.rs"
|
||||
|
@ -50,15 +50,15 @@ async fn main(_spawner: Spawner) {
|
||||
const NSPAM: usize = 17;
|
||||
static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let _spam = UarteTx::new(peri!(p, UART1), irqs!(UART1), peri!(p, PIN_A), config.clone());
|
||||
let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) };
|
||||
let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) };
|
||||
let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) };
|
||||
let spam_peri = pac::UARTE1;
|
||||
let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(spam_peri.events_endtx().as_ptr())) };
|
||||
let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(spam_peri.tasks_starttx().as_ptr())) };
|
||||
let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task);
|
||||
spam_ppi.enable();
|
||||
let p = (&raw mut TX_BUF) as *mut u8;
|
||||
spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) });
|
||||
spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) });
|
||||
spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
spam_peri.txd().ptr().write_value(p as u32);
|
||||
spam_peri.txd().maxcnt().write(|w| w.set_maxcnt(NSPAM as _));
|
||||
spam_peri.tasks_starttx().write_value(1);
|
||||
|
||||
let mut i = 0;
|
||||
let mut total = 0;
|
||||
|
@ -17,10 +17,12 @@ async fn main(_spawner: Spawner) {
|
||||
let mut output = Output::new(peri!(p, PIN_B), Level::Low, OutputDrive::Standard);
|
||||
|
||||
output.set_low();
|
||||
assert!(output.is_set_low());
|
||||
Timer::after_millis(10).await;
|
||||
assert!(input.is_low());
|
||||
|
||||
output.set_high();
|
||||
assert!(output.is_set_high());
|
||||
Timer::after_millis(10).await;
|
||||
assert!(input.is_high());
|
||||
|
||||
|
42
tests/nrf/src/bin/spim.rs
Normal file
42
tests/nrf/src/bin/spim.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// required-features: easydma
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[path = "../common.rs"]
|
||||
mod common;
|
||||
|
||||
use defmt::{assert_eq, *};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::spim::Spim;
|
||||
use embassy_nrf::{peripherals, spim};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
let mut config = spim::Config::default();
|
||||
config.frequency = spim::Frequency::M1;
|
||||
let mut spim = Spim::new(
|
||||
&mut peri!(p, SPIM0),
|
||||
irqs!(SPIM0),
|
||||
&mut peri!(p, PIN_X),
|
||||
&mut peri!(p, PIN_A), // MISO
|
||||
&mut peri!(p, PIN_B), // MOSI
|
||||
config.clone(),
|
||||
);
|
||||
let data = [
|
||||
0x42, 0x43, 0x44, 0x45, 0x66, 0x12, 0x23, 0x34, 0x45, 0x19, 0x91, 0xaa, 0xff, 0xa5, 0x5a, 0x77,
|
||||
];
|
||||
let mut buf = [0u8; 16];
|
||||
|
||||
buf.fill(0);
|
||||
spim.blocking_transfer(&mut buf, &data).unwrap();
|
||||
assert_eq!(data, buf);
|
||||
|
||||
buf.fill(0);
|
||||
spim.transfer(&mut buf, &data).await.unwrap();
|
||||
assert_eq!(data, buf);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
@ -52,51 +52,66 @@ define_peris!(PIN_A = P0_13, PIN_B = P0_14,);
|
||||
#[cfg(feature = "nrf52832")]
|
||||
define_peris!(
|
||||
PIN_A = P0_11, PIN_B = P0_12,
|
||||
PIN_X = P0_13,
|
||||
UART0 = UARTE0,
|
||||
SPIM0 = TWISPI0,
|
||||
@irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;},
|
||||
);
|
||||
|
||||
#[cfg(feature = "nrf52833")]
|
||||
define_peris!(
|
||||
PIN_A = P1_01, PIN_B = P1_02,
|
||||
PIN_X = P1_03,
|
||||
UART0 = UARTE0,
|
||||
UART1 = UARTE1,
|
||||
SPIM0 = TWISPI0,
|
||||
@irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq UART1 = {UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;},
|
||||
@irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler<peripherals::UARTE1>;},
|
||||
@irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;},
|
||||
);
|
||||
|
||||
#[cfg(feature = "nrf52840")]
|
||||
define_peris!(
|
||||
PIN_A = P1_02, PIN_B = P1_03,
|
||||
PIN_X = P1_04,
|
||||
UART0 = UARTE0,
|
||||
UART1 = UARTE1,
|
||||
SPIM0 = TWISPI0,
|
||||
@irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq UART1 = {UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;},
|
||||
@irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;},
|
||||
@irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler<peripherals::UARTE1>;},
|
||||
@irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler<peripherals::TWISPI0>;},
|
||||
);
|
||||
|
||||
#[cfg(feature = "nrf5340")]
|
||||
define_peris!(
|
||||
PIN_A = P1_08, PIN_B = P1_09,
|
||||
PIN_X = P1_10,
|
||||
UART0 = SERIAL0,
|
||||
UART1 = SERIAL1,
|
||||
SPIM0 = SERIAL0,
|
||||
@irq UART0 = {SERIAL0 => uarte::InterruptHandler<peripherals::SERIAL0>;},
|
||||
@irq UART1 = {SERIAL1 => uarte::InterruptHandler<peripherals::SERIAL1>;},
|
||||
@irq UART0_BUFFERED = {SERIAL0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;},
|
||||
@irq UART1_BUFFERED = {SERIAL1 => buffered_uarte::InterruptHandler<peripherals::SERIAL1>;},
|
||||
@irq SPIM0 = {SERIAL0 => spim::InterruptHandler<peripherals::SERIAL0>;},
|
||||
);
|
||||
|
||||
#[cfg(feature = "nrf9160")]
|
||||
define_peris!(
|
||||
PIN_A = P0_00, PIN_B = P0_01,
|
||||
PIN_X = P0_02,
|
||||
UART0 = SERIAL0,
|
||||
UART1 = SERIAL1,
|
||||
SPIM0 = SERIAL0,
|
||||
@irq UART0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => uarte::InterruptHandler<peripherals::SERIAL0>;},
|
||||
@irq UART1 = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => uarte::InterruptHandler<peripherals::SERIAL1>;},
|
||||
@irq UART0_BUFFERED = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;},
|
||||
@irq UART1_BUFFERED = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => buffered_uarte::InterruptHandler<peripherals::SERIAL1>;},
|
||||
@irq SPIM0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => spim::InterruptHandler<peripherals::SERIAL0>;},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user