Merge branch 'master' into nuc121

This commit is contained in:
Ha Thach 2020-01-07 16:26:58 +07:00 committed by GitHub
commit 130250a2be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1674 additions and 529 deletions

54
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Build
on: [pull_request, push]
jobs:
unit-test:
runs-on: ubuntu-latest
steps:
- name: Setup Ruby
uses: actions/setup-ruby@v1.0.0
- name: Checkout TinyUSB
uses: actions/checkout@v2
- name: Unit Tests
run: |
# Install Ceedling
gem install ceedling
cd test
ceedling test:all
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example: ['board_test', 'cdc_msc', 'dfu_rt', 'hid_composite', 'hid_generic_inout', 'midi_test', 'msc_dual_lun', 'usbtmc', 'webusb_serial']
steps:
- name: Setup Python
uses: actions/setup-python@v1
- name: Setup Node.js
uses: actions/setup-node@v1.1.0
- name: Install Toolchains
run: |
npm install --global xpm
xpm install --global @xpack-dev-tools/arm-none-eabi-gcc@latest
xpm install --global @xpack-dev-tools/riscv-none-embed-gcc@latest
echo "::add-path::`echo $HOME/opt/xPacks/@xpack-dev-tools/arm-none-eabi-gcc/*/.content/bin`"
echo "::add-path::`echo $HOME/opt/xPacks/@xpack-dev-tools/riscv-none-embed-gcc/*/.content/bin`"
- name: Checkout TinyUSB
uses: actions/checkout@v2
- name: Checkout submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive
- name: Build
run: python3 tools/build_all.py ${{ matrix.example }}

8
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "hw/mcu/nordic/nrfx"] [submodule "hw/mcu/nordic/nrfx"]
path = hw/mcu/nordic/nrfx path = hw/mcu/nordic/nrfx
url = https://github.com/NordicSemiconductor/nrfx.git url = https://github.com/NordicSemiconductor/nrfx.git
[submodule "hw/mcu/microchip/samd/asf4"]
path = hw/mcu/microchip/samd/asf4
url = https://github.com/adafruit/asf4.git
[submodule "tools/uf2"] [submodule "tools/uf2"]
path = tools/uf2 path = tools/uf2
url = https://github.com/microsoft/uf2.git url = https://github.com/microsoft/uf2.git
@ -19,6 +16,9 @@
[submodule "hw/mcu/nxp"] [submodule "hw/mcu/nxp"]
path = hw/mcu/nxp path = hw/mcu/nxp
url = https://github.com/hathach/nxp_driver.git url = https://github.com/hathach/nxp_driver.git
[submodule "hw/mcu/microchip"]
path = hw/mcu/microchip
url = https://github.com/hathach/microchip_driver.git
[submodule "hw/mcu/nuvoton"] [submodule "hw/mcu/nuvoton"]
path = hw/mcu/nuvoton path = hw/mcu/nuvoton
url = https://github.com/majbthrd/nuc_driver.git url = https://github.com/majbthrd/nuc_driver.git

View File

