Merge pull request #1287 from stevew817/usb-device-rel3

Silicon Labs - Add support for USBDevice
pull/1277/head^2
Martin Kojtal 2015-08-13 15:39:43 +01:00
commit 376d6a73e3
19 changed files with 7269 additions and 44 deletions

View File

@ -0,0 +1,999 @@
/***************************************************************************//**
* @file em_usb.h
* @brief USB protocol stack library API for EFM32.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __EM_USB_H
#define __EM_USB_H
#include "em_device.h"
#include "em_assert.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "usbconfig.h"
#if defined( USB_DEVICE ) || defined( USB_HOST )
#include <string.h>
#include <stddef.h>
#include "em_common.h"
#include "em_int.h"
#if defined( USB_USE_PRINTF )
#include <stdio.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __CC_ARM
#pragma anon_unions
#endif
/***************************************************************************//**
* @addtogroup USB
* @brief USB HOST and DEVICE protocol stacks.
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup USB_COMMON
* @brief Common parts for both HOST and DEVICE USB stacks, see @ref usb_device
* and @ref usb_host pages for device and host library documentation.
* @{
******************************************************************************/
#define SILABS_USB_VID 0x10C4 /**< Silicon Labs Vendor ID, supplied by USB-IF. */
/* SETUP request, direction of data stage */
#define USB_SETUP_DIR_OUT 0 /**< Setup request data stage OUT direction value. */
#define USB_SETUP_DIR_IN 1 /**< Setup request data stage IN direction value. */
#define USB_SETUP_DIR_MASK 0x80 /**< Setup request data stage direction mask. */
#define USB_SETUP_DIR_D2H 0x80 /**< Setup request data stage IN direction mask. */
#define USB_SETUP_DIR_H2D 0x00 /**< Setup request data stage OUT direction mask. */
/* SETUP request type */
#define USB_SETUP_TYPE_STANDARD 0 /**< Standard setup request value. */
#define USB_SETUP_TYPE_CLASS 1 /**< Class setup request value. */
#define USB_SETUP_TYPE_VENDOR 2 /**< Vendor setup request value. */
#define USB_SETUP_TYPE_STANDARD_MASK 0x00 /**< Standard setup request mask. */
#define USB_SETUP_TYPE_CLASS_MASK 0x20 /**< Class setup request mask. */
#define USB_SETUP_TYPE_VENDOR_MASK 0x40 /**< Vendor setup request mask. */
/* SETUP request recipient */
#define USB_SETUP_RECIPIENT_DEVICE 0 /**< Setup request device recipient value. */
#define USB_SETUP_RECIPIENT_INTERFACE 1 /**< Setup request interface recipient value. */
#define USB_SETUP_RECIPIENT_ENDPOINT 2 /**< Setup request endpoint recipient value. */
#define USB_SETUP_RECIPIENT_OTHER 3 /**< Setup request other recipient value. */
/* SETUP standard request codes for Full Speed devices */
#define GET_STATUS 0 /**< Standard setup request GET_STATUS. */
#define CLEAR_FEATURE 1 /**< Standard setup request CLEAR_FEATURE. */
#define SET_FEATURE 3 /**< Standard setup request SET_FEATURE. */
#define SET_ADDRESS 5 /**< Standard setup request SET_ADDRESS. */
#define GET_DESCRIPTOR 6 /**< Standard setup request GET_DESCRIPTOR. */
#define SET_DESCRIPTOR 7 /**< Standard setup request SET_DESCRIPTOR. */
#define GET_CONFIGURATION 8 /**< Standard setup request GET_CONFIGURATION. */
#define SET_CONFIGURATION 9 /**< Standard setup request SET_CONFIGURATION. */
#define GET_INTERFACE 10 /**< Standard setup request GET_INTERFACE. */
#define SET_INTERFACE 11 /**< Standard setup request SET_INTERFACE. */
#define SYNCH_FRAME 12 /**< Standard setup request SYNCH_FRAME. */
/* SETUP class request codes */
#define USB_HID_GET_REPORT 0x01 /**< HID class setup request GET_REPORT. */
#define USB_HID_GET_IDLE 0x02 /**< HID class setup request GET_IDLE. */
#define USB_HID_SET_REPORT 0x09 /**< HID class setup request SET_REPORT. */
#define USB_HID_SET_IDLE 0x0A /**< HID class setup request SET_IDLE. */
#define USB_HID_SET_PROTOCOL 0x0B /**< HID class setup request SET_PROTOCOL. */
#define USB_CDC_SETLINECODING 0x20 /**< CDC class setup request SET_LINE_CODING. */
#define USB_CDC_GETLINECODING 0x21 /**< CDC class setup request GET_LINE_CODING. */
#define USB_CDC_SETCTRLLINESTATE 0x22 /**< CDC class setup request SET_CONTROL_LINE_STATE. */
#define USB_MSD_BOTRESET 0xFF /**< MSD class setup request Bulk only transfer reset. */
#define USB_MSD_GETMAXLUN 0xFE /**< MSD class setup request Get Max LUN. */
#define USB_AUDIO_GET_CUR 0x81 /**< Audio class setup request GET_CUR. */
#define USB_AUDIO_SET_CUR 0x01 /**< Audio class setup request SET_CUR. */
#define USB_AUDIO_GET_CUR 0x81 /**< Audio class setup request GET_CUR. */
#define USB_AUDIO_SET_MIN 0x02 /**< Audio class setup request SET_MIN. */
#define USB_AUDIO_GET_MIN 0x82 /**< Audio class setup request GET_MIN. */
#define USB_AUDIO_SET_MAX 0x03 /**< Audio class setup request SET_MAX. */
#define USB_AUDIO_GET_MAX 0x83 /**< Audio class setup request GET_MAX. */
#define USB_AUDIO_SET_RES 0x04 /**< Audio class setup request SET_RES. */
#define USB_AUDIO_GET_RES 0x84 /**< Audio class setup request GET_RES. */
#define USB_AUDIO_SET_MEM 0x05 /**< Audio class setup request SET_MEM. */
#define USB_AUDIO_GET_MEM 0x85 /**< Audio class setup request GET_MEM. */
#define USB_AUDIO_GET_STAT 0xFF /**< Audio class setup request GET_STAT. */
/* SETUP command GET/SET_DESCRIPTOR decriptor types */
#define USB_DEVICE_DESCRIPTOR 1 /**< DEVICE descriptor value. */
#define USB_CONFIG_DESCRIPTOR 2 /**< CONFIGURATION descriptor value. */
#define USB_STRING_DESCRIPTOR 3 /**< STRING descriptor value. */
#define USB_MAX_STRING_DESCRIPTOR_CHARS 126 /**< Maximum STRING descriptor bString length. */
#define USB_INTERFACE_DESCRIPTOR 4 /**< INTERFACE descriptor value. */
#define USB_ENDPOINT_DESCRIPTOR 5 /**< ENDPOINT descriptor value. */
#define USB_DEVICE_QUALIFIER_DESCRIPTOR 6 /**< DEVICE_QUALIFIER descriptor value. */
#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR 7 /**< OTHER_SPEED_CONFIGURATION descriptor value. */
#define USB_INTERFACE_POWER_DESCRIPTOR 8 /**< INTERFACE_POWER descriptor value. */
#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR 11 /**< INTERFACE_ASSOCIATION descriptor value. */
#define USB_HID_DESCRIPTOR 0x21 /**< HID descriptor value. */
#define USB_SMARTCARD_DESCRIPTOR 0x21 /**< Smartcard usb-ccid-specific Descriptor Type. */
#define USB_HID_REPORT_DESCRIPTOR 0x22 /**< HID REPORT descriptor value. */
#define USB_CS_INTERFACE_DESCRIPTOR 0x24 /**< Audio Class-specific interface Descriptor Type. */
#define USB_CS_ENDPOINT_DESCRIPTOR 0x25 /**< Audio Class-specific endpoint Descriptor Type. */
#define USB_HUB_DESCRIPTOR 0x29 /**< HUB descriptor value. */
#define USB_CA_HEADER_DESCRIPTOR 1 /**< Audio Class-Specific AC Interface Header descriptor.*/
#define USB_CA_INPUT_TERMINAL_DESCRIPTOR 2 /**< Audio Class-Specific AC Interface Input Terminal desc. */
#define USB_CA_OUTPUT_TERMINAL_DESCRIPTOR 3 /**< Audio Class-Specific AC Interface Output Terminal desc.*/
#define USB_CA_MIXER_UNIT_DESCRIPTOR 4 /**< Audio Class-Specific AC Interface Mixer descriptor.*/
#define USB_CA_SELECTOR_UNIT_DESCRIPTOR 5 /**< Audio Class-Specific AC Interface Selector desc. */
#define USB_CA_FEATURE_UNIT_DESCRIPTOR 6 /**< Audio Class-Specific AC Interface Feature desc. */
#define USB_CA_PROCESSING_UNIT_DESCRIPTOR 7 /**< Audio Class-Specific AC Interface Processing desc.*/
#define USB_CA_EXTENSION_UNIT_DESCRIPTOR 8 /**< Audio Class-Specific AC Interface Extension desc. */
#define USB_CA_EP_GENERAL_DESCRIPTOR 1 /**< Audio Class-Specific general descriptor subtype code.*/
#define USB_CA_AS_GENERAL_DESCRIPTOR 1 /**< Audio Class-Specific AS Interface General descriptor.*/
#define USB_CA_FORMAT_TYPE_DESCRIPTOR 2 /**< Audio Class-Specific AS Interface Format Type desc. */
#define USB_DEVICE_DESCSIZE 18 /**< Device descriptor size. */
#define USB_CONFIG_DESCSIZE 9 /**< Configuration descriptor size. */
#define USB_INTERFACE_DESCSIZE 9 /**< Interface descriptor size. */
#define USB_ENDPOINT_DESCSIZE 7 /**< Endpoint descriptor size. */
#define USB_DEVICE_QUALIFIER_DESCSIZE 10 /**< Device qualifier descriptor size. */
#define USB_OTHER_SPEED_CONFIG_DESCSIZE 9 /**< Device other speed configuration descriptor size. */
#define USB_INTERFACE_ASSOCIATION_DESCSIZE 8 /**< INTERFACE_ASSOCIATION descriptor size. */
#define USB_HID_DESCSIZE 9 /**< HID descriptor size. */
#define USB_SMARTCARD_DESCSIZE 54 /**< CCID descriptor size. */
#define USB_CDC_HEADER_FND_DESCSIZE 5 /**< CDC Header functional descriptor size. */
#define USB_CDC_CALLMNG_FND_DESCSIZE 5 /**< CDC Call Management functional descriptor size. */
#define USB_CDC_ACM_FND_DESCSIZE 4 /**< CDC Abstract Control Management functional descriptor size.*/
#define USB_CA_INPUT_TERMINAL_DESCSIZE 12 /**< Audio Input Terminal descriptor size. */
#define USB_CA_OUTPUT_TERMINAL_DESCSIZE 9 /**< Audio Output Terminal descriptor size. */
#define USB_CA_EP_GENERAL_DESCSIZE 7 /**< Audio Class-Specific general descriptor subtype size.*/
#define USB_CA_AS_GENERAL_DESCSIZE 7 /**< Audio Class-Specific AS Interface General desc size.*/
#define USB_CA_STD_AS_ENDPOINT_DESCSZIE 9 /**< Audio-class standard audio stream descriptor size.*/
/* Misc. USB definitions */
#define USB_LS_CTRL_EP_MAXSIZE 8 /**< The max size of low speed control endpoints. */
#define USB_LS_INTR_EP_MAXSIZE 8 /**< The max size of low speed interrupt endpoints. */
#define USB_FS_CTRL_EP_MAXSIZE 64 /**< The max size of full speed control endpoints. */
#define USB_FS_INTR_EP_MAXSIZE 64 /**< The max size of full speed interrupt endpoints. */
#define USB_FS_BULK_EP_MAXSIZE 64 /**< The max size of full speed bulk endpoints. */
#define USB_FS_ISOC_EP_MAXSIZE 1023 /**< The max size of full speed isochronous endpoints. */
#define USB_EPTYPE_CTRL 0 /**< Endpoint type control. */
#define USB_EPTYPE_ISOC 1 /**< Endpoint type isochron. */
#define USB_EPTYPE_BULK 2 /**< Endpoint type bulk. */
#define USB_EPTYPE_INTR 3 /**< Endpoint type interrupt. */
#define USB_EPSYNC_NO (0 << 2) /**< Endpoint synchronization type, none. */
#define USB_EPSYNC_ASYNC (1 << 2) /**< Endpoint synchronization type, asynchronous. */
#define USB_EPSYNC_ADAPTIVE (2 << 2) /**< Endpoint synchronization type, adaptive. */
#define USB_EPSYNC_SYNC (3 << 2) /**< Endpoint synchronization type, synchronous. */
#define USB_EP_DIR_IN 0x80 /**< Endpoint direction mask. */
#define USB_SETUP_PKT_SIZE 8 /**< Setup request packet size. */
#define USB_EPNUM_MASK 0x0F /**< Endpoint number mask. */
#define USB_LANGID_ENUS 0x0409 /**< English-United States language id. */
#define USB_MAX_DEVICE_ADDRESS 127 /**< Maximum allowable device address. */
#define CONFIG_DESC_BM_REMOTEWAKEUP 0x20 /**< Configuration descriptor attribute macro. */
#define CONFIG_DESC_BM_SELFPOWERED 0x40 /**< Configuration descriptor attribute macro. */
#define CONFIG_DESC_BM_RESERVED_D7 0x80 /**< Configuration descriptor attribute macro. */
#define CONFIG_DESC_BM_TRANSFERTYPE 0x03 /**< Configuration descriptor transfer type bitmask. */
#define CONFIG_DESC_MAXPOWER_mA(x) (((x)+1)/2) /**< Configuration descriptor power macro. */
#define DEVICE_IS_SELFPOWERED 0x0001 /**< Standard request GET_STATUS bitmask. */
#define REMOTE_WAKEUP_ENABLED 0x0002 /**< Standard request GET_STATUS bitmask. */
#define USB_FEATURE_ENDPOINT_HALT 0 /**< Standard request CLEAR/SET_FEATURE bitmask. */
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 /**< Standard request CLEAR/SET_FEATURE bitmask. */
#define HUB_FEATURE_PORT_RESET 4 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
#define HUB_FEATURE_PORT_POWER 8 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
#define HUB_FEATURE_C_PORT_CONNECTION 16 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
#define HUB_FEATURE_C_PORT_RESET 20 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
#define HUB_FEATURE_PORT_INDICATOR 22 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
#define USB_CLASS_CDC 2 /**< CDC device/interface class code. */
#define USB_CLASS_CDC_DATA 0x0A /**< CDC Data interface class code. */
#define USB_CLASS_CDC_ACM 2 /**< CDC Abstract Control Model interface subclass code. */
#define USB_CLASS_CDC_HFN 0 /**< CDC class Header Functional Descriptor subtype. */
#define USB_CLASS_CDC_CMNGFN 1 /**< CDC class Call Management Functional Descriptor subtype.*/
#define USB_CLASS_CDC_ACMFN 2 /**< CDC class Abstract Control Management Functional Descriptor subtype.*/
#define USB_CLASS_CDC_UNIONFN 6 /**< CDC class Union Functional Descriptor subtype. */
#define USB_CLASS_HID 3 /**< HID device/interface class code. */
#define USB_CLASS_HID_KEYBOARD 1 /**< HID keyboard interface protocol code. */
#define USB_CLASS_HID_MOUSE 2 /**< HID mouse interface protocol code. */
#define USB_CLASS_HUB 9 /**< HUB device/interface class code. */
#define USB_CLASS_MSD 8 /**< MSD device/interface class code. */
#define USB_CLASS_MSD_BOT_TRANSPORT 0x50 /**< MSD Bulk Only Transport protocol. */
#define USB_CLASS_MSD_SCSI_CMDSET 6 /**< MSD Subclass SCSI transparent command set. */
#define USB_CLASS_MSD_CSW_CMDPASSED 0 /**< MSD BOT Command status wrapper command passed code. */
#define USB_CLASS_MSD_CSW_CMDFAILED 1 /**< MSD BOT Command status wrapper command failed code. */
#define USB_CLASS_MSD_CSW_PHASEERROR 2 /**< MSD BOT Command status wrapper cmd phase error code.*/
#define USB_CLASS_AUDIO 1 /**< Audio interface class code. */
#define USB_CLASS_AUDIO_CONTROL 1 /**< Audio subclass code for control interface. */
#define USB_CLASS_AUDIO_STREAMING 2 /**< Audio subclass code for streaming interface. */
#define USB_CLASS_AUDIO_MIDISTREAMING 3 /**< Audio subclass code for midi streaming interface. */
/*** Triplet for the device descriptor of a composite device using IAD descriptors. ***/
#define USB_CLASS_MISCELLANEOUS 0xEF /**< MISCELLANEOUS device class code. */
#define USB_CLASS_MISC_COMMON_SUBCLASS 2 /**< MISCELLANEOUS Common sub class code. */
#define USB_CLASS_MISC_IAD_PROTOCOL 1 /**< MISCELLANEOUS Interface Association Descriptor protocol code. */
#define PORT_FULL_SPEED 1 /**< Full speed return value for USBH_GetPortSpeed(). */
#define PORT_LOW_SPEED 2 /**< Low speed return value for USBH_GetPortSpeed(). */
#if defined( __GNUC__ ) /* GCC compilers */
#if defined( __CHAR16_TYPE__ )
typedef __CHAR16_TYPE__ char16_t;
#else
typedef unsigned short char16_t;
#endif
#elif defined( __ICCARM__ ) /* IAR compiler */
#include <uchar.h>
#elif defined( __CC_ARM ) /* MDK-ARM compiler */
typedef unsigned short char16_t;
#endif
/** Macro for creating USB compliant UTF-16LE UNICODE string descriptors.
* @n Example: STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ','M','i','c','r','o',' ','A','S' );
* @note The size of the resulting struct will be two byte larger than a USB string
* descriptor. This is to accommodate a terminating null char for the string.
* The value assigned to the 'len' member does not take this into account
* and is therefore correct usb wise.
*/
#define STATIC_CONST_STRING_DESC( _name, ... ) \
EFM32_PACK_START( 1 ) \
typedef struct \
{ \
uint8_t len; \
uint8_t type; \
char16_t name[ 1 + sizeof( (char16_t[]){__VA_ARGS__} ) / 2]; \
} __attribute__ ((packed)) _##_name; \
EFM32_PACK_END() \
EFM32_ALIGN( 4 ) \
EFM32_PACK_START( 1 ) \
static const _##_name _name __attribute__ ((aligned(4)))= \
{ \
.len = sizeof( _##_name ) - 2, \
.type = USB_STRING_DESCRIPTOR, \
.name = {__VA_ARGS__}, \
.name[ ( ( sizeof( _##_name ) - 2 ) / 2 ) - 1 ] = '\0' \
} \
EFM32_PACK_END()
/** Macro for creating USB compliant language string descriptors.
* @n Example: STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 );
*/
#define STATIC_CONST_STRING_DESC_LANGID( _name, x, y ) \
EFM32_PACK_START( 1 ) \
typedef struct \
{ \
uint8_t len; \
uint8_t type; \
uint8_t name[ 2 ]; \
} __attribute__ ((packed)) _##_name; \
EFM32_PACK_END() \
EFM32_ALIGN( 4 ) \
EFM32_PACK_START( 1 ) \
static const _##_name _name __attribute__ ((aligned(4)))= \
{ \
.len = 4, \
.type = USB_STRING_DESCRIPTOR, \
.name = { y, x } \
} \
EFM32_PACK_END()
/** Macro for creating WORD (4 byte) aligned uint8_t array with size which
* is a multiple of WORD size.
* @n Example: @n UBUF( rxBuffer, 37 ); => uint8_t rxBuffer[ 40 ];
*/
#if !defined(__GNUC__)
#define UBUF( x, y ) EFM32_ALIGN( 4 ) uint8_t x[((y)+3)&~3]
#define STATIC_UBUF( x, y ) EFM32_ALIGN( 4 ) static uint8_t x[((y)+3)&~3]
#else
#define UBUF( x, y ) uint8_t x[((y)+3)&~3] __attribute__ ((aligned(4)))
/** Macro for creating WORD (4 byte) aligned static uint8_t arrays with size which
* is a multiple of WORD size.
* @n Example: @n STATIC_UBUF( rxBuffer, 37 ); => static uint8_t rxBuffer[ 40 ];
*/
#define STATIC_UBUF( x, y ) static uint8_t x[((y)+3)&~3] __attribute__ ((aligned(4)))
#endif
/** @brief USB transfer status enumerator. */
typedef enum
{
/* NOTE: Please keep in sync with table errMsg[] in em_usbhal.c */
USB_STATUS_OK = 0, /**< No errors detected. */
USB_STATUS_REQ_ERR = -1, /**< Setup request error. */
USB_STATUS_EP_BUSY = -2, /**< Endpoint is busy. */
USB_STATUS_REQ_UNHANDLED = -3, /**< Setup request not handled. */
USB_STATUS_ILLEGAL = -4, /**< Illegal operation attempted. */
USB_STATUS_EP_STALLED = -5, /**< Endpoint is stalled. */
USB_STATUS_EP_ABORTED = -6, /**< Endpoint transfer was aborted. */
USB_STATUS_EP_ERROR = -7, /**< Endpoint transfer error. */
USB_STATUS_EP_NAK = -8, /**< Endpoint NAK'ed transfer request. */
USB_STATUS_DEVICE_UNCONFIGURED = -9, /**< Device is unconfigured. */
USB_STATUS_DEVICE_SUSPENDED = -10, /**< Device is suspended. */
USB_STATUS_DEVICE_RESET = -11, /**< Device is/was reset. */
USB_STATUS_TIMEOUT = -12, /**< Transfer timeout. */
USB_STATUS_DEVICE_REMOVED = -13, /**< Device was removed. */
USB_STATUS_HC_BUSY = -14, /**< Host channel is busy. */
USB_STATUS_DEVICE_MALFUNCTION = -15, /**< Malfunctioning device attached. */
USB_STATUS_PORT_OVERCURRENT = -16, /**< VBUS shortcircuit/overcurrent failure. */
} USB_Status_TypeDef;
/** @} (end addtogroup USB_COMMON) */
#if defined( USB_DEVICE )
/***************************************************************************//**
* @addtogroup USB_DEVICE
* @brief USB DEVICE protocol stack, see @ref usb_device page for detailed documentation.
* @{
******************************************************************************/
#define USB_PWRSAVE_MODE_OFF 0 /**< No energy saving mode selected. */
#define USB_PWRSAVE_MODE_ONSUSPEND 1 /**< Enter USB power-save mode on suspend. */
#define USB_PWRSAVE_MODE_ONVBUSOFF 2 /**< Enter USB power-save mode when not attached to host. */
#define USB_PWRSAVE_MODE_ENTEREM2 4 /**< Enter EM2 while in power-save mode. */
#define USB_USBC_32kHz_CLK_LFXO 0 /**< Use 32kHz LFXO clock while in powersave mode. */
#define USB_USBC_32kHz_CLK_LFRCO 1 /**< Use 32kHz LFRCO clock while in powersave mode. */
/** @brief USB device state enumerator. */
typedef enum
{
USBD_STATE_NONE = 0, /**< Device state is undefined/unknown. */
USBD_STATE_ATTACHED = 1, /**< Device state is ATTACHED. */
USBD_STATE_POWERED = 2, /**< Device state is POWERED. */
USBD_STATE_DEFAULT = 3, /**< Device state is DEFAULT. */
USBD_STATE_ADDRESSED = 4, /**< Device state is ADDRESSED. */
USBD_STATE_CONFIGURED = 5, /**< Device state is CONFIGURED. */
USBD_STATE_SUSPENDED = 6, /**< Device state is SUSPENDED. */
USBD_STATE_LASTMARKER = 7, /**< Device state enum end marker. */
} USBD_State_TypeDef;
/** @} (end addtogroup USB_DEVICE) */
#endif /* defined( USB_DEVICE ) */
/** @addtogroup USB_COMMON
* @{*/
/** @brief USB Setup request package. */
EFM32_PACK_START( 1 )
typedef struct
{
union
{
struct
{
union
{
struct
{
uint8_t Recipient : 5; /**< Request recipient (device, interface, endpoint or other).*/
uint8_t Type : 2; /**< Request type (standard, class or vendor). */
uint8_t Direction : 1; /**< Transfer direction of SETUP data phase. */
};
uint8_t bmRequestType; /**< Request characteristics. */
};
uint8_t bRequest; /**< Request code. */
uint16_t wValue; /**< Varies according to request. */
uint16_t wIndex; /**< Index or offset, varies according to request. */
uint16_t wLength; /**< Number of bytes to transfer if there is a data stage.*/
};
uint32_t dw[2];
};
} __attribute__ ((packed)) USB_Setup_TypeDef;
EFM32_PACK_END()
/** @brief USB Device Descriptor. */
EFM32_PACK_START( 1 )
typedef struct
{
uint8_t bLength; /**< Size of this descriptor in bytes */
uint8_t bDescriptorType; /**< Constant DEVICE Descriptor Type */
uint16_t bcdUSB; /**< USB Specification Release Number in Binary-Coded
Decimal */
uint8_t bDeviceClass; /**< Class code (assigned by the USB-IF) */
uint8_t bDeviceSubClass; /**< Subclass code (assigned by the USB-IF) */
uint8_t bDeviceProtocol; /**< Protocol code (assigned by the USB-IF) */
uint8_t bMaxPacketSize0; /**< Maximum packet size for endpoint zero */
uint16_t idVendor; /**< Vendor ID (assigned by the USB-IF) */
uint16_t idProduct; /**< Product ID (assigned by the manufacturer) */
uint16_t bcdDevice; /**< Device release number in binary-coded decimal */
uint8_t iManufacturer; /**< Index of string descriptor describing manufacturer*/
uint8_t iProduct; /**< Index of string descriptor describing product */
uint8_t iSerialNumber; /**< Index of string descriptor describing the device
serialnumber */
uint8_t bNumConfigurations; /**< Number of possible configurations */
} __attribute__ ((packed)) USB_DeviceDescriptor_TypeDef;
EFM32_PACK_END()
/** @brief USB Configuration Descriptor. */
EFM32_PACK_START( 1 )
typedef struct
{
uint8_t bLength; /**< Size of this descriptor in bytes */
uint8_t bDescriptorType; /**< Constant CONFIGURATION Descriptor Type */
uint16_t wTotalLength; /**< Total length of data returned for this
configuration. Includes the combined length of all
descriptors (configuration, interface, endpoint,
and class- or vendor-specific) returned for this
configuration. */
uint8_t bNumInterfaces; /**< Number of interfaces supported by this
configuration */
uint8_t bConfigurationValue; /**< Value to use as an argument to the
SetConfiguration request to select this
configuration. */
uint8_t iConfiguration; /**< Index of string descriptor describing this
configuration. */
uint8_t bmAttributes; /**< Configuration characteristics.
@n D7: Reserved (set to one)
@n D6: Self-powered
@n D5: Remote Wakeup
@n D4...0: Reserved (reset to zero) */
uint8_t bMaxPower; /**< Maximum power consumption of the USB device, unit
is 2mA per LSB */
} __attribute__ ((packed)) USB_ConfigurationDescriptor_TypeDef;
EFM32_PACK_END()
/** @brief USB Interface Descriptor. */
EFM32_PACK_START( 1 )
typedef struct
{
uint8_t bLength; /**< Size of this descriptor in bytes. */
uint8_t bDescriptorType; /**< Constant INTERFACE Descriptor Type. */
uint8_t bInterfaceNumber; /**< Number of this interface. Zero-based value
identifying the index in the array of concurrent
interfaces supported by this configuration. */
uint8_t bAlternateSetting; /**< Value used to select this alternate setting for
the interface identified in the prior field. */
uint8_t bNumEndpoints; /**< Number of endpoints used by this interface
(excluding endpoint zero). If this value is zero,
this interface only uses the Default Control Pipe.*/
uint8_t bInterfaceClass; /**< Class code (assigned by the USB-IF). A value
of zero is reserved for future standardization. If
this field is set to FFH, the interface class is
vendor-specific. All other values are reserved for
assignment by the USB-IF. */
uint8_t bInterfaceSubClass; /**< Subclass code (assigned by the USB-IF). These codes
are qualified by the value of the bInterfaceClass
field. If the bInterfaceClass field is reset to
zero, this field must also be reset to zero. If
the bInterfaceClass field is not set to FFH, all
values are reserved forassignment by the USB-IF. */
uint8_t bInterfaceProtocol; /**< Protocol code (assigned by the USB). These codes
are qualified by the value of the bInterfaceClass
and the bInterfaceSubClass fields. If an interface
supports class-specific requests, this code
identifies the protocols that the device uses as
defined by the specification of the device class.
If this field is reset to zero, the device does
not use a class-specific protocol on this
interface. If this field is set to FFH, the device
uses a vendor-specific protocol for this interface*/
uint8_t iInterface; /**< Index of string descriptor describing this
interface. */
} __attribute__ ((packed)) USB_InterfaceDescriptor_TypeDef;
EFM32_PACK_END()
/** @brief USB Endpoint Descriptor. */
EFM32_PACK_START( 1 )
typedef struct
{
uint8_t bLength; /**< Size of this descriptor in bytes */
uint8_t bDescriptorType; /**< Constant ENDPOINT Descriptor Type */
uint8_t bEndpointAddress; /**< The address of the endpoint */
uint8_t bmAttributes; /**< This field describes the endpoint attributes */
uint16_t wMaxPacketSize; /**< Maximum packet size for the endpoint */
uint8_t bInterval; /**< Interval for polling EP for data transfers */
} __attribute__ ((packed)) USB_EndpointDescriptor_TypeDef;
EFM32_PACK_END()
/** @brief USB String Descriptor. */
EFM32_PACK_START( 1 )
typedef struct
{
uint8_t len; /**< Size of this descriptor in bytes. */
uint8_t type; /**< Constant STRING Descriptor Type. */
char16_t name[]; /**< The string encoded with UTF-16LE UNICODE charset. */
} __attribute__ ((packed)) USB_StringDescriptor_TypeDef;
EFM32_PACK_END()
/** @} (end addtogroup USB_COMMON) */
/*** -------------------- Serial port debug configuration ---------------- ***/
#if defined( DOXY_DOC_ONLY )
/** @addtogroup USB_COMMON
* @{*/
/***************************************************************************//**
* @brief
* Transmit a single char on the debug serial port.
*
* @note
* This function is enabled with \#define DEBUG_USB_API when configuring the
* protocol stack in "usbconfig.h".
* This is convenient when debugging code, no need to remove use of this
* function when debugging has completed.
*
* @param[in] c
* Char to transmit.
*
* @return
* The char transmitted.
******************************************************************************/
int USB_PUTCHAR( char c );
/***************************************************************************//**
* @brief
* Transmit a zero terminated string on the debug serial port.
*
* @note
* This function is enabled with \#define DEBUG_USB_API when configuring the
* protocol stack in "usbconfig.h".
* This is convenient when debugging code, no need to remove use of this
* function when debugging has completed.
*
* @param[in] p
* Pointer to string to transmit.
******************************************************************************/
void USB_PUTS( const char *p );
/***************************************************************************//**
* @brief
* Transmit "printf" formated data on the debug serial port.
*
* @note
* This function is enabled with \#define USB_USE_PRINTF when configuring the
* protocol stack in "usbconfig.h".
* This is convenient when debugging code, no need to remove use of this
* function when debugging has completed.
*
* @param[in] format
* Format string (as in printf). No floating point format support.
******************************************************************************/
int USB_PRINTF( const char *format, ... );
/** @} (end addtogroup USB_COMMON) */
#endif /* defined( DOXY_DOC_ONLY ) */
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/* Hardware constraint, do not change. */
#define MAX_NUM_HOSTCHANNELS 14
/* The DMA engine use one FIFO ram word for each host channel. */
#define MAX_HOST_FIFO_SIZE_INWORDS (512-MAX_NUM_HOSTCHANNELS)/*Unit is 4 bytes*/
#if defined ( USER_PUTCHAR )
void USB_Puts( const char *p );
#define USB_PUTS( s ) USB_Puts( s )
#define USB_PUTCHAR( c ) USER_PUTCHAR( c )
#else
#define USB_PUTS( s )
#define USB_PUTCHAR( c )
#endif
#if defined( USB_USE_PRINTF )
/* Use a printf which don't support floating point formatting */
#if defined(__ICCARM__) || defined (__CC_ARM) || defined (__CROSSWORKS_ARM)
#define USB_PRINTF printf
#else
#define USB_PRINTF iprintf
#endif
#else
#define USB_PRINTF(...)
#endif /* defined( USB_USE_PRINTF ) */
#if defined( DEBUG_USB_API )
#define DEBUG_USB_API_PUTS( s ) USB_PUTS( s )
#define DEBUG_USB_API_PUTCHAR( c ) USB_PUTCHAR( c )
#else
#define DEBUG_USB_API_PUTS( s )
#define DEBUG_USB_API_PUTCHAR( c )
#endif /* defined( DEBUG_USB_API ) */
/** @endcond */
/*** -------------------- Common API definitions ------------------------- ***/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined( USB_HOST )
#if defined( NUM_APP_TIMERS )
#define NUM_QTIMERS ( NUM_HC_USED + 2 + NUM_APP_TIMERS + 1 )
#else
#define NUM_QTIMERS ( NUM_HC_USED + 2 + 1 )
#endif
/* + 2 for default ctrl. host ch. 0 & 1, + 1 for host port timer */
#else
#if defined( NUM_APP_TIMERS )
#define NUM_QTIMERS ( NUM_APP_TIMERS )
#else
#define NUM_QTIMERS 0
#endif
#endif /* defined( USB_HOST ) */
/** @endcond */
/** @addtogroup USB_COMMON
* @{*/
/***************************************************************************//**
* @brief
* USB transfer callback function.
*
* @details
* The callback function is called when a transfer has completed. An application
* should check the status, xferred and optionally the remaining parameters
* before deciding if the transfer is usable. In the case where the transfer
* is part of a control request data stage, the callback function should
* return an appropriate @ref USB_Status_TypeDef status.
*
* @param[in] status
* The transfer status. See @ref USB_Status_TypeDef.
*
* @param[in] xferred
* Number of bytes actually transferred.
*
* @param[in] remaining
* Number of bytes not transferred.
*
* @return
* @ref USB_STATUS_OK on success, else an appropriate error code.
******************************************************************************/
typedef int (*USB_XferCompleteCb_TypeDef)( USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining );
/***************************************************************************//**
* @brief
* USBTIMER callback function.
*
* @details
* The callback function is called when an USBTIMER has expired. The callback
* is done with interrupts disabled.
******************************************************************************/
typedef void (*USBTIMER_Callback_TypeDef)( void );
char *USB_GetErrorMsgString( int error );
#if defined( USB_USE_PRINTF )
void USB_PrintErrorMsgString( char *pre, int error );
#else
#define USB_PrintErrorMsgString( pre, error )
#endif
void USBTIMER_DelayMs( uint32_t msec );
void USBTIMER_DelayUs( uint32_t usec );
void USBTIMER_Init( void );
#if ( NUM_QTIMERS > 0 )
void USBTIMER_Start( uint32_t id, uint32_t timeout, USBTIMER_Callback_TypeDef callback );
void USBTIMER_Stop( uint32_t id );
#endif /* ( NUM_QTIMERS > 0 ) */
/** @} (end addtogroup USB_COMMON) */
#if defined( USB_DEVICE )
/** @addtogroup USB_DEVICE
* @{*/
/*** -------------------- DEVICE mode API definitions -------------------- ***/
/***************************************************************************//**
* @brief
* USB Reset callback function.
* @details
* Called whenever USB reset signalling is detected on the USB port.
******************************************************************************/
typedef void (*USBD_UsbResetCb_TypeDef)( void );
/***************************************************************************//**
* @brief
* USB Start Of Frame (SOF) interrupt callback function.
*
* @details
* Called at each SOF interrupt (if enabled),
*
* @param[in] sofNr
* Current frame number. The value rolls over to 0 after 16383 (0x3FFF).
******************************************************************************/
typedef void (*USBD_SofIntCb_TypeDef)( uint16_t sofNr );
/***************************************************************************//**
* @brief
* USB State change callback function.
*
* @details
* Called whenever the device change state.
*
* @param[in] oldState
* The device USB state just leaved. See @ref USBD_State_TypeDef.
*
* @param[in] newState
* New (the current) USB device state. See @ref USBD_State_TypeDef.
******************************************************************************/
typedef void (*USBD_DeviceStateChangeCb_TypeDef)( USBD_State_TypeDef oldState, USBD_State_TypeDef newState );
/***************************************************************************//**
* @brief
* USB power mode callback function.
*
* @details
* Called whenever the device stack needs to query if the device is currently
* self- or bus-powered. Typically when host has issued an @ref GET_STATUS
* setup command.
*
* @return
* True if self-powered, false otherwise.
******************************************************************************/
typedef bool (*USBD_IsSelfPoweredCb_TypeDef)( void );
/***************************************************************************//**
* @brief
* USB setup request callback function.
*
* @details
* Called on each setup request received from host. This gives the application a
* possibility to extend or override standard requests, and to implement class
* or vendor specific requests. Return @ref USB_STATUS_OK if the request is
* handled, return @ref USB_STATUS_REQ_ERR if it is an illegal request or
* return @ref USB_STATUS_REQ_UNHANDLED to pass the request on to the default
* request handler.
*
* @param[in] setup
* Pointer to an USB setup packet. See @ref USB_Setup_TypeDef.
*
* @return
* An appropriate status/error code. See @ref USB_Status_TypeDef.
******************************************************************************/
typedef int (*USBD_SetupCmdCb_TypeDef)( const USB_Setup_TypeDef *setup );
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
struct USBD_Callbacks_TypeDef;
typedef struct USBD_Callbacks_TypeDef const *USBD_Callbacks_TypeDef_Pointer;
/** @endcond */
/** @brief USB Device stack initialization structure.
* @details This structure is passed to @ref USBD_Init() when starting up
* the device. */
typedef struct
{
const USB_DeviceDescriptor_TypeDef *deviceDescriptor; /**< Pointer to a device descriptor. */
const uint8_t *configDescriptor; /**< Pointer to a configuration descriptor. */
const void * const *stringDescriptors; /**< Pointer to an array of string descriptor pointers.*/
const uint8_t numberOfStrings; /**< Number of strings in string descriptor array. */
const uint8_t *bufferingMultiplier; /**< Pointer to an array defining the size of the
endpoint buffers. The size is given in
multiples of endpoint size. Generally a value
of 1 (single) or 2 (double) buffering should be
used. */
USBD_Callbacks_TypeDef_Pointer callbacks; /**< Pointer to struct with callbacks
(@ref USBD_Callbacks_TypeDef). These callbacks
are used by the device stack to signal events
to or query the application. */
const uint32_t reserved; /**< Reserved for future use. */
} USBD_Init_TypeDef;
/** @brief USB Device stack callback structure.
* @details Callback functions used by the device stack to signal events or
* query status to/from the application. See @ref USBD_Init_TypeDef. Assign
* members to NULL if your application don't need a specific callback. */
typedef struct USBD_Callbacks_TypeDef
{
const USBD_UsbResetCb_TypeDef usbReset; /**< Called whenever USB reset signalling is detected
on the USB port. */
const USBD_DeviceStateChangeCb_TypeDef usbStateChange; /**< Called whenever the device change state. */
const USBD_SetupCmdCb_TypeDef setupCmd; /**< Called on each setup request received from host.*/
const USBD_IsSelfPoweredCb_TypeDef isSelfPowered; /**< Called whenever the device stack needs to query
if the device is currently self- or bus-powered.
Applies to devices which can operate in both modes.*/
const USBD_SofIntCb_TypeDef sofInt; /**< Called at each SOF interrupt. If NULL, the device
stack will not enable the SOF interrupt. */
} USBD_Callbacks_TypeDef;
/*** -------------------- DEVICE mode API -------------------------------- ***/
void USBD_AbortAllTransfers( void );
int USBD_AbortTransfer( int epAddr );
void USBD_Connect( void );
void USBD_Disconnect( void );
bool USBD_EpIsBusy( int epAddr );
USBD_State_TypeDef USBD_GetUsbState( void );
const char * USBD_GetUsbStateName( USBD_State_TypeDef state );
int USBD_Init( const USBD_Init_TypeDef *p );
int USBD_Read( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback );
int USBD_RemoteWakeup( void );
bool USBD_SafeToEnterEM2( void );
int USBD_StallEp( int epAddr );
void USBD_Stop( void );
int USBD_UnStallEp( int epAddr );
int USBD_Write( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback );
#ifdef __MBED__
int USBD_SetAddress( uint8_t addr );
int USBD_AddEndpoint( int epAddr, int transferType, int maxPacketSize, int bufferMult );
int USBD_EpIsStalled( int epAddr );
void USBD_StallEp0( void );
#endif
/** @} (end addtogroup USB_DEVICE) */
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
/***************************************************************************//**
* @addtogroup USB_HOST
* @brief USB HOST protocol stack, see @ref usb_host page for detailed documentation.
* @{
******************************************************************************/
/*** -------------------- HOST mode API definitions ---------------------- ***/
#define USB_VBUSOVRCUR_PORT_NONE -1 /**< No overcurrent flag functionality. */
#define USB_VBUSOVRCUR_POLARITY_LOW 0 /**< Overcurrent flag pin polarity is low. */
#define USB_VBUSOVRCUR_POLARITY_HIGH 1 /**< Overcurrent flag pin polarity is high. */
/** USB HOST endpoint status enumerator. */
typedef enum
{
H_EP_IDLE = 0, /**< The endpoint is idle. */
H_EP_SETUP = 1, /**< The endpoint is in SETUP stage. */
H_EP_DATA_IN = 2, /**< The endpoint is in DATA IN stage. */
H_EP_DATA_OUT = 3, /**< The endpoint is in DATA OUT stage. */
H_EP_STATUS_IN = 4, /**< The endpoint is in STATUS IN stage. */
H_EP_STATUS_OUT = 5, /**< The endpoint is in STATUS OUT stage. */
} USBH_EpState_TypeDef;
/** @brief USB HOST endpoint status data.
* @details A host application should not manipulate the contents of
* this struct. */
typedef struct
{
USB_Setup_TypeDef setup; /**< A SETUP package. */
uint8_t setupErrCnt; /**< Error counter for SETUP transfers. */
USB_EndpointDescriptor_TypeDef epDesc; /**< Endpoint descriptor. */
struct USBH_Device_TypeDef *parentDevice; /**< The device the endpoint belongs to. */
uint8_t type; /**< Endpoint type. */
uint16_t packetSize; /**< Packet size, current transfer. */
uint8_t hcOut; /**< Host channel number assigned for OUT transfers. */
uint8_t hcIn; /**< Host channel number assigned for IN transfers. */
bool in; /**< Endpoint direction. */
uint8_t toggle; /**< Endpoint data toggle. */
USBH_EpState_TypeDef state; /**< Endpoint state. */
uint8_t addr; /**< Endpoint address. */
uint8_t *buf; /**< Transfer buffer. */
volatile bool xferCompleted; /**< Transfer completion flag. */
USB_Status_TypeDef xferStatus; /**< Transfer status. */
USB_XferCompleteCb_TypeDef xferCompleteCb; /**< Transfer completion callback function. */
uint32_t xferred; /**< Number of bytes transferred. */
uint32_t remaining; /**< Number of bytes remaining. */
uint32_t timeout; /**< Transfer timeout. */
} USBH_Ep_TypeDef;
/** @brief USB HOST device definition.
* @details A host application should not manipulate the contents of
* this struct. */
typedef struct USBH_Device_TypeDef
{
USB_DeviceDescriptor_TypeDef devDesc; /**< The device device descriptor. */
USB_ConfigurationDescriptor_TypeDef confDesc; /**< The device configuration descriptor. */
USB_InterfaceDescriptor_TypeDef itfDesc; /**< The device interface descriptor. */
USBH_Ep_TypeDef ep0; /**< Endpoint 0 status data. */
USBH_Ep_TypeDef *ep; /**< Array of endpoint status data. */
int numEp; /**< Number of endpoints. */
uint8_t addr; /**< The device address. */
uint8_t speed; /**< The device speed (low or full speed). */
} USBH_Device_TypeDef;
/** @brief USB Host stack initialization structure.
* @details This structure is passed to @ref USBH_Init() when starting up the
* device. Max accumulated FIFO size is 2K bytes. */
typedef struct
{
uint32_t rxFifoSize; /**< Number of FIFO bytes set aside for IN endpoints. */
uint32_t nptxFifoSize; /**< Number of FIFO bytes set aside for OUT CTRL/BULK endoints. */
uint32_t ptxFifoSize; /**< Number of FIFO bytes set aside for OUT INTR/ISO endoints. */
uint32_t reserved; /**< Reserved for future use. */
} USBH_Init_TypeDef;
/** Default @ref USBH_Init_TypeDef values, provides reasonable Tx/Rx FIFO
* partitioning. */
/* In DMA mode the total available FIFO space is smaller. */
/* The DMA controller use one FIFO word pr. channel for status. */
/* The unit in the table is byte. */
#define USBH_INIT_DEFAULT \
{ \
MAX_HOST_FIFO_SIZE_INWORDS * 2,/* 1024 bytes Rx FIFO size. */ \
MAX_HOST_FIFO_SIZE_INWORDS, /* 512 bytes non-periodic Tx FIFO size. */ \
MAX_HOST_FIFO_SIZE_INWORDS, /* 512 bytes periodic Tx FIFO size. */ \
0 /* Reserved. */ \
}
/*** -------------------- HOST mode API ---------------------------------- ***/
int USBH_AssignHostChannel( USBH_Ep_TypeDef *ep, uint8_t hcnum );
int USBH_ControlMsg( USBH_Ep_TypeDef *ep, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, void *data, int timeout, USB_XferCompleteCb_TypeDef callback );
int USBH_ControlMsgB( USBH_Ep_TypeDef *ep, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, void *data, int timeout );
bool USBH_DeviceConnected( void );
int USBH_GetConfigurationDescriptorB( USBH_Device_TypeDef *device, void *buf, int len, uint8_t configIndex );
int USBH_GetDeviceDescriptorB( USBH_Device_TypeDef *device, void *buf, int len );
uint8_t USBH_GetPortSpeed( void );
int USBH_GetStringB( USBH_Device_TypeDef *device, uint8_t *buf, int bufLen, uint8_t stringIndex, uint16_t langID );
int USBH_Init( const USBH_Init_TypeDef *p );
int USBH_InitDeviceData( USBH_Device_TypeDef *device, const uint8_t *buf, USBH_Ep_TypeDef *ep, int numEp, uint8_t deviceSpeed );
int USBH_PortReset( void );
int USBH_PortResume( void );
void USBH_PortSuspend( void );
void USBH_PrintString( const char *pre, const USB_StringDescriptor_TypeDef *s, const char *post );
#if defined( USB_USE_PRINTF )
int USBH_PrintConfigurationDescriptor( const USB_ConfigurationDescriptor_TypeDef *config, int maxLen );
int USBH_PrintDeviceDescriptor( const USB_DeviceDescriptor_TypeDef *device );
int USBH_PrintEndpointDescriptor( const USB_EndpointDescriptor_TypeDef *endpoint );
int USBH_PrintInterfaceDescriptor( const USB_InterfaceDescriptor_TypeDef *interface );
#else
#define USBH_PrintConfigurationDescriptor( config, maxLen )
#define USBH_PrintDeviceDescriptor( device )
#define USBH_PrintEndpointDescriptor( endpoint )
#define USBH_PrintInterfaceDescriptor( interface )
#endif /* defined( USB_USE_PRINTF ) */
int USBH_QueryDeviceB( uint8_t *buf, size_t bufsize, uint8_t deviceSpeed );
USB_ConfigurationDescriptor_TypeDef* USBH_QGetConfigurationDescriptor( const uint8_t *buf, int configIndex );
USB_DeviceDescriptor_TypeDef* USBH_QGetDeviceDescriptor( const uint8_t *buf );
USB_EndpointDescriptor_TypeDef* USBH_QGetEndpointDescriptor( const uint8_t *buf, int configIndex, int interfaceIndex, int endpointIndex );
USB_InterfaceDescriptor_TypeDef* USBH_QGetInterfaceDescriptor( const uint8_t *buf, int configIndex, int interfaceIndex );
int USBH_Read( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout, USB_XferCompleteCb_TypeDef callback );
int USBH_ReadB( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout );
int USBH_SetAddressB( USBH_Device_TypeDef *device, uint8_t deviceAddress );
int USBH_SetAltInterfaceB( USBH_Device_TypeDef *device, uint8_t interfaceIndex, uint8_t alternateSetting );
int USBH_SetConfigurationB( USBH_Device_TypeDef *device, uint8_t configValue );
int USBH_StallEpB( USBH_Ep_TypeDef *ep );
void USBH_Stop( void );
int USBH_UnStallEpB( USBH_Ep_TypeDef *ep );
int USBH_WaitForDeviceConnectionB( uint8_t *buf, int timeoutInSeconds );
int USBH_Write( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout, USB_XferCompleteCb_TypeDef callback );
int USBH_WriteB( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout );
/** @} (end addtogroup USB_HOST) */
#endif /* defined( USB_HOST ) */
/** @} (end addtogroup USB) */
#ifdef __cplusplus
}
#endif
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
#endif /* __EM_USB_H */

View File

@ -0,0 +1,206 @@
/***************************************************************************//**
* @file em_usbd.h
* @brief USB protocol stack library API for EFM32.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __EM_USBD_H
#define __EM_USBD_H
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE )
#ifdef __cplusplus
extern "C" {
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined( DEBUG_USB_API )
#define DEBUG_TRACE_ABORT( x ) \
{ \
if ( x == USB_STATUS_EP_STALLED ) \
{ DEBUG_USB_API_PUTS( "\nEP cb(), EP stalled" ); } \
else if ( x == USB_STATUS_EP_ABORTED ) \
{ DEBUG_USB_API_PUTS( "\nEP cb(), EP aborted" ); } \
else if ( x == USB_STATUS_DEVICE_UNCONFIGURED ) \
{ DEBUG_USB_API_PUTS( "\nEP cb(), device unconfigured" ); } \
else if ( x == USB_STATUS_DEVICE_SUSPENDED ) \
{ DEBUG_USB_API_PUTS( "\nEP cb(), device suspended" ); } \
else /* ( x == USB_STATUS_DEVICE_RESET ) */ \
{ DEBUG_USB_API_PUTS( "\nEP cb(), device reset" ); } \
}
#else
#define DEBUG_TRACE_ABORT( x )
#endif
extern USBD_Device_TypeDef *dev;
extern volatile bool USBD_poweredDown;
__STATIC_INLINE void USBD_ArmEp0( USBD_Ep_TypeDef *ep );
__STATIC_INLINE void USBD_ArmEpN( USBD_Ep_TypeDef *ep );
__STATIC_INLINE void USBD_AbortEp( USBD_Ep_TypeDef *ep );
void USBD_SetUsbState( USBD_State_TypeDef newState );
int USBDCH9_SetupCmd( USBD_Device_TypeDef *device );
void USBDEP_Ep0Handler( USBD_Device_TypeDef *device );
void USBDEP_EpHandler( uint8_t epAddr );
__STATIC_INLINE void USBD_ActivateAllEps( bool forceIdle )
{
int i;
for ( i = 1; i <= NUM_EP_USED; i++ )
{
USBDHAL_ActivateEp( &dev->ep[ i ], forceIdle );
}
}
__STATIC_INLINE void USBD_ArmEp( USBD_Ep_TypeDef *ep )
{
if ( ep->num == 0 )
{
USBD_ArmEp0( ep );
}
else
{
USBD_ArmEpN( ep );
}
}
__STATIC_INLINE void USBD_ArmEp0( USBD_Ep_TypeDef *ep )
{
if ( ep->in )
{
if ( ep->remaining == 0 ) /* Zero Length Packet? */
{
ep->zlp = 1;
}
USBDHAL_SetEp0InDmaPtr( ep->buf );
USBDHAL_StartEp0In( EFM32_MIN( ep->remaining, ep->packetSize ),
dev->ep0MpsCode );
}
else
{
USBDHAL_SetEp0OutDmaPtr( ep->buf );
USBDHAL_StartEp0Out( ep->packetSize, dev->ep0MpsCode );
}
}
__STATIC_INLINE void USBD_ArmEpN( USBD_Ep_TypeDef *ep )
{
if ( ep->in )
{
USBDHAL_StartEpIn( ep );
}
else
{
USBDHAL_StartEpOut( ep );
}
}
__STATIC_INLINE void USBD_DeactivateAllEps( USB_Status_TypeDef reason )
{
int i;
USBD_Ep_TypeDef *ep;
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[ i ];
if ( ep->state == D_EP_IDLE )
{
USBDHAL_DeactivateEp( ep );
}
}
USBDHAL_AbortAllTransfers( reason );
}
__STATIC_INLINE USBD_Ep_TypeDef *USBD_GetEpFromAddr( uint8_t epAddr )
{
int epIndex;
USBD_Ep_TypeDef *ep = NULL;
if ( epAddr & USB_SETUP_DIR_MASK )
{
epIndex = dev->inEpAddr2EpIndex[ epAddr & USB_EPNUM_MASK ];
}
else
{
epIndex = dev->outEpAddr2EpIndex[ epAddr & USB_EPNUM_MASK ];
}
if ( epIndex )
{
ep = &dev->ep[ epIndex ];
}
else if ( ( epAddr & USB_EPNUM_MASK ) == 0 )
{
ep = &dev->ep[ 0 ];
}
return ep;
}
__STATIC_INLINE void USBD_ReArmEp0( USBD_Ep_TypeDef *ep )
{
if ( ep->in )
{
USBDHAL_StartEp0In( EFM32_MIN( ep->remaining, ep->packetSize ),
dev->ep0MpsCode );
}
else
{
USBDHAL_StartEp0Out( ep->packetSize, dev->ep0MpsCode );
}
}
__STATIC_INLINE void USBD_AbortEp( USBD_Ep_TypeDef *ep )
{
if ( ep->state == D_EP_IDLE )
{
return;
}
if ( ep->in )
{
USBDHAL_AbortEpIn( ep );
}
else
{
USBDHAL_AbortEpOut( ep );
}
}
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif /* defined( USB_DEVICE ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
#endif /* __EM_USBD_H */

View File

@ -0,0 +1,75 @@
/***************************************************************************//**
* @file em_usbh.h
* @brief USB protocol stack library API for EFM32.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __EM_USBH_H
#define __EM_USBH_H
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_HOST )
#ifdef __cplusplus
extern "C" {
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
extern USBH_Hc_TypeDef hcs[];
extern int USBH_attachRetryCount;
extern const USBH_AttachTiming_TypeDef USBH_attachTiming[];
extern USBH_Init_TypeDef USBH_initData;
extern volatile USBH_PortState_TypeDef USBH_portStatus;
USB_Status_TypeDef USBH_CtlSendSetup( USBH_Ep_TypeDef *ep );
USB_Status_TypeDef USBH_CtlSendData( USBH_Ep_TypeDef *ep, uint16_t length );
USB_Status_TypeDef USBH_CtlReceiveData( USBH_Ep_TypeDef *ep, uint16_t length );
#if defined( USB_RAW_API )
int USBH_CtlRxRaw( uint8_t pid, USBH_Ep_TypeDef *ep, void *data, int byteCount );
int USBH_CtlTxRaw( uint8_t pid, USBH_Ep_TypeDef *ep, void *data, int byteCount );
#endif
void USBHEP_EpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
void USBHEP_CtrlEpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
void USBHEP_TransferDone( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
__STATIC_INLINE uint16_t USBH_GetFrameNum( void )
{
return USBHHAL_GetFrameNum();
}
__STATIC_INLINE bool USBH_FrameNumIsEven( void )
{
return ( USBHHAL_GetFrameNum() & 1 ) == 0;
}
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif /* defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
#endif /* __EM_USBH_H */

View File

@ -0,0 +1,757 @@
/***************************************************************************//**
* @file em_usbhal.h
* @brief USB protocol stack library, low level USB peripheral access.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __EM_USBHAL_H
#define __EM_USBHAL_H
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE ) || defined( USB_HOST )
#ifdef __cplusplus
extern "C" {
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#define USB_PID_DATA0 0
#define USB_PID_DATA2 1
#define USB_PID_DATA1 2
#define USB_PID_SETUP 3
#define HPRT_F_SPEED ( 1 << _USB_HPRT_PRTSPD_SHIFT )
#define HPRT_L_SPEED ( 2 << _USB_HPRT_PRTSPD_SHIFT )
#define HCFG_PHYCLK_48MHZ 1
#define HCFG_PHYCLK_6MHZ 2
#define DOEP0_XFERSIZE_PKTCNT_MASK ( _USB_DOEP0TSIZ_XFERSIZE_MASK | \
_USB_DOEP0TSIZ_PKTCNT_MASK )
#define DOEP_XFERSIZE_PKTCNT_MASK ( _USB_DOEP_TSIZ_XFERSIZE_MASK | \
_USB_DOEP_TSIZ_PKTCNT_MASK )
#define DIEP0_XFERSIZE_PKTCNT_MASK ( _USB_DIEP0TSIZ_XFERSIZE_MASK | \
_USB_DIEP0TSIZ_PKTCNT_MASK )
#define DIEP_XFERSIZE_PKTCNT_MASK ( _USB_DIEP_TSIZ_XFERSIZE_MASK | \
_USB_DIEP_TSIZ_PKTCNT_MASK | \
_USB_DIEP_TSIZ_MC_MASK )
#define DIEPCTL_EPTYPE_CONTROL (0 << _USB_DIEP_CTL_EPTYPE_SHIFT )
#define DIEPCTL_EPTYPE_ISOC (1 << _USB_DIEP_CTL_EPTYPE_SHIFT )
#define DIEPCTL_EPTYPE_BULK (2 << _USB_DIEP_CTL_EPTYPE_SHIFT )
#define DIEPCTL_EPTYPE_INTR (3 << _USB_DIEP_CTL_EPTYPE_SHIFT )
#define DOEPCTL_EPTYPE_CONTROL (0 << _USB_DOEP_CTL_EPTYPE_SHIFT )
#define DOEPCTL_EPTYPE_ISOC (1 << _USB_DOEP_CTL_EPTYPE_SHIFT )
#define DOEPCTL_EPTYPE_BULK (2 << _USB_DOEP_CTL_EPTYPE_SHIFT )
#define DOEPCTL_EPTYPE_INTR (3 << _USB_DOEP_CTL_EPTYPE_SHIFT )
#define HCCHAR_EPTYPE_CTRL (0 << _USB_HC_CHAR_EPTYPE_SHIFT )
#define HCCHAR_EPTYPE_ISOC (1 << _USB_HC_CHAR_EPTYPE_SHIFT )
#define HCCHAR_EPTYPE_BULK (2 << _USB_HC_CHAR_EPTYPE_SHIFT )
#define HCCHAR_EPTYPE_INTR (3 << _USB_HC_CHAR_EPTYPE_SHIFT )
#define GRXSTSP_PKTSTS_DEVICE_GOTNAK ( 1 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_DEVICE_DATAOUTRECEIVED ( 2 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_DEVICE_DATAOUTCOMPLETE ( 3 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_DEVICE_SETUPCOMPLETE ( 4 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_DEVICE_SETUPRECEIVED ( 6 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_HOST_DATAINRECEIVED ( 2 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_HOST_DATAINCOMPLETE ( 3 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_HOST_DATATOGGLEERROR ( 5 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define GRXSTSP_PKTSTS_HOST_CHANNELHALTED ( 7 << _USB_GRXSTSP_PKTSTS_SHIFT )
#define DCTL_WO_BITMASK \
( _USB_DCTL_CGOUTNAK_MASK | _USB_DCTL_SGOUTNAK_MASK | \
_USB_DCTL_CGNPINNAK_MASK | _USB_DCTL_SGNPINNAK_MASK )
#define GUSBCFG_WO_BITMASK ( USB_GUSBCFG_CORRUPTTXPKT )
#define DEPCTL_WO_BITMASK \
( USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK | \
USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF )
#define HPRT_WC_MASK ( USB_HPRT_PRTCONNDET | USB_HPRT_PRTENA | \
USB_HPRT_PRTENCHNG | USB_HPRT_PRTOVRCURRCHNG )
typedef __IO uint32_t USB_FIFO_TypeDef[ 0x1000 / sizeof( uint32_t ) ];
typedef __IO uint32_t USB_DIEPTXF_TypeDef;
#define USB_DINEPS ((USB_DIEP_TypeDef *) &USB->DIEP0CTL )
#define USB_DOUTEPS ((USB_DOEP_TypeDef *) &USB->DOEP0CTL )
#define USB_FIFOS ((USB_FIFO_TypeDef *) &USB->FIFO0D )
#define USB_DIEPTXFS ((USB_DIEPTXF_TypeDef *) &USB->DIEPTXF1 )
void USBHAL_CoreReset( void );
#if defined( USB_DEVICE )
void USBDHAL_AbortAllTransfers( USB_Status_TypeDef reason );
USB_Status_TypeDef USBDHAL_CoreInit( const uint32_t totalRxFifoSize,
const uint32_t totalTxFifoSize );
void USBDHAL_Connect( void );
void USBDHAL_Disconnect( void );
void USBDHAL_AbortAllEps( void );
void USBDHAL_AbortEpIn( USBD_Ep_TypeDef *ep );
void USBDHAL_AbortEpOut( USBD_Ep_TypeDef *ep );
__STATIC_INLINE USB_Status_TypeDef USBDHAL_GetStallStatusEp(
USBD_Ep_TypeDef *ep, uint16_t *halt );
__STATIC_INLINE uint32_t USBDHAL_GetInEpInts( USBD_Ep_TypeDef *ep );
__STATIC_INLINE uint32_t USBDHAL_GetOutEpInts( USBD_Ep_TypeDef *ep );
__STATIC_INLINE void USBDHAL_SetEPDISNAK( USBD_Ep_TypeDef *ep );
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
USB_Status_TypeDef USBHHAL_CoreInit( const uint32_t rxFifoSize,
const uint32_t nptxFifoSize,
const uint32_t ptxFifoSize );
void USBHHAL_HCHalt( int hcnum, uint32_t hcchar );
void USBHHAL_HCInit( int hcnum );
void USBHHAL_HCStart( int hcnum );
#endif /* defined( USB_HOST ) */
__STATIC_INLINE void USBHAL_DisableGlobalInt( void )
{
USB->GAHBCFG &= ~USB_GAHBCFG_GLBLINTRMSK;
}
__STATIC_INLINE void USBHAL_DisablePhyPins( void )
{
USB->ROUTE = _USB_ROUTE_RESETVALUE;
}
__STATIC_INLINE void USBHAL_DisableUsbInt( void )
{
USB->IEN = _USB_IEN_RESETVALUE;
}
__STATIC_INLINE void USBHAL_EnableGlobalInt( void )
{
USB->GAHBCFG |= USB_GAHBCFG_GLBLINTRMSK;
}
__STATIC_INLINE void USBHAL_FlushRxFifo( void )
{
USB->GRSTCTL = USB_GRSTCTL_RXFFLSH;
while ( USB->GRSTCTL & USB_GRSTCTL_RXFFLSH ) {}
}
__STATIC_INLINE void USBHAL_FlushTxFifo( uint8_t fifoNum )
{
USB->GRSTCTL = USB_GRSTCTL_TXFFLSH | ( fifoNum << _USB_GRSTCTL_TXFNUM_SHIFT );
while ( USB->GRSTCTL & USB_GRSTCTL_TXFFLSH ) {}
}
__STATIC_INLINE uint32_t USBHAL_GetCoreInts( void )
{
uint32_t retVal;
retVal = USB->GINTSTS;
retVal &= USB->GINTMSK;
return retVal;
}
__STATIC_INLINE bool USBHAL_VbusIsOn( void )
{
return ( USB->STATUS & USB_STATUS_VREGOS ) != 0;
}
#if defined( USB_DEVICE )
__STATIC_INLINE void USBDHAL_ActivateEp( USBD_Ep_TypeDef *ep, bool forceIdle )
{
#define DIEP_MPS_EPTYPE_TXFNUM_MASK ( _USB_DIEP_CTL_MPS_MASK | \
_USB_DIEP_CTL_EPTYPE_MASK | \
_USB_DIEP_CTL_TXFNUM_MASK )
#define DOEP_MPS_EPTYPE_MASK ( _USB_DOEP_CTL_MPS_MASK | \
_USB_DOEP_CTL_EPTYPE_MASK )
uint32_t daintmask, depctl;
if ( forceIdle )
ep->state = D_EP_IDLE;
if ( ep->in )
{
daintmask = ep->mask;
depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
if ( !( depctl & USB_DIEP_CTL_USBACTEP ) )
{
depctl = ( depctl &
~( DIEP_MPS_EPTYPE_TXFNUM_MASK |
USB_DIEP_CTL_STALL ) ) |
( ep->packetSize << _USB_DIEP_CTL_MPS_SHIFT ) |
( ep->type << _USB_DIEP_CTL_EPTYPE_SHIFT ) |
( ep->txFifoNum << _USB_DIEP_CTL_TXFNUM_SHIFT ) |
USB_DIEP_CTL_SETD0PIDEF |
USB_DIEP_CTL_USBACTEP |
USB_DIEP_CTL_SNAK;
}
else
{
depctl |= USB_DIEP_CTL_SETD0PIDEF;
}
USB_DINEPS[ ep->num ].CTL = depctl;
}
else
{
daintmask = ep->mask << _USB_DAINTMSK_OUTEPMSK0_SHIFT;
depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
if ( !( depctl & USB_DOEP_CTL_USBACTEP ) )
{
depctl = ( depctl &
~( DOEP_MPS_EPTYPE_MASK |
USB_DOEP_CTL_STALL ) ) |
( ep->packetSize << _USB_DOEP_CTL_MPS_SHIFT ) |
( ep->type << _USB_DOEP_CTL_EPTYPE_SHIFT ) |
USB_DOEP_CTL_SETD0PIDEF |
USB_DOEP_CTL_USBACTEP |
USB_DOEP_CTL_SNAK;
}
else
{
depctl |= USB_DOEP_CTL_SETD0PIDEF;
}
USB_DOUTEPS[ ep->num ].CTL = depctl;
}
/* Enable interrupt for this EP */
USB->DAINTMSK |= daintmask;
#undef DIEP_MPS_EPTYPE_TXFNUM_MASK
#undef DOEP_MPS_EPTYPE_MASK
}
__STATIC_INLINE void USBDHAL_ClearRemoteWakeup( void )
{
USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_RMTWKUPSIG );
}
__STATIC_INLINE void USBDHAL_DeactivateEp( USBD_Ep_TypeDef *ep )
{
uint32_t daintmask;
if ( ep->in )
{
USB_DINEPS[ ep->num ].CTL = 0;
daintmask = ep->mask;
}
else
{
USB_DOUTEPS[ ep->num ].CTL = 0;
daintmask = ep->mask << _USB_DAINTMSK_OUTEPMSK0_SHIFT;
}
/* Disable interrupt for this EP */
USB->DAINTMSK &= ~daintmask;
}
__STATIC_INLINE void USBDHAL_EnableInts( USBD_Device_TypeDef *dev )
{
uint32_t mask;
/* Disable all interrupts. */
USB->GINTMSK = 0;
/* Clear pending interrupts */
USB->GINTSTS = 0xFFFFFFFF;
mask = USB_GINTMSK_USBSUSPMSK |
USB_GINTMSK_USBRSTMSK |
USB_GINTMSK_ENUMDONEMSK |
USB_GINTMSK_IEPINTMSK |
USB_GINTMSK_OEPINTMSK |
USB_GINTMSK_WKUPINTMSK;
if ( dev->callbacks->sofInt )
{
mask |= USB_GINTMSK_SOFMSK;
}
USB->GINTMSK = mask;
}
__STATIC_INLINE void USBDHAL_EnableUsbResetAndSuspendInt( void )
{
/* Disable all interrupts. */
USB->GINTMSK = 0;
USB->GINTMSK = USB_GINTMSK_USBRSTMSK | USB_GINTMSK_USBSUSPMSK;
}
__STATIC_INLINE void USBDHAL_Ep0Activate( uint32_t ep0mps )
{
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGNPINNAK;
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
| ep0mps;
}
__STATIC_INLINE bool USBDHAL_EpIsStalled( USBD_Ep_TypeDef *ep )
{
bool retVal = false;
uint16_t stallStatus;
if ( USBDHAL_GetStallStatusEp( ep, &stallStatus ) == USB_STATUS_OK )
{
retVal = stallStatus & 1 ? true : false;
}
return retVal;
}
__STATIC_INLINE uint32_t USBDHAL_GetAllInEpInts( void )
{
uint32_t retVal;
retVal = USB->DAINT;
retVal &= USB->DAINTMSK;
return retVal & 0xFFFF;
}
__STATIC_INLINE uint32_t USBDHAL_GetAllOutEpInts( void )
{
uint32_t retVal;
retVal = USB->DAINT;
retVal &= USB->DAINTMSK;
return retVal >> 16;
}
__STATIC_INLINE uint32_t USBDHAL_GetInEpInts( USBD_Ep_TypeDef *ep )
{
uint32_t retVal, msk;
msk = USB->DIEPMSK;
retVal = USB_DINEPS[ ep->num ].INT;
return retVal & msk;
}
__STATIC_INLINE uint32_t USBDHAL_GetOutEpInts( USBD_Ep_TypeDef *ep )
{
uint32_t retVal;
retVal = USB_DOUTEPS[ ep->num ].INT;
#if defined( USB_DOEP0INT_STUPPKTRCVD )
retVal &= USB->DOEPMSK | USB_DOEP0INT_STUPPKTRCVD;
#else
retVal &= USB->DOEPMSK;
#endif
return retVal;
}
__STATIC_INLINE USB_Status_TypeDef USBDHAL_GetStallStatusEp(
USBD_Ep_TypeDef *ep, uint16_t *halt )
{
uint32_t depctl, eptype;
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ( ep->in == true )
{
depctl = USB_DINEPS[ ep->num ].CTL;
eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
{
*halt = depctl & USB_DIEP_CTL_STALL ? 1 : 0;
retVal = USB_STATUS_OK;
}
}
else
{
depctl = USB_DOUTEPS[ ep->num ].CTL;
eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
if (( eptype == DOEPCTL_EPTYPE_INTR ) || ( eptype == DOEPCTL_EPTYPE_BULK ))
{
*halt = depctl & USB_DOEP_CTL_STALL ? 1 : 0;
retVal = USB_STATUS_OK;
}
}
return retVal;
}
__STATIC_INLINE void USBDHAL_ReenableEp0Setup( USBD_Device_TypeDef *dev )
{
USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DOEP0CTL_EPENA
| dev->ep0MpsCode;
}
__STATIC_INLINE void USBDHAL_SetAddr( uint8_t addr )
{
USB->DCFG = ( USB->DCFG &
~_USB_DCFG_DEVADDR_MASK ) |
(addr << _USB_DCFG_DEVADDR_SHIFT );
}
__STATIC_INLINE void USBDHAL_SetEp0InDmaPtr( uint8_t* addr )
{
USB->DIEP0DMAADDR = (uint32_t)addr;
}
__STATIC_INLINE void USBDHAL_SetEp0OutDmaPtr( uint8_t* addr )
{
USB->DOEP0DMAADDR = (uint32_t)addr;
}
__STATIC_INLINE void USBDHAL_SetEPDISNAK( USBD_Ep_TypeDef *ep )
{
if ( ep->in )
{
USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DIEP_CTL_SNAK |
USB_DIEP_CTL_EPDIS;
}
else
{
USB_DOUTEPS[ ep->num ].CTL = ( USB_DOUTEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DOEP_CTL_EPENA;
USB_DOUTEPS[ ep->num ].CTL = ( USB_DOUTEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DOEP_CTL_SNAK |
USB_DOEP_CTL_EPDIS;
}
}
__STATIC_INLINE void USBDHAL_SetRemoteWakeup( void )
{
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_RMTWKUPSIG;
}
__STATIC_INLINE USB_Status_TypeDef USBDHAL_StallEp( USBD_Ep_TypeDef *ep )
{
uint32_t depctl, eptype;
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ( ep->in == true )
{
depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
if ( eptype != DIEPCTL_EPTYPE_ISOC )
{
if ( depctl & USB_DIEP_CTL_EPENA )
{
depctl |= USB_DIEP_CTL_EPDIS;
}
USB_DINEPS[ ep->num ].CTL = depctl | USB_DIEP_CTL_STALL;
retVal = USB_STATUS_OK;
}
}
else
{
depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
if ( eptype != DIEPCTL_EPTYPE_ISOC )
{
USB_DOUTEPS[ ep->num ].CTL = depctl | USB_DOEP_CTL_STALL;
retVal = USB_STATUS_OK;
}
}
return retVal;
}
__STATIC_INLINE void USBDHAL_StartEp0In( uint32_t len, uint32_t ep0mps )
{
USB->DIEP0TSIZ = ( len << _USB_DIEP0TSIZ_XFERSIZE_SHIFT ) |
( 1 << _USB_DIEP0TSIZ_PKTCNT_SHIFT );
USB->DIEP0CTL = ( USB->DIEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DIEP0CTL_CNAK | USB_DIEP0CTL_EPENA
| ep0mps;
}
__STATIC_INLINE void USBDHAL_StartEp0Out( uint32_t len, uint32_t ep0mps )
{
USB->DOEP0TSIZ = ( len << _USB_DOEP0TSIZ_XFERSIZE_SHIFT ) |
( 1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT );
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
| ep0mps;
}
__STATIC_INLINE void USBDHAL_StartEp0Setup( USBD_Device_TypeDef *dev )
{
dev->ep[ 0 ].in = false;
#if defined( USB_DOEP0INT_STUPPKTRCVD )
USB->DOEP0TSIZ = ( 8*3 << _USB_DOEP0TSIZ_XFERSIZE_SHIFT ) |
( 1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT ) |
( 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT );
#else
USB->DOEP0TSIZ = 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
#endif
dev->setup = dev->setupPkt;
USB->DOEP0DMAADDR = (uint32_t)dev->setup;
#if defined( USB_DOEP0INT_STUPPKTRCVD )
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DOEP0CTL_EPENA
| dev->ep0MpsCode;
#else
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
| USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
| dev->ep0MpsCode;
#endif
}
__STATIC_INLINE void USBDHAL_StartEpIn( USBD_Ep_TypeDef *ep )
{
uint32_t pktcnt, xfersize;
if ( ep->remaining == 0 ) /* ZLP ? */
{
pktcnt = 1;
xfersize = 0;
}
else
{
pktcnt = ( ep->remaining - 1 + ep->packetSize ) / ep->packetSize;
xfersize = ep->remaining;
}
USB_DINEPS[ ep->num ].TSIZ =
( USB_DINEPS[ ep->num ].TSIZ &
~DIEP_XFERSIZE_PKTCNT_MASK ) |
( xfersize << _USB_DIEP_TSIZ_XFERSIZE_SHIFT ) |
( pktcnt << _USB_DIEP_TSIZ_PKTCNT_SHIFT );
USB_DINEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
USB_DINEPS[ ep->num ].CTL =
( USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK ) |
USB_DIEP_CTL_CNAK |
USB_DIEP_CTL_EPENA;
}
__STATIC_INLINE void USBDHAL_StartEpOut( USBD_Ep_TypeDef *ep )
{
uint32_t pktcnt, xfersize;
if ( ep->remaining == 0 ) /* ZLP ? */
{
pktcnt = 1;
xfersize = ep->packetSize;
}
else
{
pktcnt = ( ep->remaining - 1 + ep->packetSize ) / ep->packetSize;
xfersize = pktcnt * ep->packetSize;
}
USB_DOUTEPS[ ep->num ].TSIZ =
( USB_DOUTEPS[ ep->num ].TSIZ &
~DOEP_XFERSIZE_PKTCNT_MASK ) |
( xfersize << _USB_DOEP_TSIZ_XFERSIZE_SHIFT ) |
( pktcnt << _USB_DOEP_TSIZ_PKTCNT_SHIFT );
ep->hwXferSize = xfersize;
USB_DOUTEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
USB_DOUTEPS[ ep->num ].CTL =
( USB_DOUTEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DOEP_CTL_CNAK |
USB_DOEP_CTL_EPENA;
}
__STATIC_INLINE USB_Status_TypeDef USBDHAL_UnStallEp( USBD_Ep_TypeDef *ep )
{
uint32_t depctl, eptype;
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ( ep->in == true )
{
depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
{
depctl |= USB_DIEP_CTL_SETD0PIDEF;
depctl &= ~USB_DIEP_CTL_STALL;
USB_DINEPS[ ep->num ].CTL = depctl;
retVal = USB_STATUS_OK;
}
}
else
{
depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
{
depctl |= USB_DOEP_CTL_SETD0PIDEF;
depctl &= ~USB_DOEP_CTL_STALL;
USB_DOUTEPS[ ep->num ].CTL = depctl;
retVal = USB_STATUS_OK;
}
}
return retVal;
}
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
__STATIC_INLINE void USBHHAL_HCActivate( int hcnum, uint32_t hcchar, bool intep )
{
uint32_t oddframe;
if ( intep )
{
oddframe = USB->HFNUM & 1;
USB->HC[ hcnum ].CHAR =
( hcchar &
~( USB_HC_CHAR_CHDIS | _USB_HC_CHAR_ODDFRM_MASK ) ) |
/* Schedule INT transfers to start in next frame. */
( oddframe & 1 ? 0 : USB_HC_CHAR_ODDFRM ) |
USB_HC_CHAR_CHENA;
}
else
{
USB->HC[ hcnum ].CHAR = ( hcchar & ~USB_HC_CHAR_CHDIS ) |
USB_HC_CHAR_CHENA;
}
}
__STATIC_INLINE bool USBHHAL_InitializedAndPowered( void )
{
if ( ( USB->ROUTE & USB_ROUTE_PHYPEN ) &&
( USB->HPRT & USB_HPRT_PRTPWR ) )
return true;
return false;
}
__STATIC_INLINE void USBHHAL_EnableInts( void )
{
/* Disable all interrupts. */
USB->GINTMSK = 0;
/* Clear pending OTG interrupts */
USB->GOTGINT = 0xFFFFFFFF;
/* Clear pending interrupts */
USB->GINTSTS = 0xFFFFFFFF;
USB->GINTMSK = USB_GINTMSK_PRTINTMSK |
USB_GINTMSK_HCHINTMSK |
USB_GINTMSK_DISCONNINTMSK;
}
__STATIC_INLINE uint16_t USBHHAL_GetFrameNum( void )
{
return USB->HFNUM;
}
__STATIC_INLINE uint32_t USBHHAL_GetHcChar( uint8_t hcnum )
{
return USB->HC[ hcnum ].CHAR;
}
__STATIC_INLINE uint32_t USBHHAL_GetHcInts( uint8_t hcnum )
{
uint32_t retVal;
retVal = USB->HC[ hcnum ].INT;
return retVal;
}
__STATIC_INLINE uint32_t USBHHAL_GetHostChannelInts( void )
{
return USB->HAINT;
}
__STATIC_INLINE uint8_t USBHHAL_GetPortSpeed( void )
{
return ( USB->HPRT & _USB_HPRT_PRTSPD_MASK ) >> _USB_HPRT_PRTSPD_SHIFT;
}
__STATIC_INLINE void USBHHAL_PortReset( bool on )
{
if ( on )
{
DEBUG_USB_INT_LO_PUTCHAR( '+' );
USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTRST;
}
else
{
DEBUG_USB_INT_LO_PUTCHAR( '-' );
USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTRST );
}
}
__STATIC_INLINE void USBHHAL_PortResume( bool on )
{
if ( on )
{
USB->HPRT = ( USB->HPRT & ~( HPRT_WC_MASK | USB_HPRT_PRTSUSP ) ) |
USB_HPRT_PRTRES;
}
else
{
USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTSUSP | USB_HPRT_PRTRES );
}
}
__STATIC_INLINE void USBHHAL_PortSuspend( void )
{
USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTSUSP;
}
__STATIC_INLINE void USBHHAL_VbusOn( bool on )
{
if ( on )
{
USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTPWR;
DEBUG_USB_INT_LO_PUTCHAR( '/' );
}
else
{
USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTPWR );
DEBUG_USB_INT_LO_PUTCHAR( '\\' );
}
}
#endif /* defined( USB_HOST ) */
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
#endif /* __EM_USBHAL_H */

View File

@ -0,0 +1,230 @@
/***************************************************************************//**
* @file em_usbtypes.h
* @brief USB protocol stack library, internal type definitions.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __EM_USBTYPES_H
#define __EM_USBTYPES_H
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE ) || defined( USB_HOST )
#ifdef __cplusplus
extern "C" {
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/* Limits imposed by the USB peripheral */
#define NP_RX_QUE_DEPTH 8
#define HP_RX_QUE_DEPTH 8
#define MAX_XFER_LEN 524287L /* 2^19 - 1 bytes */
#define MAX_PACKETS_PR_XFER 1023 /* 2^10 - 1 packets */
#if defined( _USB_DIEPTXF6_MASK )
#define MAX_NUM_TX_FIFOS 6 /* In addition to EP0 Tx FIFO */
#define MAX_NUM_IN_EPS 6 /* In addition to EP0 */
#define MAX_NUM_OUT_EPS 6 /* In addition to EP0 */
#define MAX_DEVICE_FIFO_SIZE_INWORDS 512U
#else
#define MAX_NUM_TX_FIFOS 3 /* In addition to EP0 Tx FIFO */
#define MAX_NUM_IN_EPS 3 /* In addition to EP0 */
#define MAX_NUM_OUT_EPS 3 /* In addition to EP0 */
#define MAX_DEVICE_FIFO_SIZE_INWORDS 384U
#endif
#define MIN_EP_FIFO_SIZE_INWORDS 16U /* Unit is words (32bit) */
#define MIN_EP_FIFO_SIZE_INBYTES 64U /* Unit is bytes (8bit) */
/* For MCU's without USB host capability. */
#if !defined( USB_ROUTE_VBUSENPEN )
#define USB_VBUS_SWITCH_NOT_PRESENT
#endif
/* Limit imposed by the USB standard */
#define MAX_USB_EP_NUM 15
#if defined( USB_DEVICE )
/* Check power saving modes. */
#ifndef USB_PWRSAVE_MODE
/* Default powersave-mode is OFF. */
#define USB_PWRSAVE_MODE USB_PWRSAVE_MODE_OFF
#else
#if ( USB_PWRSAVE_MODE & \
~( USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | \
USB_PWRSAVE_MODE_ENTEREM2 ) )
#error "Illegal USB powersave mode."
#endif
#endif /* ifndef USB_PWRSAVE_MODE */
/* Check power saving low frequency clock selection. */
#ifndef USB_USBC_32kHz_CLK
/* Default clock source is LFXO. */
#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO
#else
#if ( ( USB_USBC_32kHz_CLK != USB_USBC_32kHz_CLK_LFXO ) && \
( USB_USBC_32kHz_CLK != USB_USBC_32kHz_CLK_LFRCO ) )
#error "Illegal USB 32kHz powersave clock selection."
#endif
#endif /* ifndef USB_USBC_32kHz_CLK */
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
/* Check VBUS overcurrent definitions. */
#ifndef USB_VBUSOVRCUR_PORT
#define USB_VBUSOVRCUR_PORT gpioPortE
#define USB_VBUSOVRCUR_PIN 2
#define USB_VBUSOVRCUR_POLARITY USB_VBUSOVRCUR_POLARITY_LOW
#endif
#endif
/* Developer mode debugging macro's */
#if defined( DEBUG_USB_INT_LO )
#define DEBUG_USB_INT_LO_PUTS( s ) USB_PUTS( s )
#define DEBUG_USB_INT_LO_PUTCHAR( c ) USB_PUTCHAR( c )
#else
#define DEBUG_USB_INT_LO_PUTS( s )
#define DEBUG_USB_INT_LO_PUTCHAR( c )
#endif /* defined( DEBUG_USB_INT_LO ) */
#if defined( DEBUG_USB_INT_HI )
#define DEBUG_USB_INT_HI_PUTS( s ) USB_PUTS( s )
#define DEBUG_USB_INT_HI_PUTCHAR( c ) USB_PUTCHAR( c )
#else
#define DEBUG_USB_INT_HI_PUTS( s )
#define DEBUG_USB_INT_HI_PUTCHAR( c )
#endif /* defined( DEBUG_USB_INT_HI ) */
#if defined( USB_HOST )
#if defined( NUM_APP_TIMERS )
#define HOSTPORT_TIMER_INDEX (NUM_APP_TIMERS)
#else
#define HOSTPORT_TIMER_INDEX (0)
#endif
#define HOSTCH_TIMER_INDEX (HOSTPORT_TIMER_INDEX + 1 )
#endif
/* Macros for selecting a hardware timer. */
#define USB_TIMER0 0
#define USB_TIMER1 1
#define USB_TIMER2 2
#define USB_TIMER3 3
#if defined( USB_HOST )
#define HCS_NAK 0x01
#define HCS_STALL 0x02
#define HCS_XACT 0x04
#define HCS_TGLERR 0x08
#define HCS_BABBLE 0x10
#define HCS_TIMEOUT 0x20
#define HCS_COMPLETED 0x40
#define HCS_RETRY 0x80
#endif
#if defined( USB_DEVICE )
typedef enum
{
D_EP_IDLE = 0,
D_EP_TRANSMITTING = 1,
D_EP_RECEIVING = 2,
D_EP0_IN_STATUS = 3,
D_EP0_OUT_STATUS = 4
} USBD_EpState_TypeDef;
typedef struct
{
bool in;
uint8_t zlp;
uint8_t num;
uint8_t addr;
uint8_t type;
uint8_t txFifoNum;
uint8_t *buf;
uint16_t packetSize;
uint16_t mask;
uint32_t remaining;
uint32_t xferred;
uint32_t hwXferSize;
uint32_t fifoSize;
USBD_EpState_TypeDef state;
USB_XferCompleteCb_TypeDef xferCompleteCb;
} USBD_Ep_TypeDef;
typedef struct
{
USB_Setup_TypeDef *setup;
USB_Setup_TypeDef setupPkt[3];
uint8_t configurationValue; /* Must be DWORD aligned */
bool remoteWakeupEnabled;
uint8_t numberOfStrings;
uint8_t numberOfInterfaces;
USBD_State_TypeDef state;
USBD_State_TypeDef savedState;
USBD_State_TypeDef lastState;
const USB_DeviceDescriptor_TypeDef *deviceDescriptor;
const USB_ConfigurationDescriptor_TypeDef *configDescriptor;
const void * const *stringDescriptors;
const USBD_Callbacks_TypeDef *callbacks;
USBD_Ep_TypeDef ep[ NUM_EP_USED + 1 ];
uint8_t inEpAddr2EpIndex[ MAX_USB_EP_NUM + 1 ];
uint8_t outEpAddr2EpIndex[ MAX_USB_EP_NUM + 1 ];
uint32_t ep0MpsCode;
} USBD_Device_TypeDef;
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
typedef enum
{
H_PORT_DISCONNECTED = 0,
H_PORT_CONNECTED_DEBOUNCING = 1,
H_PORT_CONNECTED_RESETTING = 2,
H_PORT_CONNECTED = 3,
H_PORT_OVERCURRENT = 4
} USBH_PortState_TypeDef;
typedef struct
{
int debounceTime;
int resetTime;
} USBH_AttachTiming_TypeDef;
typedef struct
{
uint8_t *buf;
int errorCnt;
uint32_t remaining;
uint32_t xferred;
uint32_t hwXferSize;
uint8_t status;
bool idle;
USBH_Ep_TypeDef *ep;
} USBH_Hc_TypeDef;
#endif /* defined( USB_HOST ) */
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
#endif /* __EM_USBTYPES_H */

View File

@ -0,0 +1,88 @@
/***************************************************************************//**
* @file usbconfig.h
* @brief USB protocol stack library, application supplied configuration options.
* @version 3.20.12
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef __USBCONFIG_H
#define __USBCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
/* Compile stack for device mode. */
#define USB_DEVICE
/* Maximum number of endpoint used, EP0 excluded. If you change this, you must
also change USBEndpoints_EFM32.h to match. */
#define NUM_EP_USED 6
/* Power management modes. The following can be or'd toghether. See comments in
em_usbd.c under "Energy-saving modes" for more details.
USB_PWRSAVE_MODE_ONSUSPEND Set USB peripheral in low power mode on suspend
USB_PWRSAVE_MODE_ONVBUSOFF Set USB peripheral in low power mode when not
attached to a host. While this mode assumes that the internal voltage regulator
is used and that the VREGI pin of the chip is connected to VBUS it should
be safe to use given that VREGOSEN is always enabled. If you disable VREGOSEN
you must turn this off.
USB_PWRSAVE_MODE_ENTEREM2 Enter EM2 when USB peripheral is in low power mode.
On Mbed this allows the sleep() and deepsleep() calls to enter EM2, but
does not automatically enter any sleep states. Entering EM1 is always allowed.
Note for Happy Gecko, errata USB_E111: Entering EM2 when both the system clock
(HFCLK) and the USB core clock (USBCCLK) is running on USHFRCO will result in
a lock-up.
*/
#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND|USB_PWRSAVE_MODE_ONVBUSOFF|USB_PWRSAVE_MODE_ENTEREM2)
/* Use dynamic memory to allocate rx/tx buffers in the HAL. Saves memory
as buffers are only allocated for used endpoints. The system malloc
must return memory that is aligned by 4.
Note: if you disable this, using isochronous endpoints with packet
sizes that are larger than the maximum for other EP types (64) will
not work. */
#define USB_USE_DYNAMIC_MEMORY
/* When the USB peripheral is set in low power mode, it must be clocked by a 32kHz
clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification
compliance. */
#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO
/* Uncomment to get some debugging information. Default value for USER_PUTCHAR
should work for SiLabs Gecko boards. Printf requires a working retarget
implementation for write(). */
//#define DEBUG_USB_API
//#define USB_USE_PRINTF
//#define USER_PUTCHAR ITM_SendChar
//#define DEBUG_USB_INT_HI
//#define DEBUG_USB_INT_LO
#ifdef __cplusplus
}
#endif
#endif /* __USBCONFIG_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,446 @@
/**************************************************************************//**
* @file em_usbdep.c
* @brief USB protocol stack library, USB device endpoint handlers.
* @version 3.20.14
******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE )
#include "em_usbtypes.h"
#include "em_usbhal.h"
#include "em_usbd.h"
#ifdef USB_USE_PRINTF
static const char *epStatusStr[] = {
"IDLE","TRANS","RECV","IN_S","OUT_S"
};
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/*
* USBDEP_Ep0Handler() is called each time a packet has been transmitted
* or recieved on the default endpoint.
* A state machine navigate us through the phases of a control transfer
* according to "chapter 9" in the USB spec.
*/
#if !defined( USB_DOEP0INT_STUPPKTRCVD )
void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
{
int status;
USBD_Ep_TypeDef *ep;
static bool statusIn;
static uint32_t xferred;
static USB_XferCompleteCb_TypeDef callback;
ep = &device->ep[ 0 ];
#ifdef __MBED__
(void)xferred;
(void)statusIn;
(void)status;
USB_PRINTF("USBDEP: ep0 %s, rem %ld, z %d\n", epStatusStr[ep->state], ep->remaining, ep->zlp);
if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
{
ep->state = D_EP_IDLE;
if ( ep->xferCompleteCb )
{
callback = ep->xferCompleteCb;
ep->xferCompleteCb = NULL;
callback( USB_STATUS_OK, ep->xferred, ep->remaining );
}
USBDHAL_ReenableEp0Setup(device);
}
else
{
device->callbacks->setupCmd(device->setup);
}
#else /* not __MBED__ */
switch ( ep->state )
{
case D_EP_IDLE:
ep->remaining = 0;
ep->zlp = 0;
callback = NULL;
statusIn = false;
status = USBDCH9_SetupCmd( device );
if ( status == USB_STATUS_REQ_ERR )
{
ep->in = true;
USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
ep->in = false; /* OUT for next SETUP */
USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP packet*/
}
else /* ( Status == USB_STATUS_OK ) */
{
if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
{
callback = ep->xferCompleteCb;
}
if ( ep->state != D_EP_RECEIVING )
{
if ( ep->remaining )
{
/* Data will be sent to host, check if a ZLP must be appended */
if ( ( ep->remaining < device->setup->wLength ) &&
( ep->remaining % ep->packetSize == 0 ) )
{
ep->zlp = 1;
}
}
else
{
/* Prepare for next SETUP packet*/
USBDHAL_ReenableEp0Setup( device );
/* No data stage, a ZLP may have been sent. If not, send one */
xferred = 0;
if ( ep->zlp == 0 )
{
USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
ep->state = D_EP0_IN_STATUS;
}
else
{
ep->state = D_EP_IDLE;
ep->in = false; /* OUT for next SETUP */
}
}
}
}
break;
case D_EP_RECEIVING:
if ( ep->remaining )
{
/* There is more data to receive */
USBD_ReArmEp0( ep );
}
else
{
status = USB_STATUS_OK;
if ( callback != NULL )
{
status = callback( USB_STATUS_OK, ep->xferred, 0 );
callback = NULL;
}
if ( status != USB_STATUS_OK )
{
ep->in = true;
USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
ep->in = false; /* OUT for next SETUP */
USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP pkt. */
ep->state = D_EP_IDLE;
}
else /* Everything OK, send a ZLP (ACK) to host */
{
USBDHAL_ReenableEp0Setup( device );/* Prepare for next SETUP packet*/
ep->state = D_EP_IDLE; /* USBD_Write() sets state back*/
/* to EP_TRANSMITTING */
USBD_Write( 0, NULL, 0, NULL );
ep->state = D_EP0_IN_STATUS;
}
}
break;
case D_EP_TRANSMITTING:
if ( ep->remaining )
{
/* There is more data to transmit */
USBD_ReArmEp0( ep );
}
else
{
/* All data transferred, is a ZLP packet needed ? */
if ( ep->zlp == 1 )
{
xferred = ep->xferred;
ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
/* to EP_TRANSMITTING */
USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
ep->zlp = 2;
}
else
{
if ( ep->zlp == 0 )
{
xferred = ep->xferred;
}
ep->state = D_EP_IDLE;
USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
statusIn = true;
ep->state = D_EP0_OUT_STATUS;
}
}
break;
case D_EP0_IN_STATUS:
case D_EP0_OUT_STATUS:
if ( statusIn )
{
USBDHAL_ReenableEp0Setup( device );
}
if ( callback != NULL )
{
callback( USB_STATUS_OK, xferred, 0 );
}
ep->state = D_EP_IDLE;
ep->in = false; /* OUT for next SETUP */
break;
default:
EFM_ASSERT( false );
break;
}
#endif /* __MBED__ */
}
#endif
#if defined( USB_DOEP0INT_STUPPKTRCVD )
void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
{
int status;
USBD_Ep_TypeDef *ep;
static uint32_t xferred;
static USB_XferCompleteCb_TypeDef callback;
#ifdef __MBED__
(void)xferred;
(void)status;
ep = &device->ep[ 0 ];
if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
{
ep->state = D_EP_IDLE;
if ( ep->xferCompleteCb )
{
callback = ep->xferCompleteCb;
ep->xferCompleteCb = NULL;
callback( USB_STATUS_OK, ep->xferred, ep->remaining );
}
USBDHAL_StartEp0Setup( dev );
}
else
{
device->callbacks->setupCmd(device->setup);
}
#else
ep = &device->ep[ 0 ];
switch ( ep->state )
{
case D_EP_IDLE:
ep->zlp = 0;
ep->remaining = 0;
callback = NULL;
status = USBDCH9_SetupCmd( device );
if ( status == USB_STATUS_REQ_ERR )
{
ep->in = true;
USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
ep->in = false; /* OUT for next SETUP */
USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
}
else /* ( Status == USB_STATUS_OK ) */
{
if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
{
callback = ep->xferCompleteCb;
}
if ( ep->state != D_EP_RECEIVING )
{
if ( ep->remaining )
{
/* Data will be sent to host, check if a ZLP must be appended */
if ( ( ep->remaining < device->setup->wLength ) &&
( ep->remaining % ep->packetSize == 0 ) )
{
ep->zlp = 1;
}
}
else
{
/* No data stage, a ZLP may have been sent. If not, send one */
xferred = 0;
if ( ep->zlp == 0 )
{
ep->state = D_EP_IDLE;
USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
ep->state = D_EP0_IN_STATUS;
}
}
}
}
break;
case D_EP_RECEIVING:
if ( ep->remaining )
{
ep->in = false;
USBD_ReArmEp0( ep );
}
else
{
status = USB_STATUS_OK;
if ( callback != NULL )
{
status = callback( USB_STATUS_OK, ep->xferred, 0 );
callback = NULL;
}
if ( status != USB_STATUS_OK )
{
ep->in = true;
USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
ep->in = false; /* OUT for next SETUP */
USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP pkt. */
ep->state = D_EP_IDLE;
}
else
{
USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
/* to EP_TRANSMITTING */
USBD_Write( 0, NULL, 0, NULL );
ep->state = D_EP0_IN_STATUS;
}
}
break;
case D_EP_TRANSMITTING:
if ( ep->remaining )
{
ep->in = true;
USBD_ReArmEp0( ep );
}
else
{
if ( ep->zlp == 1 )
{
xferred = ep->xferred;
ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
/* to EP_TRANSMITTING */
USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
ep->zlp = 2;
}
else
{
if ( ep->zlp == 0 )
{
xferred = ep->xferred;
}
ep->state = D_EP_IDLE;
USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
ep->state = D_EP0_OUT_STATUS;
}
}
break;
case D_EP0_IN_STATUS:
if ( ( USB->DOEP0CTL & USB_DOEP0CTL_EPENA ) == 0 )
{
/* Prepare for more SETUP Packets */
USBDHAL_StartEp0Setup( dev );
}
if ( callback != NULL )
{
callback( USB_STATUS_OK, xferred, 0 );
}
ep->state = D_EP_IDLE;
ep->in = false; /* OUT for next SETUP */
break;
case D_EP0_OUT_STATUS:
USBDHAL_StartEp0Setup( dev ); /* Prepare for more SETUP Packets */
if ( callback != NULL )
{
callback( USB_STATUS_OK, xferred, 0 );
}
ep->state = D_EP_IDLE;
ep->in = false; /* OUT for next SETUP */
break;
}
#endif /* __MBED__ */
}
#endif
/*
* USBDEP_EpHandler() is called each time a packet has been transmitted
* or recieved on an endpoint other than the default endpoint.
*/
void USBDEP_EpHandler( uint8_t epAddr )
{
USB_XferCompleteCb_TypeDef callback;
USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
{
ep->state = D_EP_IDLE;
if ( ep->xferCompleteCb )
{
callback = ep->xferCompleteCb;
ep->xferCompleteCb = NULL;
callback( USB_STATUS_OK, ep->xferred, ep->remaining );
}
}
else
{
EFM_ASSERT( false );
}
}
/** @endcond */
#endif /* defined( USB_DEVICE ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */

