Compare commits

..

57 Commits

Author SHA1 Message Date
5b61ab852a blah 2022-11-06 23:35:37 +01:00
b99533607c Merge #1039
1039: stm32-metapac-gen: Use `serde_json` to parse json files r=Dirbaio a=GrantM11235

This makes stm32-metapac-gen over twice as fast. A full run on my desktop goes from about six and a half seconds to about three seconds. Suprisingly, it also reduces the fresh compile time by almost a second.

Co-authored-by: Grant Miller <GrantM11235@gmail.com>
2022-11-01 20:58:17 +00:00
ea4d08b6cf stm32-metapac-gen: Use serde_json to parse json files 2022-11-01 14:52:43 -05:00
05968bf0f3 Merge #1037
1037: Add uart async task example r=miathedev a=miathedev

Dear Embassy Team,

here i propose an additional async uart pass-through example for the STM32WL.


Because im quite new to Rust, is there something like **interfaces**?

The code: 
```
mut usart1: Uart<
    'static,
    embassy_stm32::peripherals::USART1,
    embassy_stm32::peripherals::DMA1_CH3,
    embassy_stm32::peripherals::DMA1_CH4,
>,
mut usart2: Uart<
    'static,
    embassy_stm32::peripherals::LPUART1,
    embassy_stm32::peripherals::DMA1_CH5,
    embassy_stm32::peripherals::DMA1_CH6,
>,
```
is quite ugly in my opinion. I would like to allow any Type of DMA and USART/UART as argument. Is this possible somehow?
Im open to any feedback.

With love,
Mia

Co-authored-by: miathedev <mia@metzler.systems>
2022-11-01 08:48:54 +00:00
fc086fd4ba Add uart async example 2022-11-01 10:38:02 +01:00
ea702b3719 Merge #1038
1038: (embassy-boot): Move default initializer function to Default trait implementation r=lulf a=MathiasKoch



Co-authored-by: Mathias <mk@blackbird.online>
2022-11-01 08:05:37 +00:00
97d18c5ffb Move default initializer function to Default trait implementation 2022-11-01 07:54:43 +01:00
eed34f945c Merge #1036
1036: Fix ascii table in BootLoader doc comment r=lulf a=danbev

Signed-off-by: Daniel Bevenius <daniel.bevenius@gmail.com>

Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
2022-10-29 13:28:54 +00:00
0b2d6996e8 Fix ascii table in BootLoader doc comment
Signed-off-by: Daniel Bevenius <daniel.bevenius@gmail.com>
2022-10-29 15:16:09 +02:00
e7fdd500d8 Merge #951
951: (embassy-rp): Implementation of generic flash mutation access r=Dirbaio a=MathiasKoch

I have attempted to utilize the work done in `rp2040-flash` by implementing `embedded-storage` traits on top, for RP2040.

Concerns:
1. ~~Should the DMA be paused where I have put a FIXME note? `DMA_CHx.ctrl_trig().write(|w| { w.set_en(false) })`? If so, how to properly do that without have control over the peripheral for the DMA channels? And if so, I assume we should only re-enable/unpause the ones that were enabled before?~~
2. ~~Should I make sure core2 is halted as part of this code? I am not sure if ea8ab1ac80/examples/flash_example.rs (L103-L109) is heavy/slow code to run?~~
3. ~~Any good way of making this configurable over `FLASH_SIZE`, `WRITE_SIZE` and `ERASE_SIZE` without doing it as generics or parameters, as those make it possible to do differing configs throughout the same program, which feels wrong? Preferably, a compile-time option?~~


**EDIT:**
I have implemented the flash API here under the assumption that all external QSPI nor flashes are infact `Multiwrite` capable, as this makes it possible to use the ROM function for writes of 1 bytes at a time.

I have also added a HIL test for this, but because HIL tests are running 100% from RAM and I wanted to make sure it still works when running from flash, I have also added an example testing erase/write cycles of entire sectors, as well as single bytes in multi-write style.

Ping `@Dirbaio` 