@ -2,7 +2,7 @@
![tinyUSB_240x100](https://user-images.githubusercontent.com/249515/62646655-f9393200-b978-11e9-9c53-484862f15503.png) ![tinyUSB_240x100](https://user-images.githubusercontent.com/249515/62646655-f9393200-b978-11e9-9c53-484862f15503.png)
[![Build Status](https://travis-ci.org/hathach/tinyusb.svg?branch=master)](https://travis-ci.org/hathach/tinyusb) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://github.com/hathach/tinyusb/workflows/Build/badge.svg)](https://travis-ci.org/hathach/tinyusb) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Coverity](https://img.shields.io/coverity/scan/458.svg)](https://scan.coverity.com/projects/tinyusb)
TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function. TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function.

View File

@ -86,12 +86,32 @@ enum
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
// Note: since CDC EP ( 1 & 2), HID (4) are spot-on, thus we only need to force #define EPNUM_CDC_NOTIF 0x81
// endpoint number for MSC to 5 #define EPNUM_CDC_OUT 0x02
#define EPNUM_MSC 0x05 #define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG
// SAMG doesn't support a same endpoint number with IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else #else
#define EPNUM_MSC 0x03 #define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif #endif
uint8_t const desc_configuration[] = uint8_t const desc_configuration[] =
@ -100,10 +120,10 @@ uint8_t const desc_configuration[] =
TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size. // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, 0x02, 0x82, 64), TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size // Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC, 0x80 | EPNUM_MSC, (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64), TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64),
}; };

View File

@ -12,7 +12,7 @@ $ cd tinyusb
TinyUSB examples includes external repos aka submodules to provide low-level MCU peripheral's driver to compile with. Therefore we will firstly fetch those mcu driver repo by running this command in the top folder repo TinyUSB examples includes external repos aka submodules to provide low-level MCU peripheral's driver to compile with. Therefore we will firstly fetch those mcu driver repo by running this command in the top folder repo
``` ```
$ git submodule update --init --rescursive $ git submodule update --init --recursive
``` ```
It will takes a bit of time due to the number of supported MCUs, luckily we only need to do this once. It will takes a bit of time due to the number of supported MCUs, luckily we only need to do this once.

View File

@ -31,7 +31,7 @@ INC += \
# For TinyUSB port source # For TinyUSB port source
VENDOR = microchip VENDOR = microchip
CHIP_FAMILY = samd21 CHIP_FAMILY = samd
# For freeRTOS port source # For freeRTOS port source
FREERTOS_PORT = ARM_CM0 FREERTOS_PORT = ARM_CM0

View File

@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack. * This file is part of the TinyUSB stack.
*/ */
#include "sam.h"
#include "bsp/board.h" #include "bsp/board.h"
#include "sam.h"
#include "hal/include/hal_gpio.h" #include "hal/include/hal_gpio.h"
#include "hal/include/hal_init.h" #include "hal/include/hal_init.h"
#include "hri/hri_nvmctrl_d21.h" #include "hri/hri_nvmctrl_d21.h"

View File

@ -32,7 +32,7 @@ INC += \
# For TinyUSB port source # For TinyUSB port source
VENDOR = microchip VENDOR = microchip
CHIP_FAMILY = samd21 CHIP_FAMILY = samd
# For freeRTOS port source # For freeRTOS port source
FREERTOS_PORT = ARM_CM0 FREERTOS_PORT = ARM_CM0

View File

@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack. * This file is part of the TinyUSB stack.
*/ */
#include "sam.h"
#include "bsp/board.h" #include "bsp/board.h"
#include "sam.h"
#include "hal/include/hal_gpio.h" #include "hal/include/hal_gpio.h"
#include "hal/include/hal_init.h" #include "hal/include/hal_init.h"
#include "hri/hri_nvmctrl_d21.h" #include "hri/hri_nvmctrl_d21.h"

View File

@ -35,7 +35,7 @@ INC += \
# For TinyUSB port source # For TinyUSB port source
VENDOR = microchip VENDOR = microchip
CHIP_FAMILY = samd51 CHIP_FAMILY = samd
# For freeRTOS port source # For freeRTOS port source
FREERTOS_PORT = ARM_CM4F FREERTOS_PORT = ARM_CM4F

View File

@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack. * This file is part of the TinyUSB stack.
*/ */
#include "sam.h"
#include "bsp/board.h" #include "bsp/board.h"
#include "sam.h"
#include "hal/include/hal_gpio.h" #include "hal/include/hal_gpio.h"
#include "hal/include/hal_init.h" #include "hal/include/hal_init.h"
#include "hpl/gclk/hpl_gclk_base.h" #include "hpl/gclk/hpl_gclk_base.h"

View File

@ -32,7 +32,7 @@ INC += \
# For TinyUSB port source # For TinyUSB port source
VENDOR = microchip VENDOR = microchip
CHIP_FAMILY = samd21 CHIP_FAMILY = samd
# For freeRTOS port source # For freeRTOS port source
FREERTOS_PORT = ARM_CM0 FREERTOS_PORT = ARM_CM0

View File

@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack. * This file is part of the TinyUSB stack.
*/ */
#include "sam.h"
#include "bsp/board.h" #include "bsp/board.h"
#include "sam.h"
#include "hal/include/hal_gpio.h" #include "hal/include/hal_gpio.h"
#include "hal/include/hal_init.h" #include "hal/include/hal_init.h"
#include "hri/hri_nvmctrl_d21.h" #include "hri/hri_nvmctrl_d21.h"

View File

@ -35,7 +35,7 @@ INC += \
# For TinyUSB port source # For TinyUSB port source
VENDOR = microchip VENDOR = microchip
CHIP_FAMILY = samd51 CHIP_FAMILY = samd
# For freeRTOS port source # For freeRTOS port source
FREERTOS_PORT = ARM_CM4F FREERTOS_PORT = ARM_CM4F

View File

@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack. * This file is part of the TinyUSB stack.
*/ */
#include "sam.h"
#include "bsp/board.h" #include "bsp/board.h"
#include "sam.h"
#include "hal/include/hal_gpio.h" #include "hal/include/hal_gpio.h"
#include "hal/include/hal_init.h" #include "hal/include/hal_init.h"
#include "hpl/gclk/hpl_gclk_base.h" #include "hpl/gclk/hpl_gclk_base.h"

View File

@ -11,7 +11,8 @@ CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX
# mcu driver cause following warnings # mcu driver cause following warnings
CFLAGS += -Wno-error=unused-parameter -Wno-error=implicit-fallthrough= # CFLAGS += -Wno-error=unused-parameter -Wno-error=implicit-fallthrough=
CFLAGS += -Wno-error=unused-parameter
MCU_DIR = hw/mcu/nxp/sdk/devices/MIMXRT1011 MCU_DIR = hw/mcu/nxp/sdk/devices/MIMXRT1011

View File

@ -0,0 +1,53 @@
CFLAGS += \
-flto \
-mthumb \
-mabi=aapcs \
-mcpu=cortex-m4 \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-nostdlib -nostartfiles \
-D__SAMG55J19__ \
-DCFG_TUSB_MCU=OPT_MCU_SAMG
#CFLAGS += -Wno-error=undef
ASF_DIR = hw/mcu/microchip/samg55
# All source paths should be relative to the top level.
LD_FILE = hw/bsp/$(BOARD)/samg55j19_flash.ld
SRC_C += \
$(ASF_DIR)/samg55/gcc/gcc/startup_samg55j19.c \
$(ASF_DIR)/samg55/gcc/system_samg55j19.c \
$(ASF_DIR)/hpl/core/hpl_init.c \
$(ASF_DIR)/hpl/usart/hpl_usart.c \
$(ASF_DIR)/hpl/pmc/hpl_pmc.c \
$(ASF_DIR)/hal/src/hal_atomic.c
INC += \
$(TOP)/hw/bsp/$(BOARD) \
$(TOP)/$(ASF_DIR) \
$(TOP)/$(ASF_DIR)/config \
$(TOP)/$(ASF_DIR)/samg55/include \
$(TOP)/$(ASF_DIR)/hal/include \
$(TOP)/$(ASF_DIR)/hal/utils/include \
$(TOP)/$(ASF_DIR)/hpl/core \
$(TOP)/$(ASF_DIR)/hpl/pio \
$(TOP)/$(ASF_DIR)/hpl/pmc \
$(TOP)/$(ASF_DIR)/hri \
$(TOP)/$(ASF_DIR)/CMSIS/Core/Include
# For TinyUSB port source
VENDOR = microchip
CHIP_FAMILY = samg
# For freeRTOS port source
FREERTOS_PORT = ARM_CM4F
# For flash-jlink target
JLINK_DEVICE = ATSAMD51J19
JLINK_IF = swd
# flash using edbg from https://github.com/ataradov/edbg
flash: $(BUILD)/$(BOARD)-firmware.bin
edbg --verbose -t samg55 -pv -f $<

View File

@ -0,0 +1,215 @@
/* Auto-generated config file hpl_usart_config.h */
#ifndef HPL_USART_CONFIG_H
#define HPL_USART_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
#include <peripheral_clk_config.h>
#ifndef CONF_USART_7_ENABLE
#define CONF_USART_7_ENABLE 1
#endif
// <h> Basic Configuration
// <o> Frame parity
// <0x0=>Even parity
// <0x1=>Odd parity
// <0x2=>Parity forced to 0
// <0x3=>Parity forced to 1
// <0x4=>No parity
// <i> Parity bit mode for USART frame
// <id> usart_parity
#ifndef CONF_USART_7_PARITY
#define CONF_USART_7_PARITY 0x4
#endif
// <o> Character Size
// <0x0=>5 bits
// <0x1=>6 bits
// <0x2=>7 bits
// <0x3=>8 bits
// <i> Data character size in USART frame
// <id> usart_character_size
#ifndef CONF_USART_7_CHSIZE
#define CONF_USART_7_CHSIZE 0x3
#endif
// <o> Stop Bit
// <0=>1 stop bit
// <1=>1.5 stop bits
// <2=>2 stop bits
// <i> Number of stop bits in USART frame
// <id> usart_stop_bit
#ifndef CONF_USART_7_SBMODE
#define CONF_USART_7_SBMODE 0
#endif
// <o> Clock Output Select
// <0=>The USART does not drive the SCK pin
// <1=>The USART drives the SCK pin if USCLKS does not select the external clock SCK
// <i> Clock Output Select in USART sck, if in usrt master mode, please drive SCK.
// <id> usart_clock_output_select
#ifndef CONF_USART_7_CLKO
#define CONF_USART_7_CLKO 0
#endif
// <o> Baud rate <1-3000000>
// <i> USART baud rate setting
// <id> usart_baud_rate
#ifndef CONF_USART_7_BAUD
#define CONF_USART_7_BAUD 9600
#endif
// </h>
// <e> Advanced configuration
// <id> usart_advanced
#ifndef CONF_USART_7_ADVANCED_CONFIG
#define CONF_USART_7_ADVANCED_CONFIG 0
#endif
// <o> Channel Mode
// <0=>Normal Mode
// <1=>Automatic Echo
// <2=>Local Loopback
// <3=>Remote Loopback
// <i> Channel mode in USART frame
// <id> usart_channel_mode
#ifndef CONF_USART_7_CHMODE
#define CONF_USART_7_CHMODE 0
#endif
// <q> 9 bits character enable
// <i> Enable 9 bits character, this has high priority than 5/6/7/8 bits.
// <id> usart_9bits_enable
#ifndef CONF_USART_7_MODE9
#define CONF_USART_7_MODE9 0
#endif
// <o> Variable Sync
// <0=>User defined configuration
// <1=>sync field is updated when a character is written into US_THR
// <i> Variable Synchronization of Command/Data Sync Start Frarm Delimiter
// <id> variable_sync
#ifndef CONF_USART_7_VAR_SYNC
#define CONF_USART_7_VAR_SYNC 0
#endif
// <o> Oversampling Mode
// <0=>16 Oversampling
// <1=>8 Oversampling
// <i> Oversampling Mode in UART mode
// <id> usart__oversampling_mode
#ifndef CONF_USART_7_OVER
#define CONF_USART_7_OVER 0
#endif
// <o> Inhibit Non Ack
// <0=>The NACK is generated
// <1=>The NACK is not generated
// <i> Inhibit Non Acknowledge
// <id> usart__inack
#ifndef CONF_USART_7_INACK
#define CONF_USART_7_INACK 1
#endif
// <o> Disable Successive NACK
// <0=>NACK is sent on the ISO line as soon as a parity error occurs
// <1=>Many parity errors generate a NACK on the ISO line
// <i> Disable Successive NACK
// <id> usart_dsnack
#ifndef CONF_USART_7_DSNACK
#define CONF_USART_7_DSNACK 0
#endif
// <o> Inverted Data
// <0=>Data isn't inverted, nomal mode
// <1=>Data is inverted
// <i> Inverted Data
// <id> usart_invdata
#ifndef CONF_USART_7_INVDATA
#define CONF_USART_7_INVDATA 0
#endif
// <o> Maximum Number of Automatic Iteration <0-7>
// <i> Defines the maximum number of iterations in mode ISO7816, protocol T = 0.
// <id> usart_max_iteration
#ifndef CONF_USART_7_MAX_ITERATION
#define CONF_USART_7_MAX_ITERATION 0
#endif
// <q> Receive Line Filter enable
// <i> whether the USART filters the receive line using a three-sample filter
// <id> usart_receive_filter_enable
#ifndef CONF_USART_7_FILTER
#define CONF_USART_7_FILTER 0
#endif
// <q> Manchester Encoder/Decoder Enable
// <i> whether the USART Manchester Encoder/Decoder
// <id> usart_manchester_filter_enable
#ifndef CONF_USART_7_MAN
#define CONF_USART_7_MAN 0
#endif
// <o> Manchester Synchronization Mode
// <0=>The Manchester start bit is a 0 to 1 transition
// <1=>The Manchester start bit is a 1 to 0 transition
// <i> Manchester Synchronization Mode
// <id> usart_manchester_synchronization_mode
#ifndef CONF_USART_7_MODSYNC
#define CONF_USART_7_MODSYNC 0
#endif
// <o> Start Frame Delimiter Selector
// <0=>Start frame delimiter is COMMAND or DATA SYNC
// <1=>Start frame delimiter is one bit
// <i> Start Frame Delimiter Selector
// <id> usart_start_frame_delimiter
#ifndef CONF_USART_7_ONEBIT
#define CONF_USART_7_ONEBIT 0
#endif
// <o> Fractional Part <0-7>
// <i> Fractional part of the baud rate if baud rate generator is in fractional mode
// <id> usart_arch_fractional
#ifndef CONF_USART_7_FRACTIONAL
#define CONF_USART_7_FRACTIONAL 0x0
#endif
// <o> Data Order
// <0=>LSB is transmitted first
// <1=>MSB is transmitted first
// <i> Data order of the data bits in the frame
// <id> usart_arch_msbf
#ifndef CONF_USART_7_MSBF
#define CONF_USART_7_MSBF 0
#endif
// </e>
#define CONF_USART_7_MODE 0x0
// Calculate BAUD register value in UART mode
#if CONF_FLEXCOM7_CK_SRC < 3
#ifndef CONF_USART_7_BAUD_CD
#define CONF_USART_7_BAUD_CD ((CONF_FLEXCOM7_FREQUENCY) / CONF_USART_7_BAUD / 8 / (2 - CONF_USART_7_OVER))
#endif
#ifndef CONF_USART_7_BAUD_FP
#define CONF_USART_7_BAUD_FP \
((CONF_FLEXCOM7_FREQUENCY) / CONF_USART_7_BAUD / (2 - CONF_USART_7_OVER) - 8 * CONF_USART_7_BAUD_CD)
#endif
#elif CONF_FLEXCOM7_CK_SRC == 3
// No division is active. The value written in US_BRGR has no effect.
#ifndef CONF_USART_7_BAUD_CD
#define CONF_USART_7_BAUD_CD 1
#endif
#ifndef CONF_USART_7_BAUD_FP
#define CONF_USART_7_BAUD_FP 1
#endif
#endif
// <<< end of configuration section >>>
#endif // HPL_USART_CONFIG_H

View File

@ -0,0 +1,85 @@
/* Auto-generated config file peripheral_clk_config.h */
#ifndef PERIPHERAL_CLK_CONFIG_H
#define PERIPHERAL_CLK_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
/**
* \def CONF_HCLK_FREQUENCY
* \brief HCLK's Clock frequency
*/
#ifndef CONF_HCLK_FREQUENCY
#define CONF_HCLK_FREQUENCY 8000000
#endif
/**
* \def CONF_FCLK_FREQUENCY
* \brief FCLK's Clock frequency
*/
#ifndef CONF_FCLK_FREQUENCY
#define CONF_FCLK_FREQUENCY 8000000
#endif
/**
* \def CONF_CPU_FREQUENCY
* \brief CPU's Clock frequency
*/
#ifndef CONF_CPU_FREQUENCY
#define CONF_CPU_FREQUENCY 8000000
#endif
/**
* \def CONF_SLCK_FREQUENCY
* \brief Slow Clock frequency
*/
#define CONF_SLCK_FREQUENCY 32768
/**
* \def CONF_MCK_FREQUENCY
* \brief Master Clock frequency
*/
#define CONF_MCK_FREQUENCY 8000000
// <o> USB Clock Source
// <0=> USB Clock Controller (USB_48M)
// <id> usb_clock_source
// <i> Select the clock source for USB.
#ifndef CONF_UDP_SRC
#define CONF_UDP_SRC 0
#endif
/**
* \def CONF_UDP_FREQUENCY
* \brief UDP's Clock frequency
*/
#ifndef CONF_UDP_FREQUENCY
#define CONF_UDP_FREQUENCY 48005120
#endif
// <h> FLEXCOM Clock Settings
// <o> FLEXCOM Clock source
// <0=> Master Clock (MCK)
// <1=> MCK / 8
// <2=> Programmable Clock Controller 6 (PMC_PCK6)
// <2=> Programmable Clock Controller 7 (PMC_PCK7)
// <3=> External Clock
// <i> This defines the clock source for the FLEXCOM, PCK6 is used for FLEXCOM0/1/2/3 and PCK7 is used for FLEXCOM4/5/6/7
// <id> flexcom_clock_source
#ifndef CONF_FLEXCOM7_CK_SRC
#define CONF_FLEXCOM7_CK_SRC 0
#endif
// <o> FLEXCOM External Clock Input on SCK <1-4294967295>
// <i> Inputs the external clock frequency on SCK
// <id> flexcom_clock_freq
#ifndef CONF_FLEXCOM7_SCK_FREQ
#define CONF_FLEXCOM7_SCK_FREQ 10000000
#endif
#ifndef CONF_FLEXCOM7_FREQUENCY
#define CONF_FLEXCOM7_FREQUENCY 8000000
#endif
// <<< end of configuration section >>>
#endif // PERIPHERAL_CLK_CONFIG_H

View File

@ -0,0 +1,158 @@
/**
* \file
*
* \brief GCC linker script (flash) for ATSAMG55J19
*
* Copyright (c) 2017 Atmel Corporation, a wholly owned subsidiary of Microchip Technology Inc.
*
* \license_start
*
* \page License
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* \license_stop
*
*/
/*------------------------------------------------------------------------------
* Linker script for running in internal FLASH on the ATSAMG55J19
*----------------------------------------------------------------------------*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00080000 /* rom, 524288K */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00028000 /* ram, 163840K */
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x0400;
/* The heapsize used by the application. NOTE: you need to adjust according to your application. */
HEAP_SIZE = DEFINED(HEAP_SIZE) ? HEAP_SIZE : DEFINED(__heap_size__) ? __heap_size__ : 0x0200;
/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
end = .;
} > ram
/* heap section */
.heap (NOLOAD):
{
. = ALIGN(8);
_sheap = .;
. = . + HEAP_SIZE;
. = ALIGN(8);
_eheap = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
_ram_end_ = ORIGIN(ram) + LENGTH(ram) - 1 ;
}

View File

@ -0,0 +1,157 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019, hathach (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.
*
*/
#include "sam.h"
#include "peripheral_clk_config.h"
#include "hal/include/hal_init.h"
#include "hal/include/hpl_usart_sync.h"
#include "hpl/pmc/hpl_pmc.h"
#include "hal/include/hal_gpio.h"
#include "bsp/board.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
#define LED_PIN GPIO(GPIO_PORTA, 6)
#define BUTTON_PIN GPIO(GPIO_PORTA, 2)
#define BUTTON_STATE_ACTIVE 0
#define UART_TX_PIN GPIO(GPIO_PORTA, 28)
#define UART_RX_PIN GPIO(GPIO_PORTA, 27)
struct _usart_sync_device _edbg_com;
//------------- IMPLEMENTATION -------------//
void board_init(void)
{
init_mcu();
_pmc_enable_periph_clock(ID_PIOA);
/* Disable Watchdog */
hri_wdt_set_MR_WDDIS_bit(WDT);
// LED
gpio_set_pin_level(LED_PIN, false);
gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT);
gpio_set_pin_function(LED_PIN, GPIO_PIN_FUNCTION_OFF);
// Button
gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP);
gpio_set_pin_function(BUTTON_PIN, GPIO_PIN_FUNCTION_OFF);
// Uart via EDBG Com
_pmc_enable_periph_clock(ID_FLEXCOM7);
gpio_set_pin_function(UART_RX_PIN, MUX_PA27B_FLEXCOM7_RXD);
gpio_set_pin_function(UART_TX_PIN, MUX_PA28B_FLEXCOM7_TXD);
_usart_sync_init(&_edbg_com, FLEXCOM7);
_usart_sync_set_baud_rate(&_edbg_com, CFG_BOARD_UART_BAUDRATE);
_usart_sync_set_mode(&_edbg_com, USART_MODE_ASYNCHRONOUS);
_usart_sync_enable(&_edbg_com);
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer (samd SystemCoreClock may not correct)
SysTick_Config(CONF_CPU_FREQUENCY / 1000);
#endif
// USB Pin, Clock init
/* Clear SYSIO 10 & 11 for USB DM & DP */
hri_matrix_clear_CCFG_SYSIO_reg(MATRIX, CCFG_SYSIO_SYSIO10 | CCFG_SYSIO_SYSIO11);
// Enable clock
_pmc_enable_periph_clock(ID_UDP);
/* USB Device mode & Transceiver active */
hri_matrix_write_CCFG_USBMR_reg(MATRIX, CCFG_USBMR_USBMODE);
}
//--------------------------------------------------------------------+
// USB Interrupt Handler
//--------------------------------------------------------------------+
void UDP_Handler(void)
{
#if CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE
tud_isr(0);
#endif
}
//--------------------------------------------------------------------+
// Board porting API
//--------------------------------------------------------------------+
void board_led_write(bool state)
{
gpio_set_pin_level(LED_PIN, state);
}
uint32_t board_button_read(void)
{
return BUTTON_STATE_ACTIVE == gpio_get_pin_level(BUTTON_PIN);
}
int board_uart_read(uint8_t* buf, int len)
{
(void) buf; (void) len;
return 0;
}
int board_uart_write(void const * buf, int len)
{
uint8_t const * buf8 = (uint8_t const *) buf;
for(int i=0; i<len; i++)
{
while ( !_usart_sync_is_ready_to_send(&_edbg_com) ) {}
_usart_sync_write_byte(&_edbg_com, buf8[i]);
}
return len;
}
#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
// Required by __libc_init_array in startup code if we are compiling using
// -nostdlib/-nostartfiles.
void _init(void)
{
}

1
hw/mcu/microchip Submodule

@ -0,0 +1 @@
Subproject commit 66b5a11995025426224e0ba6f377322e6e8893b6

@ -1 +0,0 @@
Subproject commit 82fe3aa05bc3b9f4956ee775c748a3885443f66b

View File