View File

@ -0,0 +1,946 @@
/**************************************************************************//**
* @file em_usbdint.c
* @brief USB protocol stack library, USB device peripheral interrupt handlers.
* @version 3.20.14
******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE )
#include "em_cmu.h"
#include "em_usbtypes.h"
#include "em_usbhal.h"
#include "em_usbd.h"
#ifdef __MBED__
extern void usbhal_allow_em2(bool em2_allow);
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#define HANDLE_INT( x ) if ( status & x ) { Handle_##x(); status &= ~x; }
static void Handle_USB_GINTSTS_ENUMDONE ( void );
static void Handle_USB_GINTSTS_IEPINT ( void );
static void Handle_USB_GINTSTS_OEPINT ( void );
static void Handle_USB_GINTSTS_RESETDET ( void );
static void Handle_USB_GINTSTS_SOF ( void );
static void Handle_USB_GINTSTS_USBRST ( void );
static void Handle_USB_GINTSTS_USBSUSP ( void );
static void Handle_USB_GINTSTS_WKUPINT ( void );
#if defined( USB_DOEP0INT_STUPPKTRCVD )
static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep );
#else
static void ProcessSetup ( void );
static void ProcessOepData ( USBD_Ep_TypeDef *ep );
#endif
#if ( USB_PWRSAVE_MODE )
/* Variables and prototypes for USB powerdown (suspend) functionality. */
static bool UsbPowerDown( void );
static bool UsbPowerUp( void );
volatile bool USBD_poweredDown = false;
/* Storage for backing up USB core registers. */
static uint32_t x_USB_GINTMSK;
#if defined(_USB_GOTGCTL_MASK)
static uint32_t x_USB_GOTGCTL;
#endif
static uint32_t x_USB_GAHBCFG;
static uint32_t x_USB_GUSBCFG;
static uint32_t x_USB_GRXFSIZ;
static uint32_t x_USB_GNPTXFSIZ;
static uint32_t x_USB_DCFG;
static uint32_t x_USB_DCTL;
static uint32_t x_USB_DAINTMSK;
static uint32_t x_USB_DIEPMSK;
static uint32_t x_USB_DOEPMSK;
static uint32_t x_USB_PCGCCTL;
#if ( NUM_EP_USED > 0 )
static uint32_t x_USB_EP_CTL[ NUM_EP_USED ];
static uint32_t x_USB_EP_TSIZ[ NUM_EP_USED ];
static uint32_t x_USB_EP_DMAADDR[ NUM_EP_USED ];
#endif
#if ( NUM_EP_USED > MAX_NUM_TX_FIFOS )
#define FIFO_CNT MAX_NUM_TX_FIFOS
#else
#define FIFO_CNT NUM_EP_USED
#endif
#if ( FIFO_CNT > 0 )
static uint32_t x_USB_DIEPTXFS[ FIFO_CNT ];
#endif
#if ( USB_PWRSAVE_MODE )
static uint32_t cmuStatus = 0;
#endif
#endif /* if ( USB_PWRSAVE_MODE ) */
/*
* USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
*/
void USB_IRQHandler( void )
{
uint32_t status;
bool servedVbusInterrupt = false;
INT_Disable();
#if ( USB_PWRSAVE_MODE )
if ( USBD_poweredDown )
{
/* Switch USBC clock from 32kHz to a 48MHz clock to be able to */
/* read USB peripheral registers. */
/* If we woke up from EM2, HFCLK is now HFRCO. */
/* Restore clock oscillators.*/
#if defined( CMU_OSCENCMD_USHFRCOEN )
if ( ( CMU->STATUS & CMU_STATUS_USHFRCOENS ) == 0 )/*Wakeup from EM2 ?*/
{
CMU->OSCENCMD = ( cmuStatus
& ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS ) )
| CMU_OSCENCMD_USHFRCOEN;
}
#else
if ( ( CMU->STATUS & CMU_STATUS_HFXOENS ) == 0 ) /* Wakeup from EM2 ? */
{
CMU->OSCENCMD = cmuStatus
& ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS );
}
#endif
/* Select correct USBC clock.*/
#if defined( CMU_OSCENCMD_USHFRCOEN )
CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
while ( ( CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL ) == 0 ){}
#else
CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
while ( ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) == 0 ){}
#endif
}
#endif /* if ( USB_PWRSAVE_MODE ) */
if ( USB->IF && ( USB->CTRL & USB_CTRL_VREGOSEN ) )
{
if ( USB->IF & USB_IF_VREGOSH )
{
USB->IFC = USB_IFC_VREGOSH;
if ( USB->STATUS & USB_STATUS_VREGOS )
{
servedVbusInterrupt = true;
DEBUG_USB_INT_LO_PUTS( "\nVboN" );
#if ( USB_PWRSAVE_MODE )
if ( UsbPowerUp() )
{
USBDHAL_EnableUsbResetAndSuspendInt();
}
USBD_SetUsbState( USBD_STATE_POWERED );
#endif
}
}
if ( USB->IF & USB_IF_VREGOSL )
{
USB->IFC = USB_IFC_VREGOSL;
if ( ( USB->STATUS & USB_STATUS_VREGOS ) == 0 )
{
servedVbusInterrupt = true;
DEBUG_USB_INT_LO_PUTS( "\nVboF" );
#if ( USB_PWRSAVE_MODE )
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
if ( !USBD_poweredDown )
{
USB->GINTMSK = 0;
USB->GINTSTS = 0xFFFFFFFF;
}
UsbPowerDown();
#endif
USBD_SetUsbState( USBD_STATE_NONE );
#endif
}
}
}
status = USBHAL_GetCoreInts();
if ( status == 0 )
{
INT_Enable();
if ( !servedVbusInterrupt )
{
DEBUG_USB_INT_LO_PUTS( "\nSinT" );
}
return;
}
HANDLE_INT( USB_GINTSTS_RESETDET )
HANDLE_INT( USB_GINTSTS_WKUPINT )
HANDLE_INT( USB_GINTSTS_USBSUSP )
HANDLE_INT( USB_GINTSTS_SOF )
HANDLE_INT( USB_GINTSTS_ENUMDONE )
HANDLE_INT( USB_GINTSTS_USBRST )
HANDLE_INT( USB_GINTSTS_IEPINT )
HANDLE_INT( USB_GINTSTS_OEPINT )
INT_Enable();
if ( status != 0 )
{
DEBUG_USB_INT_LO_PUTS( "\nUinT" );
}
}
/*
* Handle port enumeration interrupt. This has nothing to do with normal
* device enumeration.
*/
static void Handle_USB_GINTSTS_ENUMDONE( void )
{
#if ( USB_PWRSAVE_MODE )
UsbPowerUp();
#endif
USBDHAL_Ep0Activate( dev->ep0MpsCode );
dev->ep[ 0 ].state = D_EP_IDLE;
USBDHAL_EnableInts( dev );
DEBUG_USB_INT_LO_PUTS( "EnumD" );
}
/*
* Handle IN endpoint transfer interrupt.
*/
static void Handle_USB_GINTSTS_IEPINT( void )
{
int epnum;
uint16_t epint;
uint16_t epmask;
uint32_t status;
USBD_Ep_TypeDef *ep;
DEBUG_USB_INT_HI_PUTCHAR( 'i' );
epint = USBDHAL_GetAllInEpInts();
for ( epnum = 0, epmask = 1;
epnum <= MAX_NUM_IN_EPS;
epnum++, epmask <<= 1 )
{
if ( epint & epmask )
{
ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | epnum );
status = USBDHAL_GetInEpInts( ep );
if ( status & USB_DIEP_INT_XFERCOMPL )
{
USB_DINEPS[ epnum ].INT = USB_DIEP_INT_XFERCOMPL;
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
if ( epnum == 0 )
{
if ( ep->remaining > ep->packetSize )
{
ep->remaining -= ep->packetSize;
ep->xferred += ep->packetSize;
}
else
{
ep->xferred += ep->remaining;
ep->remaining = 0;
}
USBDEP_Ep0Handler( dev );
}
else
{
ep->xferred = ep->remaining -
( ( USB_DINEPS[ epnum ].TSIZ &
_USB_DIEP_TSIZ_XFERSIZE_MASK ) >>
_USB_DIEP_TSIZ_XFERSIZE_SHIFT );
ep->remaining -= ep->xferred;
USBDEP_EpHandler( ep->addr );
#if defined( USB_DOEP0INT_STUPPKTRCVD )
if ( USB_DINEPS[ ep->num ].INT & USB_DIEP_INT_NAKINTRPT )
{
USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_NAKINTRPT;
}
#endif
}
}
}
}
}
/*
* Handle OUT endpoint transfer interrupt.
*/
static void Handle_USB_GINTSTS_OEPINT( void )
{
int epnum;
uint16_t epint;
uint16_t epmask;
uint32_t status;
USBD_Ep_TypeDef *ep;
DEBUG_USB_INT_HI_PUTCHAR( 'o' );
epint = USBDHAL_GetAllOutEpInts();
for ( epnum = 0, epmask = 1;
epnum <= MAX_NUM_OUT_EPS;
epnum++, epmask <<= 1 )
{
if ( epint & epmask )
{
ep = USBD_GetEpFromAddr( epnum );
status = USBDHAL_GetOutEpInts( ep );
#if defined( USB_DOEP0INT_STUPPKTRCVD )
HandleOutEpIntr( status, ep );
#else
if ( status & USB_DOEP_INT_XFERCOMPL )
{
USB_DOUTEPS[ epnum ].INT = USB_DOEP_INT_XFERCOMPL;
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
ProcessOepData( ep );
}
/* Setup Phase Done */
if ( status & USB_DOEP0INT_SETUP )
{
ProcessSetup();
}
#endif
}
}
}
#if !defined( USB_DOEP0INT_STUPPKTRCVD )
static void ProcessOepData( USBD_Ep_TypeDef *ep )
{
if ( ep->num == 0 )
{
#ifdef __MBED__
int xfer_size = ep->packetSize - (( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_XFERSIZE_MASK )
>> _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
int setup_pkt_received = USBDHAL_GetOutEpInts( ep ) & USB_DOEP0INT_SETUP;
if ( (!setup_pkt_received && xfer_size == 0) ||
(setup_pkt_received && xfer_size == 8) )
{
/* Higher levels need to see the correct transfer amount for ZLPs */
ep->remaining = 0;
ep->xferred = 0;
}
else
{
/* FIXME - does not work if actual read size > 56 */
if ( setup_pkt_received ) xfer_size -= 8;
ep->xferred = xfer_size;
ep->remaining -= xfer_size;
}
#else
if ( ep->remaining > ep->packetSize )
{
ep->remaining -= ep->packetSize;
ep->xferred += ep->packetSize;
}
else
{
ep->xferred += ep->remaining;
ep->remaining = 0;
}
#endif
USBDEP_Ep0Handler( dev );
}
else
{
ep->xferred = ep->hwXferSize -
( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
_USB_DOEP_TSIZ_XFERSIZE_SHIFT );
ep->remaining -= ep->xferred;
USBDEP_EpHandler( ep->addr );
}
}
#endif
#if !defined( USB_DOEP0INT_STUPPKTRCVD )
static void ProcessSetup( void )
{
DEBUG_USB_INT_LO_PUTS( "\nS" );
if ( USB->DOEP0INT & USB_DOEP0INT_BACK2BACKSETUP )
{ /* Back to back setup packets received */
USB->DOEP0INT = USB_DOEP0INT_BACK2BACKSETUP;
DEBUG_USB_INT_LO_PUTS( "B2B" );
dev->setup = (USB_Setup_TypeDef*)( USB->DOEP0DMAADDR - USB_SETUP_PKT_SIZE );
}
else
{
/* Read SETUP packet counter from hw. */
int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
>> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
if ( supCnt == 3 )
supCnt = 2;
dev->setup = &dev->setupPkt[ 2 - supCnt ];
}
USB->DOEP0TSIZ |= 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
USB->DOEP0INT = USB_DOEP0INT_SETUP;
USBDEP_Ep0Handler( dev ); /* Call the SETUP handler for EP0 */
}
#endif
/*
* Handle USB reset detected interrupt in suspend mode.
*/
static void Handle_USB_GINTSTS_RESETDET ( void )
{
#if ( USB_PWRSAVE_MODE )
if ( ! USBD_poweredDown )
{
USB->GINTSTS = USB_GINTSTS_RESETDET;
}
if ( UsbPowerUp() )
{
USB->GINTSTS = USB_GINTSTS_RESETDET;
}
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
/* Power down immediately if VBUS is off. */
if ( ! ( USB->STATUS & USB_STATUS_VREGOS ) )
{
UsbPowerDown();
}
#endif
#else
USB->GINTSTS = USB_GINTSTS_RESETDET;
#endif /* if ( USB_PWRSAVE_MODE ) */
if ( USB->STATUS & USB_STATUS_VREGOS )
{
USBD_SetUsbState( USBD_STATE_DEFAULT );
}
else
{
USBD_SetUsbState( USBD_STATE_NONE );
}
DEBUG_USB_INT_LO_PUTS( "RsuP\n" );
}
/*
* Handle Start Of Frame (SOF) interrupt.
*/
static void Handle_USB_GINTSTS_SOF( void )
{
USB->GINTSTS = USB_GINTSTS_SOF;
if ( dev->callbacks->sofInt )
{
dev->callbacks->sofInt(
( USB->DSTS & _USB_DSTS_SOFFN_MASK ) >> _USB_DSTS_SOFFN_SHIFT );
}
}
/*
* Handle USB port reset interrupt.
*/
static void Handle_USB_GINTSTS_USBRST( void )
{
int i;
DEBUG_USB_INT_LO_PUTS( "ReseT" );
/* Clear Remote Wakeup Signalling */
USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_RMTWKUPSIG );
USBHAL_FlushTxFifo( 0 );
/* Clear pending interrupts */
for ( i = 0; i <= MAX_NUM_IN_EPS; i++ )
{
USB_DINEPS[ i ].INT = 0xFFFFFFFF;
}
for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ )
{
USB_DOUTEPS[ i ].INT = 0xFFFFFFFF;
}
USB->DAINTMSK = USB_DAINTMSK_INEPMSK0 | USB_DAINTMSK_OUTEPMSK0;
#if defined( USB_DOEPMSK_STSPHSERCVDMSK )
USB->DOEPMSK = USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK
| USB_DOEPMSK_STSPHSERCVDMSK;
#else
USB->DOEPMSK = USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK;
#endif
USB->DIEPMSK = USB_DIEPMSK_XFERCOMPLMSK;
/* Reset Device Address */
USB->DCFG &= ~_USB_DCFG_DEVADDR_MASK;
/* Setup EP0 to receive SETUP packets */
USBDHAL_StartEp0Setup( dev );
USBDHAL_EnableInts( dev );
if ( dev->callbacks->usbReset )
{
dev->callbacks->usbReset();
}
USBD_SetUsbState( USBD_STATE_DEFAULT );
USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_RESET );
}
/*
* Handle USB port suspend interrupt.
*/
static void Handle_USB_GINTSTS_USBSUSP( void )
{
USBD_State_TypeDef state;
USB->GINTSTS = USB_GINTSTS_USBSUSP;
USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_SUSPENDED );
DEBUG_USB_INT_LO_PUTS( "\nSusP" );
if ( USBD_GetUsbState() == USBD_STATE_NONE )
{
USBD_SetUsbState( USBD_STATE_POWERED );
}
state = USBD_GetUsbState();
if ( ( state == USBD_STATE_POWERED ) ||
( state == USBD_STATE_DEFAULT ) ||
( state == USBD_STATE_ADDRESSED ) ||
( state == USBD_STATE_CONFIGURED ) )
{
#if ( USB_PWRSAVE_MODE )
UsbPowerDown();
#endif
USBD_SetUsbState( USBD_STATE_SUSPENDED );
}
}
/*
* Handle USB port wakeup interrupt.
*/
static void Handle_USB_GINTSTS_WKUPINT( void )
{
#if ( USB_PWRSAVE_MODE )
if ( ! USBD_poweredDown )
{
USB->GINTSTS = USB_GINTSTS_WKUPINT;
}
if ( UsbPowerUp() )
{
USB->GINTSTS = USB_GINTSTS_WKUPINT;
USBDHAL_StartEp0Setup( dev );
USBDHAL_Ep0Activate( dev->ep0MpsCode );
}
#else
USB->GINTSTS = USB_GINTSTS_WKUPINT;
#endif
USBD_SetUsbState( dev->savedState );
DEBUG_USB_INT_LO_PUTS( "WkuP\n" );
}
#if ( USB_PWRSAVE_MODE )
/*
* Backup essential USB core registers, and set the core in partial powerdown
* mode. Optionally prepare entry into EM2.
*/
static bool UsbPowerDown( void )
{
#if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
int i;
#endif
#if ( NUM_EP_USED > 0 )
int epNum;
USBD_Ep_TypeDef *ep;
#endif
if ( !USBD_poweredDown )
{
USBD_poweredDown = true;
DEBUG_USB_INT_LO_PUTCHAR( '\\' );
/* Backup USB core registers. */
x_USB_GINTMSK = USB->GINTMSK;
#if defined(_USB_GOTGCTL_MASK)
x_USB_GOTGCTL = USB->GOTGCTL;
#endif
x_USB_GAHBCFG = USB->GAHBCFG;
x_USB_GUSBCFG = USB->GUSBCFG;
x_USB_GRXFSIZ = USB->GRXFSIZ;
x_USB_GNPTXFSIZ = USB->GNPTXFSIZ;
x_USB_DCFG = USB->DCFG;
x_USB_DCTL = USB->DCTL;
x_USB_DAINTMSK = USB->DAINTMSK;
x_USB_DIEPMSK = USB->DIEPMSK;
x_USB_DOEPMSK = USB->DOEPMSK;
x_USB_PCGCCTL = USB->PCGCCTL;
#if ( NUM_EP_USED > 0 )
for ( i = 0; i < NUM_EP_USED; i++ )
{
ep = &dev->ep[ i+1 ];
epNum = ep->num;
if ( ep->in )
{
x_USB_EP_CTL[ i ] = USB_DINEPS[ epNum ].CTL;
x_USB_EP_TSIZ[ i ] = USB_DINEPS[ epNum ].TSIZ;
x_USB_EP_DMAADDR[ i ] = USB_DINEPS[ epNum ].DMAADDR;
}
else
{
x_USB_EP_CTL[ i ] = USB_DOUTEPS[ epNum ].CTL;
x_USB_EP_TSIZ[ i ] = USB_DOUTEPS[ epNum ].TSIZ;
x_USB_EP_DMAADDR[ i ] = USB_DOUTEPS[ epNum ].DMAADDR;
}
}
#endif
#if ( FIFO_CNT > 0 )
for ( i = 0; i < FIFO_CNT; i++ )
{
x_USB_DIEPTXFS[ i ] = USB_DIEPTXFS[ i ];
}
#endif
/* Prepare for wakeup on resume and reset. */
USB->DCFG = (USB->DCFG & ~_USB_DCFG_RESVALID_MASK) |
(4 << _USB_DCFG_RESVALID_SHIFT);
USB->DCFG |= USB_DCFG_ENA32KHZSUSP;
USB->GINTMSK = USB_GINTMSK_RESETDETMSK | USB_GINTMSK_WKUPINTMSK;
/* Enter partial powerdown mode. */
USB->PCGCCTL |= USB_PCGCCTL_PWRCLMP;
USB->PCGCCTL |= USB_PCGCCTL_RSTPDWNMODULE;
USB->PCGCCTL |= USB_PCGCCTL_STOPPCLK;
/* Record current clock settings. */
cmuStatus = CMU->STATUS;
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
#ifndef __MBED__
/* Enter EM2 on interrupt exit. */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk;
#else
usbhal_allow_em2(true);
#endif
#endif
/* Switch USBC clock to 32 kHz. */
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
while ( ( CMU->STATUS & CMU_STATUS_USBCLFXOSEL ) == 0 ){}
#else
CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
while ( ( CMU->STATUS & CMU_STATUS_USBCLFRCOSEL ) == 0 ){}
#endif
return true;
}
return false;
}
#endif /* if ( USB_PWRSAVE_MODE ) */
#if ( USB_PWRSAVE_MODE )
/*
* Exit USB core partial powerdown mode, restore essential USB core registers.
* Will prevent re-entry back to EM2.
* Returns true if a powerup sequence was performed.
*/
static bool UsbPowerUp( void )
{
#if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
int i;
#endif
#if ( NUM_EP_USED > 0 )
int epNum;
uint32_t tmp;
USBD_Ep_TypeDef *ep;
#endif
if ( USBD_poweredDown )
{
USBD_poweredDown = false;
DEBUG_USB_INT_LO_PUTCHAR( '/' );
#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
/* Switch HFCLK from HFRCO to HFXO. */
CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
#endif
/* Turn off HFRCO when not needed. */
if ( ( cmuStatus & CMU_STATUS_HFRCOENS ) == 0 )
{
CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
}
/* Exit partial powerdown mode. */
USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE);
if (( USB->GINTSTS & ( USB_GINTSTS_WKUPINT | USB_GINTSTS_RESETDET ) ) == 0)
{
USB->DCTL = x_USB_DCTL | USB_DCTL_RMTWKUPSIG;
USB->DCTL = x_USB_DCTL;
}
/* Restore USB core registers. */
USB->GUSBCFG = x_USB_GUSBCFG;
USB->DCFG = x_USB_DCFG;
#if ( FIFO_CNT > 0 )
for ( i = 0; i < FIFO_CNT; i++ )
{
USB_DIEPTXFS[ i ] = x_USB_DIEPTXFS[ i ];
}
#endif
#if ( NUM_EP_USED > 0 )
for ( i = 0; i < NUM_EP_USED; i++ )
{
ep = &dev->ep[ i+1 ];
epNum = ep->num;
tmp = x_USB_EP_CTL[ i ] &
~( USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK |
USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF );
if ( x_USB_EP_CTL[ i ] & USB_DIEP_CTL_DPIDEOF )
tmp |= USB_DIEP_CTL_SETD1PIDOF;
else
tmp |= USB_DIEP_CTL_SETD0PIDEF;
if ( x_USB_EP_CTL[ i ] & USB_DIEP_CTL_NAKSTS )
tmp |= USB_DIEP_CTL_SNAK;
else
tmp |= USB_DIEP_CTL_CNAK;
if ( ep->in )
{
USB_DINEPS[ epNum ].CTL = tmp;
USB_DINEPS[ epNum ].TSIZ = x_USB_EP_TSIZ[ i ];
USB_DINEPS[ epNum ].DMAADDR = x_USB_EP_DMAADDR[ i ];
}
else
{
USB_DOUTEPS[ epNum ].CTL = tmp;
USB_DOUTEPS[ epNum ].TSIZ = x_USB_EP_TSIZ[ i ];
USB_DOUTEPS[ epNum ].DMAADDR = x_USB_EP_DMAADDR[ i ];
}
}
#endif
USB->PCGCCTL = x_USB_PCGCCTL;
USB->DOEPMSK = x_USB_DOEPMSK;
USB->DIEPMSK = x_USB_DIEPMSK;
USB->DAINTMSK = x_USB_DAINTMSK;
USB->DCTL = x_USB_DCTL;
USB->GNPTXFSIZ = x_USB_GNPTXFSIZ;
USB->GRXFSIZ = x_USB_GRXFSIZ;
USB->GAHBCFG = x_USB_GAHBCFG;
#if defined(_USB_GOTGCTL_MASK)
USB->GOTGCTL = x_USB_GOTGCTL;
#endif
USB->GINTMSK = x_USB_GINTMSK;
USB->DCTL |= USB_DCTL_PWRONPRGDONE;
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
#ifndef __MBED__
/* Do not reenter EM2 on interrupt exit. */
SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
#else
usbhal_allow_em2(false);
#endif
#endif
return true;
}
return false;
}
#endif /* if ( USB_PWRSAVE_MODE ) */
#if defined( USB_DOEP0INT_STUPPKTRCVD )
static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep )
{
uint32_t doeptsiz;
if ( ep->num == 0 )
{
if ( status & USB_DOEP0INT_XFERCOMPL )
{
USB->DOEP0INT = USB_DOEP0INT_XFERCOMPL;
doeptsiz = USB->DOEP0TSIZ;
if ( ep->state == D_EP_IDLE )
{
if ( status & USB_DOEP0INT_STUPPKTRCVD )
{
USB->DOEP0INT = USB_DOEP0INT_STUPPKTRCVD;
}
status = USBDHAL_GetOutEpInts( ep );
doeptsiz = USB->DOEP0TSIZ;
if ( status & USB_DOEP0INT_SETUP )
{
retry:
/* Already started data stage, clear setup */
USB->DOEP0INT = USB_DOEP0INT_SETUP;
status &= ~USB_DOEP0INT_SETUP;
{
int supCnt = ( doeptsiz & _USB_DOEP0TSIZ_SUPCNT_MASK )
>> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
if ( supCnt == 3 )
supCnt = 2;
dev->setup = &dev->setupPkt[ 2 - supCnt ];
}
DEBUG_USB_INT_LO_PUTS( "\nS" );
USBDEP_Ep0Handler( dev );
/* Prepare for more setup packets */
if ( ep->state == D_EP0_IN_STATUS || ep->state == D_EP_TRANSMITTING )
{
USBDHAL_StartEp0Setup( dev );
}
}
else /* xfercompl && idle && !setup */
{
status = USBDHAL_GetOutEpInts( ep );
if ( status & USB_DOEP0INT_SETUP )
goto retry;
USBDHAL_StartEp0Setup( dev );
}
}
else /* ep0state != EP0_IDLE */
{
#ifdef __MBED__
if ( ep->state == D_EP_RECEIVING )
{
int xfer_size = ep->packetSize - (( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_XFERSIZE_MASK )
>> _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
int setup_pkt_received = status & USB_DOEP0INT_SETUP;
if ( (!setup_pkt_received && xfer_size == 0) ||
(setup_pkt_received && xfer_size == 8) )
{
/* Higher levels need to see the correct transfer amount for ZLPs */
ep->remaining = 0;
ep->xferred = 0;
}
else
{
/* FIXME - does not work if actual read size > 56 */
if ( setup_pkt_received ) xfer_size -= 8;
ep->xferred = xfer_size;
ep->remaining -= xfer_size;
}
USBDEP_Ep0Handler( dev );
}
#else
if ( ep->state == D_EP_RECEIVING )
{
if ( ep->remaining > ep->packetSize )
{
ep->remaining -= ep->packetSize;
ep->xferred += ep->packetSize;
}
else
{
ep->xferred += ep->remaining;
ep->remaining = 0;
}
USBDEP_Ep0Handler( dev );
}
else if ( ep->state == D_EP0_OUT_STATUS )
{
USBDEP_Ep0Handler( dev );
}
#endif
}
} /* if ( status & USB_DOEP0INT_XFERCOMPL ) */
if ( status & USB_DOEP0INT_STSPHSERCVD )
{
USB->DOEP0INT = USB_DOEP0INT_STSPHSERCVD;
}
if ( status & USB_DOEP0INT_SETUP )
{
USB->DOEP0INT = USB_DOEP0INT_SETUP;
{
int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
>> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
if ( supCnt == 3 )
supCnt = 2;
dev->setup = &dev->setupPkt[ 2 - supCnt ];
}
DEBUG_USB_INT_LO_PUTS( "\nS" );
USBDEP_Ep0Handler( dev );
}
}
else /* epnum != 0 */
{
if ( status & USB_DOEP_INT_XFERCOMPL )
{
USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_XFERCOMPL;
ep->xferred = ep->hwXferSize -
( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
_USB_DOEP_TSIZ_XFERSIZE_SHIFT );
ep->remaining -= ep->xferred;
USBDEP_EpHandler( ep->addr );
}
}
}
#endif
/** @endcond */
#endif /* defined( USB_DEVICE ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */

View File

@ -0,0 +1,799 @@
/**************************************************************************//**
* @file em_usbhal.c
* @brief USB protocol stack library, low level USB peripheral access.
* @version 3.20.14
******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE ) || defined( USB_HOST )
#include "em_usbtypes.h"
#include "em_usbhal.h"
#if defined( USB_DEVICE )
#include "em_usbd.h"
#endif
#if defined( USB_HOST )
#include "em_usbh.h"
#endif
#include "em_cmu.h"
#include "em_gpio.h"
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#define EPABORT_BREAK_LOOP_COUNT 15000 /* Approx. 100 ms */
/* NOTE: The sequence of error message strings must agree with the */
/* definition of USB_Status_TypeDef enum. */
static const char * const errMsg[] =
{
[ USB_STATUS_OK ] = "No errors",
[ -USB_STATUS_REQ_ERR ] = "Setup request error",
[ -USB_STATUS_EP_BUSY ] = "Endpoint is busy",
[ -USB_STATUS_REQ_UNHANDLED ] = "Setup request not handled",
[ -USB_STATUS_ILLEGAL ] = "Illegal operation attempted",
[ -USB_STATUS_EP_STALLED ] = "Endpoint is stalled",
[ -USB_STATUS_EP_ABORTED ] = "Transfer aborted",
[ -USB_STATUS_EP_ERROR ] = "Transfer error",
[ -USB_STATUS_EP_NAK ] = "Endpoint NAK",
[ -USB_STATUS_DEVICE_UNCONFIGURED ] = "Device is not configured",
[ -USB_STATUS_DEVICE_SUSPENDED ] = "Device is suspended",
[ -USB_STATUS_DEVICE_RESET ] = "Device has been reset",
[ -USB_STATUS_TIMEOUT ] = "Transfer timeout",
[ -USB_STATUS_DEVICE_REMOVED ] = "Device removed",
[ -USB_STATUS_HC_BUSY ] = "Host channel is busy",
[ -USB_STATUS_DEVICE_MALFUNCTION ] = "Device malfunction",
[ -USB_STATUS_PORT_OVERCURRENT ] = "VBUS overcurrent",
};
/** @endcond */
/***************************************************************************//**
* @brief
* Return an error message string for a given error code.
*
* @param[in] error
* Error code, see \ref USB_Status_TypeDef.
*
* @return
* Error message string pointer.
******************************************************************************/
char *USB_GetErrorMsgString( int error )
{
if ( error >= 0 )
return (char*)errMsg[ 0 ];
return (char*)errMsg[ -error ];
}
#if defined( USB_USE_PRINTF )
/***************************************************************************//**
* @brief
* Format and print a text string given an error code, prepends an optional user
* supplied leader string.
*
* @param[in] pre
* Optional leader string to prepend to error message string.
*
* @param[in] error
* Error code, see \ref USB_Status_TypeDef.
******************************************************************************/
void USB_PrintErrorMsgString( char *pre, int error )
{
if ( pre )
{
USB_PRINTF( "%s", pre );
}
if ( error > USB_STATUS_OK )
{
USB_PRINTF( "%d", error );
}
else
{
USB_PRINTF( "%s", USB_GetErrorMsgString( error ) );
}
}
#endif /* defined( USB_USE_PRINTF ) */
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined( DEBUG_EFM_USER )
static void PrintI( int i )
{
#if !defined ( USER_PUTCHAR )
(void)i;
#else
if ( i >= 10 )
{
PrintI( i / 10 );
}
DEBUG_USB_API_PUTCHAR( ( i % 10 ) + '0' );
#endif
}
void assertEFM( const char *file, int line )
{
#if !defined ( USER_PUTCHAR )
(void)file;
#endif
DEBUG_USB_API_PUTS( "\nASSERT " );
DEBUG_USB_API_PUTS( file );
DEBUG_USB_API_PUTCHAR( ' ' );
PrintI( line );
for(;;){}
}
#endif /* defined( DEBUG_EFM_USER ) */
#if defined ( USER_PUTCHAR )
void USB_Puts( const char *p )
{
while( *p )
USB_PUTCHAR( *p++ );
}
#endif /* defined ( USER_PUTCHAR ) */
void USBHAL_CoreReset( void )
{
USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE);
/* Core Soft Reset */
USB->GRSTCTL |= USB_GRSTCTL_CSFTRST;
while ( USB->GRSTCTL & USB_GRSTCTL_CSFTRST ) {}
USBTIMER_DelayUs( 1 );
/* Wait for AHB master IDLE state. */
while ( !( USB->GRSTCTL & USB_GRSTCTL_AHBIDLE ) ) {}
}
#ifdef USB_DEVICE
void USBDHAL_Connect( void )
{
USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_SFTDISCON );
}
USB_Status_TypeDef USBDHAL_CoreInit( uint32_t totalRxFifoSize,
uint32_t totalTxFifoSize )
{
uint8_t i, j;
uint16_t start, depth;
USBD_Ep_TypeDef *ep;
#if !defined( USB_VBUS_SWITCH_NOT_PRESENT )
CMU_ClockEnable( cmuClock_GPIO, true );
GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */
USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */
#else
USB->ROUTE = USB_ROUTE_PHYPEN; /* Enable PHY pins. */
#endif
USBHAL_CoreReset(); /* Reset USB core */
#if defined( USB_GUSBCFG_FORCEHSTMODE )
/* Force Device Mode */
USB->GUSBCFG = ( USB->GUSBCFG &
~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE ) ) |
USB_GUSBCFG_FORCEDEVMODE;
#endif
INT_Enable();
USBTIMER_DelayMs( 50 );
INT_Disable();
/* Set device speed */
USB->DCFG = ( USB->DCFG & ~_USB_DCFG_DEVSPD_MASK ) | 3; /* Full speed PHY */
/* Stall on non-zero len status OUT packets (ctrl transfers). */
USB->DCFG |= USB_DCFG_NZSTSOUTHSHK;
/* Set periodic frame interval to 80% */
USB->DCFG &= ~_USB_DCFG_PERFRINT_MASK;
USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) |
USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR;
/* Ignore frame numbers on ISO transfers. */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_IGNRFRMNUM;
/* Set Rx FIFO size */
start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) &
_USB_GRXFSIZ_RXFDEP_MASK;
/* Set Tx EP0 FIFO size */
depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) |
( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFSTADDR_MASK );
/* Set Tx EP FIFO sizes for all IN ep's */
for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ )
{
for ( i = 1; i <= MAX_NUM_IN_EPS; i++ )
{
ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i );
if ( ep ) /* Is EP in use ? */
{
if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */
{
start += depth;
depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB_DIEPTXFS[ ep->txFifoNum - 1 ] =
( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) |
( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK );
}
}
}
}
if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS )
return USB_STATUS_ILLEGAL;
if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS )
return USB_STATUS_ILLEGAL;
/* Flush the FIFO's */
USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */
USBHAL_FlushRxFifo(); /* The Rx FIFO */
/* Disable all device interrupts */
USB->DIEPMSK = 0;
USB->DOEPMSK = 0;
USB->DAINTMSK = 0;
USB->DIEPEMPMSK = 0;
/* Disable all EP's, clear all EP ints. */
for ( i = 0; i <= MAX_NUM_IN_EPS; i++ )
{
USB_DINEPS[ i ].CTL = 0;
USB_DINEPS[ i ].TSIZ = 0;
USB_DINEPS[ i ].INT = 0xFFFFFFFF;
}
for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ )
{
USB_DOUTEPS[ i ].CTL = 0;
USB_DOUTEPS[ i ].TSIZ = 0;
USB_DOUTEPS[ i ].INT = 0xFFFFFFFF;
}
#if ( USB_DCTL_SFTDISCON_DEFAULT != 0 )
USBD_Connect();
#endif
/* Enable VREGO sense. */
USB->CTRL |= USB_CTRL_VREGOSEN;
USB->IFC = USB_IFC_VREGOSH | USB_IFC_VREGOSL;
USB->IEN = USB_IFC_VREGOSH | USB_IFC_VREGOSL;
/* Force a VREGO interrupt. */
if ( USB->STATUS & USB_STATUS_VREGOS)
USB->IFS = USB_IFS_VREGOSH;
else
USB->IFS = USB_IFS_VREGOSL;
return USB_STATUS_OK;
}
USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize,
uint32_t totalTxFifoSize )
{
uint8_t i, j;
uint16_t start, depth;
USBD_Ep_TypeDef *ep;
/* Set Rx FIFO size */
start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) &
_USB_GRXFSIZ_RXFDEP_MASK;
/* Set Tx EP0 FIFO size */
depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) |
( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFSTADDR_MASK );
/* Set Tx EP FIFO sizes for all IN ep's */
for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ )
{
for ( i = 1; i <= MAX_NUM_IN_EPS; i++ )
{
ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i );
if ( ep ) /* Is EP in use ? */
{
if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */
{
start += depth;
depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS );
USB_DIEPTXFS[ ep->txFifoNum - 1 ] =
( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) |
( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK );
}
}
}
}
if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS )
return USB_STATUS_ILLEGAL;
if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS )
return USB_STATUS_ILLEGAL;
/* Flush the FIFO's */
USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */
USBHAL_FlushRxFifo(); /* The Rx FIFO */
return USB_STATUS_OK;
}
void USBDHAL_Disconnect( void )
{
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SFTDISCON;
}
void USBDHAL_AbortEpIn( USBD_Ep_TypeDef *ep )
{
/* Clear epdis & inepnakeff INT's */
USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD |
USB_DIEP_INT_INEPNAKEFF;
/* Enable epdis & inepnakeff INT's */
USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK;
USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DIEP_CTL_SNAK;
/* Wait for inepnakeff INT */
while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF ) ) {}
USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF;
USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK;
DEBUG_USB_INT_LO_PUTCHAR( '.' );
USBDHAL_SetEPDISNAK( ep );
/* Wait for epdis INT */
while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD ) ) {}
USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD;
USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK;
USBHAL_FlushTxFifo( ep->txFifoNum );
/* Clear any interrupts generated by the abort sequence. */
NVIC_ClearPendingIRQ( USB_IRQn );
DEBUG_USB_INT_LO_PUTCHAR( '.' );
}
void USBDHAL_AbortEpOut( USBD_Ep_TypeDef *ep )
{
int cnt;
/* Clear epdis INT's */
USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD;
/* Clear Global OUT NAK if already set */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK;
USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */
/* Set Global OUT NAK */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK;
/* Wait for goutnakeff */
cnt = EPABORT_BREAK_LOOP_COUNT;
while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt )
{
cnt--;
}
USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */
USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */
DEBUG_USB_INT_LO_PUTCHAR( ',' );
USBDHAL_SetEPDISNAK( ep ); /* Disable ep */
/* Wait for epdis INT */
cnt = EPABORT_BREAK_LOOP_COUNT;
while ( !( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) && cnt )
{
cnt--;
}
USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD;
USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */
/* Clear Global OUT NAK */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK;
/* Clear any interrupts generated by the abort sequence. */
NVIC_ClearPendingIRQ( USB_IRQn );
DEBUG_USB_INT_LO_PUTCHAR( ',' );
}
void USBDHAL_AbortAllEps( void )
{
int i, cnt;
USBD_Ep_TypeDef *ep;
uint16_t im, om, inmask=0, outmask=0;
/* Clear epdis & inepnakeff INT's */
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[i];
if ( ep->state != D_EP_IDLE )
{
if ( ep->in )
{
inmask |= ep->mask;
USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD |
USB_DIEP_INT_INEPNAKEFF;
}
else
{
outmask |= ep->mask;
USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD;
}
}
}
if ( inmask )
{
/* Enable epdis & inepnakeff INT's */
USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK;
/* Set NAK on all IN ep's */
im = inmask;
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[i];
if ( im & ep->mask )
{
USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL &
~DEPCTL_WO_BITMASK ) |
USB_DIEP_CTL_SNAK;
}
}
}
if ( outmask )
{
/* Clear Global OUT NAK if already set */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK;
USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */
/* Set Global OUT NAK */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK;
/* Wait for goutnakeff */
cnt = EPABORT_BREAK_LOOP_COUNT;
while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt )
{
cnt--;
}
USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */
USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */
}
if ( inmask )
{
/* Wait for inepnakeff INT on all IN ep's */
im = inmask;
cnt = EPABORT_BREAK_LOOP_COUNT;
do
{
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[i];
if ( im & ep->mask )
{
if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF )
{
USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF;
im &= ~ep->mask;
}
}
}
cnt--;
} while ( im && cnt );
USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK;
}
DEBUG_USB_INT_LO_PUTCHAR( '\'' );
/* Disable ep's */
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[i];
if ( ep->state != D_EP_IDLE )
{
USBDHAL_SetEPDISNAK( ep );
}
}
/* Wait for epdis INT */
im = inmask;
om = outmask;
cnt = EPABORT_BREAK_LOOP_COUNT;
do
{
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &dev->ep[i];
if ( ep->in && ( im & ep->mask ) )
{
if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD )
{
USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD;
im &= ~ep->mask;
}
}
if ( !ep->in && ( om & ep->mask ) )
{
if ( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD )
{
USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD;
om &= ~ep->mask;
}
}
}
cnt--;
} while ( ( im || om ) && cnt );
if ( inmask )
{
USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */
USBHAL_FlushTxFifo( 0x10 ); /* Flush all Tx FIFO's */
}
if ( outmask )
{
USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */
/* Clear Global OUT NAK */
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK;
}
DEBUG_USB_INT_LO_PUTCHAR( '\'' );
}
void USBDHAL_AbortAllTransfers( USB_Status_TypeDef reason )
{
int i;
USBD_Ep_TypeDef *ep;
USB_XferCompleteCb_TypeDef callback;
if ( reason != USB_STATUS_DEVICE_RESET )
{
USBDHAL_AbortAllEps();
}
for ( i = 1; i <= NUM_EP_USED; i++ )
{
ep = &(dev->ep[i]);
if ( ep->state != D_EP_IDLE )
{
ep->state = D_EP_IDLE;
if ( ep->xferCompleteCb )
{
callback = ep->xferCompleteCb;
ep->xferCompleteCb = NULL;
if ( ( dev->lastState == USBD_STATE_CONFIGURED ) &&
( dev->state == USBD_STATE_ADDRESSED ) )
{
USBDHAL_DeactivateEp( ep );
}
DEBUG_TRACE_ABORT( reason );
callback( reason, ep->xferred, ep->remaining );
}
}
}
/* Clear any interrupts generated by the abort sequence. */
NVIC_ClearPendingIRQ( USB_IRQn );
}
#endif /* defined( USB_DEVICE ) */
#if defined( USB_HOST )
USB_Status_TypeDef USBHHAL_CoreInit( uint32_t rxFifoSize,
uint32_t nptxFifoSize,
uint32_t ptxFifoSize )
{
uint8_t i;
rxFifoSize /= 4; /* Convert from byte count to word count. */
nptxFifoSize /= 4;
ptxFifoSize /= 4;
CMU_ClockEnable( cmuClock_GPIO, true );
GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */
#if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE )
/* Enable VBUS overcurrent flag pin. */
GPIO_PinModeSet( USB_VBUSOVRCUR_PORT, USB_VBUSOVRCUR_PIN, gpioModeInput, 0 );
#endif
USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */
USBHAL_CoreReset(); /* Reset USB core */
/* Force Host Mode */
USB->GUSBCFG = ( USB->GUSBCFG &
~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEDEVMODE ) ) |
USB_GUSBCFG_FORCEHSTMODE;
INT_Enable();
USBTIMER_DelayMs( 100 );
INT_Disable();
/* Set 48 MHz PHY clock, FS/LS mode */
USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) |
( 1 << _USB_HCFG_FSLSPCLKSEL_SHIFT ) |
( USB_HCFG_FSLSSUPP );
USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) |
USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR;
/* Set Rx FIFO size */
USB->GRXFSIZ = ( rxFifoSize << _USB_GRXFSIZ_RXFDEP_SHIFT ) &
_USB_GRXFSIZ_RXFDEP_MASK;
/* Set Tx FIFO sizes */
USB->GNPTXFSIZ = ( ( nptxFifoSize <<
_USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) |
( ( rxFifoSize <<
_USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) &
_USB_GNPTXFSIZ_NPTXFSTADDR_MASK );
USB->HPTXFSIZ = ( ( ptxFifoSize << _USB_HPTXFSIZ_PTXFSIZE_SHIFT ) &
_USB_HPTXFSIZ_PTXFSIZE_MASK ) |
( ( ( rxFifoSize + nptxFifoSize )
<< _USB_HPTXFSIZ_PTXFSTADDR_SHIFT ) &
_USB_HPTXFSIZ_PTXFSTADDR_MASK );
/* Flush Tx and Rx FIFO's */
USBHAL_FlushTxFifo( 0x10 );
USBHAL_FlushRxFifo();
for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ )
{
USB->HC[ i ].CHAR = USB_HC_CHAR_CHDIS; /* Disable channel */
USB->HC[ i ].INT = 0xFFFFFFFF; /* Clear pending interrupts */
}
/* Enable and halt all channels */
for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ )
{
USB->HC[ i ].CHAR |= USB_HC_CHAR_CHDIS | USB_HC_CHAR_CHENA;
do
{
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
}
while ( USB->HC[ i ].CHAR & USB_HC_CHAR_CHENA );
}
/* Disable all interrupts */
for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ )
{
USB->HC[ i ].INTMSK = 0;
}
USB->HAINTMSK = 0;
return USB_STATUS_OK;
}
void USBHHAL_HCHalt( int hcnum, uint32_t hcchar )
{
hcchar |= USB_HC_CHAR_CHENA | USB_HC_CHAR_CHDIS;
USB->HC[ hcnum ].CHAR = hcchar;
}
void USBHHAL_HCInit( int hcnum )
{
USBH_Ep_TypeDef *ep;
ep = hcs[ hcnum ].ep;
USB->HC[ hcnum ].INT = 0xFFFFFFFF; /* Clear all interrupt flags */
switch ( ep->type ) /* Enable host channel int. types */
{
case USB_EPTYPE_CTRL:
case USB_EPTYPE_BULK:
case USB_EPTYPE_INTR:
USB->HC[ hcnum ].INTMSK = USB_HC_INT_CHHLTD;
break;
}
hcs[ hcnum ].errorCnt = 0;
USB->HAINTMSK |= 1 << hcnum; /* Enable host channel interrupt */
USB->HC[ hcnum ].CHAR = /* Program HCCHAR register */
( ep->parentDevice->addr << _USB_HC_CHAR_DEVADDR_SHIFT ) |
( ( ep->addr & USB_EPNUM_MASK ) << _USB_HC_CHAR_EPNUM_SHIFT ) |
( ep->type << _USB_HC_CHAR_EPTYPE_SHIFT ) |
( ep->packetSize << _USB_HC_CHAR_MPS_SHIFT ) |
( ep->in ? USB_HC_CHAR_EPDIR : 0 ) |
( ep->parentDevice->speed ==
HPRT_L_SPEED >> _USB_HPRT_PRTSPD_SHIFT
? USB_HC_CHAR_LSPDDEV : 0 );
}
void USBHHAL_HCStart( int hcnum )
{
USBH_Hc_TypeDef *hc;
uint16_t packets, len;
hc = &hcs[ hcnum ];
hc->status = 0;
hc->idle = false;
if ( hc->remaining > 0 )
{
packets = ( hc->remaining + hc->ep->packetSize - 1 ) / hc->ep->packetSize;
}
else
{
packets = 1;
}
if ( hc->ep->in )
{
len = packets * hc->ep->packetSize;
}
else
{
len = hc->remaining;
}
/* Initialize the HCTSIZn register */
hc->hwXferSize = len;
USB->HC[ hcnum ].TSIZ =
( ( len << _USB_HC_TSIZ_XFERSIZE_SHIFT ) &
_USB_HC_TSIZ_XFERSIZE_MASK ) |
( ( packets << _USB_HC_TSIZ_PKTCNT_SHIFT ) &
_USB_HC_TSIZ_PKTCNT_MASK ) |
( ( hc->ep->toggle << _USB_HC_TSIZ_PID_SHIFT ) &
_USB_HC_TSIZ_PID_MASK );
USB->HC[ hcnum ].DMAADDR = (uint32_t)hc->buf;
USBHHAL_HCActivate( hcnum,
USB->HC[ hcnum ].CHAR,
hc->ep->type == USB_EPTYPE_INTR );
}
#endif /* defined( USB_HOST ) */
/** @endcond */
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */

View File

@ -0,0 +1,381 @@
/***************************************************************************//**
* @file em_usbtimer.c
* @brief USB protocol stack library, timer API.
* @version 3.20.14
*******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
* 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.
*
******************************************************************************/
#include "em_device.h"
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
#include "em_usb.h"
#if defined( USB_DEVICE ) || defined( USB_HOST )
#include "em_cmu.h"
#include "em_timer.h"
#include "em_usbtypes.h"
#include "em_usbhal.h"
#include "device_peripherals.h"
/*
* Use one HW timer to serve n software milisecond timers.
* A timer is, when running, in a linked list of timers.
* A given timers timeout period is the acculmulated timeout
* of all timers preceeding it in the queue.
* This makes timer start (linked list insertion) computing intensive,
* but the checking of the queue at each tick very effective.
* ______ ______ ______
* | | --->| | --->| |
* head --> | | | | | | | |
* |______|--- |______|--- |______|---/ NULL
*/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#ifndef USB_TIMER
#error HW platform must define the timer to use for USB
#endif
#if ( USB_TIMER == USB_TIMER0 ) && ( TIMER_COUNT >= 1 )
#define TIMER TIMER0
#define TIMER_CLK cmuClock_TIMER0
#define TIMER_IRQ TIMER0_IRQn
#define TIMER_IRQHandler TIMER0_IRQHandler
#elif ( USB_TIMER == USB_TIMER1 ) && ( TIMER_COUNT >= 2 )
#define TIMER TIMER1
#define TIMER_CLK cmuClock_TIMER1
#define TIMER_IRQ TIMER1_IRQn
#define TIMER_IRQHandler TIMER1_IRQHandler
#elif ( USB_TIMER == USB_TIMER2 ) && ( TIMER_COUNT >= 3 )
#define TIMER TIMER2
#define TIMER_CLK cmuClock_TIMER2
#define TIMER_IRQ TIMER2_IRQn
#define TIMER_IRQHandler TIMER2_IRQHandler
#elif ( USB_TIMER == USB_TIMER3 ) && ( TIMER_COUNT == 4 )
#define TIMER TIMER3
#define TIMER_CLK cmuClock_TIMER3
#define TIMER_IRQ TIMER3_IRQn
#define TIMER_IRQHandler TIMER3_IRQHandler
#else
#error "Illegal USB TIMER definition"
#endif
typedef struct _timer
{
uint32_t timeout; /* Delta value relative to prev. timer */
struct _timer *next;
USBTIMER_Callback_TypeDef callback;
bool running;
} USBTIMER_Timer_TypeDef;
#if ( NUM_QTIMERS > 0 )
static USBTIMER_Timer_TypeDef timers[ NUM_QTIMERS ];
static USBTIMER_Timer_TypeDef *head = NULL;
#endif
static uint32_t ticksPrMs, ticksPr1us, ticksPr10us, ticksPr100us;
#if ( NUM_QTIMERS > 0 )
static void TimerTick( void );
void TIMER_IRQHandler( void )
{
uint32_t flags;
flags = TIMER_IntGet( TIMER );
if ( flags & TIMER_IF_CC0 )
{
TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
TIMER_CompareSet( TIMER, 0, TIMER_CaptureGet( TIMER, 0 ) + ticksPrMs );
TimerTick();
}
}
#endif /* ( NUM_QTIMERS > 0 ) */
static void DelayTicks( uint16_t ticks )
{
uint16_t startTime;
volatile uint16_t now;
if ( ticks )
{
startTime = TIMER_CounterGet( TIMER );
do
{
now = TIMER_CounterGet(TIMER);
} while ( (uint16_t)( now - startTime ) < ticks );
}
}
/** @endcond */
/** @addtogroup USB_COMMON
* @{*/
/***************************************************************************//**
* @brief
* Active wait millisecond delay function. Can also be used inside
* interrupt handlers.
*
* @param[in] msec
* Number of milliseconds to wait.
******************************************************************************/
void USBTIMER_DelayMs( uint32_t msec )
{
uint64_t totalTicks;
totalTicks = (uint64_t)ticksPrMs * msec;
while ( totalTicks > 20000 )
{
DelayTicks( 20000 );
totalTicks -= 20000;
}
DelayTicks( (uint16_t)totalTicks );
}
/***************************************************************************//**
* @brief
* Active wait microsecond delay function. Can also be used inside
* interrupt handlers.
*
* @param[in] usec
* Number of microseconds to wait.
******************************************************************************/
void USBTIMER_DelayUs( uint32_t usec )
{
uint64_t totalTicks;
totalTicks = (uint64_t)ticksPr1us * usec;
if ( totalTicks == 0 )
{
usec /= 10;
totalTicks = (uint64_t)ticksPr10us * usec;
if ( totalTicks == 0 )
{
usec /= 10;
totalTicks = (uint64_t)ticksPr100us * usec;
}
}
while ( totalTicks > 60000 )
{
DelayTicks( 60000 );
totalTicks -= 60000;
}
DelayTicks( (uint16_t)totalTicks );
}
/***************************************************************************//**
* @brief
* Activate the hardware timer used to pace the 1 millisecond timer system.
*
* @details
* Call this function whenever the HFPERCLK frequency is changed.
* This function is initially called by HOST and DEVICE stack xxxx_Init()
* functions.
******************************************************************************/
void USBTIMER_Init( void )
{
uint32_t freq;
TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
freq = CMU_ClockFreqGet( cmuClock_HFPER );
ticksPrMs = ( freq + 500 ) / 1000;
ticksPr1us = ( freq + 500000 ) / 1000000;
ticksPr10us = ( freq + 50000 ) / 100000;
ticksPr100us = ( freq + 5000 ) / 10000;
timerCCInit.mode = timerCCModeCompare;
CMU_ClockEnable( TIMER_CLK, true );
TIMER_TopSet( TIMER, 0xFFFF );
TIMER_InitCC( TIMER, 0, &timerCCInit );
TIMER_Init( TIMER, &timerInit );
#if ( NUM_QTIMERS > 0 )
TIMER_IntClear( TIMER, 0xFFFFFFFF );
TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
TIMER_CompareSet( TIMER, 0, TIMER_CounterGet( TIMER ) + ticksPrMs );
NVIC_ClearPendingIRQ( TIMER_IRQ );
NVIC_EnableIRQ( TIMER_IRQ );
#endif /* ( NUM_QTIMERS > 0 ) */
}
#if ( NUM_QTIMERS > 0 ) || defined( DOXY_DOC_ONLY )
/***************************************************************************//**
* @brief
* Start a timer.
*
* @details
* If the timer is already running, it will be restarted with new timeout.
*
* @param[in] id
* Timer id (0..).
*
* @param[in] timeout
* Number of milliseconds before timer will elapse.
*
* @param[in] callback
* Function to be called on timer elapse, ref. @ref USBTIMER_Callback_TypeDef.
******************************************************************************/
void USBTIMER_Start( uint32_t id, uint32_t timeout,
USBTIMER_Callback_TypeDef callback )
{
uint32_t accumulated;
USBTIMER_Timer_TypeDef *this, **last;
INT_Disable();
if ( timers[ id ].running )
{
USBTIMER_Stop( id );
}
if ( timeout == 0 )
{
callback();
INT_Enable();
return;
}
timers[ id ].running = true;
timers[ id ].callback = callback;
timers[ id ].next = NULL;
if ( !head ) /* Queue empty ? */
{
timers[ id ].timeout = timeout;
head = &timers[ id ];
}
else
{
this = head;
last = &head;
accumulated = 0;
/* Do a sorted insert */
while ( this )
{
if ( timeout < accumulated + this->timeout ) /* Insert before "this" ? */
{
timers[ id ].timeout = timeout - accumulated;
timers[ id ].next = this;
*last = &timers[ id ];
this->timeout -= timers[ id ].timeout; /* Adjust timeout */
break;
}
else if ( this->next == NULL ) /* At end of queue ? */
{
timers[ id ].timeout = timeout - accumulated - this->timeout;
this->next = &timers[ id ];
break;
}
accumulated += this->timeout;
last = &this->next;
this = this->next;
}
}
INT_Enable();
}
/***************************************************************************//**
* @brief
* Stop a timer.
*
* @param[in] id
* Timer id (0..).
******************************************************************************/
void USBTIMER_Stop( uint32_t id )
{
USBTIMER_Timer_TypeDef *this, **last;
INT_Disable();
if ( head ) /* Queue empty ? */
{
this = head;
last = &head;
timers[ id ].running = false;
while ( this )
{
if ( this == &timers[ id ] ) /* Correct timer ? */
{
if ( this->next )
{
this->next->timeout += timers[ id ].timeout; /* Adjust timeout */
}
*last = this->next;
break;
}
last = &this->next;
this = this->next;
}
}
INT_Enable();
}
#endif /* ( NUM_QTIMERS > 0 ) */
/** @} (end addtogroup USB_COMMON) */
#if ( NUM_QTIMERS > 0 )
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
static void TimerTick( void )
{
USBTIMER_Callback_TypeDef cb;
INT_Disable();
if ( head )
{
head->timeout--;
while ( head )
{
if ( head->timeout == 0 )
{
cb = head->callback;
head->running = false;
head = head->next;
/* The callback may place new items in the queue !!! */
if ( cb )
{
(cb)();
}
continue; /* There might be more than one timeout pr. tick */
}
break;
}
}
INT_Enable();
}
/** @endcond */
#endif /* ( NUM_QTIMERS > 0 ) */
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */

View File

@ -49,6 +49,8 @@ typedef enum {
#include "USBEndpoints_RZ_A1H.h"
#elif defined(TARGET_Maxim)
#include "USBEndpoints_Maxim.h"
#elif defined(TARGET_EFM32GG_STK3700) || defined(TARGET_EFM32LG_STK3600) || defined(TARGET_EFM32WG_STK3800) || defined(TARGET_EFM32HG_STK3400)
#include "USBEndpoints_EFM32.h"
#else
#error "Unknown target type"
#endif

View File

@ -0,0 +1,65 @@
#ifndef TARGET_EFM32HG_STK3400
# define NUMBER_OF_LOGICAL_ENDPOINTS (6)
#else
# define NUMBER_OF_LOGICAL_ENDPOINTS (3)
#endif
#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
#define NUMBER_OF_ENDPOINTS (NUMBER_OF_PHYSICAL_ENDPOINTS + 2) /* Includes EP0 */
#define EP0OUT (0)
#define EP0IN (1)
#define EP1OUT (2)
#define EP1IN (3)
#define EP2OUT (4)
#define EP2IN (5)
#define EP3OUT (6)
#define EP3IN (7)
#ifndef TARGET_EFM32HG_STK3400
# define EP4OUT (8)
# define EP4IN (9)
# define EP5OUT (10)
# define EP5IN (11)
# define EP6OUT (12)
# define EP6IN (13)
#endif
#define USB_EP_TO_INDEX(ep) (ep)
#define USB_EP_TO_ADDR(ep) (((ep)>>1) | (((ep) & 1 ) ? 0x80 : 0x00))
#define USB_ADDR_TO_EP(ep) (((ep)<<1) | (((ep) & 0x80) ? 0x01 : 0x00))
/* Maximum Packet sizes */
#define MAX_PACKET_SIZE_EP0 64
#define MAX_PACKET_SIZE_EP1 64
#define MAX_PACKET_SIZE_EP2 64
#define MAX_PACKET_SIZE_EP3 64
#ifndef TARGET_EFM32HG_STK3400
# define MAX_PACKET_SIZE_EP4 64
# define MAX_PACKET_SIZE_EP5 64
# define MAX_PACKET_SIZE_EP6 64
#endif
/* Generic endpoints - intended to be portable accross devices */
/* and be suitable for simple USB devices. */
/* Bulk endpoints */
#define EPBULK_OUT EP2OUT
#define EPBULK_IN EP2IN
#define EPBULK_OUT_callback EP2_OUT_callback
#define EPBULK_IN_callback EP2_IN_callback
/* Interrupt endpoints */
#define EPINT_OUT EP1OUT
#define EPINT_IN EP1IN
#define EPINT_OUT_callback EP1_OUT_callback
#define EPINT_IN_callback EP1_IN_callback
/* Isochronous endpoints */
#define EPISO_OUT EP3OUT
#define EPISO_IN EP3IN
#define EPISO_OUT_callback EP3_OUT_callback
#define EPISO_IN_callback EP3_IN_callback
#define MAX_PACKET_SIZE_EPBULK 64
#define MAX_PACKET_SIZE_EPINT 64
#define MAX_PACKET_SIZE_EPISO 1023

View File

@ -0,0 +1,775 @@
/* Copyright 2015 Silicon Labs, http://www.silabs.com
*
* 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.
*/
#if defined TARGET_EFM32GG_STK3700 || \
defined TARGET_EFM32LG_STK3600 || \
defined TARGET_EFM32WG_STK3800 || \
defined TARGET_EFM32HG_STK3400
#include "USBHAL.h"
#include "em_usb.h"
#include "em_usbtypes.h"
#include "em_usbhal.h"
#include "em_usbd.h"
#include "sleepmodes.h"
enum USBISRCommand {
CMD_HANDLED = 0,
CMD_EP0SETUP,
CMD_EP0IN,
CMD_EP0OUT,
CMD_EP_XFER_COMPLETED,
CMD_SOF,
CMD_BUSRESET,
CMD_SUSPEND_STATE_CHANGED,
CMD_ENUM_END_MARKER
};
enum IEPStatus {
NOT_CONFIGURED = 0,
IDLE = 1,
READ_PENDING = 2,
WRITE_PENDING = 3,
READ_COMPLETE = 4,
WRITE_COMPLETE = 5,
FAILED_INVALID = 6,
FAILED_STALLED = 7
};
typedef struct {
IEPStatus status;
uint32_t byte_count;
uint32_t max_packet;
USB_XferCompleteCb_TypeDef intern_cb;
uint8_t *data_buf;
} ep_state_t;
USBHAL * USBHAL::instance;
static uint8_t ep0setupdata[8];
static ep_state_t ep_state[NUMBER_OF_ENDPOINTS];
#ifdef USB_USE_DYNAMIC_MEMORY
static uint8_t ep0in_data_buf[MAX_PACKET_SIZE_EP0] __attribute__ ((aligned (4)));
static uint8_t ep0out_data_buf[MAX_PACKET_SIZE_EP0]; // FIXME: does this need to be this big?
#else
static uint8_t ep_data_buf[NUMBER_OF_ENDPOINTS][64] __attribute__ ((aligned (4)));
#endif
static void run_cmd(USBISRCommand cmd, uint32_t param);
static void (*isrptr)() = NULL;
static USBISRCommand usb_isrcmd = CMD_HANDLED;
static uint32_t usb_isrcmd_param = 0;
extern "C" void usbhal_allow_em2(bool allow_em2);
#ifdef DEBUG_USB_API
#define TRACE(fmt,...) printf("USB: %s: " fmt "\n", __func__, __VA_ARGS__);
#define TRACE_FUNC_IN printf("USB: > %s\n",__func__);
#define TRACE_FUNC_IN_P(fmt, ...) printf("USB: > %s: " fmt "\n", __func__, __VA_ARGS__);
#else
#define TRACE(fmt,...)
#define TRACE_FUNC_IN
#define TRACE_FUNC_IN_P(fmt, ...)
#endif
static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize);
static int usbhal_xfer_complete_cb(uint8_t epaddr, USB_Status_TypeDef status,
uint32_t xferred, uint32_t remaining);
static void usbhal_free_buffers(void);
/* Internal EP transfer complete callbacks */
#define EPCB(n) static int usbhal_xfer_complete_cb_##n(USB_Status_TypeDef status, \
uint32_t xferred, uint32_t remaining) { \
return usbhal_xfer_complete_cb(n, status, xferred, remaining); \
}
/* ------^ */
EPCB(EP0OUT)
EPCB(EP0IN)
EPCB(EP1OUT)
EPCB(EP1IN)
EPCB(EP2OUT)
EPCB(EP2IN)
EPCB(EP3OUT)
EPCB(EP3IN)
#ifndef TARGET_EFM32HG_STK3400
EPCB(EP4OUT)
EPCB(EP4IN)
EPCB(EP5OUT)
EPCB(EP5IN)
EPCB(EP6OUT)
EPCB(EP6IN)
#endif
static inline bool is_aligned(const void *pointer, size_t byte_count)
{
return ((uintptr_t)pointer % byte_count == 0);
}
USBHAL::USBHAL(void)
{
TRACE_FUNC_IN;
isrptr = &USBHAL::_usbisr;
if (instance) {
TRACE("Assert self failed! instance=%p", instance);
abort();
}
instance = this;
// When USB is active, we can't go below EM1. This block may
// be dynamically removed/reinstated to allow deeper sleep.
usbhal_allow_em2(false);
// When in suspend / Vbus off we can go to EM2, but never below
// that as long as USB is being used. Despite the name the call here
// blocks entering modes _below_ EM2, but allows EM2.
blockSleepMode(EM2);
epCallback[EP0OUT] = NULL;
epCallback[EP0IN ] = NULL;
epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback;
epCallback[EP1IN ] = &USBHAL::EP1_IN_callback;
epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback;
epCallback[EP2IN ] = &USBHAL::EP2_IN_callback;
epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback;
epCallback[EP3IN ] = &USBHAL::EP3_IN_callback;
#ifndef TARGET_EFM32HG_STK3400
epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback;
epCallback[EP4IN ] = &USBHAL::EP4_IN_callback;
epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback;
epCallback[EP5IN ] = &USBHAL::EP5_IN_callback;
epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback;
epCallback[EP6IN ] = &USBHAL::EP6_IN_callback;
#endif
memset(ep_state, 0, sizeof(ep_state));
ep_state[EP0OUT].intern_cb = usbhal_xfer_complete_cb_EP0OUT;
ep_state[EP0IN ].intern_cb = usbhal_xfer_complete_cb_EP0IN;
ep_state[EP1OUT].intern_cb = usbhal_xfer_complete_cb_EP1OUT;
ep_state[EP1IN ].intern_cb = usbhal_xfer_complete_cb_EP1IN;
ep_state[EP2OUT].intern_cb = usbhal_xfer_complete_cb_EP2OUT;
ep_state[EP2IN ].intern_cb = usbhal_xfer_complete_cb_EP2IN;
ep_state[EP3OUT].intern_cb = usbhal_xfer_complete_cb_EP3OUT;
ep_state[EP3IN ].intern_cb = usbhal_xfer_complete_cb_EP3IN;
#ifndef TARGET_EFM32HG_STK3400
ep_state[EP4OUT].intern_cb = usbhal_xfer_complete_cb_EP4OUT;
ep_state[EP4IN ].intern_cb = usbhal_xfer_complete_cb_EP4IN;
ep_state[EP5OUT].intern_cb = usbhal_xfer_complete_cb_EP5OUT;
ep_state[EP5IN ].intern_cb = usbhal_xfer_complete_cb_EP5IN;
ep_state[EP6OUT].intern_cb = usbhal_xfer_complete_cb_EP6OUT;
ep_state[EP6IN ].intern_cb = usbhal_xfer_complete_cb_EP6IN;
#endif
#ifdef USB_USE_DYNAMIC_MEMORY
ep_state[EP0OUT].data_buf = ep0out_data_buf;
ep_state[EP0IN].data_buf = ep0in_data_buf;
#else
for (int i=0 ; i<NUMBER_OF_ENDPOINTS ; i++) {
ep_state[i].data_buf = ep_data_buf[i];
}
#endif
}
USBHAL::~USBHAL(void)
{
TRACE_FUNC_IN;
USBD_AbortAllTransfers();
USBD_Disconnect();
usbhal_free_buffers();
usbhal_allow_em2(true);
unblockSleepMode(EM2);
}
extern "C" void usbhal_allow_em2(bool allow_em2)
{
if (allow_em2) {
// unblockSleepMode is safe to call even if we would unblock
// an already unblocked mode, so no checks here.
unblockSleepMode(EM1);
} else {
blockSleepMode(EM1);
}
}
static void usbhal_reset_cb(void)
{
TRACE_FUNC_IN;
run_cmd(CMD_BUSRESET, 0);
}
#ifdef DEBUG_USB_API
static const char *usbstate[] = { "NONE", "ATTACHED", "POWERED", "DEFAULT",
"ADDRESSED", "CONFIGURED", "SUSPENDED", "???" };
#endif
static void usbhal_state_change_cb(USBD_State_TypeDef oldState,
USBD_State_TypeDef newState)
{
TRACE("state changed %s -> %s", usbstate[oldState], usbstate[newState]);
if (oldState == USBD_STATE_SUSPENDED) {
run_cmd(CMD_SUSPEND_STATE_CHANGED, 0);
}
if (newState == USBD_STATE_SUSPENDED) {
run_cmd(CMD_SUSPEND_STATE_CHANGED, 1);
}
// Should call connectStateChanged from here as well but there is
// no documentation on when to actually do so. (And the implementation
// in USBDevice.cpp is a stub)
// HACK! Since connectStateChanged is not used, indicate the loss
// off connection by reporting a bus reset. This causes USBDevice
// to realise that at least it's not in CONFIGURED anymore, and
// stop trying to read/write in a busyloop.
if (newState == USBD_STATE_NONE) {
run_cmd(CMD_BUSRESET, 0);
}
}
static int usbhal_setupcmd_cb(const USB_Setup_TypeDef *setup)
{
TRACE_FUNC_IN;
if (!setup) {
EFM_ASSERT(false);
return USB_STATUS_REQ_ERR;
}
memcpy(ep0setupdata, setup, 8);
run_cmd(CMD_EP0SETUP, 0);
return USB_STATUS_OK;
}
static void usbhal_sof_cb(uint16_t frameNum)
{
run_cmd(CMD_SOF, frameNum);
}
static void usbhal_free_buffers(void)
{
#ifdef USB_USE_DYNAMIC_MEMORY
TRACE_FUNC_IN;
for (int i=EP1OUT ; i<NUMBER_OF_ENDPOINTS ; i++ ) {
if (ep_state[i].data_buf) {
free(ep_state[i].data_buf);
ep_state[i].data_buf = NULL;
}
}
#endif
}
void USBHAL::connect(void)
{
TRACE_FUNC_IN;
// Init datastructures must be static - driver will use these even after the init function exits!
static const uint8_t buffer_multiplier[] = { 1 }; // Mult 1 for control EP
static const USBD_Callbacks_TypeDef usbd_callbacks = {
.usbReset = usbhal_reset_cb,
.usbStateChange = usbhal_state_change_cb,
.setupCmd = usbhal_setupcmd_cb,
.isSelfPowered = NULL,
.sofInt = usbhal_sof_cb
};
USBD_Init_TypeDef initdata = {
.deviceDescriptor = NULL,
.configDescriptor = NULL,
.stringDescriptors = NULL,
.numberOfStrings = 0,
.bufferingMultiplier = buffer_multiplier,
.callbacks = &usbd_callbacks,
.reserved = 0
};
int ret = USBD_Init(&initdata);
TRACE("init = %d, devicedesc = %lx, configdesc = %lx", ret,
(uint32_t) initdata.deviceDescriptor,
(uint32_t) initdata.configDescriptor);
EFM_ASSERT(ret == USB_STATUS_OK);
}
void USBHAL::disconnect(void)
{
TRACE_FUNC_IN;
USBD_Disconnect();
}
void USBHAL::configureDevice(void)
{
TRACE_FUNC_IN;
USBD_SetUsbState(USBD_STATE_CONFIGURED);
}
void USBHAL::unconfigureDevice(void)
{
TRACE_FUNC_IN;
USBD_SetUsbState(USBD_STATE_DEFAULT);
usbhal_free_buffers();
}
void USBHAL::setAddress(uint8_t address)
{
TRACE_FUNC_IN_P("addr 0x%x", (unsigned)address);
USBD_SetAddress(address);
}
void USBHAL::remoteWakeup(void)
{
TRACE_FUNC_IN;
USBD_RemoteWakeup();
}
void USBHAL::EP0setup(uint8_t *buffer)
{
TRACE_FUNC_IN;
EFM_ASSERT(buffer);
if (buffer) {
memcpy(buffer, ep0setupdata, 8);
}
}
void USBHAL::EP0read(void)
{
TRACE_FUNC_IN;
(void)internEndpointRead(0, MAX_PACKET_SIZE_EP0);
}
void USBHAL::EP0readStage(void)
{
TRACE_FUNC_IN;
// Not needed
}
uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
{
TRACE_FUNC_IN;
EFM_ASSERT(buffer);
uint32_t read = 0;
endpointReadResult(0, buffer, &read);
return read;
}
static int usbhal_xfer_complete_cb(uint8_t ep, USB_Status_TypeDef status,
uint32_t xferred, uint32_t remaining)
{
TRACE_FUNC_IN_P("ep 0x%x, status %u, xferred %lu, rem %lu",
ep, status, xferred, remaining);
if (ep >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return USB_STATUS_REQ_ERR;
}
switch (ep) {
case EP0OUT:
if (ep_state[EP0OUT].status == READ_PENDING) {
ep_state[EP0OUT].status = READ_COMPLETE;
ep_state[EP0OUT].byte_count = xferred;
// drop zlp
if (xferred == 0) {
break;
}
}
run_cmd(CMD_EP0OUT, 0);
break;
case EP0IN:
run_cmd(CMD_EP0IN, 0);
break;
default:
bool write = ep & 1;
if (status == USB_STATUS_OK) {
if (!write && ep_state[ep].status == READ_PENDING) {
ep_state[ep].status = READ_COMPLETE;
ep_state[ep].byte_count = xferred;
} else if (write && ep_state[ep].status == WRITE_PENDING) {
ep_state[ep].status = WRITE_COMPLETE;
} else {
ep_state[ep].status = FAILED_INVALID;
}
} else {
ep_state[ep].status = FAILED_INVALID;
}
if (ep_state[ep].status != FAILED_INVALID) {
run_cmd(CMD_EP_XFER_COMPLETED, ep);
}
break;
}
return USB_STATUS_OK;
}
void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
{
//TRACE_FUNC_IN_P("buffer %lx, size %lu", (uint32_t) buffer, size);
int ret;
USB_XferCompleteCb_TypeDef cb = ep_state[EP0IN].intern_cb;
EFM_ASSERT((buffer != NULL) || (size == 0));
EFM_ASSERT(size <= MAX_PACKET_SIZE_EP0);
if (!buffer || size == 0) {
// No callback after writing EP0 ZLP
cb = NULL;
}
if (buffer && !is_aligned(buffer,4)) {
// Copy unaligned data to write-buffer before USBD_Write
memcpy(ep_state[EP0IN].data_buf, buffer, size);
ret = USBD_Write(0, ep_state[EP0IN].data_buf, size, cb);
} else {
ret = USBD_Write(0, buffer, size, cb);
}
if (ret != USB_STATUS_OK) {
TRACE("FAILED - ret %d", ret);
}
}
void USBHAL::EP0stall(void)
{
TRACE_FUNC_IN;
USBD_StallEp0();
}
static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize)
{
//TRACE_FUNC_IN_P("endpoint 0x%x, size %ld, cb %d", (unsigned)ep, maxSize, useCallback);
if (ep >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return EP_INVALID;
}
ep_state[ep].status = READ_PENDING;
int ret = USBD_Read(USB_EP_TO_ADDR(ep), ep_state[ep].data_buf, maxSize,
ep_state[ep].intern_cb);
if (ret == USB_STATUS_OK) {
return EP_PENDING;
} else {
TRACE("FAILED - ret %d", ret);
if (ret == USB_STATUS_EP_STALLED) {
return EP_STALLED;
} else {
return EP_INVALID;
}
}
}
EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
{
return internEndpointRead(endpoint, maximumSize);
}
EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead)
{
TRACE_FUNC_IN;
if (endpoint >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return EP_INVALID;
}
EFM_ASSERT(data);
EFM_ASSERT(bytesRead);
if (!data || !bytesRead) {
return EP_INVALID;
}
switch (ep_state[endpoint].status) {
case READ_PENDING:
return EP_PENDING;
case READ_COMPLETE:
memcpy(data, ep_state[endpoint].data_buf, ep_state[endpoint].byte_count);
*bytesRead = ep_state[endpoint].byte_count;
ep_state[endpoint].status = IDLE;
return EP_COMPLETED;
case FAILED_STALLED:
ep_state[endpoint].status = IDLE;
return EP_STALLED;
default:
ep_state[endpoint].status = IDLE;
return EP_INVALID;
}
}
EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
{
TRACE_FUNC_IN_P("endpoint 0x%x, data 0x%lx, size %lu", (unsigned )endpoint, (uint32_t)data, size);
EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
EFM_ASSERT(endpoint > EP0IN);
EFM_ASSERT(size <= ep_state[endpoint].max_packet);
EFM_ASSERT(data);
uint8_t ep = USB_EP_TO_INDEX(endpoint);
if (endpoint >= NUMBER_OF_ENDPOINTS || endpoint <= EP0IN) {
return EP_INVALID;
}
if (size > ep_state[endpoint].max_packet) {
return EP_INVALID;
}
if (!data) {
return EP_INVALID;
}
memcpy(ep_state[ep].data_buf, data, size);
ep_state[ep].status = WRITE_PENDING;
int ret = USBD_Write(USB_EP_TO_ADDR(endpoint), ep_state[ep].data_buf, size, ep_state[ep].intern_cb);
if (ret == USB_STATUS_EP_STALLED) {
ep_state[ep].status = IDLE;
return EP_STALLED;
} else if (ret != USB_STATUS_OK) {
ep_state[ep].status = IDLE;
return EP_INVALID;
}
return EP_PENDING;
}
EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
{
if (endpoint >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return EP_INVALID;
}
switch (ep_state[endpoint].status) {
case WRITE_PENDING:
return EP_PENDING;
case WRITE_COMPLETE:
ep_state[endpoint].status = IDLE;
return EP_COMPLETED;
case FAILED_STALLED:
ep_state[endpoint].status = IDLE;
return EP_STALLED;
default:
ep_state[endpoint].status = IDLE;
return EP_INVALID;
}
}
void USBHAL::stallEndpoint(uint8_t endpoint)
{
TRACE_FUNC_IN;
EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
USBD_StallEp(USB_EP_TO_ADDR(endpoint));
}
void USBHAL::unstallEndpoint(uint8_t endpoint)
{
TRACE_FUNC_IN;
EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
USBD_UnStallEp(USB_EP_TO_ADDR(endpoint));
}
bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options)
{
TRACE_FUNC_IN_P("endpoint %d, packetsize %ld, options 0x%lx", endpoint,
maxPacket, options);
int mult = 1; // RX/TX buffer size multiplier
int type = USB_EPTYPE_INTR;
if (endpoint >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return false;
}
if (endpoint == EP0IN || endpoint == EP0OUT) {
EFM_ASSERT(false);
return false;
}
ep_state[endpoint].max_packet = 0;
if (endpoint == EPISO_OUT || endpoint == EPISO_IN) {
if (maxPacket > MAX_PACKET_SIZE_EPISO) {
EFM_ASSERT(false);
return false;
}
} else if ((maxPacket > MAX_PACKET_SIZE_EPBULK) || (maxPacket > MAX_PACKET_SIZE_EPINT)) {
EFM_ASSERT(false);
return false;
}
// USBDevice performs a read right after creating the endpoints,
// before calling configureDevice. The read will fail since
// at that point the device state is still ADDRESSED. Workaround
// is to force configured state here.
//
// This relies on USBDevice to not call realiseEndpoint unless
// it is transitioning to the CONFIGURED state.
USBD_SetUsbState(USBD_STATE_CONFIGURED);
// Why doesn't this function have a type param? This is silly...
switch (endpoint) {
case EPBULK_OUT:
case EPBULK_IN:
type = USB_EPTYPE_BULK;
mult = 2;
break;
case EPINT_OUT:
case EPINT_IN:
type = USB_EPTYPE_INTR;
mult = 1;
break;
case EPISO_OUT:
case EPISO_IN:
type = USB_EPTYPE_ISOC;
mult = 2; // ?
break;
}
// Some options force the endpoint to a specific type
if( options & ISOCHRONOUS ) {
type = USB_EPTYPE_ISOC;
mult = 2; // ?
} else if ( options & RATE_FEEDBACK_MODE ) {
// No support for whatever rate feedback is, but for interrupt only
type = USB_EPTYPE_INTR;
mult = 1;
}
#ifdef USB_USE_DYNAMIC_MEMORY
if (ep_state[endpoint].data_buf) {
free(ep_state[endpoint].data_buf);
}
ep_state[endpoint].data_buf = (uint8_t *)malloc(maxPacket);
if (!ep_state[endpoint].data_buf) {
EFM_ASSERT(false);
return false;
}
#endif
int ret = USBD_AddEndpoint(USB_EP_TO_ADDR(endpoint), type, maxPacket, mult);
if (ret == USB_STATUS_OK) {
ep_state[endpoint].status = IDLE;
ep_state[endpoint].max_packet = maxPacket;
return true;
} else {
return false;
}
}
bool USBHAL::getEndpointStallState(unsigned char endpoint)
{
TRACE_FUNC_IN;
if (endpoint >= NUMBER_OF_ENDPOINTS) {
EFM_ASSERT(false);
return false;
}
return USBD_EpIsStalled(USB_EP_TO_ADDR(endpoint));
}
static void run_cmd(USBISRCommand cmd, uint32_t param)
{
if (usb_isrcmd != CMD_HANDLED || cmd >= CMD_ENUM_END_MARKER) {
EFM_ASSERT(false);
abort();
}
usb_isrcmd = cmd;
usb_isrcmd_param = param;
isrptr();
}
void USBHAL::_usbisr(void)
{
EFM_ASSERT(instance);
instance->usbisr();
}
void USBHAL::usbisr(void)
{
//TRACE_FUNC_IN;
// This "ISR" is used just to route callbacks from SiL USB driver
// callback context (which can not call protected/private USBHAL
// methods), to the actual USBHAL.
EFM_ASSERT(usb_isrcmd != CMD_HANDLED);
switch (usb_isrcmd) {
case CMD_EP0SETUP:
this->EP0setupCallback();
break;
case CMD_EP0IN:
this->EP0in();
break;
case CMD_EP0OUT:
this->EP0out();
break;
case CMD_BUSRESET:
this->busReset();
break;
case CMD_EP_XFER_COMPLETED:
if (epCallback[usb_isrcmd_param] && instance) {
(instance->*(epCallback[usb_isrcmd_param]))();
}
break;
case CMD_SOF:
this->SOF(usb_isrcmd_param);
break;
case CMD_SUSPEND_STATE_CHANGED:
this->suspendStateChanged(usb_isrcmd_param);
break;
default:
EFM_ASSERT(false);
break;
}
usb_isrcmd = CMD_HANDLED;
}
#endif
// End of file

