diff --git a/examples/hal.rs b/examples/hal.rs index 345719c..0e75ac8 100644 --- a/examples/hal.rs +++ b/examples/hal.rs @@ -1,6 +1,6 @@ //! USB peripheral -use stm32_usbd::UsbPeripheral; +use stm32_usbd::{U16Bits, UsbPeripheral}; use stm32f1xx_hal::pac::{RCC, USB}; pub use stm32_usbd::UsbBus; @@ -20,7 +20,7 @@ unsafe impl UsbPeripheral for Peripheral { const DP_PULL_UP_FEATURE: bool = false; const EP_MEMORY: *const () = 0x4000_6000 as _; const EP_MEMORY_SIZE: usize = 512; - const EP_MEMORY_ACCESS_2X16: bool = false; + type SramAccessScheme = U16Bits; fn enable() { let rcc = unsafe { &*RCC::ptr() }; diff --git a/src/bus.rs b/src/bus.rs index 657d8f8..0e8bfdf 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -12,7 +12,7 @@ use crate::registers::UsbRegisters; use crate::UsbPeripheral; /// USB peripheral driver for STM32 microcontrollers. -pub struct UsbBus { +pub struct UsbBus { peripheral: USB, regs: Mutex>, endpoints: [Endpoint; NUM_ENDPOINTS], diff --git a/src/endpoint.rs b/src/endpoint.rs index 9434364..5ae4596 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -1,4 +1,4 @@ -use crate::endpoint_memory::{BufferDescriptor, EndpointBuffer, EndpointMemoryAllocator}; +use crate::endpoint_memory::{BufferDescriptor, DescriptorPart, EndpointBuffer, EndpointMemoryAllocator}; use crate::registers::UsbRegisters; use crate::UsbPeripheral; use core::marker::PhantomData; @@ -16,7 +16,7 @@ pub const NUM_ENDPOINTS: usize = 8; /// Arbitrates access to the endpoint-specific registers and packet buffer memory. #[derive(Default)] -pub struct Endpoint { +pub struct Endpoint { out_buf: Option>>, in_buf: Option>>, ep_type: Option, @@ -72,8 +72,7 @@ impl Endpoint { self.out_buf = Some(Mutex::new(buffer)); let descr = self.descr(); - descr.addr_rx().set(offset); - descr.count_rx().set(size_bits); + descr.set_rx(offset, size_bits); } pub fn is_in_buf_set(&self) -> bool { @@ -85,8 +84,7 @@ impl Endpoint { self.in_buf = Some(Mutex::new(buffer)); let descr = self.descr(); - descr.addr_tx().set(offset); - descr.count_tx().set(0); + descr.set_tx(offset, 0); } fn descr(&self) -> BufferDescriptor { @@ -151,7 +149,8 @@ impl Endpoint { }; in_buf.write(buf); - self.descr().count_tx().set(buf.len() as u16); + let DescriptorPart { address, count: _ } = self.descr().get_tx(); + self.descr().set_tx(address, buf.len() as u16); self.set_stat_tx(cs, EndpointStatus::Valid); @@ -173,7 +172,7 @@ impl Endpoint { self.clear_ctr_rx(cs); - let count = (self.descr().count_rx().get() & 0x3ff) as usize; + let count = (self.descr().get_rx().count & 0x3ff) as usize; if count > buf.len() { return Err(UsbError::BufferOverflow); } diff --git a/src/endpoint_memory.rs b/src/endpoint_memory.rs index 104be90..2267273 100644 --- a/src/endpoint_memory.rs +++ b/src/endpoint_memory.rs @@ -1,141 +1,131 @@ use crate::endpoint::NUM_ENDPOINTS; -use crate::UsbPeripheral; +use crate::{SramAccessScheme, UsbPeripheral, Word}; use core::marker::PhantomData; -use core::slice; +use core::mem; use usb_device::{Result, UsbError}; -use vcell::VolatileCell; -pub struct EndpointBuffer { - mem: &'static mut [VolatileCell], +pub struct EndpointBuffer { + ptr: *mut ::Word, + word_count: usize, marker: PhantomData, } +unsafe impl Send for EndpointBuffer {} + impl EndpointBuffer { pub fn new(offset_bytes: usize, size_bytes: usize) -> Self { - let ep_mem_ptr = USB::EP_MEMORY as *mut VolatileCell; - - let offset_words = offset_bytes >> 1; - let count_words = size_bytes >> 1; - let offset_u16_words; - let count_u16_words; - if USB::EP_MEMORY_ACCESS_2X16 { - offset_u16_words = offset_words; - count_u16_words = count_words; - } else { - offset_u16_words = offset_words * 2; - count_u16_words = count_words * 2; - }; + let ep_mem_ptr = USB::EP_MEMORY as *mut ::Word; + + let word_size = Self::word_size(); + let offset_words = offset_bytes / word_size; + let word_count = size_bytes / word_size; + + let offset_words = offset_words * USB::SramAccessScheme::ADDRESS_MULTIPLIER; + let word_count = word_count * USB::SramAccessScheme::ADDRESS_MULTIPLIER; unsafe { - let mem = slice::from_raw_parts_mut(ep_mem_ptr.add(offset_u16_words), count_u16_words); + let ptr = ep_mem_ptr.add(offset_words); Self { - mem, + ptr, + word_count, marker: PhantomData, } } } + fn word_size() -> usize { + mem::size_of::<::Word>() + } + #[inline(always)] - fn read_word(&self, index: usize) -> u16 { - if USB::EP_MEMORY_ACCESS_2X16 { - self.mem[index].get() - } else { - self.mem[index * 2].get() - } + fn read_word(&self, index: usize) -> ::Word { + let index = index * USB::SramAccessScheme::ADDRESS_MULTIPLIER; + assert!(index < self.word_count); + unsafe { self.ptr.add(index).read_volatile() } } #[inline(always)] - fn write_word(&self, index: usize, value: u16) { - if USB::EP_MEMORY_ACCESS_2X16 { - self.mem[index].set(value); - } else { - self.mem[index * 2].set(value); + fn write_word(&self, index: usize, value: ::Word) { + let index = index * USB::SramAccessScheme::ADDRESS_MULTIPLIER; + assert!(index < self.word_count); + unsafe { + self.ptr.add(index).write_volatile(value); } } - pub fn read(&self, mut buf: &mut [u8]) { + pub fn read(&self, buf: &mut [u8]) { let mut index = 0; + let mut writer = buf.into_iter().peekable(); - while buf.len() >= 2 { - let word = self.read_word(index); - - buf[0] = (word & 0xff) as u8; - buf[1] = (word >> 8) as u8; - + while writer.peek().is_some() { + self.read_word(index).write_to_iter_le(&mut writer); index += 1; - - buf = &mut buf[2..]; - } - - if buf.len() > 0 { - buf[0] = (self.read_word(index) & 0xff) as u8; } } - pub fn write(&self, mut buf: &[u8]) { + pub fn write(&self, buf: &[u8]) { let mut index = 0; + let mut reader = buf.into_iter().peekable(); - while buf.len() >= 2 { - let value: u16 = buf[0] as u16 | ((buf[1] as u16) << 8); + while reader.peek().is_some() { + let value = Word::from_iter_le(&mut reader); self.write_word(index, value); index += 1; - - buf = &buf[2..]; - } - - if buf.len() > 0 { - self.write_word(index, buf[0] as u16); } } pub fn offset(&self) -> u16 { - let buffer_address = self.mem.as_ptr() as usize; - let word_size = if USB::EP_MEMORY_ACCESS_2X16 { 2 } else { 4 }; - let index = (buffer_address - USB::EP_MEMORY as usize) / word_size; - (index << 1) as u16 + let buffer_address = self.ptr as usize; + let word_size = Self::word_size(); + let offset_per_word = word_size * USB::SramAccessScheme::ADDRESS_MULTIPLIER; + let index = (buffer_address - USB::EP_MEMORY as usize) / offset_per_word; + (index * word_size) as u16 } + /// Capacity in bytes pub fn capacity(&self) -> usize { - let len_words = if USB::EP_MEMORY_ACCESS_2X16 { - self.mem.len() - } else { - self.mem.len() / 2 - }; - len_words << 1 + let len_words = self.word_count / USB::SramAccessScheme::ADDRESS_MULTIPLIER; + let word_size = Self::word_size(); + len_words * word_size } } #[repr(C)] -pub struct BufferDescriptor { - ptr: *const VolatileCell, +pub struct BufferDescriptor { + ptr: *mut ::Word, marker: PhantomData, } -impl BufferDescriptor { - #[inline(always)] - fn field(&self, index: usize) -> &'static VolatileCell { - let mul = if USB::EP_MEMORY_ACCESS_2X16 { 1 } else { 2 }; - unsafe { &*(self.ptr.add(index * mul)) } - } +pub struct DescriptorPart { + pub address: u16, + pub count: u16, +} +impl BufferDescriptor { #[inline(always)] - pub fn addr_tx(&self) -> &'static VolatileCell { - self.field(0) + pub fn set_tx(&self, address: u16, count: u16) { + unsafe { + USB::SramAccessScheme::set(self.ptr, crate::AccessType::Tx, address, count); + } } #[inline(always)] - pub fn count_tx(&self) -> &'static VolatileCell { - self.field(1) + pub fn get_tx(&self) -> DescriptorPart { + let (address, count) = unsafe { USB::SramAccessScheme::read(self.ptr, crate::AccessType::Tx) }; + DescriptorPart { address, count } } #[inline(always)] - pub fn addr_rx(&self) -> &'static VolatileCell { - self.field(2) + pub fn set_rx(&self, address: u16, count: u16) { + unsafe { + USB::SramAccessScheme::set(self.ptr, crate::AccessType::Rx, address, count); + } } #[inline(always)] - pub fn count_rx(&self) -> &'static VolatileCell { - self.field(3) + pub fn get_rx(&self) -> DescriptorPart { + let (address, count) = unsafe { USB::SramAccessScheme::read(self.ptr, crate::AccessType::Rx) }; + DescriptorPart { address, count } } } @@ -167,10 +157,15 @@ impl EndpointMemoryAllocator { } pub fn buffer_descriptor(index: u8) -> BufferDescriptor { - let mul = if USB::EP_MEMORY_ACCESS_2X16 { 1 } else { 2 }; + let mul = USB::SramAccessScheme::ADDRESS_MULTIPLIER; + let word_size = mem::size_of::<::Word>(); + // 4xu16=8Bytes worth of data per descriptor + let descriptor_size_bytes = 8; + let offset_per_descriptor = descriptor_size_bytes * mul / word_size; unsafe { - let ptr = (USB::EP_MEMORY as *const VolatileCell).add((index as usize) * 4 * mul); + let ptr = (USB::EP_MEMORY as *mut ::Word) + .add((index as usize) * offset_per_descriptor); BufferDescriptor { ptr, marker: Default::default(), diff --git a/src/lib.rs b/src/lib.rs index 3f92e32..e2a3644 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub mod bus; mod endpoint; mod endpoint_memory; mod registers; + pub use crate::bus::UsbBus; mod pac; @@ -32,8 +33,11 @@ pub unsafe trait UsbPeripheral: Send + Sync { /// Endpoint memory access scheme /// /// Check Reference Manual for details. - /// Set to `true` if "2x16 bits/word" access scheme is used, otherwise set to `false`. - const EP_MEMORY_ACCESS_2X16: bool; + /// Can be any of: + /// * U16Bits + /// * U16BitsX2 + /// * U32Bits + type SramAccessScheme: SramAccessScheme; /// Enables USB device on its peripheral bus fn enable(); @@ -44,3 +48,127 @@ pub unsafe trait UsbPeripheral: Send + Sync { /// peripheral initialization. fn startup_delay(); } + +pub struct U16Bits; +pub struct U16BitsX2; +pub struct U32Bits; + +pub enum AccessType { + Tx = 0, + Rx = 1, +} + +pub trait SramAccessScheme { + type Word: Word; + const ADDRESS_MULTIPLIER: usize = 1; + + unsafe fn set(ptr: *mut Self::Word, t: AccessType, address: u16, count: u16); + unsafe fn read(ptr: *const Self::Word, t: AccessType) -> (u16, u16); +} + +impl SramAccessScheme for U16Bits { + type Word = u16; + const ADDRESS_MULTIPLIER: usize = 2; + + unsafe fn set(ptr: *mut Self::Word, t: AccessType, address: u16, count: u16) { + set(ptr, t, Self::ADDRESS_MULTIPLIER, address, count); + } + + unsafe fn read(ptr: *const Self::Word, t: AccessType) -> (u16, u16) { + read(ptr, t, Self::ADDRESS_MULTIPLIER) + } +} + +impl SramAccessScheme for U16BitsX2 { + type Word = u16; + + unsafe fn set(ptr: *mut Self::Word, t: AccessType, address: u16, count: u16) { + set(ptr, t, Self::ADDRESS_MULTIPLIER, address, count); + } + + unsafe fn read(ptr: *const Self::Word, t: AccessType) -> (u16, u16) { + read(ptr, t, Self::ADDRESS_MULTIPLIER) + } +} +impl SramAccessScheme for U32Bits { + type Word = u32; + + unsafe fn set(ptr: *mut Self::Word, t: AccessType, address: u16, count: u16) { + assert!(count < (1 << 10)); + + let offset = t as usize; + + let bits = u32::from(count) << 16 | u32::from(address); + unsafe { + ptr.add(offset).write_volatile(bits); + } + } + + unsafe fn read(ptr: *const Self::Word, t: AccessType) -> (u16, u16) { + let offset = t as usize; + + unsafe { + let bits = ptr.add(offset).read_volatile(); + let address = bits as u16; + let count = (bits >> 16) as u16; + + (address, count) + } + } +} + +pub trait Word: From + Into + Copy + Send + 'static { + fn from_iter_le<'a>(it: &mut impl Iterator) -> Self; + fn write_to_iter_le<'a>(self, it: &mut impl Iterator); +} + +impl Word for u16 { + fn from_iter_le<'a>(it: &mut impl Iterator) -> Self { + Self::from_le_bytes([*it.next().unwrap_or(&0), *it.next().unwrap_or(&0)]) + } + + fn write_to_iter_le<'a>(self, it: &mut impl Iterator) { + for (w, r) in it.zip(self.to_le_bytes()) { + *w = r; + } + } +} + +impl Word for u32 { + fn from_iter_le<'a>(it: &mut impl Iterator) -> Self { + Self::from_le_bytes([ + *it.next().unwrap_or(&0), + *it.next().unwrap_or(&0), + *it.next().unwrap_or(&0), + *it.next().unwrap_or(&0), + ]) + } + + fn write_to_iter_le<'a>(self, it: &mut impl Iterator) { + for (w, r) in it.zip(self.to_le_bytes()) { + *w = r; + } + } +} + +fn set(ptr: *mut u16, t: AccessType, mul: usize, address: u16, count: u16) { + assert!(count < (1 << 10)); + + let offset = t as usize; + + unsafe { + ptr.add(offset * mul).write_volatile(address); + ptr.add((offset + 1) * mul).write_volatile(count); + } +} + +fn read(ptr: *const u16, t: AccessType, mul: usize) -> (u16, u16) { + let offset = t as usize; + + unsafe { + let address = ptr.add(offset * mul).read_volatile(); + let count = ptr.add((offset + 1) * mul).read_volatile(); + + (address, count) + } +}