@ -39,7 +39,8 @@ enum
{ {
MSC_STAGE_CMD = 0, MSC_STAGE_CMD = 0,
MSC_STAGE_DATA, MSC_STAGE_DATA,
MSC_STAGE_STATUS MSC_STAGE_STATUS,
MSC_STAGE_STATUS_SENT
}; };
typedef struct typedef struct
@ -97,6 +98,34 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
return tu_ntohs(block_count); return tu_ntohs(block_count);
} }
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= 2
static lookup_entry_t const _msc_scsi_cmd_lookup[] =
{
{ .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" },
{ .key = SCSI_CMD_INQUIRY , .data = "Inquiry" },
{ .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" },
{ .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" },
{ .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" },
{ .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent Allow Medium Removal" },
{ .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" },
{ .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" },
{ .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" },
{ .key = SCSI_CMD_READ_10 , .data = "Read10" },
{ .key = SCSI_CMD_WRITE_10 , .data = "Write10" }
};
static lookup_table_t const _msc_scsi_cmd_table =
{
.count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
.items = _msc_scsi_cmd_lookup
};
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// APPLICATION API // APPLICATION API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -378,6 +407,9 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_ASSERT( event == XFER_RESULT_SUCCESS && TU_ASSERT( event == XFER_RESULT_SUCCESS &&
xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE ); xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE );
TU_LOG2(" SCSI Command: %s\n", lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
// TU_LOG2_MEM(p_cbw, xferred_bytes, 2);
p_csw->signature = MSC_CSW_SIGNATURE; p_csw->signature = MSC_CSW_SIGNATURE;
p_csw->tag = p_cbw->tag; p_csw->tag = p_cbw->tag;
p_csw->data_residue = 0; p_csw->data_residue = 0;
@ -448,6 +480,9 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break; break;
case MSC_STAGE_DATA: case MSC_STAGE_DATA:
TU_LOG2(" SCSI Data\n");
//TU_LOG2_MEM(_mscd_buf, xferred_bytes, 2);
// OUT transfer, invoke callback if needed // OUT transfer, invoke callback if needed
if ( !tu_bit_test(p_cbw->dir, 7) ) if ( !tu_bit_test(p_cbw->dir, 7) )
{ {
@ -535,9 +570,16 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break; break;
case MSC_STAGE_STATUS: case MSC_STAGE_STATUS:
// Wait for the command status wrapper complete event // processed immediately after this switch, supposedly to be empty
break;
case MSC_STAGE_STATUS_SENT:
// Wait for the Status phase to complete
if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
{ {
TU_LOG2(" SCSI Status: %u\n", p_csw->status);
// TU_LOG2_MEM(p_csw, xferred_bytes, 2);
// Move to default CMD stage // Move to default CMD stage
p_msc->stage = MSC_STAGE_CMD; p_msc->stage = MSC_STAGE_CMD;
@ -561,9 +603,6 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
} }
else else
{ {
// Send SCSI Status
TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
// Invoke complete callback if defined // Invoke complete callback if defined
switch(p_cbw->command[0]) switch(p_cbw->command[0])
{ {
@ -579,6 +618,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command);
break; break;
} }
// Move to Status Sent stage
p_msc->stage = MSC_STAGE_STATUS_SENT;
// Send SCSI Status
TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
} }
} }

View File

@ -39,8 +39,8 @@
// Macros Helper // Macros Helper
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) #define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
#define TU_MIN(_x, _y) ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( (_x) > (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
#define TU_U16_HIGH(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) #define TU_U16_HIGH(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
#define TU_U16_LOW(u16) ((uint8_t) ((u16) & 0x00ff)) #define TU_U16_LOW(u16) ((uint8_t) ((u16) & 0x00ff))
@ -139,9 +139,9 @@ static inline uint8_t tu_log2(uint32_t value)
} }
// Bit // Bit
static inline uint32_t tu_bit_set (uint32_t value, uint8_t n) { return value | TU_BIT(n); } static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); }
static inline uint32_t tu_bit_clear(uint32_t value, uint8_t n) { return value & (~TU_BIT(n)); } static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); }
static inline bool tu_bit_test (uint32_t value, uint8_t n) { return (value & TU_BIT(n)) ? true : false; } static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* Count number of arguments of __VA_ARGS__ /* Count number of arguments of __VA_ARGS__
@ -213,22 +213,47 @@ static inline bool tu_bit_test (uint32_t value, uint8_t n) { return (value &
// 2 : print out log // 2 : print out log
#if CFG_TUSB_DEBUG #if CFG_TUSB_DEBUG
void tu_print_mem(void const *buf, uint8_t size, uint16_t count); void tu_print_mem(void const *buf, uint16_t count, uint8_t indent);
#ifndef tu_printf #ifndef tu_printf
#define tu_printf printf #define tu_printf printf
#endif #endif
// Log with debug level 1 // Log with debug level 1
#define TU_LOG1 tu_printf #define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem #define TU_LOG1_MEM tu_print_mem
#define TU_LOG1_LOCATION() tu_printf("%s: %d:\n", __PRETTY_FUNCTION__, __LINE__)
// Log with debug level 2 // Log with debug level 2
#if CFG_TUSB_DEBUG > 1 #if CFG_TUSB_DEBUG > 1
#define TU_LOG2 TU_LOG1 #define TU_LOG2 TU_LOG1
#define TU_LOG2_MEM TU_LOG1_MEM #define TU_LOG2_MEM TU_LOG1_MEM
#define TU_LOG2_LOCATION() TU_LOG1_LOCATION()
#endif #endif
typedef struct
{
uint32_t key;
char const * data;
}lookup_entry_t;
typedef struct
{
uint16_t count;
lookup_entry_t const* items;
} lookup_table_t;
static inline char const* lookup_find(lookup_table_t const* p_table, uint32_t key)
{
for(uint16_t i=0; i<p_table->count; i++)
{
if (p_table->items[i].key == key) return p_table->items[i].data;
}
return NULL;
}
#endif // CFG_TUSB_DEBUG #endif // CFG_TUSB_DEBUG
#ifndef TU_LOG1 #ifndef TU_LOG1

View File

@ -110,6 +110,10 @@ void dcd_remote_wakeup(uint8_t rhport);
// Endpoint API // Endpoint API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
// Configure endpoint's registers according to descriptor // Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);

View File

@ -202,15 +202,16 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
static bool process_set_config(uint8_t rhport, uint8_t cfg_num); static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
void usbd_control_reset (uint8_t rhport); void usbd_control_reset(void);
bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); void usbd_control_set_request(tusb_control_request_t const *request);
void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) ); void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) );
bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Debugging // Debugging
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG > 1 #if CFG_TUSB_DEBUG >= 2
static char const* const _usbd_event_str[DCD_EVENT_COUNT] = static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
{ {
"INVALID" , "INVALID" ,
@ -321,7 +322,7 @@ static void usbd_reset(uint8_t rhport)
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
usbd_control_reset(rhport); usbd_control_reset();
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
{ {
@ -375,8 +376,7 @@ void tud_task (void)
break; break;
case DCD_EVENT_SETUP_RECEIVED: case DCD_EVENT_SETUP_RECEIVED:
TU_LOG2(" "); TU_LOG2_MEM(&event.setup_received, 8, 2);
TU_LOG1_MEM(&event.setup_received, 1, 8);
// Mark as connected after receiving 1st setup packet. // Mark as connected after receiving 1st setup packet.
// But it is easier to set it every time instead of wasting time to check then set // But it is easier to set it every time instead of wasting time to check then set
@ -385,7 +385,7 @@ void tud_task (void)
// Process control request // Process control request
if ( !process_control_request(event.rhport, &event.setup_received) ) if ( !process_control_request(event.rhport, &event.setup_received) )
{ {
TU_LOG1(" Stall EP0\r\n"); TU_LOG2(" Stall EP0\r\n");
// Failed -> stall both control endpoint IN and OUT // Failed -> stall both control endpoint IN and OUT
dcd_edpt_stall(event.rhport, 0); dcd_edpt_stall(event.rhport, 0);
dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK);
@ -405,7 +405,6 @@ void tud_task (void)
if ( 0 == epnum ) if ( 0 == epnum )
{ {
TU_LOG1(" EP Addr = 0x%02X, len = %ld\r\n", ep_addr, event.xfer_complete.len);
usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
} }
else else
@ -500,10 +499,12 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
switch ( p_request->bRequest ) switch ( p_request->bRequest )
{ {
case TUSB_REQ_SET_ADDRESS: case TUSB_REQ_SET_ADDRESS:
// Depending on mcu, status phase could be sent either before or after changing device address // Depending on mcu, status phase could be sent either before or after changing device address,
// Therefore DCD must include zero-length status response // or even require stack to not response with status at all
// Therefore DCD must take full responsibility to response and include zlp status packet if needed.
usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API
dcd_set_address(rhport, (uint8_t) p_request->wValue); dcd_set_address(rhport, (uint8_t) p_request->wValue);
return true; // skip status // skip tud_control_status()
break; break;
case TUSB_REQ_GET_CONFIGURATION: case TUSB_REQ_GET_CONFIGURATION:
@ -518,9 +519,11 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
uint8_t const cfg_num = (uint8_t) p_request->wValue; uint8_t const cfg_num = (uint8_t) p_request->wValue;
dcd_set_config(rhport, cfg_num); dcd_set_config(rhport, cfg_num);
if ( !_usbd_dev.configured && cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
_usbd_dev.configured = cfg_num ? 1 : 0; _usbd_dev.configured = cfg_num ? 1 : 0;
if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
tud_control_status(rhport, p_request); tud_control_status(rhport, p_request);
} }
break; break;
@ -617,7 +620,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
uint8_t const drvid = _usbd_dev.ep2drv[ep_num][ep_dir]; uint8_t const drvid = _usbd_dev.ep2drv[ep_num][ep_dir];
TU_ASSERT(drvid < USBD_CLASS_DRIVER_COUNT);
bool ret = false; bool ret = false;
@ -657,13 +659,17 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
} }
} }
// Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request if (drvid < 0xFF) {
// We will forward all request targeted endpoint to class drivers after TU_ASSERT(drvid < USBD_CLASS_DRIVER_COUNT);
// - For class-type requests: driver is fully responsible to reply to host
// - For std-type requests : driver init/re-init internal variable/buffer only, and // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
// must not call tud_control_status(), driver's return value will have no effect. // We will forward all request targeted endpoint to class drivers after
// EP state has already affected (stalled/cleared) // - For class-type requests: driver is fully responsible to reply to host
if ( invoke_class_control(rhport, drvid, p_request) ) ret = true; // - For std-type requests : driver init/re-init internal variable/buffer only, and
// must not call tud_control_status(), driver's return value will have no effect.
// EP state has already affected (stalled/cleared)
if ( invoke_class_control(rhport, drvid, p_request) ) ret = true;
}
if ( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ) if ( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
{ {
@ -830,19 +836,15 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
{ {
switch (event->event_id) switch (event->event_id)
{ {
case DCD_EVENT_BUS_RESET:
osal_queue_send(_usbd_q, event, in_isr);
break;
case DCD_EVENT_UNPLUGGED: case DCD_EVENT_UNPLUGGED:
_usbd_dev.connected = 0; _usbd_dev.connected = 0;
_usbd_dev.configured = 0; _usbd_dev.configured = 0;
_usbd_dev.suspended = 0; _usbd_dev.suspended = 0;
osal_queue_send(_usbd_q, event, in_isr); osal_queue_send(_usbd_q, event, in_isr);
break; break;
case DCD_EVENT_SOF: case DCD_EVENT_SOF:
// nothing to do now return; // skip SOF event for now
break; break;
case DCD_EVENT_SUSPEND: case DCD_EVENT_SUSPEND:
@ -857,6 +859,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
break; break;
case DCD_EVENT_RESUME: case DCD_EVENT_RESUME:
// skip event if not connected (especially required for SAMD)
if ( _usbd_dev.connected ) if ( _usbd_dev.connected )
{ {
_usbd_dev.suspended = 0; _usbd_dev.suspended = 0;
@ -864,21 +867,9 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
} }
break; break;
case DCD_EVENT_SETUP_RECEIVED: default:
osal_queue_send(_usbd_q, event, in_isr); osal_queue_send(_usbd_q, event, in_isr);
break; break;
case DCD_EVENT_XFER_COMPLETE:
osal_queue_send(_usbd_q, event, in_isr);
TU_ASSERT(event->xfer_complete.result == XFER_RESULT_SUCCESS,);
break;
// Not an DCD event, just a convenient way to defer ISR function should we need to
case USBD_EVENT_FUNC_CALL:
osal_queue_send(_usbd_q, event, in_isr);
break;
default: break;
} }
} }
@ -962,6 +953,8 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
TU_VERIFY( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ); TU_VERIFY( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) );
_usbd_dev.ep_status[epnum][dir].busy = true; _usbd_dev.ep_status[epnum][dir].busy = true;
TU_LOG2(" XFER Endpoint: 0x%02X, Bytes: %d\r\n", ep_addr, total_bytes);
return true; return true;
} }

View File

@ -212,7 +212,7 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \ #define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
/* Interface */\ /* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (_boot_protocol) ? HID_SUBCLASS_BOOT : 0, _boot_protocol, _stridx,\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\ /* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint In */\ /* Endpoint In */\
@ -225,7 +225,7 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \ #define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
/* Interface */\ /* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (_boot_protocol) ? HID_SUBCLASS_BOOT : 0, _boot_protocol, _stridx,\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\ /* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint Out */\ /* Endpoint Out */\

