Skip to content

Breaking - Add support for 32bit sram access scheme #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/hal.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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() };
Expand Down
2 changes: 1 addition & 1 deletion src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::registers::UsbRegisters;
use crate::UsbPeripheral;

/// USB peripheral driver for STM32 microcontrollers.
pub struct UsbBus<USB> {
pub struct UsbBus<USB: UsbPeripheral> {
peripheral: USB,
regs: Mutex<UsbRegisters<USB>>,
endpoints: [Endpoint<USB>; NUM_ENDPOINTS],
Expand Down
15 changes: 7 additions & 8 deletions src/endpoint.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<USB> {
pub struct Endpoint<USB: UsbPeripheral> {
out_buf: Option<Mutex<EndpointBuffer<USB>>>,
in_buf: Option<Mutex<EndpointBuffer<USB>>>,
ep_type: Option<EndpointType>,
Expand Down Expand Up @@ -72,8 +72,7 @@ impl<USB: UsbPeripheral> Endpoint<USB> {
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 {
Expand All @@ -85,8 +84,7 @@ impl<USB: UsbPeripheral> Endpoint<USB> {
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<USB> {
Expand Down Expand Up @@ -151,7 +149,8 @@ impl<USB: UsbPeripheral> Endpoint<USB> {
};

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

Expand All @@ -173,7 +172,7 @@ impl<USB: UsbPeripheral> Endpoint<USB> {

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);
}
Expand Down
157 changes: 76 additions & 81 deletions src/endpoint_memory.rs
Original file line number Diff line number Diff line change
@@ -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<USB> {
mem: &'static mut [VolatileCell<u16>],
pub struct EndpointBuffer<USB: UsbPeripheral> {
ptr: *mut <USB::SramAccessScheme as SramAccessScheme>::Word,
word_count: usize,
marker: PhantomData<USB>,
}

unsafe impl<USB: UsbPeripheral> Send for EndpointBuffer<USB> {}

impl<USB: UsbPeripheral> EndpointBuffer<USB> {
pub fn new(offset_bytes: usize, size_bytes: usize) -> Self {
let ep_mem_ptr = USB::EP_MEMORY as *mut VolatileCell<u16>;

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 <USB::SramAccessScheme as SramAccessScheme>::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::<<USB::SramAccessScheme as SramAccessScheme>::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) -> <USB::SramAccessScheme as SramAccessScheme>::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: <USB::SramAccessScheme as SramAccessScheme>::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<USB> {
ptr: *const VolatileCell<u16>,
pub struct BufferDescriptor<USB: UsbPeripheral> {
ptr: *mut <USB::SramAccessScheme as SramAccessScheme>::Word,
marker: PhantomData<USB>,
}

impl<USB: UsbPeripheral> BufferDescriptor<USB> {
#[inline(always)]
fn field(&self, index: usize) -> &'static VolatileCell<u16> {
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<USB: UsbPeripheral> BufferDescriptor<USB> {
#[inline(always)]
pub fn addr_tx(&self) -> &'static VolatileCell<u16> {
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<u16> {
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<u16> {
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<u16> {
self.field(3)
pub fn get_rx(&self) -> DescriptorPart {
let (address, count) = unsafe { USB::SramAccessScheme::read(self.ptr, crate::AccessType::Rx) };
DescriptorPart { address, count }
}
}

Expand Down Expand Up @@ -167,10 +157,15 @@ impl<USB: UsbPeripheral> EndpointMemoryAllocator<USB> {
}

pub fn buffer_descriptor(index: u8) -> BufferDescriptor<USB> {
let mul = if USB::EP_MEMORY_ACCESS_2X16 { 1 } else { 2 };
let mul = USB::SramAccessScheme::ADDRESS_MULTIPLIER;
let word_size = mem::size_of::<<USB::SramAccessScheme as SramAccessScheme>::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<u16>).add((index as usize) * 4 * mul);
let ptr = (USB::EP_MEMORY as *mut <USB::SramAccessScheme as SramAccessScheme>::Word)
.add((index as usize) * offset_per_descriptor);
BufferDescriptor {
ptr,
marker: Default::default(),
Expand Down
Loading
Loading