Skip to content

Commit b5ee9b5

Browse files
committed
Implement support for 32-bit memory access scheme. Tested on STM32C071.
1 parent d219616 commit b5ee9b5

File tree

3 files changed

+172
-85
lines changed

3 files changed

+172
-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: 167 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,230 @@
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

4765
#[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-
}
66+
fn get_mem_slice<T>(&self) -> &mut [VolatileCell<T>] {
67+
unsafe { slice::from_raw_parts_mut(self.mem_ptr.cast(), self.mem_len) }
5468
}
5569

5670
pub fn read(&self, mut buf: &mut [u8]) {
57-
let mut index = 0;
71+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
72+
let mem = self.get_mem_slice::<u32>();
5873

59-
while buf.len() >= 2 {
60-
let word = self.read_word(index);
74+
let mut index = 0;
6175

62-
buf[0] = (word & 0xff) as u8;
63-
buf[1] = (word >> 8) as u8;
76+
while buf.len() >= 4 {
77+
let value = mem[index].get().to_ne_bytes();
78+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
6479

65-
index += 1;
80+
buf[0..4].copy_from_slice(&value);
81+
buf = &mut buf[4..];
82+
}
6683

67-
buf = &mut buf[2..];
68-
}
84+
if buf.len() > 0 {
85+
let value = mem[index].get().to_ne_bytes();
86+
buf.copy_from_slice(&value[0..buf.len()]);
87+
}
88+
} else {
89+
let mem = self.get_mem_slice::<u16>();
90+
91+
let mut index = 0;
92+
93+
while buf.len() >= 2 {
94+
let value = mem[index].get().to_ne_bytes();
95+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
6996

70-
if buf.len() > 0 {
71-
buf[0] = (self.read_word(index) & 0xff) as u8;
97+
buf[0..2].copy_from_slice(&value);
98+
buf = &mut buf[2..];
99+
}
100+
101+
if buf.len() > 0 {
102+
let value = mem[index].get().to_ne_bytes();
103+
buf.copy_from_slice(&value[0..buf.len()]);
104+
}
72105
}
73106
}
74107

75108
pub fn write(&self, mut buf: &[u8]) {
76-
let mut index = 0;
109+
if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
110+
let mem = self.get_mem_slice::<u32>();
111+
112+
let mut index = 0;
113+
114+
while buf.len() >= 4 {
115+
let mut value = [0; 4];
116+
value.copy_from_slice(&buf[0..4]);
117+
buf = &buf[4..];
118+
119+
mem[index].set(u32::from_ne_bytes(value));
120+
index += USB::EP_MEMORY_ACCESS.offset_multiplier();
121+
}
77122

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;
123+
if buf.len() > 0 {
124+
let mut value = [0; 4];
125+
value[0..buf.len()].copy_from_slice(buf);
126+
mem[index].set(u32::from_ne_bytes(value));
127+
}
128+
} else {
129+
let mem = self.get_mem_slice::<u16>();
82130

83-
buf = &buf[2..];
84-
}
131+
let mut index = 0;
85132

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

91150
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
151+
let offset_bytes = self.mem_ptr as usize - USB::EP_MEMORY as usize;
152+
(offset_bytes / USB::EP_MEMORY_ACCESS.offset_multiplier()) as u16
96153
}
97154

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

108194
#[repr(C)]
109195
pub struct BufferDescriptor<USB> {
110-
ptr: *const VolatileCell<u16>,
196+
ptr: *const (),
111197
marker: PhantomData<USB>,
112198
}
113199

114200
impl<USB: UsbPeripheral> BufferDescriptor<USB> {
115201
#[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)) }
202+
fn field(&self, index: usize) -> Field<USB> {
203+
let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
204+
let ptr = unsafe { self.ptr.byte_add(index * 2 * mul) };
205+
Field {
206+
ptr,
207+
marker: PhantomData,
208+
}
119209
}
120210

121211
#[inline(always)]
122-
pub fn addr_tx(&self) -> &'static VolatileCell<u16> {
212+
pub fn addr_tx(&self) -> Field<USB> {
123213
self.field(0)
124214
}
125215

126216
#[inline(always)]
127-
pub fn count_tx(&self) -> &'static VolatileCell<u16> {
217+
pub fn count_tx(&self) -> Field<USB> {
128218
self.field(1)
129219
}
130220

131221
#[inline(always)]
132-
pub fn addr_rx(&self) -> &'static VolatileCell<u16> {
222+
pub fn addr_rx(&self) -> Field<USB> {
133223
self.field(2)
134224
}
135225

136226
#[inline(always)]
137-
pub fn count_rx(&self) -> &'static VolatileCell<u16> {
227+
pub fn count_rx(&self) -> Field<USB> {
138228
self.field(3)
139229
}
140230
}
@@ -167,14 +257,11 @@ impl<USB: UsbPeripheral> EndpointMemoryAllocator<USB> {
167257
}
168258

169259
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-
}
260+
let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
261+
let ptr = unsafe { USB::EP_MEMORY.byte_add((index as usize) * 8 * mul).cast() };
262+
BufferDescriptor {
263+
ptr,
264+
marker: Default::default(),
178265
}
179266
}
180267
}

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)