diff --git a/src/arduino/Adafruit_USBH_Host.cpp b/src/arduino/Adafruit_USBH_Host.cpp index cdba7732..c7254609 100644 --- a/src/arduino/Adafruit_USBH_Host.cpp +++ b/src/arduino/Adafruit_USBH_Host.cpp @@ -211,11 +211,14 @@ void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { SPIClass *spi = host->_spi; if (active) { - // MAX3421e max clock is 26MHz - // Depending on mcu ports, it may need to be clipped down + // MAX3421e max clock is 26MHz. SAMD SERCOM clocks are quantized by the + // baud generator, so request values that stay within each port's limit. #ifdef ARDUINO_ARCH_SAMD - // SAMD 21/51 can only work reliably at 12MHz +#if TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) + uint32_t const max_clock = 25000000ul; +#else uint32_t const max_clock = 12000000ul; +#endif #else uint32_t const max_clock = 26000000ul; #endif @@ -273,11 +276,20 @@ void tuh_max3421_int_api(uint8_t rhport, bool enabled) { (void)host; #ifdef ARDUINO_ARCH_SAMD - //--- SAMD51 ---// -#ifdef __SAMD51__ +//--- SAMD51/SAME51 ---// +#if TU_CHECK_MCU(OPT_MCU_SAMD51) const IRQn_Type irq = (IRQn_Type)(EIC_0_IRQn + g_APinDescription[host->_intr].ulExtInt); + if (enabled) { + NVIC_EnableIRQ(irq); + } else { + NVIC_DisableIRQ(irq); + } +#elif TU_CHECK_MCU(OPT_MCU_SAME5X) + const IRQn_Type irq = + (IRQn_Type)(EIC_EXTINT_0_IRQn + g_APinDescription[host->_intr].ulExtInt); + if (enabled) { NVIC_EnableIRQ(irq); } else { diff --git a/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp b/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp index f6fe45e0..214d3fe6 100644 --- a/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp +++ b/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp @@ -37,7 +37,7 @@ //--------------------------------------------------------------------+ extern "C" { -#if CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X +#if TU_CHECK_MCU(OPT_MCU_SAMD51) // SAMD51 void USB_0_Handler(void) { tud_int_handler(0); } @@ -45,7 +45,15 @@ void USB_1_Handler(void) { tud_int_handler(0); } void USB_2_Handler(void) { tud_int_handler(0); } void USB_3_Handler(void) { tud_int_handler(0); } -#elif CFG_TUSB_MCU == OPT_MCU_SAMD21 +#elif TU_CHECK_MCU(OPT_MCU_SAME5X) + +// SAME53/54 +void USB_OTHER_Handler(void) { tud_int_handler(0); } +void USB_SOF_HSOF_Handler(void) { tud_int_handler(0); } +void USB_TRCPT0_Handler(void) { tud_int_handler(0); } +void USB_TRCPT1_Handler(void) { tud_int_handler(0); } + +#elif TU_CHECK_MCU(OPT_MCU_SAMD21) // SAMD21 void USB_Handler(void) { tud_int_handler(0); } @@ -61,7 +69,7 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) { (void)rhport; /* Enable USB clock */ -#if defined(__SAMD51__) +#if TU_CHECK_MCU(OPT_MCU_SAMD51) MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB; MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB; @@ -84,6 +92,29 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) { NVIC_SetPriority(USB_1_IRQn, 0UL); NVIC_SetPriority(USB_2_IRQn, 0UL); NVIC_SetPriority(USB_3_IRQn, 0UL); +#elif TU_CHECK_MCU(OPT_MCU_SAME5X) + MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB; + MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB; + + // Set up the USB DP/DN pins + PORT->Group[0].PINCFG[PIN_PA24H_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24H_USB_DM / 2].reg &= + ~(0xF << (4 * (PIN_PA24H_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24H_USB_DM / 2].reg |= + MUX_PA24H_USB_DM << (4 * (PIN_PA24H_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25H_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25H_USB_DP / 2].reg &= + ~(0xF << (4 * (PIN_PA25H_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25H_USB_DP / 2].reg |= + MUX_PA25H_USB_DP << (4 * (PIN_PA25H_USB_DP & 0x01u)); + + GCLK->PCHCTRL[USB_GCLK_ID].reg = + GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + + NVIC_SetPriority(USB_OTHER_IRQn, 0UL); + NVIC_SetPriority(USB_SOF_HSOF_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT0_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT1_IRQn, 0UL); #else PM->APBBMASK.reg |= PM_APBBMASK_USB; @@ -126,7 +157,7 @@ void TinyUSB_Port_EnterDFU(void) { } uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]) { -#ifdef __SAMD51__ +#if TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) uint32_t *id_addresses[4] = {(uint32_t *)0x008061FC, (uint32_t *)0x00806010, (uint32_t *)0x00806014, (uint32_t *)0x00806018}; #else // samd21 diff --git a/src/arduino/ports/samd/tusb_config_samd.h b/src/arduino/ports/samd/tusb_config_samd.h index d2276d12..f4875022 100644 --- a/src/arduino/ports/samd/tusb_config_samd.h +++ b/src/arduino/ports/samd/tusb_config_samd.h @@ -32,8 +32,10 @@ extern "C" { //-------------------------------------------------------------------- // COMMON CONFIGURATION //-------------------------------------------------------------------- -#ifdef __SAMD51__ +#if defined(__SAMD51__) || defined(__SAME51__) #define CFG_TUSB_MCU OPT_MCU_SAMD51 +#elif defined(__SAME53__) || defined(__SAME54__) +#define CFG_TUSB_MCU OPT_MCU_SAME5X #else #define CFG_TUSB_MCU OPT_MCU_SAMD21 #endif diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index cdfb00e3..c21e94ea 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -29,6 +29,7 @@ #if CFG_TUD_ENABLED && TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAMD21, OPT_MCU_SAML2X, OPT_MCU_SAMD51, OPT_MCU_SAME5X) #include "sam.h" +#include "same5x_usb.h" #include "device/dcd.h" /*------------------------------------------------------------------*/ @@ -103,7 +104,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } -#if TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) +#if TU_CHECK_MCU(OPT_MCU_SAMD51) void dcd_int_enable(uint8_t rhport) { (void) rhport; NVIC_EnableIRQ(USB_0_IRQn); @@ -120,6 +121,23 @@ void dcd_int_disable(uint8_t rhport) { NVIC_DisableIRQ(USB_0_IRQn); } +#elif TU_CHECK_MCU(OPT_MCU_SAME5X) +void dcd_int_enable(uint8_t rhport) { + (void) rhport; + NVIC_EnableIRQ(USB_OTHER_IRQn); + NVIC_EnableIRQ(USB_SOF_HSOF_IRQn); + NVIC_EnableIRQ(USB_TRCPT0_IRQn); + NVIC_EnableIRQ(USB_TRCPT1_IRQn); +} + +void dcd_int_disable(uint8_t rhport) { + (void) rhport; + NVIC_DisableIRQ(USB_TRCPT1_IRQn); + NVIC_DisableIRQ(USB_TRCPT0_IRQn); + NVIC_DisableIRQ(USB_SOF_HSOF_IRQn); + NVIC_DisableIRQ(USB_OTHER_IRQn); +} + #elif TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAMD21, OPT_MCU_SAML2X) void dcd_int_enable(uint8_t rhport) { (void) rhport; diff --git a/src/portable/microchip/samd/hcd_samd.c b/src/portable/microchip/samd/hcd_samd.c index 0de7ddeb..110190af 100644 --- a/src/portable/microchip/samd/hcd_samd.c +++ b/src/portable/microchip/samd/hcd_samd.c @@ -31,6 +31,7 @@ #include "host/hcd.h" #include "sam.h" +#include "same5x_usb.h" /*------------------------------------------------------------------*/ /* MACRO TYPEDEF CONSTANT ENUM @@ -425,7 +426,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } -#if TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) +#if TU_CHECK_MCU(OPT_MCU_SAMD51) // Enable USB interrupt void hcd_int_enable(uint8_t rhport) @@ -447,6 +448,28 @@ void hcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_0_IRQn); } +#elif TU_CHECK_MCU(OPT_MCU_SAME5X) + +// Enable USB interrupt +void hcd_int_enable(uint8_t rhport) +{ + (void) rhport; + NVIC_EnableIRQ(USB_OTHER_IRQn); + NVIC_EnableIRQ(USB_SOF_HSOF_IRQn); + NVIC_EnableIRQ(USB_TRCPT0_IRQn); + NVIC_EnableIRQ(USB_TRCPT1_IRQn); +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) +{ + (void) rhport; + NVIC_DisableIRQ(USB_TRCPT1_IRQn); + NVIC_DisableIRQ(USB_TRCPT0_IRQn); + NVIC_DisableIRQ(USB_SOF_HSOF_IRQn); + NVIC_DisableIRQ(USB_OTHER_IRQn); +} + #elif TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAMD21, OPT_MCU_SAML2X) // Enable USB interrupt diff --git a/src/portable/microchip/samd/same5x_usb.h b/src/portable/microchip/samd/same5x_usb.h new file mode 100644 index 00000000..3dc9fbce --- /dev/null +++ b/src/portable/microchip/samd/same5x_usb.h @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026 Chris Rabel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SAME5X_USB_H_ +#define _SAME5X_USB_H_ + +#if defined(__GNUC__) +#pragma GCC system_header +#endif + +#include "tusb_option.h" + +#if TU_CHECK_MCU(OPT_MCU_SAME5X) + +#ifndef _Ul +#define _Ul(x) x##U +#endif + +#ifndef TUSB_SAME5X_COMPAT_ROREG8 +#define TUSB_SAME5X_COMPAT_ROREG8 1 +typedef volatile const uint8_t RoReg8; +#endif + +#if defined(__has_include) +#if __has_include("samd51/include/component/usb.h") +#include "samd51/include/component/usb.h" +#else +#error "SAME5x USB support requires SAMD51 USB component headers on the include path." +#endif +#else +#include "samd51/include/component/usb.h" +#endif + +#if !defined(NVMCTRL_SW0) && defined(SW0_ADDR) +#define NVMCTRL_SW0 SW0_ADDR +#elif !defined(NVMCTRL_SW0) && defined(SW0_FUSES_BASE_ADDRESS) +#define NVMCTRL_SW0 SW0_FUSES_BASE_ADDRESS +#endif + +#ifndef USB_FUSES_TRANSN_ADDR +#define USB_FUSES_TRANSN_ADDR (NVMCTRL_SW0 + 4) +#define USB_FUSES_TRANSN_Pos 0 +#define USB_FUSES_TRANSN_Msk (_Ul(0x1F) << USB_FUSES_TRANSN_Pos) +#endif + +#ifndef USB_FUSES_TRANSP_ADDR +#define USB_FUSES_TRANSP_ADDR (NVMCTRL_SW0 + 4) +#define USB_FUSES_TRANSP_Pos 5 +#define USB_FUSES_TRANSP_Msk (_Ul(0x1F) << USB_FUSES_TRANSP_Pos) +#endif + +#ifndef USB_FUSES_TRIM_ADDR +#define USB_FUSES_TRIM_ADDR (NVMCTRL_SW0 + 4) +#define USB_FUSES_TRIM_Pos 10 +#define USB_FUSES_TRIM_Msk (_Ul(0x7) << USB_FUSES_TRIM_Pos) +#endif + +#if !defined(USB) && defined(USB_REGS) +#define USB ((Usb *)USB_REGS) +#endif + +#endif + +#endif