View File

@ -26,6 +26,9 @@
#define PWM_TIMER_CLOCK cmuClock_TIMER2
#define PWM_ROUTE TIMER_ROUTE_LOCATION_LOC1
/* USB */
#define USB_TIMER USB_TIMER1
/* Clocks */
/* Clock definitions */

View File

@ -26,6 +26,9 @@
#define PWM_TIMER_CLOCK cmuClock_TIMER0
#define PWM_ROUTE TIMER_ROUTE_LOCATION_LOC0
/* USB */
#define USB_TIMER USB_TIMER2
/* Clocks */
/* Clock definitions */

View File

@ -26,6 +26,9 @@
#define PWM_TIMER_CLOCK cmuClock_TIMER2
#define PWM_ROUTE TIMER_ROUTE_LOCATION_LOC1
/* USB */
#define USB_TIMER USB_TIMER1
/* Clocks */
/* Clock definitions */

View File

@ -26,6 +26,9 @@
#define PWM_TIMER_CLOCK cmuClock_TIMER2
#define PWM_ROUTE TIMER_ROUTE_LOCATION_LOC1
/* USB */
#define USB_TIMER USB_TIMER1
/* Clocks */
/* Clock definitions */

View File

@ -27,57 +27,63 @@ import sys
# "libs" can contain "dsp", "rtos", "eth", "usb_host", "usb", "ublox", "fat"
build_list = (
{ "target": "LPC1768", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "eth", "usb_host", "usb", "ublox", "fat"] },
{ "target": "LPC2368", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "LPC2460", "toolchains": "GCC_ARM", "libs": ["rtos", "usb_host", "usb", "fat"] },
{ "target": "LPC11U24", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "OC_MBUINO", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "LPC1768", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "eth", "usb_host", "usb", "ublox", "fat"] },
{ "target": "LPC2368", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "LPC2460", "toolchains": "GCC_ARM", "libs": ["rtos", "usb_host", "usb", "fat"] },
{ "target": "LPC11U24", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "OC_MBUINO", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "LPC11U24_301", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "LPC11U24_301", "toolchains": "GCC_ARM", "libs": ["fat"] },
{ "target": "NUCLEO_L053R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_L152RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F030R8", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "NUCLEO_F070RB", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "NUCLEO_F072RB", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F091RC", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F103RB", "toolchains": "GCC_ARM", "libs": ["rtos", "fat"] },
{ "target": "NUCLEO_F302R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F303RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F334R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F401RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F411RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_L053R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_L152RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F030R8", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "NUCLEO_F070RB", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "NUCLEO_F072RB", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F091RC", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F103RB", "toolchains": "GCC_ARM", "libs": ["rtos", "fat"] },
{ "target": "NUCLEO_F302R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F303RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F334R8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F401RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NUCLEO_F411RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "MTS_MDOT_F405RG", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos"] },
{ "target": "MTS_MDOT_F411RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos"] },
{ "target": "MTS_MDOT_F405RG", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos"] },
{ "target": "MTS_MDOT_F411RE", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos"] },
{ "target": "MTS_DRAGONFLY_F411RE", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "ARCH_MAX", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "ARCH_MAX", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F051R8", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "DISCO_F334C8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F401VC", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "DISCO_F407VG", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F429ZI", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F746NG", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "DISCO_F051R8", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "DISCO_F334C8", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F401VC", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "DISCO_F407VG", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F429ZI", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "DISCO_F746NG", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "LPC1114", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U35_401", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "UBLOX_C027", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U35_501", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "LPC11U68", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U37H_401", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "LPC1114", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U35_401", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "UBLOX_C027", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U35_501", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "LPC11U68", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC11U37H_401", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "KL05Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "KL25Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "KL43Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "KL46Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "K20D50M", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "TEENSY3_1", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "K64F", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "LPC4088", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "ARCH_PRO", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC1549", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NRF51822", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "KL05Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "KL25Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "KL43Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "KL46Z", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "K20D50M", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "TEENSY3_1", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "K64F", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "LPC4088", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "usb", "fat"] },
{ "target": "ARCH_PRO", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "LPC1549", "toolchains": "GCC_ARM", "libs": ["dsp", "rtos", "fat"] },
{ "target": "NRF51822", "toolchains": "GCC_ARM", "libs": ["dsp", "fat"] },
{ "target": "EFM32ZG_STK3200", "toolchains": "GCC_ARM", "libs": ["dsp"] },
{ "target": "EFM32HG_STK3400", "toolchains": "GCC_ARM", "libs": ["dsp", "usb"] },
{ "target": "EFM32LG_STK3600", "toolchains": "GCC_ARM", "libs": ["dsp", "usb"] },
{ "target": "EFM32GG_STK3700", "toolchains": "GCC_ARM", "libs": ["dsp", "usb"] },
{ "target": "EFM32WG_STK3800", "toolchains": "GCC_ARM", "libs": ["dsp", "usb"] },
)
################################################################################