View File

@ -64,6 +64,7 @@ static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t con
return dcd_edpt_xfer(rhport, request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN, NULL, 0); return dcd_edpt_xfer(rhport, request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN, NULL, 0);
} }
// Status phase
bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request)
{ {
_ctrl_xfer.request = (*request); _ctrl_xfer.request = (*request);
@ -118,9 +119,8 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo
// USBD API // USBD API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void usbd_control_reset (uint8_t rhport) void usbd_control_reset(void)
{ {
(void) rhport;
tu_varclr(&_ctrl_xfer); tu_varclr(&_ctrl_xfer);
} }
@ -130,6 +130,15 @@ void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_reque
_ctrl_xfer.complete_cb = fp; _ctrl_xfer.complete_cb = fp;
} }
// useful for dcd_set_address where DCD is responsible for status response
void usbd_control_set_request(tusb_control_request_t const *request)
{
_ctrl_xfer.request = (*request);
_ctrl_xfer.buffer = NULL;
_ctrl_xfer.total_xferred = 0;
_ctrl_xfer.data_len = 0;
}
// callback when a transaction complete on // callback when a transaction complete on
// - DATA stage of control endpoint or // - DATA stage of control endpoint or
// - Status stage // - Status stage
@ -141,6 +150,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction )
{ {
TU_ASSERT(0 == xferred_bytes); TU_ASSERT(0 == xferred_bytes);
if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request);
return true; return true;
} }

View File

