diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-04-06 18:50:53 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-04-06 18:59:37 +0200 |
| commit | 9f28d8097704f51fb7d7dcc8d459ce86aaf07eff (patch) | |
| tree | 42e60061bee4284d3dd400547b38505f1655ab03 /embassy-stm32/src/usb | |
| parent | 52cab3a9f4f1a14b47454d38a96f01b14e688c9f (diff) | |
stm32/usb: add support for 32bit usbram.
Diffstat (limited to 'embassy-stm32/src/usb')
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 131 |
1 files changed, 85 insertions, 46 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 0355c5f14..e6ee39549 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -12,22 +12,29 @@ use embassy_usb_driver as driver; | |||
| 12 | use embassy_usb_driver::{ | 12 | use embassy_usb_driver::{ |
| 13 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | 13 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, |
| 14 | }; | 14 | }; |
| 15 | use pac::common::{Reg, RW}; | ||
| 16 | use pac::usb::vals::{EpType, Stat}; | ||
| 17 | 15 | ||
| 18 | use super::{DmPin, DpPin, Instance}; | 16 | use super::{DmPin, DpPin, Instance}; |
| 19 | use crate::gpio::sealed::AFType; | 17 | use crate::gpio::sealed::AFType; |
| 20 | use crate::interrupt::InterruptExt; | 18 | use crate::interrupt::InterruptExt; |
| 21 | use crate::pac::usb::regs; | 19 | use crate::pac::usb::regs; |
| 20 | use crate::pac::usb::vals::{EpType, Stat}; | ||
| 21 | use crate::pac::USBRAM; | ||
| 22 | use crate::rcc::sealed::RccPeripheral; | 22 | use crate::rcc::sealed::RccPeripheral; |
| 23 | use crate::{pac, Peripheral}; | 23 | use crate::Peripheral; |
| 24 | 24 | ||
| 25 | const EP_COUNT: usize = 8; | 25 | const EP_COUNT: usize = 8; |
| 26 | 26 | ||
| 27 | #[cfg(any(usb_v1_x1, usb_v1_x2))] | 27 | #[cfg(any(usbram_16x1_512, usbram_16x2_512))] |
| 28 | const EP_MEMORY_SIZE: usize = 512; | 28 | const USBRAM_SIZE: usize = 512; |
| 29 | #[cfg(not(any(usb_v1_x1, usb_v1_x2)))] | 29 | #[cfg(usbram_16x2_1024)] |
| 30 | const EP_MEMORY_SIZE: usize = 1024; | 30 | const USBRAM_SIZE: usize = 1024; |
| 31 | #[cfg(usbram_32_2048)] | ||
| 32 | const USBRAM_SIZE: usize = 2048; | ||
| 33 | |||
| 34 | #[cfg(not(usbram_32_2048))] | ||
| 35 | const USBRAM_ALIGN: usize = 2; | ||
| 36 | #[cfg(usbram_32_2048)] | ||
| 37 | const USBRAM_ALIGN: usize = 4; | ||
| 31 | 38 | ||
| 32 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 39 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 33 | static BUS_WAKER: AtomicWaker = NEW_AW; | 40 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| @@ -57,25 +64,60 @@ fn invariant(mut r: regs::Epr) -> regs::Epr { | |||
| 57 | r | 64 | r |
| 58 | } | 65 | } |
| 59 | 66 | ||
| 67 | fn align_len_up(len: u16) -> u16 { | ||
| 68 | ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16 | ||
| 69 | } | ||
| 70 | |||
| 60 | // Returns (actual_len, len_bits) | 71 | // Returns (actual_len, len_bits) |
| 61 | fn calc_out_len(len: u16) -> (u16, u16) { | 72 | fn calc_out_len(len: u16) -> (u16, u16) { |
| 62 | match len { | 73 | match len { |
| 63 | 2..=62 => ((len + 1) / 2 * 2, ((len + 1) / 2) << 10), | 74 | // NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity. |
| 64 | 63..=480 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), | 75 | 2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10), |
| 76 | 61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), | ||
| 65 | _ => panic!("invalid OUT length {}", len), | 77 | _ => panic!("invalid OUT length {}", len), |
| 66 | } | 78 | } |
| 67 | } | 79 | } |
| 68 | fn ep_in_addr<T: Instance>(index: usize) -> Reg<u16, RW> { | 80 | |
| 69 | T::regs().ep_mem(index * 4 + 0) | 81 | #[cfg(not(usbram_32_2048))] |
| 70 | } | 82 | mod btable { |
| 71 | fn ep_in_len<T: Instance>(index: usize) -> Reg<u16, RW> { | 83 | use super::*; |
| 72 | T::regs().ep_mem(index * 4 + 1) | 84 | |
| 73 | } | 85 | pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { |
| 74 | fn ep_out_addr<T: Instance>(index: usize) -> Reg<u16, RW> { | 86 | USBRAM.mem(index * 4 + 0).write_value(addr); |
| 75 | T::regs().ep_mem(index * 4 + 2) | 87 | } |
| 88 | |||
| 89 | pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { | ||
| 90 | USBRAM.mem(index * 4 + 1).write_value(len); | ||
| 91 | } | ||
| 92 | |||
| 93 | pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||
| 94 | USBRAM.mem(index * 4 + 2).write_value(addr); | ||
| 95 | USBRAM.mem(index * 4 + 3).write_value(max_len_bits); | ||
| 96 | } | ||
| 97 | |||
| 98 | pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||
| 99 | USBRAM.mem(index * 4 + 3).read() | ||
| 100 | } | ||
| 76 | } | 101 | } |
| 77 | fn ep_out_len<T: Instance>(index: usize) -> Reg<u16, RW> { | 102 | #[cfg(usbram_32_2048)] |
| 78 | T::regs().ep_mem(index * 4 + 3) | 103 | mod btable { |
| 104 | use super::*; | ||
| 105 | |||
| 106 | pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} | ||
| 107 | |||
| 108 | pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { | ||
| 109 | USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); | ||
| 110 | } | ||
| 111 | |||
| 112 | pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||
| 113 | USBRAM | ||
| 114 | .mem(index * 2 + 1) | ||
| 115 | .write_value((addr as u32) | ((max_len_bits as u32) << 16)); | ||
| 116 | } | ||
| 117 | |||
| 118 | pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||
| 119 | (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 | ||
| 120 | } | ||
| 79 | } | 121 | } |
| 80 | 122 | ||
| 81 | struct EndpointBuffer<T: Instance> { | 123 | struct EndpointBuffer<T: Instance> { |
| @@ -87,23 +129,25 @@ struct EndpointBuffer<T: Instance> { | |||
| 87 | impl<T: Instance> EndpointBuffer<T> { | 129 | impl<T: Instance> EndpointBuffer<T> { |
| 88 | fn read(&mut self, buf: &mut [u8]) { | 130 | fn read(&mut self, buf: &mut [u8]) { |
| 89 | assert!(buf.len() <= self.len as usize); | 131 | assert!(buf.len() <= self.len as usize); |
| 90 | for i in 0..((buf.len() + 1) / 2) { | 132 | for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { |
| 91 | let val = unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).read() }; | 133 | let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; |
| 92 | buf[i * 2] = val as u8; | 134 | let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); |
| 93 | if i * 2 + 1 < buf.len() { | 135 | buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); |
| 94 | buf[i * 2 + 1] = (val >> 8) as u8; | ||
| 95 | } | ||
| 96 | } | 136 | } |
| 97 | } | 137 | } |
| 98 | 138 | ||
| 99 | fn write(&mut self, buf: &[u8]) { | 139 | fn write(&mut self, buf: &[u8]) { |
| 100 | assert!(buf.len() <= self.len as usize); | 140 | assert!(buf.len() <= self.len as usize); |
| 101 | for i in 0..((buf.len() + 1) / 2) { | 141 | for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { |
| 102 | let mut val = buf[i * 2] as u16; | 142 | let mut val = [0u8; USBRAM_ALIGN]; |
| 103 | if i * 2 + 1 < buf.len() { | 143 | let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); |
| 104 | val |= (buf[i * 2 + 1] as u16) << 8; | 144 | val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); |
| 105 | } | 145 | |
| 106 | unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).write_value(val) }; | 146 | #[cfg(not(usbram_32_2048))] |
| 147 | let val = u16::from_le_bytes(val); | ||
| 148 | #[cfg(usbram_32_2048)] | ||
| 149 | let val = u32::from_le_bytes(val); | ||
| 150 | unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; | ||
| 107 | } | 151 | } |
| 108 | } | 152 | } |
| 109 | } | 153 | } |
| @@ -139,8 +183,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 139 | #[cfg(stm32l5)] | 183 | #[cfg(stm32l5)] |
| 140 | unsafe { | 184 | unsafe { |
| 141 | crate::peripherals::PWR::enable(); | 185 | crate::peripherals::PWR::enable(); |
| 142 | 186 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | |
| 143 | pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||
| 144 | } | 187 | } |
| 145 | 188 | ||
| 146 | unsafe { | 189 | unsafe { |
| @@ -256,8 +299,9 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 256 | } | 299 | } |
| 257 | 300 | ||
| 258 | fn alloc_ep_mem(&mut self, len: u16) -> u16 { | 301 | fn alloc_ep_mem(&mut self, len: u16) -> u16 { |
| 302 | assert!(len as usize % USBRAM_ALIGN == 0); | ||
| 259 | let addr = self.ep_mem_free; | 303 | let addr = self.ep_mem_free; |
| 260 | if addr + len > EP_MEMORY_SIZE as _ { | 304 | if addr + len > USBRAM_SIZE as _ { |
| 261 | panic!("Endpoint memory full"); | 305 | panic!("Endpoint memory full"); |
| 262 | } | 306 | } |
| 263 | self.ep_mem_free += len; | 307 | self.ep_mem_free += len; |
| @@ -306,10 +350,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 306 | let addr = self.alloc_ep_mem(len); | 350 | let addr = self.alloc_ep_mem(len); |
| 307 | 351 | ||
| 308 | trace!(" len_bits = {:04x}", len_bits); | 352 | trace!(" len_bits = {:04x}", len_bits); |
| 309 | unsafe { | 353 | unsafe { btable::write_out::<T>(index, addr, len_bits) } |
| 310 | ep_out_addr::<T>(index).write_value(addr); | ||
| 311 | ep_out_len::<T>(index).write_value(len_bits); | ||
| 312 | } | ||
| 313 | 354 | ||
| 314 | EndpointBuffer { | 355 | EndpointBuffer { |
| 315 | addr, | 356 | addr, |
| @@ -321,13 +362,11 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 321 | assert!(!ep.used_in); | 362 | assert!(!ep.used_in); |
| 322 | ep.used_in = true; | 363 | ep.used_in = true; |
| 323 | 364 | ||
| 324 | let len = (max_packet_size + 1) / 2 * 2; | 365 | let len = align_len_up(max_packet_size); |
| 325 | let addr = self.alloc_ep_mem(len); | 366 | let addr = self.alloc_ep_mem(len); |
| 326 | 367 | ||
| 327 | unsafe { | 368 | // ep_in_len is written when actually TXing packets. |
| 328 | ep_in_addr::<T>(index).write_value(addr); | 369 | unsafe { btable::write_in::<T>(index, addr) } |
| 329 | // ep_in_len is written when actually TXing packets. | ||
| 330 | } | ||
| 331 | 370 | ||
| 332 | EndpointBuffer { | 371 | EndpointBuffer { |
| 333 | addr, | 372 | addr, |
| @@ -398,7 +437,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 398 | w.set_ctrm(true); | 437 | w.set_ctrm(true); |
| 399 | }); | 438 | }); |
| 400 | 439 | ||
| 401 | #[cfg(usb_v3)] | 440 | #[cfg(any(usb_v3, usb_v4))] |
| 402 | regs.bcdr().write(|w| w.set_dppu(true)) | 441 | regs.bcdr().write(|w| w.set_dppu(true)) |
| 403 | } | 442 | } |
| 404 | 443 | ||
| @@ -633,12 +672,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { | |||
| 633 | fn write_data(&mut self, buf: &[u8]) { | 672 | fn write_data(&mut self, buf: &[u8]) { |
| 634 | let index = self.info.addr.index(); | 673 | let index = self.info.addr.index(); |
| 635 | self.buf.write(buf); | 674 | self.buf.write(buf); |
| 636 | unsafe { ep_in_len::<T>(index).write_value(buf.len() as _) }; | 675 | unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } |
| 637 | } | 676 | } |
| 638 | 677 | ||
| 639 | fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | 678 | fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 640 | let index = self.info.addr.index(); | 679 | let index = self.info.addr.index(); |
| 641 | let rx_len = unsafe { ep_out_len::<T>(index).read() as usize } & 0x3FF; | 680 | let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; |
| 642 | trace!("READ DONE, rx_len = {}", rx_len); | 681 | trace!("READ DONE, rx_len = {}", rx_len); |
| 643 | if rx_len > buf.len() { | 682 | if rx_len > buf.len() { |
| 644 | return Err(EndpointError::BufferOverflow); | 683 | return Err(EndpointError::BufferOverflow); |