Co-authored-by: Mathias <mk@blackbird.online>
Co-authored-by: Vincent Stakenburg <v.stakenburg@sinewave.nl>
Co-authored-by: Joakim Hulthe <joakim@hulthe.net>
Co-authored-by: Alex Martens <alex@thinglab.org>
Co-authored-by: Ulf Lilleengen <ulf.lilleengen@gmail.com>
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
2022-10-28 12:19:56 +00:00
1f246d0e37 Merge #1034
1034: stm32/usart: Fix bug where USART idle flag could end a `read` prematuraly r=Dirbaio a=guillaume-michel

on STM32, when setting USART `detect_previous_overrun = true`, the idle flag is not cleared and could result in premature end of the `read` method.

This PR fixes that.

Co-authored-by: Guillaume MICHEL <guillaume@squaremind.io>
2022-10-28 11:22:53 +00:00
a7d5c87049 Merge #1033
1033: stm32/usart: Add missing constructor with hardware flow control r=Dirbaio a=guillaume-michel

This PR follows #1031 and #987 and add missing constructors with hardware flow control.

It also factor general UART configuration like word size, parity, ... used in `Uart`, `UartRx`, `UartTx` and `BufferedUart`.

Co-authored-by: Guillaume MICHEL <guillaume@squaremind.io>
2022-10-28 11:13:11 +00:00
49e1091309 embassy-stm32: Fix bug where USART idle flag could end a read prematuraly 2022-10-28 10:49:59 +02:00
79b49c6fae embassy-stm32: remove duplicated code for USART general configuration 2022-10-28 09:32:05 +02:00
f053bf742c embassy-stm32: Add support for hardware flow control for BufferedUart 2022-10-28 09:04:36 +02:00
9423987ac5 embassy-stm32: Add hardware flow control constructor for UartRx and UartTx 2022-10-28 09:04:36 +02:00
bc21b6efaf Add delay to flash test to allow time to parse RTT header 2022-10-27 12:49:20 +02:00
a7b90c7fb6 Remove unused imports from test 2022-10-27 11:36:46 +02:00
4e61d83555 Merge #1032
1032: stm32/adc: Misc refactoring r=Dirbaio a=GrantM11235

Noteworthy changes:

- Fixed a few typos in the `SampleTime`s
- `set_resolution` now writes directly to the configuration register. This also fixed a bug in v3 where the resolution was changed while `ADEN` is enabled, which the datasheet says isn't allowed.

