Merge branch 'master' into enhance

This commit is contained in:
hathach 2021-09-29 16:18:17 +07:00
commit 0b31c40b9f
30 changed files with 6580 additions and 202 deletions

View File

@ -7,12 +7,18 @@ FREERTOS_SRC = lib/FreeRTOS-Kernel
INC += \
src \
src/FreeRTOSConfig \
$(TOP)/hw \
$(TOP)/$(FREERTOS_SRC)/include \
$(TOP)/$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
EXAMPLE_SOURCE = \
src/freertos_hook.c \
src/main.c \
src/msc_disk.c \
src/usb_descriptors.c
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# FreeRTOS source, all files in port folder

View File

@ -8,9 +8,7 @@ if(EXISTS ${board_cmake})
include(${board_cmake})
endif()
idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
target_include_directories(${COMPONENT_TARGET} PUBLIC
"${FREERTOS_ORIG_INCLUDE_PATH}"
"${TOP}/hw"
"${TOP}/src"
)

View File

@ -45,6 +45,10 @@
// Include MCU header
#include "bsp/board_mcu.h"
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
#error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
#endif
extern uint32_t SystemCoreClock;
/* Cortex M23/M33 port configuration. */

View File

@ -27,15 +27,25 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
#include "bsp/board.h"
#include "tusb.h"
#if TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#else
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include "timers.h"
#endif
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
@ -95,7 +105,7 @@ int main(void)
(void) xTaskCreateStatic( cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if CFG_TUSB_MCU != OPT_MCU_ESP32S2 && CFG_TUSB_MCU != OPT_MCU_ESP32S3
#if !( TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3) )
vTaskStartScheduler();
#endif

View File

@ -67,6 +67,11 @@
// This examples use FreeRTOS
#define CFG_TUSB_OS OPT_OS_FREERTOS
// Espressif IDF requires "freertos/" prefix in include path
#if TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
// can be defined by compiler in DEBUG build
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0

View File

@ -6,7 +6,7 @@ INC += \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += \
EXAMPLE_SOURCE = \
src/main.c \
src/usb_descriptors.c

View File

@ -7,12 +7,17 @@ FREERTOS_SRC = lib/FreeRTOS-Kernel
INC += \
src \
src/FreeRTOSConfig \
$(TOP)/hw \
$(TOP)/$(FREERTOS_SRC)/include \
$(TOP)/$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
EXAMPLE_SOURCE = \
src/freertos_hook.c \
src/main.c \
src/usb_descriptors.c
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# FreeRTOS source, all files in port folder

View File

@ -8,9 +8,7 @@ if(EXISTS ${board_cmake})
include(${board_cmake})
endif()
idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
target_include_directories(${COMPONENT_TARGET} PUBLIC
"${FREERTOS_ORIG_INCLUDE_PATH}"
"${TOP}/hw"
"${TOP}/src"
)

View File

@ -45,6 +45,10 @@
// Include MCU header
#include "bsp/board_mcu.h"
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
#error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
#endif
extern uint32_t SystemCoreClock;
/* Cortex M23/M33 port configuration. */

View File

@ -27,17 +27,26 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
#include "bsp/board.h"
#include "tusb.h"
#include "usb_descriptors.h"
#if TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#else
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include "timers.h"
#endif
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
@ -96,7 +105,7 @@ int main(void)
(void) xTaskCreateStatic( hid_task, "hid", HID_STACK_SZIE, NULL, configMAX_PRIORITIES-2, hid_stack, &hid_taskdef);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if CFG_TUSB_MCU != OPT_MCU_ESP32S2 && CFG_TUSB_MCU != OPT_MCU_ESP32S3
#if !( TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3) )
vTaskStartScheduler();
#endif

View File

@ -67,6 +67,12 @@
// This examples use FreeRTOS
#define CFG_TUSB_OS OPT_OS_FREERTOS
// Espressif IDF requires "freertos/" prefix in include path
#if TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif

View File

@ -53,6 +53,9 @@ void UnhandledIRQ(void)
while(1);
}
// DA146xx driver function that must be called whenever VBUS changes.
extern void tusb_vbus_changed(bool present);
void board_init(void)
{
// LED
@ -65,12 +68,15 @@ void board_init(void)
hal_gpio_init_out(5, 0);
// Button
hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_NONE);
hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_DOWN);
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
NVIC_SetPriority(USB_IRQn, 2);
#if TUSB_OPT_DEVICE_ENABLED
// This board is USB powered there is no need to monitor
// VBUS line. Notify driver that VBUS is present.
tusb_vbus_changed(true);
/* Setup USB IRQ */
NVIC_SetPriority(USB_IRQn, 2);
@ -81,6 +87,7 @@ void board_init(void)
mcu_gpio_set_pin_function(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
#endif
}
//--------------------------------------------------------------------+
@ -94,8 +101,8 @@ void board_led_write(bool state)
uint32_t board_button_read(void)
{
// button is active LOW
return hal_gpio_read(BUTTON_PIN) ^ 1;
// button is active HIGH
return hal_gpio_read(BUTTON_PIN);
}
int board_uart_read(uint8_t* buf, int len)

View File

@ -36,6 +36,21 @@ void USB_IRQHandler(void)
tud_int_handler(0);
}
#if TUSB_OPT_DEVICE_ENABLED
// DA146xx driver function that must be called whenever VBUS changes
extern void tusb_vbus_changed(bool present);
// VBUS change interrupt handler
void VBUS_IRQHandler(void)
{
bool present = (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0;
// Clear VBUS interrupt
CRG_TOP->VBUS_IRQ_CLEAR_REG = 1;
tusb_vbus_changed(present);
}
#endif
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
@ -65,12 +80,20 @@ void board_init(void)
hal_gpio_init_out(5, 0);
// Button
hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_NONE);
hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_UP);
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
NVIC_SetPriority(USB_IRQn, 2);
#if TUSB_OPT_DEVICE_ENABLED
// Setup interrupt for both connect and disconnect
CRG_TOP->VBUS_IRQ_MASK_REG = CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_FALL_Msk |
CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_RISE_Msk;
NVIC_SetPriority(VBUS_IRQn, 2);
// Trigger interrupt at the start to inform driver about VBUS state at start
// otherwise it could go unnoticed.
NVIC_SetPendingIRQ(VBUS_IRQn);
NVIC_EnableIRQ(VBUS_IRQn);
/* Setup USB IRQ */
NVIC_SetPriority(USB_IRQn, 2);
@ -81,6 +104,7 @@ void board_init(void)
mcu_gpio_set_pin_function(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
#endif
}
//--------------------------------------------------------------------+

View File

@ -6,9 +6,7 @@ idf_component_register(SRCS esp32s2.c
# Apply board specific content
include("${BOARD}/board.cmake")
idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
target_include_directories(${COMPONENT_TARGET} PUBLIC
"${FREERTOS_ORIG_INCLUDE_PATH}"
"${TOP}/hw"
"${TOP}/src"
)

View File

@ -8,8 +8,12 @@ CFLAGS += \
-DCPU_MKL25Z128VLK4 \
-DCFG_TUSB_MCU=OPT_MCU_MKL25ZXX
LDFLAGS += \
-Wl,--defsym,__stack_size__=0x400 \
-Wl,--defsym,__heap_size__=0
# mcu driver cause following warnings
CFLAGS += -Wno-error=unused-parameter
CFLAGS += -Wno-error=unused-parameter -Wno-error=format
MCU_DIR = $(SDK_DIR)/devices/MKL25Z4

View File

@ -54,6 +54,14 @@ void USB0_IRQHandler(void)
#define LED_PIN_FUNCTION kPORT_MuxAsGpio
#define LED_STATE_ON 0
// Button
#define BUTTON_PORT GPIOC
#define BUTTON_PIN_CLOCK kCLOCK_PortC
#define BUTTON_PIN_PORT PORTC
#define BUTTON_PIN 9U
#define BUTTON_PIN_FUNCTION kPORT_MuxAsGpio
#define BUTTON_STATE_ACTIVE 0
// UART
#define UART_PORT UART0
#define UART_PIN_CLOCK kCLOCK_PortA
@ -84,7 +92,19 @@ void board_init(void)
PORT_SetPinMux(LED_PIN_PORT, LED_PIN, LED_PIN_FUNCTION);
gpio_pin_config_t led_config = { kGPIO_DigitalOutput, 0 };
GPIO_PinInit(LED_PORT, LED_PIN, &led_config);
board_led_write(true);
board_led_write(false);
#if defined(BUTTON_PORT) && defined(BUTTON_PIN)
// Button
CLOCK_EnableClock(BUTTON_PIN_CLOCK);
port_pin_config_t button_port = {
.pullSelect = kPORT_PullUp,
.mux = BUTTON_PIN_FUNCTION,
};
PORT_SetPinConfig(BUTTON_PIN_PORT, BUTTON_PIN, &button_port);
gpio_pin_config_t button_config = { kGPIO_DigitalInput, 0 };
GPIO_PinInit(BUTTON_PORT, BUTTON_PIN, &button_config);
#endif
// UART
CLOCK_EnableClock(UART_PIN_CLOCK);
@ -119,6 +139,9 @@ void board_led_write(bool state)
uint32_t board_button_read(void)
{
#if defined(BUTTON_PORT) && defined(BUTTON_PIN)
return BUTTON_STATE_ACTIVE == GPIO_ReadPinInput(BUTTON_PORT, BUTTON_PIN);
#endif
return 0;
}

View File

@ -0,0 +1,56 @@
DEPS_SUBMODULES += hw/mcu/microchip
CFLAGS += \
-mthumb \
-mabi=aapcs \
-mcpu=cortex-m7 \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-nostdlib -nostartfiles \
-D__SAME70N19B__ \
-DCFG_TUSB_MCU=OPT_MCU_SAMX7X
# suppress following warnings from mcu driver
CFLAGS += -Wno-error=unused-parameter -Wno-error=cast-align
ASF_DIR = hw/mcu/microchip/same70
# All source paths should be relative to the top level.
LD_FILE = $(ASF_DIR)/same70b/gcc/gcc/same70q21b_flash.ld
SRC_C += \
src/portable/microchip/samx7x/dcd_samx7x.c \
$(ASF_DIR)/same70b/gcc/gcc/startup_same70q21b.c \
$(ASF_DIR)/same70b/gcc/system_same70q21b.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_usart_async.c \
$(ASF_DIR)/hal/src/hal_io.c \
$(ASF_DIR)/hal/src/hal_atomic.c \
$(ASF_DIR)/hal/utils/src/utils_ringbuffer.c
INC += \
$(TOP)/hw/bsp/$(BOARD) \
$(TOP)/$(ASF_DIR) \
$(TOP)/$(ASF_DIR)/config \
$(TOP)/$(ASF_DIR)/same70b/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 freeRTOS port source
FREERTOS_PORT = ARM_CM7
# For flash-jlink target
JLINK_DEVICE = SAME70N19B
# flash using edbg from https://github.com/ataradov/edbg
# Note: SAME70's GPNVM1 must be set to 1 to boot from flash with
# edbg -t same70 -F w0,1,1
flash: $(BUILD)/$(PROJECT).bin
edbg --verbose -t same70 -pv -f $<

File diff suppressed because it is too large Load Diff

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_1_ENABLE
#define CONF_USART_1_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_1_PARITY
#define CONF_USART_1_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_1_CHSIZE
#define CONF_USART_1_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_1_SBMODE
#define CONF_USART_1_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_1_CLKO
#define CONF_USART_1_CLKO 0
#endif
// <o> Baud rate <1-3000000>
// <i> USART baud rate setting
// <id> usart_baud_rate
#ifndef CONF_USART_1_BAUD
#define CONF_USART_1_BAUD 9600
#endif
// </h>
// <e> Advanced configuration
// <id> usart_advanced
#ifndef CONF_USART_1_ADVANCED_CONFIG
#define CONF_USART_1_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_1_CHMODE
#define CONF_USART_1_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_1_MODE9
#define CONF_USART_1_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_1_VAR_SYNC
#define CONF_USART_1_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_1_OVER
#define CONF_USART_1_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_1_INACK
#define CONF_USART_1_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_1_DSNACK
#define CONF_USART_1_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_1_INVDATA
#define CONF_USART_1_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_1_MAX_ITERATION
#define CONF_USART_1_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_1_FILTER
#define CONF_USART_1_FILTER 0
#endif
// <q> Manchester Encoder/Decoder Enable
// <i> whether the USART Manchester Encoder/Decoder
// <id> usart_manchester_filter_enable
#ifndef CONF_USART_1_MAN
#define CONF_USART_1_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_1_MODSYNC
#define CONF_USART_1_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_1_ONEBIT
#define CONF_USART_1_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_1_FRACTIONAL
#define CONF_USART_1_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_1_MSBF
#define CONF_USART_1_MSBF 0
#endif
// </e>
#define CONF_USART_1_MODE 0x0
// Calculate BAUD register value in UART mode
#if CONF_USART1_CK_SRC < 3
#ifndef CONF_USART_1_BAUD_CD
#define CONF_USART_1_BAUD_CD ((CONF_USART1_FREQUENCY) / CONF_USART_1_BAUD / 8 / (2 - CONF_USART_1_OVER))
#endif
#ifndef CONF_USART_1_BAUD_FP
#define CONF_USART_1_BAUD_FP \
((CONF_USART1_FREQUENCY) / CONF_USART_1_BAUD / (2 - CONF_USART_1_OVER) - 8 * CONF_USART_1_BAUD_CD)
#endif
#elif CONF_USART1_CK_SRC == 3
// No division is active. The value written in US_BRGR has no effect.
#ifndef CONF_USART_1_BAUD_CD
#define CONF_USART_1_BAUD_CD 1
#endif
#ifndef CONF_USART_1_BAUD_FP
#define CONF_USART_1_BAUD_FP 1
#endif
#endif
// <<< end of configuration section >>>
#endif // HPL_USART_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/* 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 300000000
#endif
/**
* \def CONF_FCLK_FREQUENCY
* \brief FCLK's Clock frequency
*/
#ifndef CONF_FCLK_FREQUENCY
#define CONF_FCLK_FREQUENCY 300000000
#endif
/**
* \def CONF_CPU_FREQUENCY
* \brief CPU's Clock frequency
*/
#ifndef CONF_CPU_FREQUENCY
#define CONF_CPU_FREQUENCY 300000000
#endif
/**
* \def CONF_SLCK_FREQUENCY
* \brief Slow Clock frequency
*/
#define CONF_SLCK_FREQUENCY 0
/**
* \def CONF_MCK_FREQUENCY
* \brief Master Clock frequency
*/
#define CONF_MCK_FREQUENCY 150000000
/**
* \def CONF_PCK6_FREQUENCY
* \brief Programmable Clock Controller 6 frequency
*/
#define CONF_PCK6_FREQUENCY 1714285
// <h> USART Clock Settings
// <o> USART Clock source
// <0=> Master Clock (MCK)
// <1=> MCK / 8 for USART
// <2=> Programmable Clock Controller 4 (PMC_PCK4)
// <3=> External Clock
// <i> This defines the clock source for the USART
// <id> usart_clock_source
#ifndef CONF_USART1_CK_SRC
#define CONF_USART1_CK_SRC 0
#endif
// <o> USART External Clock Input on SCK <1-4294967295>
// <i> Inputs the external clock frequency on SCK
// <id> usart_clock_freq
#ifndef CONF_USART1_SCK_FREQ
#define CONF_USART1_SCK_FREQ 10000000
#endif
// </h>
/**
* \def USART FREQUENCY
* \brief USART's Clock frequency
*/
#ifndef CONF_USART1_FREQUENCY
#define CONF_USART1_FREQUENCY 150000000
#endif
#ifndef CONF_SRC_USB_480M
#define CONF_SRC_USB_480M 0
#endif
#ifndef CONF_SRC_USB_48M
#define CONF_SRC_USB_48M 1
#endif
// <y> USB Full/Low Speed Clock
// <CONF_SRC_USB_48M"> USB Clock Controller (USB_48M)
// <id> usb_fsls_clock_source
// <i> 48MHz clock source for low speed and full speed.
// <i> It must be available when low speed is supported by host driver.
// <i> It must be available when low power mode is selected.
#ifndef CONF_USBHS_FSLS_SRC
#define CONF_USBHS_FSLS_SRC CONF_SRC_USB_48M
#endif
// <y> USB Clock Source(Normal/Low-power Mode Selection)
// <CONF_SRC_USB_480M"> USB High Speed Clock (USB_480M)
// <CONF_SRC_USB_48M"> USB Clock Controller (USB_48M)
// <id> usb_clock_source
// <i> Select the clock source for USB.
// <i> In normal mode, use "USB High Speed Clock (USB_480M)".
// <i> In low-power mode, use "USB Clock Controller (USB_48M)".
#ifndef CONF_USBHS_SRC
#define CONF_USBHS_SRC CONF_SRC_USB_480M
#endif
/**
* \def CONF_USBHS_FSLS_FREQUENCY
* \brief USBHS's Full/Low Speed Clock Source frequency
*/
#ifndef CONF_USBHS_FSLS_FREQUENCY
#define CONF_USBHS_FSLS_FREQUENCY 48000000
#endif
/**
* \def CONF_USBHS_FREQUENCY
* \brief USBHS's Selected Clock Source frequency
*/
#ifndef CONF_USBHS_FREQUENCY
#define CONF_USBHS_FREQUENCY 480000000
#endif
// <<< end of configuration section >>>
#endif // PERIPHERAL_CLK_CONFIG_H

View File

@ -0,0 +1,159 @@
/*
* 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 "bsp/board.h"
#include "peripheral_clk_config.h"
#include "hpl/usart/hpl_usart_base.h"
#include "hpl/pmc/hpl_pmc.h"
#include "hal/include/hal_init.h"
#include "hal/include/hal_usart_async.h"
#include "hal/include/hal_gpio.h"
// You can get the board here:
// https://www.aliexpress.com/item/1005003173783268.html
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
#define LED_PIN GPIO(GPIO_PORTA, 15)
#define BUTTON_PIN GPIO(GPIO_PORTA, 21)
#define BUTTON_STATE_ACTIVE 0
#define UART_TX_PIN GPIO(GPIO_PORTB, 1)
#define UART_RX_PIN GPIO(GPIO_PORTB, 0)
static struct usart_async_descriptor edbg_com;
static uint8_t edbg_com_buffer[64];
static volatile bool uart_busy = false;
static void tx_cb_EDBG_COM(const struct usart_async_descriptor *const io_descr)
{
(void) io_descr;
uart_busy = false;
}
//------------- IMPLEMENTATION -------------//
void board_init(void)
{
init_mcu();
/* Disable Watchdog */
hri_wdt_set_MR_WDDIS_bit(WDT);
// LED
_pmc_enable_periph_clock(ID_PIOB);
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
_pmc_enable_periph_clock(ID_PIOA);
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_USART1);
gpio_set_pin_function(UART_RX_PIN, MUX_PA21A_USART1_RXD1);
gpio_set_pin_function(UART_TX_PIN, MUX_PB4D_USART1_TXD1);
usart_async_init(&edbg_com, USART1, edbg_com_buffer, sizeof(edbg_com_buffer), _usart_get_usart_async());
usart_async_set_baud_rate(&edbg_com, CFG_BOARD_UART_BAUDRATE);
usart_async_register_callback(&edbg_com, USART_ASYNC_TXC_CB, tx_cb_EDBG_COM);
usart_async_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
// Enable USB clock
_pmc_enable_periph_clock(ID_USBHS);
}
//--------------------------------------------------------------------+
// USB Interrupt Handler
//--------------------------------------------------------------------+
void USBHS_Handler(void)
{
tud_int_handler(0);
}
//--------------------------------------------------------------------+
// 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)
{
// while until previous transfer is complete
while(uart_busy) {}
uart_busy = true;
io_write(&edbg_com.io, buf, len);
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)
{
}