@ -26,17 +26,27 @@
#include "tusb_option.h" #include "tusb_option.h"
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD51 #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAMD21)
#include "device/dcd.h"
#include "sam.h" #include "sam.h"
#include "device/dcd.h"
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM /* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
static UsbDeviceDescBank sram_registers[8][2]; static TU_ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2];
static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8]; static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8];
// ready for receiving SETUP packet
static inline void prepare_setup(void)
{
// Only make sure the EP0 OUT buffer is ready
sram_registers[0][0].ADDR.reg = (uint32_t) _setup_packet;
sram_registers[0][0].PCKSIZE.bit.MULTI_PACKET_SIZE = sizeof(_setup_packet);
sram_registers[0][0].PCKSIZE.bit.BYTE_COUNT = 0;
}
// Setup the control endpoint 0. // Setup the control endpoint 0.
static void bus_reset(void) static void bus_reset(void)
{ {
@ -51,7 +61,7 @@ static void bus_reset(void)
ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
// Prepare for setup packet // Prepare for setup packet
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); prepare_setup();
} }
@ -69,10 +79,10 @@ void dcd_init (uint8_t rhport)
USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
USB->DEVICE.PADCAL.bit.TRIM = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos; USB->DEVICE.PADCAL.bit.TRIM = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
USB->DEVICE.QOSCTRL.bit.CQOS = 3; USB->DEVICE.QOSCTRL.bit.CQOS = 3; // High Quality
USB->DEVICE.QOSCTRL.bit.DQOS = 3; USB->DEVICE.QOSCTRL.bit.DQOS = 3; // High Quality
// Configure registers // Configure registers
USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers; USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers;
@ -81,9 +91,11 @@ void dcd_init (uint8_t rhport)
while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; USB->DEVICE.INTENSET.reg = /* USB_DEVICE_INTENSET_SOF | */ USB_DEVICE_INTENSET_EORST;
} }
#if CFG_TUSB_MCU == OPT_MCU_SAMD51
void dcd_int_enable(uint8_t rhport) void dcd_int_enable(uint8_t rhport)
{ {
(void) rhport; (void) rhport;
@ -102,15 +114,30 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_0_IRQn); NVIC_DisableIRQ(USB_0_IRQn);
} }
#elif CFG_TUSB_MCU == OPT_MCU_SAMD21
void dcd_int_enable(uint8_t rhport)
{
(void) rhport;
NVIC_EnableIRQ(USB_IRQn);
}
void dcd_int_disable(uint8_t rhport)
{
(void) rhport;
NVIC_DisableIRQ(USB_IRQn);
}
#endif
void dcd_set_address (uint8_t rhport, uint8_t dev_addr) void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{ {
// Response with status first before changing device address (void) dev_addr;
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
// Wait for EP0 to finish before switching the address. // Response with zlp status
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {} dcd_edpt_xfer(rhport, 0x80, NULL, 0);
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN; // DCD can only set address after status for this request is complete
// do it at dcd_edpt0_status_complete()
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now. // Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
@ -135,6 +162,26 @@ void dcd_remote_wakeup(uint8_t rhport)
/* DCD Endpoint port /* DCD Endpoint port
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(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 )
{
uint8_t const dev_addr = (uint8_t) request->wValue;
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
}
// Just finished status stage, prepare for next setup packet
// Note: we may already prepare setup when the last EP0 OUT complete.
// but it has no harm to do it again here
prepare_setup();
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{ {
(void) rhport; (void) rhport;
@ -181,12 +228,6 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
UsbDeviceDescBank* bank = &sram_registers[epnum][dir]; UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum]; UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
// A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
// buffer for the control endpoint.
if (epnum == 0 && dir == 0 && buffer == NULL) {
buffer = _setup_packet;
}
bank->ADDR.reg = (uint32_t) buffer; bank->ADDR.reg = (uint32_t) buffer;
if ( dir == TUSB_DIR_OUT ) if ( dir == TUSB_DIR_OUT )
{ {
@ -233,39 +274,63 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
} }
} }
/*------------------------------------------------------------------*/ //--------------------------------------------------------------------+
// Interrupt Handler
//--------------------------------------------------------------------+
void maybe_transfer_complete(void) {
uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
static bool maybe_handle_setup_packet(void) { for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP) if ((epints & (1 << epnum)) == 0) {
{ continue;
USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; }
// This copies the data elsewhere so we can reuse the buffer. UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
dcd_event_setup_received(0, (uint8_t*) sram_registers[0][0].ADDR.reg, true); uint32_t epintflag = ep->EPINTFLAG.reg;
return true;
// Handle IN completions
if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT1) != 0) {
UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_IN];
uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, total_transfer_size, XFER_RESULT_SUCCESS, true);
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
}
// Handle OUT completions
if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT0) != 0) {
UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_OUT];
uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
// A SETUP token can occur immediately after an OUT packet
// so make sure we have a valid buffer for the control endpoint.
if (epnum == 0) {
prepare_setup();
}
dcd_event_xfer_complete(0, epnum, total_transfer_size, XFER_RESULT_SUCCESS, true);
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
}
} }
return false;
} }
/*
*------------------------------------------------------------------*/
/* USB_EORSM_DNRSM, USB_EORST_RST, USB_LPMSUSP_DDISC, USB_LPM_DCONN, void dcd_isr (uint8_t rhport)
USB_MSOF, USB_RAMACER, USB_RXSTP_TXSTP_0, USB_RXSTP_TXSTP_1, {
USB_RXSTP_TXSTP_2, USB_RXSTP_TXSTP_3, USB_RXSTP_TXSTP_4, (void) rhport;
USB_RXSTP_TXSTP_5, USB_RXSTP_TXSTP_6, USB_RXSTP_TXSTP_7,
USB_STALL0_STALL_0, USB_STALL0_STALL_1, USB_STALL0_STALL_2,
USB_STALL0_STALL_3, USB_STALL0_STALL_4, USB_STALL0_STALL_5,
USB_STALL0_STALL_6, USB_STALL0_STALL_7, USB_STALL1_0, USB_STALL1_1,
USB_STALL1_2, USB_STALL1_3, USB_STALL1_4, USB_STALL1_5, USB_STALL1_6,
USB_STALL1_7, USB_SUSPEND, USB_TRFAIL0_TRFAIL_0, USB_TRFAIL0_TRFAIL_1,
USB_TRFAIL0_TRFAIL_2, USB_TRFAIL0_TRFAIL_3, USB_TRFAIL0_TRFAIL_4,
USB_TRFAIL0_TRFAIL_5, USB_TRFAIL0_TRFAIL_6, USB_TRFAIL0_TRFAIL_7,
USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2,
USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5,
USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */
void USB_0_Handler(void) {
uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
/*------------- Interrupt Processing -------------*/ /*------------- Interrupt Processing -------------*/
if ( int_status & USB_DEVICE_INTFLAG_SOF )
{
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
// SAMD doesn't distinguish between Suspend and Disconnect state. // SAMD doesn't distinguish between Suspend and Disconnect state.
// Both condition will cause SUSPEND interrupt triggered. // Both condition will cause SUSPEND interrupt triggered.
// To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
@ -303,48 +368,44 @@ void USB_0_Handler(void) {
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
} }
// Setup packet received. // Handle SETUP packet
maybe_handle_setup_packet(); if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP)
{
// This copies the data elsewhere so we can reuse the buffer.
dcd_event_setup_received(0, _setup_packet, true);
USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP;
}
// Handle complete transfer
maybe_transfer_complete();
}
#if CFG_TUSB_MCU == OPT_MCU_SAMD51
/*
*------------------------------------------------------------------*/
/* USB_EORSM_DNRSM, USB_EORST_RST, USB_LPMSUSP_DDISC, USB_LPM_DCONN,
USB_MSOF, USB_RAMACER, USB_RXSTP_TXSTP_0, USB_RXSTP_TXSTP_1,
USB_RXSTP_TXSTP_2, USB_RXSTP_TXSTP_3, USB_RXSTP_TXSTP_4,
USB_RXSTP_TXSTP_5, USB_RXSTP_TXSTP_6, USB_RXSTP_TXSTP_7,
USB_STALL0_STALL_0, USB_STALL0_STALL_1, USB_STALL0_STALL_2,
USB_STALL0_STALL_3, USB_STALL0_STALL_4, USB_STALL0_STALL_5,
USB_STALL0_STALL_6, USB_STALL0_STALL_7, USB_STALL1_0, USB_STALL1_1,
USB_STALL1_2, USB_STALL1_3, USB_STALL1_4, USB_STALL1_5, USB_STALL1_6,
USB_STALL1_7, USB_SUSPEND, USB_TRFAIL0_TRFAIL_0, USB_TRFAIL0_TRFAIL_1,
USB_TRFAIL0_TRFAIL_2, USB_TRFAIL0_TRFAIL_3, USB_TRFAIL0_TRFAIL_4,
USB_TRFAIL0_TRFAIL_5, USB_TRFAIL0_TRFAIL_6, USB_TRFAIL0_TRFAIL_7,
USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2,
USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5,
USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */
void USB_0_Handler(void) {
dcd_isr(0);
} }
/* USB_SOF_HSOF */ /* USB_SOF_HSOF */
void USB_1_Handler(void) { void USB_1_Handler(void) {
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; dcd_isr(0);
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
void transfer_complete(uint8_t direction) {
uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
if ((epints & (1 << epnum)) == 0) {
continue;
}
if (direction == TUSB_DIR_OUT && maybe_handle_setup_packet()) {
continue;
}
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
UsbDeviceDescBank* bank = &sram_registers[epnum][direction];
uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
uint8_t ep_addr = epnum;
if (direction == TUSB_DIR_IN) {
ep_addr |= TUSB_DIR_IN_MASK;
}
dcd_event_xfer_complete(0, ep_addr, total_transfer_size, XFER_RESULT_SUCCESS, true);
// just finished status stage (total size = 0), prepare for next setup packet
if (epnum == 0 && total_transfer_size == 0) {
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
}
if (direction == TUSB_DIR_IN) {
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
} else {
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
}
}
} }
// Bank zero is for OUT and SETUP transactions. // Bank zero is for OUT and SETUP transactions.
@ -352,7 +413,7 @@ void transfer_complete(uint8_t direction) {
USB_TRCPT0_3, USB_TRCPT0_4, USB_TRCPT0_5, USB_TRCPT0_3, USB_TRCPT0_4, USB_TRCPT0_5,
USB_TRCPT0_6, USB_TRCPT0_7 */ USB_TRCPT0_6, USB_TRCPT0_7 */
void USB_2_Handler(void) { void USB_2_Handler(void) {
transfer_complete(TUSB_DIR_OUT); dcd_isr(0);
} }
// Bank one is used for IN transactions. // Bank one is used for IN transactions.
@ -360,7 +421,15 @@ void USB_2_Handler(void) {
USB_TRCPT1_3, USB_TRCPT1_4, USB_TRCPT1_5, USB_TRCPT1_3, USB_TRCPT1_4, USB_TRCPT1_5,
USB_TRCPT1_6, USB_TRCPT1_7 */ USB_TRCPT1_6, USB_TRCPT1_7 */
void USB_3_Handler(void) { void USB_3_Handler(void) {
transfer_complete(TUSB_DIR_IN); dcd_isr(0);
}
#elif CFG_TUSB_MCU == OPT_MCU_SAMD21
void USB_Handler(void) {
dcd_isr(0);
} }
#endif #endif
#endif

View File

@ -1,343 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* 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 "tusb_option.h"
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD21
#include "device/dcd.h"
#include "sam.h"
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
static TU_ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2];
static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8];
// Setup the control endpoint 0.
static void bus_reset(void)
{
// Max size of packets is 64 bytes.
UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
bank_out->PCKSIZE.bit.SIZE = 0x3;
UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
bank_in->PCKSIZE.bit.SIZE = 0x3;
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
// Prepare for setup packet
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
}
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
void dcd_init (uint8_t rhport)
{
(void) rhport;
// Reset to get in a clean state.
USB->DEVICE.CTRLA.bit.SWRST = true;
while (USB->DEVICE.SYNCBUSY.bit.SWRST == 0) {}
while (USB->DEVICE.SYNCBUSY.bit.SWRST == 1) {}
USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
USB->DEVICE.PADCAL.bit.TRIM = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
USB->DEVICE.QOSCTRL.bit.CQOS = USB_QOSCTRL_CQOS_HIGH_Val;
USB->DEVICE.QOSCTRL.bit.DQOS = USB_QOSCTRL_DQOS_HIGH_Val;
// Configure registers
USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers;
USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
}
void dcd_int_enable(uint8_t rhport)
{
(void) rhport;
NVIC_EnableIRQ(USB_IRQn);
}
void dcd_int_disable(uint8_t rhport)
{
(void) rhport;
NVIC_DisableIRQ(USB_IRQn);
}
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{
// Response with status first before changing device address
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
// Wait for EP0 to finish before switching the address.
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
}
void dcd_set_config (uint8_t rhport, uint8_t config_num)
{
(void) rhport;
(void) config_num;
// Nothing to do
}
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
USB->DEVICE.CTRLB.bit.UPRSM = 1;
}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
uint32_t size_value = 0;
while (size_value < 7) {
if (1 << (size_value + 3) == desc_edpt->wMaxPacketSize.size) {
break;
}
size_value++;
}
// unsupported endpoint size
if ( size_value == 7 && desc_edpt->wMaxPacketSize.size != 1023 ) return false;
bank->PCKSIZE.bit.SIZE = size_value;
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
if ( dir == TUSB_DIR_OUT )
{
ep->EPCFG.bit.EPTYPE0 = desc_edpt->bmAttributes.xfer + 1;
ep->EPINTENSET.bit.TRCPT0 = true;
}else
{
ep->EPCFG.bit.EPTYPE1 = desc_edpt->bmAttributes.xfer + 1;
ep->EPINTENSET.bit.TRCPT1 = true;
}
return true;
}
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
// A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
// buffer for the control endpoint.
if (epnum == 0 && dir == 0 && buffer == NULL) {
buffer = _setup_packet;
}
bank->ADDR.reg = (uint32_t) buffer;
if ( dir == TUSB_DIR_OUT )
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
bank->PCKSIZE.bit.BYTE_COUNT = 0;
ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
} else
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
// bank->PCKSIZE.bit.AUTO_ZLP = 1;
ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
}
return true;
}
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1;
} else {
ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0;
}
}
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN;
} else {
ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT;
}
}
/*------------------------------------------------------------------*/
static bool maybe_handle_setup_packet(void) {
if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP)
{
USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP;
// This copies the data elsewhere so we can reuse the buffer.
dcd_event_setup_received(0, (uint8_t*) sram_registers[0][0].ADDR.reg, true);
return true;
}
return false;
}
void maybe_transfer_complete(void) {
uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
if ((epints & (1 << epnum)) == 0) {
continue;
}
if (maybe_handle_setup_packet()) {
continue;
}
UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
uint32_t epintflag = ep->EPINTFLAG.reg;
uint16_t total_transfer_size = 0;
// Handle IN completions
if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT1) != 0) {
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_IN];
total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
uint8_t ep_addr = epnum | TUSB_DIR_IN_MASK;
dcd_event_xfer_complete(0, ep_addr, total_transfer_size, XFER_RESULT_SUCCESS, true);
}
// Handle OUT completions
if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT0) != 0) {
ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_OUT];
total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
uint8_t ep_addr = epnum;
dcd_event_xfer_complete(0, ep_addr, total_transfer_size, XFER_RESULT_SUCCESS, true);
}
// Just finished status stage (total size = 0), prepare for next setup packet
// TODO could cause issue with actual zero length data used by class such as DFU
if (epnum == 0 && total_transfer_size == 0) {
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
}
}
}
void USB_Handler(void)
{
uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
USB->DEVICE.INTFLAG.reg = int_status; // clear interrupt
/*------------- Interrupt Processing -------------*/
if ( int_status & USB_DEVICE_INTFLAG_SOF )
{
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
// SAMD doesn't distinguish between Suspend and Disconnect state.
// Both condition will cause SUSPEND interrupt triggered.
// To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
// enabled when we received SET_ADDRESS request and cleared on Bus Reset
if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
{
// Enable wakeup interrupt
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
// Wakeup interrupt is only enabled when we got suspended.
// Wakeup interrupt will disable itself
if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
{
// disable wakeup interrupt itself
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
if ( int_status & USB_DEVICE_INTFLAG_EORST )
{
// Disable both suspend and wakeup interrupt
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
bus_reset();
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
}
// Setup packet received.
maybe_handle_setup_packet();
// Handle complete transfer
maybe_transfer_complete();
}
#endif

View File

@ -0,0 +1,443 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018, hathach (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 "tusb_option.h"
#if CFG_TUSB_MCU == OPT_MCU_SAMG
#include "sam.h"
#include "device/dcd.h"
// TODO should support (SAM3S || SAM4S || SAM4E || SAMG55)
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
#define EP_COUNT 6
// Transfer descriptor
typedef struct
{
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
uint16_t epsize;
} xfer_desc_t;
// Endpoint 0-5, each can only be either OUT or In
xfer_desc_t _dcd_xfer[EP_COUNT];
void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize)
{
xfer->epsize = epsize;
}
void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes)
{
xfer->buffer = buffer;
xfer->total_len = total_bytes;
xfer->actual_len = 0;
}
void xfer_end(xfer_desc_t* xfer)
{
xfer->buffer = NULL;
xfer->total_len = 0;
xfer->actual_len = 0;
}
uint16_t xfer_packet_len(xfer_desc_t* xfer)
{
// also cover zero-length packet
return tu_min16(xfer->total_len - xfer->actual_len, xfer->epsize);
}
void xfer_packet_done(xfer_desc_t* xfer)
{
uint16_t const xact_len = xfer_packet_len(xfer);
xfer->buffer += xact_len;
xfer->actual_len += xact_len;
}
//------------- Transaction helpers -------------//
// Write data to EP FIFO, return number of written bytes
static void xact_ep_write(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
{
for(uint16_t i=0; i<xact_len; i++)
{
UDP->UDP_FDR[epnum] = (uint32_t) buffer[i];
}
}
// Read data from EP FIFO
static void xact_ep_read(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
{
for(uint16_t i=0; i<xact_len; i++)
{
buffer[i] = (uint8_t) UDP->UDP_FDR[epnum];
}
}
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
// Set up endpoint 0, clear all other endpoints
static void bus_reset(void)
{
tu_memclr(_dcd_xfer, sizeof(_dcd_xfer));
xfer_epsize_set(&_dcd_xfer[0], CFG_TUD_ENDPOINT0_SIZE);
// Enable EP0 control
UDP->UDP_CSR[0] = UDP_CSR_EPEDS_Msk;
// Enable interrupt : EP0, Suspend, Resume, Wakeup
UDP->UDP_IER = UDP_IER_EP0INT_Msk | UDP_IER_RXSUSP_Msk | UDP_IER_RXRSM_Msk | UDP_IER_WAKEUP_Msk;
// Enable transceiver
UDP->UDP_TXVC &= ~UDP_TXVC_TXVDIS_Msk;
}
// Initialize controller to device mode
void dcd_init (uint8_t rhport)
{
(void) rhport;
tu_memclr(_dcd_xfer, sizeof(_dcd_xfer));
// Enable pull-up, disable transceiver
UDP->UDP_TXVC = UDP_TXVC_PUON | UDP_TXVC_TXVDIS_Msk;
}
// Enable device interrupt
void dcd_int_enable (uint8_t rhport)
{
(void) rhport;
NVIC_EnableIRQ(UDP_IRQn);
}
// Disable device interrupt
void dcd_int_disable (uint8_t rhport)
{
(void) rhport;
NVIC_DisableIRQ(UDP_IRQn);
}
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
(void) dev_addr;
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0);
// DCD can only set address after status for this request is complete.
// do it at dcd_edpt0_status_complete()
}
// Receive Set Configure request
void dcd_set_config (uint8_t rhport, uint8_t config_num)
{
(void) rhport;
(void) config_num;
// Configured State
// UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG_Msk;
}
// Wake up host
void dcd_remote_wakeup (uint8_t rhport)
{
(void) rhport;
}
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
{
if (request->bRequest == TUSB_REQ_SET_ADDRESS)
{
uint8_t const dev_addr = (uint8_t) request->wValue;
// Enable addressed state
UDP->UDP_GLB_STAT |= UDP_GLB_STAT_FADDEN_Msk;
// Set new address & Function enable bit
UDP->UDP_FADDR = UDP_FADDR_FEN_Msk | UDP_FADDR_FADD(dev_addr);
}else if (request->bRequest == TUSB_REQ_SET_CONFIGURATION)
{
// Configured State
UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG_Msk;
}
}
}
// Configure endpoint's registers according to descriptor
// SAMG doesn't support a same endpoint number with IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(ep_desc->bEndpointAddress);
// TODO Isochronous is not supported yet
TU_VERIFY(ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
TU_VERIFY(epnum < EP_COUNT);
// Must not already enabled
TU_ASSERT((UDP->UDP_CSR[epnum] & UDP_CSR_EPEDS_Msk) == 0);
xfer_epsize_set(&_dcd_xfer[epnum], ep_desc->wMaxPacketSize.size);
// Configure type and eanble EP
UDP->UDP_CSR[epnum] = UDP_CSR_EPEDS_Msk | UDP_CSR_EPTYPE(ep_desc->bmAttributes.xfer + 4*dir);
// Enable EP Interrupt for IN
if (dir == TUSB_DIR_IN) UDP->UDP_IER |= (1 << epnum);
return true;
}
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_desc_t* xfer = &_dcd_xfer[epnum];
xfer_begin(xfer, buffer, total_bytes);
if (dir == TUSB_DIR_IN)
{
// Set DIR bit for EP0
if ( epnum == 0 ) UDP->UDP_CSR[epnum] |= UDP_CSR_DIR_Msk;
xact_ep_write(epnum, xfer->buffer, xfer_packet_len(xfer));
// TX ready for transfer
UDP->UDP_CSR[epnum] |= UDP_CSR_TXPKTRDY_Msk;
}
else
{
// Clear DIR bit for EP0
if ( epnum == 0 ) UDP->UDP_CSR[epnum] &= ~UDP_CSR_DIR_Msk;
// OUT Data may already received and acked by hardware
// Read it as 1st packet then continue with transfer if needed
if ( UDP->UDP_CSR[epnum] & (UDP_CSR_RX_DATA_BK0_Msk | UDP_CSR_RX_DATA_BK1_Msk) )
{
// uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos);
// TU_LOG2("xact_len = %d\r", xact_len);
// // Read from EP fifo
// xact_ep_read(epnum, xfer->buffer, xact_len);
// xfer_packet_done(xfer);
//
// // Clear DATA Bank0 bit
// UDP->UDP_CSR[epnum] &= ~UDP_CSR_RX_DATA_BK0_Msk;
//
// if ( 0 == xfer_packet_len(xfer) )
// {
// // Disable OUT EP interrupt when transfer is complete
// UDP->UDP_IER &= ~(1 << epnum);
//
// dcd_event_xfer_complete(rhport, epnum, xact_len, XFER_RESULT_SUCCESS, false);
// return true; // complete
// }
}
// Enable interrupt when starting OUT transfer
if (epnum != 0) UDP->UDP_IER |= (1 << epnum);
}
return true;
}
// Stall endpoint
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
// Set force stall bit
UDP->UDP_CSR[epnum] |= UDP_CSR_FORCESTALL_Msk;
}
// clear stall, data toggle is also reset to DATA0
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
// clear stall
UDP->UDP_CSR[epnum] &= ~UDP_CSR_FORCESTALL_Msk;
// must also reset EP to clear data toggle
UDP->UDP_RST_EP = tu_bit_set(UDP->UDP_RST_EP, epnum);
UDP->UDP_RST_EP = tu_bit_clear(UDP->UDP_RST_EP, epnum);
}
//--------------------------------------------------------------------+
// ISR
//--------------------------------------------------------------------+
void dcd_isr(uint8_t rhport)
{
uint32_t const intr_mask = UDP->UDP_IMR;
uint32_t const intr_status = UDP->UDP_ISR & intr_mask;
// clear interrupt
UDP->UDP_ICR = intr_status;
// Bus reset
if (intr_status & UDP_ISR_ENDBUSRES_Msk)
{
bus_reset();
dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
}
// SOF
// if (intr_status & UDP_ISR_SOFINT_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
// Suspend
// if (intr_status & UDP_ISR_RXSUSP_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
// Resume
// if (intr_status & UDP_ISR_RXRSM_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
// Wakeup
// if (intr_status & UDP_ISR_WAKEUP_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
//------------- Endpoints -------------//
if ( intr_status & TU_BIT(0) )
{
// setup packet
if (UDP->UDP_CSR[0] & UDP_CSR_RXSETUP)
{
// get setup from FIFO
uint8_t setup[8];
for(uint8_t i=0; i<sizeof(setup); i++)
{
setup[i] = (uint8_t) UDP->UDP_FDR[0];
}
// notify usbd
dcd_event_setup_received(rhport, setup, true);
// Clear Setup bit
UDP->UDP_CSR[0] &= ~UDP_CSR_RXSETUP_Msk;
return;
}
}
for(uint8_t epnum = 0; epnum < EP_COUNT; epnum++)
{
if ( intr_status & TU_BIT(epnum) )
{
xfer_desc_t* xfer = &_dcd_xfer[epnum];
// Endpoint IN
if (UDP->UDP_CSR[epnum] & UDP_CSR_TXCOMP_Msk)
{
xfer_packet_done(xfer);
uint16_t const xact_len = xfer_packet_len(xfer);
if (xact_len)
{
// write to EP fifo
xact_ep_write(epnum, xfer->buffer, xact_len);
// TX ready for transfer
UDP->UDP_CSR[epnum] |= UDP_CSR_TXPKTRDY_Msk;
}else
{
// xfer is complete
dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
}
// Clear TX Complete bit
UDP->UDP_CSR[epnum] &= ~UDP_CSR_TXCOMP_Msk;
}
// Endpoint OUT
// Ping-Pong is a must for Bulk/Iso
// When both Bank0 and Bank1 are both set, there is not way to know which one comes first
if (UDP->UDP_CSR[epnum] & (UDP_CSR_RX_DATA_BK0_Msk | UDP_CSR_RX_DATA_BK1_Msk))
{
uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos);
//if (epnum != 0) TU_LOG2("xact_len = %d\r", xact_len);
// Read from EP fifo
xact_ep_read(epnum, xfer->buffer, xact_len);
xfer_packet_done(xfer);
if ( 0 == xfer_packet_len(xfer) )
{
// Disable OUT EP interrupt when transfer is complete
if (epnum != 0) UDP->UDP_IDR |= (1 << epnum);
dcd_event_xfer_complete(rhport, epnum, xact_len, XFER_RESULT_SUCCESS, true);
// xfer_end(xfer);
}
// Clear DATA Bank0 bit
UDP->UDP_CSR[epnum] &= ~(UDP_CSR_RX_DATA_BK0_Msk | UDP_CSR_RX_DATA_BK1_Msk);
}
// Stall sent to host
if (UDP->UDP_CSR[epnum] & UDP_CSR_STALLSENT_Msk)
{
UDP->UDP_CSR[epnum] &= ~UDP_CSR_STALLSENT_Msk;
}
}
}
}
#endif

