mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #10689 from AGlass0fMilk/nrf52840-usbphy-implementation
nRF52840 USB Device Implementationpull/10864/head
commit
07f1e068a9
|
@ -2365,7 +2365,7 @@
|
|||
// <e> NRFX_POWER_ENABLED - nrfx_power - POWER peripheral driver
|
||||
//==========================================================
|
||||
#ifndef NRFX_POWER_ENABLED
|
||||
#define NRFX_POWER_ENABLED 0
|
||||
#define NRFX_POWER_ENABLED 1
|
||||
#endif
|
||||
// <o> NRFX_POWER_CONFIG_IRQ_PRIORITY - Interrupt priority
|
||||
|
||||
|
@ -4542,7 +4542,7 @@
|
|||
// <e> POWER_ENABLED - nrf_drv_power - POWER peripheral driver - legacy layer
|
||||
//==========================================================
|
||||
#ifndef POWER_ENABLED
|
||||
#define POWER_ENABLED 0
|
||||
#define POWER_ENABLED 1
|
||||
#endif
|
||||
// <o> POWER_CONFIG_IRQ_PRIORITY - Interrupt priority
|
||||
|
||||
|
@ -5624,7 +5624,7 @@
|
|||
// <e> USBD_ENABLED - nrf_drv_usbd - USB driver
|
||||
//==========================================================
|
||||
#ifndef USBD_ENABLED
|
||||
#define USBD_ENABLED 0
|
||||
#define USBD_ENABLED 1
|
||||
#endif
|
||||
// <o> USBD_CONFIG_IRQ_PRIORITY - Interrupt priority
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,946 @@
|
|||
/**
|
||||
* Copyright (c) 2016 - 2017, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NRF_DRV_USBD_H__
|
||||
#define NRF_DRV_USBD_H__
|
||||
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_usbd.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "app_util.h"
|
||||
#include "nrf_drv_usbd_errata.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup nrf_drv_usbd USB Device HAL and driver
|
||||
* @ingroup nrf_drivers
|
||||
* @brief @tagAPI52840 USB Device APIs.
|
||||
* @details The USB Device HAL provides basic APIs for accessing
|
||||
* the registers of the USBD.
|
||||
* The USB Device driver provides APIs on a higher level.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Possible schemes of DMA scheduling
|
||||
*
|
||||
* Definition of available configuration constants used by DMA scheduler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Highly prioritized access
|
||||
*
|
||||
* Endpoint with lower number has always higher priority and its data would
|
||||
* be transfered first.
|
||||
* OUT endpoints ale processed before IN endpoints
|
||||
*/
|
||||
#define NRF_DRV_USBD_DMASCHEDULER_PRIORITIZED 0
|
||||
|
||||
/**
|
||||
* @brief Round robin scheme
|
||||
*
|
||||
* All endpoints are processed in round-robin scheme.
|
||||
* It means that when one endpoint is processed next in order would be
|
||||
* the nearest with lower number.
|
||||
* When no endpoints with lower number requires processing - then
|
||||
* all endpoints from 0 are tested.
|
||||
*/
|
||||
#define NRF_DRV_USBD_DMASCHEDULER_ROUNDROBIN 1
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Number of bytes in the endpoint
|
||||
*
|
||||
* Constant that informs about endpoint size
|
||||
*/
|
||||
#define NRF_DRV_USBD_EPSIZE 64
|
||||
|
||||
/**
|
||||
* @brief Number of bytes for isochronous endpoints
|
||||
*
|
||||
* Number of bytes for isochronous endpoints in total.
|
||||
* This number would be shared between IN and OUT endpoint.
|
||||
* It may be also assigned totaly to one endpoint.
|
||||
* @sa nrf_usbd_isosplit_set
|
||||
* @sa nrf_usbd_isosplit_get
|
||||
*/
|
||||
#define NRF_DRV_USBD_ISOSIZE 1024
|
||||
|
||||
/**
|
||||
* @brief The size of internal feeder buffer.
|
||||
*
|
||||
* @sa nrf_drv_usbd_feeder_buffer_get
|
||||
*/
|
||||
#define NRF_DRV_USBD_FEEDER_BUFFER_SIZE NRF_DRV_USBD_EPSIZE
|
||||
|
||||
/**
|
||||
* @name Macros for creating endpoint identifiers
|
||||
*
|
||||
* Auxiliary macros to be used to create Endpoint identifier that is compatible
|
||||
* with USB specification.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Create identifier for IN endpoint
|
||||
*
|
||||
* Simple macro to create IN endpoint identifier for given endpoint number.
|
||||
*
|
||||
* @param[in] n Endpoint number.
|
||||
*
|
||||
* @return Endpoint identifier that connects endpoint number and endpoint direction.
|
||||
*/
|
||||
#define NRF_DRV_USBD_EPIN(n) ((nrf_drv_usbd_ep_t)NRF_USBD_EPIN(n))
|
||||
/**
|
||||
* @brief Create identifier for OUT endpoint
|
||||
*
|
||||
* Simple macro to create OUT endpoint identifier for given endpoint number.
|
||||
*
|
||||
* @param[in] n Endpoint number.
|
||||
*
|
||||
* @return Endpoint identifier that connects endpoint number and endpoint direction.
|
||||
*/
|
||||
#define NRF_DRV_USBD_EPOUT(n) ((nrf_drv_usbd_ep_t)NRF_USBD_EPOUT(n))
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Endpoint identifier
|
||||
*
|
||||
* Endpoint identifier used in the driver.
|
||||
* This endpoint number is consistent with USB 2.0 specification.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DRV_USBD_EPOUT0 = NRF_USBD_EPOUT(0), /**< Endpoint OUT 0 */
|
||||
NRF_DRV_USBD_EPOUT1 = NRF_USBD_EPOUT(1), /**< Endpoint OUT 1 */
|
||||
NRF_DRV_USBD_EPOUT2 = NRF_USBD_EPOUT(2), /**< Endpoint OUT 2 */
|
||||
NRF_DRV_USBD_EPOUT3 = NRF_USBD_EPOUT(3), /**< Endpoint OUT 3 */
|
||||
NRF_DRV_USBD_EPOUT4 = NRF_USBD_EPOUT(4), /**< Endpoint OUT 4 */
|
||||
NRF_DRV_USBD_EPOUT5 = NRF_USBD_EPOUT(5), /**< Endpoint OUT 5 */
|
||||
NRF_DRV_USBD_EPOUT6 = NRF_USBD_EPOUT(6), /**< Endpoint OUT 6 */
|
||||
NRF_DRV_USBD_EPOUT7 = NRF_USBD_EPOUT(7), /**< Endpoint OUT 7 */
|
||||
NRF_DRV_USBD_EPOUT8 = NRF_USBD_EPOUT(8), /**< Endpoint OUT 8 */
|
||||
|
||||
NRF_DRV_USBD_EPIN0 = NRF_USBD_EPIN(0), /**< Endpoint IN 0 */
|
||||
NRF_DRV_USBD_EPIN1 = NRF_USBD_EPIN(1), /**< Endpoint IN 1 */
|
||||
NRF_DRV_USBD_EPIN2 = NRF_USBD_EPIN(2), /**< Endpoint IN 2 */
|
||||
NRF_DRV_USBD_EPIN3 = NRF_USBD_EPIN(3), /**< Endpoint IN 3 */
|
||||
NRF_DRV_USBD_EPIN4 = NRF_USBD_EPIN(4), /**< Endpoint IN 4 */
|
||||
NRF_DRV_USBD_EPIN5 = NRF_USBD_EPIN(5), /**< Endpoint IN 5 */
|
||||
NRF_DRV_USBD_EPIN6 = NRF_USBD_EPIN(6), /**< Endpoint IN 6 */
|
||||
NRF_DRV_USBD_EPIN7 = NRF_USBD_EPIN(7), /**< Endpoint IN 7 */
|
||||
NRF_DRV_USBD_EPIN8 = NRF_USBD_EPIN(8), /**< Endpoint IN 8 */
|
||||
}nrf_drv_usbd_ep_t;
|
||||
|
||||
/**
|
||||
* @brief Events generated by the library
|
||||
*
|
||||
* Enumeration of possible events that may be generated by the library.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DRV_USBD_EVT_SOF, /**< Start Of Frame event on USB bus detected */
|
||||
NRF_DRV_USBD_EVT_RESET, /**< Reset condition on USB bus detected */
|
||||
NRF_DRV_USBD_EVT_SUSPEND, /**< This device should go to suspend mode now */
|
||||
NRF_DRV_USBD_EVT_RESUME, /**< This device should resume from suspend now */
|
||||
NRF_DRV_USBD_EVT_WUREQ, /**< Wakeup request - the USBD peripheral is ready to generate WAKEUP signal after exiting low power mode. */
|
||||
NRF_DRV_USBD_EVT_SETUP, /**< Setup frame received and decoded */
|
||||
NRF_DRV_USBD_EVT_EPTRANSFER, /**<
|
||||
* For Rx (OUT: Host->Device):
|
||||
* 1. The packet has been received but there is no buffer prepared for transfer already.
|
||||
* 2. Whole transfer has been finished
|
||||
*
|
||||
* For Tx (IN: Device->Host):
|
||||
* The last packet from requested transfer has been transfered over USB bus and acknowledged
|
||||
*/
|
||||
NRF_DRV_USBD_EVT_CNT /**< Number of defined events */
|
||||
}nrf_drv_usbd_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief Possible endpoint error codes
|
||||
*
|
||||
* Error codes that may be returned with @ref NRF_DRV_USBD_EVT_EPTRANSFER
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_USBD_EP_OK, /**< No error */
|
||||
NRF_USBD_EP_WAITING, /**< Data received, no buffer prepared already - waiting for configured transfer */
|
||||
NRF_USBD_EP_OVERLOAD, /**< Received number of bytes cannot fit given buffer
|
||||
* This error would also be returned when next_transfer function has been defined
|
||||
* but currently received data cannot fit completely in current buffer.
|
||||
* No data split from single endpoint transmission is supported.
|
||||
*
|
||||
* When this error is reported - data is left inside endpoint buffer.
|
||||
* Clear endpoint or prepare new buffer and read it.
|
||||
*/
|
||||
NRF_USBD_EP_ABORTED, /**< EP0 transfer can be aborted when new setup comes.
|
||||
* Any other transfer can be aborted by USB reset or library stopping.
|
||||
*/
|
||||
}nrf_drv_usbd_ep_status_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Event structure
|
||||
*
|
||||
* Structure passed to event handler
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_usbd_event_type_t type;
|
||||
union
|
||||
{
|
||||
struct{
|
||||
uint16_t framecnt; //!< Current value of frame counter
|
||||
}sof; //!< Data aviable for @ref NRF_DRV_USBD_EVT_SOF
|
||||
struct{
|
||||
nrf_drv_usbd_ep_t ep; //!< Endpoint number
|
||||
}isocrc;
|
||||
struct{
|
||||
nrf_drv_usbd_ep_t ep; //!< Endpoint number
|
||||
nrf_drv_usbd_ep_status_t status; //!< Status for the endpoint
|
||||
}eptransfer;
|
||||
}data;
|
||||
}nrf_drv_usbd_evt_t;
|
||||
|
||||
/**
|
||||
* @brief USBD event callback function type.
|
||||
*
|
||||
* @param[in] p_event Event information structure.
|
||||
*/
|
||||
typedef void (*nrf_drv_usbd_event_handler_t)(nrf_drv_usbd_evt_t const * const p_event);
|
||||
|
||||
/**
|
||||
* @brief Universal data pointer.
|
||||
*
|
||||
* Universal data pointer that can be used for any type of transfer.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
void const * tx; //!< Constant TX buffer pointer.
|
||||
void * rx; //!< Writable RX buffer pointer.
|
||||
uint32_t ptr; //!< Numeric value used internally by the library.
|
||||
}nrf_drv_usbd_data_ptr_t;
|
||||
|
||||
/**
|
||||
* @brief Structure to be filled with information about the next transfer.
|
||||
*
|
||||
* This is used mainly for transfer feeders and consumers.
|
||||
* It describes a single endpoint transfer and therefore the size of the buffer
|
||||
* can never be higher than the endpoint size.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the library.
|
||||
size_t size; //!< Size of the requested transfer.
|
||||
}nrf_drv_usbd_ep_transfer_t;
|
||||
|
||||
/**
|
||||
* @brief Flags for the current transfer.
|
||||
*
|
||||
* Flags configured for the transfer that can be merged using the bitwise 'or' operator (|).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DRV_USBD_TRANSFER_ZLP_FLAG = 1U << 0, //!< Add a zero-length packet.
|
||||
}nrf_drv_usbd_transfer_flags_t;
|
||||
|
||||
/**
|
||||
* @brief Total transfer configuration.
|
||||
*
|
||||
* This structure is used to configure total transfer information.
|
||||
* It is used by internal built-in feeders and consumers.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the library.
|
||||
size_t size; //!< Total size of the requested transfer.
|
||||
uint32_t flags; //!< Transfer flags.
|
||||
/**< Use the @ref nrf_drv_usbd_transfer_flags_t values. */
|
||||
}nrf_drv_usbd_transfer_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Auxiliary macro for declaring IN transfer description with flags.
|
||||
*
|
||||
* The base macro for creating transfers with any configuration option.
|
||||
*
|
||||
* @param name Instance name.
|
||||
* @param tx_buff Buffer to transfer.
|
||||
* @param tx_size Transfer size.
|
||||
* @param tx_flags Flags for the transfer (see @ref nrf_drv_usbd_transfer_flags_t).
|
||||
*
|
||||
* @return Configured variable with total transfer description.
|
||||
*/
|
||||
#define NRF_DRV_USBD_TRANSFER_IN_FLAGS(name, tx_buff, tx_size, tx_flags) \
|
||||
const nrf_drv_usbd_transfer_t name = { \
|
||||
.p_data = { .tx = (tx_buff) }, \
|
||||
.size = (tx_size), \
|
||||
.flags = (tx_flags) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper macro for declaring IN transfer description
|
||||
*
|
||||
* Normal transfer mode, no ZLP would be automatically generated.
|
||||
*
|
||||
* @sa nrf_drv_usbd_transfer_t
|
||||
* @sa NRF_DRV_USBD_TRANSFER_IN_ZLP
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param tx_buff Buffer to transfer
|
||||
* @param tx_size Transfer size
|
||||
*
|
||||
* @return Configured variable with total transfer description
|
||||
*
|
||||
*/
|
||||
#define NRF_DRV_USBD_TRANSFER_IN(name, tx_buff, tx_size) \
|
||||
NRF_DRV_USBD_TRANSFER_IN_FLAGS(name, tx_buff, tx_size, 0)
|
||||
|
||||
/**
|
||||
* @brief Helper macro for declaring IN transfer description
|
||||
*
|
||||
* ZLP mode - Zero Length Packet would be generated on the end of the transfer
|
||||
* (always!).
|
||||
*
|
||||
* @sa nrf_drv_usbd_transfer_t
|
||||
* @sa NRF_DRV_USBD_TRANSFER_IN
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param tx_buff Buffer to transfer
|
||||
* @param tx_size Transfer size
|
||||
*
|
||||
* @return Configured variable with total transfer description
|
||||
*/
|
||||
#define NRF_DRV_USBD_TRANSFER_IN_ZLP(name, tx_buff, tx_size) \
|
||||
NRF_DRV_USBD_TRANSFER_IN_FLAGS( \
|
||||
name, \
|
||||
tx_buff, \
|
||||
tx_size, \
|
||||
NRF_DRV_USBD_TRANSFER_ZLP_FLAG)
|
||||
|
||||
/**
|
||||
* @brief Helper macro for declaring OUT transfer item (@ref nrf_drv_usbd_transfer_t)
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param rx_buff Buffer to transfer
|
||||
* @param rx_size Transfer size
|
||||
* */
|
||||
#define NRF_DRV_USBD_TRANSFER_OUT(name, rx_buff, rx_size) \
|
||||
const nrf_drv_usbd_transfer_t name = { \
|
||||
.p_data = { .rx = (rx_buff) }, \
|
||||
.size = (rx_size), \
|
||||
.flags = 0 \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD transfer feeder.
|
||||
*
|
||||
* Pointer for a transfer feeder.
|
||||
* Transfer feeder is a feedback function used to prepare a single
|
||||
* TX (Device->Host) endpoint transfer.
|
||||
*
|
||||
* The transfers provided by the feeder must be simple:
|
||||
* - The size of the transfer provided by this function is limited to a single endpoint buffer.
|
||||
* Bigger transfers are not handled automatically in this case.
|
||||
* - Flash transfers are not automatically supported- you must copy them to the RAM buffer before.
|
||||
*
|
||||
* @note
|
||||
* This function may use @ref nrf_drv_usbd_feeder_buffer_get to gain a temporary buffer
|
||||
* that can be used to prepare transfer.
|
||||
*
|
||||
* @param[out] p_next Structure with the data for the next transfer to be filled.
|
||||
* Required only if the function returns true.
|
||||
* @param[in,out] p_context Context variable configured with the transfer.
|
||||
* @param[in] ep_size The endpoint size.
|
||||
*
|
||||
* @retval false The current transfer is the last one - you do not need to call
|
||||
* the function again.
|
||||
* @retval true There is more data to be prepared and when the current transfer
|
||||
* finishes, the feeder function is expected to be called again.
|
||||
*/
|
||||
typedef bool (*nrf_drv_usbd_feeder_t)(
|
||||
nrf_drv_usbd_ep_transfer_t * p_next,
|
||||
void * p_context,
|
||||
size_t ep_size);
|
||||
|
||||
/**
|
||||
* @brief USBD transfer consumer.
|
||||
*
|
||||
* Pointer for a transfer consumer.
|
||||
* Transfer consumer is a feedback function used to prepare a single
|
||||
* RX (Host->Device) endpoint transfer.
|
||||
*
|
||||
* The transfer must provide a buffer big enough to fit the whole data from the endpoint.
|
||||
* Otherwise, the NRF_USBD_EP_OVERLOAD event is generated.
|
||||
*
|
||||
* @param[out] p_next Structure with the data for the next transfer to be filled.
|
||||
* Required only if the function returns true.
|
||||
* @param[in,out] p_context Context variable configured with the transfer.
|
||||
* @param[in] ep_size The endpoint size.
|
||||
* @param[in] data_size Number of received bytes in the endpoint buffer.
|
||||
*
|
||||
* @retval false Current transfer is the last one - you do not need to call
|
||||
* the function again.
|
||||
* @retval true There is more data to be prepared and when current transfer
|
||||
* finishes, the feeder function is expected to be called again.
|
||||
*/
|
||||
typedef bool (*nrf_drv_usbd_consumer_t)(
|
||||
nrf_drv_usbd_ep_transfer_t * p_next,
|
||||
void * p_context,
|
||||
size_t ep_size,
|
||||
size_t data_size);
|
||||
|
||||
/**
|
||||
* @brief Universal transfer handler.
|
||||
*
|
||||
* Union with feeder and consumer function pointer.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
nrf_drv_usbd_feeder_t feeder; //!< Feeder function pointer.
|
||||
nrf_drv_usbd_consumer_t consumer; //!< Consumer function pointer.
|
||||
}nrf_drv_usbd_handler_t;
|
||||
|
||||
/**
|
||||
* @brief USBD transfer descriptor.
|
||||
*
|
||||
* Universal structure that may hold the setup for callback configuration for
|
||||
* IN or OUT type of the transfer.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_usbd_handler_t handler; //!< Handler for the current transfer, function pointer.
|
||||
void * p_context; //!< Context for the transfer handler.
|
||||
}nrf_drv_usbd_handler_desc_t;
|
||||
|
||||
/**
|
||||
* @brief Setup packet structure
|
||||
*
|
||||
* Structure that contains interpreted SETUP packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bmRequestType; //!< byte 0
|
||||
uint8_t bmRequest; //!< byte 1
|
||||
uint16_t wValue; //!< byte 2
|
||||
uint16_t wIndex; //!< byte 4, 5
|
||||
uint16_t wLength; //!< byte 6, 7
|
||||
}nrf_drv_usbd_setup_t;
|
||||
|
||||
/**
|
||||
* @brief Library initialization
|
||||
*
|
||||
* @param[in] event_handler Event handler provided by the user.
|
||||
*/
|
||||
ret_code_t nrf_drv_usbd_init(nrf_drv_usbd_event_handler_t const event_handler);
|
||||
|
||||
/**
|
||||
* @brief Library deinitialization
|
||||
*/
|
||||
ret_code_t nrf_drv_usbd_uninit(void);
|
||||
|
||||
/**
|
||||
* @brief Enable the USBD port
|
||||
*
|
||||
* After calling this function USBD peripheral would be enabled.
|
||||
* The USB LDO would be enabled.
|
||||
* Enabled USBD peripheral would request HFCLK.
|
||||
* This function does not enable external oscillator, so if it is not enabled by other part of the
|
||||
* program after enabling USBD driver HFINT would be used for the USBD peripheral.
|
||||
* It is perfectly fine until USBD is started. See @ref nrf_drv_usbd_start.
|
||||
*
|
||||
* In normal situation this function should be called in reaction to USBDETECTED
|
||||
* event from POWER peripheral.
|
||||
*
|
||||
* Interrupts and USB pins pull-up would stay disabled until @ref nrf_drv_usbd_start
|
||||
* function is called.
|
||||
*/
|
||||
void nrf_drv_usbd_enable(void);
|
||||
|
||||
/**
|
||||
* @brief Disable the USBD port
|
||||
*
|
||||
* After calling this function USBD peripheral would be disabled.
|
||||
* No events would be detected or processed by the library.
|
||||
* Clock for the peripheral would be disconnected.
|
||||
*/
|
||||
void nrf_drv_usbd_disable(void);
|
||||
|
||||
/**
|
||||
* @brief Start USB functionality
|
||||
*
|
||||
* After calling this function USBD peripheral should be fully functional
|
||||
* and all new incoming events / interrupts would be processed by the library.
|
||||
*
|
||||
* Also only after calling this function host sees new connected device.
|
||||
*
|
||||
* Call this function when USBD power LDO regulator is ready - on USBPWRRDY event
|
||||
* from POWER peripheral.
|
||||
*
|
||||
* Before USBD interrupts are enabled, external HFXO is requested.
|
||||
*
|
||||
* @param enable_sof The flag that is used to enable SOF processing.
|
||||
* If it is false, SOF interrupt is left disabled and will not be generated.
|
||||
* This improves power saving if SOF is not required.
|
||||
*
|
||||
* @note If the isochronous endpoints are going to be used,
|
||||
* it is required to enable the SOF.
|
||||
* In other case any isochronous endpoint would stay busy
|
||||
* after first transmission.
|
||||
*/
|
||||
void nrf_drv_usbd_start(bool enable_sof);
|
||||
|
||||
/**
|
||||
* @brief Stop USB functionality
|
||||
*
|
||||
* This function disables USBD pull-up and interrupts.
|
||||
*
|
||||
* The HFXO request is released in this function.
|
||||
*
|
||||
* @note
|
||||
* This function can also be used to logically disconnect USB from the HOST that
|
||||
* would force it to enumerate device after calling @ref nrf_drv_usbd_start.
|
||||
*/
|
||||
void nrf_drv_usbd_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Check if driver is initialized
|
||||
*
|
||||
* @retval false Driver is not initialized
|
||||
* @retval true Driver is initialized
|
||||
*/
|
||||
bool nrf_drv_usbd_is_initialized(void);
|
||||
|
||||
/**
|
||||
* @brief Check if driver is enabled
|
||||
*
|
||||
* @retval false Driver is disabled
|
||||
* @retval true Driver is enabled
|
||||
*/
|
||||
bool nrf_drv_usbd_is_enabled(void);
|
||||
|
||||
/**
|
||||
* @brief Check if driver is started
|
||||
*
|
||||
* @retval false Driver is not started
|
||||
* @retval true Driver is started (fully functional)
|
||||
* @note The USBD peripheral interrupt state is checked
|
||||
*/
|
||||
bool nrf_drv_usbd_is_started(void);
|
||||
|
||||
/**
|
||||
* @brief Suspend USBD operation
|
||||
*
|
||||
* The USBD peripheral is forced to go into the low power mode.
|
||||
* The function has to be called in the reaction to @ref NRF_DRV_USBD_EVT_SUSPEND event
|
||||
* when the firmware is ready.
|
||||
*
|
||||
* After successful call of this function most of the USBD registers would be unavailable.
|
||||
*
|
||||
* @note Check returned value for the feedback if suspending was successful.
|
||||
*
|
||||
* @retval true USBD peripheral successfully suspended
|
||||
* @retval false USBD peripheral was not suspended due to resume detection.
|
||||
*
|
||||
*/
|
||||
bool nrf_drv_usbd_suspend(void);
|
||||
|
||||
/**
|
||||
* @brief Start wake up procedure
|
||||
*
|
||||
* The USBD peripheral is forced to quit the low power mode.
|
||||
* After calling this function all the USBD registers would be available.
|
||||
*
|
||||
* The hardware starts measuring time when wake up is possible.
|
||||
* This may take 0-5 ms depending on how long the SUSPEND state was kept on the USB line.
|
||||
|
||||
* When NRF_DRV_USBD_EVT_WUREQ event is generated it means that Wake Up signaling has just been
|
||||
* started on the USB lines.
|
||||
*
|
||||
* @note Do not expect only @ref NRF_DRV_USBD_EVT_WUREQ event.
|
||||
* There always may appear @ref NRF_DRV_USBD_EVT_RESUME event.
|
||||
* @note NRF_DRV_USBD_EVT_WUREQ event means that Remote WakeUp signal
|
||||
* has just begun to be generated.
|
||||
* This may take up to 20 ms for the bus to become active.
|
||||
*
|
||||
* @retval true WakeUp procedure started.
|
||||
* @retval false No WakeUp procedure started - bus is already active.
|
||||
*/
|
||||
bool nrf_drv_usbd_wakeup_req(void);
|
||||
|
||||
/**
|
||||
* @brief Check if USBD is in SUSPEND mode
|
||||
*
|
||||
* @note This is the information about peripheral itself, not about the bus state.
|
||||
*
|
||||
* @retval true USBD peripheral is suspended
|
||||
* @retval false USBD peripheral is active
|
||||
*/
|
||||
bool nrf_drv_usbd_suspend_check(void);
|
||||
|
||||
/**
|
||||
* @brief Enable only interrupts that should be processed in SUSPEND mode
|
||||
*
|
||||
* Auxiliary function to help with SUSPEND mode integration.
|
||||
* It enables only the interrupts that can be properly processed without stable HFCLK.
|
||||
*
|
||||
* Normally all the interrupts are enabled.
|
||||
* Use this function to suspend interrupt processing that may require stable HFCLK until the
|
||||
* clock is enabled.
|
||||
*
|
||||
* @sa nrf_drv_usbd_active_irq_config
|
||||
*/
|
||||
void nrf_drv_usbd_suspend_irq_config(void);
|
||||
|
||||
/**
|
||||
* @brief Default active interrupt configuration
|
||||
*
|
||||
* Default interrupt configuration.
|
||||
* Use in a pair with @ref nrf_drv_usbd_active_irq_config.
|
||||
*
|
||||
* @sa nrf_drv_usbd_suspend_irq_config
|
||||
*/
|
||||
void nrf_drv_usbd_active_irq_config(void);
|
||||
|
||||
/**
|
||||
* @brief Check the bus state
|
||||
*
|
||||
* This function checks if the bus state is suspended
|
||||
*
|
||||
* @note The value returned by this function changes on SUSPEND and RESUME event processing.
|
||||
*
|
||||
* @retval true USBD bus is suspended
|
||||
* @retval false USBD bus is active
|
||||
*/
|
||||
bool nrf_drv_usbd_bus_suspend_check(void);
|
||||
|
||||
/**
|
||||
* @brief Configure packet size that should be supported by the endpoint
|
||||
*
|
||||
* The real endpoint buffer size is always the same.
|
||||
* This value sets max packet size that would be transmitted over the endpoint.
|
||||
* This is required by the library
|
||||
*
|
||||
* @param[in] ep Endpoint number
|
||||
* @param[in] size Required maximum packet size
|
||||
*
|
||||
* @note Endpoint size is always set to @ref NRF_DRV_USBD_EPSIZE or @ref NRF_DRV_USBD_ISOSIZE / 2
|
||||
* when @ref nrf_drv_usbd_ep_enable function is called.
|
||||
*/
|
||||
void nrf_drv_usbd_ep_max_packet_size_set(nrf_drv_usbd_ep_t ep, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief Get configured endpoint packet size
|
||||
*
|
||||
* Function to get configured endpoint size on the buffer.
|
||||
*
|
||||
* @param[in] ep Endpoint number
|
||||
*
|
||||
* @return Maximum pocket size configured on selected endpoint
|
||||
*/
|
||||
uint16_t nrf_drv_usbd_ep_max_packet_size_get(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Check if the selected endpoint is enabled.
|
||||
*
|
||||
* @param ep Endpoint number to check.
|
||||
*
|
||||
* @retval true Endpoint is enabled.
|
||||
* @retval false Endpoint is disabled.
|
||||
*/
|
||||
bool nrf_drv_usbd_ep_enable_check(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Enable selected endpoint
|
||||
*
|
||||
* This function enables endpoint itself and its interrupts.
|
||||
* @param ep Endpoint number to enable
|
||||
*
|
||||
* @note
|
||||
* Max packet size is set to endpoint default maximum value.
|
||||
*
|
||||
* @sa nrf_drv_usbd_ep_max_packet_size_set
|
||||
*/
|
||||
void nrf_drv_usbd_ep_enable(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Disable selected endpoint
|
||||
*
|
||||
* This function disables endpoint itself and its interrupts.
|
||||
* @param ep Endpoint number to disable
|
||||
*/
|
||||
void nrf_drv_usbd_ep_disable(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Disable all endpoints except for EP0
|
||||
*
|
||||
* Disable all endpoints that can be disabled in USB device while it is still active.
|
||||
*/
|
||||
void nrf_drv_usbd_ep_default_config(void);
|
||||
|
||||
/**
|
||||
* @brief Start sending data over endpoint
|
||||
*
|
||||
* Function initializes endpoint transmission.
|
||||
* This is asynchronous function - it finishes immediately after configuration
|
||||
* for transmission is prepared.
|
||||
*
|
||||
* @note Data buffer pointed by p_data have to be kept active till
|
||||
* @ref NRF_DRV_USBD_EVT_EPTRANSFER event is generated.
|
||||
*
|
||||
* @param[in] ep Endpoint number.
|
||||
* For IN endpoint sending would be initiated.
|
||||
* For OUT endpoint receiving would be initiated.
|
||||
* @param[in] p_transfer
|
||||
*
|
||||
* @retval NRF_ERROR_BUSY Selected endpoint is pending.
|
||||
* @retval NRF_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0.
|
||||
* @retval NRF_ERROR_FORBIDDEN Endpoint stalled.
|
||||
* @retval NRF_SUCCESS Transfer queued or started.
|
||||
*/
|
||||
ret_code_t nrf_drv_usbd_ep_transfer(
|
||||
nrf_drv_usbd_ep_t ep,
|
||||
nrf_drv_usbd_transfer_t const * const p_transfer);
|
||||
|
||||
/**
|
||||
* @brief Start sending data over the endpoint using the transfer handler function.
|
||||
*
|
||||
* This function initializes an endpoint transmission.
|
||||
* Just before data is transmitted, the transfer handler
|
||||
* is called and it prepares a data chunk.
|
||||
*
|
||||
* @param[in] ep Endpoint number.
|
||||
* For an IN endpoint, sending is initiated.
|
||||
* For an OUT endpoint, receiving is initiated.
|
||||
* @param p_handler Transfer handler - feeder for IN direction and consumer for
|
||||
* OUT direction.
|
||||
*
|
||||
* @retval NRF_ERROR_BUSY Selected endpoint is pending.
|
||||
* @retval NRF_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0.
|
||||
* @retval NRF_ERROR_FORBIDDEN Endpoint stalled.
|
||||
* @retval NRF_SUCCESS Transfer queued or started.
|
||||
*/
|
||||
ret_code_t nrf_drv_usbd_ep_handled_transfer(
|
||||
nrf_drv_usbd_ep_t ep,
|
||||
nrf_drv_usbd_handler_desc_t const * const p_handler);
|
||||
|
||||
/**
|
||||
* @brief Get the temporary buffer to be used by the feeder.
|
||||
*
|
||||
* This buffer is used for TX transfers and it can be reused automatically
|
||||
* when the transfer is finished.
|
||||
* Use it for transfer preparation.
|
||||
*
|
||||
* May be used inside the feeder configured in @ref nrf_drv_usbd_ep_handled_transfer.
|
||||
*
|
||||
* @return Pointer to the buffer that can be used temporarily.
|
||||
*
|
||||
* @sa NRF_DRV_USBD_FEEDER_BUFFER_SIZE
|
||||
*/
|
||||
void * nrf_drv_usbd_feeder_buffer_get(void);
|
||||
|
||||
/**
|
||||
* @brief Get the information about last finished or current transfer
|
||||
*
|
||||
* Function returns the status of the last buffer set for transfer on selected endpoint.
|
||||
* The status considers last buffer set by @ref nrf_drv_usbd_ep_transfer function or
|
||||
* by transfer callback function.
|
||||
*
|
||||
* @param[in] ep Endpoint number.
|
||||
* @param[out] p_size Information about the current/last transfer size.
|
||||
*
|
||||
* @retval NRF_SUCCESS Transfer already finished
|
||||
* @retval NRF_ERROR_BUSY Ongoing transfer
|
||||
* @retval NRF_ERROR_DATA_SIZE Too much of data received that cannot fit into buffer and cannot be splited into chunks.
|
||||
* This may happen if buffer size is not a multiplication of endpoint buffer size.
|
||||
*/
|
||||
ret_code_t nrf_drv_usbd_ep_status_get(nrf_drv_usbd_ep_t ep, size_t * p_size);
|
||||
|
||||
/**
|
||||
* @brief Get number of received bytes
|
||||
*
|
||||
* Get the number of received bytes.
|
||||
* The function behavior is undefined when called on IN endpoint.
|
||||
*
|
||||
* @param ep Endpoint number.
|
||||
*
|
||||
* @return Number of received bytes
|
||||
*/
|
||||
size_t nrf_drv_usbd_epout_size_get(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Check if endpoint buffer is ready or is under USB IP control
|
||||
*
|
||||
* Function to test if endpoint is busy.
|
||||
* Endpoint that is busy cannot be accessed by MCU.
|
||||
* It means that:
|
||||
* - OUT (TX) endpoint: Last uploaded data is still in endpoint and is waiting
|
||||
* to be received by the host.
|
||||
* - IN (RX) endpoint: Endpoint is ready to receive data from the host
|
||||
* and the endpoint does not have any data.
|
||||
* When endpoint is not busy:
|
||||
* - OUT (TX) endpoint: New data can be uploaded.
|
||||
* - IN (RX) endpoint: New data can be downloaded using @ref nrf_drv_usbd_ep_transfer
|
||||
* function.
|
||||
*/
|
||||
bool nrf_drv_usbd_ep_is_busy(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Stall endpoint
|
||||
*
|
||||
* Stall endpoit to send error information during next transfer request from
|
||||
* the host.
|
||||
*
|
||||
* @note To stall endpoint it is safer to use @ref nrf_drv_usbd_setup_stall
|
||||
* @note Stalled endpoint would not be cleared when DMA transfer finishes.
|
||||
*
|
||||
* @param ep Endpoint number to stall
|
||||
*
|
||||
*/
|
||||
void nrf_drv_usbd_ep_stall(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Clear stall flag on endpoint
|
||||
*
|
||||
* This function clears endpoint that is stalled.
|
||||
* @note
|
||||
* If it is OUT endpoint (receiving) it would be also prepared for reception.
|
||||
* It means that busy flag would be set.
|
||||
* @note
|
||||
* In endpoint (transmitting) would not be cleared - it gives possibility to
|
||||
* write new data before transmitting.
|
||||
*/
|
||||
void nrf_drv_usbd_ep_stall_clear(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Check if endpoint is stalled
|
||||
*
|
||||
* This function gets stall state of selected endpoint
|
||||
*
|
||||
* @param ep Endpoint number to check
|
||||
*/
|
||||
bool nrf_drv_usbd_ep_stall_check(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Clear current endpoint data toggle
|
||||
*
|
||||
* @param ep Endpoint number to clear
|
||||
*/
|
||||
void nrf_drv_usbd_ep_dtoggle_clear(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Get parsed setup data
|
||||
*
|
||||
* Function fills the parsed setup data structure.
|
||||
*
|
||||
* @param[out] p_setup Pointer to data structure that would be filled by
|
||||
* parsed data.
|
||||
*/
|
||||
void nrf_drv_usbd_setup_get(nrf_drv_usbd_setup_t * const p_setup);
|
||||
|
||||
/**
|
||||
* @brief Clear only for data transmission on setup endpoint
|
||||
*
|
||||
* This function may be called if any more data in control write transfer is expected.
|
||||
* Clears only OUT endpoint to be able to take another OUT data token.
|
||||
* It does not allow STATUS stage.
|
||||
* @sa nrf_drv_usbd_setup_clear
|
||||
*/
|
||||
void nrf_drv_usbd_setup_data_clear(void);
|
||||
|
||||
/**
|
||||
* @brief Clear setup endpoint
|
||||
*
|
||||
* This function acknowledges setup when SETUP command was received and processed.
|
||||
* It has to be called if no data respond for the SETUP command is sent.
|
||||
*
|
||||
* When there is any data transmission after SETUP command the data transmission
|
||||
* itself would clear the endpoint.
|
||||
*/
|
||||
void nrf_drv_usbd_setup_clear(void);
|
||||
|
||||
/**
|
||||
* @brief Stall setup endpoint
|
||||
*
|
||||
* Mark and error on setup endpoint.
|
||||
*/
|
||||
void nrf_drv_usbd_setup_stall(void);
|
||||
|
||||
/**
|
||||
* @note
|
||||
* This function locks interrupts that may be costly.
|
||||
* It is good idea to test if the endpoint is still busy before calling this function:
|
||||
* @code
|
||||
(m_ep_dma_waiting & (1U << ep2bit(ep)))
|
||||
* @endcode
|
||||
* This function would check it again, but it makes it inside critical section.
|
||||
*/
|
||||
void nrf_drv_usbd_ep_abort(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
/**
|
||||
* @brief Get the information about expected transfer SETUP data direction
|
||||
*
|
||||
* Function returns the information about last expected transfer direction.
|
||||
*
|
||||
* @retval NRF_DRV_USBD_EPOUT0 Expecting OUT (Host->Device) direction or no data
|
||||
* @retval NRF_DRV_USBD_EPIN0 Expecting IN (Device->Host) direction
|
||||
*/
|
||||
nrf_drv_usbd_ep_t nrf_drv_usbd_last_setup_dir_get(void);
|
||||
|
||||
/**
|
||||
* @brief Drop transfer on OUT endpoint
|
||||
*
|
||||
* @param[in] ep OUT endpoint ID
|
||||
*/
|
||||
void nrf_drv_usbd_transfer_out_drop(nrf_drv_usbd_ep_t ep);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif /* NRF_DRV_USBD_H__ */
|
|
@ -0,0 +1,132 @@
|
|||
/**
|
||||
* Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NRF_DRV_USBD_ERRATA_H__
|
||||
#define NRF_DRV_USBD_ERRATA_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
/**
|
||||
* @defgroup nrf_drv_usbd_errata Functions to check if selected PAN is present in current chip
|
||||
* @{
|
||||
* @ingroup nrf_drv_usbd
|
||||
*
|
||||
* Functions here are checking the presence of an error in current chip.
|
||||
* The checking is done at runtime based on the microcontroller version.
|
||||
* This file is subject to removal when nRF51840 prototype support is removed.
|
||||
*/
|
||||
|
||||
#ifndef NRF_DRV_USBD_ERRATA_ENABLE
|
||||
/**
|
||||
* @brief The constant that informs if errata should be enabled at all
|
||||
*
|
||||
* If this constant is set to 0, all the Errata bug fixes will be automatically disabled.
|
||||
*/
|
||||
#define NRF_DRV_USBD_ERRATA_ENABLE 1
|
||||
#endif
|
||||
|
||||
static inline bool nrf_drv_usbd_errata_type_52840(void)
|
||||
{
|
||||
return (*(uint32_t *)0x10000130UL == 0x8UL);
|
||||
}
|
||||
|
||||
static inline bool nrf_drv_usbd_errata_type_52840_eng_a(void)
|
||||
{
|
||||
return nrf_drv_usbd_errata_type_52840();
|
||||
}
|
||||
|
||||
static inline bool nrf_drv_usbd_errata_type_52840_eng_b(void)
|
||||
{
|
||||
return (nrf_drv_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL >= 0x1UL));
|
||||
}
|
||||
|
||||
static inline bool nrf_drv_usbd_errata_type_52840_eng_c(void)
|
||||
{
|
||||
return (nrf_drv_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL >= 0x2UL));
|
||||
}
|
||||
|
||||
static inline bool nrf_drv_usbd_errata_type_52840_eng_d(void)
|
||||
{
|
||||
return (nrf_drv_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL >= 0x3UL));
|
||||
}
|
||||
|
||||
/* Errata: USBD: EPDATA event is not always generated. */
|
||||
static inline bool nrf_drv_usbd_errata_104(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && (!nrf_drv_usbd_errata_type_52840_eng_b()));
|
||||
}
|
||||
|
||||
/* Errata: During setup read/write transfer USBD acknowledges setup stage without SETUP task. */
|
||||
static inline bool nrf_drv_usbd_errata_154(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && (!nrf_drv_usbd_errata_type_52840_eng_b()));
|
||||
}
|
||||
|
||||
/* Errata: ISO double buffering not functional. */
|
||||
static inline bool nrf_drv_usbd_errata_166(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && true);
|
||||
}
|
||||
|
||||
/* Errata: USBD might not reach its active state. */
|
||||
static inline bool nrf_drv_usbd_errata_171(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && true);
|
||||
}
|
||||
|
||||
/* Errata: USB cannot be enabled. */
|
||||
static inline bool nrf_drv_usbd_errata_187(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && nrf_drv_usbd_errata_type_52840_eng_b());
|
||||
}
|
||||
|
||||
/* Errata: USBD cannot receive tasks during DMA. */
|
||||
static inline bool nrf_drv_usbd_errata_199(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && true);
|
||||
}
|
||||
|
||||
/* Errata: SIZE.EPOUT not writable. */
|
||||
static inline bool nrf_drv_usbd_errata_200(void)
|
||||
{
|
||||
return (NRF_DRV_USBD_ERRATA_ENABLE && (!nrf_drv_usbd_errata_type_52840_eng_b()));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
#endif /* NRF_DRV_USBD_ERRATA_H__ */
|
|
@ -7236,7 +7236,8 @@
|
|||
"SYSTICK_CLK_OFF_DURING_SLEEP",
|
||||
"TRNG",
|
||||
"USTICKER",
|
||||
"QSPI"
|
||||
"QSPI",
|
||||
"USBDEVICE"
|
||||
],
|
||||
"extra_labels": [
|
||||
"NORDIC",
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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 USBPHYHW_H
|
||||
#define USBPHYHW_H
|
||||
|
||||
#include "USBPhy.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "platform/mbed_power_mgmt.h"
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include "nrf_drv_usbd.h"
|
||||
#include "nrfx_power.h"
|
||||
}
|
||||
|
||||
class USBPhyHw : public USBPhy {
|
||||
|
||||
public:
|
||||
USBPhyHw();
|
||||
virtual ~USBPhyHw();
|
||||
virtual void init(USBPhyEvents *events);
|
||||
virtual void deinit();
|
||||
virtual bool powered();
|
||||
virtual void connect();
|
||||
virtual void disconnect();
|
||||
virtual void configure();
|
||||
virtual void unconfigure();
|
||||
virtual void sof_enable();
|
||||
virtual void sof_disable();
|
||||
virtual void set_address(uint8_t address);
|
||||
virtual void remote_wakeup();
|
||||
virtual const usb_ep_table_t *endpoint_table();
|
||||
|
||||
virtual uint32_t ep0_set_max_packet(uint32_t max_packet);
|
||||
virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size);
|
||||
virtual void ep0_read(uint8_t *data, uint32_t size);
|
||||
virtual uint32_t ep0_read_result();
|
||||
virtual void ep0_write(uint8_t *buffer, uint32_t size);
|
||||
virtual void ep0_stall();
|
||||
|
||||
virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type);
|
||||
virtual void endpoint_remove(usb_ep_t endpoint);
|
||||
virtual void endpoint_stall(usb_ep_t endpoint);
|
||||
virtual void endpoint_unstall(usb_ep_t endpoint);
|
||||
|
||||
virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size);
|
||||
virtual uint32_t endpoint_read_result(usb_ep_t endpoint);
|
||||
virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size);
|
||||
virtual void endpoint_abort(usb_ep_t endpoint);
|
||||
|
||||
virtual void process();
|
||||
|
||||
static void _usb_event_handler(nrf_drv_usbd_evt_t const *const p_event);
|
||||
static void _usb_power_event_handler(nrfx_power_usb_evt_t event);
|
||||
static void _usb_virtual_status_event_handler(void);
|
||||
|
||||
private:
|
||||
USBPhyEvents *events;
|
||||
|
||||
bool sof_enabled;
|
||||
bool connect_enabled;
|
||||
|
||||
typedef enum usb_hw_event_type_t {
|
||||
USB_HW_EVENT_NONE = 0,
|
||||
USB_HW_EVENT_USBD = 1,
|
||||
USB_HW_EVENT_POWER = 2,
|
||||
USB_HW_EVENT_VIRTUAL_STATUS = 3
|
||||
} usb_hw_event_type_t;
|
||||
|
||||
// Event type to process
|
||||
usb_hw_event_type_t usb_event_type;
|
||||
|
||||
// USB event buffer
|
||||
nrf_drv_usbd_evt_t usb_event;
|
||||
|
||||
// USB power event buffer
|
||||
nrfx_power_usb_evt_t usb_power_event;
|
||||
|
||||
// Buffer to hold setup packet
|
||||
nrf_drv_usbd_setup_t setup_buf;
|
||||
|
||||
// Nordic transfer structures for each in/out endpoint
|
||||
nrf_drv_usbd_transfer_t transfer_buf[18];
|
||||
|
||||
// Returns the appropriate transfer structure buffer for the given endpoint
|
||||
nrf_drv_usbd_transfer_t *get_transfer_buffer(usb_ep_t endpoint);
|
||||
|
||||
// Returns the corresponding enumeration given an mbed endpoint number
|
||||
static nrf_drv_usbd_ep_t get_nordic_endpoint(usb_ep_t endpoint);
|
||||
|
||||
void _reset(void);
|
||||
|
||||
static void enable_usb_interrupts(void);
|
||||
static void disable_usb_interrupts(void);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,656 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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 "USBPhyHw.h"
|
||||
|
||||
#include "platform/mbed_critical.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
|
||||
#define MAX_PACKET_SIZE_SETUP NRF_DRV_USBD_EPSIZE
|
||||
#define MAX_PACKET_NON_ISO NRF_DRV_USBD_EPSIZE
|
||||
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
|
||||
#define ENDPOINT_NON_ISO (USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_ALLOW_INT)
|
||||
|
||||
#define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set)
|
||||
#define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear)
|
||||
|
||||
// If this bit is set in setup.bmRequestType, the setup transfer
|
||||
// is DEVICE->HOST (IN transfer)
|
||||
// if it is clear, the transfer is HOST->DEVICE (OUT transfer)
|
||||
#define SETUP_TRANSFER_DIR_MASK 0x80
|
||||
|
||||
// Debugging flag for tracking USB events
|
||||
#define USBD_DEBUG 0
|
||||
|
||||
// Nordic USBD driver IRQ handler
|
||||
extern "C" void USBD_IRQHandler(void);
|
||||
|
||||
// Internal USBD driver IRQ handler
|
||||
void USBD_HAL_IRQHandler(void);
|
||||
|
||||
static USBPhyHw *instance = 0;
|
||||
|
||||
static volatile bool virtual_status_xfer_event;
|
||||
|
||||
static void usbd_event_handler(nrf_drv_usbd_evt_t const *const p_event);
|
||||
static void power_usb_event_handler(nrfx_power_usb_evt_t event);
|
||||
|
||||
USBPhy *get_usb_phy()
|
||||
{
|
||||
static USBPhyHw usbphy;
|
||||
return &usbphy;
|
||||
}
|
||||
|
||||
USBPhyHw::USBPhyHw() :
|
||||
events(NULL), sof_enabled(false), connect_enabled(false),
|
||||
usb_event_type(USB_HW_EVENT_NONE),
|
||||
usb_power_event(NRFX_POWER_USB_EVT_REMOVED)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
USBPhyHw::~USBPhyHw()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void USBPhyHw::init(USBPhyEvents *events)
|
||||
{
|
||||
|
||||
// Disable the USBD interrupts
|
||||
// Interrupts will be reenabled by the Nordic driver
|
||||
NRFX_IRQ_DISABLE(USBD_IRQn);
|
||||
|
||||
if (this->events == NULL) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
|
||||
this->events = events;
|
||||
|
||||
ret_code_t ret;
|
||||
|
||||
// Initialize power module to track USB Power events
|
||||
ret = nrfx_power_init(NULL);
|
||||
MBED_ASSERT(ret == NRF_SUCCESS);
|
||||
|
||||
|
||||
// Register callback for USB Power events
|
||||
static const nrfx_power_usbevt_config_t config = {
|
||||
.handler = power_usb_event_handler
|
||||
};
|
||||
|
||||
nrfx_power_usbevt_init(&config);
|
||||
|
||||
// Initialize USB Device driver
|
||||
ret = nrf_drv_usbd_init(usbd_event_handler);
|
||||
MBED_ASSERT(ret == NRF_SUCCESS);
|
||||
|
||||
/* Configure selected size of the packed on EP0 */
|
||||
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, MAX_PACKET_SIZE_SETUP);
|
||||
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, MAX_PACKET_SIZE_SETUP);
|
||||
|
||||
// Store a reference to this instance
|
||||
instance = this;
|
||||
|
||||
virtual_status_xfer_event = false;
|
||||
|
||||
/*
|
||||
* Configure ISOIN endpoint to respond with ZLP when
|
||||
* no data is ready to be sent
|
||||
*/
|
||||
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
|
||||
|
||||
// Set up the IRQ handler
|
||||
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_HAL_IRQHandler);
|
||||
|
||||
// Enable the power events
|
||||
nrfx_power_usbevt_enable();
|
||||
|
||||
}
|
||||
|
||||
void USBPhyHw::deinit()
|
||||
{
|
||||
// Disconnect and disable interrupt
|
||||
disconnect();
|
||||
|
||||
// Disable the USB Device driver
|
||||
ret_code_t ret = nrf_drv_usbd_uninit();
|
||||
MBED_ASSERT(ret == NRF_SUCCESS);
|
||||
|
||||
// Disable the power peripheral driver
|
||||
nrfx_power_uninit();
|
||||
|
||||
if (this->events != NULL) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
this->events = NULL;
|
||||
|
||||
// Clear the instance pointer
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
bool USBPhyHw::powered()
|
||||
{
|
||||
if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED
|
||||
|| nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void USBPhyHw::connect()
|
||||
{
|
||||
|
||||
// To save power, we only enable the USBD peripheral
|
||||
// when there's actually VBUS detected
|
||||
|
||||
// So flag that the USB stack is ready to connect
|
||||
this->connect_enabled = true;
|
||||
|
||||
// If VBUS is already available, enable immediately
|
||||
if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED) {
|
||||
// Enabling USB will cause NRF_DRV_POWER_USB_EVT_READY
|
||||
// to occur, which will start the USBD peripheral
|
||||
// when the internal regulator has settled
|
||||
if (!nrf_drv_usbd_is_enabled()) {
|
||||
nrf_drv_usbd_enable();
|
||||
}
|
||||
|
||||
if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY
|
||||
&& !nrf_drv_usbd_is_started()) {
|
||||
nrf_drv_usbd_start(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USBPhyHw::disconnect()
|
||||
{
|
||||
|
||||
this->connect_enabled = false;
|
||||
|
||||
if (nrf_drv_usbd_is_started()) {
|
||||
nrf_drv_usbd_stop();
|
||||
}
|
||||
if (nrf_drv_usbd_is_enabled()) {
|
||||
nrf_drv_usbd_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void USBPhyHw::configure()
|
||||
{
|
||||
// Not needed
|
||||
}
|
||||
|
||||
void USBPhyHw::unconfigure()
|
||||
{
|
||||
// Remove all endpoints (except control, obviously)
|
||||
nrf_drv_usbd_ep_default_config();
|
||||
}
|
||||
|
||||
void USBPhyHw::sof_enable()
|
||||
{
|
||||
// TODO - Enable SOF interrupt
|
||||
// Can this safely be done if
|
||||
// nrf_drv_usbd_start is called with SoF enabled?
|
||||
// For now just mask the interrupt with a boolean flag
|
||||
sof_enabled = true;
|
||||
}
|
||||
|
||||
void USBPhyHw::sof_disable()
|
||||
{
|
||||
// TODO - Disable SOF interrupt
|
||||
// Can this safely be done if
|
||||
// nrf_drv_usbd_start is called with SoF enabled?
|
||||
sof_enabled = false;
|
||||
}
|
||||
|
||||
void USBPhyHw::set_address(uint8_t address)
|
||||
{
|
||||
// nothing to do, handled by hardware; but don't STALL
|
||||
}
|
||||
|
||||
void USBPhyHw::remote_wakeup()
|
||||
{
|
||||
// Not supported(?)
|
||||
}
|
||||
|
||||
const usb_ep_table_t *USBPhyHw::endpoint_table()
|
||||
{
|
||||
|
||||
static const usb_ep_table_t template_table = {
|
||||
1536, // 64 bytes per bulk/int endpoint pair (8), 1023 bytes for iso endpoint pair (1)
|
||||
{
|
||||
{ USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
|
||||
}
|
||||
};
|
||||
return &template_table;
|
||||
}
|
||||
|
||||
uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet)
|
||||
{
|
||||
disable_usb_interrupts();
|
||||
|
||||
if (max_packet > MAX_PACKET_SIZE_SETUP) {
|
||||
max_packet = MAX_PACKET_SIZE_SETUP;
|
||||
}
|
||||
|
||||
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, max_packet);
|
||||
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, max_packet);
|
||||
|
||||
enable_usb_interrupts();
|
||||
|
||||
return max_packet;
|
||||
}
|
||||
|
||||
// read setup packet
|
||||
void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
|
||||
disable_usb_interrupts();
|
||||
|
||||
if (size > sizeof(this->setup_buf)) {
|
||||
size = sizeof(this->setup_buf);
|
||||
}
|
||||
memcpy(buffer, &this->setup_buf, size);
|
||||
|
||||
enable_usb_interrupts();
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_read(uint8_t *data, uint32_t size)
|
||||
{
|
||||
|
||||
// Check for status stage
|
||||
if (data == NULL && size == 0) {
|
||||
// If the data stage transfer direction was OUT
|
||||
if (setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) {
|
||||
// This is the status stage -- trigger the status task and notify the Mbed stack
|
||||
// Don't trigger status stage unless endpoint is not busy!
|
||||
// (Causes an undocumented hardware-initiated stall on the control endpoint)
|
||||
if (nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPIN0)) {
|
||||
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
|
||||
} else {
|
||||
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
|
||||
}
|
||||
|
||||
virtual_status_xfer_event = true;
|
||||
|
||||
// Trigger an interrupt to process the virtual status event
|
||||
NRFX_IRQ_PENDING_SET(USBD_IRQn);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPOUT0));
|
||||
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
|
||||
transfer->p_data.rx = data;
|
||||
transfer->size = size;
|
||||
|
||||
nrf_drv_usbd_setup_data_clear(); // tell the hardware to receive another OUT packet
|
||||
|
||||
ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, transfer);
|
||||
MBED_ASSERT(ret == NRF_SUCCESS);
|
||||
}
|
||||
|
||||
uint32_t USBPhyHw::ep0_read_result()
|
||||
{
|
||||
return nrf_drv_usbd_epout_size_get(NRF_DRV_USBD_EPOUT0);
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
|
||||
// Check for status stage
|
||||
if (buffer == NULL && size == 0) {
|
||||
// If the requested size was 0 OR the data stage transfer direction was OUT
|
||||
if (setup_buf.wLength == 0
|
||||
|| ((setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) == 0)) {
|
||||
|
||||
// This is the status stage -- trigger the status task and notify the Mbed stack
|
||||
|
||||
// Don't trigger status stage unless endpoint is not busy!
|
||||
// (Causes an undocumented hardware-initiated stall on the control endpoint)
|
||||
if (nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPOUT0)) {
|
||||
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
|
||||
} else {
|
||||
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
|
||||
}
|
||||
|
||||
virtual_status_xfer_event = true;
|
||||
|
||||
// Trigger an interrupt to process the virtual status event
|
||||
NRFX_IRQ_PENDING_SET(USBD_IRQn);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(NRF_DRV_USBD_EPIN0);
|
||||
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
|
||||
transfer->p_data.tx = buffer;
|
||||
transfer->size = size;
|
||||
|
||||
if (size == 0) {
|
||||
transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG;
|
||||
}
|
||||
|
||||
ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, transfer);
|
||||
MBED_ASSERT(ret == NRF_SUCCESS);
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_stall()
|
||||
{
|
||||
// Note: This stall must be automatically cleared by the next setup packet
|
||||
nrf_drv_usbd_setup_stall();
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type)
|
||||
{
|
||||
nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint);
|
||||
nrf_drv_usbd_ep_enable(nrf_ep);
|
||||
nrf_drv_usbd_ep_max_packet_size_set(nrf_ep, max_packet);
|
||||
return nrf_drv_usbd_ep_enable_check(nrf_ep);
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
|
||||
{
|
||||
nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint);
|
||||
// Reset data toggle for bulk/interrupt endpoints
|
||||
if (nrf_ep != NRF_DRV_USBD_EPOUT8 && nrf_ep != NRF_DRV_USBD_EPIN8) {
|
||||
nrf_drv_usbd_ep_dtoggle_clear(nrf_ep);
|
||||
}
|
||||
|
||||
nrf_drv_usbd_ep_disable(nrf_ep);
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_stall(usb_ep_t endpoint)
|
||||
{
|
||||
nrf_drv_usbd_ep_stall(get_nordic_endpoint(endpoint));
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint)
|
||||
{
|
||||
nrf_drv_usbd_ep_t ep = get_nordic_endpoint(endpoint);
|
||||
|
||||
// Unstall may be called on an endpoint that isn't stalled
|
||||
if (nrf_drv_usbd_ep_stall_check(ep)) {
|
||||
nrf_drv_usbd_ep_stall_clear(ep);
|
||||
}
|
||||
|
||||
// Clear data toggle
|
||||
nrf_drv_usbd_ep_dtoggle_clear(ep);
|
||||
|
||||
/*
|
||||
* This is a somewhat hacky fix to fully "unload"
|
||||
* an IN endpoint after a buffer has been
|
||||
* transferred via EasyDMA...
|
||||
*/
|
||||
|
||||
nrf_drv_usbd_ep_disable(ep);
|
||||
nrf_drv_usbd_ep_enable(ep);
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size)
|
||||
{
|
||||
nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(endpoint);
|
||||
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
|
||||
transfer->p_data.rx = data;
|
||||
transfer->size = size;
|
||||
|
||||
ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer);
|
||||
return (ret == NRF_SUCCESS);
|
||||
}
|
||||
|
||||
uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint)
|
||||
{
|
||||
return nrf_drv_usbd_epout_size_get(get_nordic_endpoint(endpoint));
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
|
||||
{
|
||||
nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(endpoint);
|
||||
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
|
||||
transfer->p_data.tx = data;
|
||||
transfer->size = size;
|
||||
|
||||
// If this is a zero-length-packet (ZLP)
|
||||
// Set the ZLP flag
|
||||
if (size == 0) {
|
||||
transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG;
|
||||
}
|
||||
|
||||
ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer);
|
||||
return (ret == NRF_SUCCESS);
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
|
||||
{
|
||||
nrf_drv_usbd_ep_abort(get_nordic_endpoint(endpoint));
|
||||
}
|
||||
|
||||
void USBPhyHw::process()
|
||||
{
|
||||
|
||||
if (usb_event_type == USB_HW_EVENT_USBD) {
|
||||
|
||||
// Process regular USBD events
|
||||
switch (usb_event.type) {
|
||||
case NRF_DRV_USBD_EVT_SUSPEND:
|
||||
events->suspend(true);
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_RESUME:
|
||||
events->suspend(false);
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_WUREQ:
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_RESET:
|
||||
this->_reset();
|
||||
events->reset();
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_SOF:
|
||||
if (sof_enabled) {
|
||||
events->sof(usb_event.data.sof.framecnt);
|
||||
}
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_EPTRANSFER:
|
||||
if (usb_event.data.eptransfer.status == NRF_USBD_EP_OK) {
|
||||
if (!nrf_drv_usbd_ep_stall_check(usb_event.data.eptransfer.ep)) {
|
||||
if (IS_IN_EP(usb_event.data.eptransfer.ep)) {
|
||||
if ((usb_event.data.eptransfer.ep & 0x7F) == 0) {
|
||||
events->ep0_in();
|
||||
} else {
|
||||
events->in((usb_ep_t) usb_event.data.eptransfer.ep);
|
||||
}
|
||||
} else {
|
||||
if ((usb_event.data.eptransfer.ep & 0x7F) == 0) {
|
||||
events->ep0_out();
|
||||
} else {
|
||||
events->out((usb_ep_t) usb_event.data.eptransfer.ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NRF_DRV_USBD_EVT_SETUP: {
|
||||
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN0);
|
||||
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT0);
|
||||
|
||||
// Copy the setup packet into the internal buffer
|
||||
nrf_drv_usbd_setup_get(&setup_buf);
|
||||
|
||||
// Notify the Mbed stack
|
||||
events->ep0_setup();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (usb_event_type == USB_HW_EVENT_POWER) {
|
||||
// Process USB power-related events
|
||||
switch (usb_power_event) {
|
||||
case NRFX_POWER_USB_EVT_DETECTED:
|
||||
if (this->connect_enabled) {
|
||||
if (!nrf_drv_usbd_is_enabled()) {
|
||||
nrf_drv_usbd_enable();
|
||||
}
|
||||
events->power(true);
|
||||
}
|
||||
break;
|
||||
case NRFX_POWER_USB_EVT_REMOVED:
|
||||
events->power(false);
|
||||
break;
|
||||
case NRFX_POWER_USB_EVT_READY:
|
||||
if (!nrf_drv_usbd_is_started()) {
|
||||
nrf_drv_usbd_start(true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
} else if (usb_event_type == USB_HW_EVENT_VIRTUAL_STATUS) {
|
||||
// Notify Mbed stack of status stage transfer completion
|
||||
if (setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) { // DATA IN transfer, Status OUT transfer
|
||||
events->ep0_out();
|
||||
} else { // DATA OUT transfer, Status IN transfer
|
||||
events->ep0_in();
|
||||
}
|
||||
}
|
||||
|
||||
// Unflag the event type
|
||||
usb_event_type = USB_HW_EVENT_NONE;
|
||||
|
||||
// Re-enable interrupt
|
||||
enable_usb_interrupts();
|
||||
}
|
||||
|
||||
void USBPhyHw::_usb_event_handler(
|
||||
nrf_drv_usbd_evt_t const *const p_event)
|
||||
{
|
||||
disable_usb_interrupts();
|
||||
// Copy the event data into internal memory
|
||||
memcpy(&instance->usb_event, p_event, sizeof(instance->usb_event));
|
||||
// Tell the upper layers of the stack to process the event
|
||||
instance->usb_event_type = USB_HW_EVENT_USBD;
|
||||
instance->events->start_process();
|
||||
}
|
||||
|
||||
void USBPhyHw::_usb_power_event_handler(nrfx_power_usb_evt_t event)
|
||||
{
|
||||
disable_usb_interrupts();
|
||||
// Copy the event data into internal memory
|
||||
instance->usb_power_event = event;
|
||||
// Tell the upper layers of the stack to process the event
|
||||
instance->usb_event_type = USB_HW_EVENT_POWER;
|
||||
instance->events->start_process();
|
||||
}
|
||||
|
||||
void USBPhyHw::_usb_virtual_status_event_handler(void)
|
||||
{
|
||||
disable_usb_interrupts();
|
||||
|
||||
// Tell the upper layers of the stack to process the event
|
||||
instance->usb_event_type = USB_HW_EVENT_VIRTUAL_STATUS;
|
||||
instance->events->start_process();
|
||||
}
|
||||
|
||||
nrf_drv_usbd_transfer_t *USBPhyHw::get_transfer_buffer(usb_ep_t endpoint)
|
||||
{
|
||||
// Index is base endpoint number * 2 (output), add 1 for input endpoints
|
||||
return &transfer_buf[(((endpoint & 0x7F) << 1) + ((endpoint & 0x80) >> 7))];
|
||||
}
|
||||
|
||||
nrf_drv_usbd_ep_t USBPhyHw::get_nordic_endpoint(usb_ep_t endpoint)
|
||||
{
|
||||
return (nrf_drv_usbd_ep_t) endpoint;
|
||||
}
|
||||
|
||||
void USBPhyHw::_reset(void)
|
||||
{
|
||||
// Disable all endpoints except for control endpoints
|
||||
nrf_drv_usbd_ep_default_config();
|
||||
|
||||
nrf_drv_usbd_setup_clear();
|
||||
|
||||
usb_event_type = USB_HW_EVENT_NONE;
|
||||
|
||||
// Clear all endpoint interrupts
|
||||
NRFX_IRQ_PENDING_CLEAR(USBD_IRQn);
|
||||
nrf_usbd_event_clear((nrf_usbd_event_t)0x01FFFFFF);
|
||||
}
|
||||
|
||||
void USBPhyHw::enable_usb_interrupts(void)
|
||||
{
|
||||
// Enable USB and USB-related power interrupts
|
||||
NRFX_IRQ_ENABLE(USBD_IRQn);
|
||||
nrfx_power_usbevt_enable();
|
||||
}
|
||||
|
||||
void USBPhyHw::disable_usb_interrupts(void)
|
||||
{
|
||||
// Disable USB and USB-related power interrupts
|
||||
NRFX_IRQ_DISABLE(USBD_IRQn);
|
||||
nrfx_power_usbevt_disable();
|
||||
}
|
||||
|
||||
static void power_usb_event_handler(nrfx_power_usb_evt_t event)
|
||||
{
|
||||
if (instance) {
|
||||
// Pass the event on to the USBPhyHW instance
|
||||
instance->_usb_power_event_handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
static void usbd_event_handler(nrf_drv_usbd_evt_t const *const p_event)
|
||||
{
|
||||
if (instance) {
|
||||
// Pass the event on to the USBPhyHW instance
|
||||
instance->_usb_event_handler(p_event);
|
||||
}
|
||||
}
|
||||
|
||||
void USBD_HAL_IRQHandler(void)
|
||||
{
|
||||
// Process the virtual status stage transfer event
|
||||
if (virtual_status_xfer_event) {
|
||||
if (instance) {
|
||||
instance->_usb_virtual_status_event_handler();
|
||||
}
|
||||
|
||||
virtual_status_xfer_event = false;
|
||||
|
||||
}
|
||||
// Call Nordic driver IRQ handler
|
||||
USBD_IRQHandler();
|
||||
}
|
Loading…
Reference in New Issue