View File

@ -282,7 +282,7 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t* report_buf = p_hid->epin_buf;
uint16_t req_len = request->wLength;
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
uint16_t xferlen = 0;
@ -314,7 +314,7 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t const* report_buf = p_hid->epout_buf;
uint16_t report_len = request->wLength;
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )

View File

@ -32,6 +32,7 @@
#ifndef _TUSB_COMPILER_H_
#define _TUSB_COMPILER_H_
#define TU_TOKEN(x) x
#define TU_STRING(x) #x ///< stringify without expand
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
@ -41,6 +42,8 @@
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
#define TU_INCLUDE_PATH(_dir,_file) TU_XSTRING( TU_TOKEN(_dir)TU_TOKEN(_file) )
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
#define _TU_COUNTER_ __COUNTER__
#else

View File

@ -986,9 +986,11 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
uint16_t len = sizeof(tusb_desc_device_t);
// Only send up to EP0 Packet Size if not addressed
// Only send up to EP0 Packet Size if not addressed and host requested more data
// that device descriptor has.
// This only happens with the very first get device descriptor and EP0 size = 8 or 16.
if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed)
if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
((tusb_control_request_t*) p_request)->wLength > sizeof(tusb_desc_device_t))
{
len = CFG_TUD_ENDPOINT0_SIZE;
@ -1056,6 +1058,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
break;
case TUSB_DESC_DEVICE_QUALIFIER:
{
TU_LOG2(" Device Qualifier\r\n");
TU_VERIFY( tud_descriptor_device_qualifier_cb );
@ -1065,6 +1068,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
// first byte of descriptor is its size
return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]);
}
break;
default: return false;
@ -1392,7 +1396,13 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
TU_ASSERT(dcd_edpt_close, /**/);
TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_edpt_close(rhport, ep_addr);
_usbd_dev.ep_status[epnum][dir].stalled = false;
_usbd_dev.ep_status[epnum][dir].busy = false;
_usbd_dev.ep_status[epnum][dir].claimed = false;
return;
}

