stm32/usb: add support for 32bit usbram.
This commit is contained in:
parent
52cab3a9f4
commit
9f28d80977
2 changed files with 87 additions and 48 deletions
|
@ -60,7 +60,7 @@ sdio-host = "0.5.0"
|
||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = "3"
|
stm32-metapac = "4"
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
|
@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { version = "3", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "4", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["stm32-metapac/rt"]
|
default = ["stm32-metapac/rt"]
|
||||||
|
|
|
@ -12,22 +12,29 @@ use embassy_usb_driver as driver;
|
||||||
use embassy_usb_driver::{
|
use embassy_usb_driver::{
|
||||||
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
||||||
};
|
};
|
||||||
use pac::common::{Reg, RW};
|
|
||||||
use pac::usb::vals::{EpType, Stat};
|
|
||||||
|
|
||||||
use super::{DmPin, DpPin, Instance};
|
use super::{DmPin, DpPin, Instance};
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::pac::usb::regs;
|
use crate::pac::usb::regs;
|
||||||
|
use crate::pac::usb::vals::{EpType, Stat};
|
||||||
|
use crate::pac::USBRAM;
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
use crate::rcc::sealed::RccPeripheral;
|
||||||
use crate::{pac, Peripheral};
|
use crate::Peripheral;
|
||||||
|
|
||||||
const EP_COUNT: usize = 8;
|
const EP_COUNT: usize = 8;
|
||||||
|
|
||||||
#[cfg(any(usb_v1_x1, usb_v1_x2))]
|
#[cfg(any(usbram_16x1_512, usbram_16x2_512))]
|
||||||
const EP_MEMORY_SIZE: usize = 512;
|
const USBRAM_SIZE: usize = 512;
|
||||||
#[cfg(not(any(usb_v1_x1, usb_v1_x2)))]
|
#[cfg(usbram_16x2_1024)]
|
||||||
const EP_MEMORY_SIZE: usize = 1024;
|
const USBRAM_SIZE: usize = 1024;
|
||||||
|
#[cfg(usbram_32_2048)]
|
||||||
|
const USBRAM_SIZE: usize = 2048;
|
||||||
|
|
||||||
|
#[cfg(not(usbram_32_2048))]
|
||||||
|
const USBRAM_ALIGN: usize = 2;
|
||||||
|
#[cfg(usbram_32_2048)]
|
||||||
|
const USBRAM_ALIGN: usize = 4;
|
||||||
|
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
static BUS_WAKER: AtomicWaker = NEW_AW;
|
static BUS_WAKER: AtomicWaker = NEW_AW;
|
||||||
|
@ -57,25 +64,60 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn align_len_up(len: u16) -> u16 {
|
||||||
|
((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16
|
||||||
|
}
|
||||||
|
|
||||||
// Returns (actual_len, len_bits)
|
// Returns (actual_len, len_bits)
|
||||||
fn calc_out_len(len: u16) -> (u16, u16) {
|
fn calc_out_len(len: u16) -> (u16, u16) {
|
||||||
match len {
|
match len {
|
||||||
2..=62 => ((len + 1) / 2 * 2, ((len + 1) / 2) << 10),
|
// NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity.
|
||||||
63..=480 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000),
|
2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10),
|
||||||
|
61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000),
|
||||||
_ => panic!("invalid OUT length {}", len),
|
_ => panic!("invalid OUT length {}", len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn ep_in_addr<T: Instance>(index: usize) -> Reg<u16, RW> {
|
|
||||||
T::regs().ep_mem(index * 4 + 0)
|
#[cfg(not(usbram_32_2048))]
|
||||||
|
mod btable {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) {
|
||||||
|
USBRAM.mem(index * 4 + 0).write_value(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
|
||||||
|
USBRAM.mem(index * 4 + 1).write_value(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
||||||
|
USBRAM.mem(index * 4 + 2).write_value(addr);
|
||||||
|
USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
|
||||||
|
USBRAM.mem(index * 4 + 3).read()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn ep_in_len<T: Instance>(index: usize) -> Reg<u16, RW> {
|
#[cfg(usbram_32_2048)]
|
||||||
T::regs().ep_mem(index * 4 + 1)
|
mod btable {
|
||||||
}
|
use super::*;
|
||||||
fn ep_out_addr<T: Instance>(index: usize) -> Reg<u16, RW> {
|
|
||||||
T::regs().ep_mem(index * 4 + 2)
|
pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {}
|
||||||
}
|
|
||||||
fn ep_out_len<T: Instance>(index: usize) -> Reg<u16, RW> {
|
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
|
||||||
T::regs().ep_mem(index * 4 + 3)
|
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
||||||
|
USBRAM
|
||||||
|
.mem(index * 2 + 1)
|
||||||
|
.write_value((addr as u32) | ((max_len_bits as u32) << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
|
||||||
|
(USBRAM.mem(index * 2 + 1).read() >> 16) as u16
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EndpointBuffer<T: Instance> {
|
struct EndpointBuffer<T: Instance> {
|
||||||
|
@ -87,23 +129,25 @@ struct EndpointBuffer<T: Instance> {
|
||||||
impl<T: Instance> EndpointBuffer<T> {
|
impl<T: Instance> EndpointBuffer<T> {
|
||||||
fn read(&mut self, buf: &mut [u8]) {
|
fn read(&mut self, buf: &mut [u8]) {
|
||||||
assert!(buf.len() <= self.len as usize);
|
assert!(buf.len() <= self.len as usize);
|
||||||
for i in 0..((buf.len() + 1) / 2) {
|
for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
|
||||||
let val = unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).read() };
|
let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() };
|
||||||
buf[i * 2] = val as u8;
|
let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
|
||||||
if i * 2 + 1 < buf.len() {
|
buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
|
||||||
buf[i * 2 + 1] = (val >> 8) as u8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) {
|
fn write(&mut self, buf: &[u8]) {
|
||||||
assert!(buf.len() <= self.len as usize);
|
assert!(buf.len() <= self.len as usize);
|
||||||
for i in 0..((buf.len() + 1) / 2) {
|
for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
|
||||||
let mut val = buf[i * 2] as u16;
|
let mut val = [0u8; USBRAM_ALIGN];
|
||||||
if i * 2 + 1 < buf.len() {
|
let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
|
||||||
val |= (buf[i * 2 + 1] as u16) << 8;
|
val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]);
|
||||||
}
|
|
||||||
unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).write_value(val) };
|
#[cfg(not(usbram_32_2048))]
|
||||||
|
let val = u16::from_le_bytes(val);
|
||||||
|
#[cfg(usbram_32_2048)]
|
||||||
|
let val = u32::from_le_bytes(val);
|
||||||
|
unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,8 +183,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
#[cfg(stm32l5)]
|
#[cfg(stm32l5)]
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::peripherals::PWR::enable();
|
crate::peripherals::PWR::enable();
|
||||||
|
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
|
||||||
pac::PWR.cr2().modify(|w| w.set_usv(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -256,8 +299,9 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_ep_mem(&mut self, len: u16) -> u16 {
|
fn alloc_ep_mem(&mut self, len: u16) -> u16 {
|
||||||
|
assert!(len as usize % USBRAM_ALIGN == 0);
|
||||||
let addr = self.ep_mem_free;
|
let addr = self.ep_mem_free;
|
||||||
if addr + len > EP_MEMORY_SIZE as _ {
|
if addr + len > USBRAM_SIZE as _ {
|
||||||
panic!("Endpoint memory full");
|
panic!("Endpoint memory full");
|
||||||
}
|
}
|
||||||
self.ep_mem_free += len;
|
self.ep_mem_free += len;
|
||||||
|
@ -306,10 +350,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
let addr = self.alloc_ep_mem(len);
|
let addr = self.alloc_ep_mem(len);
|
||||||
|
|
||||||
trace!(" len_bits = {:04x}", len_bits);
|
trace!(" len_bits = {:04x}", len_bits);
|
||||||
unsafe {
|
unsafe { btable::write_out::<T>(index, addr, len_bits) }
|
||||||
ep_out_addr::<T>(index).write_value(addr);
|
|
||||||
ep_out_len::<T>(index).write_value(len_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndpointBuffer {
|
EndpointBuffer {
|
||||||
addr,
|
addr,
|
||||||
|
@ -321,13 +362,11 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
assert!(!ep.used_in);
|
assert!(!ep.used_in);
|
||||||
ep.used_in = true;
|
ep.used_in = true;
|
||||||
|
|
||||||
let len = (max_packet_size + 1) / 2 * 2;
|
let len = align_len_up(max_packet_size);
|
||||||
let addr = self.alloc_ep_mem(len);
|
let addr = self.alloc_ep_mem(len);
|
||||||
|
|
||||||
unsafe {
|
// ep_in_len is written when actually TXing packets.
|
||||||
ep_in_addr::<T>(index).write_value(addr);
|
unsafe { btable::write_in::<T>(index, addr) }
|
||||||
// ep_in_len is written when actually TXing packets.
|
|
||||||
}
|
|
||||||
|
|
||||||
EndpointBuffer {
|
EndpointBuffer {
|
||||||
addr,
|
addr,
|
||||||
|
@ -398,7 +437,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
||||||
w.set_ctrm(true);
|
w.set_ctrm(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(usb_v3)]
|
#[cfg(any(usb_v3, usb_v4))]
|
||||||
regs.bcdr().write(|w| w.set_dppu(true))
|
regs.bcdr().write(|w| w.set_dppu(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,12 +672,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
|
||||||
fn write_data(&mut self, buf: &[u8]) {
|
fn write_data(&mut self, buf: &[u8]) {
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
self.buf.write(buf);
|
self.buf.write(buf);
|
||||||
unsafe { ep_in_len::<T>(index).write_value(buf.len() as _) };
|
unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
let rx_len = unsafe { ep_out_len::<T>(index).read() as usize } & 0x3FF;
|
let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF;
|
||||||
trace!("READ DONE, rx_len = {}", rx_len);
|
trace!("READ DONE, rx_len = {}", rx_len);
|
||||||
if rx_len > buf.len() {
|
if rx_len > buf.len() {
|
||||||
return Err(EndpointError::BufferOverflow);
|
return Err(EndpointError::BufferOverflow);
|
||||||
|
|
Loading…
Reference in a new issue