Skip to content

Commit c5260f9

Browse files
authored
Merge pull request #39 from FeldrinH/master
Implement support for 32-bit memory access scheme
2 parents c7683ff + 7893801 commit c5260f9

File tree

3 files changed

+175
-85
lines changed

3 files changed

+175
-85
lines changed

examples/hal.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! USB peripheral
22
3-
use stm32_usbd::UsbPeripheral;
3+
use stm32_usbd::{MemoryAccess, UsbPeripheral};
44
use stm32f1xx_hal::pac::{RCC, USB};
55

66
pub use stm32_usbd::UsbBus;
@@ -20,7 +20,7 @@ unsafe impl UsbPeripheral for Peripheral {
2020
const DP_PULL_UP_FEATURE: bool = false;
2121
const EP_MEMORY: *const () = 0x4000_6000 as _;
2222
const EP_MEMORY_SIZE: usize = 512;
23-
const EP_MEMORY_ACCESS_2X16: bool = false;
23+
const EP_MEMORY_ACCESS: MemoryAccess = MemoryAccess::Word16x1;
2424

2525
fn enable() {
2626
let rcc = unsafe { &*RCC::ptr() };

src/endpoint_memory.rs

Lines changed: 170 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,233 @@
11
use crate::endpoint::NUM_ENDPOINTS;
22
use crate::UsbPeripheral;
3-
use core::marker::PhantomData;
43
use core::slice;
4+
use core::{marker::PhantomData, mem};
55
use usb_device::{Result, UsbError};
66
use vcell::VolatileCell;
77

8+
/// Different endpoint memory access schemes
9+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
10+
#[non_exhaustive]
11+
pub enum MemoryAccess {
12+
/// 16x1 bits per word. Each 32-bit word is accessed as one 16-bit half-word. The second half-word of the word is ignored.
13+
///
14+
/// This matches the behavior of `EP_MEMORY_ACCESS_2X16 = false` from previous versions of this library.
15+
Word16x1,
16+
/// 16x2 bits per word. Each 32-bit word is accessed as two 16-bit half-words.
17+
///
18+
/// This matches the behavior of `EP_MEMORY_ACCESS_2X16 = true` from previous versions of this library.
19+
Word16x2,
20+
/// 32x1 bits per word. Each 32-bit word is accessed as one 32-bit word.
21+
Word32x1,
22+
}
23+
24+
impl MemoryAccess {
25+
/// Value to multiply offsets within the EP memory by when calculating address to read or write to.
26+
#[inline(always)]
27+
const fn offset_multiplier(self) -> usize {
28+
match self {
29+
MemoryAccess::Word16x1 => 2,
30+
MemoryAccess::Word16x2 | MemoryAccess::Word32x1 => 1,
31+
}
32+
}
33+
34+
/// Size of unit used when reading and writing EP memory, in bytes.
35+
#[inline(always)]
36+
const fn unit_size(self) -> usize {
37+
match self {
38+
MemoryAccess::Word16x1 | MemoryAccess::Word16x2 => 2,
39+
MemoryAccess::Word32x1 => 4,
40+
}
41+
}
42+
}
43+
844
pub struct EndpointBuffer<USB> {
9-
mem: &'static mut [VolatileCell<u16>],
45+
mem_ptr: *mut (),
46+
mem_len: usize,
1047
marker: PhantomData<USB>,
1148
}
1249

50+
unsafe impl<USB> Send for EndpointBuffer<USB> {}
51+
1352
impl<USB: UsbPeripheral> EndpointBuffer<USB> {
1453
pub fn new(offset_bytes: usize, size_bytes: usize) -> Self {
15-
let ep_mem_ptr = USB::EP_MEMORY as *mut VolatileCell<u16>;
16-
17-
let offset_words = offset_bytes >> 1;
18-
let count_words = size_bytes >> 1;
19-
let offset_u16_words;
20-
let count_u16_words;
21-
if USB::EP_MEMORY_ACCESS_2X16 {
22-
offset_u16_words = offset_words;
23-
count_u16_words = count_words;
24-
} else {
25-
offset_u16_words = offset_words * 2;
26-
count_u16_words = count_words * 2;
27-
};
28-
29-
unsafe {
30-
let mem = slice::from_raw_parts_mut(ep_mem_ptr.add(offset_u16_words), count_u16_words);
31-
Self {
32-
mem,
33-
marker: PhantomData,
34-
}
35-
}
36-
}
54+
let mem_offset_bytes = offset_bytes * USB::EP_MEMORY_ACCESS.offset_multiplier();
55+
let mem_len = size_bytes * USB::EP_MEMORY_ACCESS.offset_multiplier() / USB::EP_MEMORY_ACCESS.unit_size();
3756

38-
#[inline(always)]
39-
fn read_word(&self, index: usize) -> u16 {
40-
if USB::EP_MEMORY_ACCESS_2X16 {
41-
self.mem[index].get()
42-
} else {
43-
self.mem[index * 2].get()
57+
let mem_ptr = unsafe { USB::EP_MEMORY.byte_add(mem_offset_bytes).cast_mut() };
58+
Self {
59+
mem_ptr,
60+
mem_len,
61+
marker: PhantomData,
4462
}
4563
}
4664

65+
/// # Safety
66+
///
67+
/// Caller must ensure that while the returned reference exists, no mutable references to the section of EP memory covered by this slice exist.
4768
#[inline(always)]
48-
fn write_word(&self, index: usize, value: u16) {
49-
if USB::EP_MEMORY_ACCESS_2X16 {
50-
self.mem[index].set(value);
51-
} else {
52-
self.mem[index * 2].set(value);
53-
}
69+
unsafe fn get_mem_slice<T>(&self) -> &[VolatileCell<T>] {
70+
unsafe { slice::from_raw_parts(self.mem_ptr.cast(), self.mem_len) }
5471
}
5572

5673
pub fn read(&self, mut buf: &mut [u8]) {
57-
let mut index = 0;
74+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
75+
let mem = unsafe { self.get_mem_slice::<u32>() };
76+
77+
let mut index = 0;
5878

59-
while buf.len() >= 2 {
60-
let word = self.read_word(index);
79+
while buf.len() >= 4 {
80+
let value = mem[index].get().to_ne_bytes();
81+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
6182

62-
buf[0] = (word & 0xff) as u8;
63-
buf[1] = (word >> 8) as u8;
83+
buf[0..4].copy_from_slice(&value);
84+
buf = &mut buf[4..];
85+
}
6486

65-
index += 1;
87+
if buf.len() > 0 {
88+
let value = mem[index].get().to_ne_bytes();
89+
buf.copy_from_slice(&value[0..buf.len()]);
90+
}
91+
} else {
92+
let mem = unsafe { self.get_mem_slice::<u16>() };
6693

67-
buf = &mut buf[2..];
68-
}
94+
let mut index = 0;
95+
96+
while buf.len() >= 2 {
97+
let value = mem[index].get().to_ne_bytes();
98+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
99+
100+
buf[0..2].copy_from_slice(&value);
101+
buf = &mut buf[2..];
102+
}
69103

70-
if buf.len() > 0 {
71-
buf[0] = (self.read_word(index) & 0xff) as u8;
104+
if buf.len() > 0 {
105+
let value = mem[index].get().to_ne_bytes();
106+
buf.copy_from_slice(&value[0..buf.len()]);
107+
}
72108
}
73109
}
74110

75111
pub fn write(&self, mut buf: &[u8]) {
76-
let mut index = 0;
112+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
113+
let mem = unsafe { self.get_mem_slice::<u32>() };
77114

78-
while buf.len() >= 2 {
79-
let value: u16 = buf[0] as u16 | ((buf[1] as u16) << 8);
80-
self.write_word(index, value);
81-
index += 1;
115+
let mut index = 0;
82116

83-
buf = &buf[2..];
84-
}
117+
while buf.len() >= 4 {
118+
let mut value = [0; 4];
119+
value.copy_from_slice(&buf[0..4]);
120+
buf = &buf[4..];
121+
122+
mem[index].set(u32::from_ne_bytes(value));
123+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
124+
}
125+
126+
if buf.len() > 0 {
127+
let mut value = [0; 4];
128+
value[0..buf.len()].copy_from_slice(buf);
129+
mem[index].set(u32::from_ne_bytes(value));
130+
}
131+
} else {
132+
let mem = unsafe { self.get_mem_slice::<u16>() };
85133

86-
if buf.len() > 0 {
87-
self.write_word(index, buf[0] as u16);
134+
let mut index = 0;
135+
136+
while buf.len() >= 2 {
137+
let mut value = [0; 2];
138+
value.copy_from_slice(&buf[0..2]);
139+
buf = &buf[2..];
140+
141+
mem[index].set(u16::from_ne_bytes(value));
142+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
143+
}
144+
145+
if buf.len() > 0 {
146+
let mut value = [0; 2];
147+
value[0..buf.len()].copy_from_slice(buf);
148+
mem[index].set(u16::from_ne_bytes(value));
149+
}
88150
}
89151
}
90152

91153
pub fn offset(&self) -> u16 {
92-
let buffer_address = self.mem.as_ptr() as usize;
93-
let word_size = if USB::EP_MEMORY_ACCESS_2X16 { 2 } else { 4 };
94-
let index = (buffer_address - USB::EP_MEMORY as usize) / word_size;
95-
(index << 1) as u16
154+
let offset_bytes = self.mem_ptr as usize - USB::EP_MEMORY as usize;
155+
(offset_bytes / USB::EP_MEMORY_ACCESS.offset_multiplier()) as u16
96156
}
97157

98158
pub fn capacity(&self) -> usize {
99-
let len_words = if USB::EP_MEMORY_ACCESS_2X16 {
100-
self.mem.len()
159+
self.mem_len * USB::EP_MEMORY_ACCESS.unit_size() / USB::EP_MEMORY_ACCESS.offset_multiplier()
160+
}
161+
}
162+
163+
pub struct Field<USB> {
164+
ptr: *const (),
165+
marker: PhantomData<USB>,
166+
}
167+
168+
impl<USB: UsbPeripheral> Field<USB> {
169+
#[inline(always)]
170+
pub fn get(&self) -> u16 {
171+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
172+
let unaligned_offset = self.ptr as usize & 0b11;
173+
let cell: &VolatileCell<u32> = unsafe { &*self.ptr.byte_sub(unaligned_offset).cast() };
174+
let value: [u16; 2] = unsafe { mem::transmute(cell.get()) };
175+
value[unaligned_offset >> 1]
176+
} else {
177+
let cell: &VolatileCell<u16> = unsafe { &*self.ptr.cast() };
178+
cell.get()
179+
}
180+
}
181+
182+
#[inline(always)]
183+
pub fn set(&self, value: u16) {
184+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
185+
let unaligned_offset = self.ptr as usize & 0b11;
186+
let cell: &VolatileCell<u32> = unsafe { &*self.ptr.byte_sub(unaligned_offset).cast() };
187+
let mut previous_value: [u16; 2] = unsafe { mem::transmute(cell.get()) };
188+
previous_value[unaligned_offset >> 1] = value;
189+
cell.set(unsafe { mem::transmute(previous_value) });
101190
} else {
102-
self.mem.len() / 2
103-
};
104-
len_words << 1
191+
let cell: &VolatileCell<u16> = unsafe { &*self.ptr.cast() };
192+
cell.set(value);
193+
}
105194
}
106195
}
107196

108197
#[repr(C)]
109198
pub struct BufferDescriptor<USB> {
110-
ptr: *const VolatileCell<u16>,
199+
ptr: *const (),
111200
marker: PhantomData<USB>,
112201
}
113202

114203
impl<USB: UsbPeripheral> BufferDescriptor<USB> {
115204
#[inline(always)]
116-
fn field(&self, index: usize) -> &'static VolatileCell<u16> {
117-
let mul = if USB::EP_MEMORY_ACCESS_2X16 { 1 } else { 2 };
118-
unsafe { &*(self.ptr.add(index * mul)) }
205+
fn field(&self, index: usize) -> Field<USB> {
206+
let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
207+
let ptr = unsafe { self.ptr.byte_add(index * 2 * mul) };
208+
Field {
209+
ptr,
210+
marker: PhantomData,
211+
}
119212
}
120213

121214
#[inline(always)]
122-
pub fn addr_tx(&self) -> &'static VolatileCell<u16> {
215+
pub fn addr_tx(&self) -> Field<USB> {
123216
self.field(0)
124217
}
125218

126219
#[inline(always)]
127-
pub fn count_tx(&self) -> &'static VolatileCell<u16> {
220+
pub fn count_tx(&self) -> Field<USB> {
128221
self.field(1)
129222
}
130223

131224
#[inline(always)]
132-
pub fn addr_rx(&self) -> &'static VolatileCell<u16> {
225+
pub fn addr_rx(&self) -> Field<USB> {
133226
self.field(2)
134227
}
135228

136229
#[inline(always)]
137-
pub fn count_rx(&self) -> &'static VolatileCell<u16> {
230+
pub fn count_rx(&self) -> Field<USB> {
138231
self.field(3)
139232
}
140233
}
@@ -167,14 +260,11 @@ impl<USB: UsbPeripheral> EndpointMemoryAllocator<USB> {
167260
}
168261

169262
pub fn buffer_descriptor(index: u8) -> BufferDescriptor<USB> {
170-
let mul = if USB::EP_MEMORY_ACCESS_2X16 { 1 } else { 2 };
171-
172-
unsafe {
173-
let ptr = (USB::EP_MEMORY as *const VolatileCell<u16>).add((index as usize) * 4 * mul);
174-
BufferDescriptor {
175-
ptr,
176-
marker: Default::default(),
177-
}
263+
let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
264+
let ptr = unsafe { USB::EP_MEMORY.byte_add((index as usize) * 8 * mul).cast() };
265+
BufferDescriptor {
266+
ptr,
267+
marker: Default::default(),
178268
}
179269
}
180270
}

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod endpoint;
1010
mod endpoint_memory;
1111
mod registers;
1212
pub use crate::bus::UsbBus;
13+
pub use crate::endpoint_memory::MemoryAccess;
1314

1415
mod pac;
1516

@@ -31,9 +32,8 @@ pub unsafe trait UsbPeripheral: Send + Sync {
3132

3233
/// Endpoint memory access scheme
3334
///
34-
/// Check Reference Manual for details.
35-
/// Set to `true` if "2x16 bits/word" access scheme is used, otherwise set to `false`.
36-
const EP_MEMORY_ACCESS_2X16: bool;
35+
/// See `MemoryAccess` enum for more details. Check Reference Manual to determine the correct access scheme to use.
36+
const EP_MEMORY_ACCESS: MemoryAccess;
3737

3838
/// Enables USB device on its peripheral bus
3939
fn enable();

0 commit comments

Comments
 (0)