Merge pull request #355 from adafruit/add-rp2040-max3421e-support
Add rp2040 max3421e support
This commit is contained in:
commit
de5353d0ca
6 changed files with 288 additions and 29 deletions
|
|
@ -0,0 +1,242 @@
|
|||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (roothub port0)
|
||||
* - Host run on MAX3421E controller (roothub port1) tested with:
|
||||
* - SAMD21, SAMD51, nRF52840, ESP32S2, ESP32S3, ESP32
|
||||
* - RP2040: "pio_usb.h" must not be included, otherwise pio-usb will be used as host controller
|
||||
*
|
||||
* Requirements:
|
||||
* - SPI instance, CS pin, INT pin are correctly configured
|
||||
*/
|
||||
|
||||
/* Host example will get device descriptors of attached devices and print it out via
|
||||
* device cdc (Serial) as follows:
|
||||
* Device 1: ID 046d:c52f
|
||||
Device Descriptor:
|
||||
bLength 18
|
||||
bDescriptorType 1
|
||||
bcdUSB 0200
|
||||
bDeviceClass 0
|
||||
bDeviceSubClass 0
|
||||
bDeviceProtocol 0
|
||||
bMaxPacketSize0 8
|
||||
idVendor 0x046d
|
||||
idProduct 0xc52f
|
||||
bcdDevice 2200
|
||||
iManufacturer 1 Logitech
|
||||
iProduct 2 USB Receiver
|
||||
iSerialNumber 0
|
||||
bNumConfigurations 1
|
||||
*
|
||||
*/
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// USBHost is defined in usbh_helper.h
|
||||
// USB Host using MAX3421E: SPI, CS, INT
|
||||
#include "SPI.h"
|
||||
|
||||
#if defined(ARDUINO_METRO_ESP32S2)
|
||||
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||
|
||||
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||
Adafruit_USBH_Host USBHost(&SPI, 27, 33);
|
||||
|
||||
#else
|
||||
|
||||
// Default CS and INT are pin 10, 9
|
||||
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
typedef struct {
|
||||
tusb_desc_device_t desc_device;
|
||||
uint16_t manufacturer[32];
|
||||
uint16_t product[48];
|
||||
uint16_t serial[16];
|
||||
bool mounted;
|
||||
} dev_info_t;
|
||||
|
||||
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
|
||||
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// init host stack on controller (rhport) 1
|
||||
// For rp2040: this is called in core1's setup1()
|
||||
USBHost.begin(1);
|
||||
|
||||
// while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("TinyUSB Dual: Device Info Example with MAX3421E");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
USBHost.task();
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
void print_device_descriptor(tuh_xfer_t *xfer);
|
||||
|
||||
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
|
||||
|
||||
void print_lsusb(void) {
|
||||
bool no_device = true;
|
||||
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
|
||||
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
|
||||
// use local connected flag instead
|
||||
dev_info_t *dev = &dev_info[daddr - 1];
|
||||
if (dev->mounted) {
|
||||
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
|
||||
dev->desc_device.idVendor, dev->desc_device.idProduct,
|
||||
(char *) dev->manufacturer, (char *) dev->product);
|
||||
|
||||
no_device = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (no_device) {
|
||||
Serial.println("No device connected (except hub)");
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb(uint8_t daddr) {
|
||||
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||
|
||||
dev_info_t *dev = &dev_info[daddr - 1];
|
||||
dev->mounted = true;
|
||||
|
||||
// Get Device Descriptor
|
||||
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr) {
|
||||
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||
dev_info_t *dev = &dev_info[daddr - 1];
|
||||
dev->mounted = false;
|
||||
|
||||
// print device summary
|
||||
print_lsusb();
|
||||
}
|
||||
|
||||
void print_device_descriptor(tuh_xfer_t *xfer) {
|
||||
if (XFER_RESULT_SUCCESS != xfer->result) {
|
||||
Serial.printf("Failed to get device descriptor\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
dev_info_t *dev = &dev_info[daddr - 1];
|
||||
tusb_desc_device_t *desc = &dev->desc_device;
|
||||
|
||||
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
|
||||
Serial.printf("Device Descriptor:\r\n");
|
||||
Serial.printf(" bLength %u\r\n" , desc->bLength);
|
||||
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
|
||||
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
|
||||
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
|
||||
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
|
||||
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
|
||||
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
|
||||
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
|
||||
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
|
||||
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
|
||||
|
||||
// Get String descriptor using Sync API
|
||||
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
|
||||
if (XFER_RESULT_SUCCESS ==
|
||||
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
|
||||
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
|
||||
Serial.printf((char *) dev->manufacturer);
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" iProduct %u ", desc->iProduct);
|
||||
if (XFER_RESULT_SUCCESS ==
|
||||
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
|
||||
utf16_to_utf8(dev->product, sizeof(dev->product));
|
||||
Serial.printf((char *) dev->product);
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
|
||||
if (XFER_RESULT_SUCCESS ==
|
||||
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
|
||||
utf16_to_utf8(dev->serial, sizeof(dev->serial));
|
||||
Serial.printf((char *) dev->serial);
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
|
||||
|
||||
// print device summary
|
||||
print_lsusb();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptor Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||
// TODO: Check for runover.
|
||||
(void) utf8_len;
|
||||
// Get the UTF-16 length out of the data itself.
|
||||
|
||||
for (size_t i = 0; i < utf16_len; i++) {
|
||||
uint16_t chr = utf16[i];
|
||||
if (chr < 0x80) {
|
||||
*utf8++ = chr & 0xff;
|
||||
} else if (chr < 0x800) {
|
||||
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
|
||||
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||
} else {
|
||||
// TODO: Verify surrogate.
|
||||
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
|
||||
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
|
||||
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||
}
|
||||
// TODO: Handle UTF-16 code points that take two entries.
|
||||
}
|
||||
}
|
||||
|
||||
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||
size_t total_bytes = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint16_t chr = buf[i];
|
||||
if (chr < 0x80) {
|
||||
total_bytes += 1;
|
||||
} else if (chr < 0x800) {
|
||||
total_bytes += 2;
|
||||
} else {
|
||||
total_bytes += 3;
|
||||
}
|
||||
// TODO: Handle UTF-16 code points that take two entries.
|
||||
}
|
||||
return total_bytes;
|
||||
}
|
||||
|
||||
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
|
||||
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||
|
||||
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
|
||||
((uint8_t *) temp_buf)[utf8_len] = '\0';
|
||||
}
|
||||
|
|
@ -186,8 +186,10 @@ TU_ATTR_WEAK void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance,
|
|||
!defined(PLATFORMIO)
|
||||
extern "C" void hcd_int_handler_esp32(uint8_t rhport, bool in_isr);
|
||||
#define tuh_int_handler_esp32 hcd_int_handler_esp32
|
||||
|
||||
#else
|
||||
#define tuh_int_handler_esp32 tuh_int_handler
|
||||
|
||||
#endif
|
||||
|
||||
static void max3421_intr_task(void *param) {
|
||||
|
|
@ -321,8 +323,13 @@ void tuh_max3421_int_api(uint8_t rhport, bool enabled) {
|
|||
} else {
|
||||
gpio_intr_disable((gpio_num_t)host->_intr);
|
||||
}
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
//--- RP2040 ---//
|
||||
irq_set_enabled(IO_IRQ_BANK0, enabled);
|
||||
|
||||
#else
|
||||
#error "MAX3421e host is not Unsupported by this architecture"
|
||||
#error "MAX3421e host is not supported by this architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,16 +38,23 @@ extern "C" {
|
|||
#define CFG_TUD_ENABLED 0
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
|
||||
#else
|
||||
// native as device
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Enable host stack with pio-usb if Pico-PIO-USB library is available
|
||||
#if __has_include("pio_usb.h")
|
||||
// Enable host stack with pio-usb if Pico-PIO-USB library is available
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_RPI_PIO_USB 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Otherwise enable host controller with MAX3421E
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_MAX3421 1
|
||||
|
||||
#endif // pio_usb.h
|
||||
#endif // USE_TINYUSB_HOST
|
||||
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#define CFG_TUSB_MCU OPT_MCU_RP2040
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ enum {
|
|||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct {
|
||||
uint8_t daddr;
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t ep_dir : 1;
|
||||
uint8_t is_iso : 1;
|
||||
|
|
@ -184,17 +186,19 @@ typedef struct {
|
|||
uint8_t xfer_pending : 1;
|
||||
uint8_t xfer_complete : 1;
|
||||
};
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t daddr : 4;
|
||||
uint8_t ep_num : 4;
|
||||
uint16_t packet_size : 12;
|
||||
};
|
||||
|
||||
uint16_t packet_size;
|
||||
uint16_t total_len;
|
||||
uint16_t xferred_len;
|
||||
uint8_t* buf;
|
||||
} max3421_ep_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(max3421_ep_t) == 12, "size is not correct");
|
||||
|
||||
typedef struct {
|
||||
// cached register
|
||||
uint8_t sndbc;
|
||||
|
|
@ -325,7 +329,7 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is
|
|||
static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
|
||||
reg_write(rhport, HIRQ_ADDR, data, in_isr);
|
||||
// HIRQ write 1 is clear
|
||||
_hcd_data.hirq &= ~data;
|
||||
_hcd_data.hirq &= (uint8_t) ~data;
|
||||
}
|
||||
|
||||
static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
|
||||
|
|
@ -395,13 +399,13 @@ static void free_ep(uint8_t daddr) {
|
|||
}
|
||||
|
||||
static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
|
||||
size_t const idx = cur_ep - _hcd_data.ep;
|
||||
size_t const idx = (size_t) (cur_ep - _hcd_data.ep);
|
||||
|
||||
// starting from next endpoint
|
||||
for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
|
||||
max3421_ep_t* ep = &_hcd_data.ep[i];
|
||||
if (ep->xfer_pending && ep->packet_size) {
|
||||
// TU_LOG3("next pending i = %u\n", i);
|
||||
// TU_LOG3("next pending i = %u\r\n", i);
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
|
|
@ -410,7 +414,7 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
|
|||
for (size_t i = 0; i <= idx; i++) {
|
||||
max3421_ep_t* ep = &_hcd_data.ep[i];
|
||||
if (ep->xfer_pending && ep->packet_size) {
|
||||
// TU_LOG3("next pending i = %u\n", i);
|
||||
// TU_LOG3("next pending i = %u\r\n", i);
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
|
|
@ -542,8 +546,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
|
|||
(void) rhport;
|
||||
(void) daddr;
|
||||
|
||||
uint8_t ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
|
||||
uint8_t ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
|
||||
uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
|
||||
tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
|
||||
|
||||
max3421_ep_t * ep;
|
||||
if (daddr == 0 && ep_num == 0) {
|
||||
|
|
@ -552,15 +556,15 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
|
|||
ep = allocate_ep();
|
||||
TU_ASSERT(ep);
|
||||
ep->daddr = daddr;
|
||||
ep->ep_num = ep_num;
|
||||
ep->ep_dir = ep_dir;
|
||||
ep->ep_num = (uint8_t) (ep_num & 0x0f);
|
||||
ep->ep_dir = (ep_dir == TUSB_DIR_IN) ? 1 : 0;
|
||||
}
|
||||
|
||||
if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) {
|
||||
ep->is_iso = 1;
|
||||
}
|
||||
|
||||
ep->packet_size = tu_edpt_packet_size(ep_desc);
|
||||
ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -582,7 +586,7 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
|||
}
|
||||
sndbc_write(rhport, xact_len, in_isr);
|
||||
|
||||
uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0);
|
||||
uint8_t const hxfr = (uint8_t ) (ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0));
|
||||
hxfr_write(rhport, hxfr, in_isr);
|
||||
}
|
||||
|
||||
|
|
@ -595,7 +599,7 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
|||
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
|
||||
}
|
||||
|
||||
uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0);
|
||||
uint8_t const hxfr = (uint8_t) (ep->ep_num | (ep->is_iso ? HXFR_ISO : 0));
|
||||
hxfr_write(rhport, hxfr, in_isr);
|
||||
}
|
||||
|
||||
|
|
@ -628,13 +632,13 @@ TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t
|
|||
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
|
||||
uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
|
||||
|
||||
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
|
||||
TU_VERIFY(ep);
|
||||
|
||||
// control transfer can switch direction
|
||||
ep->ep_dir = ep_dir;
|
||||
ep->ep_dir = ep_dir ? 1u : 0u;
|
||||
|
||||
ep->buf = buffer;
|
||||
ep->total_len = buflen;
|
||||
|
|
@ -736,9 +740,9 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
|
|||
// However, since we are always in full speed mode, we can just check J-state
|
||||
if (jk == HRSL_KSTATUS) {
|
||||
new_mode |= MODE_LOWSPEED;
|
||||
TU_LOG3("Low speed\n");
|
||||
TU_LOG3("Low speed\r\n");
|
||||
}else {
|
||||
TU_LOG3("Full speed\n");
|
||||
TU_LOG3("Full speed\r\n");
|
||||
}
|
||||
new_mode |= MODE_SOFKAENAB;
|
||||
mode_write(rhport, new_mode, in_isr);
|
||||
|
|
@ -758,9 +762,9 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
|
|||
|
||||
// save data toggle
|
||||
if (ep->ep_dir) {
|
||||
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0;
|
||||
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
|
||||
}else {
|
||||
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0;
|
||||
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
|
||||
}
|
||||
|
||||
ep->xfer_pending = 0;
|
||||
|
|
@ -944,7 +948,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
|||
}
|
||||
|
||||
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
||||
hirq &= ~HIRQ_SNDBAV_IRQ;
|
||||
hirq &= (uint8_t) ~HIRQ_SNDBAV_IRQ;
|
||||
if ( hirq ) {
|
||||
hirq_write(rhport, hirq, in_isr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -340,6 +340,9 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
|||
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
|
||||
NRF_USBD->EPINEN |= TU_BIT(epnum);
|
||||
}
|
||||
// clear stall and reset DataToggle
|
||||
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
||||
NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -375,10 +378,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
|||
}
|
||||
}
|
||||
|
||||
// clear stall and reset DataToggle
|
||||
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
||||
NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
|
||||
|
||||
__ISB(); __DSB();
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB
|
||||
#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB && !CFG_TUH_MAX3421
|
||||
|
||||
#include "pico.h"
|
||||
#include "rp2040_usb.h"
|
||||
|
|
|
|||
Loading…
Reference in a new issue