Co-authored-by: Grant Miller <GrantM11235@gmail.com>
2022-10-27 08:45:12 +00:00
c871fe0848 Rebase on master 2022-10-27 07:12:34 +02:00
3c6c382465 Remove random delay from example, and move flash functions to allow using without embedded-storage in scope 2022-10-27 07:10:35 +02:00
171b764d82 Refactor: Use PeripheralRef 2022-10-26 18:36:04 -05:00
08c8022583 Refactor: Reorder _version cfgs 2022-10-26 18:04:52 -05:00
4f2dcca34b Refactor: Fix v4 RccPeripheral bounds 2022-10-26 17:59:44 -05:00
9c30d565b9 Refactor: Factor out Adc struct declaration 2022-10-26 17:51:12 -05:00
f363f6ce92 Refactor: Don't return references to pointers 2022-10-26 17:35:06 -05:00
6bf24b4d1a Refactor: Remove unused Common trait 2022-10-26 17:35:01 -05:00
88bbc238b7 Set resolution directly 2022-10-26 17:07:58 -05:00
2cfe2439c9 Refactor: Impl From for SampleTime and Resolution 2022-10-26 17:07:58 -05:00
7b38b95e10 Refactor: Factor out Resolution 2022-10-26 17:07:58 -05:00
5142674786 Fix pre-existing SampleTime typos 2022-10-26 17:07:50 -05:00
a5b1d2237f Refactor: Factor out SampleTime 2022-10-26 17:06:44 -05:00
61560e740d time: add missing cargo manifest fields. 2022-10-26 22:18:10 +02:00
1669e39565 Buffer data to be written to flash in ram if it does not already reside in ram 2022-10-26 15:02:39 +02:00
80e58426fc Add flash example & flash HIL test 2022-10-26 12:24:04 +02:00
ad0eb3f4bd Implement flash padding to 256 under assumption that all QSPI NOR flashes are MultiwriteNorFlashes 2022-10-24 12:17:22 +02:00
8d809c96ec Merge branch 'master' of https://github.com/embassy-rs/embassy into embassy-rp/flash 2022-10-24 12:14:26 +02:00
7152031229 Add flash ram helpers 2022-09-29 10:03:49 +02:00
7ee7109508 Rebase on master 2022-09-29 10:00:13 +02:00
18dc0dea63 Drop rp2040-flash as dependency, as they pull in rp2040-hal for rom-data functions, which are now part of this HAL as well 2022-09-23 08:12:32 +02:00
9d674f0212 First iteration attempt on implementing generic flash mutation access for RP2040 2022-09-23 07:59:10 +02:00
816778e3fa Add RP2040 ROM functions and intrinsics aliases 2022-09-23 07:58:48 +02:00
4f33cc5d1a Replace futures::future::join -> embassy_futures::join::join. 2022-09-23 07:58:48 +02:00
2fed9f949a Replace futures::future::poll_fn -> core::future::poll_fn. 2022-09-23 07:58:48 +02:00
7412a859fd Update Rust nightly.
Removes feature(generic_associated_types)
2022-09-23 07:58:48 +02:00
0db1332da8 Implement RealTimeClock for embassy-rp 2022-09-23 07:58:48 +02:00
334dfcdb65 Take into account size of revert index
Fixes a bug in the partition assertions that ensures that the state
page(s) have enough space for 2x active partition range.

Add unit test to verify that panic is observed.
2022-09-23 07:58:48 +02:00
54ba472540 Remove BootFlash borrow
Compiler will infer a different lifetime for BootFlash than for the
borrowed flash, which makes it require more type annotations than if it
was just owning the type. Since it doesn't really matter if it owns or
borrows in practical use, change it to own so that it simplifies usage.
2022-09-23 07:58:48 +02:00
4322293f63 rp: let SPI RX overflow during async write 2022-09-23 07:58:48 +02:00
c14527486d rp: fix async SPI read and write 2022-09-23 07:58:48 +02:00
81298394b5 rp: remove extraneous newlines in logs 2022-09-23 07:58:48 +02:00
5d1576ea73 Add time-driver feature to docs 2022-09-23 07:58:48 +02:00
f46b838746 Feature-gate time-driver in embassy-rp 2022-09-23 07:58:48 +02:00
3f672c8a93 Make rustfmt happy 2022-09-23 07:58:48 +02:00
e5af4c4bce Add .into_inner() and .get_mut() to Mutex 2022-09-23 07:58:48 +02:00
7bb9620b1a make State::new() const, consistent with others 2022-09-23 07:58:48 +02:00
feb840c503 First iteration attempt on implementing generic flash mutation access for RP2040 2022-09-16 13:20:22 +02:00
31 changed files with 1836 additions and 1130 deletions

View File

@ -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:

View File

@ -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 {

View File

@ -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)
}
}

View 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);
}
}

View File

@ -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;

View File

@ -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"] }

View File

@ -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
View 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 {}

View File

@ -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 {}
)*
};
}

View File

@ -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"]

View File

@ -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)
}
}

View File

@ -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())
}
}
};
}

View File

@ -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));
}
}
}

View File

@ -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 {}

View 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,
}
}
}

View 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)
)
);

View File

@ -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));
}
}
}

View File

@ -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));
}
}
}

View File

@ -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));
}
}
}

View File

@ -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);
});

View File

@ -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,
});
});
}
}

View File

@ -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/"

View File

@ -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]

View 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");
}
}

View File

@ -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());

View 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
}
}
}
}

View File

@ -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"

View File

@ -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) {

View File

@ -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
View 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();
}

View File

@ -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);