diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 3beef45d0..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Bug Report -about: Create a report to help us improve -title: 'Please provide all details at least for Setup/Describe/Reproduce' -labels: Bug 🐞 -assignees: '' - ---- - -**Set Up** - -- **PC OS** e.g Ubuntu 20.04 / Windows 10 / macOS 10.15 -- **Board** e.g Feather nRF52840 Express (if custom specify your MCUs) -- **TinyUSB version** relase version or git hash (preferrably running with master for lastest code) -- **Firmware** e.g examples/device/cdc_msc - -**Describe The Bug** - -A clear and concise description of what the bug is. - -**To Reproduce** - -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. See error - -**Screenshots** - -If applicable, add screenshots, bus capture to help explain your problem. - -**Log** - -If applicable, provide the stack's log (uart/rtt/swo) where the issue occurred as attached txt file, best with comments to explain the actual events. -Note: To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. More information can be found at [example's readme](/docs/getting_started.md) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..291b22079 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,74 @@ +name: Bug Report +description: Report a problem with TinyUSB +labels: 'Bug 🐞' +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + It's okay to leave some blank if it doesn't apply to your problem. + + - type: dropdown + attributes: + label: Operating System + options: + - Linux + - MacOS + - RaspberryPi OS + - Windows 7 + - Windows 10 + - Windows 11 + - Others + validations: + required: true + + - type: input + attributes: + label: Board + placeholder: e.g Feather nRF52840 Express + validations: + required: true + + - type: textarea + attributes: + label: Firmware + placeholder: | + e.g examples/device/cdc_msc. + If it is custom firmware, please provide links to your minimal sources or as attached files. + validations: + required: true + + - type: textarea + attributes: + label: What happened ? + placeholder: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + attributes: + label: How to reproduce ? + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. See error + validations: + required: true + + - type: textarea + attributes: + label: Debug Log + placeholder: | + TinyUSB debug log where the issue occurred as attached txt file, best with comments to explain the actual events. + + Note: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h. + More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md) + validations: + required: false + + - type: textarea + attributes: + label: Screenshots + description: If applicable, add screenshots to help explain your problem. + validations: + required: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1e149dc65..fc5b92b68 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,8 +49,7 @@ jobs: - 'samd11' - 'samd21' - 'samd51' - - 'saml21' - - 'saml22' + - 'saml2x' - 'stm32f0' - 'stm32f4' - 'stm32f7' diff --git a/.github/workflows/build_esp.yml b/.github/workflows/build_esp.yml index 08bb4f5d2..25f4e68f8 100644 --- a/.github/workflows/build_esp.yml +++ b/.github/workflows/build_esp.yml @@ -16,10 +16,10 @@ jobs: board: # Alphabetical order # ESP32-S2 - - 'adafruit_metro_esp32s2' - 'espressif_saola_1' # ESP32-S3 - - 'espressif_addax_1' + # latest IDF does not define USB0 in linker + #- 'espressif_addax_1' steps: - name: Setup Python diff --git a/.github/workflows/build_renesas.yml b/.github/workflows/build_renesas.yml index 45e0c5fd5..ee9ba8289 100644 --- a/.github/workflows/build_renesas.yml +++ b/.github/workflows/build_renesas.yml @@ -15,7 +15,7 @@ jobs: matrix: family: # Alphabetical order - - 'rx63n' + - 'rx' steps: - name: Setup Python uses: actions/setup-python@v2 diff --git a/README.md b/README.md index bea6d0d49..11c1df3f8 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The stack supports the following MCUs: - **Dialog:** DA1469x - **Espressif:** ESP32-S2, ESP32-S3 -- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55 +- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55, SAML21, SAML22 - **NordicSemi:** nRF52833, nRF52840 - **Nuvoton:** NUC120, NUC121/NUC125, NUC126, NUC505 - **NXP:** @@ -40,7 +40,7 @@ The stack supports the following MCUs: - Kinetis: KL25 - LPC Series: 11u, 13, 15, 17, 18, 40, 43, 51u, 54, 55 - **Raspberry Pi:** RP2040 -- **Renesas:** RX63N +- **Renesas:** RX63N, RX65N - **Silabs:** EFM32GG12 - **Sony:** CXD56 - **ST:** STM32 series: L0, F0, F1, F2, F3, F4, F7, H7 both FullSpeed and HighSpeed diff --git a/docs/boards.md b/docs/boards.md index ebba1f841..53b0da702 100644 --- a/docs/boards.md +++ b/docs/boards.md @@ -47,8 +47,9 @@ This code base already had supported for a handful of following boards (sorted a - [Microchip SAMG55 Xplained Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMG55-XPRO) -### MicroChip SAML22 +### MicroChip SAML2x +- [SAML21 Xplaind Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAML21-XPRO-B) - [SAML22 Feather](https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather) - [Sensor Watch](https://github.com/joeycastillo/Sensor-Watch) @@ -126,6 +127,7 @@ This code base already had supported for a handful of following boards (sorted a ### Renesas RX - [GR-CITRUS](https://www.renesas.com/us/en/products/gadget-renesas/boards/gr-citrus) +- [Renesas RX65N Cloud Kit](https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/rx65n-cloud-kit-renesas-rx65n-cloud-kit) ### Raspberry Pi RP2040 diff --git a/examples/device/cdc_msc_freertos/src/freertos_hook.c b/examples/device/cdc_msc_freertos/src/freertos_hook.c index 273ad46e6..ab885947c 100644 --- a/examples/device/cdc_msc_freertos/src/freertos_hook.c +++ b/examples/device/cdc_msc_freertos/src/freertos_hook.c @@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } -#if CFG_TUSB_MCU == OPT_MCU_RX63X +#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X #include "iodefine.h" void vApplicationSetupTimerInterrupt(void) { diff --git a/examples/device/hid_composite_freertos/src/freertos_hook.c b/examples/device/hid_composite_freertos/src/freertos_hook.c index 273ad46e6..ab885947c 100644 --- a/examples/device/hid_composite_freertos/src/freertos_hook.c +++ b/examples/device/hid_composite_freertos/src/freertos_hook.c @@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } -#if CFG_TUSB_MCU == OPT_MCU_RX63X +#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X #include "iodefine.h" void vApplicationSetupTimerInterrupt(void) { diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 23ab12404..817646dab 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -30,7 +30,8 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ -// If your host terminal support ansi escape code, it can be use to simulate mouse cursor +// If your host terminal support ansi escape code such as TeraTerm +// it can be use to simulate mouse cursor movement within terminal #define USE_ANSI_ESCAPE 0 #define MAX_REPORT 4 @@ -113,6 +114,13 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons return; } + // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples: + // - Keyboard : Desktop, Keyboard + // - Mouse : Desktop, Mouse + // - Gamepad : Desktop, Gamepad + // - Consumer Control (Media Key) : Consumer, Consumer Control + // - System Control (Power key) : Desktop, System Control + // - Generic (vendor) : 0xFFxx, xx if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP ) { switch (rpt_info->usage) @@ -164,7 +172,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report) }else { // not existed in previous report means the current key is pressed - bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); + bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0]; putchar(ch); if ( ch == '\r' ) putchar('\n'); // added new line for enter key diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index cc77b6554..b574acf9b 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -76,7 +76,7 @@ #define CFG_TUH_HUB 1 #define CFG_TUH_CDC 1 -#define CFG_TUH_HID 2 +#define CFG_TUH_HID 4 #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h index f8e89ad04..9f6b489ea 100644 --- a/hw/bsp/board_mcu.h +++ b/hw/bsp/board_mcu.h @@ -127,7 +127,7 @@ #elif CFG_TUSB_MCU == OPT_MCU_EFM32GG || CFG_TUSB_MCU == OPT_MCU_EFM32GG11 || CFG_TUSB_MCU == OPT_MCU_EFM32GG12 #include "em_device.h" -#elif CFG_TUSB_MCU == OPT_MCU_RX63X +#elif CFG_TUSB_MCU == OPT_MCU_RX63X || CFG_TUSB_MCU == OPT_MCU_RX65X // no header needed #else diff --git a/hw/bsp/rx/boards/gr_citrus/board.mk b/hw/bsp/rx/boards/gr_citrus/board.mk new file mode 100644 index 000000000..0eba94610 --- /dev/null +++ b/hw/bsp/rx/boards/gr_citrus/board.mk @@ -0,0 +1,24 @@ +DEPS_SUBMODULES += hw/mcu/renesas/rx + +CFLAGS += \ + -mcpu=rx610 \ + -misa=v1 \ + -DCFG_TUSB_MCU=OPT_MCU_RX63X + +MCU_DIR = hw/mcu/renesas/rx/rx63n + +# All source paths should be relative to the top level. +LD_FILE = $(BOARD_PATH)/r5f5631fd.ld + +# For freeRTOS port source +FREERTOS_PORT = RX600 + +# For flash-jlink target +JLINK_DEVICE = R5F5631F +JLINK_IF = JTAG + +# For flash-pyocd target +PYOCD_TARGET = + +# flash using jlink +flash: flash-jlink diff --git a/hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c b/hw/bsp/rx/boards/gr_citrus/gr_citrus.c similarity index 100% rename from hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c rename to hw/bsp/rx/boards/gr_citrus/gr_citrus.c diff --git a/hw/bsp/rx63n/boards/gr_citrus/hwinit.c b/hw/bsp/rx/boards/gr_citrus/hwinit.c similarity index 100% rename from hw/bsp/rx63n/boards/gr_citrus/hwinit.c rename to hw/bsp/rx/boards/gr_citrus/hwinit.c diff --git a/hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld b/hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld similarity index 100% rename from hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld rename to hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld diff --git a/hw/bsp/rx/boards/rx65n_cloud_kit/board.mk b/hw/bsp/rx/boards/rx65n_cloud_kit/board.mk new file mode 100644 index 000000000..fc76d79fa --- /dev/null +++ b/hw/bsp/rx/boards/rx65n_cloud_kit/board.mk @@ -0,0 +1,25 @@ +CFLAGS += \ + -mcpu=rx64m \ + -misa=v2 \ + -DCFG_TUSB_MCU=OPT_MCU_RX65X \ + -DIR_USB0_USBI0=IR_PERIB_INTB185 \ + -DIER_USB0_USBI0=IER_PERIB_INTB185 \ + -DIEN_USB0_USBI0=IEN_PERIB_INTB185 + +MCU_DIR = hw/mcu/renesas/rx/rx65n + +# All source paths should be relative to the top level. +LD_FILE = $(BOARD_PATH)/r5f565ne.ld + +# For freeRTOS port source +FREERTOS_PORT = RX600 + +# For flash-jlink target +JLINK_DEVICE = R5F565NE +JLINK_IF = JTAG + +# For flash-pyocd target +PYOCD_TARGET = + +# flash using rfp-cli +flash: flash-rfp diff --git a/hw/bsp/rx/boards/rx65n_cloud_kit/r5f565ne.ld b/hw/bsp/rx/boards/rx65n_cloud_kit/r5f565ne.ld new file mode 100644 index 000000000..a02f0c02f --- /dev/null +++ b/hw/bsp/rx/boards/rx65n_cloud_kit/r5f565ne.ld @@ -0,0 +1,168 @@ +__USTACK_SIZE = 0x00000200; +__ISTACK_SIZE = 0x00000200; + +MEMORY +{ + RAM : ORIGIN = 0x4, LENGTH = 0x3fffc + RAM2 : ORIGIN = 0x00800000, LENGTH = 0x60000 + OFS : ORIGIN = 0xFE7F5D00, LENGTH = 128 + ROM : ORIGIN = 0xFFE00000, LENGTH = 0x200000 +} +SECTIONS +{ + .exvectors 0xFFFFFF80: AT(0xFFFFFF80) + { + "_exvectors_start" = .; + KEEP(*(.exvectors)) + "_exvectors_end" = .; + } >ROM + .fvectors 0xFFFFFFFC: AT(0xFFFFFFFC) + { + KEEP(*(.fvectors)) + } > ROM + .text 0xFFE00000: AT(0xFFE00000) + { + *(.text) + *(.text.*) + *(P) + KEEP(*(.text.*_isr)) + etext = .; + } > ROM + .rvectors ALIGN(4): + { + _rvectors_start = .; + KEEP(*(.rvectors)) + _rvectors_end = .; + } > ROM + .init : + { + KEEP(*(.init)) + __preinit_array_start = .; + KEEP(*(.preinit_array)) + __preinit_array_end = .; + __init_array_start = (. + 3) & ~ 3; + KEEP(*(.init_array)) + KEEP(*(SORT(.init_array.*))) + __init_array_end = .; + __fini_array_start = .; + KEEP(*(.fini_array)) + KEEP(*(SORT(.fini_array.*))) + __fini_array_end = .; + } > ROM + .fini : + { + KEEP(*(.fini)) + } > ROM + .got : + { + *(.got) + *(.got.plt) + } > ROM + .rodata : + { + *(.rodata) + *(.rodata.*) + *(C_1) + *(C_2) + *(C) + _erodata = .; + } > ROM + .eh_frame_hdr : + { + *(.eh_frame_hdr) + } > ROM + .eh_frame : + { + *(.eh_frame) + } > ROM + .jcr : + { + *(.jcr) + } > ROM + .tors : + { + __CTOR_LIST__ = .; + . = ALIGN(2); + ___ctors = .; + *(.ctors) + ___ctors_end = .; + __CTOR_END__ = .; + __DTOR_LIST__ = .; + ___dtors = .; + *(.dtors) + ___dtors_end = .; + __DTOR_END__ = .; + . = ALIGN(2); + _mdata = .; + } > ROM + .data : AT(_mdata) + { + _data = .; + *(.data) + *(.data.*) + *(D) + *(D_1) + *(D_2) + _edata = .; + } > RAM + .gcc_exc : + { + *(.gcc_exc) + } > RAM + .bss : + { + _bss = .; + *(.bss) + *(.bss.**) + *(COMMON) + *(B) + *(B_1) + *(B_2) + _ebss = .; + _end = .; + } > RAM + .ustack : + { + . = ALIGN(8); + . = . + __USTACK_SIZE; + PROVIDE(_ustack = .); + } > RAM + .istack : + { + . = ALIGN(8); + . = . + __ISTACK_SIZE; + PROVIDE(_istack = .); + } > RAM + .ofs1 0xFE7F5D00: AT(0xFE7F5D00) + { + KEEP(*(.ofs1)) + } > OFS + .ofs2 0xFE7F5D10: AT(0xFE7F5D10) + { + KEEP(*(.ofs2)) + } > OFS + .ofs3 0xFE7F5D20: AT(0xFE7F5D20) + { + KEEP(*(.ofs3)) + } > OFS + .ofs4 0xFE7F5D40: AT(0xFE7F5D40) + { + KEEP(*(.ofs4)) + } > OFS + .ofs5 0xFE7F5D48: AT(0xFE7F5D48) + { + KEEP(*(.ofs5)) + } > OFS + .ofs6 0xFE7F5D50: AT(0xFE7F5D50) + { + KEEP(*(.ofs6)) + } > OFS + .ofs7 0xFE7F5D64: AT(0xFE7F5D64) + { + KEEP(*(.ofs7)) + } > OFS + .ofs8 0xFE7F5D70: AT(0xFE7F5D70) + { + KEEP(*(.ofs8)) + } > OFS +} diff --git a/hw/bsp/rx/boards/rx65n_cloud_kit/rx65n_cloud_kit.c b/hw/bsp/rx/boards/rx65n_cloud_kit/rx65n_cloud_kit.c new file mode 100644 index 000000000..895b82e23 --- /dev/null +++ b/hw/bsp/rx/boards/rx65n_cloud_kit/rx65n_cloud_kit.c @@ -0,0 +1,270 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Koji Kitayama + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "bsp/board.h" +#include "iodefine.h" +#include "interrupt_handlers.h" + +#define IRQ_PRIORITY_CMT0 5 +#define IRQ_PRIORITY_USBI0 6 +#define IRQ_PRIORITY_SCI5 5 + +#define SYSTEM_PRCR_PRC1 (1<<1) +#define SYSTEM_PRCR_PRKEY (0xA5u<<8) + +#define CMT_PCLK 60000000 +#define CMT_CMCR_CKS_DIV_128 2 +#define CMT_CMCR_CMIE (1<<6) +#define MPC_PFS_ISEL (1<<6) + +#define SCI_PCLK 60000000 +#define SCI_SSR_FER (1<<4) +#define SCI_SSR_ORER (1<<5) + +#define SCI_SCR_TEIE (1u<<2) +#define SCI_SCR_RE (1u<<4) +#define SCI_SCR_TE (1u<<5) +#define SCI_SCR_RIE (1u<<6) +#define SCI_SCR_TIE (1u<<7) +#define INT_Excep_SCI5_TEI5 INT_Excep_ICU_GROUPBL0 + +#define IRQ_USB0_USBI0 62 +#define SLIBR_USBI0 SLIBR185 +#define IPR_USB0_USBI0 IPR_PERIB_INTB185 +#define INT_Excep_USB0_USBI0 INT_Excep_PERIB_INTB185 + +void HardwareSetup(void) +{ + FLASH.ROMCIV.WORD = 1; + while (FLASH.ROMCIV.WORD) ; + FLASH.ROMCE.WORD = 1; + while (!FLASH.ROMCE.WORD) ; + + SYSTEM.PRCR.WORD = 0xA503u; + if (!SYSTEM.RSTSR1.BYTE) { + RTC.RCR4.BYTE = 0; + RTC.RCR3.BYTE = 12; + while (12 != RTC.RCR3.BYTE) ; + } + SYSTEM.SOSCCR.BYTE = 1; + + if (SYSTEM.HOCOCR.BYTE) { + SYSTEM.HOCOCR.BYTE = 0; + while (!SYSTEM.OSCOVFSR.BIT.HCOVF) ; + } + SYSTEM.PLLCR.WORD = 0x1D10u; /* HOCO x 15 */ + SYSTEM.PLLCR2.BYTE = 0; + while (!SYSTEM.OSCOVFSR.BIT.PLOVF) ; + + SYSTEM.SCKCR.LONG = 0x21C11222u; + SYSTEM.SCKCR2.WORD = 0x0041u; + SYSTEM.ROMWT.BYTE = 0x02u; + while (0x02u != SYSTEM.ROMWT.BYTE) ; + SYSTEM.SCKCR3.WORD = 0x400u; + SYSTEM.PRCR.WORD = 0xA500u; +} + +//--------------------------------------------------------------------+ +// SCI handling +//--------------------------------------------------------------------+ +typedef struct { + uint8_t *buf; + uint32_t cnt; +} sci_buf_t; +static volatile sci_buf_t sci_buf[2]; + +void INT_Excep_SCI5_TXI5(void) +{ + uint8_t *buf = sci_buf[0].buf; + uint32_t cnt = sci_buf[0].cnt; + + if (!buf || !cnt) { + SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE); + return; + } + SCI5.TDR = *buf; + if (--cnt) { + ++buf; + } else { + buf = NULL; + SCI5.SCR.BIT.TIE = 0; + SCI5.SCR.BIT.TEIE = 1; + } + sci_buf[0].buf = buf; + sci_buf[0].cnt = cnt; +} + +void INT_Excep_SCI5_TEI5(void) +{ + SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE); +} + +void INT_Excep_SCI5_RXI5(void) +{ + uint8_t *buf = sci_buf[1].buf; + uint32_t cnt = sci_buf[1].cnt; + + if (!buf || !cnt || + (SCI5.SSR.BYTE & (SCI_SSR_FER | SCI_SSR_ORER))) { + sci_buf[1].buf = NULL; + SCI5.SSR.BYTE = 0; + SCI5.SCR.BYTE &= ~(SCI_SCR_RE | SCI_SCR_RIE); + return; + } + *buf = SCI5.RDR; + if (--cnt) { + ++buf; + } else { + buf = NULL; + SCI5.SCR.BYTE &= ~(SCI_SCR_RE | SCI_SCR_RIE); + } + sci_buf[1].buf = buf; + sci_buf[1].cnt = cnt; +} + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void INT_Excep_USB0_USBI0(void) +{ + tud_int_handler(0); +} + +void board_init(void) +{ + /* setup software configurable interrupts */ + ICU.SLIBR_USBI0.BYTE = IRQ_USB0_USBI0; + ICU.SLIPRCR.BYTE = 1; + +#if CFG_TUSB_OS == OPT_OS_NONE + /* Enable CMT0 */ + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1; + MSTP(CMT0) = 0; + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY; + /* Setup 1ms tick timer */ + CMT0.CMCNT = 0; + CMT0.CMCOR = CMT_PCLK / 1000 / 128; + CMT0.CMCR.WORD = CMT_CMCR_CMIE | CMT_CMCR_CKS_DIV_128; + IR(CMT0, CMI0) = 0; + IPR(CMT0, CMI0) = IRQ_PRIORITY_CMT0; + IEN(CMT0, CMI0) = 1; + CMT.CMSTR0.BIT.STR0 = 1; +#endif + + /* Unlock MPC registers */ + MPC.PWPR.BIT.B0WI = 0; + MPC.PWPR.BIT.PFSWE = 1; + // SW PB1 + PORTB.PMR.BIT.B1 = 0U; + PORTB.PDR.BIT.B1 = 0U; + // LED PD6 + PORTD.PODR.BIT.B6 = 1U; + PORTD.ODR1.BIT.B4 = 1U; + PORTD.PMR.BIT.B6 = 0U; + PORTD.PDR.BIT.B6 = 1U; + /* UART TXD5 => PA4, RXD5 => PA3 */ + PORTA.PMR.BIT.B4 = 1U; + PORTA.PCR.BIT.B4 = 1U; + MPC.PA4PFS.BYTE = 0b01010; + PORTA.PMR.BIT.B3 = 1U; + MPC.PA5PFS.BYTE = 0b01010; + /* USB VBUS -> P16 */ + PORT1.PMR.BIT.B6 = 1U; + MPC.P16PFS.BYTE = MPC_PFS_ISEL | 0b10001; + /* Lock MPC registers */ + MPC.PWPR.BIT.PFSWE = 0; + MPC.PWPR.BIT.B0WI = 1; + + /* Enable SCI5 */ + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1; + MSTP(SCI5) = 0; + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY; + SCI5.SEMR.BIT.ABCS = 1; + SCI5.SEMR.BIT.BGDM = 1; + SCI5.BRR = (SCI_PCLK / (8 * 115200)) - 1; + IR(SCI5, RXI5) = 0; + IR(SCI5, TXI5) = 0; + IS(SCI5, TEI5) = 0; + IR(ICU, GROUPBL0) = 0; + IPR(SCI5, RXI5) = IRQ_PRIORITY_SCI5; + IPR(SCI5, TXI5) = IRQ_PRIORITY_SCI5; + IPR(ICU,GROUPBL0) = IRQ_PRIORITY_SCI5; + IEN(SCI5, RXI5) = 1; + IEN(SCI5, TXI5) = 1; + IEN(ICU,GROUPBL0) = 1; + EN(SCI5, TEI5) = 1; + + /* setup USBI0 interrupt. */ + IR(USB0, USBI0) = 0; + IPR(USB0, USBI0) = IRQ_PRIORITY_USBI0; +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) +{ + PORTD.PODR.BIT.B6 = state ? 0 : 1; +} + +uint32_t board_button_read(void) +{ + return PORTB.PIDR.BIT.B1 ? 0 : 1; +} + +int board_uart_read(uint8_t* buf, int len) +{ + sci_buf[1].buf = buf; + sci_buf[1].cnt = len; + SCI5.SCR.BYTE |= SCI_SCR_RE | SCI_SCR_RIE; + while (SCI5.SCR.BIT.RE) ; + return len - sci_buf[1].cnt; +} + +int board_uart_write(void const *buf, int len) +{ + sci_buf[0].buf = (uint8_t*)buf; + sci_buf[0].cnt = len; + SCI5.SCR.BYTE |= SCI_SCR_TE | SCI_SCR_TIE; + while (SCI5.SCR.BIT.TE) ; + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; +void INT_Excep_CMT0_CMI0(void) +{ + ++system_ticks; +} + +uint32_t board_millis(void) +{ + return system_ticks; +} +#else +uint32_t SystemCoreClock = 120000000; +#endif diff --git a/hw/bsp/rx/family.mk b/hw/bsp/rx/family.mk new file mode 100644 index 000000000..7d7585b4a --- /dev/null +++ b/hw/bsp/rx/family.mk @@ -0,0 +1,50 @@ +DEPS_SUBMODULES += hw/mcu/renesas/rx + +# Cross Compiler for RX +CROSS_COMPILE = rx-elf- + +include $(TOP)/$(BOARD_PATH)/board.mk + +CFLAGS += \ + -nostartfiles \ + -ffunction-sections \ + -fdata-sections \ + -fshort-enums \ + -mlittle-endian-data \ + +RX_NEWLIB ?= 1 + +ifeq ($(CMDEXE),1) + OPTLIBINC="$(shell for /F "usebackq delims=" %%i in (`where rx-elf-gcc`) do echo %%~dpi..\rx-elf\optlibinc)" +else + OPTLIBINC=$(shell dirname `which rx-elf-gcc`)../rx-elf/optlibinc +endif + +ifeq ($(RX_NEWLIB),1) + CFLAGS += -DSSIZE_MAX=__INT_MAX__ +else + # setup for optlib + CFLAGS += -nostdinc \ + -isystem $(OPTLIBINC) \ + -DLWIP_NO_INTTYPES_H + + LIBS += -loptc -loptm +endif + +SRC_C += \ + src/portable/renesas/usba/dcd_usba.c \ + $(MCU_DIR)/vects.c + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MCU_DIR) + +SRC_S += $(MCU_DIR)/start.S + +$(BUILD)/$(PROJECT).mot: $(BUILD)/$(PROJECT).elf + @echo CREATE $@ + $(OBJCOPY) -O srec -I elf32-rx-be-ns $^ $@ + +# flash using rfp-cli +flash-rfp: $(BUILD)/$(PROJECT).mot + rfp-cli -device rx65x -tool e2l -if fine -fo id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auth id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auto $^ diff --git a/hw/bsp/rx63n/boards/gr_citrus/board.mk b/hw/bsp/rx63n/boards/gr_citrus/board.mk deleted file mode 100644 index feab5b5e6..000000000 --- a/hw/bsp/rx63n/boards/gr_citrus/board.mk +++ /dev/null @@ -1,61 +0,0 @@ -DEPS_SUBMODULES += hw/mcu/renesas/rx - -CFLAGS += \ - -nostartfiles \ - -ffunction-sections \ - -fdata-sections \ - -fshort-enums \ - -mcpu=rx610 \ - -misa=v1 \ - -mlittle-endian-data \ - -DCFG_TUSB_MCU=OPT_MCU_RX63X - -# Cross Compiler for RX -CROSS_COMPILE = rx-elf- - -RX_NEWLIB ?= 1 - -ifeq ($(CMDEXE),1) -OPTLIBINC="$(shell for /F "usebackq delims=" %%i in (`where rx-elf-gcc`) do echo %%~dpi..\rx-elf\optlibinc)" -else -OPTLIBINC=$(shell dirname `which rx-elf-gcc`)../rx-elf/optlibinc -endif - -ifeq ($(RX_NEWLIB),1) -CFLAGS += -DSSIZE_MAX=__INT_MAX__ -else -# setup for optlib -CFLAGS += -nostdinc \ - -isystem $(OPTLIBINC) \ - -DLWIP_NO_INTTYPES_H - -LIBS += -loptc -loptm -endif - -MCU_DIR = hw/mcu/renesas/rx/rx63n - -# All source paths should be relative to the top level. -LD_FILE = $(BOARD_PATH)/r5f5631fd.ld - -SRC_C += \ - src/portable/renesas/usba/dcd_usba.c \ - $(MCU_DIR)/vects.c - -INC += \ - $(TOP)/$(BOARD_PATH) \ - $(TOP)/$(MCU_DIR) - -SRC_S += $(MCU_DIR)/start.S - -# For freeRTOS port source -FREERTOS_PORT = RX600 - -# For flash-jlink target -JLINK_DEVICE = R5F5631F -JLINK_IF = JTAG - -# For flash-pyocd target -PYOCD_TARGET = - -# flash using jlink -flash: flash-jlink diff --git a/hw/bsp/rx63n/family.mk b/hw/bsp/rx63n/family.mk deleted file mode 100644 index d3c743ed1..000000000 --- a/hw/bsp/rx63n/family.mk +++ /dev/null @@ -1 +0,0 @@ -include $(TOP)/$(BOARD_PATH)/board.mk \ No newline at end of file diff --git a/hw/bsp/saml21/family.mk b/hw/bsp/saml21/family.mk deleted file mode 100644 index a6611d5f4..000000000 --- a/hw/bsp/saml21/family.mk +++ /dev/null @@ -1,50 +0,0 @@ -UF2_FAMILY_ID = 0x68ed2b88 -DEPS_SUBMODULES += hw/mcu/microchip - -include $(TOP)/$(BOARD_PATH)/board.mk - -CFLAGS += \ - -mthumb \ - -mabi=aapcs \ - -mcpu=cortex-m0plus \ - -nostdlib -nostartfiles \ - -DCONF_OSC32K_CALIB_ENABLE=0 \ - -DCFG_TUSB_MCU=OPT_MCU_SAML21 - -SRC_C += \ - src/portable/microchip/samd/dcd_samd.c \ - hw/mcu/microchip/saml21/gcc/gcc/startup_saml21.c \ - hw/mcu/microchip/saml21/gcc/system_saml21.c \ - hw/mcu/microchip/saml21/hpl/gclk/hpl_gclk.c \ - hw/mcu/microchip/saml21/hpl/mclk/hpl_mclk.c \ - hw/mcu/microchip/saml21/hpl/pm/hpl_pm.c \ - hw/mcu/microchip/saml21/hpl/osc32kctrl/hpl_osc32kctrl.c \ - hw/mcu/microchip/saml21/hpl/oscctrl/hpl_oscctrl.c \ - hw/mcu/microchip/saml21/hal/src/hal_atomic.c - -INC += \ - $(TOP)/$(BOARD_PATH) \ - $(TOP)/hw/mcu/microchip/saml21/ \ - $(TOP)/hw/mcu/microchip/saml21/config \ - $(TOP)/hw/mcu/microchip/saml21/include \ - $(TOP)/hw/mcu/microchip/saml21/hal/include \ - $(TOP)/hw/mcu/microchip/saml21/hal/utils/include \ - $(TOP)/hw/mcu/microchip/saml21/hpl/port \ - $(TOP)/hw/mcu/microchip/saml21/hri \ - $(TOP)/hw/mcu/microchip/saml21/CMSIS/Include - -# For TinyUSB port source -VENDOR = microchip -CHIP_FAMILY = samd - -# For freeRTOS port source -FREERTOS_PORT = ARM_CM0 - -# flash using bossac at least version 1.8 -# can be found in arduino15/packages/arduino/tools/bossac/ -# Add it to your PATH or change BOSSAC variable to match your installation -BOSSAC = bossac - -flash-bossac: $(BUILD)/$(PROJECT).bin - @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0) - $(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R diff --git a/hw/bsp/saml22/family.c b/hw/bsp/saml22/family.c deleted file mode 100644 index fff11cbe5..000000000 --- a/hw/bsp/saml22/family.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * 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. - * - * This file is part of the TinyUSB stack. - */ - -#include "sam.h" -#include "bsp/board.h" -#include "board.h" - -#include "hal/include/hal_gpio.h" -#include "hal/include/hal_init.h" -#include "hpl/gclk/hpl_gclk_base.h" -#include "hpl_mclk_config.h" - -//--------------------------------------------------------------------+ -// Forward USB interrupt events to TinyUSB IRQ Handler -//--------------------------------------------------------------------+ -void USB_Handler(void) -{ - tud_int_handler(0); -} - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - -/* Referenced GCLKs (out of 0~4), should be initialized firstly */ -#define _GCLK_INIT_1ST 0x00000000 -/* Not referenced GCLKs, initialized last */ -#define _GCLK_INIT_LAST 0x0000001F - -void board_init(void) -{ - // Clock init ( follow hpl_init.c ) - hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, CONF_NVM_WAIT_STATE); - - _set_performance_level(2); - - _osc32kctrl_init_sources(); - _oscctrl_init_sources(); - _mclk_init(); -#if _GCLK_INIT_1ST - _gclk_init_generators_by_fref(_GCLK_INIT_1ST); -#endif - _oscctrl_init_referenced_generators(); - _gclk_init_generators_by_fref(_GCLK_INIT_LAST); - -#if (CONF_PORT_EVCTRL_PORT_0 | CONF_PORT_EVCTRL_PORT_1 | CONF_PORT_EVCTRL_PORT_2 | CONF_PORT_EVCTRL_PORT_3) - hri_port_set_EVCTRL_reg(PORT, 0, CONF_PORTA_EVCTRL); - hri_port_set_EVCTRL_reg(PORT, 1, CONF_PORTB_EVCTRL); -#endif - - // Update SystemCoreClock since it is hard coded with asf4 and not correct - // Init 1ms tick timer (samd SystemCoreClock may not correct) - SystemCoreClock = CONF_CPU_FREQUENCY; - SysTick_Config(CONF_CPU_FREQUENCY / 1000); - - // Led init - gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT); - gpio_set_pin_level(LED_PIN, !LED_STATE_ON); - - // Button init - gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN); - gpio_set_pin_pull_mode(BUTTON_PIN, BUTTON_STATE_ACTIVE ? GPIO_PULL_DOWN : GPIO_PULL_UP); - -#if CFG_TUSB_OS == OPT_OS_FREERTOS - // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) - NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); -#endif - - /* USB Clock init - * The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock - * for low speed and full speed operation. */ - hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN); - hri_mclk_set_AHBMASK_USB_bit(MCLK); - hri_mclk_set_APBBMASK_USB_bit(MCLK); - - // USB Pin Init - gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA24, false); - gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF); - gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA25, false); - gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF); - - gpio_set_pin_function(PIN_PA24, PINMUX_PA24G_USB_DM); - gpio_set_pin_function(PIN_PA25, PINMUX_PA25G_USB_DP); - - // Output 500hz PWM on PB23 (TCC0 WO[3]) so we can validate the GCLK1 clock speed - hri_mclk_set_APBCMASK_TCC0_bit(MCLK); - TCC0->PER.bit.PER = 48000000 / 1000; - TCC0->CC[3].bit.CC = 48000000 / 2000; - TCC0->CTRLA.bit.ENABLE = true; - - gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3); - hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN); -} - -//--------------------------------------------------------------------+ -// Board porting API -//--------------------------------------------------------------------+ - -void board_led_write(bool state) -{ - gpio_set_pin_level(LED_PIN, state); -} - -uint32_t board_button_read(void) -{ - // button is active low - return gpio_get_pin_level(BUTTON_PIN) ? 0 : 1; -} - -int board_uart_read(uint8_t* buf, int len) -{ - (void) buf; (void) len; - return 0; -} - -int board_uart_write(void const * buf, int len) -{ - (void) buf; (void) len; - return 0; -} - -#if CFG_TUSB_OS == OPT_OS_NONE -volatile uint32_t system_ticks = 0; - -void SysTick_Handler (void) -{ - system_ticks++; -} - -uint32_t board_millis(void) -{ - return system_ticks; -} -#endif -void _init(void) -{ - -} \ No newline at end of file diff --git a/hw/bsp/saml22/family.mk b/hw/bsp/saml22/family.mk deleted file mode 100644 index fbe4e66f8..000000000 --- a/hw/bsp/saml22/family.mk +++ /dev/null @@ -1,50 +0,0 @@ -UF2_FAMILY_ID = 0x68ed2b88 -DEPS_SUBMODULES += hw/mcu/microchip - -include $(TOP)/$(BOARD_PATH)/board.mk - -CFLAGS += \ - -mthumb \ - -mabi=aapcs \ - -mcpu=cortex-m0plus \ - -nostdlib -nostartfiles \ - -DCONF_OSC32K_CALIB_ENABLE=0 \ - -DCFG_TUSB_MCU=OPT_MCU_SAML22 - -SRC_C += \ - src/portable/microchip/samd/dcd_samd.c \ - hw/mcu/microchip/saml22/gcc/gcc/startup_saml22.c \ - hw/mcu/microchip/saml22/gcc/system_saml22.c \ - hw/mcu/microchip/saml22/hpl/gclk/hpl_gclk.c \ - hw/mcu/microchip/saml22/hpl/mclk/hpl_mclk.c \ - hw/mcu/microchip/saml22/hpl/pm/hpl_pm.c \ - hw/mcu/microchip/saml22/hpl/osc32kctrl/hpl_osc32kctrl.c \ - hw/mcu/microchip/saml22/hpl/oscctrl/hpl_oscctrl.c \ - hw/mcu/microchip/saml22/hal/src/hal_atomic.c - -INC += \ - $(TOP)/$(BOARD_PATH) \ - $(TOP)/hw/mcu/microchip/saml22/ \ - $(TOP)/hw/mcu/microchip/saml22/config \ - $(TOP)/hw/mcu/microchip/saml22/include \ - $(TOP)/hw/mcu/microchip/saml22/hal/include \ - $(TOP)/hw/mcu/microchip/saml22/hal/utils/include \ - $(TOP)/hw/mcu/microchip/saml22/hpl/port \ - $(TOP)/hw/mcu/microchip/saml22/hri \ - $(TOP)/hw/mcu/microchip/saml22/CMSIS/Core/Include - -# For TinyUSB port source -VENDOR = microchip -CHIP_FAMILY = samd - -# For freeRTOS port source -FREERTOS_PORT = ARM_CM0 - -# flash using bossac at least version 1.8 -# can be found in arduino15/packages/arduino/tools/bossac/ -# Add it to your PATH or change BOSSAC variable to match your installation -BOSSAC = bossac - -flash-bossac: $(BUILD)/$(PROJECT).bin - @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0) - $(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R diff --git a/hw/bsp/saml21/boards/atsaml21_xpro/board.h b/hw/bsp/saml2x/boards/atsaml21_xpro/board.h similarity index 100% rename from hw/bsp/saml21/boards/atsaml21_xpro/board.h rename to hw/bsp/saml2x/boards/atsaml21_xpro/board.h diff --git a/hw/bsp/saml21/boards/atsaml21_xpro/board.mk b/hw/bsp/saml2x/boards/atsaml21_xpro/board.mk similarity index 90% rename from hw/bsp/saml21/boards/atsaml21_xpro/board.mk rename to hw/bsp/saml2x/boards/atsaml21_xpro/board.mk index aa77d4a21..81b4ecdcb 100644 --- a/hw/bsp/saml21/boards/atsaml21_xpro/board.mk +++ b/hw/bsp/saml2x/boards/atsaml21_xpro/board.mk @@ -1,5 +1,7 @@ CFLAGS += -D__SAML21J18B__ +SAML_VARIANT = saml21 + # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/saml21j18b_flash.ld diff --git a/hw/bsp/saml21/boards/atsaml21_xpro/saml21j18b_flash.ld b/hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld similarity index 100% rename from hw/bsp/saml21/boards/atsaml21_xpro/saml21j18b_flash.ld rename to hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld diff --git a/hw/bsp/saml22/boards/saml22_feather/board.h b/hw/bsp/saml2x/boards/saml22_feather/board.h similarity index 100% rename from hw/bsp/saml22/boards/saml22_feather/board.h rename to hw/bsp/saml2x/boards/saml22_feather/board.h diff --git a/hw/bsp/saml22/boards/saml22_feather/board.mk b/hw/bsp/saml2x/boards/saml22_feather/board.mk similarity index 89% rename from hw/bsp/saml22/boards/saml22_feather/board.mk rename to hw/bsp/saml2x/boards/saml22_feather/board.mk index a6a773137..0605dca19 100644 --- a/hw/bsp/saml22/boards/saml22_feather/board.mk +++ b/hw/bsp/saml2x/boards/saml22_feather/board.mk @@ -1,5 +1,7 @@ CFLAGS += -D__SAML22J18A__ +SAML_VARIANT = saml22 + # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/$(BOARD).ld diff --git a/hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld b/hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld similarity index 100% rename from hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld rename to hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/board.h b/hw/bsp/saml2x/boards/sensorwatch_m0/board.h similarity index 100% rename from hw/bsp/saml22/boards/sensorwatch_m0/board.h rename to hw/bsp/saml2x/boards/sensorwatch_m0/board.h diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/board.mk b/hw/bsp/saml2x/boards/sensorwatch_m0/board.mk similarity index 89% rename from hw/bsp/saml22/boards/sensorwatch_m0/board.mk rename to hw/bsp/saml2x/boards/sensorwatch_m0/board.mk index a6a773137..0605dca19 100644 --- a/hw/bsp/saml22/boards/sensorwatch_m0/board.mk +++ b/hw/bsp/saml2x/boards/sensorwatch_m0/board.mk @@ -1,5 +1,7 @@ CFLAGS += -D__SAML22J18A__ +SAML_VARIANT = saml22 + # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/$(BOARD).ld diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld b/hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld similarity index 100% rename from hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld rename to hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld diff --git a/hw/bsp/saml21/family.c b/hw/bsp/saml2x/family.c similarity index 93% rename from hw/bsp/saml21/family.c rename to hw/bsp/saml2x/family.c index d2d25ecac..470fde750 100644 --- a/hw/bsp/saml21/family.c +++ b/hw/bsp/saml2x/family.c @@ -108,13 +108,13 @@ void board_init(void) gpio_set_pin_function(PIN_PA25, PINMUX_PA25G_USB_DP); // Output 500hz PWM on PB23 (TCC0 WO[3]) so we can validate the GCLK1 clock speed - hri_mclk_set_APBCMASK_TCC0_bit(MCLK); - TCC0->PER.bit.PER = 48000000 / 1000; - TCC0->CC[3].bit.CC = 48000000 / 2000; - TCC0->CTRLA.bit.ENABLE = true; - - gpio_set_pin_function(PIN_PA19, PINMUX_PA19F_TCC0_WO3); - hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN); +// hri_mclk_set_APBCMASK_TCC0_bit(MCLK); +// TCC0->PER.bit.PER = 48000000 / 1000; +// TCC0->CC[3].bit.CC = 48000000 / 2000; +// TCC0->CTRLA.bit.ENABLE = true; +// +// gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3); +// hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN); } //--------------------------------------------------------------------+ @@ -160,4 +160,4 @@ uint32_t board_millis(void) void _init(void) { -} \ No newline at end of file +} diff --git a/hw/bsp/saml2x/family.mk b/hw/bsp/saml2x/family.mk new file mode 100644 index 000000000..e0f6b2f77 --- /dev/null +++ b/hw/bsp/saml2x/family.mk @@ -0,0 +1,48 @@ +UF2_FAMILY_ID = 0x68ed2b88 +DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/microchip + +include $(TOP)/$(BOARD_PATH)/board.mk + +MCU_DIR = hw/mcu/microchip/$(SAML_VARIANT) + +CFLAGS += \ + -mthumb \ + -mabi=aapcs \ + -mcpu=cortex-m0plus \ + -nostdlib -nostartfiles \ + -DCONF_OSC32K_CALIB_ENABLE=0 \ + -DCFG_TUSB_MCU=OPT_MCU_SAML22 + +SRC_C += \ + src/portable/microchip/samd/dcd_samd.c \ + $(MCU_DIR)/gcc/gcc/startup_$(SAML_VARIANT).c \ + $(MCU_DIR)/gcc/system_$(SAML_VARIANT).c \ + $(MCU_DIR)/hpl/gclk/hpl_gclk.c \ + $(MCU_DIR)/hpl/mclk/hpl_mclk.c \ + $(MCU_DIR)/hpl/pm/hpl_pm.c \ + $(MCU_DIR)/hpl/osc32kctrl/hpl_osc32kctrl.c \ + $(MCU_DIR)/hpl/oscctrl/hpl_oscctrl.c \ + $(MCU_DIR)/hal/src/hal_atomic.c + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MCU_DIR)/ \ + $(TOP)/$(MCU_DIR)/config \ + $(TOP)/$(MCU_DIR)/include \ + $(TOP)/$(MCU_DIR)/hal/include \ + $(TOP)/$(MCU_DIR)/hal/utils/include \ + $(TOP)/$(MCU_DIR)/hpl/port \ + $(TOP)/$(MCU_DIR)/hri \ + $(TOP)/lib/CMSIS_5/CMSIS/Core/Include + +# For freeRTOS port source +FREERTOS_PORT = ARM_CM0 + +# flash using bossac at least version 1.8 +# can be found in arduino15/packages/arduino/tools/bossac/ +# Add it to your PATH or change BOSSAC variable to match your installation +BOSSAC = bossac + +flash-bossac: $(BUILD)/$(PROJECT).bin + @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0) + $(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R diff --git a/hw/mcu/renesas/rx b/hw/mcu/renesas/rx index 4a51dfe6e..706b4e0cf 160000 --- a/hw/mcu/renesas/rx +++ b/hw/mcu/renesas/rx @@ -1 +1 @@ -Subproject commit 4a51dfe6ecdf936d2d89f223f069e24a2d109207 +Subproject commit 706b4e0cf485605c32351e2f90f5698267996023 diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 761258f1b..16d908a5d 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -37,16 +37,6 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -/* - "KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard - "MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse - "CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control - "SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control - "GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen - "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF - */ typedef struct { uint8_t itf_num; @@ -452,9 +442,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t const data8 = desc_report[0]; - TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; i= 2 diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index 542809899..56ba8bcd1 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -75,7 +75,7 @@ #if CFG_TUSB_DEBUG #include #define _MESS_ERR(_err) tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err]) - #define _MESS_FAILED() tu_printf("%s %d: assert failed\r\n", __func__, __LINE__) + #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) #else #define _MESS_ERR(_err) do {} while (0) #define _MESS_FAILED() do {} while (0) diff --git a/src/device/usbd.c b/src/device/usbd.c index 00ec29c9a..338bff118 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1260,14 +1260,13 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) { - TU_LOG2("OK\r\n"); return true; }else { // DCD error, mark endpoint as ready to allow next transfer _usbd_dev.ep_status[epnum][dir].busy = false; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG2("failed\r\n"); + TU_LOG2("FAILED\r\n"); TU_BREAKPOINT(); return false; } diff --git a/src/host/usbh.c b/src/host/usbh.c index 8ecc87488..bad1aa61a 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -795,6 +795,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r return false; } + TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE); + // Reset device again before Set Address TU_LOG2("Port reset \r\n"); @@ -938,7 +940,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request // Parse configuration & set up drivers // Driver open aren't allowed to make any usb transfer yet - parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); + TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) ); TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM); tusb_control_request_t const new_request = @@ -988,49 +990,54 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura // parse each interfaces while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) { - // skip until we see interface descriptor - if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) - { - p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length - }else - { - tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + // TODO Do we need to use IAD + // tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; - // Check if class is supported - uint8_t drv_id; - for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) - { - if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; - } + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + // desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; + p_desc = tu_desc_next(p_desc); + } - if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + + tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Check if class is supported + uint8_t drv_id; + for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) + { + if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; + } + + if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + { + // skip unsupported class + p_desc = tu_desc_next(p_desc); + } + else + { + usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; + + // Interface number must not be used already TODO alternate interface + TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff ); + dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; + + if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0) { - // skip unsupported class + // TODO Attach hub to Hub is not currently supported + // skip this interface p_desc = tu_desc_next(p_desc); } else { - usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; + TU_LOG2("%s open\r\n", driver->name); - // Interface number must not be used already TODO alternate interface - TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff ); - dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; - - if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0) - { - // TODO Attach hub to Hub is not currently supported - // skip this interface - p_desc = tu_desc_next(p_desc); - } - else - { - TU_LOG2("%s open\r\n", driver->name); - - uint16_t itf_len = 0; - TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) ); - TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); - p_desc += itf_len; - } + uint16_t itf_len = 0; + TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) ); + TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); + p_desc += itf_len; } } } diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c index 53413b6e5..0bdb66fb5 100644 --- a/src/host/usbh_control.c +++ b/src/host/usbh_control.c @@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, _ctrl_xfer.stage = STAGE_SETUP; _ctrl_xfer.complete_cb = complete_cb; - TU_LOG2("Control Setup: "); + TU_LOG2("Control Setup (addr = %u): ", dev_addr); TU_LOG2_VAR(request); TU_LOG2("\r\n"); @@ -119,7 +119,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu if (request->wLength) { - TU_LOG2("Control data:\r\n"); + TU_LOG2("Control data (addr = %u):\r\n", dev_addr); TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2); } diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index b3b2dec2d..5f4fe08ad 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -787,7 +787,7 @@ static bool hfclk_running(void) #ifdef SOFTDEVICE_PRESENT if ( is_sd_enabled() ) { - uint32_t is_running; + uint32_t is_running = 0; (void) sd_clock_hfclk_is_running(&is_running); return (is_running ? true : false); } diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 0048270a6..f78a932f1 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -64,67 +64,48 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr) static void _hw_endpoint_alloc(struct hw_endpoint *ep) { - uint16_t size = tu_min16(64, ep->wMaxPacketSize); + // size must be multiple of 64 + uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; - // Assumes single buffered for now - ep->hw_data_buf = next_buffer_ptr; - next_buffer_ptr += size; - // Bits 0-5 are ignored by the controller so make sure these are 0 - if ((uintptr_t)next_buffer_ptr & 0b111111u) - { - // Round up to the next 64 - uint32_t fixptr = (uintptr_t)next_buffer_ptr; - fixptr &= ~0b111111u; - fixptr += 64; - pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr); - next_buffer_ptr = (uint8_t*)fixptr; - } - assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0); - uint dpram_offset = hw_data_offset(ep->hw_data_buf); - assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); + // double buffered for Control and Bulk endpoint + if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK) + { + size *= 2u; + } - pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n", - size, - dpram_offset, - ep->hw_data_buf, - ep->num, - ep_dir_string[ep->in]); + ep->hw_data_buf = next_buffer_ptr; + next_buffer_ptr += size; - // Fill in endpoint control register with buffer offset - uint32_t reg = EP_CTRL_ENABLE_BITS - | EP_CTRL_INTERRUPT_PER_BUFFER - | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) - | dpram_offset; + assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0); + uint dpram_offset = hw_data_offset(ep->hw_data_buf); + assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); - *ep->endpoint_control = reg; + pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n", + size, + dpram_offset, + ep->hw_data_buf, + tu_edpt_number(ep->ep_addr), + ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + + // Fill in endpoint control register with buffer offset + uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; + + *ep->endpoint_control = reg; } static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { const uint8_t num = tu_edpt_number(ep_addr); const tusb_dir_t dir = tu_edpt_dir(ep_addr); + ep->ep_addr = ep_addr; + // For device, IN is a tx transfer and OUT is an rx transfer ep->rx = (dir == TUSB_DIR_OUT); + // Response to a setup packet on EP0 starts with pid of 1 ep->next_pid = num == 0 ? 1u : 0u; - // Add some checks around the max packet size - if (transfer_type == TUSB_XFER_ISOCHRONOUS) - { - if (wMaxPacketSize > USB_MAX_ISO_PACKET_SIZE) - { - panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize); - } - } - else - { - if (wMaxPacketSize > USB_MAX_PACKET_SIZE) - { - panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize); - } - } - ep->wMaxPacketSize = wMaxPacketSize; ep->transfer_type = transfer_type; @@ -164,6 +145,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t // Now if it hasn't already been done //alloc a buffer and fill in endpoint control register + // TODO device may change configuration (dynamic), should clear and reallocate if(!(ep->configured)) { _hw_endpoint_alloc(ep); @@ -198,10 +180,10 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t b _hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes); } -static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool start) +static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); - _hw_endpoint_xfer(ep, buffer, total_bytes, start); + hw_endpoint_xfer_start(ep, buffer, total_bytes); } static void hw_handle_buff_status(void) @@ -213,19 +195,16 @@ static void hw_handle_buff_status(void) { if (remaining_buffers & bit) { - uint __unused which = (usb_hw->buf_cpu_should_handle & bit) ? 1 : 0; - // Should be single buffered - assert(which == 0); // clear this in advance usb_hw_clear->buf_status = bit; // IN transfer for even i, OUT transfer for odd i struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u)); // Continue xfer - bool done = _hw_endpoint_xfer_continue(ep); + bool done = hw_endpoint_xfer_continue(ep); if (done) { // Notify - dcd_event_xfer_complete(0, ep->ep_addr, ep->len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true); hw_endpoint_reset_transfer(ep); } remaining_buffers &= ~bit; @@ -251,7 +230,7 @@ static void ep0_0len_status(void) { // Send 0len complete response on EP0 IN reset_ep0(); - hw_endpoint_xfer(0x80, NULL, 0, true); + hw_endpoint_xfer(0x80, NULL, 0); } static void _hw_endpoint_stall(struct hw_endpoint *ep) @@ -339,10 +318,7 @@ static void dcd_rp2040_irq(void) #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX // Only run enumeration walk-around if pull up is enabled - if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) - { - rp2040_usb_device_enumeration_fix(); - } + if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix(); #endif } @@ -402,9 +378,9 @@ void dcd_init (uint8_t rhport) // EP0 always exists so init it now // EP0 OUT - hw_endpoint_init(0x0, 64, 0); + hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL); // EP0 IN - hw_endpoint_init(0x80, 64, 0); + hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL); // Initializes the USB peripheral for device mode and enables it. // Don't need to enable the pull up here. Force VBUS @@ -470,23 +446,22 @@ void dcd_connect(uint8_t rhport) void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) { - pico_trace("dcd_edpt0_status_complete %d\n", rhport); - assert(rhport == 0); + (void) rhport; - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) - { - pico_trace("Set HW address %d\n", assigned_address); - usb_hw->dev_addr_ctrl = (uint8_t) request->wValue; - } + if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS ) + { + pico_trace("Set HW address %d\n", request->wValue); + usb_hw->dev_addr_ctrl = (uint8_t) request->wValue; + } - reset_ep0(); + reset_ep0(); } bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) { - pico_info("dcd_edpt_open %d %02x\n", rhport, desc_edpt->bEndpointAddress); + pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress); assert(rhport == 0); hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer); return true; @@ -495,21 +470,20 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { assert(rhport == 0); - // True means start new xfer - hw_endpoint_xfer(ep_addr, buffer, total_bytes, true); + hw_endpoint_xfer(ep_addr, buffer, total_bytes); return true; } void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { - pico_trace("dcd_edpt_stall %d %02x\n", rhport, ep_addr); + pico_trace("dcd_edpt_stall %02x\n", ep_addr); assert(rhport == 0); hw_endpoint_stall(ep_addr); } void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { - pico_trace("dcd_edpt_clear_stall %d %02x\n", rhport, ep_addr); + pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr); assert(rhport == 0); hw_endpoint_clear_stall(ep_addr); } @@ -517,9 +491,11 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { - // usbd.c says: In progress transfers on this EP may be delivered after this call - pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr); + (void) rhport; + (void) ep_addr; + // usbd.c says: In progress transfers on this EP may be delivered after this call + pico_trace("dcd_edpt_close %02x\n", ep_addr); } void dcd_int_handler(uint8_t rhport) diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index b575c6afc..40a0805c6 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -52,46 +53,30 @@ static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, ""); // Host mode uses one shared endpoint register for non-interrupt endpoint -struct hw_endpoint eps[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS]; -#define epx (eps[0]) +static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS]; +#define epx (ep_pool[0]) -#define usb_hw_set hw_set_alias(usb_hw) +#define usb_hw_set hw_set_alias(usb_hw) #define usb_hw_clear hw_clear_alias(usb_hw) -// Used for hcd pipe busy. -// todo still a bit wasteful -// top bit set if valid -uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2]; - // Flags we set by default in sie_ctrl (we add other bits on top) -static uint32_t sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS | - USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | - USB_SIE_CTRL_PULLDOWN_EN_BITS | - USB_SIE_CTRL_EP0_INT_1BUF_BITS; +enum { + SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | + USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS +}; static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) { - uint8_t num = tu_edpt_number(ep_addr); - if (num == 0) { - return &epx; - } - uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0; - uint mapping = dev_ep_map[dev_addr-1][num][in]; - pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping); - return mapping >= 128 ? eps + (mapping & 0x7fu) : NULL; -} + uint8_t num = tu_edpt_number(ep_addr); + if ( num == 0 ) return &epx; -static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep) -{ - uint8_t num = tu_edpt_number(ep_addr); - uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0; - uint32_t index = ep - eps; - hard_assert(index < TU_ARRAY_SIZE(eps)); - // todo revisit why dev_addr can be 0 here - if (dev_addr) { - dev_ep_map[dev_addr-1][num][in] = 128u | index; - } - pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index); + for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ ) + { + struct hw_endpoint *ep = &ep_pool[i]; + if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep; + } + + return NULL; } static inline uint8_t dev_speed(void) @@ -111,15 +96,15 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result) // Mark transfer as done before we tell the tinyusb stack uint8_t dev_addr = ep->dev_addr; uint8_t ep_addr = ep->ep_addr; - uint total_len = ep->total_len; + uint xferred_len = ep->xferred_len; hw_endpoint_reset_transfer(ep); - hcd_event_xfer_complete(dev_addr, ep_addr, total_len, xfer_result, true); + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true); } static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep) { usb_hw_clear->buf_status = bit; - bool done = _hw_endpoint_xfer_continue(ep); + bool done = hw_endpoint_xfer_continue(ep); if (done) { hw_xfer_complete(ep, XFER_RESULT_SUCCESS); @@ -137,6 +122,17 @@ static void hw_handle_buff_status(void) { remaining_buffers &= ~bit; struct hw_endpoint *ep = &epx; + + uint32_t ep_ctrl = *ep->endpoint_control; + if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS) + { + TU_LOG(3, "Double Buffered: "); + }else + { + TU_LOG(3, "Single Buffered: "); + } + TU_LOG_HEX(3, ep_ctrl); + _handle_buff_status_bit(bit, ep); } @@ -153,7 +149,7 @@ static void hw_handle_buff_status(void) if (remaining_buffers & bit) { remaining_buffers &= ~bit; - _handle_buff_status_bit(bit, &eps[i]); + _handle_buff_status_bit(bit, &ep_pool[i]); } } @@ -165,19 +161,19 @@ static void hw_handle_buff_status(void) static void hw_trans_complete(void) { - struct hw_endpoint *ep = &epx; - assert(ep->active); + struct hw_endpoint *ep = &epx; + assert(ep->active); - if (ep->sent_setup) - { - pico_trace("Sent setup packet\n"); - hw_xfer_complete(ep, XFER_RESULT_SUCCESS); - } - else - { - // Don't care. Will handle this in buff status - return; - } + if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS) + { + pico_trace("Sent setup packet\n"); + hw_xfer_complete(ep, XFER_RESULT_SUCCESS); + } + else + { + // Don't care. Will handle this in buff status + return; + } } static void hcd_rp2040_irq(void) @@ -202,20 +198,22 @@ static void hcd_rp2040_irq(void) usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS; } + if (status & USB_INTS_BUFF_STATUS_BITS) + { + handled |= USB_INTS_BUFF_STATUS_BITS; + TU_LOG(2, "Buffer complete\n"); + // print_bufctrl32(*epx.buffer_control); + hw_handle_buff_status(); + } + if (status & USB_INTS_TRANS_COMPLETE_BITS) { handled |= USB_INTS_TRANS_COMPLETE_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS; + TU_LOG(2, "Transfer complete\n"); hw_trans_complete(); } - if (status & USB_INTS_BUFF_STATUS_BITS) - { - handled |= USB_INTS_BUFF_STATUS_BITS; - // print_bufctrl32(*epx.buffer_control); - hw_handle_buff_status(); - } - if (status & USB_INTS_STALL_BITS) { // We have rx'd a stall from the device @@ -234,7 +232,7 @@ static void hcd_rp2040_irq(void) if (status & USB_INTS_ERROR_DATA_SEQ_BITS) { usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS; - // print_bufctrl32(*epx.buffer_control); + print_bufctrl32(*epx.buffer_control); panic("Data Seq Error \n"); } @@ -247,9 +245,9 @@ static void hcd_rp2040_irq(void) static struct hw_endpoint *_next_free_interrupt_ep(void) { struct hw_endpoint *ep = NULL; - for (uint i = 1; i < TU_ARRAY_SIZE(eps); i++) + for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) { - ep = &eps[i]; + ep = &ep_pool[i]; if (!ep->configured) { // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate @@ -263,6 +261,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void) static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) { struct hw_endpoint *ep = NULL; + if (transfer_type == TUSB_XFER_INTERRUPT) { ep = _next_free_interrupt_ep(); @@ -270,11 +269,11 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) assert(ep); ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl; ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl; - // 0x180 for epx - // 0x1c0 for intep0 - // 0x200 for intep1 + // 0 for epx (double buffered): TODO increase to 1024 for ISO + // 2x64 for intep0 + // 3x64 for intep1 // etc - ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 1)]; + ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)]; } else { @@ -283,6 +282,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) ep->endpoint_control = &usbh_dpram->epx_ctrl; ep->hw_data_buf = &usbh_dpram->epx_data[0]; } + return ep; } @@ -303,7 +303,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep->rx = (dir == TUSB_DIR_IN); // Response to a setup packet on EP0 starts with pid of 1 - ep->next_pid = num == 0 ? 1u : 0u; + ep->next_pid = (num == 0 ? 1u : 0u); ep->wMaxPacketSize = wMaxPacketSize; ep->transfer_type = transfer_type; @@ -332,6 +332,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t // preamble uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB); // Assert the interrupt endpoint is IN_TO_HOST + // TODO Interrupt can also be OUT assert(dir == TUSB_DIR_IN); if (need_pre(dev_addr)) @@ -345,24 +346,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t // If it's an interrupt endpoint we need to set up the buffer control // register - } } -static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) -{ - // Allocated differently based on if it's an interrupt endpoint or not - struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); - _hw_endpoint_init(ep, - dev_addr, - ep_desc->bEndpointAddress, - ep_desc->wMaxPacketSize.size, - ep_desc->bmAttributes.xfer, - ep_desc->bInterval); - // Map this struct to ep@device address - set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); -} - //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ @@ -377,11 +363,11 @@ bool hcd_init(uint8_t rhport) irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq); // clear epx and interrupt eps - memset(&eps, 0, sizeof(eps)); + memset(&ep_pool, 0, sizeof(ep_pool)); // Enable in host mode with SOF / Keep alive on usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS; - usb_hw->sie_ctrl = sie_ctrl_base; + usb_hw->sie_ctrl = SIE_CTRL_BASE; usb_hw->inte = USB_INTE_BUFF_STATUS_BITS | USB_INTE_HOST_CONN_DIS_BITS | USB_INTE_HOST_RESUME_BITS | @@ -409,7 +395,6 @@ bool hcd_port_connect_status(uint8_t rhport) tusb_speed_t hcd_port_speed_get(uint8_t rhport) { - pico_trace("hcd_port_speed_get\n"); assert(rhport == 0); // TODO: Should enumval this register switch (dev_speed()) @@ -420,15 +405,25 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) return TUSB_SPEED_FULL; default: panic("Invalid speed\n"); + return TUSB_SPEED_INVALID; } } // Close all opened endpoint belong to this device void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + (void) dev_addr; + pico_trace("hcd_device_close %d\n", dev_addr); } +uint32_t hcd_frame_number(uint8_t rhport) +{ + (void) rhport; + return usb_hw->sof_rd; +} + void hcd_int_enable(uint8_t rhport) { assert(rhport == 0); @@ -442,36 +437,70 @@ void hcd_int_disable(uint8_t rhport) irq_set_enabled(USBCTRL_IRQ, false); } +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) +{ + (void) rhport; + + pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); + + // Allocated differently based on if it's an interrupt endpoint or not + struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); + + _hw_endpoint_init(ep, + dev_addr, + ep_desc->bEndpointAddress, + ep_desc->wMaxPacketSize.size, + ep_desc->bmAttributes.xfer, + ep_desc->bInterval); + + return true; +} + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { - pico_info("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); + (void) rhport; + + pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); + // Get appropriate ep. Either EPX or interrupt endpoint struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr); assert(ep); - if (ep_addr != ep->ep_addr) + // Control endpoint can change direction 0x00 <-> 0x80 + if ( ep_addr != ep->ep_addr ) { - // Direction has flipped so re init it but with same properties - // TODO treat IN and OUT as invidual endpoints - _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); - } + assert(ep_num == 0); - // True indicates this is the start of the transfer - _hw_endpoint_xfer(ep, buffer, buflen, true); + // Direction has flipped on endpoint control so re init it but with same properties + _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); + } // If a normal transfer (non-interrupt) then initiate using // sie ctrl registers. Otherwise interrupt ep registers should // already be configured if (ep == &epx) { + hw_endpoint_xfer_start(ep, buffer, buflen); + // That has set up buffer control, endpoint control etc // for host we have to initiate the transfer - usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB); - uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base; - flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS; + usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB); + + uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE | + (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS); // Set pre if we are a low speed device on full speed hub flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; + usb_hw->sie_ctrl = flags; + }else + { + hw_endpoint_xfer_start(ep, buffer, buflen); } return true; @@ -479,41 +508,33 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { - pico_info("hcd_setup_send dev_addr %d\n", dev_addr); - + (void) rhport; + // Copy data into setup packet buffer memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8); // Configure EP0 struct with setup info for the trans complete struct hw_endpoint *ep = _hw_endpoint_allocate(0); + // EP0 out _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0); assert(ep->configured); - ep->total_len = 8; - ep->transfer_size = 8; - ep->active = true; - ep->sent_setup = true; + + ep->remaining_len = 8; + ep->active = true; // Set device address usb_hw->dev_addr_ctrl = dev_addr; + // Set pre if we are a low speed device on full speed hub - uint32_t flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS; - flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; + uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS | + (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0); + usb_hw->sie_ctrl = flags; + return true; } -uint32_t hcd_frame_number(uint8_t rhport) -{ - return usb_hw->sof_rd; -} - -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) -{ - pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); - hw_endpoint_init(dev_addr, ep_desc); - return true; -} //bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) //{ @@ -531,6 +552,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) { + (void) dev_addr; + (void) ep_addr; + panic("hcd_clear_stall"); return true; } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 31381e6c2..dc12e6d82 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,42 +44,38 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) { // sense to have worker and IRQ on same core, however I think using critsec is about equivalent. } -#if TUSB_OPT_HOST_ENABLED -static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep) -{ - ep->last_buf = (ep->len + ep->transfer_size == ep->total_len); -} -#endif +static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); +static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ void rp2040_usb_init(void) { - // Reset usb controller - reset_block(RESETS_RESET_USBCTRL_BITS); - unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + // Reset usb controller + reset_block(RESETS_RESET_USBCTRL_BITS); + unreset_block_wait(RESETS_RESET_USBCTRL_BITS); - // Clear any previous state just in case - memset(usb_hw, 0, sizeof(*usb_hw)); - memset(usb_dpram, 0, sizeof(*usb_dpram)); + // Clear any previous state just in case + memset(usb_hw, 0, sizeof(*usb_hw)); + memset(usb_dpram, 0, sizeof(*usb_dpram)); - // Mux the controller to the onboard usb phy - usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; + // Mux the controller to the onboard usb phy + usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; - // Force VBUS detect so the device thinks it is plugged into a host - // TODO support VBUs detect - usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; + // Force VBUS detect so the device thinks it is plugged into a host + // TODO support VBUs detect + usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; } void hw_endpoint_reset_transfer(struct hw_endpoint *ep) { - ep->stalled = false; - ep->active = false; -#if TUSB_OPT_HOST_ENABLED - ep->sent_setup = false; -#endif - ep->total_len = 0; - ep->len = 0; - ep->transfer_size = 0; - ep->user_buf = 0; + ep->stalled = false; + ep->active = false; + ep->remaining_len = 0; + ep->xferred_len = 0; + ep->user_buf = 0; } void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) { @@ -111,215 +108,223 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) +// prepare buffer, return buffer control +static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) { - // Prepare buffer control register value - uint32_t val = ep->transfer_size | USB_BUF_CTRL_AVAIL; + uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); + ep->remaining_len -= buflen; - if (!ep->rx) + uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL; + + // PID + buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; + ep->next_pid ^= 1u; + + if ( !ep->rx ) + { + // Copy data from user buffer to hw buffer + memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen); + ep->user_buf += buflen; + + // Mark as full + buf_ctrl |= USB_BUF_CTRL_FULL; + } + + // Is this the last buffer? Only really matters for host mode. Will trigger + // the trans complete irq but also stop it polling. We only really care about + // trans complete for setup packets being sent + if (ep->remaining_len == 0) + { + buf_ctrl |= USB_BUF_CTRL_LAST; + } + + if (buf_id) buf_ctrl = buf_ctrl << 16; + + return buf_ctrl; +} + +// Prepare buffer control register value +static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) +{ + uint32_t ep_ctrl = *ep->endpoint_control; + + // always compute and start with buffer 0 + uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL; + + // For now: skip double buffered for Device mode, OUT endpoint since + // host could send < 64 bytes and cause short packet on buffer0 + // NOTE this could happen to Host mode IN endpoint + bool const force_single = !(usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) && !tu_edpt_dir(ep->ep_addr); + + if(ep->remaining_len && !force_single) + { + // Use buffer 1 (double buffered) if there is still data + // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) + + buf_ctrl |= prepare_ep_buffer(ep, 1); + + // Set endpoint control double buffered bit if needed + ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; + ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; + }else + { + // Single buffered since 1 is enough + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + } + + *ep->endpoint_control = ep_ctrl; + + TU_LOG(3, "Prepare Buffer Control:\r\n"); + print_bufctrl32(buf_ctrl); + + // Finally, write to buffer_control which will trigger the transfer + // the next time the controller polls this dpram address + _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); +} + +void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) +{ + _hw_endpoint_lock_update(ep, 1); + + if ( ep->active ) + { + // TODO: Is this acceptable for interrupt packets? + TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), + ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + + hw_endpoint_reset_transfer(ep); + } + + // Fill in info now that we're kicking off the hw + ep->remaining_len = total_len; + ep->xferred_len = 0; + ep->active = true; + ep->user_buf = buffer; + + _hw_endpoint_start_next_buffer(ep); + _hw_endpoint_lock_update(ep, -1); +} + +// sync endpoint buffer and return transferred bytes +static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) +{ + uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + if (buf_id) buf_ctrl = buf_ctrl >> 16; + + uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; + + if ( !ep->rx ) + { + // We are continuing a transfer here. If we are TX, we have successfully + // sent some data can increase the length we have sent + assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); + + ep->xferred_len += xferred_bytes; + }else + { + // If we have received some data, so can increase the length + // we have received AFTER we have copied it to the user buffer at the appropriate offset + assert(buf_ctrl & USB_BUF_CTRL_FULL); + + memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes); + ep->xferred_len += xferred_bytes; + ep->user_buf += xferred_bytes; + } + + // Short packet + if (xferred_bytes < ep->wMaxPacketSize) + { + pico_trace("Short rx transfer on buffer %d with %u bytes\n", buf_id, xferred_bytes); + // Reduce total length as this is last packet + ep->remaining_len = 0; + } + + return xferred_bytes; +} + +static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) +{ + // Update hw endpoint struct with info from hardware + // after a buff status interrupt + + uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + TU_LOG(3, "_hw_endpoint_xfer_sync:\r\n"); + print_bufctrl32(buf_ctrl); + + // always sync buffer 0 + uint16_t buf0_bytes = sync_ep_buffer(ep, 0); + + // sync buffer 1 if double buffered + if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) + { + if (buf0_bytes == ep->wMaxPacketSize) { - // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, &ep->user_buf[ep->len], ep->transfer_size); - // Mark as full - val |= USB_BUF_CTRL_FULL; - } - - // PID - val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; - -#if TUSB_OPT_DEVICE_ENABLED - ep->next_pid ^= 1u; - -#else - // For Host (also device but since we dictate the endpoint size, following scenario does not occur) - // Next PID depends on the number of packet in case wMaxPacketSize < 64 (e.g Interrupt Endpoint 8, or 12) - // Special case with control status stage where PID is always DATA1 - if ( ep->transfer_size == 0 ) - { - // ZLP also toggle data - ep->next_pid ^= 1u; + // sync buffer 1 if not short packet + sync_ep_buffer(ep, 1); }else { - uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize); + // short packet on buffer 0 + // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example + // At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from + // the next transfer (not current one). For now we disable double buffered for device OUT + // NOTE this could happen to Host IN +#if 0 + uint8_t const ep_num = tu_edpt_number(ep->ep_addr); + uint8_t const dir = (uint8_t) tu_edpt_dir(ep->ep_addr); + uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1); - if ( packet_count & 0x01 ) - { - ep->next_pid ^= 1u; - } - } + // abort queued transfer on buffer 1 + usb_hw->abort |= TU_BIT(ep_id); + + while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {} + + uint32_t ep_ctrl = *ep->endpoint_control; + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + + _hw_endpoint_buffer_control_set_value32(ep, 0); + + usb_hw->abort &= ~TU_BIT(ep_id); + + TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr); + print_bufctrl32(buf_ctrl); #endif - - -#if TUSB_OPT_HOST_ENABLED - // Is this the last buffer? Only really matters for host mode. Will trigger - // the trans complete irq but also stop it polling. We only really care about - // trans complete for setup packets being sent - if (ep->last_buf) - { - pico_trace("Last buf (%d bytes left)\n", ep->transfer_size); - val |= USB_BUF_CTRL_LAST; - } -#endif - - // Finally, write to buffer_control which will trigger the transfer - // the next time the controller polls this dpram address - _hw_endpoint_buffer_control_set_value32(ep, val); - pico_trace("buffer control (0x%p) <- 0x%x\n", ep->buffer_control, val); - //print_bufctrl16(val); -} - - -void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) -{ - _hw_endpoint_lock_update(ep, 1); - pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - if (ep->active) - { - // TODO: Is this acceptable for interrupt packets? - pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - - hw_endpoint_reset_transfer(ep); - } - - // Fill in info now that we're kicking off the hw - ep->total_len = total_len; - ep->len = 0; - - // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0) - ep->transfer_size = tu_min16(total_len, tu_max16(64, ep->wMaxPacketSize)); - - ep->active = true; - ep->user_buf = buffer; -#if TUSB_OPT_HOST_ENABLED - // Recalculate if this is the last buffer - _hw_endpoint_update_last_buf(ep); - ep->buf_sel = 0; -#endif - - _hw_endpoint_start_next_buffer(ep); - _hw_endpoint_lock_update(ep, -1); -} - -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep) -{ - // Update hw endpoint struct with info from hardware - // after a buff status interrupt - - uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); - -#if TUSB_OPT_HOST_ENABLED - // RP2040-E4 - // tag::host_buf_sel_fix[] - // TODO need changes to support double buffering - if (ep->buf_sel == 1) - { - // Host can erroneously write status to top half of buf_ctrl register - buf_ctrl = buf_ctrl >> 16; - - // update buf1 -> buf0 to prevent panic with "already available" - *ep->buffer_control = buf_ctrl; - } - // Flip buf sel for host - ep->buf_sel ^= 1u; - // end::host_buf_sel_fix[] -#endif - - // Get tranferred bytes after adjusted buf sel - uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; - - // We are continuing a transfer here. If we are TX, we have successfullly - // sent some data can increase the length we have sent - if (!ep->rx) - { - assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); - pico_trace("tx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl); - ep->len += transferred_bytes; - } - else - { - // If we are OUT we have recieved some data, so can increase the length - // we have recieved AFTER we have copied it to the user buffer at the appropriate - // offset - pico_trace("rx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl); - assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, transferred_bytes); - ep->len += transferred_bytes; - } - - // Sometimes the host will send less data than we expect... - // If this is a short out transfer update the total length of the transfer - // to be the current length - if ((ep->rx) && (transferred_bytes < ep->wMaxPacketSize)) - { - pico_trace("Short rx transfer\n"); - // Reduce total length as this is last packet - ep->total_len = ep->len; } + } } // Returns true if transfer is complete -bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep) +bool hw_endpoint_xfer_continue(struct hw_endpoint *ep) { - _hw_endpoint_lock_update(ep, 1); - // Part way through a transfer - if (!ep->active) - { - panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string); - } + _hw_endpoint_lock_update(ep, 1); + // Part way through a transfer + if (!ep->active) + { + panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string); + } - // Update EP struct from hardware state - _hw_endpoint_xfer_sync(ep); - - // Now we have synced our state with the hardware. Is there more data to transfer? - // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0) - uint16_t remaining_bytes = ep->total_len - ep->len; - ep->transfer_size = tu_min16(remaining_bytes, tu_max16(64, ep->wMaxPacketSize)); -#if TUSB_OPT_HOST_ENABLED - _hw_endpoint_update_last_buf(ep); -#endif - - // Can happen because of programmer error so check for it - if (ep->len > ep->total_len) - { - panic("Transferred more data than expected"); - } - - // If we are done then notify tinyusb - if (ep->len == ep->total_len) - { - pico_trace("Completed transfer of %d bytes on ep %d %s\n", - ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - // Notify caller we are done so it can notify the tinyusb stack - _hw_endpoint_lock_update(ep, -1); - return true; - } - else - { - _hw_endpoint_start_next_buffer(ep); - } + // Update EP struct from hardware state + _hw_endpoint_xfer_sync(ep); + // Now we have synced our state with the hardware. Is there more data to transfer? + // If we are done then notify tinyusb + if (ep->remaining_len == 0) + { + pico_trace("Completed transfer of %d bytes on ep %d %s\n", + ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + // Notify caller we are done so it can notify the tinyusb stack _hw_endpoint_lock_update(ep, -1); - // More work to do - return false; -} + return true; + } + else + { + _hw_endpoint_start_next_buffer(ep); + } -void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start) -{ - // Trace - pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - pico_trace(" total_len %d, start=%d\n", total_len, start); - - assert(ep->configured); - - - if (start) - { - _hw_endpoint_xfer_start(ep, buffer, total_len); - } - else - { - _hw_endpoint_xfer_continue(ep); - } + _hw_endpoint_lock_update(ep, -1); + // More work to do + return false; } #endif diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 33f3ecd41..514152cd9 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -17,23 +17,8 @@ #endif -#if false && !defined(NDEBUG) -#define pico_trace(format,args...) printf(format, ## args) -#else -#define pico_trace(format,...) ((void)0) -#endif - -#if false && !defined(NDEBUG) -#define pico_info(format,args...) printf(format, ## args) -#else -#define pico_info(format,...) ((void)0) -#endif - -#if false && !defined(NDEBUG) -#define pico_warn(format,args...) printf(format, ## args) -#else -#define pico_warn(format,...) ((void)0) -#endif +#define pico_info(...) TU_LOG(2, __VA_ARGS__) +#define pico_trace(...) TU_LOG(3, __VA_ARGS__) // Hardware information per endpoint struct hw_endpoint @@ -50,6 +35,7 @@ struct hw_endpoint // Endpoint control register io_rw_32 *endpoint_control; + // Buffer control register io_rw_32 *buffer_control; @@ -61,27 +47,22 @@ struct hw_endpoint // Current transfer information bool active; - uint16_t total_len; - uint16_t len; - // Amount of data with the hardware - uint16_t transfer_size; + uint16_t remaining_len; + uint16_t xferred_len; + // User buffer in main memory uint8_t *user_buf; // Data needed from EP descriptor uint16_t wMaxPacketSize; + // Interrupt, bulk, etc uint8_t transfer_type; #if TUSB_OPT_HOST_ENABLED - // Only needed for host mode - bool last_buf; - // RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer - // control register when doing transfers > 1 packet - uint8_t buf_sel; // Only needed for host uint8_t dev_addr; - bool sent_setup; + // If interrupt endpoint uint8_t interrupt_num; #endif @@ -89,12 +70,10 @@ struct hw_endpoint void rp2040_usb_init(void); +void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); +bool hw_endpoint_xfer_continue(struct hw_endpoint *ep); void hw_endpoint_reset_transfer(struct hw_endpoint *ep); -void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start); -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); -void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); -bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep); + void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask); static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) { return *ep->buffer_control; @@ -134,14 +113,15 @@ typedef union TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(rp2040_buffer_control_t) == 2, "size is not correct"); -static inline void print_bufctrl16(uint32_t __unused u16) +#if CFG_TUSB_DEBUG >= 3 +static inline void print_bufctrl16(uint32_t u16) { - rp2040_buffer_control_t __unused bufctrl = { + rp2040_buffer_control_t bufctrl = { .u16 = u16 }; - TU_LOG(2, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n", - bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full); + TU_LOG(3, "len = %u, available = %u, full = %u, last = %u, stall = %u, reset = %u, toggle = %u\r\n", + bufctrl.xfer_len, bufctrl.available, bufctrl.full, bufctrl.last_buf, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle); } static inline void print_bufctrl32(uint32_t u32) @@ -149,12 +129,19 @@ static inline void print_bufctrl32(uint32_t u32) uint16_t u16; u16 = u32 >> 16; - TU_LOG(2, "Buffer Control 1 0x%x: ", u16); + TU_LOG(3, " Buffer Control 1 0x%x: ", u16); print_bufctrl16(u16); u16 = u32 & 0x0000ffff; - TU_LOG(2, "Buffer Control 0 0x%x: ", u16); + TU_LOG(3, " Buffer Control 0 0x%x: ", u16); print_bufctrl16(u16); } +#else + +#define print_bufctrl16(u16) +#define print_bufctrl32(u32) + +#endif + #endif diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c index 51729de06..bb4a08e2b 100644 --- a/src/portable/renesas/usba/dcd_usba.c +++ b/src/portable/renesas/usba/dcd_usba.c @@ -26,8 +26,13 @@ #include "tusb_option.h" +<<<<<<< HEAD #if TUSB_OPT_DEVICE_ENABLED && (( CFG_TUSB_MCU == OPT_MCU_RX63X ) || ( CFG_TUSB_MCU == OPT_MCU_RX72N )) +======= +#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \ + CFG_TUSB_MCU == OPT_MCU_RX65X) +>>>>>>> origin/master #include "device/dcd.h" #include "iodefine.h" diff --git a/src/tusb_option.h b/src/tusb_option.h index bf2ca4d69..2a68dcbc1 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -113,7 +113,11 @@ // Renesas RX #define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631 +<<<<<<< HEAD #define OPT_MCU_RX72N 1401 ///< Renesas RX72N +======= +#define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651 +>>>>>>> origin/master // Mind Motion #define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327