View File

@ -28,10 +28,10 @@
#define _TUSB_OSAL_FREERTOS_H_
// FreeRTOS Headers
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h)
#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h)
#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h)
#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h)
#ifdef __cplusplus
extern "C" {

View File

@ -193,8 +193,14 @@ typedef struct
#define REG_CLR_BIT(reg, field) USB->reg &= ~USB_ ## reg ## _ ## field ## _Msk
#define REG_SET_VAL(reg, field, val) USB->reg = (USB->reg & ~USB_ ## reg ## _ ## field ## _Msk) | (val << USB_ ## reg ## _ ## field ## _Pos)
static EPx_REGS * const ep_regs[EP_MAX] = {
EP_REGS(USB_EPC0_REG),
EP_REGS(USB_EPC1_REG),
EP_REGS(USB_EPC3_REG),
EP_REGS(USB_EPC5_REG),
};
typedef struct {
EPx_REGS * regs;
uint8_t * buffer;
// Total length of current transfer
uint16_t total_len;
@ -217,6 +223,7 @@ typedef struct {
static struct
{
bool vbus_present;
bool init_called;
bool in_reset;
xfer_ctl_t xfer_status[EP_MAX][2];
// Endpoints that use DMA, one for each direction
@ -224,15 +231,16 @@ static struct
} _dcd =
{
.vbus_present = false,
.xfer_status =
{
{ { .regs = EP_REGS(USB_EPC0_REG) }, { .regs = EP_REGS(USB_EPC0_REG) } },
{ { .regs = EP_REGS(USB_EPC1_REG) }, { .regs = EP_REGS(USB_EPC1_REG) } },
{ { .regs = EP_REGS(USB_EPC3_REG) }, { .regs = EP_REGS(USB_EPC3_REG) } },
{ { .regs = EP_REGS(USB_EPC5_REG) }, { .regs = EP_REGS(USB_EPC5_REG) } },
}
.init_called = false,
};
// Converts xfer pointer to epnum (0,1,2,3) regardless of xfer direction
#define XFER_EPNUM(xfer) ((xfer - &_dcd.xfer_status[0][0]) >> 1)
// Converts xfer pinter to EPx_REGS pointer (returns same pointer for IN and OUT with same endpoint number)
#define XFER_REGS(xfer) ep_regs[XFER_EPNUM(xfer)]
// Converts epnum (0,1,2,3) to EPx_REGS pointer
#define EPNUM_REGS(epnum) ep_regs[epnum]
// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
static const tusb_desc_endpoint_t ep0OUT_desc =
{
@ -262,8 +270,8 @@ static void fill_tx_fifo(xfer_ctl_t * xfer)
{
int left_to_send;
uint8_t const *src;
EPx_REGS *regs = xfer->regs;
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
EPx_REGS *regs = EPNUM_REGS(epnum);
src = &xfer->buffer[xfer->transferred];
left_to_send = xfer->total_len - xfer->transferred;
@ -291,7 +299,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer)
}
else
{
xfer->regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk;
regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk;
USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos));
// Whole packet already in fifo, no need to refill it later. Mark last.
regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk;
@ -332,30 +340,31 @@ static void start_rx_packet(xfer_ctl_t *xfer)
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint16_t remaining = xfer->total_len - xfer->transferred;
uint16_t size = tu_min16(remaining, xfer->max_packet_size);
EPx_REGS *regs = XFER_REGS(xfer);
xfer->last_packet_size = 0;
if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE)
{
if (try_allocate_dma(epnum, TUSB_DIR_OUT))
{
start_rx_dma(&xfer->regs->rxd, xfer->buffer + xfer->transferred, size);
start_rx_dma(&regs->rxd, xfer->buffer + xfer->transferred, size);
}
else
{
// Other endpoint is using DMA in that direction, fall back to interrupts.
// For endpoint size greater then FIFO size enable FIFO level warning interrupt
// when FIFO has less then 17 bytes free.
xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos);
}
}
else if (epnum != 0)
{
// If max_packet_size would fit in FIFO no need for FIFO level warning interrupt.
xfer->regs->rxc &= ~USB_USB_RXC1_REG_USB_RFWL_Msk;
regs->rxc &= ~USB_USB_RXC1_REG_USB_RFWL_Msk;
USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos));
}
xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
}
static void start_tx_dma(void *src, volatile void *dst, uint16_t size)
@ -374,13 +383,13 @@ static void start_tx_packet(xfer_ctl_t *xfer)
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint16_t remaining = xfer->total_len - xfer->transferred;
uint16_t size = tu_min16(remaining, xfer->max_packet_size);
EPx_REGS *regs = xfer->regs;
EPx_REGS *regs = EPNUM_REGS(epnum);
xfer->last_packet_size = 0;
regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk;
if (xfer->data1) xfer->regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk;
if (xfer->data1) regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk;
if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN))
{
@ -397,7 +406,7 @@ static void start_tx_packet(xfer_ctl_t *xfer)
static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
{
EPx_REGS *regs = xfer->regs;
EPx_REGS *regs = XFER_REGS(xfer);
uint16_t remaining = xfer->total_len - xfer->transferred - xfer->last_packet_size;
uint16_t receive_this_time = bytes_in_fifo;
@ -467,7 +476,7 @@ static void handle_ep0_tx(void)
{
uint32_t txs0;
xfer_ctl_t *xfer = XFER_CTL_BASE(0, TUSB_DIR_IN);
EPx_REGS *regs = xfer->regs;
EPx_REGS *regs = XFER_REGS(xfer);
txs0 = regs->USB_TXS0_REG;
@ -501,7 +510,7 @@ static void handle_epx_rx_ev(uint8_t ep)
int fifo_bytes;
xfer_ctl_t *xfer = XFER_CTL_BASE(ep, TUSB_DIR_OUT);
EPx_REGS *regs = xfer->regs;
EPx_REGS *regs = EPNUM_REGS(ep);
do
{
@ -580,7 +589,7 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer)
{
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint32_t txs;
EPx_REGS *regs = xfer->regs;
EPx_REGS *regs = EPNUM_REGS(epnum);
txs = regs->txs;
@ -735,19 +744,13 @@ static void handle_ep0_nak(void)
*------------------------------------------------------------------*/
void dcd_init(uint8_t rhport)
{
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
USB->USB_NFSR_REG = 0;
USB->USB_FAR_REG = 0x80;
USB->USB_NFSR_REG = NFSR_NODE_RESET;
USB->USB_TXMSK_REG = 0;
USB->USB_RXMSK_REG = 0;
(void) rhport;
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
USB_USB_MAMSK_REG_USB_M_ALT_Msk |
USB_USB_MAMSK_REG_USB_M_WARN_Msk;
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk;
dcd_connect(rhport);
_dcd.init_called = true;
if (_dcd.vbus_present)
{
dcd_connect(rhport);
}
}
void dcd_int_enable(uint8_t rhport)
@ -783,10 +786,25 @@ void dcd_connect(uint8_t rhport)
{
(void)rhport;
REG_SET_BIT(USB_MCTRL_REG, USB_NAT);
if (GET_BIT(USB->USB_MCTRL_REG, USB_USB_MCTRL_REG_USB_NAT) == 0)
{
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
USB->USB_NFSR_REG = 0;
USB->USB_FAR_REG = 0x80;
USB->USB_NFSR_REG = NFSR_NODE_RESET;
USB->USB_TXMSK_REG = 0;
USB->USB_RXMSK_REG = 0;
// Select chosen DMA to be triggered by USB.
DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX;
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
USB_USB_MAMSK_REG_USB_M_ALT_Msk |
USB_USB_MAMSK_REG_USB_M_WARN_Msk;
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk;
REG_SET_BIT(USB_MCTRL_REG, USB_NAT);
// Select chosen DMA to be triggered by USB.
DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX;
}
}
void dcd_disconnect(uint8_t rhport)
@ -796,6 +814,30 @@ void dcd_disconnect(uint8_t rhport)
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
}
TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
{
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
}
void tusb_vbus_changed(bool present)
{
if (present && !_dcd.vbus_present)
{
_dcd.vbus_present = true;
// If power event happened before USB started, delay dcd_connect
// until dcd_init is called.
if (_dcd.init_called)
{
dcd_connect(0);
}
}
else if (!present && _dcd.vbus_present)
{
_dcd.vbus_present = false;
USB->USB_MCTRL_REG = 0;
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
}
}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
@ -808,6 +850,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
EPx_REGS *regs = EPNUM_REGS(epnum);
uint8_t iso_mask = 0;
TU_ASSERT(epnum < EP_MAX);
@ -832,13 +875,13 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
if (dir == TUSB_DIR_OUT)
{
xfer->regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
USB->USB_RXMSK_REG |= 0x101 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_RX_EV);
}
else
{
xfer->regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
USB->USB_TXMSK_REG |= 0x101 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
}
@ -850,13 +893,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
// TODO implement dcd_edpt_close_all()
for (int epnum = 1; epnum < EP_MAX; ++epnum)
{
dcd_edpt_close(0, epnum | TUSB_DIR_OUT);
dcd_edpt_close(0, epnum | TUSB_DIR_IN);
}
}
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
EPx_REGS *regs = EPNUM_REGS(epnum);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
(void)rhport;
@ -872,8 +921,8 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
if (dir == TUSB_DIR_OUT)
{
xfer->regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
xfer->regs->epc_out = 0;
regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
regs->epc_out = 0;
USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
@ -884,8 +933,8 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
}
else
{
xfer->regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
xfer->regs->epc_in = 0;
regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
regs->epc_in = 0;
USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
@ -895,6 +944,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
}
}
}
tu_memclr(xfer, sizeof(*xfer));
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
@ -930,6 +980,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
(void)rhport;
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
EPx_REGS *regs = EPNUM_REGS(epnum);
xfer->stall = 1;
if (epnum == 0)
@ -938,11 +989,11 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
REG_SET_BIT(USB_EPC0_REG, USB_STALL);
if (dir == TUSB_DIR_OUT)
{
xfer->regs->USB_RXC0_REG = USB_USB_RXC0_REG_USB_RX_EN_Msk;
regs->USB_RXC0_REG = USB_USB_RXC0_REG_USB_RX_EN_Msk;
}
else
{
if (xfer->regs->USB_RXC0_REG & USB_USB_RXC0_REG_USB_RX_EN_Msk)
if (regs->USB_RXC0_REG & USB_USB_RXC0_REG_USB_RX_EN_Msk)
{
// If RX is also enabled TX will not be stalled since RX has
// higher priority. Enable NAK interrupt to handle stall.
@ -950,7 +1001,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
}
else
{
xfer->regs->USB_TXC0_REG |= USB_USB_TXC0_REG_USB_TX_EN_Msk;
regs->USB_TXC0_REG |= USB_USB_TXC0_REG_USB_TX_EN_Msk;
}
}
}
@ -958,13 +1009,13 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
if (dir == TUSB_DIR_OUT)
{
xfer->regs->epc_out |= USB_USB_EPC1_REG_USB_STALL_Msk;
xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
regs->epc_out |= USB_USB_EPC1_REG_USB_STALL_Msk;
regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
}
else
{
xfer->regs->epc_in |= USB_USB_EPC1_REG_USB_STALL_Msk;
xfer->regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_LAST_Msk;
regs->epc_in |= USB_USB_EPC1_REG_USB_STALL_Msk;
regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_LAST_Msk;
}
}
}
@ -977,6 +1028,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
(void)rhport;
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
EPx_REGS *regs = EPNUM_REGS(epnum);
// Clear stall is called in response to Clear Feature ENDPOINT_HALT, reset toggle
xfer->data1 = 0;
@ -984,11 +1036,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
if (dir == TUSB_DIR_OUT)
{
xfer->regs->epc_out &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
regs->epc_out &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
}
else
{
xfer->regs->epc_in &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
regs->epc_in &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
}
if (epnum == 0)
{

View File

@ -52,23 +52,23 @@ typedef struct TU_ATTR_PACKED
struct {
union {
struct {
uint16_t : 2;
uint16_t tok_pid : 4;
uint16_t data : 1;
uint16_t own : 1;
uint16_t : 8;
uint16_t : 2;
__IO uint16_t tok_pid : 4;
uint16_t data : 1;
__IO uint16_t own : 1;
uint16_t : 8;
};
struct {
uint16_t : 2;
uint16_t bdt_stall: 1;
uint16_t dts : 1;
uint16_t ninc : 1;
uint16_t keep : 1;
uint16_t : 10;
uint16_t : 2;
uint16_t bdt_stall : 1;
uint16_t dts : 1;
uint16_t ninc : 1;
uint16_t keep : 1;
uint16_t : 10;
};
};
uint16_t bc : 10;
uint16_t : 6;
__IO uint16_t bc : 10;
uint16_t : 6;
};
};
uint8_t *addr;
@ -120,10 +120,8 @@ static void prepare_next_setup_packet(uint8_t rhport)
{
const unsigned out_odd = _dcd.endpoint[0][0].odd;
const unsigned in_odd = _dcd.endpoint[0][1].odd;
if (_dcd.bdt[0][0][out_odd].own) {
TU_LOG1("DCD fail to prepare the next SETUP %d %d\r\n", out_odd, in_odd);
return;
}
TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
_dcd.bdt[0][0][out_odd].data = 0;
_dcd.bdt[0][0][out_odd ^ 1].data = 1;
_dcd.bdt[0][1][in_odd].data = 1;
@ -134,10 +132,16 @@ static void prepare_next_setup_packet(uint8_t rhport)
static void process_stall(uint8_t rhport)
{
if (KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_EPSTALL_MASK) {
/* clear stall condition of the control pipe */
prepare_next_setup_packet(rhport);
KHCI->ENDPOINT[0].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
for (int i = 0; i < 16; ++i) {
unsigned const endpt = KHCI->ENDPOINT[i].ENDPT;
if (endpt & USB_ENDPT_EPSTALL_MASK) {
// prepare next setup if endpoint0
if ( i == 0 ) prepare_next_setup_packet(rhport);
// clear stall bit
KHCI->ENDPOINT[i].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
}
}
}
@ -145,12 +149,17 @@ static void process_tokdne(uint8_t rhport)
{
const unsigned s = KHCI->STAT;
KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
/* fetch pid before discarded by the next steps */
const unsigned pid = bd->tok_pid;
/* reset values for a next transfer */
bd->bdt_stall = 0;
bd->dts = 1;
@ -163,9 +172,6 @@ static void process_tokdne(uint8_t rhport)
KHCI->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
return;
}
if (s >> 4) {
TU_LOG1("TKDNE %x\r\n", s);
}
const unsigned bc = bd->bc;
const unsigned remaining = ep->remaining - bc;
@ -184,9 +190,9 @@ static void process_tokdne(uint8_t rhport)
}
const unsigned length = ep->length;
dcd_event_xfer_complete(rhport,
((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT),
tu_edpt_addr(epnum, dir),
length - remaining, XFER_RESULT_SUCCESS, true);
if (0 == (s & USB_STAT_ENDP_MASK) && 0 == length) {
if (0 == epnum && 0 == length) {
/* After completion a ZLP of control transfer,
* it prepares for the next steup transfer. */
if (_dcd.addr) {
@ -204,7 +210,8 @@ static void process_bus_reset(uint8_t rhport)
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
KHCI->CTL |= USB_CTL_ODDRST_MASK;
KHCI->ADDR = 0;
KHCI->INTEN = (KHCI->INTEN & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
for (unsigned i = 1; i < 16; ++i) {
@ -229,21 +236,27 @@ static void process_bus_reset(uint8_t rhport)
dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
}
static void process_bus_inactive(uint8_t rhport)
static void process_bus_sleep(uint8_t rhport)
{
(void) rhport;
// Enable resume & disable suspend interrupt
const unsigned inten = KHCI->INTEN;
KHCI->INTEN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
KHCI->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
KHCI->USBCTRL |= USB_USBCTRL_SUSP_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
static void process_bus_active(uint8_t rhport)
static void process_bus_resume(uint8_t rhport)
{
(void) rhport;
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
// Enable suspend & disable resume interrupt
const unsigned inten = KHCI->INTEN;
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
KHCI->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
KHCI->INTEN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
}
@ -256,12 +269,15 @@ void dcd_init(uint8_t rhport)
KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
tu_memclr(&_dcd, sizeof(_dcd));
KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
KHCI->INTEN = USB_INTEN_USBRSTEN_MASK;
dcd_connect(rhport);
NVIC_ClearPendingIRQ(USB0_IRQn);
}
@ -269,8 +285,6 @@ void dcd_init(uint8_t rhport)
void dcd_int_enable(uint8_t rhport)
{
(void) rhport;
KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
NVIC_EnableIRQ(USB0_IRQn);
}
@ -278,13 +292,11 @@ void dcd_int_disable(uint8_t rhport)
{
(void) rhport;
NVIC_DisableIRQ(USB0_IRQn);
KHCI->INTEN = 0;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
_dcd.addr = dev_addr & 0x7F;
_dcd.addr = dev_addr & 0x7F;
/* Response with status first before changing device address */
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
}
@ -292,9 +304,12 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
unsigned cnt = SystemCoreClock / 100;
KHCI->CTL |= USB_CTL_RESUME_MASK;
unsigned cnt = SystemCoreClock / 1000;
while (cnt--) __NOP();
KHCI->CTL &= ~USB_CTL_RESUME_MASK;
}
@ -321,12 +336,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
(void) rhport;
const unsigned ep_addr = ep_desc->bEndpointAddress;
const unsigned epn = ep_addr & 0xFu;
const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
const unsigned epn = tu_edpt_number(ep_addr);
const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned xfer = ep_desc->bmAttributes.xfer;
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
const unsigned odd = ep->odd;
buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
/* No support for control transfer */
TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
@ -347,41 +362,60 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
void dcd_edpt_close_all (uint8_t rhport)
void dcd_edpt_close_all(uint8_t rhport)
{
(void) rhport;
// TODO implement dcd_edpt_close_all()
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
for (unsigned i = 1; i < 16; ++i) {
KHCI->ENDPOINT[i].ENDPT = 0;
}
if (ie) NVIC_EnableIRQ(USB0_IRQn);
buffer_descriptor_t *bd = _dcd.bdt[1][0];
for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
bd->head = 0;
}
endpoint_state_t *ep = &_dcd.endpoint[1][0];
for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
/* Clear except the odd */
ep->max_packet_size = 0;
ep->length = 0;
ep->remaining = 0;
}
}
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
const unsigned epn = ep_addr & 0xFu;
const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
const unsigned epn = tu_edpt_number(ep_addr);
const unsigned dir = tu_edpt_dir(ep_addr);
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
KHCI->ENDPOINT[epn].ENDPT &= ~msk;
ep->max_packet_size = 0;
ep->length = 0;
ep->remaining = 0;
bd->head = 0;
bd[0].head = 0;
bd[1].head = 0;
if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
(void) rhport;
NVIC_DisableIRQ(USB0_IRQn);
const unsigned epn = ep_addr & 0xFu;
const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
const unsigned epn = tu_edpt_number(ep_addr);
const unsigned dir = tu_edpt_dir(ep_addr);
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
TU_ASSERT(0 == bd->own);
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
if (bd->own) {
TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head);
return false; /* The last transfer has not completed */
}
ep->length = total_bytes;
ep->remaining = total_bytes;
@ -394,42 +428,69 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
next->addr = buffer + mps;
next->own = 1;
}
bd->bc = total_bytes >= mps ? mps: total_bytes;
bd->addr = buffer;
bd->bc = total_bytes >= mps ? mps: total_bytes;
bd->addr = buffer;
__DSB();
bd->own = 1; /* the own bit must set after addr */
NVIC_EnableIRQ(USB0_IRQn);
bd->own = 1; /* This bit must be set last */
if (ie) NVIC_EnableIRQ(USB0_IRQn);
return true;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
const unsigned epn = ep_addr & 0xFu;
const unsigned epn = tu_edpt_number(ep_addr);
if (0 == epn) {
KHCI->ENDPOINT[epn].ENDPT |= USB_ENDPT_EPSTALL_MASK;
} else {
const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
bd[0].bdt_stall = 1;
bd[1].bdt_stall = 1;
const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned odd = _dcd.endpoint[epn][dir].odd;
buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
TU_ASSERT(0 == bd->own,);
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
bd->bdt_stall = 1;
__DSB();
bd->own = 1; /* This bit must be set last */
if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
const unsigned epn = ep_addr & 0xFu;
const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
const unsigned epn = tu_edpt_number(ep_addr);
TU_VERIFY(epn,);
const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned odd = _dcd.endpoint[epn][dir].odd;
buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
TU_VERIFY(bd[odd].own,);
bd[odd ^ 1].own = 0;
bd[odd ^ 1].data = 1;
bd[odd ^ 1].bdt_stall = 0;
bd[odd].own = 0;
bd[odd].data = 0;
bd[odd].bdt_stall = 0;
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
bd[odd].own = 0;
__DSB();
// clear stall
bd[odd].bdt_stall = 0;
// Reset data toggle
bd[odd ].data = 0;
bd[odd ^ 1].data = 1;
// We already cleared this in ISR, but just clear it here to be safe
const unsigned endpt = KHCI->ENDPOINT[epn].ENDPT;
if (endpt & USB_ENDPT_EPSTALL_MASK) {
KHCI->ENDPOINT[epn].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
}
if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
//--------------------------------------------------------------------+
@ -437,48 +498,59 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
void dcd_int_handler(uint8_t rhport)
{
(void) rhport;
uint32_t is = KHCI->ISTAT;
uint32_t msk = KHCI->INTEN;
// clear non-enabled interrupts
KHCI->ISTAT = is & ~msk;
is &= msk;
if (is & USB_ISTAT_ERROR_MASK) {
/* TODO: */
uint32_t es = KHCI->ERRSTAT;
KHCI->ERRSTAT = es;
KHCI->ISTAT = is; /* discard any pending events */
return;
}
if (is & USB_ISTAT_USBRST_MASK) {
KHCI->ISTAT = is; /* discard any pending events */
process_bus_reset(rhport);
return;
}
if (is & USB_ISTAT_SLEEP_MASK) {
// TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
// Note Host usually has extra delay after bus reset (without SOF), which could falsely
// detected as Sleep event. Though usbd has debouncing logic so we are good
KHCI->ISTAT = USB_ISTAT_SLEEP_MASK;
process_bus_inactive(rhport);
return;
process_bus_sleep(rhport);
}
#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
if (is & USB_ISTAT_RESUME_MASK) {
// TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
process_bus_active(rhport);
return;
process_bus_resume(rhport);
}
#endif
if (KHCI->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
// TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
process_bus_resume(rhport);
}
if (is & USB_ISTAT_SOFTOK_MASK) {
KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
return;
}
if (is & USB_ISTAT_STALL_MASK) {
KHCI->ISTAT = USB_ISTAT_STALL_MASK;
process_stall(rhport);
return;
}
if (is & USB_ISTAT_TOKDNE_MASK) {
process_tokdne(rhport);
return;
}
}

View File

@ -134,7 +134,8 @@ typedef struct
// QHD is 64 bytes aligned but occupies only 48 bytes
// Therefore there are 16 bytes padding that we can use.
//--------------------------------------------------------------------+
uint8_t reserved[16];
tu_fifo_t * ff;
uint8_t reserved[12];
} dcd_qhd_t;
TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
@ -240,8 +241,9 @@ void dcd_init(uint8_t rhport)
dcd_reg->USBMODE = USBMODE_CM_DEVICE;
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
// TODO Force fullspeed on non-highspeed port
// dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
#if !TUD_OPT_HIGH_SPEED
dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
#endif
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
@ -296,18 +298,30 @@ void dcd_disconnect(uint8_t rhport)
static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
{
// Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
// address to 32-byte boundaries. Buffer must be word aligned
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
p_qtd->next = QTD_NEXT_INVALID;
p_qtd->active = 1;
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
p_qtd->next = QTD_NEXT_INVALID;
p_qtd->active = 1;
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
p_qtd->int_on_complete = true;
if (data_ptr != NULL)
{
p_qtd->buffer[0] = (uint32_t) data_ptr;
p_qtd->buffer[0] = (uint32_t) data_ptr;
uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
for(uint8_t i=1; i<5; i++)
{
p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
if ( bufend <= next_page ) break;
p_qtd->buffer[i] = next_page;
// TODO page[1] FRAME_N for ISO transfer
}
}
}
@ -340,9 +354,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
// TODO not support ISO yet
TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
@ -355,13 +366,27 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
p_qhd->zero_length_termination = 1;
p_qhd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
{
p_qhd->iso_mult = 1;
}
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
// Enable EP Control
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->ENDPTCTRL[epnum] |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
if ( dir == TUSB_DIR_OUT )
{
dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
}else
{
dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
}
return true;
}
@ -381,11 +406,35 @@ void dcd_edpt_close_all (uint8_t rhport)
}
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
_dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
// Flush EP
uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
dcd_reg->ENDPTFLUSH = flush_mask;
while(dcd_reg->ENDPTFLUSH & flush_mask);
// Clear EP enable
dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
}
static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
{
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
p_qhd->qtd_overlay.halted = false; // clear any previous error
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
// flush cache
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
if ( epnum == 0 )
{
@ -394,25 +443,87 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
}
// start transfer
dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
// Prepare qtd
qtd_init(p_qtd, buffer, total_bytes);
// Start qhd transfer
p_qhd->ff = NULL;
qhd_start_xfer(rhport, epnum, dir);
return true;
}
// fifo has to be aligned to 4k boundary
bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
// Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
// address to 32-byte boundaries.
// void* cast to suppress cast-align warning, buffer must be
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
tu_fifo_buffer_info_t fifo_info;
//------------- Prepare qtd -------------//
qtd_init(p_qtd, buffer, total_bytes);
p_qtd->int_on_complete = true;
if (dir)
{
tu_fifo_get_read_info(ff, &fifo_info);
} else
{
tu_fifo_get_write_info(ff, &fifo_info);
}
p_qhd->qtd_overlay.halted = false; // clear any previous error
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // activate by linking qtd to qhd
if ( fifo_info.len_lin >= total_bytes )
{
// Linear length is enough for this transfer
qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
}
else
{
// linear part is not enough
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
// prepare TD up to linear length
qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
// start transfer
dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
{
// If buffer is aligned to 4K & buffer size is multiple of 4K
// We can make use of buffer page array to also combine the linear + wrapped length
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
for(uint8_t i = 1, page = 0; i < 5; i++)
{
// pick up buffer array where linear ends
if (p_qtd->buffer[i] == 0)
{
p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
page++;
}
}
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
}
else
{
// TODO we may need to carry the wrapped length after the linear part complete
// for now only transfer up to linear part
}
}
// Start qhd transfer
p_qhd->ff = ff;
qhd_start_xfer(rhport, epnum, dir);
return true;
}
@ -423,6 +534,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
{
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
@ -435,8 +547,21 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir
dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
}
uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
if (p_qhd->ff)
{
if (dir == TUSB_DIR_IN)
{
tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
} else
{
tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
}
}
// only number of bytes in the IOC qtd
dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true);
dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
}
void dcd_int_handler(uint8_t rhport)

View File

@ -203,14 +203,20 @@
#define CFG_TUSB_MEM_SECTION
#endif
// alignment requirement of buffer used for endpoint transferring
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
#endif
// OS selection
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_OS_INC_PATH
#define CFG_TUSB_OS_INC_PATH
#endif
//--------------------------------------------------------------------
// DEVICE OPTIONS
//--------------------------------------------------------------------