View File

@ -175,7 +175,6 @@ static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir)
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
static uint8_t newDADDR; // Used to set the new device address during the CTR IRQ handler
static uint8_t remoteWakeCountdown; // When wake is requested static uint8_t remoteWakeCountdown; // When wake is requested
// EP Buffers assigned from end of memory location, to minimize their chance of crashing // EP Buffers assigned from end of memory location, to minimize their chance of crashing
@ -298,14 +297,14 @@ void dcd_int_disable(uint8_t rhport)
// Receive Set Address request, mcu port must also include status IN response // Receive Set Address request, mcu port must also include status IN response
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{ {
(void)rhport; (void) rhport;
// We cannot immediatly change it; it must be queued to change after the STATUS packet is sent. (void) dev_addr;
// (CTR handler will actually change the address once it sees that the transmission is complete)
newDADDR = dev_addr;
// Respond with status // Respond with status
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
// DCD can only set address after status for this request is complete.
// do it at dcd_edpt0_status_complete()
} }
// Receive Set Config request // Receive Set Config request
@ -362,7 +361,7 @@ static void dcd_handle_bus_reset(void)
ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each)
dcd_edpt_open (0, &ep0OUT_desc); dcd_edpt_open (0, &ep0OUT_desc);
dcd_edpt_open (0, &ep0IN_desc); dcd_edpt_open (0, &ep0IN_desc);
newDADDR = 0u;
USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
} }
@ -398,13 +397,7 @@ static uint16_t dcd_ep_ctr_handler(void)
if((xfer->total_len == xfer->queued_len)) if((xfer->total_len == xfer->queued_len))
{ {
dcd_event_xfer_complete(0u, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); dcd_event_xfer_complete(0u, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
if((newDADDR != 0) && ( xfer->total_len == 0U))
{
// Delayed setting of the DADDR after the 0-len DATA packet acking the request is sent.
reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
USB->DADDR = (uint16_t)(USB->DADDR | newDADDR); // leave the enable bit set
newDADDR = 0;
}
if(xfer->total_len == 0) // Probably a status message? if(xfer->total_len == 0) // Probably a status message?
{ {
pcd_clear_rx_dtog(USB,EPindex); pcd_clear_rx_dtog(USB,EPindex);
@ -602,6 +595,24 @@ static void dcd_fs_irqHandler(void) {
// Endpoint API // Endpoint API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(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 )
{
uint8_t const dev_addr = (uint8_t) request->wValue;
// Setting new address after the whole request is complete
reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set
}
}
// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, // The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
// so I'm using the #define from HAL here, instead. // so I'm using the #define from HAL here, instead.

View File

@ -232,7 +232,6 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
(void) rhport; (void) rhport;
USB_OTG_DeviceTypeDef * dev = DEVICE_BASE; USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
dev->DCFG |= (dev_addr << USB_OTG_DCFG_DAD_Pos) & USB_OTG_DCFG_DAD_Msk; dev->DCFG |= (dev_addr << USB_OTG_DCFG_DAD_Pos) & USB_OTG_DCFG_DAD_Msk;
// Response with status after changing device address // Response with status after changing device address

View File

@ -0,0 +1,116 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018, hathach (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 "tusb_option.h"
#if CFG_TUSB_MCU == OPT_MCU_NONE
#include "device/dcd.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
// Initialize controller to device mode
void dcd_init (uint8_t rhport)
{
(void) rhport;
}
// Enable device interrupt
void dcd_int_enable (uint8_t rhport)
{
(void) rhport;
}
// Disable device interrupt
void dcd_int_disable (uint8_t rhport)
{
(void) rhport;
}
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
(void) dev_addr;
}
// Receive Set Configure request
void dcd_set_config (uint8_t rhport, uint8_t config_num)
{
(void) rhport;
(void) config_num;
}
// Wake up host
void dcd_remote_wakeup (uint8_t rhport)
{
(void) rhport;
}
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
// Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
(void) ep_desc;
return false;
}
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
(void) ep_addr;
(void) buffer;
(void) total_bytes;
return false;
}
// Stall endpoint
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
(void) ep_addr;
}
// clear stall, data toggle is also reset to DATA0
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
(void) ep_addr;
}
#endif

View File

@ -81,8 +81,10 @@ static void dump_str_line(uint8_t const* buf, uint16_t count)
// size : item size in bytes // size : item size in bytes
// count : number of item // count : number of item
// print offet or not (handfy for dumping large memory) // print offet or not (handfy for dumping large memory)
void tu_print_mem(void const *buf, uint8_t size, uint16_t count) void tu_print_mem(void const *buf, uint16_t count, uint8_t indent)
{ {
uint8_t const size = 1; // fixed 1 byte for now
if ( !buf || !count ) if ( !buf || !count )
{ {
tu_printf("NULL\r\n"); tu_printf("NULL\r\n");
@ -110,6 +112,8 @@ void tu_print_mem(void const *buf, uint8_t size, uint16_t count)
tu_printf("\r\n"); tu_printf("\r\n");
} }
for(uint8_t s=0; s < indent; s++) tu_printf(" ");
// print offset or absolute address // print offset or absolute address
tu_printf("%03lX: ", 16*i/item_per_line); tu_printf("%03lX: ", 16*i/item_per_line);
} }

View File

@ -36,6 +36,8 @@
* \ref CFG_TUSB_MCU must be defined to one of these * \ref CFG_TUSB_MCU must be defined to one of these
* @{ */ * @{ */
#define OPT_MCU_NONE 0
// LPC // LPC
#define OPT_MCU_LPC11UXX 1 ///< NXP LPC11Uxx #define OPT_MCU_LPC11UXX 1 ///< NXP LPC11Uxx
#define OPT_MCU_LPC13XX 2 ///< NXP LPC13xx #define OPT_MCU_LPC13XX 2 ///< NXP LPC13xx
@ -55,6 +57,7 @@
// SAM // SAM
#define OPT_MCU_SAMD21 200 ///< MicroChip SAMD21 #define OPT_MCU_SAMD21 200 ///< MicroChip SAMD21
#define OPT_MCU_SAMD51 201 ///< MicroChip SAMD51 #define OPT_MCU_SAMD51 201 ///< MicroChip SAMD51
#define OPT_MCU_SAMG 202 ///< MicroChip SAMDG series
// STM32 // STM32
#define OPT_MCU_STM32F0 300 ///< ST STM32F0 #define OPT_MCU_STM32F0 300 ///< ST STM32F0

View File

@ -149,6 +149,8 @@ void test_usbd_get_device_descriptor(void)
// status // status
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_device, 1);
tud_task(); tud_task();
} }
@ -180,6 +182,8 @@ void test_usbd_get_configuration_descriptor(void)
// status // status
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1);
tud_task(); tud_task();
} }
@ -231,6 +235,7 @@ void test_usbd_control_in_zlp(void)
// Status // Status
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false); dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1);
tud_task(); tud_task();
} }

