From 0cf375f787c83a6d355dadb50e6eff5d087a5d30 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Thu, 27 Jul 2023 07:14:51 +0200 Subject: [PATCH 01/20] USB host experiment This example blinks the LEDs of an attached USB keyboard. It does not work with any keyboard yet, but it does work with some. Usage: let host = hal::usb::BlockingHost::new( usbctrl_reg, usbctrl_dpram, usb_clock, &mut resets ); host.reset(); host.run(); --- rp2040-hal/src/usb.rs | 2 + rp2040-hal/src/usb/host_blocking.rs | 634 ++++++++++++++++++++++++++++ 2 files changed, 636 insertions(+) create mode 100644 rp2040-hal/src/usb/host_blocking.rs diff --git a/rp2040-hal/src/usb.rs b/rp2040-hal/src/usb.rs index e6114251c..7cb42a836 100644 --- a/rp2040-hal/src/usb.rs +++ b/rp2040-hal/src/usb.rs @@ -124,6 +124,8 @@ use usb_device::{ #[cfg(feature = "rp2040-e5")] mod errata5; +pub mod host_blocking; + #[allow(clippy::bool_to_int_with_if)] fn ep_addr_to_ep_buf_ctrl_idx(ep_addr: EndpointAddress) -> usize { ep_addr.index() * 2 + (if ep_addr.is_in() { 0 } else { 1 }) diff --git a/rp2040-hal/src/usb/host_blocking.rs b/rp2040-hal/src/usb/host_blocking.rs new file mode 100644 index 000000000..6e54779f7 --- /dev/null +++ b/rp2040-hal/src/usb/host_blocking.rs @@ -0,0 +1,634 @@ +#[cfg(feature = "defmt")] +use defmt::Format; + +use defmt::info; + +use usb_device::{UsbDirection, control::{Request, RequestType, Recipient}}; + +use crate::clocks::UsbClock; +use crate::pac::{ + RESETS, + USBCTRL_DPRAM, + USBCTRL_REGS, +}; +use crate::resets::SubsystemReset; + +pub struct BlockingHost { + ctrl_reg: USBCTRL_REGS, + ctrl_dpram: USBCTRL_DPRAM, +} + +impl BlockingHost { + pub fn new( + ctrl_reg: USBCTRL_REGS, + ctrl_dpram: USBCTRL_DPRAM, + _pll: UsbClock, + resets: &mut RESETS, + ) -> Self { + ctrl_reg.reset_bring_down(resets); + ctrl_reg.reset_bring_up(resets); + + Self { ctrl_reg, ctrl_dpram } + } + + pub fn run(&mut self, delay: &mut cortex_m::delay::Delay) { + let event = self.wait_for(|e| matches!(e, Event::ConnDis(Some(_)))); + info!("New USB device: {}", event); + + delay.delay_ms(20); + + self.ctrl_dpram.epx_control.write(|w| { + unsafe { + w.enable().set_bit() + .interrupt_per_buff().set_bit() + .endpoint_type().control() + .buffer_address().bits(0x180) + } + }); + + let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 1 << 8, 0, 18); + info!("Received device descriptor from ADDR0/EDPT0: {}", buf); + + self.control_out(RequestType::Standard, Recipient::Device, Request::SET_ADDRESS, 42, 0, &[]); + info!("Assigned address 42 to device"); + self.ctrl_reg.addr_endp.write(|w| { + unsafe { w.address().bits(42) } + }); + + let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 1 << 8, 0, 18); + print_device_descriptor(buf); + + let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 2 << 8, 0, 9); + info!("Get config descriptor: received first 9 bytes: {}", buf); + let total_length = ((buf[3] as u16) << 8) | (buf[2] as u16); + + let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 2 << 8, 0, total_length); + print_config_descriptor(buf); + + let cfg_value = buf[5] as u16; + + info!("SetConfiguration({})", cfg_value); + self.control_out(RequestType::Standard, Recipient::Device, Request::SET_CONFIGURATION, cfg_value, 0, &[]); + + info!("Set configuration complete!"); + // self.write_setup_packet(UsbDirection::In, RequestType::Standard, Recipient::Device, Request::SET_CONFIGURATION, cfg_value, 0, 0); + // self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); + // info!("SetConfiguration({})", cfg_value); + // self.wait_for(|e| matches!(e, Event::TransComplete)); + // self.ctrl_dpram.ep_buffer_control[0].write(|w| { + // w.pid_0().set_bit(); + // w.full_0().clear_bit(); + // w.available_0().set_bit(); + // unsafe { w.length_0().bits(0) } + // }); + // self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + // self.wait_for(|e| matches!(e, Event::TransComplete)); + + // self.ctrl_reg.addr_endp1.write(|w| { + // unsafe { w.address().bits(42).endpoint().bits(1).intep_dir().clear_bit() } + // }); + + let buf = self.control_in(RequestType::Standard, Recipient::Interface, Request::GET_DESCRIPTOR, 0x22 << 8, 0, 54); + print_hid_report(buf); + + defmt::info!("SET PROTOCOL (boot)"); + self.control_out(RequestType::Class, Recipient::Interface, 0x0b, 0, 0, &[]); + + delay.delay_us(100); + + let sequence = [ + 0b001, + 0b010, + 0b100, + 0b111, + 0b000, + 0b111, + 0b000, + 0b100, + 0b010, + 0b001, + 0b111, + 0b000, + 0b111, + 0b000, + ]; + + let mut index = 0; + + loop { + defmt::info!("SET REPORT {}", sequence[index]); + self.control_out(RequestType::Class, Recipient::Interface, 0x09, 2 << 8, 0, &[sequence[index]]); + self.ctrl_reg.sie_ctrl.write(|w| w.keep_alive_en().set_bit()); + delay.delay_ms(200); + index += 1; + if index == sequence.len() { + index = 0; + } + } + + + // let mut state = 1; + + // loop { + // self.control_out(RequestType::Class, Recipient::Interface, 0x09, 2 << 8, 0, &[state]); + // info!("toggled"); + // delay.delay_ms(1000); + // state = !state; + // } + + // self.ctrl_reg.addr_endp.write(|w| { + // unsafe { w.endpoint().bits(1) } + // }); + // self.ctrl_dpram.ep_control[0].write(|w| { + // w.enable().set_bit(); + // w.endpoint_type().interrupt(); + // w.interrupt_per_buff().set_bit(); + // unsafe { w.buffer_address().bits(0x280) } + // }); + // self.ctrl_dpram.ep_buffer_control[1].write(|w| { + // w.pid_0().set_bit(); + // w.full_0().clear_bit(); + // w.available_0().set_bit(); + // w.reset().set_bit(); + // unsafe { w.length_0().bits(54) } + // }); + + // self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + + // self.wait_for(|e| matches!(e, Event::TransComplete)); + + // info!("INT TRANS COMPLETE"); + + // self.ctrl_reg.int_ep_ctrl.write(|w| { + // unsafe { w.int_ep_active().bits(1) } + // }); + + // info!("Configured interrupt endpoint"); + + // loop { + // let e = self.wait_for(|e| matches!(e, Event::BuffStatus(_))); + // info!("Buff status... {}", e); + + // const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + // let data = unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x280), 54) }; + // info!("INT DATA: {}", data); + // } + } + + fn wait_for bool>(&mut self, f: F) -> Event { + loop { + let event = self.wait_for_event(); + if f(event) { + return event + } + + match event { + Event::ErrCrc | Event::ErrDataSeq | Event::ErrBitStuff | Event::ErrRxTimeout | Event::ErrRxOverflow | Event::Stall | Event::ConnDis(_) => { + defmt::error!("ERROR: {}", event); + }, + _ => {} + } + } + } + + fn wait_for_event(&mut self) -> Event { + let ints = self.ctrl_reg.ints.read(); + + if ints.host_conn_dis().bit_is_set() { + let speed = match self.ctrl_reg.sie_status.read().speed().bits() { + 0b01 => Some(ConnectionSpeed::Low), + 0b10 => Some(ConnectionSpeed::Full), + _ => None, + }; + self.ctrl_reg.sie_status.write(|w| unsafe { w.speed().bits(0b11) }); + return Event::ConnDis(speed) + } + if ints.host_resume().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.resume().set_bit()); + return Event::Resume; + } + if ints.stall().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.stall_rec().set_bit()); + return Event::Stall; + } + if ints.trans_complete().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.trans_complete().set_bit()); + return Event::TransComplete; + } + if ints.error_crc().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.crc_error().set_bit()); + return Event::ErrCrc; + } + if ints.error_bit_stuff().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.bit_stuff_error().set_bit()); + return Event::ErrBitStuff; + } + if ints.error_rx_overflow().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.rx_overflow().set_bit()); + return Event::ErrRxOverflow; + } + if ints.error_rx_timeout().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.rx_timeout().set_bit()); + return Event::ErrRxTimeout; + } + if ints.error_data_seq().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.data_seq_error().set_bit()); + return Event::ErrDataSeq; + } + if ints.host_sof().bit_is_set() { + let count = self.ctrl_reg.sof_rd.read().count().bits(); + return Event::Sof(count); + }; + if ints.buff_status().bit_is_set() { + let status = self.ctrl_reg.buff_status.read().bits(); + self.ctrl_reg.buff_status.write(|w| unsafe { w.bits(0xFFFFFFFF) }); + return Event::BuffStatus(status); + } + if ints.bus_reset().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.bus_reset().set_bit()); + return Event::BusReset; + } + Event::None + } + + pub fn reset(&self) { + defmt::debug!("RESET"); + unsafe { + let raw_ctrl_reg = + core::slice::from_raw_parts_mut(USBCTRL_REGS::ptr() as *mut u32, 1 + 0x98 / 4); + raw_ctrl_reg.fill(0); + + let raw_ctrl_pdram = + core::slice::from_raw_parts_mut(USBCTRL_DPRAM::ptr() as *mut u32, 1 + 0xfc / 4); + raw_ctrl_pdram.fill(0); + } + + self.ctrl_reg.usb_muxing.modify(|_, w| { + w.to_phy().set_bit(); + w.softcon().set_bit() + }); + + // Taken from hcd_rp2040.c, with comment: + // // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En) + self.ctrl_reg.usb_pwr.modify(|_, w| { + w.vbus_detect().set_bit() + .vbus_detect_override_en().set_bit() + }); + + self.ctrl_reg.sie_ctrl.modify(|_, w| { + // The host needs to send keep-alive packets to the device every 1ms to keep the device from suspending. In Full Speed + // mode this is done by sending a SOF (start of frame) packet. In Low Speed mode, an EOP (end of packet) is sent. When + // setting up the controller, SIE_CTRL.KEEP_ALIVE_EN and SIE_CTRL.SOF_EN should be set to enable these packets. + w.sof_en().set_bit() + .keep_alive_en().set_bit() + .pulldown_en().set_bit() + .sof_sync().set_bit() + }); + + self.ctrl_reg.main_ctrl.modify(|_, w| { + w.host_ndevice().set_bit() + .controller_en().set_bit() + }); + + self.ctrl_reg.inte.modify(|_, w| { + w.buff_status().set_bit() + .bus_reset().set_bit() + .host_conn_dis().set_bit() + .host_resume().set_bit() + .stall().set_bit() + .trans_complete().set_bit() + .error_rx_timeout().set_bit() + .error_data_seq().set_bit() + .host_sof().set_bit() + .ep_stall_nak().set_bit() + .error_crc().set_bit() + .error_bit_stuff().set_bit() + .error_rx_overflow().set_bit() + }); + } + + fn control_in(&mut self, request_type: RequestType, recipient: Recipient, request: u8, value: u16, index: u16, length: u16) -> &[u8] { + // 1. Setup packet + self.write_setup_packet(UsbDirection::In, request_type, recipient, request, value, index, length); + self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("IN: setup complete"); + + // 2. IN packet(s) + self.ctrl_dpram.ep_buffer_control[0].write(|w| { + w.pid_0().set_bit(); + w.full_0().clear_bit(); + w.available_0().set_bit(); + unsafe { w.length_0().bits(length) } + }); + self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("IN: data complete"); + + let received_len = self.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() as usize; + + // 3. Confirmation (empty OUT packet) + self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { + unsafe { + w.available_0().set_bit() + .pid_0().set_bit() + .full_0().set_bit() + .length_0().bits(0) + .last_0().set_bit() + .reset().set_bit() + } + }); + self.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); + + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("IN: confirm complete"); + + self.control_buffer(received_len) + } + + fn control_out(&mut self, request_type: RequestType, recipient: Recipient, request: u8, value: u16, index: u16, buf: &[u8]) { + // 1. Setup packet + self.write_setup_packet(UsbDirection::Out, request_type, recipient, request, value, index, buf.len() as u16); + self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("OUT: setup complete"); + if buf.len() > 0 { + // 2. OUT data + self.control_buffer_mut(buf.len()).copy_from_slice(buf); + self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { + unsafe { + w.available_0().set_bit() + .pid_0().set_bit() + .full_0().set_bit() + .length_0().bits(buf.len() as u16) + .last_0().set_bit() + .reset().set_bit() + } + }); + self.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("OUT: send complete"); + } + // 3. IN data (empty packet) for confirmation + self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { + unsafe { + w.available_0().set_bit() + .pid_0().set_bit() + .full_0().clear_bit() + .length_0().bits(0) + .last_0().set_bit() + .reset().set_bit() + } + }); + self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + self.wait_for(|e| matches!(e, Event::TransComplete)); + defmt::debug!("OUT: confirm complete"); + } + + pub fn write_setup_packet( + &self, + direction: UsbDirection, + request_type: RequestType, + recipient: Recipient, + request: u8, + value: u16, + index: u16, + length: u16 + ) { + self.ctrl_dpram.setup_packet_low.write(|w| { + unsafe { + w.bmrequesttype().bits( + (direction as u8) | + ((request_type as u8) << 5) | + (recipient as u8) + ); + w.brequest().bits(request); + w.wvalue().bits(value) + } + }); + + self.ctrl_dpram.setup_packet_high.write(|w| { + unsafe { + w.windex().bits(index); + w.wlength().bits(length) + } + }); + + self.dump_setup_packet(); + } + + fn dump_setup_packet(&self) { + let low = self.ctrl_dpram.setup_packet_low.read().bits(); + let high = self.ctrl_dpram.setup_packet_high.read().bits(); + defmt::debug!("SETUP PACKET: {:#X} {:#X} {:#X} {:#X} {:#X} {:#X} {:#X} {:#X}", + low & 0x000000FF, + (low & 0x0000FF00) >> 8, + (low & 0x00FF0000) >> 16, + (low & 0xFF000000) >> 24, + high & 0x000000FF, + (high & 0x0000FF00) >> 8, + (high & 0x00FF0000) >> 16, + (high & 0xFF000000) >> 24, + ); + } + + pub fn control_buffer(&self, len: usize) -> &[u8] { + const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } + } + + fn control_buffer_mut(&self, len: usize) -> &mut [u8] { + const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + unsafe { core::slice::from_raw_parts_mut(DPRAM_BASE.offset(0x180), len) } + } +} + +#[cfg_attr(feature = "defmt", derive(Format))] +#[derive(Copy, Clone)] +pub enum Event { + None, + ConnDis(Option), + Stall, + Resume, + ErrCrc, + ErrBitStuff, + ErrRxOverflow, + ErrRxTimeout, + ErrDataSeq, + Sof(u16), + TransComplete, + BuffStatus(u32), + BusReset, +} + +#[derive(Copy, Clone)] +pub enum ConnectionSpeed { + Low, + Full, +} + +#[cfg(feature = "defmt")] +impl defmt::Format for ConnectionSpeed { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{}", match self { + ConnectionSpeed::Low => "low-speed", + ConnectionSpeed::Full => "full-speed", + }) + } +} + +fn print_device_descriptor(bytes: &[u8]) -> usize { + let size = bytes[0]; + if size != bytes.len() as u8 { + defmt::error!("Invalid device descriptor? bLength={} does not match buffer size {}", size, bytes.len()); + } else if size != 18 { + defmt::info!("Device descriptor too short ({} bytes), not printing for now.", size); + } else { + defmt::info!("Device descriptor:\n - Desc. Type:\t\t{}\n - USB Version:\t\t{}{}.{}.{}\n - Device Class:\t{}\n - vendor/product:\t{:#X}:{:#X}\n - #configurations:\t{}", + bytes[1], (bytes[3] & 0xF0) >> 4, bytes[3] & 0x0F, (bytes[2] & 0xF0) >> 4, bytes[2] & 0x0F, bytes[4], + ((bytes[9] as u16) << 8) | (bytes[8] as u16), + ((bytes[11] as u16) << 8) | (bytes[10] as u16), + bytes[17] + ); + } + bytes.len() +} + +fn print_config_descriptor(bytes: &[u8]) -> usize { + defmt::info!("Config descriptor:\n - Num Interfaces:\t{}\n - Config Value:\t{}\n - Self powered:\t{}\n - Remote wakeup:\t{}\n - Max power (mA):\t{}\n", + bytes[4], bytes[5], (bytes[7] >> 6) & 1 == 1, (bytes[7] >> 5) & 1 == 1, bytes[8] * 2 + ); + let mut consumed = 9; // size of config descriptor itself + + loop { + if bytes.len() > consumed { + consumed += print_descriptor(&bytes[consumed..]); + } else { + break + } + } + + consumed +} + +fn print_interface_descriptor(bytes: &[u8]) -> usize { + defmt::info!( + "Interface descriptor:\n - Interface num:\t{}\n - Alt setting: \t{}\n - Num endpoints:\t{}\n - Interface class:\t{}\n - Iface subclass:\t{}\n - Iface protocol:\t{}\n", + bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] + ); + 9 +} + +fn print_endpoint_descriptor(bytes: &[u8]) -> usize { + defmt::info!( + "Endpoint descriptor:\n - EP Address:\t{} ({})\n - Transfer type:\t{}\n - Sync type:\t{}\n - Usage type:\t{}\n - Max packet:\t{}\n - Poll interval:\t{}\n", + bytes[2] & 0b111, + if (bytes[2] >> 7) & 1 == 1 { "IN" } else { "OUT" }, + match bytes[3] & 0b11 { + 0 => "control", + 1 => "isochronous", + 2 => "bulk", + 3 => "interrupt", + _ => unreachable!(), + }, + match (bytes[3] >> 2) & 0b11 { + 0 => "none", + 1 => "asynchronous", + 2 => "adaptive", + 3 => "synchronous", + _ => unreachable!(), + }, + match (bytes[3] >> 4) & 0b11 { + 0 => "data", + 1 => "feedback", + 2 => "explicit feedback", + 3 => "(reserved)", + _ => unreachable!(), + }, + bytes[4] as u16 | ((bytes[5] as u16) << 8), + bytes[6] + ); + 7 +} + +fn print_hid_kbd_descriptor(bytes: &[u8]) -> usize { + defmt::info!( + "HID (Keyboard) Descriptor:\n - HID version:\t{}{}.{}.{}\n - Country code:\t{}\n - Report type:\t{:#X}\n - Report length:\t{}\n", + (bytes[3] & 0xF0) >> 4, bytes[3] & 0x0F, (bytes[2] & 0xF0) >> 4, bytes[2] & 0x0F, + bytes[4], bytes[6], bytes[7] + ); + 9 +} + +fn print_descriptor(bytes: &[u8]) -> usize { + match bytes[1] { + 1 => print_device_descriptor(bytes), + 2 => print_config_descriptor(bytes), + 4 => print_interface_descriptor(bytes), + 5 => print_endpoint_descriptor(bytes), + 0x21 => print_hid_kbd_descriptor(bytes), + n => { + defmt::error!("Not implemented: {} ({} bytes)", n, bytes[0]); + bytes[0] as usize + } + } +} + +fn print_hid_report(bytes: &[u8]) { + let mut consumed = 0; + loop { + consumed += print_hid_item(&bytes[consumed..]); + if consumed == bytes.len() { + return + } + } +} + +fn print_hid_item(bytes: &[u8]) -> usize { + if bytes[0] == 0b11111110 { + // long item + let size = bytes[1]; + let tag = bytes[2]; + let data = &bytes[3..(3 + size as usize)]; + defmt::info!("HID ITEM (long): size={} tag={} data={}", size, tag, data); + 3 + size as usize + } else { + // short item + let size = bytes[0] & 0b11; + + let type_ = match (bytes[0] >> 2) & 0b11 { + 0 => "main", + 1 => "global", + 2 => "local", + 3 => "reserved", + _ => unreachable!(), + }; + + let tag = (bytes[0] >> 4) & 0b1111; + + defmt::info!("HID ITEM: size={}, type={}, tag={}, data={}", size, type_, tag, &bytes[1..(1 + size) as usize]); + + match (bytes[0] >> 2) & 0b11 { + 0 => { // MAIN + if size > 0 { + match bytes[1] | 0b11111100 { + 0b10000000 => defmt::info!(" INPUT, size {}", bytes[1] | 0b11), + 0b10010000 => defmt::info!(" OUTPUT, size {}", bytes[1] | 0b11), + 0b10110000 => defmt::info!(" FEATURE, size {}", bytes[1] | 0b11), + 0b10100000 => defmt::info!(" COLLECTION, size {}", bytes[1] | 0b11), + 0b11000000 => defmt::info!(" END COLLECTION, size {}", bytes[1] | 0b11), + _ => defmt::error!("Not sure how to interpret {:#X}", bytes[1]), + } + } + }, + 1 => { // GLOBAL + }, + 2 => { // LOCAL + }, + 3 => { /* reserved */ } + _ => unreachable!(), + } + + 1 + size as usize + } +} From 183bf7be8242f5f1766d09dab2289339b236f704 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 30 Jul 2023 16:45:25 +0200 Subject: [PATCH 02/20] non-blocking host implementation, using new `usbh` abstraction --- rp2040-hal/Cargo.toml | 3 +- rp2040-hal/src/usb.rs | 1 + rp2040-hal/src/usb/host.rs | 301 +++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 rp2040-hal/src/usb/host.rs diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 02f1b9143..f76b393bf 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -24,7 +24,7 @@ embedded-dma = "0.2.0" fugit = "0.3.6" itertools = { version = "0.10.1", default-features = false } nb = "1.0" -rp2040-pac = "0.4.0" +rp2040-pac = { path = "../rp2040-pac" } paste = "1.0" pio = "0.2.0" rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" } @@ -33,6 +33,7 @@ vcell = "0.1" void = { version = "1.0.2", default-features = false } rand_core = "0.6.3" critical-section = { version = "1.0.0" } +usbh = { path = "../../usbh" } chrono = { version = "0.4", default-features = false, optional = true } diff --git a/rp2040-hal/src/usb.rs b/rp2040-hal/src/usb.rs index 7cb42a836..91a944ac8 100644 --- a/rp2040-hal/src/usb.rs +++ b/rp2040-hal/src/usb.rs @@ -125,6 +125,7 @@ use usb_device::{ mod errata5; pub mod host_blocking; +pub mod host; #[allow(clippy::bool_to_int_with_if)] fn ep_addr_to_ep_buf_ctrl_idx(ep_addr: EndpointAddress) -> usize { diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs new file mode 100644 index 000000000..7d94cda4d --- /dev/null +++ b/rp2040-hal/src/usb/host.rs @@ -0,0 +1,301 @@ +use usbh::{ + bus::{ + HostBus, + PollResult, + Event, + Error, + }, + types::{ + ConnectionSpeed, + }, +}; + +use critical_section::Mutex; +use core::cell::RefCell; +use crate::clocks::UsbClock; +use crate::pac::{ + RESETS, + USBCTRL_DPRAM, + USBCTRL_REGS, +}; +use crate::resets::SubsystemReset; +use defmt::debug; + +// Endpoint management... how to do it? +// - DPRAM_BASE + 0x180 is the start. We can allocate amount X there for control transfers +// - what about huge descriptors? Do they get read in parts? (handle multiple BuffStatus before TransComplete) +// - buffers for interrupt endpoints must be allocated when a device connects. How to handle that? +// +// How to handle delays? + +const CONTROL_BUFFER_SIZE: usize = 64; + +pub struct UsbHostBus { + inner: Mutex>, +} + +impl UsbHostBus { + pub fn new( + ctrl_reg: USBCTRL_REGS, + ctrl_dpram: USBCTRL_DPRAM, + _pll: UsbClock, + resets: &mut RESETS, + ) -> Self { + ctrl_reg.reset_bring_down(resets); + ctrl_reg.reset_bring_up(resets); + + Self { inner: Mutex::new(RefCell::new(Inner { ctrl_reg, ctrl_dpram })) } + } +} + +impl HostBus for UsbHostBus { + fn reset_controller(&mut self) { + debug!("[HostBus] reset_controller"); + critical_section::with(|cs| { + let mut inner = self.inner.borrow(cs).borrow_mut(); + unsafe { + let raw_ctrl_reg = + core::slice::from_raw_parts_mut(USBCTRL_REGS::ptr() as *mut u32, 1 + 0x98 / 4); + raw_ctrl_reg.fill(0); + + let raw_ctrl_pdram = + core::slice::from_raw_parts_mut(USBCTRL_DPRAM::ptr() as *mut u32, 1 + 0xfc / 4); + raw_ctrl_pdram.fill(0); + } + inner.ctrl_reg.usb_muxing.modify(|_, w| { + w.to_phy().set_bit(); + w.softcon().set_bit() + }); + inner.ctrl_reg.usb_pwr.modify(|_, w| { + w.vbus_detect().set_bit() + .vbus_detect_override_en().set_bit() + }); + inner.ctrl_reg.sie_ctrl.modify(|_, w| { + w.sof_en().set_bit() + .keep_alive_en().set_bit() + .pulldown_en().set_bit() + .sof_sync().set_bit() + }); + inner.ctrl_reg.main_ctrl.modify(|_, w| { + w.host_ndevice().set_bit() + .controller_en().set_bit() + }); + + inner.ctrl_reg.inte.modify(|_, w| { + w.buff_status().set_bit() + .host_conn_dis().set_bit() + .host_resume().set_bit() + .stall().set_bit() + .trans_complete().set_bit() + .error_rx_timeout().set_bit() + .error_data_seq().set_bit() + .error_crc().set_bit() + .error_bit_stuff().set_bit() + .error_rx_overflow().set_bit() + }); + + // FIXME: put this elsewhere! + inner.ctrl_dpram.epx_control.write(|w| { + unsafe { + w.enable().set_bit() + .interrupt_per_buff().set_bit() + .endpoint_type().control() + .buffer_address().bits(0x180) + } + }); + }); + } + + fn enable_sof(&mut self) { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.sie_ctrl.write(|w| { + w.sof_en().set_bit().keep_alive_en().set_bit() + }); + }); + } + + fn sof_enabled(&self) -> bool { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + let sie_ctrl = inner.ctrl_reg.sie_ctrl.read(); + sie_ctrl.sof_en().bit_is_set() && sie_ctrl.keep_alive_en().bit_is_set() + }) + } + + fn reset_bus(&mut self) { + debug!("[HostBus] reset_bus"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.sie_ctrl.write(|w| w.reset_bus().set_bit()); + }); + } + + fn set_recipient(&mut self, dev_addr: Option, endpoint: u8) { + debug!("[HostBus] set_recipient"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.addr_endp.write(|w| { + unsafe { + w.address().bits(dev_addr.map(|addr| u8::from(addr)).unwrap_or(0)); + w.endpoint().bits(endpoint) + } + }); + }); + } + + fn write_setup(&mut self, setup: usbh::types::SetupPacket) { + debug!("[HostBus] write_setup"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_dpram.setup_packet_low.write(|w| { + unsafe { + w.bmrequesttype().bits(setup.request_type); + w.brequest().bits(setup.request); + w.wvalue().bits(setup.value) + } + }); + inner.ctrl_dpram.setup_packet_high.write(|w| { + unsafe { + w.windex().bits(setup.index); + w.wlength().bits(setup.length) + } + }); + inner.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); + }); + } + + fn write_data_in(&mut self, length: u16) { + debug!("[HostBus] write_data_in"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_dpram.ep_buffer_control[0].write(|w| { + unsafe { + w.available_0().set_bit() + .pid_0().set_bit() + .full_0().clear_bit() + .length_0().bits(length) + .last_0().set_bit() + .reset().set_bit() + } + }); + inner.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + }); + } + + fn prepare_data_out(&mut self, data: &[u8]) { + debug!("[HostBus] prepare_data_out"); + critical_section::with(|cs| { + let mut inner = self.inner.borrow(cs).borrow_mut(); + inner.control_buffer_mut()[0..data.len()].copy_from_slice(data); + inner.ctrl_dpram.ep_buffer_control[0].write(|w| { + unsafe { + w.available_0().set_bit() + .pid_0().set_bit() + .full_0().set_bit() + .length_0().bits(data.len() as u16) + .last_0().set_bit() + .reset().set_bit() + } + }); + }); + } + + fn write_data_out_prepared(&mut self) { + debug!("[HostBus] write_data_out_prepared"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); + }); + } + + fn poll(&mut self) -> PollResult { + debug!("[HostBus] poll"); + critical_section::with(|cs| { + let mut inner = self.inner.borrow(cs).borrow_mut(); + PollResult { + event: inner.ints_to_event(), + poll_again_after: None, + } + }) + } + + fn process_received_data T, T>(&self, f: F) -> T { + debug!("[HostBus] process_received_data"); + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + let len = inner.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() as usize; + f(&inner.control_buffer()[0..len]) + }) + } +} + +struct Inner { + ctrl_reg: USBCTRL_REGS, + ctrl_dpram: USBCTRL_DPRAM, +} + +impl Inner { + fn control_buffer(&self) -> &[u8] { + const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; + unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), CONTROL_BUFFER_SIZE) } + } + + fn control_buffer_mut(&mut self) -> &mut [u8] { + const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + unsafe { core::slice::from_raw_parts_mut(DPRAM_BASE.offset(0x180), CONTROL_BUFFER_SIZE) } + } + + fn ints_to_event(&mut self) -> Option { + let ints = self.ctrl_reg.ints.read(); + + if ints.host_conn_dis().bit_is_set() { + let event = match self.ctrl_reg.sie_status.read().speed().bits() { + 0b01 => Event::Attached(ConnectionSpeed::Low), + 0b10 => Event::Attached(ConnectionSpeed::Full), + _ => Event::Detached, + }; + self.ctrl_reg.sie_status.write(|w| unsafe { w.speed().bits(0b11) }); + return Some(event) + } + if ints.host_resume().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.resume().set_bit()); + return Some(Event::Resume); + } + if ints.stall().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.stall_rec().set_bit()); + return Some(Event::Stall); + } + if ints.trans_complete().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.trans_complete().set_bit()); + return Some(Event::WriteComplete); + } + if ints.error_crc().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.crc_error().set_bit()); + return Some(Event::Error(Error::Crc)); + } + if ints.error_bit_stuff().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.bit_stuff_error().set_bit()); + return Some(Event::Error(Error::BitStuffing)); + } + if ints.error_rx_overflow().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.rx_overflow().set_bit()); + return Some(Event::Error(Error::RxOverflow)); + } + if ints.error_rx_timeout().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.rx_timeout().set_bit()); + return Some(Event::Error(Error::RxTimeout)); + } + if ints.error_data_seq().bit_is_set() { + self.ctrl_reg.sie_status.write(|w| w.data_seq_error().set_bit()); + return Some(Event::Error(Error::DataSequence)); + } + if ints.buff_status().bit_is_set() { + // let status = self.ctrl_reg.buff_status.read().bits(); + self.ctrl_reg.buff_status.write(|w| unsafe { w.bits(0xFFFFFFFF) }); + // TODO: handle buffer updates more gracefully. Currently we always wait for TransComplete, + // which only works for transfers that fit into a single buffer. + } + None + } +} From 5387da4cd5983b31246a0519181b5e0b78f0b0f2 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 30 Jul 2023 17:57:51 +0200 Subject: [PATCH 03/20] cleanup --- rp2040-hal/src/usb/host.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 7d94cda4d..14b4131f4 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -5,9 +5,7 @@ use usbh::{ Event, Error, }, - types::{ - ConnectionSpeed, - }, + types::ConnectionSpeed, }; use critical_section::Mutex; @@ -19,14 +17,6 @@ use crate::pac::{ USBCTRL_REGS, }; use crate::resets::SubsystemReset; -use defmt::debug; - -// Endpoint management... how to do it? -// - DPRAM_BASE + 0x180 is the start. We can allocate amount X there for control transfers -// - what about huge descriptors? Do they get read in parts? (handle multiple BuffStatus before TransComplete) -// - buffers for interrupt endpoints must be allocated when a device connects. How to handle that? -// -// How to handle delays? const CONTROL_BUFFER_SIZE: usize = 64; @@ -50,7 +40,6 @@ impl UsbHostBus { impl HostBus for UsbHostBus { fn reset_controller(&mut self) { - debug!("[HostBus] reset_controller"); critical_section::with(|cs| { let mut inner = self.inner.borrow(cs).borrow_mut(); unsafe { @@ -124,7 +113,6 @@ impl HostBus for UsbHostBus { } fn reset_bus(&mut self) { - debug!("[HostBus] reset_bus"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.sie_ctrl.write(|w| w.reset_bus().set_bit()); @@ -132,7 +120,6 @@ impl HostBus for UsbHostBus { } fn set_recipient(&mut self, dev_addr: Option, endpoint: u8) { - debug!("[HostBus] set_recipient"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.addr_endp.write(|w| { @@ -145,7 +132,6 @@ impl HostBus for UsbHostBus { } fn write_setup(&mut self, setup: usbh::types::SetupPacket) { - debug!("[HostBus] write_setup"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_dpram.setup_packet_low.write(|w| { @@ -166,7 +152,6 @@ impl HostBus for UsbHostBus { } fn write_data_in(&mut self, length: u16) { - debug!("[HostBus] write_data_in"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_dpram.ep_buffer_control[0].write(|w| { @@ -184,7 +169,6 @@ impl HostBus for UsbHostBus { } fn prepare_data_out(&mut self, data: &[u8]) { - debug!("[HostBus] prepare_data_out"); critical_section::with(|cs| { let mut inner = self.inner.borrow(cs).borrow_mut(); inner.control_buffer_mut()[0..data.len()].copy_from_slice(data); @@ -202,7 +186,6 @@ impl HostBus for UsbHostBus { } fn write_data_out_prepared(&mut self) { - debug!("[HostBus] write_data_out_prepared"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); @@ -210,7 +193,6 @@ impl HostBus for UsbHostBus { } fn poll(&mut self) -> PollResult { - debug!("[HostBus] poll"); critical_section::with(|cs| { let mut inner = self.inner.borrow(cs).borrow_mut(); PollResult { @@ -221,7 +203,6 @@ impl HostBus for UsbHostBus { } fn process_received_data T, T>(&self, f: F) -> T { - debug!("[HostBus] process_received_data"); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); let len = inner.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() as usize; From c52e41681486049d98cae3caeb23179d10f96ad8 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 30 Jul 2023 17:58:43 +0200 Subject: [PATCH 04/20] remove temporary host_blocking impl --- rp2040-hal/src/usb.rs | 1 - rp2040-hal/src/usb/host_blocking.rs | 634 ---------------------------- 2 files changed, 635 deletions(-) delete mode 100644 rp2040-hal/src/usb/host_blocking.rs diff --git a/rp2040-hal/src/usb.rs b/rp2040-hal/src/usb.rs index 91a944ac8..3e419f81e 100644 --- a/rp2040-hal/src/usb.rs +++ b/rp2040-hal/src/usb.rs @@ -124,7 +124,6 @@ use usb_device::{ #[cfg(feature = "rp2040-e5")] mod errata5; -pub mod host_blocking; pub mod host; #[allow(clippy::bool_to_int_with_if)] diff --git a/rp2040-hal/src/usb/host_blocking.rs b/rp2040-hal/src/usb/host_blocking.rs deleted file mode 100644 index 6e54779f7..000000000 --- a/rp2040-hal/src/usb/host_blocking.rs +++ /dev/null @@ -1,634 +0,0 @@ -#[cfg(feature = "defmt")] -use defmt::Format; - -use defmt::info; - -use usb_device::{UsbDirection, control::{Request, RequestType, Recipient}}; - -use crate::clocks::UsbClock; -use crate::pac::{ - RESETS, - USBCTRL_DPRAM, - USBCTRL_REGS, -}; -use crate::resets::SubsystemReset; - -pub struct BlockingHost { - ctrl_reg: USBCTRL_REGS, - ctrl_dpram: USBCTRL_DPRAM, -} - -impl BlockingHost { - pub fn new( - ctrl_reg: USBCTRL_REGS, - ctrl_dpram: USBCTRL_DPRAM, - _pll: UsbClock, - resets: &mut RESETS, - ) -> Self { - ctrl_reg.reset_bring_down(resets); - ctrl_reg.reset_bring_up(resets); - - Self { ctrl_reg, ctrl_dpram } - } - - pub fn run(&mut self, delay: &mut cortex_m::delay::Delay) { - let event = self.wait_for(|e| matches!(e, Event::ConnDis(Some(_)))); - info!("New USB device: {}", event); - - delay.delay_ms(20); - - self.ctrl_dpram.epx_control.write(|w| { - unsafe { - w.enable().set_bit() - .interrupt_per_buff().set_bit() - .endpoint_type().control() - .buffer_address().bits(0x180) - } - }); - - let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 1 << 8, 0, 18); - info!("Received device descriptor from ADDR0/EDPT0: {}", buf); - - self.control_out(RequestType::Standard, Recipient::Device, Request::SET_ADDRESS, 42, 0, &[]); - info!("Assigned address 42 to device"); - self.ctrl_reg.addr_endp.write(|w| { - unsafe { w.address().bits(42) } - }); - - let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 1 << 8, 0, 18); - print_device_descriptor(buf); - - let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 2 << 8, 0, 9); - info!("Get config descriptor: received first 9 bytes: {}", buf); - let total_length = ((buf[3] as u16) << 8) | (buf[2] as u16); - - let buf = self.control_in(RequestType::Standard, Recipient::Device, Request::GET_DESCRIPTOR, 2 << 8, 0, total_length); - print_config_descriptor(buf); - - let cfg_value = buf[5] as u16; - - info!("SetConfiguration({})", cfg_value); - self.control_out(RequestType::Standard, Recipient::Device, Request::SET_CONFIGURATION, cfg_value, 0, &[]); - - info!("Set configuration complete!"); - // self.write_setup_packet(UsbDirection::In, RequestType::Standard, Recipient::Device, Request::SET_CONFIGURATION, cfg_value, 0, 0); - // self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); - // info!("SetConfiguration({})", cfg_value); - // self.wait_for(|e| matches!(e, Event::TransComplete)); - // self.ctrl_dpram.ep_buffer_control[0].write(|w| { - // w.pid_0().set_bit(); - // w.full_0().clear_bit(); - // w.available_0().set_bit(); - // unsafe { w.length_0().bits(0) } - // }); - // self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); - // self.wait_for(|e| matches!(e, Event::TransComplete)); - - // self.ctrl_reg.addr_endp1.write(|w| { - // unsafe { w.address().bits(42).endpoint().bits(1).intep_dir().clear_bit() } - // }); - - let buf = self.control_in(RequestType::Standard, Recipient::Interface, Request::GET_DESCRIPTOR, 0x22 << 8, 0, 54); - print_hid_report(buf); - - defmt::info!("SET PROTOCOL (boot)"); - self.control_out(RequestType::Class, Recipient::Interface, 0x0b, 0, 0, &[]); - - delay.delay_us(100); - - let sequence = [ - 0b001, - 0b010, - 0b100, - 0b111, - 0b000, - 0b111, - 0b000, - 0b100, - 0b010, - 0b001, - 0b111, - 0b000, - 0b111, - 0b000, - ]; - - let mut index = 0; - - loop { - defmt::info!("SET REPORT {}", sequence[index]); - self.control_out(RequestType::Class, Recipient::Interface, 0x09, 2 << 8, 0, &[sequence[index]]); - self.ctrl_reg.sie_ctrl.write(|w| w.keep_alive_en().set_bit()); - delay.delay_ms(200); - index += 1; - if index == sequence.len() { - index = 0; - } - } - - - // let mut state = 1; - - // loop { - // self.control_out(RequestType::Class, Recipient::Interface, 0x09, 2 << 8, 0, &[state]); - // info!("toggled"); - // delay.delay_ms(1000); - // state = !state; - // } - - // self.ctrl_reg.addr_endp.write(|w| { - // unsafe { w.endpoint().bits(1) } - // }); - // self.ctrl_dpram.ep_control[0].write(|w| { - // w.enable().set_bit(); - // w.endpoint_type().interrupt(); - // w.interrupt_per_buff().set_bit(); - // unsafe { w.buffer_address().bits(0x280) } - // }); - // self.ctrl_dpram.ep_buffer_control[1].write(|w| { - // w.pid_0().set_bit(); - // w.full_0().clear_bit(); - // w.available_0().set_bit(); - // w.reset().set_bit(); - // unsafe { w.length_0().bits(54) } - // }); - - // self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); - - // self.wait_for(|e| matches!(e, Event::TransComplete)); - - // info!("INT TRANS COMPLETE"); - - // self.ctrl_reg.int_ep_ctrl.write(|w| { - // unsafe { w.int_ep_active().bits(1) } - // }); - - // info!("Configured interrupt endpoint"); - - // loop { - // let e = self.wait_for(|e| matches!(e, Event::BuffStatus(_))); - // info!("Buff status... {}", e); - - // const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; - // let data = unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x280), 54) }; - // info!("INT DATA: {}", data); - // } - } - - fn wait_for bool>(&mut self, f: F) -> Event { - loop { - let event = self.wait_for_event(); - if f(event) { - return event - } - - match event { - Event::ErrCrc | Event::ErrDataSeq | Event::ErrBitStuff | Event::ErrRxTimeout | Event::ErrRxOverflow | Event::Stall | Event::ConnDis(_) => { - defmt::error!("ERROR: {}", event); - }, - _ => {} - } - } - } - - fn wait_for_event(&mut self) -> Event { - let ints = self.ctrl_reg.ints.read(); - - if ints.host_conn_dis().bit_is_set() { - let speed = match self.ctrl_reg.sie_status.read().speed().bits() { - 0b01 => Some(ConnectionSpeed::Low), - 0b10 => Some(ConnectionSpeed::Full), - _ => None, - }; - self.ctrl_reg.sie_status.write(|w| unsafe { w.speed().bits(0b11) }); - return Event::ConnDis(speed) - } - if ints.host_resume().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.resume().set_bit()); - return Event::Resume; - } - if ints.stall().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.stall_rec().set_bit()); - return Event::Stall; - } - if ints.trans_complete().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.trans_complete().set_bit()); - return Event::TransComplete; - } - if ints.error_crc().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.crc_error().set_bit()); - return Event::ErrCrc; - } - if ints.error_bit_stuff().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.bit_stuff_error().set_bit()); - return Event::ErrBitStuff; - } - if ints.error_rx_overflow().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.rx_overflow().set_bit()); - return Event::ErrRxOverflow; - } - if ints.error_rx_timeout().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.rx_timeout().set_bit()); - return Event::ErrRxTimeout; - } - if ints.error_data_seq().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.data_seq_error().set_bit()); - return Event::ErrDataSeq; - } - if ints.host_sof().bit_is_set() { - let count = self.ctrl_reg.sof_rd.read().count().bits(); - return Event::Sof(count); - }; - if ints.buff_status().bit_is_set() { - let status = self.ctrl_reg.buff_status.read().bits(); - self.ctrl_reg.buff_status.write(|w| unsafe { w.bits(0xFFFFFFFF) }); - return Event::BuffStatus(status); - } - if ints.bus_reset().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.bus_reset().set_bit()); - return Event::BusReset; - } - Event::None - } - - pub fn reset(&self) { - defmt::debug!("RESET"); - unsafe { - let raw_ctrl_reg = - core::slice::from_raw_parts_mut(USBCTRL_REGS::ptr() as *mut u32, 1 + 0x98 / 4); - raw_ctrl_reg.fill(0); - - let raw_ctrl_pdram = - core::slice::from_raw_parts_mut(USBCTRL_DPRAM::ptr() as *mut u32, 1 + 0xfc / 4); - raw_ctrl_pdram.fill(0); - } - - self.ctrl_reg.usb_muxing.modify(|_, w| { - w.to_phy().set_bit(); - w.softcon().set_bit() - }); - - // Taken from hcd_rp2040.c, with comment: - // // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En) - self.ctrl_reg.usb_pwr.modify(|_, w| { - w.vbus_detect().set_bit() - .vbus_detect_override_en().set_bit() - }); - - self.ctrl_reg.sie_ctrl.modify(|_, w| { - // The host needs to send keep-alive packets to the device every 1ms to keep the device from suspending. In Full Speed - // mode this is done by sending a SOF (start of frame) packet. In Low Speed mode, an EOP (end of packet) is sent. When - // setting up the controller, SIE_CTRL.KEEP_ALIVE_EN and SIE_CTRL.SOF_EN should be set to enable these packets. - w.sof_en().set_bit() - .keep_alive_en().set_bit() - .pulldown_en().set_bit() - .sof_sync().set_bit() - }); - - self.ctrl_reg.main_ctrl.modify(|_, w| { - w.host_ndevice().set_bit() - .controller_en().set_bit() - }); - - self.ctrl_reg.inte.modify(|_, w| { - w.buff_status().set_bit() - .bus_reset().set_bit() - .host_conn_dis().set_bit() - .host_resume().set_bit() - .stall().set_bit() - .trans_complete().set_bit() - .error_rx_timeout().set_bit() - .error_data_seq().set_bit() - .host_sof().set_bit() - .ep_stall_nak().set_bit() - .error_crc().set_bit() - .error_bit_stuff().set_bit() - .error_rx_overflow().set_bit() - }); - } - - fn control_in(&mut self, request_type: RequestType, recipient: Recipient, request: u8, value: u16, index: u16, length: u16) -> &[u8] { - // 1. Setup packet - self.write_setup_packet(UsbDirection::In, request_type, recipient, request, value, index, length); - self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("IN: setup complete"); - - // 2. IN packet(s) - self.ctrl_dpram.ep_buffer_control[0].write(|w| { - w.pid_0().set_bit(); - w.full_0().clear_bit(); - w.available_0().set_bit(); - unsafe { w.length_0().bits(length) } - }); - self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("IN: data complete"); - - let received_len = self.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() as usize; - - // 3. Confirmation (empty OUT packet) - self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { - unsafe { - w.available_0().set_bit() - .pid_0().set_bit() - .full_0().set_bit() - .length_0().bits(0) - .last_0().set_bit() - .reset().set_bit() - } - }); - self.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); - - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("IN: confirm complete"); - - self.control_buffer(received_len) - } - - fn control_out(&mut self, request_type: RequestType, recipient: Recipient, request: u8, value: u16, index: u16, buf: &[u8]) { - // 1. Setup packet - self.write_setup_packet(UsbDirection::Out, request_type, recipient, request, value, index, buf.len() as u16); - self.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("OUT: setup complete"); - if buf.len() > 0 { - // 2. OUT data - self.control_buffer_mut(buf.len()).copy_from_slice(buf); - self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { - unsafe { - w.available_0().set_bit() - .pid_0().set_bit() - .full_0().set_bit() - .length_0().bits(buf.len() as u16) - .last_0().set_bit() - .reset().set_bit() - } - }); - self.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("OUT: send complete"); - } - // 3. IN data (empty packet) for confirmation - self.ctrl_dpram.ep_buffer_control[0].modify(|r, w| { - unsafe { - w.available_0().set_bit() - .pid_0().set_bit() - .full_0().clear_bit() - .length_0().bits(0) - .last_0().set_bit() - .reset().set_bit() - } - }); - self.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); - self.wait_for(|e| matches!(e, Event::TransComplete)); - defmt::debug!("OUT: confirm complete"); - } - - pub fn write_setup_packet( - &self, - direction: UsbDirection, - request_type: RequestType, - recipient: Recipient, - request: u8, - value: u16, - index: u16, - length: u16 - ) { - self.ctrl_dpram.setup_packet_low.write(|w| { - unsafe { - w.bmrequesttype().bits( - (direction as u8) | - ((request_type as u8) << 5) | - (recipient as u8) - ); - w.brequest().bits(request); - w.wvalue().bits(value) - } - }); - - self.ctrl_dpram.setup_packet_high.write(|w| { - unsafe { - w.windex().bits(index); - w.wlength().bits(length) - } - }); - - self.dump_setup_packet(); - } - - fn dump_setup_packet(&self) { - let low = self.ctrl_dpram.setup_packet_low.read().bits(); - let high = self.ctrl_dpram.setup_packet_high.read().bits(); - defmt::debug!("SETUP PACKET: {:#X} {:#X} {:#X} {:#X} {:#X} {:#X} {:#X} {:#X}", - low & 0x000000FF, - (low & 0x0000FF00) >> 8, - (low & 0x00FF0000) >> 16, - (low & 0xFF000000) >> 24, - high & 0x000000FF, - (high & 0x0000FF00) >> 8, - (high & 0x00FF0000) >> 16, - (high & 0xFF000000) >> 24, - ); - } - - pub fn control_buffer(&self, len: usize) -> &[u8] { - const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; - unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } - } - - fn control_buffer_mut(&self, len: usize) -> &mut [u8] { - const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; - unsafe { core::slice::from_raw_parts_mut(DPRAM_BASE.offset(0x180), len) } - } -} - -#[cfg_attr(feature = "defmt", derive(Format))] -#[derive(Copy, Clone)] -pub enum Event { - None, - ConnDis(Option), - Stall, - Resume, - ErrCrc, - ErrBitStuff, - ErrRxOverflow, - ErrRxTimeout, - ErrDataSeq, - Sof(u16), - TransComplete, - BuffStatus(u32), - BusReset, -} - -#[derive(Copy, Clone)] -pub enum ConnectionSpeed { - Low, - Full, -} - -#[cfg(feature = "defmt")] -impl defmt::Format for ConnectionSpeed { - fn format(&self, fmt: defmt::Formatter) { - defmt::write!(fmt, "{}", match self { - ConnectionSpeed::Low => "low-speed", - ConnectionSpeed::Full => "full-speed", - }) - } -} - -fn print_device_descriptor(bytes: &[u8]) -> usize { - let size = bytes[0]; - if size != bytes.len() as u8 { - defmt::error!("Invalid device descriptor? bLength={} does not match buffer size {}", size, bytes.len()); - } else if size != 18 { - defmt::info!("Device descriptor too short ({} bytes), not printing for now.", size); - } else { - defmt::info!("Device descriptor:\n - Desc. Type:\t\t{}\n - USB Version:\t\t{}{}.{}.{}\n - Device Class:\t{}\n - vendor/product:\t{:#X}:{:#X}\n - #configurations:\t{}", - bytes[1], (bytes[3] & 0xF0) >> 4, bytes[3] & 0x0F, (bytes[2] & 0xF0) >> 4, bytes[2] & 0x0F, bytes[4], - ((bytes[9] as u16) << 8) | (bytes[8] as u16), - ((bytes[11] as u16) << 8) | (bytes[10] as u16), - bytes[17] - ); - } - bytes.len() -} - -fn print_config_descriptor(bytes: &[u8]) -> usize { - defmt::info!("Config descriptor:\n - Num Interfaces:\t{}\n - Config Value:\t{}\n - Self powered:\t{}\n - Remote wakeup:\t{}\n - Max power (mA):\t{}\n", - bytes[4], bytes[5], (bytes[7] >> 6) & 1 == 1, (bytes[7] >> 5) & 1 == 1, bytes[8] * 2 - ); - let mut consumed = 9; // size of config descriptor itself - - loop { - if bytes.len() > consumed { - consumed += print_descriptor(&bytes[consumed..]); - } else { - break - } - } - - consumed -} - -fn print_interface_descriptor(bytes: &[u8]) -> usize { - defmt::info!( - "Interface descriptor:\n - Interface num:\t{}\n - Alt setting: \t{}\n - Num endpoints:\t{}\n - Interface class:\t{}\n - Iface subclass:\t{}\n - Iface protocol:\t{}\n", - bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] - ); - 9 -} - -fn print_endpoint_descriptor(bytes: &[u8]) -> usize { - defmt::info!( - "Endpoint descriptor:\n - EP Address:\t{} ({})\n - Transfer type:\t{}\n - Sync type:\t{}\n - Usage type:\t{}\n - Max packet:\t{}\n - Poll interval:\t{}\n", - bytes[2] & 0b111, - if (bytes[2] >> 7) & 1 == 1 { "IN" } else { "OUT" }, - match bytes[3] & 0b11 { - 0 => "control", - 1 => "isochronous", - 2 => "bulk", - 3 => "interrupt", - _ => unreachable!(), - }, - match (bytes[3] >> 2) & 0b11 { - 0 => "none", - 1 => "asynchronous", - 2 => "adaptive", - 3 => "synchronous", - _ => unreachable!(), - }, - match (bytes[3] >> 4) & 0b11 { - 0 => "data", - 1 => "feedback", - 2 => "explicit feedback", - 3 => "(reserved)", - _ => unreachable!(), - }, - bytes[4] as u16 | ((bytes[5] as u16) << 8), - bytes[6] - ); - 7 -} - -fn print_hid_kbd_descriptor(bytes: &[u8]) -> usize { - defmt::info!( - "HID (Keyboard) Descriptor:\n - HID version:\t{}{}.{}.{}\n - Country code:\t{}\n - Report type:\t{:#X}\n - Report length:\t{}\n", - (bytes[3] & 0xF0) >> 4, bytes[3] & 0x0F, (bytes[2] & 0xF0) >> 4, bytes[2] & 0x0F, - bytes[4], bytes[6], bytes[7] - ); - 9 -} - -fn print_descriptor(bytes: &[u8]) -> usize { - match bytes[1] { - 1 => print_device_descriptor(bytes), - 2 => print_config_descriptor(bytes), - 4 => print_interface_descriptor(bytes), - 5 => print_endpoint_descriptor(bytes), - 0x21 => print_hid_kbd_descriptor(bytes), - n => { - defmt::error!("Not implemented: {} ({} bytes)", n, bytes[0]); - bytes[0] as usize - } - } -} - -fn print_hid_report(bytes: &[u8]) { - let mut consumed = 0; - loop { - consumed += print_hid_item(&bytes[consumed..]); - if consumed == bytes.len() { - return - } - } -} - -fn print_hid_item(bytes: &[u8]) -> usize { - if bytes[0] == 0b11111110 { - // long item - let size = bytes[1]; - let tag = bytes[2]; - let data = &bytes[3..(3 + size as usize)]; - defmt::info!("HID ITEM (long): size={} tag={} data={}", size, tag, data); - 3 + size as usize - } else { - // short item - let size = bytes[0] & 0b11; - - let type_ = match (bytes[0] >> 2) & 0b11 { - 0 => "main", - 1 => "global", - 2 => "local", - 3 => "reserved", - _ => unreachable!(), - }; - - let tag = (bytes[0] >> 4) & 0b1111; - - defmt::info!("HID ITEM: size={}, type={}, tag={}, data={}", size, type_, tag, &bytes[1..(1 + size) as usize]); - - match (bytes[0] >> 2) & 0b11 { - 0 => { // MAIN - if size > 0 { - match bytes[1] | 0b11111100 { - 0b10000000 => defmt::info!(" INPUT, size {}", bytes[1] | 0b11), - 0b10010000 => defmt::info!(" OUTPUT, size {}", bytes[1] | 0b11), - 0b10110000 => defmt::info!(" FEATURE, size {}", bytes[1] | 0b11), - 0b10100000 => defmt::info!(" COLLECTION, size {}", bytes[1] | 0b11), - 0b11000000 => defmt::info!(" END COLLECTION, size {}", bytes[1] | 0b11), - _ => defmt::error!("Not sure how to interpret {:#X}", bytes[1]), - } - } - }, - 1 => { // GLOBAL - }, - 2 => { // LOCAL - }, - 3 => { /* reserved */ } - _ => unreachable!(), - } - - 1 + size as usize - } -} From 35a1e08f7be4b84c643ce7569bb1d8a35c808d0d Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Tue, 1 Aug 2023 11:02:05 +0200 Subject: [PATCH 05/20] WIP interrupt polling support --- rp2040-hal/src/usb/host.rs | 93 ++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 14b4131f4..9c64c9f12 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -5,7 +5,11 @@ use usbh::{ Event, Error, }, - types::ConnectionSpeed, + types::{ + ConnectionSpeed, + DeviceAddress, + TransferType, + }, }; use critical_section::Mutex; @@ -82,16 +86,6 @@ impl HostBus for UsbHostBus { .error_bit_stuff().set_bit() .error_rx_overflow().set_bit() }); - - // FIXME: put this elsewhere! - inner.ctrl_dpram.epx_control.write(|w| { - unsafe { - w.enable().set_bit() - .interrupt_per_buff().set_bit() - .endpoint_type().control() - .buffer_address().bits(0x180) - } - }); }); } @@ -119,7 +113,7 @@ impl HostBus for UsbHostBus { }); } - fn set_recipient(&mut self, dev_addr: Option, endpoint: u8) { + fn set_recipient(&mut self, dev_addr: Option, endpoint: u8, transfer_type: TransferType) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.addr_endp.write(|w| { @@ -128,6 +122,20 @@ impl HostBus for UsbHostBus { w.endpoint().bits(endpoint) } }); + + inner.ctrl_dpram.epx_control.write(|w| { + unsafe { + w.enable().set_bit() + .interrupt_per_buff().set_bit() + .buffer_address().bits(0x180); + match transfer_type { + TransferType::Control => w.endpoint_type().control(), + TransferType::Isochronous => w.endpoint_type().isochronous(), + TransferType::Bulk => w.endpoint_type().bulk(), + TransferType::Interrupt => w.endpoint_type().interrupt(), + } + } + }); }); } @@ -209,6 +217,59 @@ impl HostBus for UsbHostBus { f(&inner.control_buffer()[0..len]) }) } + + unsafe fn control_buffer(&self, len: usize) -> &[u8] { + const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; + unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } + } + + fn create_interrupt_pipe(&mut self, device_address: DeviceAddress, endpoint_number: u8, size: u16) -> u32 { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + // TODO: handle more than one interrupt + inner.ctrl_dpram.ep_control[0].write(|w| { +// w.bits( +// /* +// uint32_t ep_reg = EP_CTRL_ENABLE_BITS +// | EP_CTRL_INTERRUPT_PER_BUFFER +// | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) +// | dpram_offset; +// if ( bmInterval ) +// { +// ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); +// } +// */ +// ); + w.interrupt_per_buff().set_bit(); + w.double_buffered().clear_bit(); + w.endpoint_type().interrupt(); + unsafe { w.buffer_address().bits(0x180 + CONTROL_BUFFER_SIZE as u16) } + }); + inner.ctrl_dpram.ep_control[0].modify(|r, w| { + unsafe { w.bits(r.bits() | (9 << 18)) } + }); + cortex_m::asm::delay(12); + inner.ctrl_dpram.ep_control[0].write(|w| w.enable().set_bit()); + let ep_ctrl_bits = inner.ctrl_dpram.ep_control[0].read().bits(); + inner.ctrl_dpram.ep_buffer_control[1].write(|w| { + w.available_0().set_bit(); + w.full_0().clear_bit(); + unsafe { w.length_0().bits(size) } + }); + inner.ctrl_reg.addr_endp1.write(|w| { + unsafe { + w.address().bits(device_address.into()); + w.endpoint().bits(endpoint_number); + w.intep_dir().clear_bit() // IN (FIXME) + } + }); + cortex_m::asm::delay(12); + inner.ctrl_reg.int_ep_ctrl.write(|w| { + unsafe { w.int_ep_active().bits(1) } + }); + ep_ctrl_bits + }) + } } struct Inner { @@ -272,10 +333,16 @@ impl Inner { return Some(Event::Error(Error::DataSequence)); } if ints.buff_status().bit_is_set() { - // let status = self.ctrl_reg.buff_status.read().bits(); + let status = self.ctrl_reg.buff_status.read().bits(); self.ctrl_reg.buff_status.write(|w| unsafe { w.bits(0xFFFFFFFF) }); // TODO: handle buffer updates more gracefully. Currently we always wait for TransComplete, // which only works for transfers that fit into a single buffer. + + for i in 0..32 { + if (status >> i) & 1 == 1 { + return Some(Event::InterruptData(i as u8)); + } + } } None } From 79612c91fefb46867bbedbba8859f592a14a448d Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Thu, 3 Aug 2023 23:42:56 +0200 Subject: [PATCH 06/20] interrupt polling works, pass on some references for pipe support --- rp2040-hal/src/usb/host.rs | 165 ++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 55 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 9c64c9f12..33f8e41e2 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -11,6 +11,7 @@ use usbh::{ TransferType, }, }; +use usb_device::UsbDirection; use critical_section::Mutex; use core::cell::RefCell; @@ -67,7 +68,6 @@ impl HostBus for UsbHostBus { w.sof_en().set_bit() .keep_alive_en().set_bit() .pulldown_en().set_bit() - .sof_sync().set_bit() }); inner.ctrl_reg.main_ctrl.modify(|_, w| { w.host_ndevice().set_bit() @@ -92,8 +92,8 @@ impl HostBus for UsbHostBus { fn enable_sof(&mut self) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.sie_ctrl.write(|w| { - w.sof_en().set_bit().keep_alive_en().set_bit() + inner.ctrl_reg.sie_ctrl.modify(|_, w| { + w.sof_en().set_bit().keep_alive_en().set_bit().pulldown_en().set_bit() }); }); } @@ -109,7 +109,7 @@ impl HostBus for UsbHostBus { fn reset_bus(&mut self) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.sie_ctrl.write(|w| w.reset_bus().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.reset_bus().set_bit()); }); } @@ -123,7 +123,7 @@ impl HostBus for UsbHostBus { } }); - inner.ctrl_dpram.epx_control.write(|w| { + inner.ctrl_dpram.epx_control.modify(|_, w| { unsafe { w.enable().set_bit() .interrupt_per_buff().set_bit() @@ -155,24 +155,24 @@ impl HostBus for UsbHostBus { w.wlength().bits(setup.length) } }); - inner.ctrl_reg.sie_ctrl.write(|w| w.send_setup().set_bit().start_trans().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_data().clear_bit().receive_data().clear_bit().send_setup().set_bit().start_trans().set_bit()); }); } - fn write_data_in(&mut self, length: u16) { + fn write_data_in(&mut self, length: u16, pid: bool) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_dpram.ep_buffer_control[0].write(|w| { unsafe { - w.available_0().set_bit() - .pid_0().set_bit() - .full_0().clear_bit() + w.available_0().set_bit(); + w.pid_0().bit(pid); + w.full_0().clear_bit() .length_0().bits(length) .last_0().set_bit() .reset().set_bit() } }); - inner.ctrl_reg.sie_ctrl.write(|w| w.receive_data().set_bit().start_trans().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_data().clear_bit().send_setup().clear_bit().receive_data().set_bit().start_trans().set_bit()); }); } @@ -196,7 +196,7 @@ impl HostBus for UsbHostBus { fn write_data_out_prepared(&mut self) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.sie_ctrl.write(|w| w.send_data().set_bit().start_trans().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_setup().clear_bit().receive_data().clear_bit().send_data().set_bit().start_trans().set_bit()); }); } @@ -223,55 +223,104 @@ impl HostBus for UsbHostBus { unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } } - fn create_interrupt_pipe(&mut self, device_address: DeviceAddress, endpoint_number: u8, size: u16) -> u32 { + fn create_interrupt_pipe(&mut self, device_address: DeviceAddress, endpoint_number: u8, direction: UsbDirection, size: u16, interval: u8) -> Option<(*mut u8, u8)> { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - // TODO: handle more than one interrupt inner.ctrl_dpram.ep_control[0].write(|w| { -// w.bits( -// /* -// uint32_t ep_reg = EP_CTRL_ENABLE_BITS -// | EP_CTRL_INTERRUPT_PER_BUFFER -// | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) -// | dpram_offset; -// if ( bmInterval ) -// { -// ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); -// } -// */ -// ); - w.interrupt_per_buff().set_bit(); - w.double_buffered().clear_bit(); - w.endpoint_type().interrupt(); - unsafe { w.buffer_address().bits(0x180 + CONTROL_BUFFER_SIZE as u16) } - }); - inner.ctrl_dpram.ep_control[0].modify(|r, w| { - unsafe { w.bits(r.bits() | (9 << 18)) } + unsafe { + w.bits( + (0x180 + CONTROL_BUFFER_SIZE as u32) | + ((TransferType::Interrupt as u8 as u32) << 26) | + (1 << 29) | // interrupt per buf + (1 << 31) | // enable + ((interval as u32 - 1) << 16) + ) + } }); - cortex_m::asm::delay(12); - inner.ctrl_dpram.ep_control[0].write(|w| w.enable().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.sof_sync().set_bit()); let ep_ctrl_bits = inner.ctrl_dpram.ep_control[0].read().bits(); - inner.ctrl_dpram.ep_buffer_control[1].write(|w| { - w.available_0().set_bit(); + inner.ctrl_dpram.ep_buffer_control[2].write(|w| { + w.last_0().set_bit(); + w.pid_0().clear_bit(); w.full_0().clear_bit(); + w.reset().set_bit(); unsafe { w.length_0().bits(size) } }); + cortex_m::asm::delay(12); + inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); + let buf_control = inner.ctrl_dpram.ep_buffer_control[2].read().bits(); inner.ctrl_reg.addr_endp1.write(|w| { unsafe { + w.intep_preamble().clear_bit(); w.address().bits(device_address.into()); w.endpoint().bits(endpoint_number); - w.intep_dir().clear_bit() // IN (FIXME) + w.intep_dir().bit(direction == UsbDirection::Out) } }); cortex_m::asm::delay(12); - inner.ctrl_reg.int_ep_ctrl.write(|w| { - unsafe { w.int_ep_active().bits(1) } + inner.ctrl_reg.int_ep_ctrl.modify(|_, w| { + unsafe { w.int_ep_active().bits(0x01) } }); - ep_ctrl_bits + + const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + let buf_ptr = unsafe { DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize) }; + Some((buf_ptr, 2)) }) } + + fn release_interrupt_pipe(&mut self, pipe_ref: u8) {} + + fn received_len(&self) -> u16 { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() + }) + } + + fn dump_dpram(&self) { + const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; + let dpram = unsafe { core::slice::from_raw_parts(DPRAM_BASE, 0x180) }; + defmt::info!("DPRAM: {}", dpram); + let regs = unsafe { core::slice::from_raw_parts(USBCTRL_REGS::ptr() as *const u8, 156) }; + defmt::info!("REGS: {}", regs); + } + + fn pipe_buf(&self, pipe_index: u8) -> &[u8] { + const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; + unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize), 8) } + } + + fn pipe_continue(&self, pipe_index: u8) { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + let buf_control = inner.ctrl_dpram.ep_buffer_control[2].read().bits(); + //defmt::debug!("BUF CONTROL (continue): {:#X}, ep int ctr: {:#X}", buf_control, inner.ctrl_reg.int_ep_ctrl.read().bits()); + inner.ctrl_dpram.ep_buffer_control[2].modify(|r, w| { + w.last_0().set_bit(); + w.pid_0().bit(!r.pid_0().bit()); + w.full_0().clear_bit(); + w.reset().set_bit(); + unsafe { w.length_0().bits(8) } + }); + cortex_m::asm::delay(12); + inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); + // inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| { + // w.full_0().clear_bit(); + // w.available_0().set_bit() + // }); + }) + } + + fn interrupt_on_sof(&mut self, enable: bool) { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.inte.modify(|_, w| w.host_sof().bit(enable)); + }); + } } +unsafe impl Send for UsbHostBus {} + struct Inner { ctrl_reg: USBCTRL_REGS, ctrl_dpram: USBCTRL_DPRAM, @@ -297,53 +346,59 @@ impl Inner { 0b10 => Event::Attached(ConnectionSpeed::Full), _ => Event::Detached, }; - self.ctrl_reg.sie_status.write(|w| unsafe { w.speed().bits(0b11) }); + self.ctrl_reg.sie_status.modify(|_, w| unsafe { w.speed().bits(0b11) }); return Some(event) } if ints.host_resume().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.resume().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.resume().set_bit()); return Some(Event::Resume); } if ints.stall().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.stall_rec().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.stall_rec().set_bit()); return Some(Event::Stall); } - if ints.trans_complete().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.trans_complete().set_bit()); - return Some(Event::WriteComplete); - } if ints.error_crc().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.crc_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.crc_error().set_bit()); return Some(Event::Error(Error::Crc)); } if ints.error_bit_stuff().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.bit_stuff_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.bit_stuff_error().set_bit()); return Some(Event::Error(Error::BitStuffing)); } if ints.error_rx_overflow().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.rx_overflow().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.rx_overflow().set_bit()); return Some(Event::Error(Error::RxOverflow)); } if ints.error_rx_timeout().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.rx_timeout().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.rx_timeout().set_bit()); return Some(Event::Error(Error::RxTimeout)); } if ints.error_data_seq().bit_is_set() { - self.ctrl_reg.sie_status.write(|w| w.data_seq_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.data_seq_error().set_bit()); return Some(Event::Error(Error::DataSequence)); } if ints.buff_status().bit_is_set() { let status = self.ctrl_reg.buff_status.read().bits(); - self.ctrl_reg.buff_status.write(|w| unsafe { w.bits(0xFFFFFFFF) }); // TODO: handle buffer updates more gracefully. Currently we always wait for TransComplete, // which only works for transfers that fit into a single buffer. for i in 0..32 { if (status >> i) & 1 == 1 { - return Some(Event::InterruptData(i as u8)); + self.ctrl_reg.buff_status.modify(|_, w| unsafe { w.bits(1 << i) }); + // control transfers (buffer 0) + if i != 0 { + return Some(Event::InterruptPipe(i as u8)); + } } } } + if ints.trans_complete().bit_is_set() { + self.ctrl_reg.sie_status.modify(|_, w| w.trans_complete().set_bit()); + return Some(Event::TransComplete); + } + if ints.host_sof().bit_is_set() { + return Some(Event::Sof); + } None } } From 01a799c19822a44dfd117f3867554707bc216cf3 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Fri, 4 Aug 2023 14:09:56 +0200 Subject: [PATCH 07/20] updates after merge from latest main --- rp2040-hal/src/usb/host.rs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 33f8e41e2..8bba940c5 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -277,14 +277,6 @@ impl HostBus for UsbHostBus { }) } - fn dump_dpram(&self) { - const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; - let dpram = unsafe { core::slice::from_raw_parts(DPRAM_BASE, 0x180) }; - defmt::info!("DPRAM: {}", dpram); - let regs = unsafe { core::slice::from_raw_parts(USBCTRL_REGS::ptr() as *const u8, 156) }; - defmt::info!("REGS: {}", regs); - } - fn pipe_buf(&self, pipe_index: u8) -> &[u8] { const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize), 8) } @@ -294,7 +286,6 @@ impl HostBus for UsbHostBus { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); let buf_control = inner.ctrl_dpram.ep_buffer_control[2].read().bits(); - //defmt::debug!("BUF CONTROL (continue): {:#X}, ep int ctr: {:#X}", buf_control, inner.ctrl_reg.int_ep_ctrl.read().bits()); inner.ctrl_dpram.ep_buffer_control[2].modify(|r, w| { w.last_0().set_bit(); w.pid_0().bit(!r.pid_0().bit()); @@ -350,31 +341,31 @@ impl Inner { return Some(event) } if ints.host_resume().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.resume().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.resume().clear_bit_by_one()); return Some(Event::Resume); } if ints.stall().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.stall_rec().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.stall_rec().clear_bit_by_one()); return Some(Event::Stall); } if ints.error_crc().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.crc_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.crc_error().clear_bit_by_one()); return Some(Event::Error(Error::Crc)); } if ints.error_bit_stuff().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.bit_stuff_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.bit_stuff_error().clear_bit_by_one()); return Some(Event::Error(Error::BitStuffing)); } if ints.error_rx_overflow().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.rx_overflow().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.rx_overflow().clear_bit_by_one()); return Some(Event::Error(Error::RxOverflow)); } if ints.error_rx_timeout().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.rx_timeout().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.rx_timeout().clear_bit_by_one()); return Some(Event::Error(Error::RxTimeout)); } if ints.error_data_seq().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.data_seq_error().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.data_seq_error().clear_bit_by_one()); return Some(Event::Error(Error::DataSequence)); } if ints.buff_status().bit_is_set() { @@ -393,7 +384,7 @@ impl Inner { } } if ints.trans_complete().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.trans_complete().set_bit()); + self.ctrl_reg.sie_status.modify(|_, w| w.trans_complete().clear_bit_by_one()); return Some(Event::TransComplete); } if ints.host_sof().bit_is_set() { From 355ddf1c9f3adb6f35c71265741d7651d33f3e94 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sat, 5 Aug 2023 19:51:10 +0200 Subject: [PATCH 08/20] updates after usbh changes, some cleanup --- rp2040-hal/src/usb/host.rs | 54 ++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 8bba940c5..ef5c6a9c8 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -1,7 +1,14 @@ +//! USB host support +//! +//! This module implements host mode for the USB. Host mode means the RP2040 controls the USB devices connected to it, +//! it does not act as a USB device itself. +//! +//! Host-mode and device-mode are mutually exclusive. The controller can only operate as one of them at a time. +//! + use usbh::{ bus::{ HostBus, - PollResult, Event, Error, }, @@ -25,11 +32,15 @@ use crate::resets::SubsystemReset; const CONTROL_BUFFER_SIZE: usize = 64; +/// USB host bus implementation pub struct UsbHostBus { inner: Mutex>, } impl UsbHostBus { + /// Initialize USB host bus + /// + /// The host bus implements [`usbh::bus::HostBus`]. pub fn new( ctrl_reg: USBCTRL_REGS, ctrl_dpram: USBCTRL_DPRAM, @@ -46,7 +57,7 @@ impl UsbHostBus { impl HostBus for UsbHostBus { fn reset_controller(&mut self) { critical_section::with(|cs| { - let mut inner = self.inner.borrow(cs).borrow_mut(); + let inner = self.inner.borrow(cs).borrow_mut(); unsafe { let raw_ctrl_reg = core::slice::from_raw_parts_mut(USBCTRL_REGS::ptr() as *mut u32, 1 + 0x98 / 4); @@ -200,21 +211,10 @@ impl HostBus for UsbHostBus { }); } - fn poll(&mut self) -> PollResult { + fn poll(&mut self) -> Option { critical_section::with(|cs| { let mut inner = self.inner.borrow(cs).borrow_mut(); - PollResult { - event: inner.ints_to_event(), - poll_again_after: None, - } - }) - } - - fn process_received_data T, T>(&self, f: F) -> T { - critical_section::with(|cs| { - let inner = self.inner.borrow(cs).borrow_mut(); - let len = inner.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() as usize; - f(&inner.control_buffer()[0..len]) + inner.ints_to_event() }) } @@ -223,7 +223,14 @@ impl HostBus for UsbHostBus { unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } } - fn create_interrupt_pipe(&mut self, device_address: DeviceAddress, endpoint_number: u8, direction: UsbDirection, size: u16, interval: u8) -> Option<(*mut u8, u8)> { + fn create_interrupt_pipe( + &mut self, + device_address: DeviceAddress, + endpoint_number: u8, + direction: UsbDirection, + size: u16, + interval: u8, + ) -> Option<(*mut u8, u8)> { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_dpram.ep_control[0].write(|w| { @@ -238,7 +245,6 @@ impl HostBus for UsbHostBus { } }); inner.ctrl_reg.sie_ctrl.modify(|_, w| w.sof_sync().set_bit()); - let ep_ctrl_bits = inner.ctrl_dpram.ep_control[0].read().bits(); inner.ctrl_dpram.ep_buffer_control[2].write(|w| { w.last_0().set_bit(); w.pid_0().clear_bit(); @@ -248,10 +254,8 @@ impl HostBus for UsbHostBus { }); cortex_m::asm::delay(12); inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); - let buf_control = inner.ctrl_dpram.ep_buffer_control[2].read().bits(); inner.ctrl_reg.addr_endp1.write(|w| { unsafe { - w.intep_preamble().clear_bit(); w.address().bits(device_address.into()); w.endpoint().bits(endpoint_number); w.intep_dir().bit(direction == UsbDirection::Out) @@ -285,7 +289,6 @@ impl HostBus for UsbHostBus { fn pipe_continue(&self, pipe_index: u8) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - let buf_control = inner.ctrl_dpram.ep_buffer_control[2].read().bits(); inner.ctrl_dpram.ep_buffer_control[2].modify(|r, w| { w.last_0().set_bit(); w.pid_0().bit(!r.pid_0().bit()); @@ -295,10 +298,6 @@ impl HostBus for UsbHostBus { }); cortex_m::asm::delay(12); inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); - // inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| { - // w.full_0().clear_bit(); - // w.available_0().set_bit() - // }); }) } @@ -310,19 +309,12 @@ impl HostBus for UsbHostBus { } } -unsafe impl Send for UsbHostBus {} - struct Inner { ctrl_reg: USBCTRL_REGS, ctrl_dpram: USBCTRL_DPRAM, } impl Inner { - fn control_buffer(&self) -> &[u8] { - const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; - unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), CONTROL_BUFFER_SIZE) } - } - fn control_buffer_mut(&mut self) -> &mut [u8] { const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; unsafe { core::slice::from_raw_parts_mut(DPRAM_BASE.offset(0x180), CONTROL_BUFFER_SIZE) } From 09f798c1d7d2bed06499b3b20e193b174fbf6373 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 10:52:44 +0200 Subject: [PATCH 09/20] use new `host_poll_interval` field instead of manual bit fiddling Also make some changes to the bus interface --- rp2040-hal/src/usb/host.rs | 39 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index ef5c6a9c8..5cf24dc6b 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -11,6 +11,7 @@ use usbh::{ HostBus, Event, Error, + InterruptPipe, }, types::{ ConnectionSpeed, @@ -218,7 +219,7 @@ impl HostBus for UsbHostBus { }) } - unsafe fn control_buffer(&self, len: usize) -> &[u8] { + fn received_data(&self, len: usize) -> &[u8] { const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180), len) } } @@ -230,19 +231,16 @@ impl HostBus for UsbHostBus { direction: UsbDirection, size: u16, interval: u8, - ) -> Option<(*mut u8, u8)> { + ) -> Option { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_dpram.ep_control[0].write(|w| { - unsafe { - w.bits( - (0x180 + CONTROL_BUFFER_SIZE as u32) | - ((TransferType::Interrupt as u8 as u32) << 26) | - (1 << 29) | // interrupt per buf - (1 << 31) | // enable - ((interval as u32 - 1) << 16) - ) - } + w.endpoint_type().interrupt(); + w.interrupt_per_buff().set_bit(); + unsafe { w.host_poll_interval().bits(interval as u16 - 1) }; + unsafe { w.buffer_address().bits(0x180 + CONTROL_BUFFER_SIZE as u16) }; + w.enable().set_bit() }); inner.ctrl_reg.sie_ctrl.modify(|_, w| w.sof_sync().set_bit()); inner.ctrl_dpram.ep_buffer_control[2].write(|w| { @@ -268,25 +266,16 @@ impl HostBus for UsbHostBus { const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; let buf_ptr = unsafe { DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize) }; - Some((buf_ptr, 2)) + Some(InterruptPipe { + bus_ref: 2, + ptr: buf_ptr, + }) }) } fn release_interrupt_pipe(&mut self, pipe_ref: u8) {} - fn received_len(&self) -> u16 { - critical_section::with(|cs| { - let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_dpram.ep_buffer_control[0].read().length_0().bits() - }) - } - - fn pipe_buf(&self, pipe_index: u8) -> &[u8] { - const DPRAM_BASE: *const u8 = USBCTRL_DPRAM::ptr() as *const u8; - unsafe { core::slice::from_raw_parts(DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize), 8) } - } - - fn pipe_continue(&self, pipe_index: u8) { + fn pipe_continue(&self, pipe_ref: u8) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_dpram.ep_buffer_control[2].modify(|r, w| { From cad55cb820ad13fa305879976e9db5e4d0abc3a9 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 13:06:20 +0200 Subject: [PATCH 10/20] add support for multiple interrupt pipes --- rp2040-hal/src/usb/host.rs | 103 +++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 5cf24dc6b..4067c0df1 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -51,7 +51,7 @@ impl UsbHostBus { ctrl_reg.reset_bring_down(resets); ctrl_reg.reset_bring_up(resets); - Self { inner: Mutex::new(RefCell::new(Inner { ctrl_reg, ctrl_dpram })) } + Self { inner: Mutex::new(RefCell::new(Inner::new(ctrl_reg, ctrl_dpram))) } } } @@ -233,9 +233,15 @@ impl HostBus for UsbHostBus { interval: u8, ) -> Option { critical_section::with(|cs| { - let inner = self.inner.borrow(cs).borrow_mut(); + let mut inner = self.inner.borrow(cs).borrow_mut(); + + let interrupt_pipe = inner.alloc_pipe(size)?; + let index = interrupt_pipe.bus_ref as usize; + let ep_control = &inner.ctrl_dpram.ep_control[index]; + let ep_buffer_control = &inner.ctrl_dpram.ep_buffer_control[2 * (index + 1)]; + let addr_endp = &inner.ctrl_reg.host_addr_endp[index]; - inner.ctrl_dpram.ep_control[0].write(|w| { + ep_control.write(|w| { w.endpoint_type().interrupt(); w.interrupt_per_buff().set_bit(); unsafe { w.host_poll_interval().bits(interval as u16 - 1) }; @@ -243,7 +249,7 @@ impl HostBus for UsbHostBus { w.enable().set_bit() }); inner.ctrl_reg.sie_ctrl.modify(|_, w| w.sof_sync().set_bit()); - inner.ctrl_dpram.ep_buffer_control[2].write(|w| { + ep_buffer_control.write(|w| { w.last_0().set_bit(); w.pid_0().clear_bit(); w.full_0().clear_bit(); @@ -251,8 +257,8 @@ impl HostBus for UsbHostBus { unsafe { w.length_0().bits(size) } }); cortex_m::asm::delay(12); - inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); - inner.ctrl_reg.addr_endp1.write(|w| { + ep_buffer_control.modify(|_, w| w.available_0().set_bit()); + addr_endp.write(|w| { unsafe { w.address().bits(device_address.into()); w.endpoint().bits(endpoint_number); @@ -260,33 +266,53 @@ impl HostBus for UsbHostBus { } }); cortex_m::asm::delay(12); - inner.ctrl_reg.int_ep_ctrl.modify(|_, w| { - unsafe { w.int_ep_active().bits(0x01) } + inner.ctrl_reg.int_ep_ctrl.modify(|r, w| { + unsafe { w.int_ep_active().bits(r.int_ep_active().bits() | 1 << index) } }); - const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; - let buf_ptr = unsafe { DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize) }; - Some(InterruptPipe { - bus_ref: 2, - ptr: buf_ptr, - }) + Some(interrupt_pipe) }) } - fn release_interrupt_pipe(&mut self, pipe_ref: u8) {} + fn release_interrupt_pipe(&mut self, pipe_ref: u8) { + assert!(pipe_ref <= 15); + critical_section::with(|cs| { + let mut inner = self.inner.borrow(cs).borrow_mut(); + let index = pipe_ref as usize; + let ep_control = &inner.ctrl_dpram.ep_control[index]; + let ep_buffer_control = &inner.ctrl_dpram.ep_buffer_control[2 * (index + 1)]; + let addr_endp = &inner.ctrl_reg.host_addr_endp[index]; + + // disable endpoint polling + inner.ctrl_reg.int_ep_ctrl.modify(|r, w| { + unsafe { w.int_ep_active().bits(r.int_ep_active().bits() & !(1 << index)) } + }); + + // clear all related registers + ep_control.write(|w| unsafe { w.bits(0) }); + ep_buffer_control.write(|w| unsafe { w.bits(0) }); + addr_endp.write(|w| unsafe { w.bits(0) }); + + // mark pipe as released + inner.release_pipe(pipe_ref); + }); + } fn pipe_continue(&self, pipe_ref: u8) { + assert!(pipe_ref <= 15); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_dpram.ep_buffer_control[2].modify(|r, w| { + let index = pipe_ref as usize; + let ep_buffer_control = &inner.ctrl_dpram.ep_buffer_control[2 * (index + 1)]; + + ep_buffer_control.modify(|r, w| { w.last_0().set_bit(); w.pid_0().bit(!r.pid_0().bit()); w.full_0().clear_bit(); - w.reset().set_bit(); - unsafe { w.length_0().bits(8) } + w.reset().set_bit() }); cortex_m::asm::delay(12); - inner.ctrl_dpram.ep_buffer_control[2].modify(|_, w| w.available_0().set_bit()); + ep_buffer_control.modify(|_, w| w.available_0().set_bit()); }) } @@ -301,9 +327,44 @@ impl HostBus for UsbHostBus { struct Inner { ctrl_reg: USBCTRL_REGS, ctrl_dpram: USBCTRL_DPRAM, + // bitfield to keep track of which interrupt pipes are in use + // bits 0..15 correspond to registers ADDR_ENDP1-ADDR_ENDP15. + allocated_pipes: u16, } impl Inner { + fn new(ctrl_reg: USBCTRL_REGS, ctrl_dpram: USBCTRL_DPRAM) -> Self { + Self { + ctrl_reg, + ctrl_dpram, + allocated_pipes: 0, + } + } + + fn alloc_pipe(&mut self, size: u16) -> Option { + if size > 64 { + return None + } + let ap = self.allocated_pipes; + let free_index = (0..15).into_iter().find(|i| ap & (1 << i) == 0)? as u8; + + // for simplicity, all pipes are considered to be 64 bytes long for now. + // This is the maximum supported size for pipes other than Isochronous, which are not implemented yet. + let DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + let ptr = unsafe { DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize + free_index as isize * 64) }; + + self.allocated_pipes |= 1 << free_index; + + Some(InterruptPipe { + bus_ref: free_index, + ptr, + }) + } + + fn release_pipe(&mut self, pipe_ref: u8) { + self.allocated_pipes &= !(1 << pipe_ref); + } + fn control_buffer_mut(&mut self) -> &mut [u8] { const DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; unsafe { core::slice::from_raw_parts_mut(DPRAM_BASE.offset(0x180), CONTROL_BUFFER_SIZE) } @@ -357,9 +418,9 @@ impl Inner { for i in 0..32 { if (status >> i) & 1 == 1 { self.ctrl_reg.buff_status.modify(|_, w| unsafe { w.bits(1 << i) }); - // control transfers (buffer 0) + // control transfers (buffer 0) if i != 0 { - return Some(Event::InterruptPipe(i as u8)); + return Some(Event::InterruptPipe((i / 2) - 1)); } } } From bfe23c4133d1decc4e8f194c0b8deecd6683ad7a Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:31:14 +0200 Subject: [PATCH 11/20] formatting --- rp2040-hal/src/usb/host.rs | 301 +++++++++++++++++++++++-------------- 1 file changed, 186 insertions(+), 115 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 4067c0df1..31f117b4a 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -6,30 +6,17 @@ //! Host-mode and device-mode are mutually exclusive. The controller can only operate as one of them at a time. //! +use usb_device::UsbDirection; use usbh::{ - bus::{ - HostBus, - Event, - Error, - InterruptPipe, - }, - types::{ - ConnectionSpeed, - DeviceAddress, - TransferType, - }, + bus::{Error, Event, HostBus, InterruptPipe}, + types::{ConnectionSpeed, DeviceAddress, TransferType}, }; -use usb_device::UsbDirection; -use critical_section::Mutex; -use core::cell::RefCell; use crate::clocks::UsbClock; -use crate::pac::{ - RESETS, - USBCTRL_DPRAM, - USBCTRL_REGS, -}; +use crate::pac::{RESETS, USBCTRL_DPRAM, USBCTRL_REGS}; use crate::resets::SubsystemReset; +use core::cell::RefCell; +use critical_section::Mutex; const CONTROL_BUFFER_SIZE: usize = 64; @@ -51,7 +38,9 @@ impl UsbHostBus { ctrl_reg.reset_bring_down(resets); ctrl_reg.reset_bring_up(resets); - Self { inner: Mutex::new(RefCell::new(Inner::new(ctrl_reg, ctrl_dpram))) } + Self { + inner: Mutex::new(RefCell::new(Inner::new(ctrl_reg, ctrl_dpram))), + } } } @@ -73,30 +62,45 @@ impl HostBus for UsbHostBus { w.softcon().set_bit() }); inner.ctrl_reg.usb_pwr.modify(|_, w| { - w.vbus_detect().set_bit() - .vbus_detect_override_en().set_bit() + w.vbus_detect() + .set_bit() + .vbus_detect_override_en() + .set_bit() }); inner.ctrl_reg.sie_ctrl.modify(|_, w| { - w.sof_en().set_bit() - .keep_alive_en().set_bit() - .pulldown_en().set_bit() - }); - inner.ctrl_reg.main_ctrl.modify(|_, w| { - w.host_ndevice().set_bit() - .controller_en().set_bit() + w.sof_en() + .set_bit() + .keep_alive_en() + .set_bit() + .pulldown_en() + .set_bit() }); + inner + .ctrl_reg + .main_ctrl + .modify(|_, w| w.host_ndevice().set_bit().controller_en().set_bit()); inner.ctrl_reg.inte.modify(|_, w| { - w.buff_status().set_bit() - .host_conn_dis().set_bit() - .host_resume().set_bit() - .stall().set_bit() - .trans_complete().set_bit() - .error_rx_timeout().set_bit() - .error_data_seq().set_bit() - .error_crc().set_bit() - .error_bit_stuff().set_bit() - .error_rx_overflow().set_bit() + w.buff_status() + .set_bit() + .host_conn_dis() + .set_bit() + .host_resume() + .set_bit() + .stall() + .set_bit() + .trans_complete() + .set_bit() + .error_rx_timeout() + .set_bit() + .error_data_seq() + .set_bit() + .error_crc() + .set_bit() + .error_bit_stuff() + .set_bit() + .error_rx_overflow() + .set_bit() }); }); } @@ -105,7 +109,12 @@ impl HostBus for UsbHostBus { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.sie_ctrl.modify(|_, w| { - w.sof_en().set_bit().keep_alive_en().set_bit().pulldown_en().set_bit() + w.sof_en() + .set_bit() + .keep_alive_en() + .set_bit() + .pulldown_en() + .set_bit() }); }); } @@ -121,31 +130,39 @@ impl HostBus for UsbHostBus { fn reset_bus(&mut self) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.sie_ctrl.modify(|_, w| w.reset_bus().set_bit()); + inner + .ctrl_reg + .sie_ctrl + .modify(|_, w| w.reset_bus().set_bit()); }); } - fn set_recipient(&mut self, dev_addr: Option, endpoint: u8, transfer_type: TransferType) { + fn set_recipient( + &mut self, + dev_addr: Option, + endpoint: u8, + transfer_type: TransferType, + ) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.addr_endp.write(|w| { - unsafe { - w.address().bits(dev_addr.map(|addr| u8::from(addr)).unwrap_or(0)); - w.endpoint().bits(endpoint) - } + inner.ctrl_reg.addr_endp.write(|w| unsafe { + w.address() + .bits(dev_addr.map(|addr| u8::from(addr)).unwrap_or(0)); + w.endpoint().bits(endpoint) }); - inner.ctrl_dpram.epx_control.modify(|_, w| { - unsafe { - w.enable().set_bit() - .interrupt_per_buff().set_bit() - .buffer_address().bits(0x180); - match transfer_type { - TransferType::Control => w.endpoint_type().control(), - TransferType::Isochronous => w.endpoint_type().isochronous(), - TransferType::Bulk => w.endpoint_type().bulk(), - TransferType::Interrupt => w.endpoint_type().interrupt(), - } + inner.ctrl_dpram.epx_control.modify(|_, w| unsafe { + w.enable() + .set_bit() + .interrupt_per_buff() + .set_bit() + .buffer_address() + .bits(0x180); + match transfer_type { + TransferType::Control => w.endpoint_type().control(), + TransferType::Isochronous => w.endpoint_type().isochronous(), + TransferType::Bulk => w.endpoint_type().bulk(), + TransferType::Interrupt => w.endpoint_type().interrupt(), } }); }); @@ -154,37 +171,53 @@ impl HostBus for UsbHostBus { fn write_setup(&mut self, setup: usbh::types::SetupPacket) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_dpram.setup_packet_low.write(|w| { - unsafe { - w.bmrequesttype().bits(setup.request_type); - w.brequest().bits(setup.request); - w.wvalue().bits(setup.value) - } + inner.ctrl_dpram.setup_packet_low.write(|w| unsafe { + w.bmrequesttype().bits(setup.request_type); + w.brequest().bits(setup.request); + w.wvalue().bits(setup.value) }); - inner.ctrl_dpram.setup_packet_high.write(|w| { - unsafe { - w.windex().bits(setup.index); - w.wlength().bits(setup.length) - } + inner.ctrl_dpram.setup_packet_high.write(|w| unsafe { + w.windex().bits(setup.index); + w.wlength().bits(setup.length) + }); + inner.ctrl_reg.sie_ctrl.modify(|_, w| { + w.send_data() + .clear_bit() + .receive_data() + .clear_bit() + .send_setup() + .set_bit() + .start_trans() + .set_bit() }); - inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_data().clear_bit().receive_data().clear_bit().send_setup().set_bit().start_trans().set_bit()); }); } fn write_data_in(&mut self, length: u16, pid: bool) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_dpram.ep_buffer_control[0].write(|w| { - unsafe { - w.available_0().set_bit(); - w.pid_0().bit(pid); - w.full_0().clear_bit() - .length_0().bits(length) - .last_0().set_bit() - .reset().set_bit() - } + inner.ctrl_dpram.ep_buffer_control[0].write(|w| unsafe { + w.available_0().set_bit(); + w.pid_0().bit(pid); + w.full_0() + .clear_bit() + .length_0() + .bits(length) + .last_0() + .set_bit() + .reset() + .set_bit() + }); + inner.ctrl_reg.sie_ctrl.modify(|_, w| { + w.send_data() + .clear_bit() + .send_setup() + .clear_bit() + .receive_data() + .set_bit() + .start_trans() + .set_bit() }); - inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_data().clear_bit().send_setup().clear_bit().receive_data().set_bit().start_trans().set_bit()); }); } @@ -192,15 +225,19 @@ impl HostBus for UsbHostBus { critical_section::with(|cs| { let mut inner = self.inner.borrow(cs).borrow_mut(); inner.control_buffer_mut()[0..data.len()].copy_from_slice(data); - inner.ctrl_dpram.ep_buffer_control[0].write(|w| { - unsafe { - w.available_0().set_bit() - .pid_0().set_bit() - .full_0().set_bit() - .length_0().bits(data.len() as u16) - .last_0().set_bit() - .reset().set_bit() - } + inner.ctrl_dpram.ep_buffer_control[0].write(|w| unsafe { + w.available_0() + .set_bit() + .pid_0() + .set_bit() + .full_0() + .set_bit() + .length_0() + .bits(data.len() as u16) + .last_0() + .set_bit() + .reset() + .set_bit() }); }); } @@ -208,7 +245,16 @@ impl HostBus for UsbHostBus { fn write_data_out_prepared(&mut self) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); - inner.ctrl_reg.sie_ctrl.modify(|_, w| w.send_setup().clear_bit().receive_data().clear_bit().send_data().set_bit().start_trans().set_bit()); + inner.ctrl_reg.sie_ctrl.modify(|_, w| { + w.send_setup() + .clear_bit() + .receive_data() + .clear_bit() + .send_data() + .set_bit() + .start_trans() + .set_bit() + }); }); } @@ -248,7 +294,10 @@ impl HostBus for UsbHostBus { unsafe { w.buffer_address().bits(0x180 + CONTROL_BUFFER_SIZE as u16) }; w.enable().set_bit() }); - inner.ctrl_reg.sie_ctrl.modify(|_, w| w.sof_sync().set_bit()); + inner + .ctrl_reg + .sie_ctrl + .modify(|_, w| w.sof_sync().set_bit()); ep_buffer_control.write(|w| { w.last_0().set_bit(); w.pid_0().clear_bit(); @@ -258,16 +307,15 @@ impl HostBus for UsbHostBus { }); cortex_m::asm::delay(12); ep_buffer_control.modify(|_, w| w.available_0().set_bit()); - addr_endp.write(|w| { - unsafe { - w.address().bits(device_address.into()); - w.endpoint().bits(endpoint_number); - w.intep_dir().bit(direction == UsbDirection::Out) - } + addr_endp.write(|w| unsafe { + w.address().bits(device_address.into()); + w.endpoint().bits(endpoint_number); + w.intep_dir().bit(direction == UsbDirection::Out) }); cortex_m::asm::delay(12); - inner.ctrl_reg.int_ep_ctrl.modify(|r, w| { - unsafe { w.int_ep_active().bits(r.int_ep_active().bits() | 1 << index) } + inner.ctrl_reg.int_ep_ctrl.modify(|r, w| unsafe { + w.int_ep_active() + .bits(r.int_ep_active().bits() | 1 << index) }); Some(interrupt_pipe) @@ -284,8 +332,9 @@ impl HostBus for UsbHostBus { let addr_endp = &inner.ctrl_reg.host_addr_endp[index]; // disable endpoint polling - inner.ctrl_reg.int_ep_ctrl.modify(|r, w| { - unsafe { w.int_ep_active().bits(r.int_ep_active().bits() & !(1 << index)) } + inner.ctrl_reg.int_ep_ctrl.modify(|r, w| unsafe { + w.int_ep_active() + .bits(r.int_ep_active().bits() & !(1 << index)) }); // clear all related registers @@ -295,7 +344,7 @@ impl HostBus for UsbHostBus { // mark pipe as released inner.release_pipe(pipe_ref); - }); + }); } fn pipe_continue(&self, pipe_ref: u8) { @@ -343,7 +392,7 @@ impl Inner { fn alloc_pipe(&mut self, size: u16) -> Option { if size > 64 { - return None + return None; } let ap = self.allocated_pipes; let free_index = (0..15).into_iter().find(|i| ap & (1 << i) == 0)? as u8; @@ -351,7 +400,9 @@ impl Inner { // for simplicity, all pipes are considered to be 64 bytes long for now. // This is the maximum supported size for pipes other than Isochronous, which are not implemented yet. let DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; - let ptr = unsafe { DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize + free_index as isize * 64) }; + let ptr = unsafe { + DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize + free_index as isize * 64) + }; self.allocated_pipes |= 1 << free_index; @@ -379,35 +430,51 @@ impl Inner { 0b10 => Event::Attached(ConnectionSpeed::Full), _ => Event::Detached, }; - self.ctrl_reg.sie_status.modify(|_, w| unsafe { w.speed().bits(0b11) }); - return Some(event) + self.ctrl_reg + .sie_status + .modify(|_, w| unsafe { w.speed().bits(0b11) }); + return Some(event); } if ints.host_resume().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.resume().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.resume().clear_bit_by_one()); return Some(Event::Resume); } if ints.stall().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.stall_rec().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.stall_rec().clear_bit_by_one()); return Some(Event::Stall); } if ints.error_crc().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.crc_error().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.crc_error().clear_bit_by_one()); return Some(Event::Error(Error::Crc)); } if ints.error_bit_stuff().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.bit_stuff_error().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.bit_stuff_error().clear_bit_by_one()); return Some(Event::Error(Error::BitStuffing)); } if ints.error_rx_overflow().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.rx_overflow().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.rx_overflow().clear_bit_by_one()); return Some(Event::Error(Error::RxOverflow)); } if ints.error_rx_timeout().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.rx_timeout().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.rx_timeout().clear_bit_by_one()); return Some(Event::Error(Error::RxTimeout)); } if ints.error_data_seq().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.data_seq_error().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.data_seq_error().clear_bit_by_one()); return Some(Event::Error(Error::DataSequence)); } if ints.buff_status().bit_is_set() { @@ -417,7 +484,9 @@ impl Inner { for i in 0..32 { if (status >> i) & 1 == 1 { - self.ctrl_reg.buff_status.modify(|_, w| unsafe { w.bits(1 << i) }); + self.ctrl_reg + .buff_status + .modify(|_, w| unsafe { w.bits(1 << i) }); // control transfers (buffer 0) if i != 0 { return Some(Event::InterruptPipe((i / 2) - 1)); @@ -426,7 +495,9 @@ impl Inner { } } if ints.trans_complete().bit_is_set() { - self.ctrl_reg.sie_status.modify(|_, w| w.trans_complete().clear_bit_by_one()); + self.ctrl_reg + .sie_status + .modify(|_, w| w.trans_complete().clear_bit_by_one()); return Some(Event::TransComplete); } if ints.host_sof().bit_is_set() { From 1cc370e07ee10c10691940e4f78cbfa47c835455 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:42:16 +0200 Subject: [PATCH 12/20] address clippy suggestions --- rp2040-hal/src/usb/host.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 31f117b4a..843d47d88 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -147,7 +147,7 @@ impl HostBus for UsbHostBus { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.addr_endp.write(|w| unsafe { w.address() - .bits(dev_addr.map(|addr| u8::from(addr)).unwrap_or(0)); + .bits(dev_addr.map(u8::from).unwrap_or(0)); w.endpoint().bits(endpoint) }); @@ -395,13 +395,16 @@ impl Inner { return None; } let ap = self.allocated_pipes; - let free_index = (0..15).into_iter().find(|i| ap & (1 << i) == 0)? as u8; + let free_index = (0..15).find(|i| ap & (1 << i) == 0)? as u8; // for simplicity, all pipes are considered to be 64 bytes long for now. // This is the maximum supported size for pipes other than Isochronous, which are not implemented yet. - let DPRAM_BASE: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + let dpram_base: *mut u8 = USBCTRL_DPRAM::ptr() as *mut u8; + + // Safety: this is the only place where offsets larger than 0x180+CONTROL_BUFFER_SIZE are used. + // Since the highest index is 15, all offsets are below `0x180 + 16 * 64 = 1408`, which is below the 4096 bytes available in DPRAM. let ptr = unsafe { - DPRAM_BASE.offset(0x180 + CONTROL_BUFFER_SIZE as isize + free_index as isize * 64) + dpram_base.offset(0x180 + CONTROL_BUFFER_SIZE as isize + free_index as isize * 64) }; self.allocated_pipes |= 1 << free_index; From 33e3ad25e55c5fb132a239127350587bf590cb31 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:44:26 +0200 Subject: [PATCH 13/20] use PAC from git temporarily --- rp2040-hal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index f76b393bf..4aea4eeaf 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -24,7 +24,7 @@ embedded-dma = "0.2.0" fugit = "0.3.6" itertools = { version = "0.10.1", default-features = false } nb = "1.0" -rp2040-pac = { path = "../rp2040-pac" } +rp2040-pac = { git = "https://github.com/nilclass/rp2040-pac", branch = "usb-host-support" } paste = "1.0" pio = "0.2.0" rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" } From 8481907251183e1ab3ec4a9f0e4fc774830c2924 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:45:56 +0200 Subject: [PATCH 14/20] use usbh from git --- rp2040-hal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 4aea4eeaf..ae6e4399a 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -33,7 +33,7 @@ vcell = "0.1" void = { version = "1.0.2", default-features = false } rand_core = "0.6.3" critical-section = { version = "1.0.0" } -usbh = { path = "../../usbh" } +usbh = { git = "https://github.com/nilclass/usbh" } chrono = { version = "0.4", default-features = false, optional = true } From 3e965676b9a012ffc4e1a662851362c34b65565f Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:50:58 +0200 Subject: [PATCH 15/20] undo unintended Cargo.toml changes --- rp2040-hal/Cargo.toml | 96 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index ae6e4399a..8974c60e2 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -2,7 +2,7 @@ name = "rp2040-hal" version = "0.9.0-alpha.1" authors = ["The rp-rs Developers"] -edition = "2018" +edition = "2021" homepage = "https://github.com/rp-rs/rp-hal" description = "A Rust Embeded-HAL impl for the rp2040 microcontroller" license = "MIT OR Apache-2.0" @@ -24,7 +24,7 @@ embedded-dma = "0.2.0" fugit = "0.3.6" itertools = { version = "0.10.1", default-features = false } nb = "1.0" -rp2040-pac = { git = "https://github.com/nilclass/rp2040-pac", branch = "usb-host-support" } +rp2040-pac = { git = "https://github.com/nilclass/rp2040-pac", branch = "usb-host-support", features = ["critical-section"] } paste = "1.0" pio = "0.2.0" rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" } @@ -103,3 +103,95 @@ required-features = ["rt", "critical-section-impl"] # adc_fifo_dma example uses cortex-m-rt::interrupt, need rt feature for that name = "adc_fifo_dma" required-features = ["rt", "critical-section-impl"] + +[[example]] +name = "adc" +required-features = ["critical-section-impl"] + +[[example]] +name = "adc_fifo_poll" +required-features = ["critical-section-impl"] + +[[example]] +name = "blinky" +required-features = ["critical-section-impl"] + +[[example]] +name = "dht11" +required-features = ["critical-section-impl"] + +[[example]] +name = "gpio_in_out" +required-features = ["critical-section-impl"] + +[[example]] +name = "i2c" +required-features = ["critical-section-impl"] + +[[example]] +name = "lcd_display" +required-features = ["critical-section-impl"] + +[[example]] +name = "mem_to_mem_dma" +required-features = ["critical-section-impl"] + +[[example]] +name = "multicore_fifo_blink" +required-features = ["critical-section-impl"] + +[[example]] +name = "multicore_polyblink" +required-features = ["critical-section-impl"] + +[[example]] +name = "pio_blink" +required-features = ["critical-section-impl"] + +[[example]] +name = "pio_dma" +required-features = ["critical-section-impl"] + +[[example]] +name = "pio_proc_blink" +required-features = ["critical-section-impl"] + +[[example]] +name = "pio_side_set" +required-features = ["critical-section-impl"] + +[[example]] +name = "pio_synchronized" +required-features = ["critical-section-impl"] + +[[example]] +name = "pwm_blink" +required-features = ["critical-section-impl"] + +[[example]] +name = "rom_funcs" +required-features = ["critical-section-impl"] + +[[example]] +name = "rosc_as_system_clock" +required-features = ["critical-section-impl"] + +[[example]] +name = "spi" +required-features = ["critical-section-impl"] + +[[example]] +name = "spi_dma" +required-features = ["critical-section-impl"] + +[[example]] +name = "uart" +required-features = ["critical-section-impl"] + +[[example]] +name = "uart_dma" +required-features = ["critical-section-impl"] + +[[example]] +name = "watchdog" +required-features = ["critical-section-impl"] From fd35115dd3729dda54b0eb36dfaeb83fd84a2f88 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sun, 6 Aug 2023 14:55:05 +0200 Subject: [PATCH 16/20] re-run formatter --- rp2040-hal/src/usb/host.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index 843d47d88..e523bcdcb 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -146,8 +146,7 @@ impl HostBus for UsbHostBus { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); inner.ctrl_reg.addr_endp.write(|w| unsafe { - w.address() - .bits(dev_addr.map(u8::from).unwrap_or(0)); + w.address().bits(dev_addr.map(u8::from).unwrap_or(0)); w.endpoint().bits(endpoint) }); From 5b1056f1dfbd8d2f85657232f858595f3d19364f Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sat, 18 Nov 2023 13:06:15 +0100 Subject: [PATCH 17/20] Implement missing HostBus methods --- rp2040-hal/src/usb/host.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index e523bcdcb..d0ee48633 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -167,6 +167,20 @@ impl HostBus for UsbHostBus { }); } + fn stop_transaction(&mut self) { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.stop_trans().set_bit()); + }); + } + + fn ls_preamble(&mut self, enable: bool) { + critical_section::with(|cs| { + let inner = self.inner.borrow(cs).borrow_mut(); + inner.ctrl_reg.sie_ctrl.modify(|_, w| w.preamble_en().bit(enable)); + }); + } + fn write_setup(&mut self, setup: usbh::types::SetupPacket) { critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); @@ -179,6 +193,7 @@ impl HostBus for UsbHostBus { w.windex().bits(setup.index); w.wlength().bits(setup.length) }); + defmt::info!("writing setup to {}... preamble currently {}", inner.ctrl_reg.addr_endp.read().address().bits(), inner.ctrl_reg.sie_ctrl.read().preamble_en().bit()); inner.ctrl_reg.sie_ctrl.modify(|_, w| { w.send_data() .clear_bit() @@ -346,7 +361,7 @@ impl HostBus for UsbHostBus { }); } - fn pipe_continue(&self, pipe_ref: u8) { + fn pipe_continue(&mut self, pipe_ref: u8) { assert!(pipe_ref <= 15); critical_section::with(|cs| { let inner = self.inner.borrow(cs).borrow_mut(); From d3814bfa88cb6bc3ae49875426f3e9afd04adff7 Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sat, 18 Nov 2023 13:08:19 +0100 Subject: [PATCH 18/20] Remove debug logging --- rp2040-hal/src/usb/host.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rp2040-hal/src/usb/host.rs b/rp2040-hal/src/usb/host.rs index d0ee48633..cbb0e2b72 100644 --- a/rp2040-hal/src/usb/host.rs +++ b/rp2040-hal/src/usb/host.rs @@ -193,7 +193,6 @@ impl HostBus for UsbHostBus { w.windex().bits(setup.index); w.wlength().bits(setup.length) }); - defmt::info!("writing setup to {}... preamble currently {}", inner.ctrl_reg.addr_endp.read().address().bits(), inner.ctrl_reg.sie_ctrl.read().preamble_en().bit()); inner.ctrl_reg.sie_ctrl.modify(|_, w| { w.send_data() .clear_bit() From d8009b0cfcbb52ed9d79cf2a31f1079c3b20c27f Mon Sep 17 00:00:00 2001 From: Niklas Cathor Date: Sat, 18 Nov 2023 13:33:29 +0100 Subject: [PATCH 19/20] Switch rp2040-pac back to upstream git --- rp2040-hal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 8974c60e2..6229af726 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -24,7 +24,7 @@ embedded-dma = "0.2.0" fugit = "0.3.6" itertools = { version = "0.10.1", default-features = false } nb = "1.0" -rp2040-pac = { git = "https://github.com/nilclass/rp2040-pac", branch = "usb-host-support", features = ["critical-section"] } +rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", features = ["critical-section"] } paste = "1.0" pio = "0.2.0" rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" } From 4e447c02408e77b669bd612b91b0df8d5e248d01 Mon Sep 17 00:00:00 2001 From: Tommy Gilligan <7865781+tommy-gilligan@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:01:15 +1100 Subject: [PATCH 20/20] add usb_host example from rp-hal-usb-host-example --- rp2040-hal/Cargo.toml | 4 + rp2040-hal/examples/usb_host.rs | 200 ++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 rp2040-hal/examples/usb_host.rs diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 6229af726..2ea46281a 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -195,3 +195,7 @@ required-features = ["critical-section-impl"] [[example]] name = "watchdog" required-features = ["critical-section-impl"] + +[[example]] +name = "usb_host" +required-features = ["rt", "critical-section-impl"] diff --git a/rp2040-hal/examples/usb_host.rs b/rp2040-hal/examples/usb_host.rs new file mode 100644 index 000000000..11fdcd67b --- /dev/null +++ b/rp2040-hal/examples/usb_host.rs @@ -0,0 +1,200 @@ +//! USB host support example, using the keyboard driver +//! +//! This example illustrates initializing the USB host stack, and using +//! the keyboard driver. +//! +//! It also interprets pressing the NumLock key, by toggling the NumLock LED (and GPIO25) +//! +//! If a LED is connected to GPIO25, like on a Pico board, the LED should toggle with NumLock LED +//! on keyboard. +#![no_std] +#![no_main] + +use panic_halt as _; + +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. +/// Note: This boot block is not necessary when using a rp-hal based BSP +/// as the BSPs already perform this step. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H; + +#[rtic::app(device = rp2040_hal::pac, dispatchers = [TIMER_IRQ_1])] +mod app { + use embedded_hal::digital::v2::OutputPin; + use hal::usb::host::UsbHostBus; + use rp2040_hal as hal; + use usbh::{ + driver::kbd::{KbdDriver, KbdEvent, KbdLed}, + driver::log::{EventMask, LogDriver}, + PollResult, UsbHost, + }; + + /// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust + /// if your board has a different frequency + const XTAL_FREQ_HZ: u32 = 12_000_000u32; + + #[shared] + struct Shared {} + + #[local] + struct Local { + usb_host: UsbHost, + log_driver: LogDriver, + kbd_driver: KbdDriver, + pin: hal::gpio::Pin< + hal::gpio::bank0::Gpio2, + hal::gpio::FunctionSioOutput, + hal::gpio::PullDown, + >, + led: hal::gpio::Pin< + hal::gpio::bank0::Gpio25, + hal::gpio::FunctionSioOutput, + hal::gpio::PullDown, + >, + } + + #[init] + fn init(mut c: init::Context) -> (Shared, Local, init::Monotonics) { + // Soft-reset does not release the hardware spinlocks + // Release them now to avoid a deadlock after debug or watchdog reset + unsafe { + hal::sio::spinlock_reset(); + } + + let mut watchdog = hal::Watchdog::new(c.device.WATCHDOG); + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + c.device.XOSC, + c.device.CLOCKS, + c.device.PLL_SYS, + c.device.PLL_USB, + &mut c.device.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + let sio = hal::Sio::new(c.device.SIO); + let pins = hal::gpio::Pins::new( + c.device.IO_BANK0, + c.device.PADS_BANK0, + sio.gpio_bank0, + &mut c.device.RESETS, + ); + + let pin = pins.gpio2.into_push_pull_output(); + let led = pins.gpio25.into_push_pull_output(); + + // Create UsbHost instance. Conceptually the `UsbHost` is not specific to any host implementation. + let usb_host = UsbHost::new( + // UsbHostBus here is the `usbh::bus::HostBus` implementation for the rp2040. + UsbHostBus::new( + c.device.USBCTRL_REGS, + c.device.USBCTRL_DPRAM, + clocks.usb_clock, + &mut c.device.RESETS, + ), + ); + + ( + Shared { + // Initialization of shared resources go here + }, + Local { + // Initialization of local resources go here + usb_host, + kbd_driver: KbdDriver::new(), + log_driver: LogDriver::new(EventMask::all()), + pin, + led, + }, + init::Monotonics(), + ) + } + + // Optional idle, can be removed if not needed. + #[idle] + fn idle(_: idle::Context) -> ! { + loop { + continue; + } + } + + #[task(binds = USBCTRL_IRQ, local = [usb_host, kbd_driver, log_driver, pin, led, num_state: bool = false])] + fn usbctrl_irq(c: usbctrl_irq::Context) { + _ = c.local.pin.set_high(); + + match c + .local + .usb_host + .poll(&mut [c.local.log_driver, c.local.kbd_driver]) + { + PollResult::NoDevice => { + // No device is attached (yet) + return; + } + PollResult::Busy => { + // Bus is currently busy communicating with the device + } + PollResult::Idle => { + // Bus is idle, we can issue commands via the host interface + } + + PollResult::BusError(_) => { + // Bus error + } + + PollResult::DiscoveryError(_) => { + // Discovery for device failed + } + + _ => {} + } + + match c.local.kbd_driver.take_event() { + None => {} + Some(event) => { + match event { + KbdEvent::DeviceAdded(dev_addr) => { + // Keyboard with address dev_addr added + c.local + .kbd_driver + .set_idle(dev_addr, 0, c.local.usb_host) + .ok() + .unwrap(); + } + KbdEvent::DeviceRemoved(_) => { + // Keyboard with address dev_addr removed + } + KbdEvent::InputChanged(dev_addr, report) => { + // Input on keyboard + + // toggle Num lock LED when NumLock key is pressed + if report.pressed_keys().any(|key| key == 83) { + *c.local.num_state = !*c.local.num_state; + if *c.local.num_state { + c.local.led.set_high().unwrap(); + } else { + c.local.led.set_low().unwrap(); + } + c.local + .kbd_driver + .set_led( + dev_addr, + KbdLed::NumLock, + *c.local.num_state, + c.local.usb_host, + ) + .ok() + .unwrap(); + } + } + _ => {} + } + } + } + + _ = c.local.pin.set_low(); + } +}