mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-15 20:42:23 +00:00
update to dcd ip3511 to add work-around for lpc54628 usb hs errata USB.1 and USB.2
msc is mounted, but device couldn't work reliably and got constant reset due to other errata probably.
This commit is contained in:
parent
6d877c3170
commit
b8b01c1075
4
.idea/cmake.xml
generated
4
.idea/cmake.xml
generated
@ -30,7 +30,8 @@
|
||||
<configuration PROFILE_NAME="mcb1800" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mcb1800 -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="ea4088 quickstart" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=ea4088_quickstart -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="ea4357" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=ea4357 -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="lpc55s69" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=lpcxpresso55s69" />
|
||||
<configuration PROFILE_NAME="lpc54628" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=lpcxpresso54628 -DLOG=4 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="lpc55s69" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=lpcxpresso55s69 -DLOG=4 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="mcxn947" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mcxn947brk -DLOG=3 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="pca10056" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pca10056 -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="pca10095" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pca10095 -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
@ -51,6 +52,7 @@
|
||||
<configuration PROFILE_NAME="ra6m5 PORT0" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=ra6m5_ek -DLOG=3 -DLOGGER=RTT -DTRACE_ETM=1 -DPORT=0" />
|
||||
<configuration PROFILE_NAME="uno_r4" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=uno_r4 -DLOG=4 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="portenta_c33" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=portenta_c33 -DLOG=3" />
|
||||
<configuration PROFILE_NAME="lpc54628 PORT0" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=lpcxpresso54628 -DLOG=4 -DLOGGER=RTT -DPORT=0" />
|
||||
</configurations>
|
||||
</component>
|
||||
</project>
|
@ -70,13 +70,11 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// Forward USB interrupt events to TinyUSB IRQ Handler
|
||||
//--------------------------------------------------------------------+
|
||||
void USB0_IRQHandler(void)
|
||||
{
|
||||
void USB0_IRQHandler(void) {
|
||||
tud_int_handler(0);
|
||||
}
|
||||
|
||||
void USB1_IRQHandler(void)
|
||||
{
|
||||
void USB1_IRQHandler(void) {
|
||||
tud_int_handler(1);
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ function(add_board_target BOARD_TARGET)
|
||||
BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED
|
||||
BOARD_TUH_MAX_SPEED=OPT_MODE_HIGH_SPEED
|
||||
CFG_TUH_MEM_SECTION=__attribute__\(\(section\(\"m_usb_global\"\)\)\)
|
||||
#CFG_TUD_MEM_SECTION=__attribute__\(\(section\(\"m_usb_global\"\)\)\)
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
@ -159,11 +159,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
|
||||
|
||||
//------------- Align -------------//
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) {
|
||||
return value & ((uint32_t) ~(alignment-1));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4 (uint32_t value) { return (value & 0xFFFFFFFCUL); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align8 (uint32_t value) { return (value & 0xFFFFFFF8UL); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
|
||||
|
@ -58,6 +58,7 @@
|
||||
// NXP
|
||||
//--------------------------------------------------------------------+
|
||||
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
|
||||
#define TUP_USBIP_IP3511
|
||||
#define TUP_DCD_ENDPOINT_MAX 5
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
|
||||
@ -66,14 +67,17 @@
|
||||
#define TUP_OHCI_RHPORTS 2
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
|
||||
#define TUP_USBIP_IP3511
|
||||
#define TUP_DCD_ENDPOINT_MAX 5
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC54)
|
||||
// TODO USB0 has 5, USB1 has 6
|
||||
#define TUP_USBIP_IP3511
|
||||
#define TUP_DCD_ENDPOINT_MAX 6
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC55)
|
||||
// TODO USB0 has 5, USB1 has 6
|
||||
#define TUP_USBIP_IP3511
|
||||
#define TUP_DCD_ENDPOINT_MAX 6
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
|
||||
|
@ -34,18 +34,13 @@
|
||||
* - LPC54114
|
||||
* - LPC55s69
|
||||
*/
|
||||
#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_LPC13XX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_LPC15XX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_LPC55XX)
|
||||
#if CFG_TUD_ENABLED && defined(TUP_USBIP_IP3511)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13XX || CFG_TUSB_MCU == OPT_MCU_LPC15XX
|
||||
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
|
||||
// LPCOpen
|
||||
#include "chip.h"
|
||||
#else
|
||||
@ -80,7 +75,7 @@ typedef struct {
|
||||
enum {
|
||||
NBYTES_ISO_FS_MAX = 1023, // FS ISO
|
||||
NBYTES_ISO_HS_MAX = 1024, // HS ISO
|
||||
NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt
|
||||
NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt. TODO some FS can do burst with higher size e.g 1024. Need to test
|
||||
NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
|
||||
};
|
||||
|
||||
@ -90,26 +85,36 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
CMDSTAT_DEVICE_ADDR_MASK = TU_BIT(7 )-1,
|
||||
CMDSTAT_DEVICE_ENABLE_MASK = TU_BIT(7 ),
|
||||
CMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ),
|
||||
CMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), // reflect the soft-connect only, does not reflect the actual attached state
|
||||
CMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17),
|
||||
// 23-22 is link speed (only available for HighSpeed port)
|
||||
CMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24),
|
||||
CMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25),
|
||||
CMDSTAT_RESET_CHANGE_MASK = TU_BIT(26),
|
||||
CMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28),
|
||||
DEVCMDSTAT_DEVICE_ADDR_MASK = TU_BIT(7 )-1,
|
||||
DEVCMDSTAT_DEVICE_ENABLE_MASK = TU_BIT(7 ),
|
||||
DEVCMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ),
|
||||
DEVCMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), // reflect the soft-connect only, does not reflect the actual attached state
|
||||
DEVCMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17),
|
||||
// 23-22 is link speed (only available for HighSpeed port)
|
||||
DEVCMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24),
|
||||
DEVCMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25),
|
||||
DEVCMDSTAT_RESET_CHANGE_MASK = TU_BIT(26),
|
||||
DEVCMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28),
|
||||
};
|
||||
|
||||
enum {
|
||||
CMDSTAT_SPEED_SHIFT = 22
|
||||
DEVCMDSTAT_SPEED_SHIFT = 22
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint Command/Status List
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// EP Command/Status field definition
|
||||
enum {
|
||||
EPCS_TYPE = TU_BIT(26),
|
||||
EPCS_RF_TV = TU_BIT(27),
|
||||
EPCS_TOGGLE_RESET = TU_BIT(28),
|
||||
EPCS_STALL = TU_BIT(29),
|
||||
EPCS_DISABLED = TU_BIT(30),
|
||||
EPCS_ACTIVE = TU_BIT(31),
|
||||
};
|
||||
|
||||
// Endpoint Command/Status
|
||||
typedef union TU_ATTR_PACKED
|
||||
{
|
||||
@ -133,8 +138,8 @@ typedef union TU_ATTR_PACKED
|
||||
|
||||
volatile struct {
|
||||
uint32_t TU_RESERVED : 26;
|
||||
uint32_t is_iso : 1 ;
|
||||
uint32_t toggle_mode : 1 ;
|
||||
uint32_t type : 1 ;
|
||||
uint32_t rf_tv : 1 ; // rate feedback or toggle value
|
||||
uint32_t toggle_reset : 1 ;
|
||||
uint32_t stall : 1 ;
|
||||
uint32_t disable : 1 ;
|
||||
@ -180,6 +185,7 @@ typedef struct
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
|
||||
|
||||
// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
|
||||
// TODO find way to save memory
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -188,59 +194,73 @@ CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dcd_registers_t* regs; // registers
|
||||
const tusb_speed_t max_speed; // max link speed
|
||||
const IRQn_Type irqnum; // IRQ number
|
||||
const uint8_t ep_pairs; // Max bi-directional Endpoints
|
||||
dcd_registers_t* regs; // registers
|
||||
const bool is_highspeed; // max link speed
|
||||
const IRQn_Type irqnum; // IRQ number
|
||||
const uint8_t ep_pairs; // Max bi-directional Endpoints
|
||||
}dcd_controller_t;
|
||||
|
||||
#ifdef INCLUDE_FSL_DEVICE_REGISTERS
|
||||
|
||||
static const dcd_controller_t _dcd_controller[] =
|
||||
{
|
||||
{ .regs = (dcd_registers_t*) USB0_BASE , .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = FSL_FEATURE_USB_EP_NUM },
|
||||
static const dcd_controller_t _dcd_controller[] = {
|
||||
{ .regs = (dcd_registers_t*) USB0_BASE , .is_highspeed = false, .irqnum = USB0_IRQn, .ep_pairs = FSL_FEATURE_USB_EP_NUM },
|
||||
#if defined(FSL_FEATURE_SOC_USBHSD_COUNT) && FSL_FEATURE_SOC_USBHSD_COUNT
|
||||
{ .regs = (dcd_registers_t*) USBHSD_BASE, .max_speed = TUSB_SPEED_HIGH, .irqnum = USB1_IRQn, .ep_pairs = FSL_FEATURE_USBHSD_EP_NUM }
|
||||
{ .regs = (dcd_registers_t*) USBHSD_BASE, .is_highspeed = true, .irqnum = USB1_IRQn, .ep_pairs = FSL_FEATURE_USBHSD_EP_NUM }
|
||||
#endif
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
static const dcd_controller_t _dcd_controller[] =
|
||||
{
|
||||
{ .regs = (dcd_registers_t*) LPC_USB0_BASE, .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = 5 },
|
||||
static const dcd_controller_t _dcd_controller[] = {
|
||||
{ .regs = (dcd_registers_t*) LPC_USB0_BASE, .is_highspeed = false, .irqnum = USB0_IRQn, .ep_pairs = 5 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FSL_FEATURE_SOC_USBHSD_COUNT) && FSL_FEATURE_SOC_USBHSD_COUNT
|
||||
#define IP3511_HAS_HIGHSPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static inline uint16_t get_buf_offset(void const * buffer)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint16_t get_buf_offset(void const * buffer) {
|
||||
uint32_t addr = (uint32_t) buffer;
|
||||
TU_ASSERT( (addr & 0x3f) == 0, 0 );
|
||||
return ( (addr >> 6) & 0xFFFFUL ) ;
|
||||
}
|
||||
|
||||
static inline uint8_t ep_addr2id(uint8_t ep_addr)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t ep_addr2id(uint8_t ep_addr) {
|
||||
return 2*(ep_addr & 0x0F) + ((ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(ep_cmd_sts_t* ep_cs, bool is_highspeed) {
|
||||
return is_highspeed ? (ep_cs[0].cmd_sts.type && !ep_cs[0].cmd_sts.rf_tv) : ep_cs->cmd_sts.type;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool ep_is_bulk(ep_cmd_sts_t* ep_cs) {
|
||||
return (ep_cs[0].cmd_sts.type == 0) && (ep_cs[0].cmd_sts.rf_tv == 0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline ep_cmd_sts_t* get_ep_cs(uint8_t ep_id) {
|
||||
return _dcd.ep[ep_id];
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool rhport_is_highspeed(uint8_t rhport) {
|
||||
return _dcd_controller[rhport].is_highspeed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROLLER API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void prepare_setup_packet(uint8_t rhport)
|
||||
{
|
||||
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
|
||||
{
|
||||
_dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);
|
||||
}else
|
||||
{
|
||||
_dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);
|
||||
static void prepare_setup_packet(uint8_t rhport) {
|
||||
uint16_t const buf_offset = get_buf_offset(_dcd.setup_packet);
|
||||
if ( _dcd_controller[rhport].is_highspeed ) {
|
||||
_dcd.ep[0][1].buffer_hs.offset = buf_offset;
|
||||
} else {
|
||||
_dcd.ep[0][1].buffer_fs.offset = buf_offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,8 +288,8 @@ void dcd_init(uint8_t rhport)
|
||||
dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment
|
||||
dcd_reg->INTSTAT |= dcd_reg->INTSTAT; // clear all pending interrupt
|
||||
dcd_reg->INTEN = INT_DEVICE_STATUS_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
|
||||
CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK |
|
||||
DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
|
||||
NVIC_ClearPendingIRQ(_dcd_controller[rhport].irqnum);
|
||||
}
|
||||
@ -291,7 +311,7 @@ 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);
|
||||
|
||||
dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK;
|
||||
dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_ADDR_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= dev_addr;
|
||||
}
|
||||
|
||||
@ -303,13 +323,13 @@ void dcd_remote_wakeup(uint8_t rhport)
|
||||
void dcd_connect(uint8_t rhport)
|
||||
{
|
||||
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||
dcd_reg->DEVCMDSTAT |= CMDSTAT_DEVICE_CONNECT_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_CONNECT_MASK;
|
||||
}
|
||||
|
||||
void dcd_disconnect(uint8_t rhport)
|
||||
{
|
||||
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||
dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK;
|
||||
dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_CONNECT_MASK;
|
||||
}
|
||||
|
||||
void dcd_sof_enable(uint8_t rhport, bool en)
|
||||
@ -340,19 +360,39 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
|
||||
_dcd.ep[ep_id][0].cmd_sts.stall = 0;
|
||||
_dcd.ep[ep_id][0].cmd_sts.toggle_reset = 1;
|
||||
_dcd.ep[ep_id][0].cmd_sts.toggle_mode = 0;
|
||||
_dcd.ep[ep_id][0].cmd_sts.rf_tv = 0;
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||
{
|
||||
//------------- Prepare Queue Head -------------//
|
||||
uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress);
|
||||
ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id);
|
||||
|
||||
// Check if endpoint is available
|
||||
TU_ASSERT( _dcd.ep[ep_id][0].cmd_sts.disable && _dcd.ep[ep_id][1].cmd_sts.disable );
|
||||
TU_ASSERT( ep_cs[0].cmd_sts.disable && ep_cs[1].cmd_sts.disable );
|
||||
|
||||
edpt_reset(rhport, ep_id);
|
||||
_dcd.ep[ep_id][0].cmd_sts.is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
|
||||
|
||||
switch (p_endpoint_desc->bmAttributes.xfer) {
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
ep_cs[0].cmd_sts.type = 1;
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
// What is interrupt endpoint in rate feedback mode ?
|
||||
if ( rhport_is_highspeed(rhport) ) {
|
||||
ep_cs[0].cmd_sts.type = 1;
|
||||
ep_cs[0].cmd_sts.rf_tv = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_BULK:
|
||||
// nothing to do both type and rf_tv are 0
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Enable EP interrupt
|
||||
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||
@ -379,42 +419,50 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
|
||||
_dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1;
|
||||
}
|
||||
|
||||
static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
|
||||
{
|
||||
static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes) {
|
||||
uint16_t nbytes;
|
||||
ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id);
|
||||
|
||||
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
|
||||
{
|
||||
nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].cmd_sts.is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
|
||||
_dcd.ep[ep_id][0].buffer_fs.offset = buf_offset;
|
||||
_dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes;
|
||||
}else
|
||||
{
|
||||
nbytes = tu_min16(total_bytes, NBYTES_CBI_HS_MAX);
|
||||
_dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
|
||||
_dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
|
||||
const bool is_iso = ep_is_iso(ep_cs, _dcd_controller[rhport].is_highspeed);
|
||||
|
||||
if ( rhport_is_highspeed(rhport) ) {
|
||||
nbytes = tu_min16(total_bytes, is_iso ? NBYTES_ISO_HS_MAX : NBYTES_CBI_HS_MAX);
|
||||
#if TU_CHECK_MCU(OPT_MCU_LPC54)
|
||||
// LPC54 Errata USB.1: In USB high-speed device mode, the NBytes field does not decrement after BULK OUT transfer.
|
||||
// Suggested Work-around: Program the NByte to the max packet size (512)
|
||||
// Actual Work-around: round up NByte to multiple of 4.
|
||||
// Note: this can cause buffer overflowed and corrupt data if host send more data than total_bytes
|
||||
if ( (ep_id > 1) && (ep_id & 0x01) == 0 && ep_is_bulk(ep_cs) ) {
|
||||
if ( nbytes & 0x03 ) {
|
||||
nbytes = tu_align4(nbytes) + 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ep_cs[0].buffer_hs.offset = buf_offset;
|
||||
ep_cs[0].buffer_hs.nbytes = nbytes;
|
||||
}else {
|
||||
nbytes = tu_min16(total_bytes, is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
|
||||
ep_cs[0].buffer_fs.offset = buf_offset;
|
||||
ep_cs[0].buffer_fs.nbytes = nbytes;
|
||||
}
|
||||
|
||||
_dcd.dma[ep_id].nbytes = nbytes;
|
||||
|
||||
_dcd.ep[ep_id][0].cmd_sts.active = 1;
|
||||
ep_cs[0].cmd_sts.active = 1;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
|
||||
{
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
|
||||
uint8_t const ep_id = ep_addr2id(ep_addr);
|
||||
|
||||
if (!buffer || total_bytes == 0) {
|
||||
// Although having no data, ZLPs can cause buffer overwritten to zeroes. Probably due to USB/DMA controller side
|
||||
// effect/bug. Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
|
||||
buffer = (uint8_t *) (uint32_t) dummy;
|
||||
}
|
||||
|
||||
tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t));
|
||||
_dcd.dma[ep_id].total_bytes = total_bytes;
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
// Although having no data, ZLPs can cause buffer overwritten to zeroes.
|
||||
// Probably due to USB/DMA controller side effect/bug.
|
||||
// Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
|
||||
buffer = (uint8_t*)(uint32_t)dummy;
|
||||
}
|
||||
|
||||
prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes);
|
||||
|
||||
return true;
|
||||
@ -441,23 +489,19 @@ static void bus_reset(uint8_t rhport)
|
||||
dcd_reg->EPSKIP = 0xFFFFFFFF;
|
||||
|
||||
dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt
|
||||
dcd_reg->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt
|
||||
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt
|
||||
dcd_reg->INTEN = INT_DEVICE_STATUS_MASK | TU_BIT(0) | TU_BIT(1); // enable device status & control endpoints
|
||||
}
|
||||
|
||||
static void process_xfer_isr(uint8_t rhport, uint32_t int_status)
|
||||
{
|
||||
static void process_xfer_isr(uint8_t rhport, uint32_t int_status) {
|
||||
uint8_t const max_ep = 2*_dcd_controller[rhport].ep_pairs;
|
||||
|
||||
for(uint8_t ep_id = 0; ep_id < max_ep; ep_id++ )
|
||||
{
|
||||
if ( tu_bit_test(int_status, ep_id) )
|
||||
{
|
||||
for(uint8_t ep_id = 0; ep_id < max_ep; ep_id++ ) {
|
||||
if ( tu_bit_test(int_status, ep_id) ) {
|
||||
ep_cmd_sts_t * ep_cs = &_dcd.ep[ep_id][0];
|
||||
xfer_dma_t* xfer_dma = &_dcd.dma[ep_id];
|
||||
|
||||
if ( ep_id == 0 || ep_id == 1)
|
||||
{
|
||||
if ( ep_id <= 1 ) {
|
||||
// For control endpoint, we need to manually clear Active bit
|
||||
ep_cs->cmd_sts.active = 0;
|
||||
}
|
||||
@ -465,26 +509,29 @@ static void process_xfer_isr(uint8_t rhport, uint32_t int_status)
|
||||
uint16_t buf_offset;
|
||||
uint16_t buf_nbytes;
|
||||
|
||||
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL)
|
||||
{
|
||||
buf_offset = ep_cs->buffer_fs.offset;
|
||||
buf_nbytes = ep_cs->buffer_fs.nbytes;
|
||||
}else
|
||||
{
|
||||
if ( rhport_is_highspeed(rhport) ) {
|
||||
buf_offset = ep_cs->buffer_hs.offset;
|
||||
buf_nbytes = ep_cs->buffer_hs.nbytes;
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_LPC54)
|
||||
// LPC54 Errata USB.2: In USB high-speed device mode, the NBytes field is not correct after BULK IN transfer
|
||||
// There is no work-around. For EP in transfer, the NByte value can be ignored after a packet is transmitted.
|
||||
if ( (ep_id > 1) && (ep_id & 0x01) == 1 && ep_is_bulk(ep_cs) ) {
|
||||
buf_nbytes = 0;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
buf_offset = ep_cs->buffer_fs.offset;
|
||||
buf_nbytes = ep_cs->buffer_fs.nbytes;
|
||||
}
|
||||
|
||||
xfer_dma->xferred_bytes += xfer_dma->nbytes - buf_nbytes;
|
||||
|
||||
if ( (buf_nbytes == 0) && (xfer_dma->total_bytes > xfer_dma->xferred_bytes) )
|
||||
{
|
||||
if ( (buf_nbytes == 0) && (xfer_dma->total_bytes > xfer_dma->xferred_bytes) ) {
|
||||
// There is more data to transfer
|
||||
// buff_offset has been already increased by hw to correct value for next transfer
|
||||
prepare_ep_xfer(rhport, ep_id, buf_offset, xfer_dma->total_bytes - xfer_dma->xferred_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// for detecting ZLP
|
||||
xfer_dma->total_bytes = xfer_dma->xferred_bytes;
|
||||
|
||||
@ -511,19 +558,16 @@ void dcd_int_handler(uint8_t rhport)
|
||||
//------------- Device Status -------------//
|
||||
if ( int_status & INT_DEVICE_STATUS_MASK )
|
||||
{
|
||||
dcd_reg->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
|
||||
if ( cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
|
||||
if ( cmd_stat & DEVCMDSTAT_RESET_CHANGE_MASK) // bus reset
|
||||
{
|
||||
bus_reset(rhport);
|
||||
|
||||
tusb_speed_t speed = TUSB_SPEED_FULL;
|
||||
|
||||
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_HIGH)
|
||||
{
|
||||
if ( _dcd_controller[rhport].is_highspeed ) {
|
||||
// 0 : reserved, 1 : full, 2 : high, 3: super
|
||||
if ( 2 == ((cmd_stat >> CMDSTAT_SPEED_SHIFT) & 0x3UL) )
|
||||
{
|
||||
if ( 2 == ((cmd_stat >> DEVCMDSTAT_SPEED_SHIFT) & 0x3UL) ) {
|
||||
speed= TUSB_SPEED_HIGH;
|
||||
}
|
||||
}
|
||||
@ -531,35 +575,35 @@ void dcd_int_handler(uint8_t rhport)
|
||||
dcd_event_bus_reset(rhport, speed, true);
|
||||
}
|
||||
|
||||
if (cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
|
||||
if (cmd_stat & DEVCMDSTAT_CONNECT_CHANGE_MASK)
|
||||
{
|
||||
// device disconnect
|
||||
if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
|
||||
if (cmd_stat & DEVCMDSTAT_DEVICE_ADDR_MASK)
|
||||
{
|
||||
// debouncing as this can be set when device is powering
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
|
||||
if (cmd_stat & DEVCMDSTAT_SUSPEND_CHANGE_MASK)
|
||||
{
|
||||
// suspend signal, bus idle for more than 3ms
|
||||
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
|
||||
if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
|
||||
if (cmd_stat & DEVCMDSTAT_DEVICE_ADDR_MASK)
|
||||
{
|
||||
dcd_event_bus_signal(rhport, (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
|
||||
dcd_event_bus_signal(rhport, (cmd_stat & DEVCMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Receive
|
||||
if ( tu_bit_test(int_status, 0) && (cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
|
||||
if ( tu_bit_test(int_status, 0) && (cmd_stat & DEVCMDSTAT_SETUP_RECEIVED_MASK) )
|
||||
{
|
||||
// Follow UM flowchart to clear Active & Stall on both Control IN/OUT endpoints
|
||||
_dcd.ep[0][0].cmd_sts.active = _dcd.ep[1][0].cmd_sts.active = 0;
|
||||
_dcd.ep[0][0].cmd_sts.stall = _dcd.ep[1][0].cmd_sts.stall = 0;
|
||||
|
||||
dcd_reg->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
|
||||
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK;
|
||||
|
||||
dcd_event_setup_received(rhport, _dcd.setup_packet, true);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user