Skip to content

Commit 869de97

Browse files
committed
Added write_some and read_some methods to I2c and UART peripherals
1 parent 1df5d43 commit 869de97

File tree

4 files changed

+196
-10
lines changed

4 files changed

+196
-10
lines changed

src/aes.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@ impl<Target, Channel, Buffer> Transfer<Target, Channel, Buffer, dma::Ready>
595595
)
596596
-> Self
597597
{
598+
let num_words = buffer.as_slice().len() / 4;
599+
598600
let transfer = dma::Transfer::new(
599601
dma,
600602
target,
@@ -603,8 +605,9 @@ impl<Target, Channel, Buffer> Transfer<Target, Channel, Buffer, dma::Ready>
603605
// this should be fine.
604606
Pin::new(dma::PtrBuffer {
605607
ptr: buffer.as_slice().as_ptr() as *const u32,
606-
len: buffer.as_slice().len() / 4,
608+
len: num_words
607609
}),
610+
num_words,
608611
address,
609612
priority,
610613
dir,

src/dma.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,27 +104,29 @@ impl<T, C, B> Transfer<T, C, B, Ready>
104104
///
105105
/// Panics, if the buffer is not aligned to the word size.
106106
pub(crate) unsafe fn new<Word>(
107-
handle: &mut Handle,
108-
target: T,
109-
channel: C,
110-
buffer: Pin<B>,
111-
address: u32,
112-
priority: Priority,
113-
dir: Direction,
107+
handle: &mut Handle,
108+
target: T,
109+
channel: C,
110+
buffer: Pin<B>,
111+
num_words: usize,
112+
address: u32,
113+
priority: Priority,
114+
dir: Direction,
114115
)
115116
-> Self
116117
where
117118
B: Deref,
118119
B::Target: Buffer<Word>,
119120
Word: SupportedWordSize,
120121
{
121-
assert!(buffer.len() <= u16::max_value() as usize);
122+
assert!(buffer.len() >= num_words);
123+
assert!(num_words <= u16::max_value() as usize);
122124
assert_eq!(buffer.as_ptr().align_offset(mem::size_of::<Word>()), 0);
123125

124126
channel.select_target(handle, &target);
125127
channel.set_peripheral_address(handle, address);
126128
channel.set_memory_address(handle, buffer.as_ptr() as u32);
127-
channel.set_transfer_len(handle, buffer.len() as u16);
129+
channel.set_transfer_len(handle, num_words as u16);
128130
channel.configure::<Word>(handle, priority.0, dir.0);
129131

130132
Transfer {

src/i2c.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use crate::hal::blocking::i2c::{Read, Write, WriteRead};
1919

2020
#[cfg(feature = "stm32l0x2")]
2121
use crate::dma;
22+
#[cfg(feature = "stm32l0x2")]
23+
use crate::dma::Buffer;
2224
use crate::gpio::gpioa::{PA10, PA9};
2325
use crate::gpio::gpiob::{PB6, PB7};
2426
use crate::gpio::{AltMode, OpenDrain, Output};
@@ -238,6 +240,7 @@ where
238240
// Safe, because we're only taking the address of a register.
239241
let address = &unsafe { &*I::ptr() }.txdr as *const _ as u32;
240242

243+
let num_words = buffer.len();
241244
// Safe, because the trait bounds of this method guarantee that the
242245
// buffer can be read from.
243246
let transfer = unsafe {
@@ -246,6 +249,62 @@ where
246249
token,
247250
channel,
248251
buffer,
252+
num_words,
253+
address,
254+
dma::Priority::high(),
255+
dma::Direction::memory_to_peripheral(),
256+
)
257+
};
258+
259+
Transfer {
260+
target: self,
261+
inner: transfer,
262+
}
263+
}
264+
265+
#[cfg(feature = "stm32l0x2")]
266+
pub fn write_some<Channel, Buffer>(mut self,
267+
dma: &mut dma::Handle,
268+
channel: Channel,
269+
address: u8,
270+
buffer: Pin<Buffer>,
271+
num_words: usize,
272+
)
273+
-> Transfer<Self, Tx<I>, Channel, Buffer, dma::Ready>
274+
where
275+
Tx<I>: dma::Target<Channel>,
276+
Channel: dma::Channel,
277+
Buffer: Deref + 'static,
278+
Buffer::Target: AsSlice<Element=u8>,
279+
{
280+
assert!(buffer.len() >= num_words);
281+
self.start_transfer(address, buffer.as_slice().len(), RD_WRNW::WRITE);
282+
283+
// This token represents the transmission capability of I2C and this is
284+
// what the `dma::Target` trait is implemented for. It can't be
285+
// implemented for `I2c` itself, as that would allow for the user to
286+
// pass, for example, a channel that can do I2C RX to `write_all`.
287+
//
288+
// Theoretically, one could create both `Rx` and `Tx` at the same time,
289+
// or create multiple tokens of the same type, and use that to create
290+
// multiple simultaneous DMA transfers, which would be wrong and is not
291+
// supported by the I2C peripheral. We prevent that by only ever
292+
// creating an `Rx` or `Tx` token while we have ownership of `I2c`, and
293+
// dropping the token before returning ownership of `I2c` ot the user.
294+
let token = Tx(PhantomData);
295+
296+
// Safe, because we're only taking the address of a register.
297+
let address = &unsafe { &*I::ptr() }.txdr as *const _ as u32;
298+
299+
// Safe, because the trait bounds of this method guarantee that the
300+
// buffer can be read from.
301+
let transfer = unsafe {
302+
dma::Transfer::new(
303+
dma,
304+
token,
305+
channel,
306+
buffer,
307+
num_words,
249308
address,
250309
dma::Priority::high(),
251310
dma::Direction::memory_to_peripheral(),
@@ -280,6 +339,53 @@ where
280339
// Safe, because we're only taking the address of a register.
281340
let address = &unsafe { &*I::ptr() }.rxdr as *const _ as u32;
282341

342+
let num_words = buffer.len();
343+
// Safe, because the trait bounds of this method guarantee that the
344+
// buffer can be written to.
345+
let transfer = unsafe {
346+
dma::Transfer::new(
347+
dma,
348+
token,
349+
channel,
350+
buffer,
351+
num_words,
352+
address,
353+
dma::Priority::high(),
354+
dma::Direction::peripheral_to_memory(),
355+
)
356+
};
357+
358+
Transfer {
359+
target: self,
360+
inner: transfer,
361+
}
362+
}
363+
364+
#[cfg(feature = "stm32l0x2")]
365+
pub fn read_some<Channel, Buffer>(mut self,
366+
dma: &mut dma::Handle,
367+
channel: Channel,
368+
address: u8,
369+
buffer: Pin<Buffer>,
370+
num_words: usize,
371+
)
372+
-> Transfer<Self, Rx<I>, Channel, Buffer, dma::Ready>
373+
where
374+
Rx<I>: dma::Target<Channel>,
375+
Channel: dma::Channel,
376+
Buffer: DerefMut + 'static,
377+
Buffer::Target: AsMutSlice<Element=u8>,
378+
{
379+
assert!(buffer.len() >= num_words);
380+
self.start_transfer(address, buffer.as_slice().len(), RD_WRNW::READ);
381+
382+
// See explanation of tokens in `write_all`.
383+
let token = Rx(PhantomData);
384+
385+
// Safe, because we're only taking the address of a register.
386+
let address = &unsafe { &*I::ptr() }.rxdr as *const _ as u32;
387+
388+
let num_words = buffer.len();
283389
// Safe, because the trait bounds of this method guarantee that the
284390
// buffer can be written to.
285391
let transfer = unsafe {
@@ -288,6 +394,7 @@ where
288394
token,
289395
channel,
290396
buffer,
397+
num_words,
291398
address,
292399
dma::Priority::high(),
293400
dma::Direction::peripheral_to_memory(),

src/serial.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ pub use crate::{
3232
pac::{LPUART1, USART1, USART4, USART5},
3333
};
3434

35+
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
36+
use dma::Buffer;
37+
3538
/// Serial error
3639
#[derive(Debug)]
3740
pub enum Error {
@@ -380,6 +383,40 @@ macro_rules! usart {
380383
let address =
381384
&unsafe { &*$USARTX::ptr() }.rdr as *const _ as u32;
382385

386+
let num_words = (*buffer).len();
387+
// Safe, because the trait bounds of this method guarantee
388+
// that the buffer can be written to.
389+
unsafe {
390+
dma::Transfer::new(
391+
dma,
392+
self,
393+
channel,
394+
buffer,
395+
num_words,
396+
address,
397+
dma::Priority::high(),
398+
dma::Direction::peripheral_to_memory(),
399+
)
400+
}
401+
}
402+
pub fn read_some<Buffer, Channel>(self,
403+
dma: &mut dma::Handle,
404+
buffer: Pin<Buffer>,
405+
num_words: usize,
406+
channel: Channel,
407+
)
408+
-> dma::Transfer<Self, Channel, Buffer, dma::Ready>
409+
where
410+
Self: dma::Target<Channel>,
411+
Buffer: DerefMut + 'static,
412+
Buffer::Target: AsMutSlice<Element=u8>,
413+
Channel: dma::Channel,
414+
{
415+
// Safe, because we're only taking the address of a
416+
// register.
417+
let address =
418+
&unsafe { &*$USARTX::ptr() }.rdr as *const _ as u32;
419+
383420
// Safe, because the trait bounds of this method guarantee
384421
// that the buffer can be written to.
385422
unsafe {
@@ -388,6 +425,7 @@ macro_rules! usart {
388425
self,
389426
channel,
390427
buffer,
428+
num_words,
391429
address,
392430
dma::Priority::high(),
393431
dma::Direction::peripheral_to_memory(),
@@ -497,6 +535,41 @@ macro_rules! usart {
497535
let address =
498536
&unsafe { &*$USARTX::ptr() }.tdr as *const _ as u32;
499537

538+
let num_words = (*buffer).len();
539+
// Safe, because the trait bounds of this method guarantee
540+
// that the buffer can be read from.
541+
unsafe {
542+
dma::Transfer::new(
543+
dma,
544+
self,
545+
channel,
546+
buffer,
547+
num_words,
548+
address,
549+
dma::Priority::high(),
550+
dma::Direction::memory_to_peripheral(),
551+
)
552+
}
553+
}
554+
555+
pub fn write_some<Buffer, Channel>(self,
556+
dma: &mut dma::Handle,
557+
buffer: Pin<Buffer>,
558+
num_words: usize,
559+
channel: Channel,
560+
)
561+
-> dma::Transfer<Self, Channel, Buffer, dma::Ready>
562+
where
563+
Self: dma::Target<Channel>,
564+
Buffer: Deref + 'static,
565+
Buffer::Target: AsSlice<Element=u8>,
566+
Channel: dma::Channel,
567+
{
568+
// Safe, because we're only taking the address of a
569+
// register.
570+
let address =
571+
&unsafe { &*$USARTX::ptr() }.tdr as *const _ as u32;
572+
500573
// Safe, because the trait bounds of this method guarantee
501574
// that the buffer can be read from.
502575
unsafe {
@@ -505,6 +578,7 @@ macro_rules! usart {
505578
self,
506579
channel,
507580
buffer,
581+
num_words,
508582
address,
509583
dma::Priority::high(),
510584
dma::Direction::memory_to_peripheral(),

0 commit comments

Comments
 (0)