Compare commits
57 Commits
embassy-sy
...
rp-remove-
Author | SHA1 | Date | |
---|---|---|---|
5b61ab852a | |||
b99533607c | |||
ea4d08b6cf | |||
05968bf0f3 | |||
fc086fd4ba | |||
ea702b3719 | |||
97d18c5ffb | |||
eed34f945c | |||
0b2d6996e8 | |||
e7fdd500d8 | |||
1f246d0e37 | |||
a7d5c87049 | |||
49e1091309 | |||
79b49c6fae | |||
f053bf742c | |||
9423987ac5 | |||
bc21b6efaf | |||
a7b90c7fb6 | |||
4e61d83555 | |||
c871fe0848 | |||
3c6c382465 | |||
171b764d82 | |||
08c8022583 | |||
4f2dcca34b | |||
9c30d565b9 | |||
f363f6ce92 | |||
6bf24b4d1a | |||
88bbc238b7 | |||
2cfe2439c9 | |||
7b38b95e10 | |||
5142674786 | |||
a5b1d2237f | |||
61560e740d | |||
1669e39565 | |||
80e58426fc | |||
ad0eb3f4bd | |||
8d809c96ec | |||
7152031229 | |||
7ee7109508 | |||
18dc0dea63 | |||
9d674f0212 | |||
816778e3fa | |||
4f33cc5d1a | |||
2fed9f949a | |||
7412a859fd | |||
0db1332da8 | |||
334dfcdb65 | |||
54ba472540 | |||
4322293f63 | |||
c14527486d | |||
81298394b5 | |||
5d1576ea73 | |||
f46b838746 | |||
3f672c8a93 | |||
e5af4c4bce | |||
7bb9620b1a | |||
feb840c503 |
@ -150,7 +150,7 @@ impl BootLoader {
|
||||
/// +-----------+------------+--------+--------+--------+--------+
|
||||
/// | Active | 0 | 1 | 2 | 3 | - |
|
||||
/// | DFU | 0 | 3 | 2 | 1 | X |
|
||||
/// +-----------+-------+--------+--------+--------+--------+
|
||||
/// +-----------+------------+--------+--------+--------+--------+
|
||||
///
|
||||
/// The algorithm starts by copying 'backwards', and after the first step, the layout is
|
||||
/// as follows:
|
||||
|
@ -17,9 +17,9 @@ pub struct BootLoader {
|
||||
page: AlignedBuffer<PAGE_SIZE>,
|
||||
}
|
||||
|
||||
impl BootLoader {
|
||||
impl Default for BootLoader {
|
||||
/// Create a new bootloader instance using parameters from linker script
|
||||
pub fn default() -> Self {
|
||||
fn default() -> Self {
|
||||
extern "C" {
|
||||
static __bootloader_state_start: u32;
|
||||
static __bootloader_state_end: u32;
|
||||
@ -54,7 +54,9 @@ impl BootLoader {
|
||||
|
||||
Self::new(active, dfu, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl BootLoader {
|
||||
/// Create a new bootloader instance using the supplied partitions for active, dfu and state.
|
||||
pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
|
||||
Self {
|
||||
|
@ -14,43 +14,6 @@ pub struct BootLoader<const PAGE_SIZE: usize, const WRITE_SIZE: usize> {
|
||||
}
|
||||
|
||||
impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> BootLoader<PAGE_SIZE, WRITE_SIZE> {
|
||||
/// Create a new bootloader instance using parameters from linker script
|
||||
pub fn default() -> Self {
|
||||
extern "C" {
|
||||
static __bootloader_state_start: u32;
|
||||
static __bootloader_state_end: u32;
|
||||
static __bootloader_active_start: u32;
|
||||
static __bootloader_active_end: u32;
|
||||
static __bootloader_dfu_start: u32;
|
||||
static __bootloader_dfu_end: u32;
|
||||
}
|
||||
|
||||
let active = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_active_start as *const u32 as usize,
|
||||
&__bootloader_active_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
let dfu = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_dfu_start as *const u32 as usize,
|
||||
&__bootloader_dfu_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
let state = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_state_start as *const u32 as usize,
|
||||
&__bootloader_state_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
|
||||
trace!("ACTIVE: 0x{:x} - 0x{:x}", active.from, active.to);
|
||||
trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to);
|
||||
trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to);
|
||||
|
||||
Self::new(active, dfu, state)
|
||||
}
|
||||
|
||||
/// Create a new bootloader instance using the supplied partitions for active, dfu and state.
|
||||
pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
|
||||
Self {
|
||||
@ -85,3 +48,42 @@ impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> BootLoader<PAGE_SIZE, WRIT
|
||||
cortex_m::asm::bootload(start as *const u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> Default for BootLoader<PAGE_SIZE, WRITE_SIZE> {
|
||||
/// Create a new bootloader instance using parameters from linker script
|
||||
fn default() -> Self {
|
||||
extern "C" {
|
||||
static __bootloader_state_start: u32;
|
||||
static __bootloader_state_end: u32;
|
||||
static __bootloader_active_start: u32;
|
||||
static __bootloader_active_end: u32;
|
||||
static __bootloader_dfu_start: u32;
|
||||
static __bootloader_dfu_end: u32;
|
||||
}
|
||||
|
||||
let active = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_active_start as *const u32 as usize,
|
||||
&__bootloader_active_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
let dfu = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_dfu_start as *const u32 as usize,
|
||||
&__bootloader_dfu_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
let state = unsafe {
|
||||
Partition::new(
|
||||
&__bootloader_state_start as *const u32 as usize,
|
||||
&__bootloader_state_end as *const u32 as usize,
|
||||
)
|
||||
};
|
||||
|
||||
trace!("ACTIVE: 0x{:x} - 0x{:x}", active.from, active.to);
|
||||
trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to);
|
||||
trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to);
|
||||
|
||||
Self::new(active, dfu, state)
|
||||
}
|
||||
}
|
||||
|
154
embassy-hal-common/src/atomic_ring_buffer.rs
Normal file
154
embassy-hal-common/src/atomic_ring_buffer.rs
Normal file
@ -0,0 +1,154 @@
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
|
||||
pub struct RingBuffer {
|
||||
buf: AtomicPtr<u8>,
|
||||
len: AtomicUsize,
|
||||
start: AtomicUsize,
|
||||
end: AtomicUsize,
|
||||
}
|
||||
|
||||
pub struct Reader<'a>(&'a RingBuffer);
|
||||
pub struct Writer<'a>(&'a RingBuffer);
|
||||
|
||||
impl RingBuffer {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
buf: AtomicPtr::new(core::ptr::null_mut()),
|
||||
len: AtomicUsize::new(0),
|
||||
start: AtomicUsize::new(0),
|
||||
end: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// - The buffer (`buf .. buf+len`) must be valid memory until `deinit` is called.
|
||||
/// - Must not be called concurrently with any other methods.
|
||||
pub unsafe fn init(&self, buf: *mut u8, len: usize) {
|
||||
self.buf.store(buf, Ordering::Relaxed);
|
||||
self.len.store(len, Ordering::Relaxed);
|
||||
self.start.store(0, Ordering::Relaxed);
|
||||
self.end.store(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub unsafe fn deinit(&self) {
|
||||
self.len.store(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub unsafe fn reader(&self) -> Reader<'_> {
|
||||
Reader(self)
|
||||
}
|
||||
|
||||
pub unsafe fn writer(&self) -> Writer<'_> {
|
||||
Writer(self)
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
let start = self.start.load(Ordering::Relaxed);
|
||||
let end = self.end.load(Ordering::Relaxed);
|
||||
|
||||
self.wrap(end + 1) == start
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let start = self.start.load(Ordering::Relaxed);
|
||||
let end = self.end.load(Ordering::Relaxed);
|
||||
|
||||
start == end
|
||||
}
|
||||
|
||||
pub fn wrap(&self, n: usize) -> usize {
|
||||
let len = self.len.load(Ordering::Relaxed);
|
||||
|
||||
assert!(n <= len);
|
||||
if n == len {
|
||||
0
|
||||
} else {
|
||||
n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Writer<'a> {
|
||||
pub fn push(&self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
|
||||
let (p, n) = self.push_buf();
|
||||
let buf = unsafe { slice::from_raw_parts_mut(p, n) };
|
||||
let n = f(buf);
|
||||
self.push_done(n);
|
||||
n
|
||||
}
|
||||
|
||||
pub fn push_one(&self, val: u8) -> bool {
|
||||
let n = self.push(|f| match f {
|
||||
[] => 0,
|
||||
[x, ..] => {
|
||||
*x = val;
|
||||
1
|
||||
}
|
||||
});
|
||||
n != 0
|
||||
}
|
||||
|
||||
pub fn push_buf(&self) -> (*mut u8, usize) {
|
||||
let start = self.0.start.load(Ordering::Acquire);
|
||||
let buf = self.0.buf.load(Ordering::Relaxed);
|
||||
let len = self.0.len.load(Ordering::Relaxed);
|
||||
let end = self.0.end.load(Ordering::Relaxed);
|
||||
|
||||
let n = if start <= end {
|
||||
len - end - (start == 0) as usize
|
||||
} else {
|
||||
start - end - 1
|
||||
};
|
||||
|
||||
trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
|
||||
(unsafe { buf.add(end) }, n)
|
||||
}
|
||||
|
||||
pub fn push_done(&self, n: usize) {
|
||||
trace!(" ringbuf: push {:?}", n);
|
||||
let end = self.0.end.load(Ordering::Relaxed);
|
||||
self.0.end.store(self.0.wrap(end + n), Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
pub fn pop(&self, f: impl FnOnce(&[u8]) -> usize) -> usize {
|
||||
let (p, n) = self.pop_buf();
|
||||
let buf = unsafe { slice::from_raw_parts(p, n) };
|
||||
let n = f(buf);
|
||||
self.pop_done(n);
|
||||
n
|
||||
}
|
||||
|
||||
pub fn pop_one(&self) -> Option<u8> {
|
||||
let mut res = None;
|
||||
self.pop(|f| match f {
|
||||
&[] => 0,
|
||||
&[x, ..] => {
|
||||
res = Some(x);
|
||||
1
|
||||
}
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
pub fn pop_buf(&self) -> (*mut u8, usize) {
|
||||
let end = self.0.end.load(Ordering::Acquire);
|
||||
let buf = self.0.buf.load(Ordering::Relaxed);
|
||||
let len = self.0.len.load(Ordering::Relaxed);
|
||||
let start = self.0.start.load(Ordering::Relaxed);
|
||||
|
||||
let n = if end < start { len - start } else { end - start };
|
||||
|
||||
trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
|
||||
(unsafe { buf.add(start) }, n)
|
||||
}
|
||||
|
||||
pub fn pop_done(&self, n: usize) {
|
||||
trace!(" ringbuf: pop {:?}", n);
|
||||
|
||||
let start = self.0.start.load(Ordering::Relaxed);
|
||||
self.0.start.store(self.0.wrap(start + n), Ordering::Release);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
pub mod atomic_ring_buffer;
|
||||
pub mod drop;
|
||||
mod macros;
|
||||
mod peripheral;
|
||||
|
@ -54,6 +54,7 @@ critical-section = "1.1"
|
||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||
chrono = { version = "0.4", default-features = false, optional = true }
|
||||
embedded-io = { version = "0.3.1", features = ["async"], optional = true }
|
||||
embedded-storage = { version = "0.3" }
|
||||
|
||||
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
|
||||
#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
|
||||
|
@ -191,7 +191,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
|
||||
}
|
||||
}
|
||||
|
||||
const CHANNEL_COUNT: usize = 12;
|
||||
pub(crate) const CHANNEL_COUNT: usize = 12;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT];
|
||||
|
||||
|
463
embassy-rp/src/flash.rs
Normal file
463
embassy-rp/src/flash.rs
Normal file
@ -0,0 +1,463 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::Peripheral;
|
||||
use embedded_storage::nor_flash::{
|
||||
check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind,
|
||||
ReadNorFlash,
|
||||
};
|
||||
|
||||
use crate::peripherals::FLASH;
|
||||
|
||||
pub const FLASH_BASE: usize = 0x10000000;
|
||||
|
||||
// **NOTE**:
|
||||
//
|
||||
// These limitations are currently enforced because of using the
|
||||
// RP2040 boot-rom flash functions, that are optimized for flash compatibility
|
||||
// rather than performance.
|
||||
pub const PAGE_SIZE: usize = 256;
|
||||
pub const WRITE_SIZE: usize = 1;
|
||||
pub const READ_SIZE: usize = 1;
|
||||
pub const ERASE_SIZE: usize = 4096;
|
||||
|
||||
/// Error type for NVMC operations.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
/// Opration using a location not in flash.
|
||||
OutOfBounds,
|
||||
/// Unaligned operation or using unaligned buffers.
|
||||
Unaligned,
|
||||
Other,
|
||||
}
|
||||
|
||||
impl From<NorFlashErrorKind> for Error {
|
||||
fn from(e: NorFlashErrorKind) -> Self {
|
||||
match e {
|
||||
NorFlashErrorKind::NotAligned => Self::Unaligned,
|
||||
NorFlashErrorKind::OutOfBounds => Self::OutOfBounds,
|
||||
_ => Self::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NorFlashError for Error {
|
||||
fn kind(&self) -> NorFlashErrorKind {
|
||||
match self {
|
||||
Self::OutOfBounds => NorFlashErrorKind::OutOfBounds,
|
||||
Self::Unaligned => NorFlashErrorKind::NotAligned,
|
||||
Self::Other => NorFlashErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Flash<'d, T: Instance, const FLASH_SIZE: usize>(PhantomData<&'d mut T>);
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
||||
pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
|
||||
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
||||
check_read(self, offset, bytes.len())?;
|
||||
|
||||
let flash_data = unsafe { core::slice::from_raw_parts((FLASH_BASE as u32 + offset) as *const u8, bytes.len()) };
|
||||
|
||||
bytes.copy_from_slice(flash_data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
FLASH_SIZE
|
||||
}
|
||||
|
||||
pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
|
||||
check_erase(self, from, to)?;
|
||||
|
||||
trace!(
|
||||
"Erasing from 0x{:x} to 0x{:x}",
|
||||
FLASH_BASE as u32 + from,
|
||||
FLASH_BASE as u32 + to
|
||||
);
|
||||
|
||||
let len = to - from;
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true)) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
|
||||
check_write(self, offset, bytes.len())?;
|
||||
|
||||
trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset);
|
||||
|
||||
let end_offset = offset as usize + bytes.len();
|
||||
|
||||
let padded_offset = (offset as *const u8).align_offset(PAGE_SIZE);
|
||||
let start_padding = core::cmp::min(padded_offset, bytes.len());
|
||||
|
||||
// Pad in the beginning
|
||||
if start_padding > 0 {
|
||||
let start = PAGE_SIZE - padded_offset;
|
||||
let end = start + start_padding;
|
||||
|
||||
let mut pad_buf = [0xFF_u8; PAGE_SIZE];
|
||||
pad_buf[start..end].copy_from_slice(&bytes[..start_padding]);
|
||||
|
||||
let unaligned_offset = offset as usize - start;
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true)) }
|
||||
}
|
||||
|
||||
let remaining_len = bytes.len() - start_padding;
|
||||
let end_padding = start_padding + PAGE_SIZE * (remaining_len / PAGE_SIZE);
|
||||
|
||||
// Write aligned slice of length in multiples of 256 bytes
|
||||
// If the remaining bytes to be written is more than a full page.
|
||||
if remaining_len >= PAGE_SIZE {
|
||||
let mut aligned_offset = if start_padding > 0 {
|
||||
offset as usize + padded_offset
|
||||
} else {
|
||||
offset as usize
|
||||
};
|
||||
|
||||
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
||||
let aligned_data = &bytes[start_padding..end_padding];
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true)) }
|
||||
} else {
|
||||
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
||||
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
||||
ram_buf.copy_from_slice(chunk);
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true)) }
|
||||
aligned_offset += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pad in the end
|
||||
let rem_offset = (end_offset as *const u8).align_offset(PAGE_SIZE);
|
||||
let rem_padding = remaining_len % PAGE_SIZE;
|
||||
if rem_padding > 0 {
|
||||
let mut pad_buf = [0xFF_u8; PAGE_SIZE];
|
||||
pad_buf[..rem_padding].copy_from_slice(&bytes[end_padding..]);
|
||||
|
||||
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true)) }
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Make sure to uphold the contract points with rp2040-flash.
|
||||
/// - interrupts must be disabled
|
||||
/// - DMA must not access flash memory
|
||||
unsafe fn in_ram(&mut self, operation: impl FnOnce()) {
|
||||
let dma_status = &mut [false; crate::dma::CHANNEL_COUNT];
|
||||
|
||||
// TODO: Make sure CORE1 is paused during the entire duration of the RAM function
|
||||
|
||||
critical_section::with(|_| {
|
||||
// Pause all DMA channels for the duration of the ram operation
|
||||
for (number, status) in dma_status.iter_mut().enumerate() {
|
||||
let ch = crate::pac::DMA.ch(number as _);
|
||||
*status = ch.ctrl_trig().read().en();
|
||||
if *status {
|
||||
ch.ctrl_trig().modify(|w| w.set_en(false));
|
||||
}
|
||||
}
|
||||
|
||||
// Run our flash operation in RAM
|
||||
operation();
|
||||
|
||||
// Re-enable previously enabled DMA channels
|
||||
for (number, status) in dma_status.iter().enumerate() {
|
||||
let ch = crate::pac::DMA.ch(number as _);
|
||||
if *status {
|
||||
ch.ctrl_trig().modify(|w| w.set_en(true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> {
|
||||
const READ_SIZE: usize = READ_SIZE;
|
||||
|
||||
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(offset, bytes)
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
self.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> {
|
||||
const WRITE_SIZE: usize = WRITE_SIZE;
|
||||
|
||||
const ERASE_SIZE: usize = ERASE_SIZE;
|
||||
|
||||
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||
self.erase(from, to)
|
||||
}
|
||||
|
||||
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(offset, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod ram_helpers {
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::rom_data;
|
||||
|
||||
#[repr(C)]
|
||||
struct FlashFunctionPointers<'a> {
|
||||
connect_internal_flash: unsafe extern "C" fn() -> (),
|
||||
flash_exit_xip: unsafe extern "C" fn() -> (),
|
||||
flash_range_erase: Option<unsafe extern "C" fn(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> ()>,
|
||||
flash_range_program: Option<unsafe extern "C" fn(addr: u32, data: *const u8, count: usize) -> ()>,
|
||||
flash_flush_cache: unsafe extern "C" fn() -> (),
|
||||
flash_enter_cmd_xip: unsafe extern "C" fn() -> (),
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn flash_function_pointers(erase: bool, write: bool) -> FlashFunctionPointers<'static> {
|
||||
FlashFunctionPointers {
|
||||
connect_internal_flash: rom_data::connect_internal_flash::ptr(),
|
||||
flash_exit_xip: rom_data::flash_exit_xip::ptr(),
|
||||
flash_range_erase: if erase {
|
||||
Some(rom_data::flash_range_erase::ptr())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
flash_range_program: if write {
|
||||
Some(rom_data::flash_range_program::ptr())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
flash_flush_cache: rom_data::flash_flush_cache::ptr(),
|
||||
flash_enter_cmd_xip: rom_data::flash_enter_cmd_xip::ptr(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
/// # Safety
|
||||
///
|
||||
/// `boot2` must contain a valid 2nd stage boot loader which can be called to re-initialize XIP mode
|
||||
unsafe fn flash_function_pointers_with_boot2(erase: bool, write: bool, boot2: &[u32; 64]) -> FlashFunctionPointers {
|
||||
let boot2_fn_ptr = (boot2 as *const u32 as *const u8).offset(1);
|
||||
let boot2_fn: unsafe extern "C" fn() -> () = core::mem::transmute(boot2_fn_ptr);
|
||||
FlashFunctionPointers {
|
||||
connect_internal_flash: rom_data::connect_internal_flash::ptr(),
|
||||
flash_exit_xip: rom_data::flash_exit_xip::ptr(),
|
||||
flash_range_erase: if erase {
|
||||
Some(rom_data::flash_range_erase::ptr())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
flash_range_program: if write {
|
||||
Some(rom_data::flash_range_program::ptr())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
flash_flush_cache: rom_data::flash_flush_cache::ptr(),
|
||||
flash_enter_cmd_xip: boot2_fn,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Erase a flash range starting at `addr` with length `len`.
|
||||
///
|
||||
/// `addr` and `len` must be multiples of 4096
|
||||
///
|
||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
||||
/// is used to re-initialize the XIP engine after flashing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Nothing must access flash while this is running.
|
||||
/// Usually this means:
|
||||
/// - interrupts must be disabled
|
||||
/// - 2nd core must be running code from RAM or ROM with interrupts disabled
|
||||
/// - DMA must not access flash memory
|
||||
///
|
||||
/// `addr` and `len` parameters must be valid and are not checked.
|
||||
pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) {
|
||||
let mut boot2 = [0u32; 256 / 4];
|
||||
let ptrs = if use_boot2 {
|
||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
||||
flash_function_pointers_with_boot2(true, false, &boot2)
|
||||
} else {
|
||||
flash_function_pointers(true, false)
|
||||
};
|
||||
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
write_flash_inner(addr, len, None, &ptrs as *const FlashFunctionPointers);
|
||||
}
|
||||
|
||||
/// Erase and rewrite a flash range starting at `addr` with data `data`.
|
||||
///
|
||||
/// `addr` and `data.len()` must be multiples of 4096
|
||||
///
|
||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
||||
/// is used to re-initialize the XIP engine after flashing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Nothing must access flash while this is running.
|
||||
/// Usually this means:
|
||||
/// - interrupts must be disabled
|
||||
/// - 2nd core must be running code from RAM or ROM with interrupts disabled
|
||||
/// - DMA must not access flash memory
|
||||
///
|
||||
/// `addr` and `len` parameters must be valid and are not checked.
|
||||
pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) {
|
||||
let mut boot2 = [0u32; 256 / 4];
|
||||
let ptrs = if use_boot2 {
|
||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
||||
flash_function_pointers_with_boot2(true, true, &boot2)
|
||||
} else {
|
||||
flash_function_pointers(true, true)
|
||||
};
|
||||
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
write_flash_inner(
|
||||
addr,
|
||||
data.len() as u32,
|
||||
Some(data),
|
||||
&ptrs as *const FlashFunctionPointers,
|
||||
);
|
||||
}
|
||||
|
||||
/// Write a flash range starting at `addr` with data `data`.
|
||||
///
|
||||
/// `addr` and `data.len()` must be multiples of 256
|
||||
///
|
||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
||||
/// is used to re-initialize the XIP engine after flashing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Nothing must access flash while this is running.
|
||||
/// Usually this means:
|
||||
/// - interrupts must be disabled
|
||||
/// - 2nd core must be running code from RAM or ROM with interrupts disabled
|
||||
/// - DMA must not access flash memory
|
||||
///
|
||||
/// `addr` and `len` parameters must be valid and are not checked.
|
||||
pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) {
|
||||
let mut boot2 = [0u32; 256 / 4];
|
||||
let ptrs = if use_boot2 {
|
||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
||||
flash_function_pointers_with_boot2(false, true, &boot2)
|
||||
} else {
|
||||
flash_function_pointers(false, true)
|
||||
};
|
||||
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
write_flash_inner(
|
||||
addr,
|
||||
data.len() as u32,
|
||||
Some(data),
|
||||
&ptrs as *const FlashFunctionPointers,
|
||||
);
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Nothing must access flash while this is running.
|
||||
/// Usually this means:
|
||||
/// - interrupts must be disabled
|
||||
/// - 2nd core must be running code from RAM or ROM with interrupts disabled
|
||||
/// - DMA must not access flash memory
|
||||
/// Length of data must be a multiple of 4096
|
||||
/// addr must be aligned to 4096
|
||||
#[inline(never)]
|
||||
#[link_section = ".data.ram_func"]
|
||||
unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
|
||||
/*
|
||||
Should be equivalent to:
|
||||
rom_data::connect_internal_flash();
|
||||
rom_data::flash_exit_xip();
|
||||
rom_data::flash_range_erase(addr, len, 1 << 31, 0); // if selected
|
||||
rom_data::flash_range_program(addr, data as *const _, len); // if selected
|
||||
rom_data::flash_flush_cache();
|
||||
rom_data::flash_enter_cmd_xip();
|
||||
*/
|
||||
#[cfg(target_arch = "arm")]
|
||||
core::arch::asm!(
|
||||
"mov r8, r0",
|
||||
"mov r9, r2",
|
||||
"mov r10, r1",
|
||||
"ldr r4, [{ptrs}, #0]",
|
||||
"blx r4", // connect_internal_flash()
|
||||
|
||||
"ldr r4, [{ptrs}, #4]",
|
||||
"blx r4", // flash_exit_xip()
|
||||
|
||||
"mov r0, r8", // r0 = addr
|
||||
"mov r1, r10", // r1 = len
|
||||
"movs r2, #1",
|
||||
"lsls r2, r2, #31", // r2 = 1 << 31
|
||||
"movs r3, #0", // r3 = 0
|
||||
"ldr r4, [{ptrs}, #8]",
|
||||
"cmp r4, #0",
|
||||
"beq 1f",
|
||||
"blx r4", // flash_range_erase(addr, len, 1 << 31, 0)
|
||||
"1:",
|
||||
|
||||
"mov r0, r8", // r0 = addr
|
||||
"mov r1, r9", // r0 = data
|
||||
"mov r2, r10", // r2 = len
|
||||
"ldr r4, [{ptrs}, #12]",
|
||||
"cmp r4, #0",
|
||||
"beq 1f",
|
||||
"blx r4", // flash_range_program(addr, data, len);
|
||||
"1:",
|
||||
|
||||
"ldr r4, [{ptrs}, #16]",
|
||||
"blx r4", // flash_flush_cache();
|
||||
|
||||
"ldr r4, [{ptrs}, #20]",
|
||||
"blx r4", // flash_enter_cmd_xip();
|
||||
ptrs = in(reg) ptrs,
|
||||
// Registers r8-r15 are not allocated automatically,
|
||||
// so assign them manually. We need to use them as
|
||||
// otherwise there are not enough registers available.
|
||||
in("r0") addr,
|
||||
in("r2") data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()),
|
||||
in("r1") len,
|
||||
out("r3") _,
|
||||
out("r4") _,
|
||||
lateout("r8") _,
|
||||
lateout("r9") _,
|
||||
lateout("r10") _,
|
||||
clobber_abi("C"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Instance {}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance {}
|
||||
|
||||
impl sealed::Instance for FLASH {}
|
||||
impl Instance for FLASH {}
|
@ -34,3 +34,27 @@ declare!(ADC_IRQ_FIFO);
|
||||
declare!(I2C0_IRQ);
|
||||
declare!(I2C1_IRQ);
|
||||
declare!(RTC_IRQ);
|
||||
|
||||
pub trait InterruptFunction {
|
||||
fn on_interrupt();
|
||||
}
|
||||
|
||||
// Marker trait
|
||||
pub unsafe trait Registration<T: Interrupt> {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! register_interrupts {
|
||||
($name:ident: $($irq:ident),*) => {
|
||||
struct $name;
|
||||
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
extern "C" fn $irq() {
|
||||
<$crate::interrupt::$irq as $crate::interrupt::InterruptFunction>::on_interrupt();
|
||||
}
|
||||
|
||||
unsafe impl $crate::interrupt::Registration<$crate::interrupt::$irq> for $name {}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ pub mod uart;
|
||||
pub mod usb;
|
||||
|
||||
mod clocks;
|
||||
pub mod flash;
|
||||
mod reset;
|
||||
|
||||
// Reexports
|
||||
@ -95,6 +96,8 @@ embassy_hal_common::peripherals! {
|
||||
USB,
|
||||
|
||||
RTC,
|
||||
|
||||
FLASH,
|
||||
}
|
||||
|
||||
#[link_section = ".boot2"]
|
||||
|
@ -1,339 +1,335 @@
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::task::{Poll, Waker};
|
||||
use core::slice;
|
||||
use core::task::Poll;
|
||||
|
||||
use atomic_polyfill::{compiler_fence, Ordering};
|
||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
||||
use embassy_hal_common::ring_buffer::RingBuffer;
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
use crate::interrupt::Registration;
|
||||
|
||||
pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>);
|
||||
impl<'d, T: Instance> State<'d, T> {
|
||||
pub(crate) struct State {
|
||||
tx_waker: AtomicWaker,
|
||||
tx_buf: RingBuffer,
|
||||
rx_waker: AtomicWaker,
|
||||
rx_buf: RingBuffer,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self(StateStorage::new())
|
||||
Self {
|
||||
rx_buf: RingBuffer::new(),
|
||||
tx_buf: RingBuffer::new(),
|
||||
rx_waker: AtomicWaker::new(),
|
||||
tx_waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>);
|
||||
impl<'d, T: Instance> RxState<'d, T> {
|
||||
pub const fn new() -> Self {
|
||||
Self(StateStorage::new())
|
||||
}
|
||||
pub struct BufferedUart<'d> {
|
||||
info: &'static Info,
|
||||
phantom: PhantomData<&'d mut ()>,
|
||||
}
|
||||
|
||||
pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>);
|
||||
impl<'d, T: Instance> TxState<'d, T> {
|
||||
pub const fn new() -> Self {
|
||||
Self(StateStorage::new())
|
||||
}
|
||||
pub struct BufferedUartRx<'d> {
|
||||
info: &'static Info,
|
||||
phantom: PhantomData<&'d mut ()>,
|
||||
}
|
||||
|
||||
struct RxStateInner<'d, T: Instance> {
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
|
||||
waker: WakerRegistration,
|
||||
buf: RingBuffer<'d>,
|
||||
pub struct BufferedUartTx<'d> {
|
||||
info: &'static Info,
|
||||
phantom: PhantomData<&'d mut ()>,
|
||||
}
|
||||
|
||||
struct TxStateInner<'d, T: Instance> {
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
|
||||
waker: WakerRegistration,
|
||||
buf: RingBuffer<'d>,
|
||||
}
|
||||
|
||||
struct FullStateInner<'d, T: Instance> {
|
||||
rx: RxStateInner<'d, T>,
|
||||
tx: TxStateInner<'d, T>,
|
||||
}
|
||||
|
||||
unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {}
|
||||
unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {}
|
||||
|
||||
unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {}
|
||||
unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {}
|
||||
|
||||
unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {}
|
||||
unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {}
|
||||
|
||||
pub struct BufferedUart<'d, T: Instance> {
|
||||
inner: PeripheralMutex<'d, FullStateInner<'d, T>>,
|
||||
}
|
||||
|
||||
pub struct BufferedUartRx<'d, T: Instance> {
|
||||
inner: PeripheralMutex<'d, RxStateInner<'d, T>>,
|
||||
}
|
||||
|
||||
pub struct BufferedUartTx<'d, T: Instance> {
|
||||
inner: PeripheralMutex<'d, TxStateInner<'d, T>>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
|
||||
impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {}
|
||||
impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {}
|
||||
|
||||
impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||
pub fn new<M: Mode>(
|
||||
state: &'d mut State<'d, T>,
|
||||
_uart: Uart<'d, T, M>,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
impl<'d> BufferedUart<'d> {
|
||||
pub fn new<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl Registration<T::Interrupt>,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
) -> BufferedUart<'d, T> {
|
||||
into_ref!(irq);
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(tx, rx);
|
||||
Self::new_inner(
|
||||
T::info(),
|
||||
tx.map_into(),
|
||||
rx.map_into(),
|
||||
None,
|
||||
None,
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_with_rtscts<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl Registration<T::Interrupt>,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(tx, rx, cts, rts);
|
||||
Self::new_inner(
|
||||
T::info(),
|
||||
tx.map_into(),
|
||||
rx.map_into(),
|
||||
Some(rts.map_into()),
|
||||
Some(cts.map_into()),
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
info: &'static Info,
|
||||
mut tx: PeripheralRef<'d, AnyPin>,
|
||||
mut rx: PeripheralRef<'d, AnyPin>,
|
||||
mut rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mut cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
init(
|
||||
info,
|
||||
Some(tx.reborrow()),
|
||||
Some(rx.reborrow()),
|
||||
rts.as_mut().map(|x| x.reborrow()),
|
||||
cts.as_mut().map(|x| x.reborrow()),
|
||||
config,
|
||||
);
|
||||
|
||||
let len = tx_buffer.len();
|
||||
unsafe { info.state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
unsafe { info.state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
r.uartimsc().modify(|w| {
|
||||
info.regs.uartimsc().modify(|w| {
|
||||
w.set_rxim(true);
|
||||
w.set_rtim(true);
|
||||
w.set_txim(true);
|
||||
});
|
||||
|
||||
NVIC::unpend(info.irq);
|
||||
NVIC::unmask(info.irq);
|
||||
NVIC::pend(info.irq);
|
||||
}
|
||||
|
||||
Self {
|
||||
inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner {
|
||||
tx: TxStateInner {
|
||||
phantom: PhantomData,
|
||||
waker: WakerRegistration::new(),
|
||||
buf: RingBuffer::new(tx_buffer),
|
||||
},
|
||||
rx: RxStateInner {
|
||||
phantom: PhantomData,
|
||||
waker: WakerRegistration::new(),
|
||||
buf: RingBuffer::new(rx_buffer),
|
||||
},
|
||||
}),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
pub fn new<M: Mode>(
|
||||
state: &'d mut RxState<'d, T>,
|
||||
_uart: UartRx<'d, T, M>,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
impl<'d> BufferedUartRx<'d> {
|
||||
pub fn new<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Registration<T::Interrupt>,
|
||||
rx_buffer: &'d mut [u8],
|
||||
) -> BufferedUartRx<'d, T> {
|
||||
into_ref!(irq);
|
||||
|
||||
let r = T::regs();
|
||||
config: Config,
|
||||
) -> BufferedUartRx<'d> {
|
||||
let info = T::info();
|
||||
unsafe {
|
||||
r.uartimsc().modify(|w| {
|
||||
info.regs.uartimsc().modify(|w| {
|
||||
w.set_rxim(true);
|
||||
w.set_rtim(true);
|
||||
});
|
||||
|
||||
NVIC::unpend(info.irq);
|
||||
NVIC::unmask(info.irq);
|
||||
}
|
||||
|
||||
Self {
|
||||
inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner {
|
||||
phantom: PhantomData,
|
||||
|
||||
buf: RingBuffer::new(rx_buffer),
|
||||
waker: WakerRegistration::new(),
|
||||
}),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
pub fn new<M: Mode>(
|
||||
state: &'d mut TxState<'d, T>,
|
||||
_uart: UartTx<'d, T, M>,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
impl<'d> BufferedUartTx<'d> {
|
||||
pub fn new<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Registration<T::Interrupt>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> BufferedUartTx<'d, T> {
|
||||
into_ref!(irq);
|
||||
|
||||
let r = T::regs();
|
||||
config: Config,
|
||||
) -> BufferedUartTx<'d> {
|
||||
let info = T::info();
|
||||
unsafe {
|
||||
info.regs.uartimsc().modify(|w| {
|
||||
w.set_txim(true);
|
||||
});
|
||||
|
||||
NVIC::unpend(info.irq);
|
||||
NVIC::unmask(info.irq);
|
||||
}
|
||||
|
||||
Self {
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for BufferedUart<'d> {
|
||||
fn drop(&mut self) {
|
||||
NVIC::mask(self.info.irq);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for BufferedUartRx<'d> {
|
||||
fn drop(&mut self) {
|
||||
NVIC::mask(self.info.irq);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for BufferedUartTx<'d> {
|
||||
fn drop(&mut self) {
|
||||
NVIC::mask(self.info.irq);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn on_interrupt(info: &'static Info) {
|
||||
trace!("on_interrupt");
|
||||
|
||||
let r = info.regs;
|
||||
let s = info.state;
|
||||
|
||||
unsafe {
|
||||
// RX
|
||||
|
||||
let ris = r.uartris().read();
|
||||
// Clear interrupt flags
|
||||
r.uarticr().write(|w| {
|
||||
w.set_rxic(true);
|
||||
w.set_rtic(true);
|
||||
});
|
||||
|
||||
if ris.peris() {
|
||||
warn!("Parity error");
|
||||
r.uarticr().write(|w| {
|
||||
w.set_peic(true);
|
||||
});
|
||||
}
|
||||
if ris.feris() {
|
||||
warn!("Framing error");
|
||||
r.uarticr().write(|w| {
|
||||
w.set_feic(true);
|
||||
});
|
||||
}
|
||||
if ris.beris() {
|
||||
warn!("Break error");
|
||||
r.uarticr().write(|w| {
|
||||
w.set_beic(true);
|
||||
});
|
||||
}
|
||||
if ris.oeris() {
|
||||
warn!("Overrun error");
|
||||
r.uarticr().write(|w| {
|
||||
w.set_oeic(true);
|
||||
});
|
||||
}
|
||||
|
||||
let rx_writer = s.rx_buf.writer();
|
||||
if !r.uartfr().read().rxfe() {
|
||||
let val = r.uartdr().read().data();
|
||||
if !rx_writer.push_one(val) {
|
||||
warn!("RX buffer full, discard received byte");
|
||||
}
|
||||
s.rx_waker.wake();
|
||||
}
|
||||
|
||||
// TX
|
||||
let tx_reader = s.tx_buf.reader();
|
||||
if let Some(val) = tx_reader.pop_one() {
|
||||
r.uartimsc().modify(|w| {
|
||||
w.set_txim(true);
|
||||
});
|
||||
}
|
||||
|
||||
Self {
|
||||
inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner {
|
||||
phantom: PhantomData,
|
||||
|
||||
buf: RingBuffer::new(tx_buffer),
|
||||
waker: WakerRegistration::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T>
|
||||
where
|
||||
Self: 'd,
|
||||
{
|
||||
type Interrupt = T::Interrupt;
|
||||
fn on_interrupt(&mut self) {
|
||||
self.rx.on_interrupt();
|
||||
self.tx.on_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> RxStateInner<'d, T>
|
||||
where
|
||||
Self: 'd,
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) {
|
||||
// We have data ready in buffer? Return it.
|
||||
let mut do_pend = false;
|
||||
let data = self.buf.pop_buf();
|
||||
if !data.is_empty() {
|
||||
let len = data.len().min(buf.len());
|
||||
buf[..len].copy_from_slice(&data[..len]);
|
||||
|
||||
if self.buf.is_full() {
|
||||
do_pend = true;
|
||||
}
|
||||
self.buf.pop(len);
|
||||
|
||||
return (Poll::Ready(Ok(len)), do_pend);
|
||||
}
|
||||
|
||||
self.waker.register(waker);
|
||||
(Poll::Pending, do_pend)
|
||||
}
|
||||
|
||||
fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll<Result<&'a [u8], Error>> {
|
||||
// We have data ready in buffer? Return it.
|
||||
let buf = self.buf.pop_buf();
|
||||
if !buf.is_empty() {
|
||||
let buf: &[u8] = buf;
|
||||
// Safety: buffer lives as long as uart
|
||||
let buf: &[u8] = unsafe { core::mem::transmute(buf) };
|
||||
return Poll::Ready(Ok(buf));
|
||||
}
|
||||
|
||||
self.waker.register(waker);
|
||||
Poll::Pending
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) -> bool {
|
||||
let full = self.buf.is_full();
|
||||
self.buf.pop(amt);
|
||||
full
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T>
|
||||
where
|
||||
Self: 'd,
|
||||
{
|
||||
type Interrupt = T::Interrupt;
|
||||
fn on_interrupt(&mut self) {
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
let ris = r.uartris().read();
|
||||
// Clear interrupt flags
|
||||
r.uarticr().modify(|w| {
|
||||
w.set_rxic(true);
|
||||
w.set_rtic(true);
|
||||
r.uartdr().write(|w| w.set_data(val));
|
||||
s.tx_waker.wake();
|
||||
} else {
|
||||
// Disable interrupt until we have something to transmit again
|
||||
r.uartimsc().modify(|w| {
|
||||
w.set_txim(false);
|
||||
});
|
||||
|
||||
if ris.peris() {
|
||||
warn!("Parity error");
|
||||
r.uarticr().modify(|w| {
|
||||
w.set_peic(true);
|
||||
});
|
||||
}
|
||||
if ris.feris() {
|
||||
warn!("Framing error");
|
||||
r.uarticr().modify(|w| {
|
||||
w.set_feic(true);
|
||||
});
|
||||
}
|
||||
if ris.beris() {
|
||||
warn!("Break error");
|
||||
r.uarticr().modify(|w| {
|
||||
w.set_beic(true);
|
||||
});
|
||||
}
|
||||
if ris.oeris() {
|
||||
warn!("Overrun error");
|
||||
r.uarticr().modify(|w| {
|
||||
w.set_oeic(true);
|
||||
});
|
||||
}
|
||||
|
||||
if !r.uartfr().read().rxfe() {
|
||||
let buf = self.buf.push_buf();
|
||||
if !buf.is_empty() {
|
||||
buf[0] = r.uartdr().read().data();
|
||||
self.buf.push(1);
|
||||
} else {
|
||||
warn!("RX buffer full, discard received byte");
|
||||
}
|
||||
|
||||
if self.buf.is_full() {
|
||||
self.waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
if ris.rtris() {
|
||||
self.waker.wake();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> TxStateInner<'d, T>
|
||||
where
|
||||
Self: 'd,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) {
|
||||
let empty = self.buf.is_empty();
|
||||
let tx_buf = self.buf.push_buf();
|
||||
if tx_buf.is_empty() {
|
||||
self.waker.register(waker);
|
||||
return (Poll::Pending, empty);
|
||||
fn read<'a>(info: &'static Info, buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||
poll_fn(move |cx| {
|
||||
let rx_reader = unsafe { info.state.rx_buf.reader() };
|
||||
let n = rx_reader.pop(|data| {
|
||||
let n = data.len().min(buf.len());
|
||||
buf[..n].copy_from_slice(&data[..n]);
|
||||
n
|
||||
});
|
||||
if n == 0 {
|
||||
info.state.rx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
let n = core::cmp::min(tx_buf.len(), buf.len());
|
||||
tx_buf[..n].copy_from_slice(&buf[..n]);
|
||||
self.buf.push(n);
|
||||
Poll::Ready(Ok(n))
|
||||
})
|
||||
}
|
||||
|
||||
(Poll::Ready(Ok(n)), empty)
|
||||
}
|
||||
fn fill_buf<'a>(info: &'static Info) -> impl Future<Output = Result<&'a [u8], Error>> {
|
||||
poll_fn(move |cx| {
|
||||
let rx_reader = unsafe { info.state.rx_buf.reader() };
|
||||
let (p, n) = rx_reader.pop_buf();
|
||||
if n == 0 {
|
||||
info.state.rx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
fn flush(&mut self, waker: &Waker) -> Poll<Result<(), Error>> {
|
||||
if !self.buf.is_empty() {
|
||||
self.waker.register(waker);
|
||||
let buf = unsafe { slice::from_raw_parts(p, n) };
|
||||
Poll::Ready(Ok(buf))
|
||||
})
|
||||
}
|
||||
|
||||
fn consume(info: &'static Info, amt: usize) {
|
||||
let rx_reader = unsafe { info.state.rx_buf.reader() };
|
||||
rx_reader.pop_done(amt)
|
||||
}
|
||||
|
||||
fn write<'a>(info: &'static Info, buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||
poll_fn(move |cx| {
|
||||
let tx_writer = unsafe { info.state.tx_buf.writer() };
|
||||
let n = tx_writer.push(|data| {
|
||||
let n = data.len().min(buf.len());
|
||||
data[..n].copy_from_slice(&buf[..n]);
|
||||
n
|
||||
});
|
||||
if n == 0 {
|
||||
info.state.tx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
} else {
|
||||
NVIC::pend(info.irq);
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn flush(info: &'static Info) -> impl Future<Output = Result<(), Error>> {
|
||||
poll_fn(move |cx| {
|
||||
if !info.state.tx_buf.is_empty() {
|
||||
info.state.tx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T>
|
||||
where
|
||||
Self: 'd,
|
||||
{
|
||||
type Interrupt = T::Interrupt;
|
||||
fn on_interrupt(&mut self) {
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
let buf = self.buf.pop_buf();
|
||||
if !buf.is_empty() {
|
||||
r.uartimsc().modify(|w| {
|
||||
w.set_txim(true);
|
||||
});
|
||||
r.uartdr().write(|w| w.set_data(buf[0].into()));
|
||||
self.buf.pop(1);
|
||||
self.waker.wake();
|
||||
} else {
|
||||
// Disable interrupt until we have something to transmit again
|
||||
r.uartimsc().modify(|w| {
|
||||
w.set_txim(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl embedded_io::Error for Error {
|
||||
@ -342,117 +338,73 @@ impl embedded_io::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> {
|
||||
impl<'d> embedded_io::Io for BufferedUart<'d> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::Io for BufferedUartRx<'d, T> {
|
||||
impl<'d> embedded_io::Io for BufferedUartRx<'d> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> {
|
||||
impl<'d> embedded_io::Io for BufferedUartTx<'d> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
|
||||
impl<'d> embedded_io::asynch::Read for BufferedUart<'d> {
|
||||
type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
let (res, do_pend) = self.inner.with(|state| {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
state.rx.read(buf, cx.waker())
|
||||
});
|
||||
|
||||
if do_pend {
|
||||
self.inner.pend();
|
||||
}
|
||||
|
||||
res
|
||||
})
|
||||
read(self.info, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> {
|
||||
impl<'d> embedded_io::asynch::Read for BufferedUartRx<'d> {
|
||||
type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
let (res, do_pend) = self.inner.with(|state| {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
state.read(buf, cx.waker())
|
||||
});
|
||||
|
||||
if do_pend {
|
||||
self.inner.pend();
|
||||
}
|
||||
|
||||
res
|
||||
})
|
||||
read(self.info, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
|
||||
impl<'d> embedded_io::asynch::BufRead for BufferedUart<'d> {
|
||||
type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
self.inner.with(|state| {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
state.rx.fill_buf(cx.waker())
|
||||
})
|
||||
})
|
||||
fill_buf(self.info)
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
let signal = self.inner.with(|state| state.rx.consume(amt));
|
||||
if signal {
|
||||
self.inner.pend();
|
||||
}
|
||||
consume(self.info, amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> {
|
||||
impl<'d> embedded_io::asynch::BufRead for BufferedUartRx<'d> {
|
||||
type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
self.inner.with(|state| {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
state.fill_buf(cx.waker())
|
||||
})
|
||||
})
|
||||
fill_buf(self.info)
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
let signal = self.inner.with(|state| state.consume(amt));
|
||||
if signal {
|
||||
self.inner.pend();
|
||||
}
|
||||
consume(self.info, amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
|
||||
impl<'d> embedded_io::asynch::Write for BufferedUart<'d> {
|
||||
type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker()));
|
||||
if empty {
|
||||
self.inner.pend();
|
||||
}
|
||||
poll
|
||||
})
|
||||
write(self.info, buf)
|
||||
}
|
||||
|
||||
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
|
||||
@ -460,23 +412,17 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
|
||||
Self: 'a;
|
||||
|
||||
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
|
||||
poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker())))
|
||||
flush(self.info)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> {
|
||||
impl<'d> embedded_io::asynch::Write for BufferedUartTx<'d> {
|
||||
type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
poll_fn(move |cx| {
|
||||
let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker()));
|
||||
if empty {
|
||||
self.inner.pend();
|
||||
}
|
||||
poll
|
||||
})
|
||||
write(self.info, buf)
|
||||
}
|
||||
|
||||
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
|
||||
@ -484,6 +430,6 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T>
|
||||
Self: 'a;
|
||||
|
||||
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
|
||||
poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker())))
|
||||
flush(self.info)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,13 @@ use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use crate::dma::{AnyChannel, Channel};
|
||||
use crate::gpio::sealed::Pin;
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::{pac, peripherals, Peripheral};
|
||||
use crate::pac::uart as pac;
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod buffered;
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use buffered::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum DataBits {
|
||||
@ -77,31 +83,26 @@ pub enum Error {
|
||||
Framing,
|
||||
}
|
||||
|
||||
pub struct Uart<'d, T: Instance, M: Mode> {
|
||||
tx: UartTx<'d, T, M>,
|
||||
rx: UartRx<'d, T, M>,
|
||||
pub struct Uart<'d, M: Mode> {
|
||||
tx: UartTx<'d, M>,
|
||||
rx: UartRx<'d, M>,
|
||||
}
|
||||
|
||||
pub struct UartTx<'d, T: Instance, M: Mode> {
|
||||
pub struct UartTx<'d, M: Mode> {
|
||||
info: &'static Info,
|
||||
tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
phantom: PhantomData<(&'d mut T, M)>,
|
||||
phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
pub struct UartRx<'d, T: Instance, M: Mode> {
|
||||
pub struct UartRx<'d, M: Mode> {
|
||||
info: &'static Info,
|
||||
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
phantom: PhantomData<(&'d mut T, M)>,
|
||||
phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
fn new(tx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
||||
Self {
|
||||
tx_dma,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: Mode> UartTx<'d, M> {
|
||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
unsafe {
|
||||
for &b in buffer {
|
||||
while r.uartfr().read().txff() {}
|
||||
@ -112,38 +113,31 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
}
|
||||
|
||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
unsafe { while !r.uartfr().read().txfe() {} }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartTx<'d, T, Async> {
|
||||
impl<'d> UartTx<'d, Async> {
|
||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
let ch = self.tx_dma.as_mut().unwrap();
|
||||
let transfer = unsafe {
|
||||
T::regs().uartdmacr().modify(|reg| {
|
||||
self.info.regs.uartdmacr().modify(|reg| {
|
||||
reg.set_txdmae(true);
|
||||
});
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ)
|
||||
crate::dma::write(ch, buffer, self.info.regs.uartdr().ptr() as *mut _, self.info.tx_dreq)
|
||||
};
|
||||
transfer.await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||
fn new(rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
||||
Self {
|
||||
rx_dma,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: Mode> UartRx<'d, M> {
|
||||
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
unsafe {
|
||||
for b in buffer {
|
||||
*b = loop {
|
||||
@ -171,37 +165,37 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
impl<'d> UartRx<'d, Async> {
|
||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
let ch = self.rx_dma.as_mut().unwrap();
|
||||
let transfer = unsafe {
|
||||
T::regs().uartdmacr().modify(|reg| {
|
||||
self.info.regs.uartdmacr().modify(|reg| {
|
||||
reg.set_rxdmae(true);
|
||||
});
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ)
|
||||
crate::dma::read(ch, self.info.regs.uartdr().ptr() as *const _, buffer, self.info.rx_dreq)
|
||||
};
|
||||
transfer.await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
impl<'d> Uart<'d, Blocking> {
|
||||
/// Create a new UART without hardware flow control
|
||||
pub fn new_blocking(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
pub fn new_blocking<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(tx, rx);
|
||||
Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, None, None, config)
|
||||
Self::new_inner(T::info(), tx.map_into(), rx.map_into(), None, None, None, None, config)
|
||||
}
|
||||
|
||||
/// Create a new UART with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts_blocking(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
pub fn new_with_rtscts_blocking<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
@ -210,9 +204,9 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
) -> Self {
|
||||
into_ref!(tx, rx, cts, rts);
|
||||
Self::new_inner(
|
||||
uart,
|
||||
rx.map_into(),
|
||||
T::info(),
|
||||
tx.map_into(),
|
||||
rx.map_into(),
|
||||
Some(rts.map_into()),
|
||||
Some(cts.map_into()),
|
||||
None,
|
||||
@ -222,10 +216,10 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
impl<'d> Uart<'d, Async> {
|
||||
/// Create a new DMA enabled UART without hardware flow control
|
||||
pub fn new(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
pub fn new<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl Channel> + 'd,
|
||||
@ -234,9 +228,9 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
) -> Self {
|
||||
into_ref!(tx, rx, tx_dma, rx_dma);
|
||||
Self::new_inner(
|
||||
uart,
|
||||
rx.map_into(),
|
||||
T::info(),
|
||||
tx.map_into(),
|
||||
rx.map_into(),
|
||||
None,
|
||||
None,
|
||||
Some(tx_dma.map_into()),
|
||||
@ -246,8 +240,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
}
|
||||
|
||||
/// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
pub fn new_with_rtscts<T: Instance>(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
@ -258,7 +252,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
) -> Self {
|
||||
into_ref!(tx, rx, cts, rts, tx_dma, rx_dma);
|
||||
Self::new_inner(
|
||||
uart,
|
||||
T::info(),
|
||||
rx.map_into(),
|
||||
tx.map_into(),
|
||||
Some(rts.map_into()),
|
||||
@ -270,104 +264,120 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> Uart<'d, M> {
|
||||
fn new_inner(
|
||||
_uart: impl Peripheral<P = T> + 'd,
|
||||
tx: PeripheralRef<'d, AnyPin>,
|
||||
rx: PeripheralRef<'d, AnyPin>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
info: &'static Info,
|
||||
mut tx: PeripheralRef<'d, AnyPin>,
|
||||
mut rx: PeripheralRef<'d, AnyPin>,
|
||||
mut rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mut cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(_uart);
|
||||
|
||||
unsafe {
|
||||
let r = T::regs();
|
||||
|
||||
tx.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
rx.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
|
||||
tx.pad_ctrl().write(|w| {
|
||||
w.set_ie(true);
|
||||
});
|
||||
|
||||
rx.pad_ctrl().write(|w| {
|
||||
w.set_ie(true);
|
||||
});
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| {
|
||||
w.set_ie(true);
|
||||
});
|
||||
}
|
||||
if let Some(pin) = &rts {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| {
|
||||
w.set_ie(true);
|
||||
});
|
||||
}
|
||||
|
||||
let clk_base = crate::clocks::clk_peri_freq();
|
||||
|
||||
let baud_rate_div = (8 * clk_base) / config.baudrate;
|
||||
let mut baud_ibrd = baud_rate_div >> 7;
|
||||
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
|
||||
|
||||
if baud_ibrd == 0 {
|
||||
baud_ibrd = 1;
|
||||
baud_fbrd = 0;
|
||||
} else if baud_ibrd >= 65535 {
|
||||
baud_ibrd = 65535;
|
||||
baud_fbrd = 0;
|
||||
}
|
||||
|
||||
// Load PL011's baud divisor registers
|
||||
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
||||
|
||||
let (pen, eps) = match config.parity {
|
||||
Parity::ParityNone => (false, false),
|
||||
Parity::ParityOdd => (true, false),
|
||||
Parity::ParityEven => (true, true),
|
||||
};
|
||||
|
||||
// PL011 needs a (dummy) line control register write to latch in the
|
||||
// divisors. We don't want to actually change LCR contents here.
|
||||
r.uartlcr_h().modify(|_| {});
|
||||
|
||||
r.uartlcr_h().write(|w| {
|
||||
w.set_wlen(config.data_bits.bits());
|
||||
w.set_stp2(config.stop_bits == StopBits::STOP2);
|
||||
w.set_pen(pen);
|
||||
w.set_eps(eps);
|
||||
w.set_fen(true);
|
||||
});
|
||||
|
||||
r.uartifls().write(|w| {
|
||||
w.set_rxiflsel(0b000);
|
||||
w.set_txiflsel(0b000);
|
||||
});
|
||||
|
||||
r.uartcr().write(|w| {
|
||||
w.set_uarten(true);
|
||||
w.set_rxe(true);
|
||||
w.set_txe(true);
|
||||
w.set_ctsen(cts.is_some());
|
||||
w.set_rtsen(rts.is_some());
|
||||
});
|
||||
}
|
||||
init(
|
||||
info,
|
||||
Some(tx.reborrow()),
|
||||
Some(rx.reborrow()),
|
||||
rts.as_mut().map(|x| x.reborrow()),
|
||||
cts.as_mut().map(|x| x.reborrow()),
|
||||
config,
|
||||
);
|
||||
|
||||
Self {
|
||||
tx: UartTx::new(tx_dma),
|
||||
rx: UartRx::new(rx_dma),
|
||||
tx: UartTx {
|
||||
info,
|
||||
tx_dma,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
rx: UartRx {
|
||||
info,
|
||||
rx_dma,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
fn init(
|
||||
info: &'static Info,
|
||||
tx: Option<PeripheralRef<'_, AnyPin>>,
|
||||
rx: Option<PeripheralRef<'_, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'_, AnyPin>>,
|
||||
cts: Option<PeripheralRef<'_, AnyPin>>,
|
||||
config: Config,
|
||||
) {
|
||||
let r = info.regs;
|
||||
unsafe {
|
||||
if let Some(pin) = &tx {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| w.set_ie(true));
|
||||
}
|
||||
if let Some(pin) = &rx {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| w.set_ie(true));
|
||||
}
|
||||
if let Some(pin) = &cts {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| w.set_ie(true));
|
||||
}
|
||||
if let Some(pin) = &rts {
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(2));
|
||||
pin.pad_ctrl().write(|w| w.set_ie(true));
|
||||
}
|
||||
|
||||
let clk_base = crate::clocks::clk_peri_freq();
|
||||
|
||||
let baud_rate_div = (8 * clk_base) / config.baudrate;
|
||||
let mut baud_ibrd = baud_rate_div >> 7;
|
||||
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
|
||||
|
||||
if baud_ibrd == 0 {
|
||||
baud_ibrd = 1;
|
||||
baud_fbrd = 0;
|
||||
} else if baud_ibrd >= 65535 {
|
||||
baud_ibrd = 65535;
|
||||
baud_fbrd = 0;
|
||||
}
|
||||
|
||||
// Load PL011's baud divisor registers
|
||||
r.uartibrd().write_value(pac::regs::Uartibrd(baud_ibrd));
|
||||
r.uartfbrd().write_value(pac::regs::Uartfbrd(baud_fbrd));
|
||||
|
||||
let (pen, eps) = match config.parity {
|
||||
Parity::ParityNone => (false, false),
|
||||
Parity::ParityOdd => (true, false),
|
||||
Parity::ParityEven => (true, true),
|
||||
};
|
||||
|
||||
// PL011 needs a (dummy) line control register write to latch in the
|
||||
// divisors. We don't want to actually change LCR contents here.
|
||||
r.uartlcr_h().modify(|_| {});
|
||||
|
||||
r.uartlcr_h().write(|w| {
|
||||
w.set_wlen(config.data_bits.bits());
|
||||
w.set_stp2(config.stop_bits == StopBits::STOP2);
|
||||
w.set_pen(pen);
|
||||
w.set_eps(eps);
|
||||
w.set_fen(true);
|
||||
});
|
||||
|
||||
r.uartifls().write(|w| {
|
||||
w.set_rxiflsel(0b000);
|
||||
w.set_txiflsel(0b000);
|
||||
});
|
||||
|
||||
r.uartcr().write(|w| {
|
||||
w.set_uarten(true);
|
||||
w.set_rxe(true);
|
||||
w.set_txe(true);
|
||||
w.set_ctsen(cts.is_some());
|
||||
w.set_rtsen(rts.is_some());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: Mode> Uart<'d, M> {
|
||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.tx.blocking_write(buffer)
|
||||
}
|
||||
@ -382,12 +392,12 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
|
||||
/// Split the Uart into a transmitter and receiver, which is particuarly
|
||||
/// useful when having two tasks correlating to transmitting and receiving.
|
||||
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
|
||||
pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
impl<'d> Uart<'d, Async> {
|
||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.tx.write(buffer).await
|
||||
}
|
||||
@ -400,10 +410,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
mod eh02 {
|
||||
use super::*;
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
|
||||
type Error = Error;
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
unsafe {
|
||||
if r.uartfr().read().rxfe() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
@ -426,7 +436,7 @@ mod eh02 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -438,7 +448,7 @@ mod eh02 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
@ -446,7 +456,7 @@ mod eh02 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -474,21 +484,21 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_1::serial::ErrorType for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_1::serial::ErrorType for UartTx<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
unsafe {
|
||||
let dr = r.uartdr().read();
|
||||
|
||||
@ -509,7 +519,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, M> {
|
||||
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(buffer)
|
||||
}
|
||||
@ -519,7 +529,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -529,13 +539,13 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_1::serial::Write for Uart<'d, M> {
|
||||
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(buffer)
|
||||
}
|
||||
@ -545,7 +555,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -566,7 +576,7 @@ mod eha {
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Write for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_async::serial::Write for UartTx<'d, M> {
|
||||
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
||||
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
@ -580,7 +590,7 @@ mod eha {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Read for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_async::serial::Read for UartRx<'d, M> {
|
||||
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
@ -588,7 +598,7 @@ mod eha {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Write for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_async::serial::Write for Uart<'d, M> {
|
||||
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
||||
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
@ -602,7 +612,7 @@ mod eha {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Read for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_async::serial::Read for Uart<'d, M> {
|
||||
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
@ -611,30 +621,32 @@ mod eha {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod buffered;
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use buffered::*;
|
||||
|
||||
mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub trait Mode {}
|
||||
|
||||
pub trait Instance {
|
||||
const TX_DREQ: u8;
|
||||
const RX_DREQ: u8;
|
||||
|
||||
type Interrupt: crate::interrupt::Interrupt;
|
||||
|
||||
fn regs() -> pac::uart::Uart;
|
||||
fn info() -> &'static Info;
|
||||
}
|
||||
pub trait TxPin<T: Instance> {}
|
||||
pub trait RxPin<T: Instance> {}
|
||||
pub trait CtsPin<T: Instance> {}
|
||||
pub trait RtsPin<T: Instance> {}
|
||||
|
||||
/// Info about one concrete peripheral instance.
|
||||
pub struct Info {
|
||||
pub(crate) regs: pac::Uart,
|
||||
pub(crate) tx_dreq: u8,
|
||||
pub(crate) rx_dreq: u8,
|
||||
pub(crate) irq: crate::pac::Interrupt,
|
||||
pub(crate) state: &'static super::buffered::State,
|
||||
}
|
||||
}
|
||||
|
||||
use sealed::Info;
|
||||
|
||||
pub trait Mode: sealed::Mode {}
|
||||
|
||||
macro_rules! impl_mode {
|
||||
@ -655,16 +667,27 @@ pub trait Instance: sealed::Instance {}
|
||||
macro_rules! impl_instance {
|
||||
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||
impl sealed::Instance for peripherals::$inst {
|
||||
const TX_DREQ: u8 = $tx_dreq;
|
||||
const RX_DREQ: u8 = $rx_dreq;
|
||||
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
|
||||
fn regs() -> pac::uart::Uart {
|
||||
pac::$inst
|
||||
fn info() -> &'static Info {
|
||||
static STATE: buffered::State = buffered::State::new();
|
||||
static INFO: Info = Info {
|
||||
regs: crate::pac::$inst,
|
||||
tx_dreq: $tx_dreq,
|
||||
rx_dreq: $rx_dreq,
|
||||
irq: crate::pac::Interrupt::$irq,
|
||||
state: &STATE,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
}
|
||||
impl Instance for peripherals::$inst {}
|
||||
|
||||
impl crate::interrupt::InterruptFunction for crate::interrupt::$irq {
|
||||
fn on_interrupt() {
|
||||
buffered::on_interrupt(<peripherals::$inst as sealed::Instance>::info())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{AdcPin, Instance};
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::rcc::get_freqs;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
@ -29,69 +27,9 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||
}
|
||||
}
|
||||
|
||||
mod sample_time {
|
||||
/// ADC sample time
|
||||
///
|
||||
/// The default setting is 1.5 ADC clock cycles.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
/// 1.5 ADC clock cycles
|
||||
Cycles1_5 = 0b000,
|
||||
|
||||
/// 7.5 ADC clock cycles
|
||||
Cycles7_5 = 0b001,
|
||||
|
||||
/// 13.5 ADC clock cycles
|
||||
Cycles13_5 = 0b010,
|
||||
|
||||
/// 28.5 ADC clock cycles
|
||||
Cycles28_5 = 0b011,
|
||||
|
||||
/// 41.5 ADC clock cycles
|
||||
Cycles41_5 = 0b100,
|
||||
|
||||
/// 55.5 ADC clock cycles
|
||||
Cycles55_5 = 0b101,
|
||||
|
||||
/// 71.5 ADC clock cycles
|
||||
Cycles71_5 = 0b110,
|
||||
|
||||
/// 239.5 ADC clock cycles
|
||||
Cycles239_5 = 0b111,
|
||||
}
|
||||
|
||||
impl SampleTime {
|
||||
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
||||
match self {
|
||||
SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
|
||||
SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
|
||||
SampleTime::Cycles13_5 => crate::pac::adc::vals::SampleTime::CYCLES13_5,
|
||||
SampleTime::Cycles28_5 => crate::pac::adc::vals::SampleTime::CYCLES28_5,
|
||||
SampleTime::Cycles41_5 => crate::pac::adc::vals::SampleTime::CYCLES41_5,
|
||||
SampleTime::Cycles55_5 => crate::pac::adc::vals::SampleTime::CYCLES55_5,
|
||||
SampleTime::Cycles71_5 => crate::pac::adc::vals::SampleTime::CYCLES71_5,
|
||||
SampleTime::Cycles239_5 => crate::pac::adc::vals::SampleTime::CYCLES239_5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::Cycles28_5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use sample_time::SampleTime;
|
||||
|
||||
pub struct Adc<'d, T: Instance> {
|
||||
sample_time: SampleTime,
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(_peri);
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
unsafe {
|
||||
@ -120,8 +58,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
delay.delay_us((1_000_000) / Self::freq().0 + 1);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
sample_time: Default::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,14 +139,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
let sample_time = sample_time.into();
|
||||
if ch <= 9 {
|
||||
T::regs()
|
||||
.smpr2()
|
||||
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
|
||||
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||
} else {
|
||||
T::regs()
|
||||
.smpr1()
|
||||
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
|
||||
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,38 @@
|
||||
#![macro_use]
|
||||
|
||||
#[cfg_attr(adc_v4, path = "v4.rs")]
|
||||
#[cfg_attr(adc_v3, path = "v3.rs")]
|
||||
#[cfg_attr(adc_v2, path = "v2.rs")]
|
||||
#[cfg_attr(adc_g0, path = "v3.rs")]
|
||||
#[cfg_attr(adc_f1, path = "f1.rs")]
|
||||
#[cfg_attr(adc_v1, path = "v1.rs")]
|
||||
#[cfg_attr(adc_v2, path = "v2.rs")]
|
||||
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
|
||||
#[cfg_attr(adc_v4, path = "v4.rs")]
|
||||
mod _version;
|
||||
|
||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||
mod resolution;
|
||||
#[cfg(not(adc_v1))]
|
||||
mod sample_time;
|
||||
|
||||
#[allow(unused)]
|
||||
pub use _version::*;
|
||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||
pub use resolution::Resolution;
|
||||
#[cfg(not(adc_v1))]
|
||||
pub use sample_time::SampleTime;
|
||||
|
||||
use crate::peripherals;
|
||||
|
||||
#[cfg(not(adc_v1))]
|
||||
pub struct Adc<'d, T: Instance> {
|
||||
#[allow(unused)]
|
||||
adc: crate::PeripheralRef<'d, T>,
|
||||
sample_time: SampleTime,
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::adc::Adc;
|
||||
fn regs() -> crate::pac::adc::Adc;
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon;
|
||||
}
|
||||
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
pub trait Common {
|
||||
fn regs() -> &'static crate::pac::adccommon::AdcCommon;
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||
}
|
||||
|
||||
pub trait AdcPin<T: Instance> {
|
||||
@ -34,12 +44,11 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(adc_f1, adc_v2)))]
|
||||
pub trait Instance: sealed::Instance + 'static {}
|
||||
#[cfg(any(adc_f1, adc_v2))]
|
||||
pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {}
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
pub trait Common: sealed::Common + 'static {}
|
||||
#[cfg(not(any(adc_f1, adc_v2, adc_v4)))]
|
||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
||||
#[cfg(any(adc_f1, adc_v2, adc_v4))]
|
||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
||||
|
||||
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
||||
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
||||
|
||||
@ -47,14 +56,14 @@ pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
||||
foreach_peripheral!(
|
||||
(adc, $inst:ident) => {
|
||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::adc::Adc {
|
||||
&crate::pac::$inst
|
||||
fn regs() -> crate::pac::adc::Adc {
|
||||
crate::pac::$inst
|
||||
}
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, $common_inst:ident) => {
|
||||
return &crate::pac::$common_inst
|
||||
return crate::pac::$common_inst
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -68,14 +77,14 @@ foreach_peripheral!(
|
||||
foreach_peripheral!(
|
||||
(adc, ADC3) => {
|
||||
impl crate::adc::sealed::Instance for peripherals::ADC3 {
|
||||
fn regs() -> &'static crate::pac::adc::Adc {
|
||||
&crate::pac::ADC3
|
||||
fn regs() -> crate::pac::adc::Adc {
|
||||
crate::pac::ADC3
|
||||
}
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, ADC3_COMMON) => {
|
||||
return &crate::pac::ADC3_COMMON
|
||||
return crate::pac::ADC3_COMMON
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -85,14 +94,14 @@ foreach_peripheral!(
|
||||
};
|
||||
(adc, $inst:ident) => {
|
||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::adc::Adc {
|
||||
&crate::pac::$inst
|
||||
fn regs() -> crate::pac::adc::Adc {
|
||||
crate::pac::$inst
|
||||
}
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, ADC_COMMON) => {
|
||||
return &crate::pac::ADC_COMMON
|
||||
return crate::pac::ADC_COMMON
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -102,19 +111,6 @@ foreach_peripheral!(
|
||||
};
|
||||
);
|
||||
|
||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
||||
foreach_peripheral!(
|
||||
(adccommon, $inst:ident) => {
|
||||
impl sealed::Common for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::adccommon::AdcCommon {
|
||||
&crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::adc::Common for peripherals::$inst {}
|
||||
};
|
||||
);
|
||||
|
||||
macro_rules! impl_adc_pin {
|
||||
($inst:ident, $pin:ident, $ch:expr) => {
|
||||
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
|
||||
|
63
embassy-stm32/src/adc/resolution.rs
Normal file
63
embassy-stm32/src/adc/resolution.rs
Normal file
@ -0,0 +1,63 @@
|
||||
#[cfg(any(adc_v2, adc_v3, adc_g0))]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Resolution {
|
||||
TwelveBit,
|
||||
TenBit,
|
||||
EightBit,
|
||||
SixBit,
|
||||
}
|
||||
|
||||
#[cfg(adc_v4)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Resolution {
|
||||
SixteenBit,
|
||||
FourteenBit,
|
||||
TwelveBit,
|
||||
TenBit,
|
||||
EightBit,
|
||||
}
|
||||
|
||||
impl Default for Resolution {
|
||||
fn default() -> Self {
|
||||
#[cfg(any(adc_v2, adc_v3, adc_g0))]
|
||||
{
|
||||
Self::TwelveBit
|
||||
}
|
||||
#[cfg(adc_v4)]
|
||||
{
|
||||
Self::SixteenBit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Resolution> for crate::pac::adc::vals::Res {
|
||||
fn from(res: Resolution) -> crate::pac::adc::vals::Res {
|
||||
match res {
|
||||
#[cfg(adc_v4)]
|
||||
Resolution::SixteenBit => crate::pac::adc::vals::Res::SIXTEENBIT,
|
||||
#[cfg(adc_v4)]
|
||||
Resolution::FourteenBit => crate::pac::adc::vals::Res::FOURTEENBITV,
|
||||
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
||||
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
||||
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
||||
#[cfg(any(adc_v2, adc_v3, adc_g0))]
|
||||
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
pub fn to_max_count(&self) -> u32 {
|
||||
match self {
|
||||
#[cfg(adc_v4)]
|
||||
Resolution::SixteenBit => (1 << 16) - 1,
|
||||
#[cfg(adc_v4)]
|
||||
Resolution::FourteenBit => (1 << 14) - 1,
|
||||
Resolution::TwelveBit => (1 << 12) - 1,
|
||||
Resolution::TenBit => (1 << 10) - 1,
|
||||
Resolution::EightBit => (1 << 8) - 1,
|
||||
#[cfg(any(adc_v2, adc_v3, adc_g0))]
|
||||
Resolution::SixBit => (1 << 6) - 1,
|
||||
}
|
||||
}
|
||||
}
|
111
embassy-stm32/src/adc/sample_time.rs
Normal file
111
embassy-stm32/src/adc/sample_time.rs
Normal file
@ -0,0 +1,111 @@
|
||||
macro_rules! impl_sample_time {
|
||||
($default_doc:expr, $default:ident, $pac:ty, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
|
||||
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
$(
|
||||
#[doc = concat!($doc, " ADC clock cycles.")]
|
||||
$variant,
|
||||
)*
|
||||
}
|
||||
|
||||
impl From<SampleTime> for $pac {
|
||||
fn from(sample_time: SampleTime) -> $pac {
|
||||
match sample_time {
|
||||
$(SampleTime::$variant => <$pac>::$pac_variant),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::$default
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(adc_f1)]
|
||||
impl_sample_time!(
|
||||
"1.5",
|
||||
Cycles1_5,
|
||||
crate::pac::adc::vals::SampleTime,
|
||||
(
|
||||
("1.5", Cycles1_5, CYCLES1_5),
|
||||
("7.5", Cycles7_5, CYCLES7_5),
|
||||
("13.5", Cycles13_5, CYCLES13_5),
|
||||
("28.5", Cycles28_5, CYCLES28_5),
|
||||
("41.5", Cycles41_5, CYCLES41_5),
|
||||
("55.5", Cycles55_5, CYCLES55_5),
|
||||
("71.5", Cycles71_5, CYCLES71_5),
|
||||
("239.5", Cycles239_5, CYCLES239_5)
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(adc_v2)]
|
||||
impl_sample_time!(
|
||||
"3",
|
||||
Cycles3,
|
||||
crate::pac::adc::vals::Smp,
|
||||
(
|
||||
("3", Cycles3, CYCLES3),
|
||||
("15", Cycles15, CYCLES15),
|
||||
("28", Cycles28, CYCLES28),
|
||||
("56", Cycles56, CYCLES56),
|
||||
("84", Cycles84, CYCLES84),
|
||||
("112", Cycles112, CYCLES112),
|
||||
("144", Cycles144, CYCLES144),
|
||||
("480", Cycles480, CYCLES480)
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(adc_v3)]
|
||||
impl_sample_time!(
|
||||
"2.5",
|
||||
Cycles2_5,
|
||||
crate::pac::adc::vals::SampleTime,
|
||||
(
|
||||
("2.5", Cycles2_5, CYCLES2_5),
|
||||
("6.5", Cycles6_5, CYCLES6_5),
|
||||
("12.5", Cycles12_5, CYCLES12_5),
|
||||
("24.5", Cycles24_5, CYCLES24_5),
|
||||
("47.5", Cycles47_5, CYCLES47_5),
|
||||
("92.5", Cycles92_5, CYCLES92_5),
|
||||
("247.5", Cycles247_5, CYCLES247_5),
|
||||
("640.5", Cycles640_5, CYCLES640_5)
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(adc_g0)]
|
||||
impl_sample_time!(
|
||||
"1.5",
|
||||
Cycles1_5,
|
||||
crate::pac::adc::vals::SampleTime,
|
||||
(
|
||||
("1.5", Cycles1_5, CYCLES1_5),
|
||||
("3.5", Cycles3_5, CYCLES3_5),
|
||||
("7.5", Cycles7_5, CYCLES7_5),
|
||||
("12.5", Cycles12_5, CYCLES12_5),
|
||||
("19.5", Cycles19_5, CYCLES19_5),
|
||||
("39.5", Cycles39_5, CYCLES39_5),
|
||||
("79.5", Cycles79_5, CYCLES79_5),
|
||||
("160.5", Cycles160_5, CYCLES160_5)
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(adc_v4)]
|
||||
impl_sample_time!(
|
||||
"1.5",
|
||||
Cycles1_5,
|
||||
crate::pac::adc::vals::Smp,
|
||||
(
|
||||
("1.5", Cycles1_5, CYCLES1_5),
|
||||
("2.5", Cycles2_5, CYCLES2_5),
|
||||
("8.5", Cycles8_5, CYCLES8_5),
|
||||
("16.5", Cycles16_5, CYCLES16_5),
|
||||
("32.5", Cycles32_5, CYCLES32_5),
|
||||
("64.5", Cycles64_5, CYCLES64_5),
|
||||
("387.5", Cycles387_5, CYCLES387_5),
|
||||
("810.5", Cycles810_5, CYCLES810_5)
|
||||
)
|
||||
);
|
@ -1,10 +1,8 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::InternalChannel;
|
||||
use crate::adc::{AdcPin, Instance};
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::peripherals::ADC1;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
@ -17,39 +15,6 @@ pub const VREF_CALIB_MV: u32 = 3300;
|
||||
/// ADC turn-on time
|
||||
pub const ADC_POWERUP_TIME_US: u32 = 3;
|
||||
|
||||
pub enum Resolution {
|
||||
TwelveBit,
|
||||
TenBit,
|
||||
EightBit,
|
||||
SixBit,
|
||||
}
|
||||
|
||||
impl Default for Resolution {
|
||||
fn default() -> Self {
|
||||
Self::TwelveBit
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
fn res(&self) -> crate::pac::adc::vals::Res {
|
||||
match self {
|
||||
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
||||
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
||||
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
||||
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_max_count(&self) -> u32 {
|
||||
match self {
|
||||
Resolution::TwelveBit => (1 << 12) - 1,
|
||||
Resolution::TenBit => (1 << 10) - 1,
|
||||
Resolution::EightBit => (1 << 8) - 1,
|
||||
Resolution::SixBit => (1 << 6) - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VrefInt;
|
||||
impl InternalChannel<ADC1> for VrefInt {}
|
||||
impl super::sealed::InternalChannel<ADC1> for VrefInt {
|
||||
@ -94,42 +59,6 @@ impl super::sealed::InternalChannel<ADC1> for Vbat {
|
||||
}
|
||||
}
|
||||
|
||||
/// ADC sample time
|
||||
///
|
||||
/// The default setting is 3 ADC clock cycles.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
Cycles3 = 0b000,
|
||||
Cycles15 = 0b001,
|
||||
Cycles28 = 0b010,
|
||||
Cycles56 = 0b011,
|
||||
Cycles85 = 0b100,
|
||||
Cycles112 = 0b101,
|
||||
Cycles144 = 0b110,
|
||||
Cycles480 = 0b111,
|
||||
}
|
||||
|
||||
impl SampleTime {
|
||||
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp {
|
||||
match self {
|
||||
SampleTime::Cycles3 => crate::pac::adc::vals::Smp::CYCLES3,
|
||||
SampleTime::Cycles15 => crate::pac::adc::vals::Smp::CYCLES15,
|
||||
SampleTime::Cycles28 => crate::pac::adc::vals::Smp::CYCLES28,
|
||||
SampleTime::Cycles56 => crate::pac::adc::vals::Smp::CYCLES56,
|
||||
SampleTime::Cycles85 => crate::pac::adc::vals::Smp::CYCLES84,
|
||||
SampleTime::Cycles112 => crate::pac::adc::vals::Smp::CYCLES112,
|
||||
SampleTime::Cycles144 => crate::pac::adc::vals::Smp::CYCLES144,
|
||||
SampleTime::Cycles480 => crate::pac::adc::vals::Smp::CYCLES480,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::Cycles3
|
||||
}
|
||||
}
|
||||
|
||||
enum Prescaler {
|
||||
Div2,
|
||||
Div4,
|
||||
@ -161,18 +90,12 @@ impl Prescaler {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Adc<'d, T: Instance> {
|
||||
sample_time: SampleTime,
|
||||
resolution: Resolution,
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
impl<'d, T> Adc<'d, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(_peri);
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
@ -188,9 +111,8 @@ where
|
||||
delay.delay_us(ADC_POWERUP_TIME_US);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
sample_time: Default::default(),
|
||||
resolution: Resolution::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +121,9 @@ where
|
||||
}
|
||||
|
||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||
self.resolution = resolution;
|
||||
unsafe {
|
||||
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables internal voltage reference and returns [VrefInt], which can be used in
|
||||
@ -283,7 +207,6 @@ where
|
||||
|
||||
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
|
||||
// Configure ADC
|
||||
T::regs().cr1().modify(|reg| reg.set_res(self.resolution.res()));
|
||||
|
||||
// Select channel
|
||||
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
|
||||
@ -297,14 +220,11 @@ where
|
||||
}
|
||||
|
||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
let sample_time = sample_time.into();
|
||||
if ch <= 9 {
|
||||
T::regs()
|
||||
.smpr2()
|
||||
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
|
||||
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||
} else {
|
||||
T::regs()
|
||||
.smpr1()
|
||||
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
|
||||
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{AdcPin, Instance};
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::Peripheral;
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
@ -24,39 +22,6 @@ fn enable() {
|
||||
});
|
||||
}
|
||||
|
||||
pub enum Resolution {
|
||||
TwelveBit,
|
||||
TenBit,
|
||||
EightBit,
|
||||
SixBit,
|
||||
}
|
||||
|
||||
impl Default for Resolution {
|
||||
fn default() -> Self {
|
||||
Self::TwelveBit
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
fn res(&self) -> crate::pac::adc::vals::Res {
|
||||
match self {
|
||||
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
||||
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
||||
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
||||
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_max_count(&self) -> u32 {
|
||||
match self {
|
||||
Resolution::TwelveBit => (1 << 12) - 1,
|
||||
Resolution::TenBit => (1 << 10) - 1,
|
||||
Resolution::EightBit => (1 << 8) - 1,
|
||||
Resolution::SixBit => (1 << 6) - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VrefInt;
|
||||
impl<T: Instance> AdcPin<T> for VrefInt {}
|
||||
impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
|
||||
@ -93,125 +58,9 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(adc_g0))]
|
||||
mod sample_time {
|
||||
/// ADC sample time
|
||||
///
|
||||
/// The default setting is 2.5 ADC clock cycles.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
/// 2.5 ADC clock cycles
|
||||
Cycles2_5 = 0b000,
|
||||
|
||||
/// 6.5 ADC clock cycles
|
||||
Cycles6_5 = 0b001,
|
||||
|
||||
/// 12.5 ADC clock cycles
|
||||
Cycles12_5 = 0b010,
|
||||
|
||||
/// 24.5 ADC clock cycles
|
||||
Cycles24_5 = 0b011,
|
||||
|
||||
/// 47.5 ADC clock cycles
|
||||
Cycles47_5 = 0b100,
|
||||
|
||||
/// 92.5 ADC clock cycles
|
||||
Cycles92_5 = 0b101,
|
||||
|
||||
/// 247.5 ADC clock cycles
|
||||
Cycles247_5 = 0b110,
|
||||
|
||||
/// 640.5 ADC clock cycles
|
||||
Cycles640_5 = 0b111,
|
||||
}
|
||||
|
||||
impl SampleTime {
|
||||
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
||||
match self {
|
||||
SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5,
|
||||
SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5,
|
||||
SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
|
||||
SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5,
|
||||
SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5,
|
||||
SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5,
|
||||
SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5,
|
||||
SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::Cycles2_5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(adc_g0)]
|
||||
mod sample_time {
|
||||
/// ADC sample time
|
||||
///
|
||||
/// The default setting is 1.5 ADC clock cycles.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
/// 1.5 ADC clock cycles
|
||||
Cycles1_5 = 0b000,
|
||||
|
||||
/// 3.5 ADC clock cycles
|
||||
Cycles3_5 = 0b001,
|
||||
|
||||
/// 7.5 ADC clock cycles
|
||||
Cycles7_5 = 0b010,
|
||||
|
||||
/// 12.5 ADC clock cycles
|
||||
Cycles12_5 = 0b011,
|
||||
|
||||
/// 19.5 ADC clock cycles
|
||||
Cycles19_5 = 0b100,
|
||||
|
||||
/// 39.5 ADC clock cycles
|
||||
Cycles39_5 = 0b101,
|
||||
|
||||
/// 79.5 ADC clock cycles
|
||||
Cycles79_5 = 0b110,
|
||||
|
||||
/// 160.5 ADC clock cycles
|
||||
Cycles160_5 = 0b111,
|
||||
}
|
||||
|
||||
impl SampleTime {
|
||||
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
|
||||
match self {
|
||||
SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
|
||||
SampleTime::Cycles3_5 => crate::pac::adc::vals::SampleTime::CYCLES3_5,
|
||||
SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
|
||||
SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
|
||||
SampleTime::Cycles19_5 => crate::pac::adc::vals::SampleTime::CYCLES19_5,
|
||||
SampleTime::Cycles39_5 => crate::pac::adc::vals::SampleTime::CYCLES39_5,
|
||||
SampleTime::Cycles79_5 => crate::pac::adc::vals::SampleTime::CYCLES79_5,
|
||||
SampleTime::Cycles160_5 => crate::pac::adc::vals::SampleTime::CYCLES160_5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::Cycles1_5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use sample_time::SampleTime;
|
||||
|
||||
pub struct Adc<'d, T: Instance> {
|
||||
sample_time: SampleTime,
|
||||
resolution: Resolution,
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(_peri);
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
enable();
|
||||
unsafe {
|
||||
T::regs().cr().modify(|reg| {
|
||||
@ -241,9 +90,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
delay.delay_us(1);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
sample_time: Default::default(),
|
||||
resolution: Resolution::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +136,12 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||
self.resolution = resolution;
|
||||
unsafe {
|
||||
#[cfg(not(stm32g0))]
|
||||
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
||||
#[cfg(stm32g0)]
|
||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -340,12 +193,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
// spin
|
||||
}
|
||||
|
||||
// Configure ADC
|
||||
#[cfg(not(stm32g0))]
|
||||
T::regs().cfgr().modify(|reg| reg.set_res(self.resolution.res()));
|
||||
#[cfg(stm32g0)]
|
||||
T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res()));
|
||||
|
||||
// Configure channel
|
||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||
|
||||
@ -374,19 +221,16 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
|
||||
#[cfg(stm32g0)]
|
||||
unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
|
||||
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.sample_time()));
|
||||
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
|
||||
}
|
||||
|
||||
#[cfg(not(stm32g0))]
|
||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
let sample_time = sample_time.into();
|
||||
if ch <= 9 {
|
||||
T::regs()
|
||||
.smpr1()
|
||||
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
|
||||
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||
} else {
|
||||
T::regs()
|
||||
.smpr2()
|
||||
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
|
||||
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use atomic_polyfill::{AtomicU8, Ordering};
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
|
||||
use pac::adccommon::vals::Presc;
|
||||
|
||||
use super::{AdcPin, Instance, InternalChannel};
|
||||
use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -14,42 +12,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
||||
pub const VREF_CALIB_MV: u32 = 3300;
|
||||
|
||||
pub enum Resolution {
|
||||
SixteenBit,
|
||||
FourteenBit,
|
||||
TwelveBit,
|
||||
TenBit,
|
||||
EightBit,
|
||||
}
|
||||
|
||||
impl Default for Resolution {
|
||||
fn default() -> Self {
|
||||
Self::SixteenBit
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
fn res(&self) -> pac::adc::vals::Res {
|
||||
match self {
|
||||
Resolution::SixteenBit => pac::adc::vals::Res::SIXTEENBIT,
|
||||
Resolution::FourteenBit => pac::adc::vals::Res::FOURTEENBITV,
|
||||
Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBITV,
|
||||
Resolution::TenBit => pac::adc::vals::Res::TENBIT,
|
||||
Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_max_count(&self) -> u32 {
|
||||
match self {
|
||||
Resolution::SixteenBit => (1 << 16) - 1,
|
||||
Resolution::FourteenBit => (1 << 14) - 1,
|
||||
Resolution::TwelveBit => (1 << 12) - 1,
|
||||
Resolution::TenBit => (1 << 10) - 1,
|
||||
Resolution::EightBit => (1 << 8) - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
|
||||
pub struct VrefInt;
|
||||
impl<T: Instance> InternalChannel<T> for VrefInt {}
|
||||
@ -193,57 +155,6 @@ foreach_peripheral!(
|
||||
};
|
||||
);
|
||||
|
||||
/// ADC sample time
|
||||
///
|
||||
/// The default setting is 2.5 ADC clock cycles.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum SampleTime {
|
||||
/// 1.5 ADC clock cycles
|
||||
Cycles1_5,
|
||||
|
||||
/// 2.5 ADC clock cycles
|
||||
Cycles2_5,
|
||||
|
||||
/// 8.5 ADC clock cycles
|
||||
Cycles8_5,
|
||||
|
||||
/// 16.5 ADC clock cycles
|
||||
Cycles16_5,
|
||||
|
||||
/// 32.5 ADC clock cycles
|
||||
Cycles32_5,
|
||||
|
||||
/// 64.5 ADC clock cycles
|
||||
Cycles64_5,
|
||||
|
||||
/// 387.5 ADC clock cycles
|
||||
Cycles387_5,
|
||||
|
||||
/// 810.5 ADC clock cycles
|
||||
Cycles810_5,
|
||||
}
|
||||
|
||||
impl SampleTime {
|
||||
pub(crate) fn sample_time(&self) -> pac::adc::vals::Smp {
|
||||
match self {
|
||||
SampleTime::Cycles1_5 => pac::adc::vals::Smp::CYCLES1_5,
|
||||
SampleTime::Cycles2_5 => pac::adc::vals::Smp::CYCLES2_5,
|
||||
SampleTime::Cycles8_5 => pac::adc::vals::Smp::CYCLES8_5,
|
||||
SampleTime::Cycles16_5 => pac::adc::vals::Smp::CYCLES16_5,
|
||||
SampleTime::Cycles32_5 => pac::adc::vals::Smp::CYCLES32_5,
|
||||
SampleTime::Cycles64_5 => pac::adc::vals::Smp::CYCLES64_5,
|
||||
SampleTime::Cycles387_5 => pac::adc::vals::Smp::CYCLES387_5,
|
||||
SampleTime::Cycles810_5 => pac::adc::vals::Smp::CYCLES810_5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SampleTime {
|
||||
fn default() -> Self {
|
||||
Self::Cycles1_5
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
|
||||
// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
|
||||
#[allow(unused)]
|
||||
@ -312,15 +223,9 @@ impl Prescaler {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Adc<'d, T: Instance> {
|
||||
sample_time: SampleTime,
|
||||
resolution: Resolution,
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
|
||||
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
|
||||
embassy_hal_common::into_ref!(_peri);
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
|
||||
embassy_hal_common::into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
@ -350,9 +255,8 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
|
||||
}
|
||||
|
||||
let mut s = Self {
|
||||
adc,
|
||||
sample_time: Default::default(),
|
||||
resolution: Resolution::default(),
|
||||
phantom: PhantomData,
|
||||
};
|
||||
s.power_up(delay);
|
||||
s.configure_differential_inputs();
|
||||
@ -454,7 +358,9 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
|
||||
}
|
||||
|
||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||
self.resolution = resolution;
|
||||
unsafe {
|
||||
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a single conversion.
|
||||
@ -495,9 +401,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
|
||||
}
|
||||
|
||||
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
|
||||
// Configure ADC
|
||||
T::regs().cfgr().modify(|reg| reg.set_res(self.resolution.res()));
|
||||
|
||||
// Configure channel
|
||||
Self::set_channel_sample_time(channel, self.sample_time);
|
||||
|
||||
@ -514,14 +417,11 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
|
||||
}
|
||||
|
||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
let sample_time = sample_time.into();
|
||||
if ch <= 9 {
|
||||
T::regs()
|
||||
.smpr(0)
|
||||
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
|
||||
T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||
} else {
|
||||
T::regs()
|
||||
.smpr(1)
|
||||
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
|
||||
T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,51 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {}
|
||||
|
||||
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
pub fn new(
|
||||
state: &'d mut State<'d, T>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> BufferedUart<'d, T> {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
pub fn new_with_rtscts(
|
||||
state: &'d mut State<'d, T>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> BufferedUart<'d, T> {
|
||||
into_ref!(cts, rts);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
unsafe {
|
||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||
T::regs().cr3().write(|w| {
|
||||
w.set_rtse(true);
|
||||
w.set_ctse(true);
|
||||
});
|
||||
}
|
||||
|
||||
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
state: &'d mut State<'d, T>,
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
@ -56,34 +101,17 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
) -> BufferedUart<'d, T> {
|
||||
into_ref!(_peri, rx, tx, irq);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER);
|
||||
|
||||
unsafe {
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
}
|
||||
|
||||
r.cr2().write(|_w| {});
|
||||
r.cr3().write(|_w| {});
|
||||
r.cr1().write(|w| {
|
||||
w.set_ue(true);
|
||||
w.set_te(true);
|
||||
w.set_re(true);
|
||||
w.set_m0(if config.parity != Parity::ParityNone {
|
||||
vals::M0::BIT9
|
||||
} else {
|
||||
vals::M0::BIT8
|
||||
});
|
||||
w.set_pce(config.parity != Parity::ParityNone);
|
||||
w.set_ps(match config.parity {
|
||||
Parity::ParityOdd => vals::Ps::ODD,
|
||||
Parity::ParityEven => vals::Ps::EVEN,
|
||||
_ => vals::Ps::EVEN,
|
||||
});
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
|
||||
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
w.set_rxneie(true);
|
||||
w.set_idleie(true);
|
||||
});
|
||||
|
@ -102,7 +102,59 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
|
||||
}
|
||||
|
||||
impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
||||
fn new(tx_dma: PeripheralRef<'d, TxDma>) -> Self {
|
||||
/// usefull if you only want Uart Tx. It saves 1 pin and consumes a little less power
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(peri, tx, tx_dma, config)
|
||||
}
|
||||
|
||||
pub fn new_with_cts(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(cts);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
unsafe {
|
||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||
T::regs().cr3().write(|w| {
|
||||
w.set_ctse(true);
|
||||
});
|
||||
}
|
||||
Self::new_inner(peri, tx, tx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(_peri, tx, tx_dma);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
unsafe {
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, false, true);
|
||||
|
||||
// create state once!
|
||||
let _s = T::state();
|
||||
|
||||
Self {
|
||||
tx_dma,
|
||||
phantom: PhantomData,
|
||||
@ -156,44 +208,52 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, irq, rx, rx_dma);
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(peri, irq, rx, rx_dma, config)
|
||||
}
|
||||
|
||||
pub fn new_with_rts(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rts);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||
T::regs().cr3().write(|w| {
|
||||
w.set_rtse(true);
|
||||
});
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER);
|
||||
Self::new_inner(peri, irq, rx, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, irq, rx, rx_dma);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
unsafe {
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
|
||||
r.cr2().write(|_w| {});
|
||||
r.cr3().write(|w| {
|
||||
// enable Error Interrupt: (Frame error, Noise error, Overrun error)
|
||||
w.set_eie(true);
|
||||
});
|
||||
r.cr1().write(|w| {
|
||||
// enable uart
|
||||
w.set_ue(true);
|
||||
// enable receiver
|
||||
w.set_re(true);
|
||||
// configure word size
|
||||
w.set_m0(if config.parity != Parity::ParityNone {
|
||||
vals::M0::BIT9
|
||||
} else {
|
||||
vals::M0::BIT8
|
||||
});
|
||||
// configure parity
|
||||
w.set_pce(config.parity != Parity::ParityNone);
|
||||
w.set_ps(match config.parity {
|
||||
Parity::ParityOdd => vals::Ps::ODD,
|
||||
Parity::ParityEven => vals::Ps::EVEN,
|
||||
_ => vals::Ps::EVEN,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, false);
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
@ -465,7 +525,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
}
|
||||
}
|
||||
|
||||
if sr.idle() {
|
||||
if enable_idle_line_detection && sr.idle() {
|
||||
// Idle line
|
||||
|
||||
// stop dma transfer
|
||||
@ -563,31 +623,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER);
|
||||
|
||||
unsafe {
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
r.cr2().write(|_w| {});
|
||||
r.cr1().write(|w| {
|
||||
w.set_ue(true);
|
||||
w.set_te(true);
|
||||
w.set_re(true);
|
||||
w.set_m0(if config.parity != Parity::ParityNone {
|
||||
vals::M0::BIT9
|
||||
} else {
|
||||
vals::M0::BIT8
|
||||
});
|
||||
w.set_pce(config.parity != Parity::ParityNone);
|
||||
w.set_ps(match config.parity {
|
||||
Parity::ParityOdd => vals::Ps::ODD,
|
||||
Parity::ParityEven => vals::Ps::EVEN,
|
||||
_ => vals::Ps::EVEN,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
|
||||
|
||||
irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
@ -596,7 +638,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
let _s = T::state();
|
||||
|
||||
Self {
|
||||
tx: UartTx::new(tx_dma),
|
||||
tx: UartTx {
|
||||
tx_dma,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
rx: UartRx {
|
||||
_peri: peri,
|
||||
rx_dma,
|
||||
@ -650,12 +695,38 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
}
|
||||
}
|
||||
|
||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) {
|
||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) {
|
||||
if !enable_rx && !enable_tx {
|
||||
panic!("USART: At least one of RX or TX should be enabled");
|
||||
}
|
||||
|
||||
// TODO: better calculation, including error checking and OVER8 if possible.
|
||||
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
|
||||
|
||||
unsafe {
|
||||
r.brr().write_value(regs::Brr(div));
|
||||
r.cr2().write(|_w| {});
|
||||
r.cr1().write(|w| {
|
||||
// enable uart
|
||||
w.set_ue(true);
|
||||
// enable transceiver
|
||||
w.set_te(enable_tx);
|
||||
// enable receiver
|
||||
w.set_re(enable_rx);
|
||||
// configure word size
|
||||
w.set_m0(if config.parity != Parity::ParityNone {
|
||||
vals::M0::BIT9
|
||||
} else {
|
||||
vals::M0::BIT8
|
||||
});
|
||||
// configure parity
|
||||
w.set_pce(config.parity != Parity::ParityNone);
|
||||
w.set_ps(match config.parity {
|
||||
Parity::ParityOdd => vals::Ps::ODD,
|
||||
Parity::ParityEven => vals::Ps::EVEN,
|
||||
_ => vals::Ps::EVEN,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,16 @@
|
||||
name = "embassy-time"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Instant and Duration for embedded no-std systems, with async timer support"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
categories = [
|
||||
"embedded",
|
||||
"no-std",
|
||||
"concurrency",
|
||||
"asynchronous",
|
||||
]
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/"
|
||||
|
@ -30,6 +30,7 @@ byte-slice-cast = { version = "1.2.0", default-features = false }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
|
||||
embedded-hal-async = { version = "0.1.0-alpha.3" }
|
||||
embedded-io = { version = "0.3.1", features = ["async", "defmt"] }
|
||||
embedded-storage = { version = "0.3" }
|
||||
static_cell = "1.0.0"
|
||||
|
||||
[profile.release]
|
||||
|
89
examples/rp/src/bin/flash.rs
Normal file
89
examples/rp/src/bin/flash.rs
Normal file
@ -0,0 +1,89 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
|
||||
use embassy_rp::peripherals::FLASH;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDR_OFFSET: u32 = 0x100000;
|
||||
const FLASH_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
// add some delay to give an attached debug probe time to parse the
|
||||
// defmt RTT header. Reading that header might touch flash memory, which
|
||||
// interferes with flash write operations.
|
||||
// https://github.com/knurling-rs/defmt/pull/683
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
|
||||
let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
|
||||
erase_write_sector(&mut flash, 0x00);
|
||||
|
||||
multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
|
||||
info!(">>>> [multiwrite_bytes]");
|
||||
let mut read_buf = [0u8; ERASE_SIZE];
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||
|
||||
info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
|
||||
info!("Contents start with {=[u8]}", read_buf[0..4]);
|
||||
|
||||
defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||
info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
|
||||
if read_buf.iter().any(|x| *x != 0xFF) {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01]));
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02]));
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03]));
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04]));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||
info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
|
||||
if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
|
||||
info!(">>>> [erase_write_sector]");
|
||||
let mut buf = [0u8; ERASE_SIZE];
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||
|
||||
info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
|
||||
info!("Contents start with {=[u8]}", buf[0..4]);
|
||||
|
||||
defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||
info!("Contents after erase starts with {=[u8]}", buf[0..4]);
|
||||
if buf.iter().any(|x| *x != 0xFF) {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
|
||||
for b in buf.iter_mut() {
|
||||
*b = 0xDA;
|
||||
}
|
||||
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||
info!("Contents after write starts with {=[u8]}", buf[0..4]);
|
||||
if buf.iter().any(|x| *x != 0xDA) {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
}
|
@ -3,9 +3,11 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::uart;
|
||||
use embassy_rp::{register_interrupts, uart};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
register_interrupts!(Reg: UART0_IRQ);
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
|
60
examples/stm32wl/src/bin/uart_async.rs
Normal file
60
examples/stm32wl/src/bin/uart_async.rs
Normal file
@ -0,0 +1,60 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::interrupt;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
/*
|
||||
Pass Incoming data from LPUART1 to USART1
|
||||
Example is written for the LoRa-E5 mini v1.0,
|
||||
but can be surely changed for your needs.
|
||||
*/
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut config = embassy_stm32::Config::default();
|
||||
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
|
||||
let p = embassy_stm32::init(config);
|
||||
|
||||
defmt::info!("Starting system");
|
||||
|
||||
let mut config1 = Config::default();
|
||||
config1.baudrate = 9600;
|
||||
|
||||
let mut config2 = Config::default();
|
||||
config2.baudrate = 9600;
|
||||
|
||||
//RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0
|
||||
let irq = interrupt::take!(USART1);
|
||||
let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH3, p.DMA1_CH4, config1);
|
||||
|
||||
//RX1/TX1 (LPUART) on LoRa-E5 mini v1.0
|
||||
let irq = interrupt::take!(LPUART1);
|
||||
let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, irq, p.DMA1_CH5, p.DMA1_CH6, config2);
|
||||
|
||||
unwrap!(usart1.write(b"Hello Embassy World!\r\n").await);
|
||||
unwrap!(usart2.write(b"Hello Embassy World!\r\n").await);
|
||||
|
||||
let mut buf = [0u8; 300];
|
||||
loop {
|
||||
let result = usart2.read_until_idle(&mut buf).await;
|
||||
match result {
|
||||
Ok(size) => {
|
||||
match usart1.write(&buf[0..size]).await {
|
||||
Ok(()) => {
|
||||
//Write suc.
|
||||
}
|
||||
Err(..) => {
|
||||
//Wasnt able to write
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_err) => {
|
||||
//Ignore eg. framing errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,5 +9,7 @@ license = "MIT OR Apache-2.0"
|
||||
regex = "1.5.4"
|
||||
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "28ffa8a19d84914089547f52900ffb5877a5dc23" }
|
||||
serde = { version = "1.0.130", features = [ "derive" ] }
|
||||
serde_json = "1.0.87"
|
||||
serde_yaml = "0.8.21"
|
||||
proc-macro2 = "1.0.29"
|
||||
|
||||
|
@ -223,7 +223,7 @@ impl Gen {
|
||||
fn load_chip(&mut self, name: &str) -> Chip {
|
||||
let chip_path = self.opts.data_dir.join("chips").join(&format!("{}.json", name));
|
||||
let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name));
|
||||
serde_yaml::from_slice(&chip).unwrap()
|
||||
serde_json::from_slice(&chip).unwrap()
|
||||
}
|
||||
|
||||
pub fn gen(&mut self) {
|
||||
|
@ -22,6 +22,7 @@ embedded-hal-async = { version = "=0.1.0-alpha.3" }
|
||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||
embedded-io = { version = "0.3.1", features = ["async"] }
|
||||
embedded-storage = { version = "0.3" }
|
||||
|
||||
[profile.dev]
|
||||
debug = 2
|
||||
|
54
tests/rp/src/bin/flash.rs
Normal file
54
tests/rp/src/bin/flash.rs
Normal file
@ -0,0 +1,54 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDR_OFFSET: u32 = 0x4000;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
// add some delay to give an attached debug probe time to parse the
|
||||
// defmt RTT header. Reading that header might touch flash memory, which
|
||||
// interferes with flash write operations.
|
||||
// https://github.com/knurling-rs/defmt/pull/683
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
|
||||
let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH);
|
||||
|
||||
let mut buf = [0u8; ERASE_SIZE];
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||
|
||||
info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32);
|
||||
info!("Contents start with {=[u8]}", buf[0..4]);
|
||||
|
||||
defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||
info!("Contents after erase starts with {=[u8]}", buf[0..4]);
|
||||
if buf.iter().any(|x| *x != 0xFF) {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
|
||||
for b in buf.iter_mut() {
|
||||
*b = 0xDA;
|
||||
}
|
||||
|
||||
defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf));
|
||||
|
||||
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||
info!("Contents after write starts with {=[u8]}", buf[0..4]);
|
||||
if buf.iter().any(|x| *x != 0xDA) {
|
||||
defmt::panic!("unexpected");
|
||||
}
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
@ -4,11 +4,13 @@
|
||||
|
||||
use defmt::{assert_eq, *};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::interrupt;
|
||||
use embassy_rp::uart::{BufferedUart, Config, State, Uart};
|
||||
use embassy_rp::register_interrupts;
|
||||
use embassy_rp::uart::{BufferedUart, Config};
|
||||
use embedded_io::asynch::{Read, Write};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
register_interrupts!(Irqs: UART0_IRQ);
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
@ -16,26 +18,26 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||
|
||||
let config = Config::default();
|
||||
let uart = Uart::new_blocking(uart, tx, rx, config);
|
||||
|
||||
let irq = interrupt::take!(UART0_IRQ);
|
||||
let tx_buf = &mut [0u8; 16];
|
||||
let rx_buf = &mut [0u8; 16];
|
||||
let mut state = State::new();
|
||||
let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf);
|
||||
let config = Config::default();
|
||||
let mut uart = BufferedUart::new(uart, Irqs, tx, rx, tx_buf, rx_buf, config);
|
||||
|
||||
// Make sure we send more bytes than fits in the FIFO, to test the actual
|
||||
// bufferedUart.
|
||||
|
||||
let data = [
|
||||
1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32,
|
||||
30, 31,
|
||||
];
|
||||
let data = [
|
||||
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31,
|
||||
];
|
||||
uart.write_all(&data).await.unwrap();
|
||||
info!("Done writing");
|
||||
|
||||
let mut buf = [0; 32];
|
||||
let mut buf = [0; 31];
|
||||
uart.read_exact(&mut buf).await.unwrap();
|
||||
assert_eq!(buf, data);
|
||||
|
||||
|
Reference in New Issue
Block a user