View File

@ -36,7 +36,7 @@ for entry in os.scandir("hw/bsp"):
def build_example(example, board): def build_example(example, board):
subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True, subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return subprocess.run("make -j 8 -C examples/device/{} BOARD={} all".format(example, board), shell=True, return subprocess.run("make -j 4 -C examples/device/{} BOARD={} all".format(example, board), shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

View File

@ -0,0 +1,18 @@
# Copy this file to the location of your distribution's udev rules, for example on Ubuntu:
# sudo cp 99-tinyusb.rules /etc/udev/rules.d/
# Then reload udev configuration by executing:
# sudo udevadm control --reload-rules
# sudo udevadm trigger
# Check SUBSYSTEM
SUBSYSTEMS=="hidraw", KERNEL=="hidraw*", MODE="0666", GROUP="dialout"
# Rule applies to all TinyUSB example
ATTRS{idVendor}=="cafe", MODE="0666", GROUP="dialout"
# Rule to blacklist TinyUSB example from being manipulated by ModemManager.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="cafe", ENV{ID_MM_DEVICE_IGNORE}="1"
# Xplained Pro SamG55 Device
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE="0666", GROUP="users", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEMS=="tty", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE="0666", GROUP="users", ENV{ID_MM_DEVICE_IGNORE}="1"