I changed one line of code in the file with path name: USBDeviceHT/targets/TARGET_Maxim
Fork of USBDeviceHT by
targets/TARGET_Silicon_Labs/src/em_usbd.c@0:a3ea811f80f2, 2018-02-05 (annotated)
- Committer:
- Helmut64
- Date:
- Mon Feb 05 10:22:57 2018 +0000
- Revision:
- 0:a3ea811f80f2
Inital checkin after copied from mbed.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Helmut64 | 0:a3ea811f80f2 | 1 | /**************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 2 | * @file em_usbd.c |
Helmut64 | 0:a3ea811f80f2 | 3 | * @brief USB protocol stack library, device API. |
Helmut64 | 0:a3ea811f80f2 | 4 | * @version 3.20.14 |
Helmut64 | 0:a3ea811f80f2 | 5 | ****************************************************************************** |
Helmut64 | 0:a3ea811f80f2 | 6 | * @section License |
Helmut64 | 0:a3ea811f80f2 | 7 | * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> |
Helmut64 | 0:a3ea811f80f2 | 8 | ******************************************************************************* |
Helmut64 | 0:a3ea811f80f2 | 9 | * |
Helmut64 | 0:a3ea811f80f2 | 10 | * Licensed under the Apache License, Version 2.0 (the "License"); |
Helmut64 | 0:a3ea811f80f2 | 11 | * you may not use this file except in compliance with the License. |
Helmut64 | 0:a3ea811f80f2 | 12 | * You may obtain a copy of the License at |
Helmut64 | 0:a3ea811f80f2 | 13 | * |
Helmut64 | 0:a3ea811f80f2 | 14 | * http://www.apache.org/licenses/LICENSE-2.0 |
Helmut64 | 0:a3ea811f80f2 | 15 | * |
Helmut64 | 0:a3ea811f80f2 | 16 | * Unless required by applicable law or agreed to in writing, software |
Helmut64 | 0:a3ea811f80f2 | 17 | * distributed under the License is distributed on an "AS IS" BASIS, |
Helmut64 | 0:a3ea811f80f2 | 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Helmut64 | 0:a3ea811f80f2 | 19 | * See the License for the specific language governing permissions and |
Helmut64 | 0:a3ea811f80f2 | 20 | * limitations under the License. |
Helmut64 | 0:a3ea811f80f2 | 21 | * |
Helmut64 | 0:a3ea811f80f2 | 22 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 23 | |
Helmut64 | 0:a3ea811f80f2 | 24 | #include "em_device.h" |
Helmut64 | 0:a3ea811f80f2 | 25 | #if defined( USB_PRESENT ) && ( USB_COUNT == 1 ) |
Helmut64 | 0:a3ea811f80f2 | 26 | #include "em_usb.h" |
Helmut64 | 0:a3ea811f80f2 | 27 | #if defined( USB_DEVICE ) |
Helmut64 | 0:a3ea811f80f2 | 28 | |
Helmut64 | 0:a3ea811f80f2 | 29 | #include "em_cmu.h" |
Helmut64 | 0:a3ea811f80f2 | 30 | #include "em_core.h" |
Helmut64 | 0:a3ea811f80f2 | 31 | #include "em_usbtypes.h" |
Helmut64 | 0:a3ea811f80f2 | 32 | #include "em_usbhal.h" |
Helmut64 | 0:a3ea811f80f2 | 33 | #include "em_usbd.h" |
Helmut64 | 0:a3ea811f80f2 | 34 | |
Helmut64 | 0:a3ea811f80f2 | 35 | /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ |
Helmut64 | 0:a3ea811f80f2 | 36 | |
Helmut64 | 0:a3ea811f80f2 | 37 | static USBD_Device_TypeDef device; |
Helmut64 | 0:a3ea811f80f2 | 38 | USBD_Device_TypeDef *dev = &device; |
Helmut64 | 0:a3ea811f80f2 | 39 | |
Helmut64 | 0:a3ea811f80f2 | 40 | static uint32_t totalRxFifoSize = 0, totalTxFifoSize = 0; |
Helmut64 | 0:a3ea811f80f2 | 41 | static int numEps = 0; |
Helmut64 | 0:a3ea811f80f2 | 42 | static int txFifoNum = 1; |
Helmut64 | 0:a3ea811f80f2 | 43 | |
Helmut64 | 0:a3ea811f80f2 | 44 | static void USBD_ResetEndpoints(void); |
Helmut64 | 0:a3ea811f80f2 | 45 | extern USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize, |
Helmut64 | 0:a3ea811f80f2 | 46 | uint32_t totalTxFifoSize ); |
Helmut64 | 0:a3ea811f80f2 | 47 | #ifndef __MBED__ |
Helmut64 | 0:a3ea811f80f2 | 48 | static const char *stateNames[] = |
Helmut64 | 0:a3ea811f80f2 | 49 | { |
Helmut64 | 0:a3ea811f80f2 | 50 | [ USBD_STATE_NONE ] = "NONE ", |
Helmut64 | 0:a3ea811f80f2 | 51 | [ USBD_STATE_ATTACHED ] = "ATTACHED ", |
Helmut64 | 0:a3ea811f80f2 | 52 | [ USBD_STATE_POWERED ] = "POWERED ", |
Helmut64 | 0:a3ea811f80f2 | 53 | [ USBD_STATE_DEFAULT ] = "DEFAULT ", |
Helmut64 | 0:a3ea811f80f2 | 54 | [ USBD_STATE_ADDRESSED ] = "ADDRESSED ", |
Helmut64 | 0:a3ea811f80f2 | 55 | [ USBD_STATE_CONFIGURED ] = "CONFIGURED", |
Helmut64 | 0:a3ea811f80f2 | 56 | [ USBD_STATE_SUSPENDED ] = "SUSPENDED ", |
Helmut64 | 0:a3ea811f80f2 | 57 | [ USBD_STATE_LASTMARKER ] = "UNDEFINED " |
Helmut64 | 0:a3ea811f80f2 | 58 | }; |
Helmut64 | 0:a3ea811f80f2 | 59 | #endif |
Helmut64 | 0:a3ea811f80f2 | 60 | |
Helmut64 | 0:a3ea811f80f2 | 61 | /** @endcond */ |
Helmut64 | 0:a3ea811f80f2 | 62 | |
Helmut64 | 0:a3ea811f80f2 | 63 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 64 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 65 | * Abort all pending transfers. |
Helmut64 | 0:a3ea811f80f2 | 66 | * |
Helmut64 | 0:a3ea811f80f2 | 67 | * @details |
Helmut64 | 0:a3ea811f80f2 | 68 | * Aborts transfers for all endpoints currently in use. Pending |
Helmut64 | 0:a3ea811f80f2 | 69 | * transfers on the default endpoint (EP0) are not aborted. |
Helmut64 | 0:a3ea811f80f2 | 70 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 71 | void USBD_AbortAllTransfers( void ) |
Helmut64 | 0:a3ea811f80f2 | 72 | { |
Helmut64 | 0:a3ea811f80f2 | 73 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 74 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 75 | USBDHAL_AbortAllTransfers( USB_STATUS_EP_ABORTED ); |
Helmut64 | 0:a3ea811f80f2 | 76 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 77 | } |
Helmut64 | 0:a3ea811f80f2 | 78 | |
Helmut64 | 0:a3ea811f80f2 | 79 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 80 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 81 | * Abort a pending transfer on a specific endpoint. |
Helmut64 | 0:a3ea811f80f2 | 82 | * |
Helmut64 | 0:a3ea811f80f2 | 83 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 84 | * The address of the endpoint to abort. |
Helmut64 | 0:a3ea811f80f2 | 85 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 86 | int USBD_AbortTransfer( int epAddr ) |
Helmut64 | 0:a3ea811f80f2 | 87 | { |
Helmut64 | 0:a3ea811f80f2 | 88 | USB_XferCompleteCb_TypeDef callback; |
Helmut64 | 0:a3ea811f80f2 | 89 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 90 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 91 | |
Helmut64 | 0:a3ea811f80f2 | 92 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 93 | { |
Helmut64 | 0:a3ea811f80f2 | 94 | DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 95 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 96 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 97 | } |
Helmut64 | 0:a3ea811f80f2 | 98 | |
Helmut64 | 0:a3ea811f80f2 | 99 | if ( ep->num == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 100 | { |
Helmut64 | 0:a3ea811f80f2 | 101 | DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 102 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 103 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 104 | } |
Helmut64 | 0:a3ea811f80f2 | 105 | |
Helmut64 | 0:a3ea811f80f2 | 106 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 107 | if ( ep->state == D_EP_IDLE ) |
Helmut64 | 0:a3ea811f80f2 | 108 | { |
Helmut64 | 0:a3ea811f80f2 | 109 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 110 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 111 | } |
Helmut64 | 0:a3ea811f80f2 | 112 | |
Helmut64 | 0:a3ea811f80f2 | 113 | USBD_AbortEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 114 | |
Helmut64 | 0:a3ea811f80f2 | 115 | ep->state = D_EP_IDLE; |
Helmut64 | 0:a3ea811f80f2 | 116 | if ( ep->xferCompleteCb ) |
Helmut64 | 0:a3ea811f80f2 | 117 | { |
Helmut64 | 0:a3ea811f80f2 | 118 | callback = ep->xferCompleteCb; |
Helmut64 | 0:a3ea811f80f2 | 119 | ep->xferCompleteCb = NULL; |
Helmut64 | 0:a3ea811f80f2 | 120 | |
Helmut64 | 0:a3ea811f80f2 | 121 | if ( ( dev->lastState == USBD_STATE_CONFIGURED ) && |
Helmut64 | 0:a3ea811f80f2 | 122 | ( dev->state == USBD_STATE_ADDRESSED ) ) |
Helmut64 | 0:a3ea811f80f2 | 123 | { |
Helmut64 | 0:a3ea811f80f2 | 124 | USBDHAL_DeactivateEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 125 | } |
Helmut64 | 0:a3ea811f80f2 | 126 | |
Helmut64 | 0:a3ea811f80f2 | 127 | DEBUG_TRACE_ABORT( USB_STATUS_EP_ABORTED ); |
Helmut64 | 0:a3ea811f80f2 | 128 | callback( USB_STATUS_EP_ABORTED, ep->xferred, ep->remaining ); |
Helmut64 | 0:a3ea811f80f2 | 129 | } |
Helmut64 | 0:a3ea811f80f2 | 130 | |
Helmut64 | 0:a3ea811f80f2 | 131 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 132 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 133 | } |
Helmut64 | 0:a3ea811f80f2 | 134 | |
Helmut64 | 0:a3ea811f80f2 | 135 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 136 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 137 | * Start USB device operation. |
Helmut64 | 0:a3ea811f80f2 | 138 | * |
Helmut64 | 0:a3ea811f80f2 | 139 | * @details |
Helmut64 | 0:a3ea811f80f2 | 140 | * Device operation is started by connecting a pullup resistor on the |
Helmut64 | 0:a3ea811f80f2 | 141 | * appropriate USB data line. |
Helmut64 | 0:a3ea811f80f2 | 142 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 143 | void USBD_Connect( void ) |
Helmut64 | 0:a3ea811f80f2 | 144 | { |
Helmut64 | 0:a3ea811f80f2 | 145 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 146 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 147 | USBDHAL_Connect(); |
Helmut64 | 0:a3ea811f80f2 | 148 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 149 | } |
Helmut64 | 0:a3ea811f80f2 | 150 | |
Helmut64 | 0:a3ea811f80f2 | 151 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 152 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 153 | * Stop USB device operation. |
Helmut64 | 0:a3ea811f80f2 | 154 | * |
Helmut64 | 0:a3ea811f80f2 | 155 | * @details |
Helmut64 | 0:a3ea811f80f2 | 156 | * Device operation is stopped by disconnecting the pullup resistor from the |
Helmut64 | 0:a3ea811f80f2 | 157 | * appropriate USB data line. Often referred to as a "soft" disconnect. |
Helmut64 | 0:a3ea811f80f2 | 158 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 159 | void USBD_Disconnect( void ) |
Helmut64 | 0:a3ea811f80f2 | 160 | { |
Helmut64 | 0:a3ea811f80f2 | 161 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 162 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 163 | USBDHAL_Disconnect(); |
Helmut64 | 0:a3ea811f80f2 | 164 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 165 | } |
Helmut64 | 0:a3ea811f80f2 | 166 | |
Helmut64 | 0:a3ea811f80f2 | 167 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 168 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 169 | * Check if an endpoint is busy doing a transfer. |
Helmut64 | 0:a3ea811f80f2 | 170 | * |
Helmut64 | 0:a3ea811f80f2 | 171 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 172 | * The address of the endpoint to check. |
Helmut64 | 0:a3ea811f80f2 | 173 | * |
Helmut64 | 0:a3ea811f80f2 | 174 | * @return |
Helmut64 | 0:a3ea811f80f2 | 175 | * True if endpoint is busy, false otherwise. |
Helmut64 | 0:a3ea811f80f2 | 176 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 177 | bool USBD_EpIsBusy( int epAddr ) |
Helmut64 | 0:a3ea811f80f2 | 178 | { |
Helmut64 | 0:a3ea811f80f2 | 179 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 180 | |
Helmut64 | 0:a3ea811f80f2 | 181 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 182 | { |
Helmut64 | 0:a3ea811f80f2 | 183 | DEBUG_USB_API_PUTS( "\nUSBD_EpIsBusy(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 184 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 185 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 186 | } |
Helmut64 | 0:a3ea811f80f2 | 187 | |
Helmut64 | 0:a3ea811f80f2 | 188 | if ( ep->state == D_EP_IDLE ) |
Helmut64 | 0:a3ea811f80f2 | 189 | return false; |
Helmut64 | 0:a3ea811f80f2 | 190 | |
Helmut64 | 0:a3ea811f80f2 | 191 | return true; |
Helmut64 | 0:a3ea811f80f2 | 192 | } |
Helmut64 | 0:a3ea811f80f2 | 193 | |
Helmut64 | 0:a3ea811f80f2 | 194 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 195 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 196 | * Get current USB device state. |
Helmut64 | 0:a3ea811f80f2 | 197 | * |
Helmut64 | 0:a3ea811f80f2 | 198 | * @return |
Helmut64 | 0:a3ea811f80f2 | 199 | * Device USB state. See @ref USBD_State_TypeDef. |
Helmut64 | 0:a3ea811f80f2 | 200 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 201 | USBD_State_TypeDef USBD_GetUsbState( void ) |
Helmut64 | 0:a3ea811f80f2 | 202 | { |
Helmut64 | 0:a3ea811f80f2 | 203 | return dev->state; |
Helmut64 | 0:a3ea811f80f2 | 204 | } |
Helmut64 | 0:a3ea811f80f2 | 205 | |
Helmut64 | 0:a3ea811f80f2 | 206 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 207 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 208 | * Get a string naming a device USB state. |
Helmut64 | 0:a3ea811f80f2 | 209 | * |
Helmut64 | 0:a3ea811f80f2 | 210 | * @param[in] state |
Helmut64 | 0:a3ea811f80f2 | 211 | * Device USB state. See @ref USBD_State_TypeDef. |
Helmut64 | 0:a3ea811f80f2 | 212 | * |
Helmut64 | 0:a3ea811f80f2 | 213 | * @return |
Helmut64 | 0:a3ea811f80f2 | 214 | * State name string pointer. |
Helmut64 | 0:a3ea811f80f2 | 215 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 216 | const char *USBD_GetUsbStateName( USBD_State_TypeDef state ) |
Helmut64 | 0:a3ea811f80f2 | 217 | { |
Helmut64 | 0:a3ea811f80f2 | 218 | if ( state > USBD_STATE_LASTMARKER ) |
Helmut64 | 0:a3ea811f80f2 | 219 | state = USBD_STATE_LASTMARKER; |
Helmut64 | 0:a3ea811f80f2 | 220 | |
Helmut64 | 0:a3ea811f80f2 | 221 | #ifndef __MBED__ |
Helmut64 | 0:a3ea811f80f2 | 222 | return stateNames[ state ]; |
Helmut64 | 0:a3ea811f80f2 | 223 | #else |
Helmut64 | 0:a3ea811f80f2 | 224 | return NULL; |
Helmut64 | 0:a3ea811f80f2 | 225 | #endif |
Helmut64 | 0:a3ea811f80f2 | 226 | } |
Helmut64 | 0:a3ea811f80f2 | 227 | |
Helmut64 | 0:a3ea811f80f2 | 228 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 229 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 230 | * Initializes USB device hardware and internal protocol stack data structures, |
Helmut64 | 0:a3ea811f80f2 | 231 | * then connects the data-line (D+ or D-) pullup resistor to signal host that |
Helmut64 | 0:a3ea811f80f2 | 232 | * enumeration can begin. |
Helmut64 | 0:a3ea811f80f2 | 233 | * |
Helmut64 | 0:a3ea811f80f2 | 234 | * @note |
Helmut64 | 0:a3ea811f80f2 | 235 | * You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force |
Helmut64 | 0:a3ea811f80f2 | 236 | * reenumeration. |
Helmut64 | 0:a3ea811f80f2 | 237 | * |
Helmut64 | 0:a3ea811f80f2 | 238 | * @param[in] p |
Helmut64 | 0:a3ea811f80f2 | 239 | * Pointer to device initialization struct. See @ref USBD_Init_TypeDef. |
Helmut64 | 0:a3ea811f80f2 | 240 | * |
Helmut64 | 0:a3ea811f80f2 | 241 | * @return |
Helmut64 | 0:a3ea811f80f2 | 242 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 243 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 244 | int USBD_Init( const USBD_Init_TypeDef *p ) |
Helmut64 | 0:a3ea811f80f2 | 245 | { |
Helmut64 | 0:a3ea811f80f2 | 246 | USBD_Ep_TypeDef *ep; |
Helmut64 | 0:a3ea811f80f2 | 247 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 248 | |
Helmut64 | 0:a3ea811f80f2 | 249 | #if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN ) |
Helmut64 | 0:a3ea811f80f2 | 250 | /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */ |
Helmut64 | 0:a3ea811f80f2 | 251 | /* All other devices must use HFXO as core clock. */ |
Helmut64 | 0:a3ea811f80f2 | 252 | if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO ) |
Helmut64 | 0:a3ea811f80f2 | 253 | { |
Helmut64 | 0:a3ea811f80f2 | 254 | CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); |
Helmut64 | 0:a3ea811f80f2 | 255 | } |
Helmut64 | 0:a3ea811f80f2 | 256 | #endif |
Helmut64 | 0:a3ea811f80f2 | 257 | |
Helmut64 | 0:a3ea811f80f2 | 258 | #if !defined( CMU_OSCENCMD_USHFRCOEN ) |
Helmut64 | 0:a3ea811f80f2 | 259 | #if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO ) |
Helmut64 | 0:a3ea811f80f2 | 260 | CMU_OscillatorEnable(cmuOsc_LFXO, true, false); |
Helmut64 | 0:a3ea811f80f2 | 261 | #else |
Helmut64 | 0:a3ea811f80f2 | 262 | CMU_OscillatorEnable(cmuOsc_LFRCO, true, false); |
Helmut64 | 0:a3ea811f80f2 | 263 | #endif |
Helmut64 | 0:a3ea811f80f2 | 264 | |
Helmut64 | 0:a3ea811f80f2 | 265 | #else |
Helmut64 | 0:a3ea811f80f2 | 266 | CMU_ClockEnable(cmuClock_CORELE, true); |
Helmut64 | 0:a3ea811f80f2 | 267 | /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */ |
Helmut64 | 0:a3ea811f80f2 | 268 | #if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO ) |
Helmut64 | 0:a3ea811f80f2 | 269 | CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO); |
Helmut64 | 0:a3ea811f80f2 | 270 | #else |
Helmut64 | 0:a3ea811f80f2 | 271 | CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO); |
Helmut64 | 0:a3ea811f80f2 | 272 | #endif |
Helmut64 | 0:a3ea811f80f2 | 273 | CMU_ClockEnable(cmuClock_USBLE, true); |
Helmut64 | 0:a3ea811f80f2 | 274 | #endif |
Helmut64 | 0:a3ea811f80f2 | 275 | |
Helmut64 | 0:a3ea811f80f2 | 276 | USBTIMER_Init(); |
Helmut64 | 0:a3ea811f80f2 | 277 | |
Helmut64 | 0:a3ea811f80f2 | 278 | memset( dev, 0, sizeof( USBD_Device_TypeDef ) ); |
Helmut64 | 0:a3ea811f80f2 | 279 | |
Helmut64 | 0:a3ea811f80f2 | 280 | dev->setup = dev->setupPkt; |
Helmut64 | 0:a3ea811f80f2 | 281 | dev->state = USBD_STATE_LASTMARKER; |
Helmut64 | 0:a3ea811f80f2 | 282 | dev->savedState = USBD_STATE_NONE; |
Helmut64 | 0:a3ea811f80f2 | 283 | dev->lastState = USBD_STATE_NONE; |
Helmut64 | 0:a3ea811f80f2 | 284 | dev->callbacks = p->callbacks; |
Helmut64 | 0:a3ea811f80f2 | 285 | dev->remoteWakeupEnabled = false; |
Helmut64 | 0:a3ea811f80f2 | 286 | |
Helmut64 | 0:a3ea811f80f2 | 287 | /* Initialize EP0 */ |
Helmut64 | 0:a3ea811f80f2 | 288 | |
Helmut64 | 0:a3ea811f80f2 | 289 | ep = &dev->ep[ 0 ]; |
Helmut64 | 0:a3ea811f80f2 | 290 | ep->in = false; |
Helmut64 | 0:a3ea811f80f2 | 291 | ep->buf = NULL; |
Helmut64 | 0:a3ea811f80f2 | 292 | ep->num = 0; |
Helmut64 | 0:a3ea811f80f2 | 293 | ep->mask = 1; |
Helmut64 | 0:a3ea811f80f2 | 294 | ep->addr = 0; |
Helmut64 | 0:a3ea811f80f2 | 295 | ep->type = USB_EPTYPE_CTRL; |
Helmut64 | 0:a3ea811f80f2 | 296 | ep->txFifoNum = 0; |
Helmut64 | 0:a3ea811f80f2 | 297 | |
Helmut64 | 0:a3ea811f80f2 | 298 | /* FIXME! */ |
Helmut64 | 0:a3ea811f80f2 | 299 | ep->packetSize = 64; |
Helmut64 | 0:a3ea811f80f2 | 300 | dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B; |
Helmut64 | 0:a3ea811f80f2 | 301 | |
Helmut64 | 0:a3ea811f80f2 | 302 | ep->remaining = 0; |
Helmut64 | 0:a3ea811f80f2 | 303 | ep->xferred = 0; |
Helmut64 | 0:a3ea811f80f2 | 304 | ep->state = D_EP_IDLE; |
Helmut64 | 0:a3ea811f80f2 | 305 | ep->xferCompleteCb = NULL; |
Helmut64 | 0:a3ea811f80f2 | 306 | ep->fifoSize = ep->packetSize / 4; |
Helmut64 | 0:a3ea811f80f2 | 307 | |
Helmut64 | 0:a3ea811f80f2 | 308 | totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ]; |
Helmut64 | 0:a3ea811f80f2 | 309 | totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ]; |
Helmut64 | 0:a3ea811f80f2 | 310 | |
Helmut64 | 0:a3ea811f80f2 | 311 | /* Rx-FIFO size: SETUP packets : 4*n + 6 n=#CTRL EP's |
Helmut64 | 0:a3ea811f80f2 | 312 | * GOTNAK : 1 |
Helmut64 | 0:a3ea811f80f2 | 313 | * Status info : 2*n n=#OUT EP's (EP0 included) in HW |
Helmut64 | 0:a3ea811f80f2 | 314 | */ |
Helmut64 | 0:a3ea811f80f2 | 315 | totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) ); |
Helmut64 | 0:a3ea811f80f2 | 316 | |
Helmut64 | 0:a3ea811f80f2 | 317 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 318 | |
Helmut64 | 0:a3ea811f80f2 | 319 | /* Enable USB clock */ |
Helmut64 | 0:a3ea811f80f2 | 320 | CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC; |
Helmut64 | 0:a3ea811f80f2 | 321 | |
Helmut64 | 0:a3ea811f80f2 | 322 | #if defined( CMU_OSCENCMD_USHFRCOEN ) |
Helmut64 | 0:a3ea811f80f2 | 323 | CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ; |
Helmut64 | 0:a3ea811f80f2 | 324 | CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO ); |
Helmut64 | 0:a3ea811f80f2 | 325 | |
Helmut64 | 0:a3ea811f80f2 | 326 | /* Enable USHFRCO Clock Recovery mode. */ |
Helmut64 | 0:a3ea811f80f2 | 327 | CMU->USBCRCTRL |= CMU_USBCRCTRL_EN; |
Helmut64 | 0:a3ea811f80f2 | 328 | |
Helmut64 | 0:a3ea811f80f2 | 329 | /* Turn on Low Energy Mode (LEM) features. */ |
Helmut64 | 0:a3ea811f80f2 | 330 | USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE |
Helmut64 | 0:a3ea811f80f2 | 331 | | USB_CTRL_LEMIDLEEN |
Helmut64 | 0:a3ea811f80f2 | 332 | | USB_CTRL_LEMPHYCTRL; |
Helmut64 | 0:a3ea811f80f2 | 333 | #else |
Helmut64 | 0:a3ea811f80f2 | 334 | CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK ); |
Helmut64 | 0:a3ea811f80f2 | 335 | #endif |
Helmut64 | 0:a3ea811f80f2 | 336 | |
Helmut64 | 0:a3ea811f80f2 | 337 | USBHAL_DisableGlobalInt(); |
Helmut64 | 0:a3ea811f80f2 | 338 | |
Helmut64 | 0:a3ea811f80f2 | 339 | if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK ) |
Helmut64 | 0:a3ea811f80f2 | 340 | { |
Helmut64 | 0:a3ea811f80f2 | 341 | USBDHAL_EnableUsbResetAndSuspendInt(); |
Helmut64 | 0:a3ea811f80f2 | 342 | USBHAL_EnableGlobalInt(); |
Helmut64 | 0:a3ea811f80f2 | 343 | NVIC_ClearPendingIRQ( USB_IRQn ); |
Helmut64 | 0:a3ea811f80f2 | 344 | NVIC_EnableIRQ( USB_IRQn ); |
Helmut64 | 0:a3ea811f80f2 | 345 | } |
Helmut64 | 0:a3ea811f80f2 | 346 | else |
Helmut64 | 0:a3ea811f80f2 | 347 | { |
Helmut64 | 0:a3ea811f80f2 | 348 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 349 | DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" ); |
Helmut64 | 0:a3ea811f80f2 | 350 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 351 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 352 | } |
Helmut64 | 0:a3ea811f80f2 | 353 | |
Helmut64 | 0:a3ea811f80f2 | 354 | #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF ) |
Helmut64 | 0:a3ea811f80f2 | 355 | if ( USBHAL_VbusIsOn() ) |
Helmut64 | 0:a3ea811f80f2 | 356 | { |
Helmut64 | 0:a3ea811f80f2 | 357 | USBD_SetUsbState( USBD_STATE_POWERED ); |
Helmut64 | 0:a3ea811f80f2 | 358 | } |
Helmut64 | 0:a3ea811f80f2 | 359 | else |
Helmut64 | 0:a3ea811f80f2 | 360 | #endif |
Helmut64 | 0:a3ea811f80f2 | 361 | { |
Helmut64 | 0:a3ea811f80f2 | 362 | USBD_SetUsbState( USBD_STATE_NONE ); |
Helmut64 | 0:a3ea811f80f2 | 363 | } |
Helmut64 | 0:a3ea811f80f2 | 364 | |
Helmut64 | 0:a3ea811f80f2 | 365 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 366 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 367 | } |
Helmut64 | 0:a3ea811f80f2 | 368 | |
Helmut64 | 0:a3ea811f80f2 | 369 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 370 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 371 | * Start a read (OUT) transfer on an endpoint. |
Helmut64 | 0:a3ea811f80f2 | 372 | * |
Helmut64 | 0:a3ea811f80f2 | 373 | * @note |
Helmut64 | 0:a3ea811f80f2 | 374 | * The transfer buffer length must be a multiple of 4 bytes in length and |
Helmut64 | 0:a3ea811f80f2 | 375 | * WORD (4 byte) aligned. When allocating the buffer, round buffer length up. |
Helmut64 | 0:a3ea811f80f2 | 376 | * If it is possible that the host will send more data than your device |
Helmut64 | 0:a3ea811f80f2 | 377 | * expects, round buffer size up to the next multiple of maxpacket size. |
Helmut64 | 0:a3ea811f80f2 | 378 | * |
Helmut64 | 0:a3ea811f80f2 | 379 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 380 | * Endpoint address. |
Helmut64 | 0:a3ea811f80f2 | 381 | * |
Helmut64 | 0:a3ea811f80f2 | 382 | * @param[in] data |
Helmut64 | 0:a3ea811f80f2 | 383 | * Pointer to transfer data buffer. |
Helmut64 | 0:a3ea811f80f2 | 384 | * |
Helmut64 | 0:a3ea811f80f2 | 385 | * @param[in] byteCount |
Helmut64 | 0:a3ea811f80f2 | 386 | * Transfer length. |
Helmut64 | 0:a3ea811f80f2 | 387 | * |
Helmut64 | 0:a3ea811f80f2 | 388 | * @param[in] callback |
Helmut64 | 0:a3ea811f80f2 | 389 | * Function to be called on transfer completion. Supply NULL if no callback |
Helmut64 | 0:a3ea811f80f2 | 390 | * is needed. See @ref USB_XferCompleteCb_TypeDef. |
Helmut64 | 0:a3ea811f80f2 | 391 | * |
Helmut64 | 0:a3ea811f80f2 | 392 | * @return |
Helmut64 | 0:a3ea811f80f2 | 393 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 394 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 395 | int USBD_Read( int epAddr, void *data, int byteCount, |
Helmut64 | 0:a3ea811f80f2 | 396 | USB_XferCompleteCb_TypeDef callback ) |
Helmut64 | 0:a3ea811f80f2 | 397 | { |
Helmut64 | 0:a3ea811f80f2 | 398 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 399 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 400 | |
Helmut64 | 0:a3ea811f80f2 | 401 | USB_PRINTF("USBD: Read addr %x, data %p, size %d, cb 0x%lx\n", |
Helmut64 | 0:a3ea811f80f2 | 402 | epAddr, data, byteCount, (uint32_t)callback); |
Helmut64 | 0:a3ea811f80f2 | 403 | |
Helmut64 | 0:a3ea811f80f2 | 404 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 405 | { |
Helmut64 | 0:a3ea811f80f2 | 406 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 407 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 408 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 409 | } |
Helmut64 | 0:a3ea811f80f2 | 410 | |
Helmut64 | 0:a3ea811f80f2 | 411 | if ( ( byteCount > MAX_XFER_LEN ) || |
Helmut64 | 0:a3ea811f80f2 | 412 | ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) ) |
Helmut64 | 0:a3ea811f80f2 | 413 | { |
Helmut64 | 0:a3ea811f80f2 | 414 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal transfer size" ); |
Helmut64 | 0:a3ea811f80f2 | 415 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 416 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 417 | } |
Helmut64 | 0:a3ea811f80f2 | 418 | |
Helmut64 | 0:a3ea811f80f2 | 419 | if ( (uint32_t)data & 3 ) |
Helmut64 | 0:a3ea811f80f2 | 420 | { |
Helmut64 | 0:a3ea811f80f2 | 421 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Misaligned data buffer" ); |
Helmut64 | 0:a3ea811f80f2 | 422 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 423 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 424 | } |
Helmut64 | 0:a3ea811f80f2 | 425 | |
Helmut64 | 0:a3ea811f80f2 | 426 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 427 | |
Helmut64 | 0:a3ea811f80f2 | 428 | if ( USBDHAL_EpIsStalled( ep ) ) |
Helmut64 | 0:a3ea811f80f2 | 429 | { |
Helmut64 | 0:a3ea811f80f2 | 430 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 431 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is halted" ); |
Helmut64 | 0:a3ea811f80f2 | 432 | return USB_STATUS_EP_STALLED; |
Helmut64 | 0:a3ea811f80f2 | 433 | } |
Helmut64 | 0:a3ea811f80f2 | 434 | |
Helmut64 | 0:a3ea811f80f2 | 435 | if ( ep->state != D_EP_IDLE ) |
Helmut64 | 0:a3ea811f80f2 | 436 | { |
Helmut64 | 0:a3ea811f80f2 | 437 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 438 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is busy" ); |
Helmut64 | 0:a3ea811f80f2 | 439 | return USB_STATUS_EP_BUSY; |
Helmut64 | 0:a3ea811f80f2 | 440 | } |
Helmut64 | 0:a3ea811f80f2 | 441 | |
Helmut64 | 0:a3ea811f80f2 | 442 | if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) ) |
Helmut64 | 0:a3ea811f80f2 | 443 | { |
Helmut64 | 0:a3ea811f80f2 | 444 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 445 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Device not configured" ); |
Helmut64 | 0:a3ea811f80f2 | 446 | return USB_STATUS_DEVICE_UNCONFIGURED; |
Helmut64 | 0:a3ea811f80f2 | 447 | } |
Helmut64 | 0:a3ea811f80f2 | 448 | |
Helmut64 | 0:a3ea811f80f2 | 449 | ep->buf = (uint8_t*)data; |
Helmut64 | 0:a3ea811f80f2 | 450 | ep->remaining = byteCount; |
Helmut64 | 0:a3ea811f80f2 | 451 | ep->xferred = 0; |
Helmut64 | 0:a3ea811f80f2 | 452 | |
Helmut64 | 0:a3ea811f80f2 | 453 | if ( ep->num == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 454 | { |
Helmut64 | 0:a3ea811f80f2 | 455 | ep->in = false; |
Helmut64 | 0:a3ea811f80f2 | 456 | } |
Helmut64 | 0:a3ea811f80f2 | 457 | else if ( ep->in != false ) |
Helmut64 | 0:a3ea811f80f2 | 458 | { |
Helmut64 | 0:a3ea811f80f2 | 459 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 460 | DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal EP direction" ); |
Helmut64 | 0:a3ea811f80f2 | 461 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 462 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 463 | } |
Helmut64 | 0:a3ea811f80f2 | 464 | |
Helmut64 | 0:a3ea811f80f2 | 465 | ep->state = D_EP_RECEIVING; |
Helmut64 | 0:a3ea811f80f2 | 466 | ep->xferCompleteCb = callback; |
Helmut64 | 0:a3ea811f80f2 | 467 | |
Helmut64 | 0:a3ea811f80f2 | 468 | USBD_ArmEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 469 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 470 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 471 | } |
Helmut64 | 0:a3ea811f80f2 | 472 | |
Helmut64 | 0:a3ea811f80f2 | 473 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 474 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 475 | * Perform a remote wakeup signalling sequence. |
Helmut64 | 0:a3ea811f80f2 | 476 | * |
Helmut64 | 0:a3ea811f80f2 | 477 | * @note |
Helmut64 | 0:a3ea811f80f2 | 478 | * It is the responsibility of the application to ensure that remote wakeup |
Helmut64 | 0:a3ea811f80f2 | 479 | * is not attempted before the device has been suspended for at least 5 |
Helmut64 | 0:a3ea811f80f2 | 480 | * miliseconds. This function should not be called from within an interrupt |
Helmut64 | 0:a3ea811f80f2 | 481 | * handler. |
Helmut64 | 0:a3ea811f80f2 | 482 | * |
Helmut64 | 0:a3ea811f80f2 | 483 | * @return |
Helmut64 | 0:a3ea811f80f2 | 484 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 485 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 486 | int USBD_RemoteWakeup( void ) |
Helmut64 | 0:a3ea811f80f2 | 487 | { |
Helmut64 | 0:a3ea811f80f2 | 488 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 489 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 490 | |
Helmut64 | 0:a3ea811f80f2 | 491 | if ( ( dev->state != USBD_STATE_SUSPENDED ) || |
Helmut64 | 0:a3ea811f80f2 | 492 | ( dev->remoteWakeupEnabled == false ) ) |
Helmut64 | 0:a3ea811f80f2 | 493 | { |
Helmut64 | 0:a3ea811f80f2 | 494 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 495 | DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" ); |
Helmut64 | 0:a3ea811f80f2 | 496 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 497 | } |
Helmut64 | 0:a3ea811f80f2 | 498 | |
Helmut64 | 0:a3ea811f80f2 | 499 | USBDHAL_SetRemoteWakeup(); |
Helmut64 | 0:a3ea811f80f2 | 500 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 501 | |
Helmut64 | 0:a3ea811f80f2 | 502 | USBTIMER_DelayMs( 10 ); |
Helmut64 | 0:a3ea811f80f2 | 503 | |
Helmut64 | 0:a3ea811f80f2 | 504 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 505 | USBDHAL_ClearRemoteWakeup(); |
Helmut64 | 0:a3ea811f80f2 | 506 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 507 | |
Helmut64 | 0:a3ea811f80f2 | 508 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 509 | } |
Helmut64 | 0:a3ea811f80f2 | 510 | |
Helmut64 | 0:a3ea811f80f2 | 511 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 512 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 513 | * Check if it is ok to enter energy mode EM2. |
Helmut64 | 0:a3ea811f80f2 | 514 | * |
Helmut64 | 0:a3ea811f80f2 | 515 | * @note |
Helmut64 | 0:a3ea811f80f2 | 516 | * Before entering EM2 both the USB hardware and the USB stack must be in a |
Helmut64 | 0:a3ea811f80f2 | 517 | * certain state, this function checks if all conditions for entering EM2 |
Helmut64 | 0:a3ea811f80f2 | 518 | * is met. |
Helmut64 | 0:a3ea811f80f2 | 519 | * Refer to the @ref usb_device_powersave section for more information. |
Helmut64 | 0:a3ea811f80f2 | 520 | * |
Helmut64 | 0:a3ea811f80f2 | 521 | * @return |
Helmut64 | 0:a3ea811f80f2 | 522 | * True if ok to enter EM2, false otherwise. |
Helmut64 | 0:a3ea811f80f2 | 523 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 524 | bool USBD_SafeToEnterEM2( void ) |
Helmut64 | 0:a3ea811f80f2 | 525 | { |
Helmut64 | 0:a3ea811f80f2 | 526 | #if ( USB_PWRSAVE_MODE ) |
Helmut64 | 0:a3ea811f80f2 | 527 | return USBD_poweredDown ? true : false; |
Helmut64 | 0:a3ea811f80f2 | 528 | #else |
Helmut64 | 0:a3ea811f80f2 | 529 | return false; |
Helmut64 | 0:a3ea811f80f2 | 530 | #endif |
Helmut64 | 0:a3ea811f80f2 | 531 | } |
Helmut64 | 0:a3ea811f80f2 | 532 | |
Helmut64 | 0:a3ea811f80f2 | 533 | /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ |
Helmut64 | 0:a3ea811f80f2 | 534 | |
Helmut64 | 0:a3ea811f80f2 | 535 | void USBD_SetUsbState( USBD_State_TypeDef newState ) |
Helmut64 | 0:a3ea811f80f2 | 536 | { |
Helmut64 | 0:a3ea811f80f2 | 537 | USBD_State_TypeDef currentState; |
Helmut64 | 0:a3ea811f80f2 | 538 | |
Helmut64 | 0:a3ea811f80f2 | 539 | currentState = dev->state; |
Helmut64 | 0:a3ea811f80f2 | 540 | if ( newState == USBD_STATE_SUSPENDED ) |
Helmut64 | 0:a3ea811f80f2 | 541 | { |
Helmut64 | 0:a3ea811f80f2 | 542 | dev->savedState = currentState; |
Helmut64 | 0:a3ea811f80f2 | 543 | } |
Helmut64 | 0:a3ea811f80f2 | 544 | |
Helmut64 | 0:a3ea811f80f2 | 545 | dev->lastState = dev->state; |
Helmut64 | 0:a3ea811f80f2 | 546 | dev->state = newState; |
Helmut64 | 0:a3ea811f80f2 | 547 | |
Helmut64 | 0:a3ea811f80f2 | 548 | if ( ( dev->callbacks->usbStateChange ) && |
Helmut64 | 0:a3ea811f80f2 | 549 | ( currentState != newState ) ) |
Helmut64 | 0:a3ea811f80f2 | 550 | { |
Helmut64 | 0:a3ea811f80f2 | 551 | /* When we transition to a state "lower" than CONFIGURED |
Helmut64 | 0:a3ea811f80f2 | 552 | * we must reset the endpoint data |
Helmut64 | 0:a3ea811f80f2 | 553 | */ |
Helmut64 | 0:a3ea811f80f2 | 554 | if ( (dev->lastState == USBD_STATE_CONFIGURED || |
Helmut64 | 0:a3ea811f80f2 | 555 | dev->lastState == USBD_STATE_SUSPENDED ) && |
Helmut64 | 0:a3ea811f80f2 | 556 | dev->state < USBD_STATE_CONFIGURED ) |
Helmut64 | 0:a3ea811f80f2 | 557 | { |
Helmut64 | 0:a3ea811f80f2 | 558 | USBD_ResetEndpoints(); |
Helmut64 | 0:a3ea811f80f2 | 559 | } |
Helmut64 | 0:a3ea811f80f2 | 560 | |
Helmut64 | 0:a3ea811f80f2 | 561 | dev->callbacks->usbStateChange( currentState, newState ); |
Helmut64 | 0:a3ea811f80f2 | 562 | } |
Helmut64 | 0:a3ea811f80f2 | 563 | } |
Helmut64 | 0:a3ea811f80f2 | 564 | |
Helmut64 | 0:a3ea811f80f2 | 565 | /** @endcond */ |
Helmut64 | 0:a3ea811f80f2 | 566 | |
Helmut64 | 0:a3ea811f80f2 | 567 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 568 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 569 | * Set an endpoint in the stalled (halted) state. |
Helmut64 | 0:a3ea811f80f2 | 570 | * |
Helmut64 | 0:a3ea811f80f2 | 571 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 572 | * The address of the endpoint to stall. |
Helmut64 | 0:a3ea811f80f2 | 573 | * |
Helmut64 | 0:a3ea811f80f2 | 574 | * @return |
Helmut64 | 0:a3ea811f80f2 | 575 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 576 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 577 | int USBD_StallEp( int epAddr ) |
Helmut64 | 0:a3ea811f80f2 | 578 | { |
Helmut64 | 0:a3ea811f80f2 | 579 | USB_Status_TypeDef retVal; |
Helmut64 | 0:a3ea811f80f2 | 580 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 581 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 582 | |
Helmut64 | 0:a3ea811f80f2 | 583 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 584 | { |
Helmut64 | 0:a3ea811f80f2 | 585 | DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal request" ); |
Helmut64 | 0:a3ea811f80f2 | 586 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 587 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 588 | } |
Helmut64 | 0:a3ea811f80f2 | 589 | |
Helmut64 | 0:a3ea811f80f2 | 590 | if ( ep->num == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 591 | { |
Helmut64 | 0:a3ea811f80f2 | 592 | DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 593 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 594 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 595 | } |
Helmut64 | 0:a3ea811f80f2 | 596 | |
Helmut64 | 0:a3ea811f80f2 | 597 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 598 | retVal = USBDHAL_StallEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 599 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 600 | |
Helmut64 | 0:a3ea811f80f2 | 601 | if ( retVal != USB_STATUS_OK ) |
Helmut64 | 0:a3ea811f80f2 | 602 | { |
Helmut64 | 0:a3ea811f80f2 | 603 | retVal = USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 604 | } |
Helmut64 | 0:a3ea811f80f2 | 605 | |
Helmut64 | 0:a3ea811f80f2 | 606 | return retVal; |
Helmut64 | 0:a3ea811f80f2 | 607 | } |
Helmut64 | 0:a3ea811f80f2 | 608 | |
Helmut64 | 0:a3ea811f80f2 | 609 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 610 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 611 | * Stop USB device stack operation. |
Helmut64 | 0:a3ea811f80f2 | 612 | * |
Helmut64 | 0:a3ea811f80f2 | 613 | * @details |
Helmut64 | 0:a3ea811f80f2 | 614 | * The data-line pullup resistor is turned off, USB interrupts are disabled, |
Helmut64 | 0:a3ea811f80f2 | 615 | * and finally the USB pins are disabled. |
Helmut64 | 0:a3ea811f80f2 | 616 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 617 | void USBD_Stop( void ) |
Helmut64 | 0:a3ea811f80f2 | 618 | { |
Helmut64 | 0:a3ea811f80f2 | 619 | USBD_Disconnect(); |
Helmut64 | 0:a3ea811f80f2 | 620 | NVIC_DisableIRQ( USB_IRQn ); |
Helmut64 | 0:a3ea811f80f2 | 621 | USBHAL_DisableGlobalInt(); |
Helmut64 | 0:a3ea811f80f2 | 622 | USBHAL_DisableUsbInt(); |
Helmut64 | 0:a3ea811f80f2 | 623 | USBHAL_DisablePhyPins(); |
Helmut64 | 0:a3ea811f80f2 | 624 | USBD_SetUsbState( USBD_STATE_NONE ); |
Helmut64 | 0:a3ea811f80f2 | 625 | /* Turn off USB clocks. */ |
Helmut64 | 0:a3ea811f80f2 | 626 | CMU->HFCORECLKEN0 &= ~(CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC); |
Helmut64 | 0:a3ea811f80f2 | 627 | } |
Helmut64 | 0:a3ea811f80f2 | 628 | |
Helmut64 | 0:a3ea811f80f2 | 629 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 630 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 631 | * Reset stall state on a stalled (halted) endpoint. |
Helmut64 | 0:a3ea811f80f2 | 632 | * |
Helmut64 | 0:a3ea811f80f2 | 633 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 634 | * The address of the endpoint to un-stall. |
Helmut64 | 0:a3ea811f80f2 | 635 | * |
Helmut64 | 0:a3ea811f80f2 | 636 | * @return |
Helmut64 | 0:a3ea811f80f2 | 637 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 638 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 639 | int USBD_UnStallEp( int epAddr ) |
Helmut64 | 0:a3ea811f80f2 | 640 | { |
Helmut64 | 0:a3ea811f80f2 | 641 | USB_Status_TypeDef retVal; |
Helmut64 | 0:a3ea811f80f2 | 642 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 643 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 644 | |
Helmut64 | 0:a3ea811f80f2 | 645 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 646 | { |
Helmut64 | 0:a3ea811f80f2 | 647 | DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" ); |
Helmut64 | 0:a3ea811f80f2 | 648 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 649 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 650 | } |
Helmut64 | 0:a3ea811f80f2 | 651 | |
Helmut64 | 0:a3ea811f80f2 | 652 | if ( ep->num == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 653 | { |
Helmut64 | 0:a3ea811f80f2 | 654 | DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 655 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 656 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 657 | } |
Helmut64 | 0:a3ea811f80f2 | 658 | |
Helmut64 | 0:a3ea811f80f2 | 659 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 660 | retVal = USBDHAL_UnStallEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 661 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 662 | |
Helmut64 | 0:a3ea811f80f2 | 663 | if ( retVal != USB_STATUS_OK ) |
Helmut64 | 0:a3ea811f80f2 | 664 | { |
Helmut64 | 0:a3ea811f80f2 | 665 | retVal = USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 666 | } |
Helmut64 | 0:a3ea811f80f2 | 667 | |
Helmut64 | 0:a3ea811f80f2 | 668 | return retVal; |
Helmut64 | 0:a3ea811f80f2 | 669 | } |
Helmut64 | 0:a3ea811f80f2 | 670 | |
Helmut64 | 0:a3ea811f80f2 | 671 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 672 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 673 | * Start a write (IN) transfer on an endpoint. |
Helmut64 | 0:a3ea811f80f2 | 674 | * |
Helmut64 | 0:a3ea811f80f2 | 675 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 676 | * Endpoint address. |
Helmut64 | 0:a3ea811f80f2 | 677 | * |
Helmut64 | 0:a3ea811f80f2 | 678 | * @param[in] data |
Helmut64 | 0:a3ea811f80f2 | 679 | * Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned. |
Helmut64 | 0:a3ea811f80f2 | 680 | * |
Helmut64 | 0:a3ea811f80f2 | 681 | * @param[in] byteCount |
Helmut64 | 0:a3ea811f80f2 | 682 | * Transfer length. |
Helmut64 | 0:a3ea811f80f2 | 683 | * |
Helmut64 | 0:a3ea811f80f2 | 684 | * @param[in] callback |
Helmut64 | 0:a3ea811f80f2 | 685 | * Function to be called on transfer completion. Supply NULL if no callback |
Helmut64 | 0:a3ea811f80f2 | 686 | * is needed. See @ref USB_XferCompleteCb_TypeDef. |
Helmut64 | 0:a3ea811f80f2 | 687 | * |
Helmut64 | 0:a3ea811f80f2 | 688 | * @return |
Helmut64 | 0:a3ea811f80f2 | 689 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 690 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 691 | int USBD_Write( int epAddr, void *data, int byteCount, |
Helmut64 | 0:a3ea811f80f2 | 692 | USB_XferCompleteCb_TypeDef callback ) |
Helmut64 | 0:a3ea811f80f2 | 693 | { |
Helmut64 | 0:a3ea811f80f2 | 694 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 695 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 696 | |
Helmut64 | 0:a3ea811f80f2 | 697 | USB_PRINTF("USBD: Write addr %x, data %p, size %d, cb 0x%lx\n", |
Helmut64 | 0:a3ea811f80f2 | 698 | epAddr, data, byteCount, (uint32_t)callback); |
Helmut64 | 0:a3ea811f80f2 | 699 | |
Helmut64 | 0:a3ea811f80f2 | 700 | if ( ep == NULL ) |
Helmut64 | 0:a3ea811f80f2 | 701 | { |
Helmut64 | 0:a3ea811f80f2 | 702 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal endpoint" ); |
Helmut64 | 0:a3ea811f80f2 | 703 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 704 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 705 | } |
Helmut64 | 0:a3ea811f80f2 | 706 | |
Helmut64 | 0:a3ea811f80f2 | 707 | if ( ( byteCount > MAX_XFER_LEN ) || |
Helmut64 | 0:a3ea811f80f2 | 708 | ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) ) |
Helmut64 | 0:a3ea811f80f2 | 709 | { |
Helmut64 | 0:a3ea811f80f2 | 710 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal transfer size" ); |
Helmut64 | 0:a3ea811f80f2 | 711 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 712 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 713 | } |
Helmut64 | 0:a3ea811f80f2 | 714 | |
Helmut64 | 0:a3ea811f80f2 | 715 | if ( (uint32_t)data & 3 ) |
Helmut64 | 0:a3ea811f80f2 | 716 | { |
Helmut64 | 0:a3ea811f80f2 | 717 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Misaligned data buffer" ); |
Helmut64 | 0:a3ea811f80f2 | 718 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 719 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 720 | } |
Helmut64 | 0:a3ea811f80f2 | 721 | |
Helmut64 | 0:a3ea811f80f2 | 722 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 723 | |
Helmut64 | 0:a3ea811f80f2 | 724 | if ( USBDHAL_EpIsStalled( ep ) ) |
Helmut64 | 0:a3ea811f80f2 | 725 | { |
Helmut64 | 0:a3ea811f80f2 | 726 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 727 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is halted" ); |
Helmut64 | 0:a3ea811f80f2 | 728 | return USB_STATUS_EP_STALLED; |
Helmut64 | 0:a3ea811f80f2 | 729 | } |
Helmut64 | 0:a3ea811f80f2 | 730 | |
Helmut64 | 0:a3ea811f80f2 | 731 | if ( ep->state != D_EP_IDLE ) |
Helmut64 | 0:a3ea811f80f2 | 732 | { |
Helmut64 | 0:a3ea811f80f2 | 733 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 734 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is busy" ); |
Helmut64 | 0:a3ea811f80f2 | 735 | return USB_STATUS_EP_BUSY; |
Helmut64 | 0:a3ea811f80f2 | 736 | } |
Helmut64 | 0:a3ea811f80f2 | 737 | |
Helmut64 | 0:a3ea811f80f2 | 738 | if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) ) |
Helmut64 | 0:a3ea811f80f2 | 739 | { |
Helmut64 | 0:a3ea811f80f2 | 740 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 741 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Device not configured" ); |
Helmut64 | 0:a3ea811f80f2 | 742 | return USB_STATUS_DEVICE_UNCONFIGURED; |
Helmut64 | 0:a3ea811f80f2 | 743 | } |
Helmut64 | 0:a3ea811f80f2 | 744 | |
Helmut64 | 0:a3ea811f80f2 | 745 | ep->buf = (uint8_t*)data; |
Helmut64 | 0:a3ea811f80f2 | 746 | ep->remaining = byteCount; |
Helmut64 | 0:a3ea811f80f2 | 747 | ep->xferred = 0; |
Helmut64 | 0:a3ea811f80f2 | 748 | |
Helmut64 | 0:a3ea811f80f2 | 749 | if ( ep->num == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 750 | { |
Helmut64 | 0:a3ea811f80f2 | 751 | ep->in = true; |
Helmut64 | 0:a3ea811f80f2 | 752 | } |
Helmut64 | 0:a3ea811f80f2 | 753 | else if ( ep->in != true ) |
Helmut64 | 0:a3ea811f80f2 | 754 | { |
Helmut64 | 0:a3ea811f80f2 | 755 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 756 | DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal EP direction" ); |
Helmut64 | 0:a3ea811f80f2 | 757 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 758 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 759 | } |
Helmut64 | 0:a3ea811f80f2 | 760 | |
Helmut64 | 0:a3ea811f80f2 | 761 | ep->state = D_EP_TRANSMITTING; |
Helmut64 | 0:a3ea811f80f2 | 762 | ep->xferCompleteCb = callback; |
Helmut64 | 0:a3ea811f80f2 | 763 | |
Helmut64 | 0:a3ea811f80f2 | 764 | USBD_ArmEp( ep ); |
Helmut64 | 0:a3ea811f80f2 | 765 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 766 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 767 | } |
Helmut64 | 0:a3ea811f80f2 | 768 | |
Helmut64 | 0:a3ea811f80f2 | 769 | int USBD_SetAddress(uint8_t addr) |
Helmut64 | 0:a3ea811f80f2 | 770 | { |
Helmut64 | 0:a3ea811f80f2 | 771 | int retVal = USB_STATUS_REQ_ERR; |
Helmut64 | 0:a3ea811f80f2 | 772 | |
Helmut64 | 0:a3ea811f80f2 | 773 | if ( dev->state == USBD_STATE_DEFAULT ) |
Helmut64 | 0:a3ea811f80f2 | 774 | { |
Helmut64 | 0:a3ea811f80f2 | 775 | if ( addr != 0 ) |
Helmut64 | 0:a3ea811f80f2 | 776 | { |
Helmut64 | 0:a3ea811f80f2 | 777 | USBD_SetUsbState( USBD_STATE_ADDRESSED ); |
Helmut64 | 0:a3ea811f80f2 | 778 | } |
Helmut64 | 0:a3ea811f80f2 | 779 | USBDHAL_SetAddr( addr ); |
Helmut64 | 0:a3ea811f80f2 | 780 | retVal = USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 781 | } |
Helmut64 | 0:a3ea811f80f2 | 782 | else if ( dev->state == USBD_STATE_ADDRESSED ) |
Helmut64 | 0:a3ea811f80f2 | 783 | { |
Helmut64 | 0:a3ea811f80f2 | 784 | if ( addr == 0 ) |
Helmut64 | 0:a3ea811f80f2 | 785 | { |
Helmut64 | 0:a3ea811f80f2 | 786 | USBD_SetUsbState( USBD_STATE_DEFAULT ); |
Helmut64 | 0:a3ea811f80f2 | 787 | } |
Helmut64 | 0:a3ea811f80f2 | 788 | USBDHAL_SetAddr( addr ); |
Helmut64 | 0:a3ea811f80f2 | 789 | retVal = USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 790 | } |
Helmut64 | 0:a3ea811f80f2 | 791 | |
Helmut64 | 0:a3ea811f80f2 | 792 | return retVal; |
Helmut64 | 0:a3ea811f80f2 | 793 | } |
Helmut64 | 0:a3ea811f80f2 | 794 | |
Helmut64 | 0:a3ea811f80f2 | 795 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 796 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 797 | * Query the stall state of an endpoint |
Helmut64 | 0:a3ea811f80f2 | 798 | * |
Helmut64 | 0:a3ea811f80f2 | 799 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 800 | * The address of the endpoint to query. |
Helmut64 | 0:a3ea811f80f2 | 801 | * |
Helmut64 | 0:a3ea811f80f2 | 802 | * @return |
Helmut64 | 0:a3ea811f80f2 | 803 | * True if endpoint is stalled, false otherwise |
Helmut64 | 0:a3ea811f80f2 | 804 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 805 | int USBD_EpIsStalled(int epAddr) |
Helmut64 | 0:a3ea811f80f2 | 806 | { |
Helmut64 | 0:a3ea811f80f2 | 807 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 808 | |
Helmut64 | 0:a3ea811f80f2 | 809 | if( !ep ) |
Helmut64 | 0:a3ea811f80f2 | 810 | { |
Helmut64 | 0:a3ea811f80f2 | 811 | return false; |
Helmut64 | 0:a3ea811f80f2 | 812 | } |
Helmut64 | 0:a3ea811f80f2 | 813 | |
Helmut64 | 0:a3ea811f80f2 | 814 | return USBDHAL_EpIsStalled(ep); |
Helmut64 | 0:a3ea811f80f2 | 815 | } |
Helmut64 | 0:a3ea811f80f2 | 816 | |
Helmut64 | 0:a3ea811f80f2 | 817 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 818 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 819 | * Reset (remove) all client endpoints |
Helmut64 | 0:a3ea811f80f2 | 820 | * |
Helmut64 | 0:a3ea811f80f2 | 821 | * @details |
Helmut64 | 0:a3ea811f80f2 | 822 | * Removes client endpoints, and resets the RX/TX fifos. No endpoints |
Helmut64 | 0:a3ea811f80f2 | 823 | * other than EP0 can be used until added with @ref USBD_AddEndpoint. |
Helmut64 | 0:a3ea811f80f2 | 824 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 825 | static void USBD_ResetEndpoints(void) |
Helmut64 | 0:a3ea811f80f2 | 826 | { |
Helmut64 | 0:a3ea811f80f2 | 827 | USBD_Ep_TypeDef *ep = &dev->ep[0]; |
Helmut64 | 0:a3ea811f80f2 | 828 | |
Helmut64 | 0:a3ea811f80f2 | 829 | numEps = 0; |
Helmut64 | 0:a3ea811f80f2 | 830 | txFifoNum = 1; |
Helmut64 | 0:a3ea811f80f2 | 831 | |
Helmut64 | 0:a3ea811f80f2 | 832 | totalTxFifoSize = ep->fifoSize * 1; |
Helmut64 | 0:a3ea811f80f2 | 833 | totalRxFifoSize = (ep->fifoSize + 1) * 1; |
Helmut64 | 0:a3ea811f80f2 | 834 | totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) ); |
Helmut64 | 0:a3ea811f80f2 | 835 | } |
Helmut64 | 0:a3ea811f80f2 | 836 | |
Helmut64 | 0:a3ea811f80f2 | 837 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 838 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 839 | * Add a new endpoint |
Helmut64 | 0:a3ea811f80f2 | 840 | * |
Helmut64 | 0:a3ea811f80f2 | 841 | * @param[in] epAddr |
Helmut64 | 0:a3ea811f80f2 | 842 | * Endpoint address |
Helmut64 | 0:a3ea811f80f2 | 843 | * |
Helmut64 | 0:a3ea811f80f2 | 844 | * @param[in] transferType |
Helmut64 | 0:a3ea811f80f2 | 845 | * Endpoint type, one of @ref USB_EPTYPE_BULK, @ref USB_EPTYPE_INTR or |
Helmut64 | 0:a3ea811f80f2 | 846 | * @ref USB_EPTYPE_ISOC. |
Helmut64 | 0:a3ea811f80f2 | 847 | * |
Helmut64 | 0:a3ea811f80f2 | 848 | * @param[in] maxPacketSize |
Helmut64 | 0:a3ea811f80f2 | 849 | * Maximum packet size of the new endpoint, in bytes |
Helmut64 | 0:a3ea811f80f2 | 850 | * |
Helmut64 | 0:a3ea811f80f2 | 851 | * @param[in] bufferMult |
Helmut64 | 0:a3ea811f80f2 | 852 | * FIFO buffer size multiplier |
Helmut64 | 0:a3ea811f80f2 | 853 | * |
Helmut64 | 0:a3ea811f80f2 | 854 | * @return |
Helmut64 | 0:a3ea811f80f2 | 855 | * @ref USB_STATUS_OK on success, else an appropriate error code. |
Helmut64 | 0:a3ea811f80f2 | 856 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 857 | int USBD_AddEndpoint(int epAddr, int transferType, |
Helmut64 | 0:a3ea811f80f2 | 858 | int maxPacketSize, int bufferMult) |
Helmut64 | 0:a3ea811f80f2 | 859 | { |
Helmut64 | 0:a3ea811f80f2 | 860 | CORE_DECLARE_IRQ_STATE; |
Helmut64 | 0:a3ea811f80f2 | 861 | USBD_Ep_TypeDef *ep; |
Helmut64 | 0:a3ea811f80f2 | 862 | |
Helmut64 | 0:a3ea811f80f2 | 863 | numEps++; |
Helmut64 | 0:a3ea811f80f2 | 864 | |
Helmut64 | 0:a3ea811f80f2 | 865 | ep = &dev->ep[ numEps ]; |
Helmut64 | 0:a3ea811f80f2 | 866 | ep->in = ( epAddr & USB_SETUP_DIR_MASK ) != 0; |
Helmut64 | 0:a3ea811f80f2 | 867 | ep->buf = NULL; |
Helmut64 | 0:a3ea811f80f2 | 868 | ep->addr = epAddr; |
Helmut64 | 0:a3ea811f80f2 | 869 | ep->num = ep->addr & USB_EPNUM_MASK; |
Helmut64 | 0:a3ea811f80f2 | 870 | ep->mask = 1 << ep->num; |
Helmut64 | 0:a3ea811f80f2 | 871 | ep->type = transferType; |
Helmut64 | 0:a3ea811f80f2 | 872 | ep->packetSize = maxPacketSize; |
Helmut64 | 0:a3ea811f80f2 | 873 | ep->remaining = 0; |
Helmut64 | 0:a3ea811f80f2 | 874 | ep->xferred = 0; |
Helmut64 | 0:a3ea811f80f2 | 875 | ep->state = D_EP_IDLE; |
Helmut64 | 0:a3ea811f80f2 | 876 | ep->xferCompleteCb = NULL; |
Helmut64 | 0:a3ea811f80f2 | 877 | |
Helmut64 | 0:a3ea811f80f2 | 878 | if ( ep->in ) |
Helmut64 | 0:a3ea811f80f2 | 879 | { |
Helmut64 | 0:a3ea811f80f2 | 880 | ep->txFifoNum = txFifoNum++; |
Helmut64 | 0:a3ea811f80f2 | 881 | ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 ) * bufferMult; |
Helmut64 | 0:a3ea811f80f2 | 882 | dev->inEpAddr2EpIndex[ ep->num ] = numEps; |
Helmut64 | 0:a3ea811f80f2 | 883 | totalTxFifoSize += ep->fifoSize; |
Helmut64 | 0:a3ea811f80f2 | 884 | |
Helmut64 | 0:a3ea811f80f2 | 885 | if ( ep->num > MAX_NUM_IN_EPS ) |
Helmut64 | 0:a3ea811f80f2 | 886 | { |
Helmut64 | 0:a3ea811f80f2 | 887 | DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal IN EP address" ); |
Helmut64 | 0:a3ea811f80f2 | 888 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 889 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 890 | } |
Helmut64 | 0:a3ea811f80f2 | 891 | } |
Helmut64 | 0:a3ea811f80f2 | 892 | else |
Helmut64 | 0:a3ea811f80f2 | 893 | { |
Helmut64 | 0:a3ea811f80f2 | 894 | ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 ) * bufferMult; |
Helmut64 | 0:a3ea811f80f2 | 895 | dev->outEpAddr2EpIndex[ ep->num ] = numEps; |
Helmut64 | 0:a3ea811f80f2 | 896 | totalRxFifoSize += ep->fifoSize; |
Helmut64 | 0:a3ea811f80f2 | 897 | |
Helmut64 | 0:a3ea811f80f2 | 898 | if ( ep->num > MAX_NUM_OUT_EPS ) |
Helmut64 | 0:a3ea811f80f2 | 899 | { |
Helmut64 | 0:a3ea811f80f2 | 900 | DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal OUT EP address" ); |
Helmut64 | 0:a3ea811f80f2 | 901 | EFM_ASSERT( false ); |
Helmut64 | 0:a3ea811f80f2 | 902 | return USB_STATUS_ILLEGAL; |
Helmut64 | 0:a3ea811f80f2 | 903 | } |
Helmut64 | 0:a3ea811f80f2 | 904 | } |
Helmut64 | 0:a3ea811f80f2 | 905 | |
Helmut64 | 0:a3ea811f80f2 | 906 | USB_PRINTF("USBD: Added endpoint %d to slot %d, in %d, addr 0x%x, type %d, ps %d, fifo %ld (total tx %ld, rx %ld)\n", |
Helmut64 | 0:a3ea811f80f2 | 907 | ep->num, numEps, ep->in, ep->addr, ep->type, ep->packetSize, ep->fifoSize, |
Helmut64 | 0:a3ea811f80f2 | 908 | totalTxFifoSize, totalRxFifoSize); |
Helmut64 | 0:a3ea811f80f2 | 909 | |
Helmut64 | 0:a3ea811f80f2 | 910 | CORE_ENTER_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 911 | #if defined( CMU_OSCENCMD_USHFRCOEN ) |
Helmut64 | 0:a3ea811f80f2 | 912 | /* Happy Gecko workaround: disable LEM GATE mode if using ISOC endpoints. */ |
Helmut64 | 0:a3ea811f80f2 | 913 | if ( transferType == USB_EPTYPE_ISOC ) |
Helmut64 | 0:a3ea811f80f2 | 914 | { |
Helmut64 | 0:a3ea811f80f2 | 915 | USB->CTRL = (USB->CTRL & ~_USB_CTRL_LEMOSCCTRL_MASK) | USB_CTRL_LEMOSCCTRL_NONE; |
Helmut64 | 0:a3ea811f80f2 | 916 | } |
Helmut64 | 0:a3ea811f80f2 | 917 | #endif |
Helmut64 | 0:a3ea811f80f2 | 918 | |
Helmut64 | 0:a3ea811f80f2 | 919 | int ret = USBDHAL_ReconfigureFifos(totalRxFifoSize, totalTxFifoSize); |
Helmut64 | 0:a3ea811f80f2 | 920 | CORE_EXIT_CRITICAL(); |
Helmut64 | 0:a3ea811f80f2 | 921 | |
Helmut64 | 0:a3ea811f80f2 | 922 | if( ret != USB_STATUS_OK ) { |
Helmut64 | 0:a3ea811f80f2 | 923 | return ret; |
Helmut64 | 0:a3ea811f80f2 | 924 | } |
Helmut64 | 0:a3ea811f80f2 | 925 | |
Helmut64 | 0:a3ea811f80f2 | 926 | USBDHAL_ActivateEp(ep, false); |
Helmut64 | 0:a3ea811f80f2 | 927 | |
Helmut64 | 0:a3ea811f80f2 | 928 | return USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 929 | } |
Helmut64 | 0:a3ea811f80f2 | 930 | |
Helmut64 | 0:a3ea811f80f2 | 931 | |
Helmut64 | 0:a3ea811f80f2 | 932 | /***************************************************************************//** |
Helmut64 | 0:a3ea811f80f2 | 933 | * @brief |
Helmut64 | 0:a3ea811f80f2 | 934 | * Set an endpoint0 in the stalled (halted) state. |
Helmut64 | 0:a3ea811f80f2 | 935 | * |
Helmut64 | 0:a3ea811f80f2 | 936 | * @details |
Helmut64 | 0:a3ea811f80f2 | 937 | * Temporarily stalls endpoint 0. Used to signal a failure to respond to |
Helmut64 | 0:a3ea811f80f2 | 938 | * the host's setup packet. |
Helmut64 | 0:a3ea811f80f2 | 939 | ******************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 940 | void USBD_StallEp0() |
Helmut64 | 0:a3ea811f80f2 | 941 | { |
Helmut64 | 0:a3ea811f80f2 | 942 | int const epAddr = 0; |
Helmut64 | 0:a3ea811f80f2 | 943 | USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); |
Helmut64 | 0:a3ea811f80f2 | 944 | ep->in = true; |
Helmut64 | 0:a3ea811f80f2 | 945 | USBDHAL_StallEp( ep ); /* Stall Ep0 IN */ |
Helmut64 | 0:a3ea811f80f2 | 946 | ep->in = false; /* OUT for next SETUP */ |
Helmut64 | 0:a3ea811f80f2 | 947 | USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */ |
Helmut64 | 0:a3ea811f80f2 | 948 | #if !defined( USB_DOEP0INT_STUPPKTRCVD ) |
Helmut64 | 0:a3ea811f80f2 | 949 | USBDHAL_ReenableEp0Setup( dev ); /* Prepare for next SETUP pkt. */ |
Helmut64 | 0:a3ea811f80f2 | 950 | #else |
Helmut64 | 0:a3ea811f80f2 | 951 | USBDHAL_StartEp0Setup( dev ); |
Helmut64 | 0:a3ea811f80f2 | 952 | #endif |
Helmut64 | 0:a3ea811f80f2 | 953 | ep->state = D_EP_IDLE; |
Helmut64 | 0:a3ea811f80f2 | 954 | } |
Helmut64 | 0:a3ea811f80f2 | 955 | |
Helmut64 | 0:a3ea811f80f2 | 956 | /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************//** |
Helmut64 | 0:a3ea811f80f2 | 957 | * @{ |
Helmut64 | 0:a3ea811f80f2 | 958 | |
Helmut64 | 0:a3ea811f80f2 | 959 | @page usb_device USB device stack library |
Helmut64 | 0:a3ea811f80f2 | 960 | |
Helmut64 | 0:a3ea811f80f2 | 961 | The source files for the USB device stack resides in the usb directory |
Helmut64 | 0:a3ea811f80f2 | 962 | and follows the naming convention: em_usbd<em>nnn</em>.c/h. |
Helmut64 | 0:a3ea811f80f2 | 963 | |
Helmut64 | 0:a3ea811f80f2 | 964 | @li @ref usb_device_intro |
Helmut64 | 0:a3ea811f80f2 | 965 | @li @ref usb_device_api |
Helmut64 | 0:a3ea811f80f2 | 966 | @li @ref usb_device_conf |
Helmut64 | 0:a3ea811f80f2 | 967 | @li @ref usb_device_powersave |
Helmut64 | 0:a3ea811f80f2 | 968 | @li @ref usb_device_example1 |
Helmut64 | 0:a3ea811f80f2 | 969 | |
Helmut64 | 0:a3ea811f80f2 | 970 | |
Helmut64 | 0:a3ea811f80f2 | 971 | @n @section usb_device_intro Introduction |
Helmut64 | 0:a3ea811f80f2 | 972 | |
Helmut64 | 0:a3ea811f80f2 | 973 | The USB device protocol stack provides an API which makes it possible to |
Helmut64 | 0:a3ea811f80f2 | 974 | create USB devices with a minimum of effort. The device stack supports control, |
Helmut64 | 0:a3ea811f80f2 | 975 | bulk and interrupt transfers. |
Helmut64 | 0:a3ea811f80f2 | 976 | |
Helmut64 | 0:a3ea811f80f2 | 977 | The stack is highly configurable to suit various needs, it does also contain |
Helmut64 | 0:a3ea811f80f2 | 978 | useful debugging features together with several demonstration projects to |
Helmut64 | 0:a3ea811f80f2 | 979 | get you started fast. |
Helmut64 | 0:a3ea811f80f2 | 980 | |
Helmut64 | 0:a3ea811f80f2 | 981 | We recommend that you read through this documentation, then proceed to build |
Helmut64 | 0:a3ea811f80f2 | 982 | and test a few example projects before you start designing your own device. |
Helmut64 | 0:a3ea811f80f2 | 983 | |
Helmut64 | 0:a3ea811f80f2 | 984 | @n @section usb_device_api The device stack API |
Helmut64 | 0:a3ea811f80f2 | 985 | |
Helmut64 | 0:a3ea811f80f2 | 986 | This section contains brief descriptions of the functions in the API. You will |
Helmut64 | 0:a3ea811f80f2 | 987 | find detailed information on input and output parameters and return values by |
Helmut64 | 0:a3ea811f80f2 | 988 | clicking on the hyperlinked function names. It is also a good idea to study |
Helmut64 | 0:a3ea811f80f2 | 989 | the code in the USB demonstration projects. |
Helmut64 | 0:a3ea811f80f2 | 990 | |
Helmut64 | 0:a3ea811f80f2 | 991 | Your application code must include one header file: @em em_usb.h. |
Helmut64 | 0:a3ea811f80f2 | 992 | |
Helmut64 | 0:a3ea811f80f2 | 993 | All functions defined in the API can be called from within interrupt handlers. |
Helmut64 | 0:a3ea811f80f2 | 994 | |
Helmut64 | 0:a3ea811f80f2 | 995 | The USB stack use a hardware timer to keep track of time. TIMER0 is the |
Helmut64 | 0:a3ea811f80f2 | 996 | default choice, refer to @ref usb_device_conf for other possibilities. |
Helmut64 | 0:a3ea811f80f2 | 997 | Your application must not use the selected timer. |
Helmut64 | 0:a3ea811f80f2 | 998 | |
Helmut64 | 0:a3ea811f80f2 | 999 | <b>Pitfalls:</b>@n |
Helmut64 | 0:a3ea811f80f2 | 1000 | The USB peripheral will fill your receive buffers in quantities of WORD's |
Helmut64 | 0:a3ea811f80f2 | 1001 | (4 bytes). Transmit and receive buffers must be WORD aligned, in |
Helmut64 | 0:a3ea811f80f2 | 1002 | addition when allocating storage for receive buffers, round size up to |
Helmut64 | 0:a3ea811f80f2 | 1003 | next WORD boundary. If it is possible that the host will send more data |
Helmut64 | 0:a3ea811f80f2 | 1004 | than your device expects, round buffer size up to the next multiple of |
Helmut64 | 0:a3ea811f80f2 | 1005 | maxpacket size for the relevant endpoint to avoid data corruption. |
Helmut64 | 0:a3ea811f80f2 | 1006 | |
Helmut64 | 0:a3ea811f80f2 | 1007 | Transmit buffers passed to @htmlonly USBD_Write() @endhtmlonly must be |
Helmut64 | 0:a3ea811f80f2 | 1008 | statically allocated because @htmlonly USBD_Write() @endhtmlonly only |
Helmut64 | 0:a3ea811f80f2 | 1009 | initiates the transfer. When the host decide to actually perform the |
Helmut64 | 0:a3ea811f80f2 | 1010 | transfer, your data must be available. |
Helmut64 | 0:a3ea811f80f2 | 1011 | |
Helmut64 | 0:a3ea811f80f2 | 1012 | @n @ref USBD_Init() @n |
Helmut64 | 0:a3ea811f80f2 | 1013 | This function is called to register your device and all its properties with |
Helmut64 | 0:a3ea811f80f2 | 1014 | the device stack. The application must fill in a @ref USBD_Init_TypeDef |
Helmut64 | 0:a3ea811f80f2 | 1015 | structure prior to calling. Refer to @ref DeviceInitCallbacks for the |
Helmut64 | 0:a3ea811f80f2 | 1016 | optional callback functions defined within this structure. When this |
Helmut64 | 0:a3ea811f80f2 | 1017 | function has been called your device is ready to be enumerated by the USB |
Helmut64 | 0:a3ea811f80f2 | 1018 | host. |
Helmut64 | 0:a3ea811f80f2 | 1019 | |
Helmut64 | 0:a3ea811f80f2 | 1020 | @ref USBD_Read(), @ref USBD_Write() @n |
Helmut64 | 0:a3ea811f80f2 | 1021 | These functions initiate data transfers. |
Helmut64 | 0:a3ea811f80f2 | 1022 | @n @htmlonly USBD_Read() @endhtmlonly initiate a transfer of data @em |
Helmut64 | 0:a3ea811f80f2 | 1023 | from host @em to device (an @em OUT transfer in USB terminology). |
Helmut64 | 0:a3ea811f80f2 | 1024 | @n @htmlonly USBD_Write() @endhtmlonly initiate a transfer of data @em from |
Helmut64 | 0:a3ea811f80f2 | 1025 | device @em to host (an @em IN transfer). |
Helmut64 | 0:a3ea811f80f2 | 1026 | |
Helmut64 | 0:a3ea811f80f2 | 1027 | When the USB host actually performs the transfer, your application will be |
Helmut64 | 0:a3ea811f80f2 | 1028 | notified by means of a callback function which you provide (optionally). |
Helmut64 | 0:a3ea811f80f2 | 1029 | Refer to @ref TransferCallback for details of the callback functionality. |
Helmut64 | 0:a3ea811f80f2 | 1030 | |
Helmut64 | 0:a3ea811f80f2 | 1031 | @ref USBD_AbortTransfer(), @ref USBD_AbortAllTransfers() @n |
Helmut64 | 0:a3ea811f80f2 | 1032 | These functions terminate transfers that are initiated, but has not yet |
Helmut64 | 0:a3ea811f80f2 | 1033 | taken place. If a transfer is initiated with @htmlonly USBD_Read() |
Helmut64 | 0:a3ea811f80f2 | 1034 | or USBD_Write(), @endhtmlonly but the USB host never actually peform |
Helmut64 | 0:a3ea811f80f2 | 1035 | the transfers, these functions will deactivate the transfer setup to make |
Helmut64 | 0:a3ea811f80f2 | 1036 | the USB device endpoint hardware ready for new (and potentially) different |
Helmut64 | 0:a3ea811f80f2 | 1037 | transfers. |
Helmut64 | 0:a3ea811f80f2 | 1038 | |
Helmut64 | 0:a3ea811f80f2 | 1039 | @ref USBD_Connect(), @ref USBD_Disconnect() @n |
Helmut64 | 0:a3ea811f80f2 | 1040 | These functions turns the data-line (D+ or D-) pullup on or off. They can be |
Helmut64 | 0:a3ea811f80f2 | 1041 | used to force reenumeration. It's good practice to delay at least one second |
Helmut64 | 0:a3ea811f80f2 | 1042 | between @htmlonly USBD_Disconnect() and USBD_Connect() @endhtmlonly |
Helmut64 | 0:a3ea811f80f2 | 1043 | to allow the USB host to unload the currently active device driver. |
Helmut64 | 0:a3ea811f80f2 | 1044 | |
Helmut64 | 0:a3ea811f80f2 | 1045 | @ref USBD_EpIsBusy() @n |
Helmut64 | 0:a3ea811f80f2 | 1046 | Check if an endpoint is busy. |
Helmut64 | 0:a3ea811f80f2 | 1047 | |
Helmut64 | 0:a3ea811f80f2 | 1048 | @ref USBD_StallEp(), @ref USBD_UnStallEp() @n |
Helmut64 | 0:a3ea811f80f2 | 1049 | These functions stalls or un-stalls an endpoint. This functionality may not |
Helmut64 | 0:a3ea811f80f2 | 1050 | be needed by your application, but the USB device stack use them in response |
Helmut64 | 0:a3ea811f80f2 | 1051 | to standard setup commands SET_FEATURE and CLEAR_FEATURE. They may be useful |
Helmut64 | 0:a3ea811f80f2 | 1052 | when implementing some USB classes, e.g. a mass storage device use them |
Helmut64 | 0:a3ea811f80f2 | 1053 | extensively. |
Helmut64 | 0:a3ea811f80f2 | 1054 | |
Helmut64 | 0:a3ea811f80f2 | 1055 | @ref USBD_RemoteWakeup() @n |
Helmut64 | 0:a3ea811f80f2 | 1056 | Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to |
Helmut64 | 0:a3ea811f80f2 | 1057 | host. It's the applications responsibility to adhere to the USB standard |
Helmut64 | 0:a3ea811f80f2 | 1058 | which states that a device can not signal resume before it has been |
Helmut64 | 0:a3ea811f80f2 | 1059 | SUSPENDED for at least 5 ms. The function will also check the configuration |
Helmut64 | 0:a3ea811f80f2 | 1060 | descriptor defined by the application to see if it is legal for the device |
Helmut64 | 0:a3ea811f80f2 | 1061 | to signal resume. |
Helmut64 | 0:a3ea811f80f2 | 1062 | |
Helmut64 | 0:a3ea811f80f2 | 1063 | @ref USBD_GetUsbState() @n |
Helmut64 | 0:a3ea811f80f2 | 1064 | Returns the device USB state (see @ref USBD_State_TypeDef). Refer to |
Helmut64 | 0:a3ea811f80f2 | 1065 | Figure 9-1. "Device State Diagram" in the USB revision 2.0 specification. |
Helmut64 | 0:a3ea811f80f2 | 1066 | |
Helmut64 | 0:a3ea811f80f2 | 1067 | @ref USBD_GetUsbStateName() @n |
Helmut64 | 0:a3ea811f80f2 | 1068 | Returns a text string naming a given USB device state. |
Helmut64 | 0:a3ea811f80f2 | 1069 | |
Helmut64 | 0:a3ea811f80f2 | 1070 | @ref USBD_SafeToEnterEM2() @n |
Helmut64 | 0:a3ea811f80f2 | 1071 | Check if it is ok to enter energy mode EM2. Refer to the |
Helmut64 | 0:a3ea811f80f2 | 1072 | @ref usb_device_powersave section for more information. |
Helmut64 | 0:a3ea811f80f2 | 1073 | |
Helmut64 | 0:a3ea811f80f2 | 1074 | @n @anchor TransferCallback <b>The transfer complete callback function:</b> @n |
Helmut64 | 0:a3ea811f80f2 | 1075 | @n USB_XferCompleteCb_TypeDef() is called when a transfer completes. It is |
Helmut64 | 0:a3ea811f80f2 | 1076 | called with three parameters, the status of the transfer, the number of |
Helmut64 | 0:a3ea811f80f2 | 1077 | bytes transferred and the number of bytes remaining. It may not always be |
Helmut64 | 0:a3ea811f80f2 | 1078 | needed to have a callback on transfer completion, but you should keep in |
Helmut64 | 0:a3ea811f80f2 | 1079 | mind that a transfer may be aborted when you least expect it. A transfer |
Helmut64 | 0:a3ea811f80f2 | 1080 | will be aborted if host stalls the endpoint, if host resets your device, if |
Helmut64 | 0:a3ea811f80f2 | 1081 | host unconfigures your device or if you unplug your device cable and the |
Helmut64 | 0:a3ea811f80f2 | 1082 | device is selfpowered. |
Helmut64 | 0:a3ea811f80f2 | 1083 | @htmlonly USB_XferCompleteCb_TypeDef() @endhtmlonly is also called if your |
Helmut64 | 0:a3ea811f80f2 | 1084 | application use @htmlonly USBD_AbortTransfer() or USBD_AbortAllTransfers() |
Helmut64 | 0:a3ea811f80f2 | 1085 | @endhtmlonly calls. |
Helmut64 | 0:a3ea811f80f2 | 1086 | @note This callback is called from within an interrupt handler with |
Helmut64 | 0:a3ea811f80f2 | 1087 | interrupts disabled. |
Helmut64 | 0:a3ea811f80f2 | 1088 | |
Helmut64 | 0:a3ea811f80f2 | 1089 | @n @anchor DeviceInitCallbacks <b>Optional callbacks passed to the stack via |
Helmut64 | 0:a3ea811f80f2 | 1090 | the @ref USBD_Init() function:</b> @n |
Helmut64 | 0:a3ea811f80f2 | 1091 | @n These callbacks are all optional, and it is up to the application |
Helmut64 | 0:a3ea811f80f2 | 1092 | programmer to decide if the application needs the functionality they |
Helmut64 | 0:a3ea811f80f2 | 1093 | provide. |
Helmut64 | 0:a3ea811f80f2 | 1094 | @note These callbacks are all called from within an interrupt handler |
Helmut64 | 0:a3ea811f80f2 | 1095 | with interrupts disabled. |
Helmut64 | 0:a3ea811f80f2 | 1096 | |
Helmut64 | 0:a3ea811f80f2 | 1097 | USBD_UsbResetCb_TypeDef() is called each time reset signalling is sensed on |
Helmut64 | 0:a3ea811f80f2 | 1098 | the USB wire. |
Helmut64 | 0:a3ea811f80f2 | 1099 | |
Helmut64 | 0:a3ea811f80f2 | 1100 | @n USBD_SofIntCb_TypeDef() is called with framenumber as a parameter on |
Helmut64 | 0:a3ea811f80f2 | 1101 | each SOF interrupt. |
Helmut64 | 0:a3ea811f80f2 | 1102 | |
Helmut64 | 0:a3ea811f80f2 | 1103 | @n USBD_DeviceStateChangeCb_TypeDef() is called whenever the device state |
Helmut64 | 0:a3ea811f80f2 | 1104 | change. Useful for detecting e.g. SUSPENDED state change in order to reduce |
Helmut64 | 0:a3ea811f80f2 | 1105 | current consumption of buspowered devices. The USB HID keyboard example |
Helmut64 | 0:a3ea811f80f2 | 1106 | project has a good example on how to use this callback. |
Helmut64 | 0:a3ea811f80f2 | 1107 | |
Helmut64 | 0:a3ea811f80f2 | 1108 | @n USBD_IsSelfPoweredCb_TypeDef() is called by the device stack when host |
Helmut64 | 0:a3ea811f80f2 | 1109 | queries the device with a standard setup GET_STATUS command to check if the |
Helmut64 | 0:a3ea811f80f2 | 1110 | device is currently selfpowered or buspowered. This feature is only |
Helmut64 | 0:a3ea811f80f2 | 1111 | applicable on selfpowered devices which also works when only buspower is |
Helmut64 | 0:a3ea811f80f2 | 1112 | available. |
Helmut64 | 0:a3ea811f80f2 | 1113 | |
Helmut64 | 0:a3ea811f80f2 | 1114 | @n USBD_SetupCmdCb_TypeDef() is called each time a setup command is |
Helmut64 | 0:a3ea811f80f2 | 1115 | received from host. Use this callback to override or extend the default |
Helmut64 | 0:a3ea811f80f2 | 1116 | handling of standard setup commands, and to implement class or vendor |
Helmut64 | 0:a3ea811f80f2 | 1117 | specific setup commands. The USB HID keyboard example project has a good |
Helmut64 | 0:a3ea811f80f2 | 1118 | example on how to use this callback. |
Helmut64 | 0:a3ea811f80f2 | 1119 | |
Helmut64 | 0:a3ea811f80f2 | 1120 | @n <b>Utility functions:</b> @n |
Helmut64 | 0:a3ea811f80f2 | 1121 | @n USB_PUTCHAR() Transmit a single char on the debug serial port. |
Helmut64 | 0:a3ea811f80f2 | 1122 | @n @n USB_PUTS() Transmit a zero terminated string on the debug serial port. |
Helmut64 | 0:a3ea811f80f2 | 1123 | @n @n USB_PRINTF() Transmit "printf" formated data on the debug serial port. |
Helmut64 | 0:a3ea811f80f2 | 1124 | @n @n USB_GetErrorMsgString() Return an error message string for a given |
Helmut64 | 0:a3ea811f80f2 | 1125 | error code. |
Helmut64 | 0:a3ea811f80f2 | 1126 | @n @n USB_PrintErrorMsgString() Format and print a text string given an |
Helmut64 | 0:a3ea811f80f2 | 1127 | error code, prepends an optional user supplied leader string. |
Helmut64 | 0:a3ea811f80f2 | 1128 | @n @n USBTIMER_DelayMs() Active wait millisecond delay function. Can also be |
Helmut64 | 0:a3ea811f80f2 | 1129 | used inside interrupt handlers. |
Helmut64 | 0:a3ea811f80f2 | 1130 | @n @n USBTIMER_DelayUs() Active wait microsecond delay function. Can also be |
Helmut64 | 0:a3ea811f80f2 | 1131 | used inside interrupt handlers. |
Helmut64 | 0:a3ea811f80f2 | 1132 | @n @n USBTIMER_Init() Initialize the timer system. Called by @htmlonly |
Helmut64 | 0:a3ea811f80f2 | 1133 | USBD_Init(), @endhtmlonly but your application must call it again to |
Helmut64 | 0:a3ea811f80f2 | 1134 | reinitialize whenever you change the HFPERCLK frequency. |
Helmut64 | 0:a3ea811f80f2 | 1135 | @n @n USBTIMER_Start() Start a timer. You can configure the USB device stack |
Helmut64 | 0:a3ea811f80f2 | 1136 | to provide any number of timers. The timers have 1 ms resolution, your |
Helmut64 | 0:a3ea811f80f2 | 1137 | application is notified of timeout by means of a callback. |
Helmut64 | 0:a3ea811f80f2 | 1138 | @n @n USBTIMER_Stop() Stop a timer. |
Helmut64 | 0:a3ea811f80f2 | 1139 | |
Helmut64 | 0:a3ea811f80f2 | 1140 | @n @section usb_device_conf Configuring the device stack |
Helmut64 | 0:a3ea811f80f2 | 1141 | |
Helmut64 | 0:a3ea811f80f2 | 1142 | Your application must provide a header file named @em usbconfig.h. This file |
Helmut64 | 0:a3ea811f80f2 | 1143 | must contain the following \#define's:@n @n |
Helmut64 | 0:a3ea811f80f2 | 1144 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1145 | #define USB_DEVICE // Compile the stack for device mode. |
Helmut64 | 0:a3ea811f80f2 | 1146 | #define NUM_EP_USED n // Your application use 'n' endpoints in |
Helmut64 | 0:a3ea811f80f2 | 1147 | // addition to endpoint 0. @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1148 | |
Helmut64 | 0:a3ea811f80f2 | 1149 | @n @em usbconfig.h may define the following items: @n @n |
Helmut64 | 0:a3ea811f80f2 | 1150 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1151 | #define NUM_APP_TIMERS n // Your application needs 'n' timers |
Helmut64 | 0:a3ea811f80f2 | 1152 | |
Helmut64 | 0:a3ea811f80f2 | 1153 | #define DEBUG_USB_API // Turn on API debug diagnostics. |
Helmut64 | 0:a3ea811f80f2 | 1154 | |
Helmut64 | 0:a3ea811f80f2 | 1155 | // Some utility functions in the API needs printf. These |
Helmut64 | 0:a3ea811f80f2 | 1156 | // functions have "print" in their name. This macro enables |
Helmut64 | 0:a3ea811f80f2 | 1157 | // these functions. |
Helmut64 | 0:a3ea811f80f2 | 1158 | #define USB_USE_PRINTF // Enable utility print functions. |
Helmut64 | 0:a3ea811f80f2 | 1159 | |
Helmut64 | 0:a3ea811f80f2 | 1160 | // Define a function for transmitting a single char on the serial port. |
Helmut64 | 0:a3ea811f80f2 | 1161 | extern int RETARGET_WriteChar(char c); |
Helmut64 | 0:a3ea811f80f2 | 1162 | #define USER_PUTCHAR RETARGET_WriteChar |
Helmut64 | 0:a3ea811f80f2 | 1163 | |
Helmut64 | 0:a3ea811f80f2 | 1164 | #define USB_TIMER USB_TIMERn // Select which hardware timer the USB stack |
Helmut64 | 0:a3ea811f80f2 | 1165 | // is allowed to use. Valid values are n=0,1,2... |
Helmut64 | 0:a3ea811f80f2 | 1166 | // corresponding to TIMER0, TIMER1, ... |
Helmut64 | 0:a3ea811f80f2 | 1167 | // If not specified, TIMER0 is used |
Helmut64 | 0:a3ea811f80f2 | 1168 | |
Helmut64 | 0:a3ea811f80f2 | 1169 | #define USB_VBUS_SWITCH_NOT_PRESENT // Hardware does not have a VBUS switch |
Helmut64 | 0:a3ea811f80f2 | 1170 | |
Helmut64 | 0:a3ea811f80f2 | 1171 | #define USB_CORECLK_HFRCO // Devices supporting crystal-less USB can use |
Helmut64 | 0:a3ea811f80f2 | 1172 | // HFRCO as core clock, default is HFXO |
Helmut64 | 0:a3ea811f80f2 | 1173 | @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1174 | |
Helmut64 | 0:a3ea811f80f2 | 1175 | @n You are strongly encouraged to start application development with DEBUG_USB_API |
Helmut64 | 0:a3ea811f80f2 | 1176 | turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful |
Helmut64 | 0:a3ea811f80f2 | 1177 | debugging information will be output on the development kit serial port. |
Helmut64 | 0:a3ea811f80f2 | 1178 | Compiling with the DEBUG_EFM_USER flag will also enable all asserts |
Helmut64 | 0:a3ea811f80f2 | 1179 | in both @em emlib and in the USB stack. If asserts are enabled and |
Helmut64 | 0:a3ea811f80f2 | 1180 | USER_PUTCHAR defined, assert texts will be output on the serial port. |
Helmut64 | 0:a3ea811f80f2 | 1181 | |
Helmut64 | 0:a3ea811f80f2 | 1182 | You application must include @em retargetserial.c if DEBUG_USB_API is defined |
Helmut64 | 0:a3ea811f80f2 | 1183 | and @em retargetio.c if USB_USE_PRINTF is defined. |
Helmut64 | 0:a3ea811f80f2 | 1184 | These files reside in the @em drivers |
Helmut64 | 0:a3ea811f80f2 | 1185 | directory in the software package for your development board. Refer to |
Helmut64 | 0:a3ea811f80f2 | 1186 | @ref usb_device_powersave for energy-saving mode configurations. |
Helmut64 | 0:a3ea811f80f2 | 1187 | |
Helmut64 | 0:a3ea811f80f2 | 1188 | @n @section usb_device_powersave Energy-saving modes |
Helmut64 | 0:a3ea811f80f2 | 1189 | |
Helmut64 | 0:a3ea811f80f2 | 1190 | The device stack provides two energy saving levels. The first level is to |
Helmut64 | 0:a3ea811f80f2 | 1191 | set the USB peripheral in energy saving mode, the next level is to enter |
Helmut64 | 0:a3ea811f80f2 | 1192 | Energy Mode 2 (EM2). These energy saving modes can be applied when the device |
Helmut64 | 0:a3ea811f80f2 | 1193 | is suspended by the USB host, or when when the device is not connected to a |
Helmut64 | 0:a3ea811f80f2 | 1194 | USB host. |
Helmut64 | 0:a3ea811f80f2 | 1195 | In addition to this an application can use energy modes EM1 and EM2. There |
Helmut64 | 0:a3ea811f80f2 | 1196 | are no restrictions on when EM1 can be entered, EM2 can only be entered |
Helmut64 | 0:a3ea811f80f2 | 1197 | when the USB device is suspended or detached from host. |
Helmut64 | 0:a3ea811f80f2 | 1198 | |
Helmut64 | 0:a3ea811f80f2 | 1199 | Energy-saving modes are selected with a \#define in @em usbconfig.h, default |
Helmut64 | 0:a3ea811f80f2 | 1200 | selection is to not use any energy saving modes.@n @n |
Helmut64 | 0:a3ea811f80f2 | 1201 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1202 | #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ENTEREM2)@endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1203 | |
Helmut64 | 0:a3ea811f80f2 | 1204 | There are three flags available, the flags can be or'ed together as shown above. |
Helmut64 | 0:a3ea811f80f2 | 1205 | |
Helmut64 | 0:a3ea811f80f2 | 1206 | <b>\#define USB_PWRSAVE_MODE_ONSUSPEND</b>@n Set USB peripheral in low power |
Helmut64 | 0:a3ea811f80f2 | 1207 | mode on suspend. |
Helmut64 | 0:a3ea811f80f2 | 1208 | |
Helmut64 | 0:a3ea811f80f2 | 1209 | <b>\#define USB_PWRSAVE_MODE_ONVBUSOFF</b>@n Set USB peripheral in low power |
Helmut64 | 0:a3ea811f80f2 | 1210 | mode when not attached to a host. This mode assumes that the internal voltage |
Helmut64 | 0:a3ea811f80f2 | 1211 | regulator is used and that the VREGI pin of the chip is connected to VBUS. |
Helmut64 | 0:a3ea811f80f2 | 1212 | This option can not be used with bus-powered devices. |
Helmut64 | 0:a3ea811f80f2 | 1213 | |
Helmut64 | 0:a3ea811f80f2 | 1214 | <b>\#define USB_PWRSAVE_MODE_ENTEREM2</b>@n Enter EM2 when USB peripheral is |
Helmut64 | 0:a3ea811f80f2 | 1215 | in low power mode. |
Helmut64 | 0:a3ea811f80f2 | 1216 | |
Helmut64 | 0:a3ea811f80f2 | 1217 | When the USB peripheral is set in low power mode, it must be clocked by a 32kHz |
Helmut64 | 0:a3ea811f80f2 | 1218 | clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification |
Helmut64 | 0:a3ea811f80f2 | 1219 | compliance. Selection is done with a \#define in @em usbconfig.h.@n @n |
Helmut64 | 0:a3ea811f80f2 | 1220 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1221 | #define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1222 | Two flags are available, <b>USB_USBC_32kHz_CLK_LFXO</b> and |
Helmut64 | 0:a3ea811f80f2 | 1223 | <b>USB_USBC_32kHz_CLK_LFRCO</b>. <b>USB_USBC_32kHz_CLK_LFXO</b> is selected |
Helmut64 | 0:a3ea811f80f2 | 1224 | by default. |
Helmut64 | 0:a3ea811f80f2 | 1225 | |
Helmut64 | 0:a3ea811f80f2 | 1226 | The USB HID keyboard and Mass Storage device example projects demonstrate |
Helmut64 | 0:a3ea811f80f2 | 1227 | different energy-saving modes. |
Helmut64 | 0:a3ea811f80f2 | 1228 | |
Helmut64 | 0:a3ea811f80f2 | 1229 | <b>Example 1:</b> |
Helmut64 | 0:a3ea811f80f2 | 1230 | Leave all energy saving to the stack, the device enters EM2 on suspend and |
Helmut64 | 0:a3ea811f80f2 | 1231 | when detached from host. @n |
Helmut64 | 0:a3ea811f80f2 | 1232 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1233 | In usbconfig.h: |
Helmut64 | 0:a3ea811f80f2 | 1234 | |
Helmut64 | 0:a3ea811f80f2 | 1235 | #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | USB_PWRSAVE_MODE_ENTEREM2) |
Helmut64 | 0:a3ea811f80f2 | 1236 | @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1237 | |
Helmut64 | 0:a3ea811f80f2 | 1238 | @n <b>Example 2:</b> |
Helmut64 | 0:a3ea811f80f2 | 1239 | Let the stack control energy saving in the USB periheral but let your |
Helmut64 | 0:a3ea811f80f2 | 1240 | application control energy modes EM1 and EM2. @n |
Helmut64 | 0:a3ea811f80f2 | 1241 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1242 | In usbconfig.h: |
Helmut64 | 0:a3ea811f80f2 | 1243 | |
Helmut64 | 0:a3ea811f80f2 | 1244 | #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF) |
Helmut64 | 0:a3ea811f80f2 | 1245 | |
Helmut64 | 0:a3ea811f80f2 | 1246 | In application code: |
Helmut64 | 0:a3ea811f80f2 | 1247 | |
Helmut64 | 0:a3ea811f80f2 | 1248 | if ( USBD_SafeToEnterEM2() ) |
Helmut64 | 0:a3ea811f80f2 | 1249 | EMU_EnterEM2(true); |
Helmut64 | 0:a3ea811f80f2 | 1250 | else |
Helmut64 | 0:a3ea811f80f2 | 1251 | EMU_EnterEM1(); @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1252 | |
Helmut64 | 0:a3ea811f80f2 | 1253 | @n @section usb_device_example1 Vendor unique device example application |
Helmut64 | 0:a3ea811f80f2 | 1254 | |
Helmut64 | 0:a3ea811f80f2 | 1255 | This example represents the most simple USB device imaginable. It's purpose |
Helmut64 | 0:a3ea811f80f2 | 1256 | is to turn user LED's on or off under control of vendor unique setup commands. |
Helmut64 | 0:a3ea811f80f2 | 1257 | The device will rely on @em libusb device driver on the host, a host |
Helmut64 | 0:a3ea811f80f2 | 1258 | application @em EFM32-LedApp.exe is bundled with the example. |
Helmut64 | 0:a3ea811f80f2 | 1259 | |
Helmut64 | 0:a3ea811f80f2 | 1260 | The main() is really simple ! @n @n |
Helmut64 | 0:a3ea811f80f2 | 1261 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1262 | #include "em_usb.h" |
Helmut64 | 0:a3ea811f80f2 | 1263 | |
Helmut64 | 0:a3ea811f80f2 | 1264 | #include "descriptors.h" |
Helmut64 | 0:a3ea811f80f2 | 1265 | |
Helmut64 | 0:a3ea811f80f2 | 1266 | int main( void ) |
Helmut64 | 0:a3ea811f80f2 | 1267 | { |
Helmut64 | 0:a3ea811f80f2 | 1268 | BSP_Init(BSP_INIT_DEFAULT); // Initialize DK board register access |
Helmut64 | 0:a3ea811f80f2 | 1269 | CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); |
Helmut64 | 0:a3ea811f80f2 | 1270 | BSP_LedsSet(0); // Turn off all LED's |
Helmut64 | 0:a3ea811f80f2 | 1271 | |
Helmut64 | 0:a3ea811f80f2 | 1272 | ConsoleDebugInit(); // Initialize UART for debug diagnostics |
Helmut64 | 0:a3ea811f80f2 | 1273 | |
Helmut64 | 0:a3ea811f80f2 | 1274 | USB_PUTS( "\nEFM32 USB LED Vendor Unique Device example\n" ); |
Helmut64 | 0:a3ea811f80f2 | 1275 | |
Helmut64 | 0:a3ea811f80f2 | 1276 | USBD_Init( &initstruct ); // GO ! |
Helmut64 | 0:a3ea811f80f2 | 1277 | |
Helmut64 | 0:a3ea811f80f2 | 1278 | //When using a debugger it is pratical to uncomment the following three |
Helmut64 | 0:a3ea811f80f2 | 1279 | //lines to force host to re-enumerate the device. |
Helmut64 | 0:a3ea811f80f2 | 1280 | |
Helmut64 | 0:a3ea811f80f2 | 1281 | //USBD_Disconnect(); |
Helmut64 | 0:a3ea811f80f2 | 1282 | //USBTIMER_DelayMs( 1000 ); |
Helmut64 | 0:a3ea811f80f2 | 1283 | //USBD_Connect(); |
Helmut64 | 0:a3ea811f80f2 | 1284 | |
Helmut64 | 0:a3ea811f80f2 | 1285 | for (;;) {} |
Helmut64 | 0:a3ea811f80f2 | 1286 | } @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1287 | |
Helmut64 | 0:a3ea811f80f2 | 1288 | @n Configure the device stack in <em>usbconfig.h</em>: @n @n |
Helmut64 | 0:a3ea811f80f2 | 1289 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1290 | #define USB_DEVICE // Compile stack for device mode. |
Helmut64 | 0:a3ea811f80f2 | 1291 | |
Helmut64 | 0:a3ea811f80f2 | 1292 | // ************************************************************************** |
Helmut64 | 0:a3ea811f80f2 | 1293 | ** ** |
Helmut64 | 0:a3ea811f80f2 | 1294 | ** Specify number of endpoints used (in addition to EP0). ** |
Helmut64 | 0:a3ea811f80f2 | 1295 | ** ** |
Helmut64 | 0:a3ea811f80f2 | 1296 | ***************************************************************************** |
Helmut64 | 0:a3ea811f80f2 | 1297 | #define NUM_EP_USED 0 // EP0 is the only endpoint used. |
Helmut64 | 0:a3ea811f80f2 | 1298 | |
Helmut64 | 0:a3ea811f80f2 | 1299 | // ************************************************************************** |
Helmut64 | 0:a3ea811f80f2 | 1300 | ** ** |
Helmut64 | 0:a3ea811f80f2 | 1301 | ** Configure serial port debug output. ** |
Helmut64 | 0:a3ea811f80f2 | 1302 | ** ** |
Helmut64 | 0:a3ea811f80f2 | 1303 | ***************************************************************************** |
Helmut64 | 0:a3ea811f80f2 | 1304 | // Prototype a function for transmitting a single char on the serial port. |
Helmut64 | 0:a3ea811f80f2 | 1305 | extern int RETARGET_WriteChar(char c); |
Helmut64 | 0:a3ea811f80f2 | 1306 | #define USER_PUTCHAR RETARGET_WriteChar |
Helmut64 | 0:a3ea811f80f2 | 1307 | |
Helmut64 | 0:a3ea811f80f2 | 1308 | // Enable debug diagnostics from API functions (illegal input params etc.) |
Helmut64 | 0:a3ea811f80f2 | 1309 | #define DEBUG_USB_API @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1310 | |
Helmut64 | 0:a3ea811f80f2 | 1311 | @n Define device properties and fill in USB initstruct in |
Helmut64 | 0:a3ea811f80f2 | 1312 | <em>descriptors.h</em>: @n @n |
Helmut64 | 0:a3ea811f80f2 | 1313 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1314 | EFM32_ALIGN(4) |
Helmut64 | 0:a3ea811f80f2 | 1315 | static const USB_DeviceDescriptor_TypeDef deviceDesc __attribute__ ((aligned(4))) = |
Helmut64 | 0:a3ea811f80f2 | 1316 | { |
Helmut64 | 0:a3ea811f80f2 | 1317 | .bLength = USB_DEVICE_DESCSIZE, |
Helmut64 | 0:a3ea811f80f2 | 1318 | .bDescriptorType = USB_DEVICE_DESCRIPTOR, |
Helmut64 | 0:a3ea811f80f2 | 1319 | .bcdUSB = 0x0200, |
Helmut64 | 0:a3ea811f80f2 | 1320 | .bDeviceClass = 0xFF, |
Helmut64 | 0:a3ea811f80f2 | 1321 | .bDeviceSubClass = 0, |
Helmut64 | 0:a3ea811f80f2 | 1322 | .bDeviceProtocol = 0, |
Helmut64 | 0:a3ea811f80f2 | 1323 | .bMaxPacketSize0 = USB_FS_CTRL_EP_MAXSIZE, |
Helmut64 | 0:a3ea811f80f2 | 1324 | .idVendor = 0x10C4, |
Helmut64 | 0:a3ea811f80f2 | 1325 | .idProduct = 0x0001, |
Helmut64 | 0:a3ea811f80f2 | 1326 | .bcdDevice = 0x0000, |
Helmut64 | 0:a3ea811f80f2 | 1327 | .iManufacturer = 1, |
Helmut64 | 0:a3ea811f80f2 | 1328 | .iProduct = 2, |
Helmut64 | 0:a3ea811f80f2 | 1329 | .iSerialNumber = 3, |
Helmut64 | 0:a3ea811f80f2 | 1330 | .bNumConfigurations = 1 |
Helmut64 | 0:a3ea811f80f2 | 1331 | }; |
Helmut64 | 0:a3ea811f80f2 | 1332 | |
Helmut64 | 0:a3ea811f80f2 | 1333 | EFM32_ALIGN(4) |
Helmut64 | 0:a3ea811f80f2 | 1334 | static const uint8_t configDesc[] __attribute__ ((aligned(4)))= |
Helmut64 | 0:a3ea811f80f2 | 1335 | { |
Helmut64 | 0:a3ea811f80f2 | 1336 | // *** Configuration descriptor *** |
Helmut64 | 0:a3ea811f80f2 | 1337 | USB_CONFIG_DESCSIZE, // bLength |
Helmut64 | 0:a3ea811f80f2 | 1338 | USB_CONFIG_DESCRIPTOR, // bDescriptorType |
Helmut64 | 0:a3ea811f80f2 | 1339 | USB_CONFIG_DESCSIZE + // wTotalLength (LSB) |
Helmut64 | 0:a3ea811f80f2 | 1340 | USB_INTERFACE_DESCSIZE, |
Helmut64 | 0:a3ea811f80f2 | 1341 | (USB_CONFIG_DESCSIZE + // wTotalLength (MSB) |
Helmut64 | 0:a3ea811f80f2 | 1342 | USB_INTERFACE_DESCSIZE)>>8, |
Helmut64 | 0:a3ea811f80f2 | 1343 | 1, // bNumInterfaces |
Helmut64 | 0:a3ea811f80f2 | 1344 | 1, // bConfigurationValue |
Helmut64 | 0:a3ea811f80f2 | 1345 | 0, // iConfiguration |
Helmut64 | 0:a3ea811f80f2 | 1346 | CONFIG_DESC_BM_RESERVED_D7 | // bmAttrib: Self powered |
Helmut64 | 0:a3ea811f80f2 | 1347 | CONFIG_DESC_BM_SELFPOWERED, |
Helmut64 | 0:a3ea811f80f2 | 1348 | CONFIG_DESC_MAXPOWER_mA( 100 ), // bMaxPower: 100 mA |
Helmut64 | 0:a3ea811f80f2 | 1349 | |
Helmut64 | 0:a3ea811f80f2 | 1350 | // *** Interface descriptor *** |
Helmut64 | 0:a3ea811f80f2 | 1351 | USB_INTERFACE_DESCSIZE, // bLength |
Helmut64 | 0:a3ea811f80f2 | 1352 | USB_INTERFACE_DESCRIPTOR, // bDescriptorType |
Helmut64 | 0:a3ea811f80f2 | 1353 | 0, // bInterfaceNumber |
Helmut64 | 0:a3ea811f80f2 | 1354 | 0, // bAlternateSetting |
Helmut64 | 0:a3ea811f80f2 | 1355 | NUM_EP_USED, // bNumEndpoints |
Helmut64 | 0:a3ea811f80f2 | 1356 | 0xFF, // bInterfaceClass |
Helmut64 | 0:a3ea811f80f2 | 1357 | 0, // bInterfaceSubClass |
Helmut64 | 0:a3ea811f80f2 | 1358 | 0, // bInterfaceProtocol |
Helmut64 | 0:a3ea811f80f2 | 1359 | 0, // iInterface |
Helmut64 | 0:a3ea811f80f2 | 1360 | }; |
Helmut64 | 0:a3ea811f80f2 | 1361 | |
Helmut64 | 0:a3ea811f80f2 | 1362 | STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 ); |
Helmut64 | 0:a3ea811f80f2 | 1363 | STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ', \ |
Helmut64 | 0:a3ea811f80f2 | 1364 | 'M','i','c','r','o',' ','A','S' ); |
Helmut64 | 0:a3ea811f80f2 | 1365 | STATIC_CONST_STRING_DESC( iProduct , 'V','e','n','d','o','r',' ', \ |
Helmut64 | 0:a3ea811f80f2 | 1366 | 'U','n','i','q','u','e',' ', \ |
Helmut64 | 0:a3ea811f80f2 | 1367 | 'L','E','D',' ', \ |
Helmut64 | 0:a3ea811f80f2 | 1368 | 'D','e','v','i','c','e' ); |
Helmut64 | 0:a3ea811f80f2 | 1369 | STATIC_CONST_STRING_DESC( iSerialNumber, '0','0','0','0','0','0', \ |
Helmut64 | 0:a3ea811f80f2 | 1370 | '0','0','1','2','3','4' ); |
Helmut64 | 0:a3ea811f80f2 | 1371 | |
Helmut64 | 0:a3ea811f80f2 | 1372 | static const void * const strings[] = |
Helmut64 | 0:a3ea811f80f2 | 1373 | { |
Helmut64 | 0:a3ea811f80f2 | 1374 | &langID, |
Helmut64 | 0:a3ea811f80f2 | 1375 | &iManufacturer, |
Helmut64 | 0:a3ea811f80f2 | 1376 | &iProduct, |
Helmut64 | 0:a3ea811f80f2 | 1377 | &iSerialNumber |
Helmut64 | 0:a3ea811f80f2 | 1378 | }; |
Helmut64 | 0:a3ea811f80f2 | 1379 | |
Helmut64 | 0:a3ea811f80f2 | 1380 | // Endpoint buffer sizes |
Helmut64 | 0:a3ea811f80f2 | 1381 | // 1 = single buffer, 2 = double buffering, 3 = tripple buffering ... |
Helmut64 | 0:a3ea811f80f2 | 1382 | static const uint8_t bufferingMultiplier[ NUM_EP_USED + 1 ] = { 1 }; |
Helmut64 | 0:a3ea811f80f2 | 1383 | |
Helmut64 | 0:a3ea811f80f2 | 1384 | static const USBD_Callbacks_TypeDef callbacks = |
Helmut64 | 0:a3ea811f80f2 | 1385 | { |
Helmut64 | 0:a3ea811f80f2 | 1386 | .usbReset = NULL, |
Helmut64 | 0:a3ea811f80f2 | 1387 | .usbStateChange = NULL, |
Helmut64 | 0:a3ea811f80f2 | 1388 | .setupCmd = SetupCmd, |
Helmut64 | 0:a3ea811f80f2 | 1389 | .isSelfPowered = NULL, |
Helmut64 | 0:a3ea811f80f2 | 1390 | .sofInt = NULL |
Helmut64 | 0:a3ea811f80f2 | 1391 | }; |
Helmut64 | 0:a3ea811f80f2 | 1392 | |
Helmut64 | 0:a3ea811f80f2 | 1393 | static const USBD_Init_TypeDef initstruct = |
Helmut64 | 0:a3ea811f80f2 | 1394 | { |
Helmut64 | 0:a3ea811f80f2 | 1395 | .deviceDescriptor = &deviceDesc, |
Helmut64 | 0:a3ea811f80f2 | 1396 | .configDescriptor = configDesc, |
Helmut64 | 0:a3ea811f80f2 | 1397 | .stringDescriptors = strings, |
Helmut64 | 0:a3ea811f80f2 | 1398 | .numberOfStrings = sizeof(strings)/sizeof(void*), |
Helmut64 | 0:a3ea811f80f2 | 1399 | .callbacks = &callbacks, |
Helmut64 | 0:a3ea811f80f2 | 1400 | .bufferingMultiplier = bufferingMultiplier |
Helmut64 | 0:a3ea811f80f2 | 1401 | }; @endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1402 | |
Helmut64 | 0:a3ea811f80f2 | 1403 | @n Now we have to implement vendor unique USB setup commands to control the |
Helmut64 | 0:a3ea811f80f2 | 1404 | LED's (see callbacks variable above). Notice that the buffer variable below is |
Helmut64 | 0:a3ea811f80f2 | 1405 | statically allocated because @htmlonly USBD_Write() @endhtmlonly only |
Helmut64 | 0:a3ea811f80f2 | 1406 | initiates the transfer. When the host actually performs the transfer, the |
Helmut64 | 0:a3ea811f80f2 | 1407 | SetupCmd() function will have returned ! @n @n |
Helmut64 | 0:a3ea811f80f2 | 1408 | |
Helmut64 | 0:a3ea811f80f2 | 1409 | @verbatim |
Helmut64 | 0:a3ea811f80f2 | 1410 | #define VND_GET_LEDS 0x10 |
Helmut64 | 0:a3ea811f80f2 | 1411 | #define VND_SET_LED 0x11 |
Helmut64 | 0:a3ea811f80f2 | 1412 | |
Helmut64 | 0:a3ea811f80f2 | 1413 | static int SetupCmd( const USB_Setup_TypeDef *setup ) |
Helmut64 | 0:a3ea811f80f2 | 1414 | { |
Helmut64 | 0:a3ea811f80f2 | 1415 | int retVal; |
Helmut64 | 0:a3ea811f80f2 | 1416 | uint16_t leds; |
Helmut64 | 0:a3ea811f80f2 | 1417 | static uint32_t buffer; |
Helmut64 | 0:a3ea811f80f2 | 1418 | uint8_t *pBuffer = (uint8_t*)&buffer; |
Helmut64 | 0:a3ea811f80f2 | 1419 | |
Helmut64 | 0:a3ea811f80f2 | 1420 | retVal = USB_STATUS_REQ_UNHANDLED; |
Helmut64 | 0:a3ea811f80f2 | 1421 | |
Helmut64 | 0:a3ea811f80f2 | 1422 | if ( setup->Type == USB_SETUP_TYPE_VENDOR ) |
Helmut64 | 0:a3ea811f80f2 | 1423 | { |
Helmut64 | 0:a3ea811f80f2 | 1424 | switch ( setup->bRequest ) |
Helmut64 | 0:a3ea811f80f2 | 1425 | { |
Helmut64 | 0:a3ea811f80f2 | 1426 | case VND_GET_LEDS: |
Helmut64 | 0:a3ea811f80f2 | 1427 | // ******************** |
Helmut64 | 0:a3ea811f80f2 | 1428 | *pBuffer = BSP_LedsGet() & 0x1F; |
Helmut64 | 0:a3ea811f80f2 | 1429 | retVal = USBD_Write( 0, pBuffer, setup->wLength, NULL ); |
Helmut64 | 0:a3ea811f80f2 | 1430 | break; |
Helmut64 | 0:a3ea811f80f2 | 1431 | |
Helmut64 | 0:a3ea811f80f2 | 1432 | case VND_SET_LED: |
Helmut64 | 0:a3ea811f80f2 | 1433 | // ******************** |
Helmut64 | 0:a3ea811f80f2 | 1434 | leds = DVK_getLEDs() & 0x1F; |
Helmut64 | 0:a3ea811f80f2 | 1435 | if ( setup->wValue ) |
Helmut64 | 0:a3ea811f80f2 | 1436 | { |
Helmut64 | 0:a3ea811f80f2 | 1437 | leds |= LED0 << setup->wIndex; |
Helmut64 | 0:a3ea811f80f2 | 1438 | } |
Helmut64 | 0:a3ea811f80f2 | 1439 | else |
Helmut64 | 0:a3ea811f80f2 | 1440 | { |
Helmut64 | 0:a3ea811f80f2 | 1441 | leds &= ~( LED0 << setup->wIndex ); |
Helmut64 | 0:a3ea811f80f2 | 1442 | } |
Helmut64 | 0:a3ea811f80f2 | 1443 | BSP_LedsSet( leds ); |
Helmut64 | 0:a3ea811f80f2 | 1444 | retVal = USB_STATUS_OK; |
Helmut64 | 0:a3ea811f80f2 | 1445 | break; |
Helmut64 | 0:a3ea811f80f2 | 1446 | } |
Helmut64 | 0:a3ea811f80f2 | 1447 | } |
Helmut64 | 0:a3ea811f80f2 | 1448 | |
Helmut64 | 0:a3ea811f80f2 | 1449 | return retVal; |
Helmut64 | 0:a3ea811f80f2 | 1450 | }@endverbatim |
Helmut64 | 0:a3ea811f80f2 | 1451 | |
Helmut64 | 0:a3ea811f80f2 | 1452 | * @}**************************************************************************/ |
Helmut64 | 0:a3ea811f80f2 | 1453 | |
Helmut64 | 0:a3ea811f80f2 | 1454 | #endif /* defined( USB_DEVICE ) */ |
Helmut64 | 0:a3ea811f80f2 | 1455 | #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */ |