1 /***************************************************************************//** 2 * \file cyhal_usb_dev.h 3 * 4 * \brief 5 * Provides a high level interface for interacting with the Infineon USB Device. 6 * This interface abstracts out the chip specific details. 7 * If any chip specific functionality is necessary, or performance is critical 8 * the low level functions can be used directly. 9 * 10 ******************************************************************************** 11 * \copyright 12 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or 13 * an affiliate of Cypress Semiconductor Corporation 14 * 15 * SPDX-License-Identifier: Apache-2.0 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 *******************************************************************************/ 29 30 /** 31 * \addtogroup group_hal_usb_dev USB Device 32 * \ingroup group_hal 33 * \{ 34 * High level interface for interacting with the USB Device. 35 * 36 * This block supports one control endpoint (EP0) and one or more data endpoints. 37 * See the device datasheet for the number of data endpoints supported. 38 * 39 * Four transfer types are supported (see \ref cyhal_usb_dev_ep_type_t): 40 * * Bulk 41 * * Interrupt 42 * * Isochronous 43 * * Control 44 * 45 * \section section_usb_dev_features Features 46 * * Complies with USB specification 2.0 47 * * Supports full-speed peripheral device operation with a signaling bit rate of 12 Mbps. 48 * * Configurable D+ AND D- pins using \ref cyhal_gpio_t 49 * * Configurable Interrupt and Callback assignment on USB events like SOF, Bus Reset, EP0 Setup and EP0 transaction. 50 * * Configurable USB device address. 51 * * Configurable USB Endpoints (except for Endpoint 0) 52 * 53 * \section section_usb_dev_quickstart Quick Start 54 * \ref cyhal_usb_dev_init can be used for initialization of USB by providing the USBDP and USBDM pins. 55 * See \ref subsection_usb_dev_snippet_1 for the initialization code snippet. 56 * 57 * \section section_usb_dev_snippets Code snippets 58 * 59 * \subsection subsection_usb_dev_snippet_1 Snippet 1: USB Device Initialization 60 * The following section initializes the USB Device and assigns the USBDM and USBDP pins using 61 * \ref cyhal_usb_dev_init. The clock parameter <b>clk</b> is optional and need not be provided (NULL), 62 * to generate and use an available clock resource with a default frequency. The device can be made 63 * physically visible to the USB Host by using \ref cyhal_usb_dev_connect 64 * 65 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_init 66 * 67 * 68 * \subsection subsection_usb_dev_snippet_2 Snippet 2: Handling USB Event Completion 69 * USB events (see \ref cyhal_usb_dev_event_t) like Bus Reset, EP0 transaction, EP0 Setup can be mapped to an interrupt and assigned 70 * a callback function. The callback function needs to be first registered using 71 * \ref cyhal_usb_dev_register_event_callback. Use different callback functions to handle events individually. 72 * 73 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_event 74 * 75 * 76 * \subsection subsection_usb_dev_snippet_3 Snippet 3: Custom USB Interrupt Handler 77 * The following section illustrates how to set up the IRQ interrupt handler for USB device. Inside the handler 78 * \ref cyhal_usb_dev_process_irq has been used to process the interrupts. 79 * 80 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_irq 81 * 82 * 83 * \subsection subsection_usb_dev_snippet_4 Snippet 4: Adding an Endpoint and Handling its Interrupts 84 * The following section shows how to add endpoint to the USB device and configure the endpoint using 85 * \ref cyhal_usb_dev_endpoint_add. The interrupts associated with the endpoints are handled by a 86 * callback function registered using \ref cyhal_usb_dev_register_endpoint_callback. 87 * The endpoint can also be configured using <a href="https://www.cypress.com/ModusToolboxUSBConfig">ModusToolbox™ USB Configurator</a> 88 * 89 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_endpoint 90 */ 91 92 #pragma once 93 94 #include <stdint.h> 95 #include <stdbool.h> 96 #include "cy_result.h" 97 #include "cyhal_hw_types.h" 98 99 #if defined(__cplusplus) 100 extern "C" { 101 #endif 102 103 /** \addtogroup group_hal_results_usbdev USB Device HAL Results 104 * USB Device specific return codes 105 * \ingroup group_hal_results 106 * \{ *//** 107 */ 108 109 /** The usb error */ 110 #define CYHAL_USB_DEV_RSLT_ERR \ 111 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 0)) 112 /** The driver configuration is not supported by the HAL */ 113 #define CYHAL_USB_DEV_RSLT_ERR_BAD_DRV_CFG \ 114 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 1)) 115 /** The configuration of USB clock failed */ 116 #define CYHAL_USB_DEV_RSLT_ERR_CLK_CFG \ 117 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 2)) 118 119 /** 120 * \} 121 */ 122 123 /** 124 * \addtogroup group_hal_usb_dev_endpoint Endpoint 125 * \{ 126 * APIs relating to endpoint management 127 */ 128 129 /** Returns true if endpoint direction is IN */ 130 #define CYHAL_USB_DEV_IS_IN_EP(endpoint) (0U != (0x80U & (uint32_t) (endpoint))) 131 132 /** Returns endpoint number (type uint32_t) */ 133 #define CYHAL_USB_DEV_GET_EP_NUM(endpoint) ((uint32_t) (endpoint) & 0x0FU) 134 135 /** Returns endpoint index (type uint32_t) */ 136 #define CYHAL_USB_DEV_GET_EP_IDX(endpoint) (CYHAL_USB_DEV_GET_EP_NUM(endpoint) - 1U) 137 138 /** USB Device Endpoints types */ 139 typedef enum 140 { 141 CYHAL_USB_DEV_EP_TYPE_CTRL = 0, 142 CYHAL_USB_DEV_EP_TYPE_ISO = 1, 143 CYHAL_USB_DEV_EP_TYPE_BULK = 2, 144 CYHAL_USB_DEV_EP_TYPE_INT = 3 145 } cyhal_usb_dev_ep_type_t; 146 147 /** \} group_hal_usb_dev_endpoint */ 148 149 150 /** 151 * \addtogroup group_hal_usb_dev_common Common 152 * \{ 153 */ 154 155 /** Service Callback Events */ 156 typedef enum 157 { 158 CYHAL_USB_DEV_EVENT_BUS_RESET, /**< Callback hooked to bus reset interrupt */ 159 CYHAL_USB_DEV_EVENT_EP0_SETUP, /**< Callback hooked to endpoint 0 SETUP packet interrupt */ 160 CYHAL_USB_DEV_EVENT_EP0_IN, /**< Callback hooked to endpoint 0 IN packet interrupt */ 161 CYHAL_USB_DEV_EVENT_EP0_OUT, /**< Callback hooked to endpoint 0 OUT packet interrupt */ 162 } cyhal_usb_dev_event_t; 163 164 165 /** 166 * USB endpoint address (consists from endpoint number and direction) 167 */ 168 typedef uint8_t cyhal_usb_dev_ep_t; 169 170 /** 171 * Callback handler for USB Device interrupt 172 */ 173 typedef void (*cyhal_usb_dev_irq_callback_t)(void); 174 175 /** 176 * Callback handler for the transfer completion event for data endpoints (not applicable for endpoint 0) 177 */ 178 typedef void (* cyhal_usb_dev_endpoint_callback_t)(cyhal_usb_dev_ep_t endpoint); 179 180 /** Callback handler for the events for USB Device */ 181 typedef void (*cyhal_usb_dev_event_callback_t)(void); 182 183 /** Callback handler for the events for USB Device */ 184 typedef void (*cyhal_usb_dev_sof_callback_t)(uint32_t frame_number); 185 186 187 /** 188 * Initialize the USB instance. 189 * 190 * @param[out] obj Pointer to a USB object. The caller must allocate the 191 * memory for this object but the init function will initialize its contents. 192 * @param[in] dp The D+ pin to initialize 193 * @param[in] dm The D- pin to initialize 194 * @param[in] clk The clock to use can be shared, if not provided a new clock will be allocated 195 * 196 * @return The status of the initialization request 197 */ 198 cy_rslt_t cyhal_usb_dev_init(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm, const cyhal_clock_t *clk); 199 200 /** 201 * Power down the USB instance 202 * 203 * Disable interrupts and stop sending events. 204 * 205 * @param[in,out] obj The USB device object 206 */ 207 void cyhal_usb_dev_free(cyhal_usb_dev_t *obj); 208 209 /** 210 * Make the USB device visible to the USB host 211 * 212 * Enable either the D+ or D- pull-up so the host can detect 213 * the presence of this device. 214 * 215 * @param[in,out] obj The USB device object 216 */ 217 void cyhal_usb_dev_connect(cyhal_usb_dev_t *obj); 218 219 /** 220 * Detach the USB device 221 * 222 * Disable the D+ and D- pull-up and stop responding to 223 * USB traffic. 224 * 225 * @param[in,out] obj The USB device object 226 */ 227 void cyhal_usb_dev_disconnect(cyhal_usb_dev_t *obj); 228 229 /** 230 * Suspend the USB phy. This allows the device to enter deepsleep. 231 * Any data left any USB EP buffers will be lost, when device go into deepsleep. 232 * Call \ref cyhal_usb_dev_resume to resume USB from deepsleep. 233 * 234 * @param[in] obj The usb device object 235 */ 236 void cyhal_usb_dev_suspend(cyhal_usb_dev_t *obj); 237 238 /** 239 * Resume the USB phy from a suspended state. \see cyhal_usb_dev_suspend 240 * 241 * @param[in] obj The usb device object 242 */ 243 void cyhal_usb_dev_resume(cyhal_usb_dev_t *obj); 244 245 /** 246 * Set this device to the configured state 247 * 248 * Enable added endpoints if they are not enabled 249 * already. 250 * 251 * @param[in,out] obj The USB device object 252 */ 253 void cyhal_usb_dev_set_configured(cyhal_usb_dev_t *obj); 254 255 /** 256 * Leave the configured state 257 * 258 * This is a notification to the USBPhy indicating that the device 259 * is leaving the configured state. The USBPhy can disable all 260 * endpoints other than endpoint 0. 261 * 262 * @param[in,out] obj The USB device object 263 */ 264 void cyhal_usb_dev_set_unconfigured(cyhal_usb_dev_t *obj); 265 266 /** 267 * Configure start of frame interrupt enablement. 268 * 269 * @param[in,out] obj The USB device object 270 * @param[in] enable True to turn on interrupt and start calling sof callback on every frame, 271 * False to turn off interrupt and stop calling sof callback. 272 */ 273 void cyhal_usb_dev_sof_enable(cyhal_usb_dev_t *obj, bool enable); 274 275 /** 276 * Set the USBPhy's address 277 * 278 * @param[in,out] obj The USB device object 279 * @param[in] address This device's USB address 280 */ 281 void cyhal_usb_dev_set_address(cyhal_usb_dev_t *obj, uint8_t address); 282 283 /** \} group_hal_usb_dev_common */ 284 285 /** 286 * \addtogroup group_hal_usb_dev_ep0 EP0 287 * \{ 288 * APIs relating specifically to management of endpoint zero 289 */ 290 291 /** 292 * Get wMaxPacketSize of endpoint 0. 293 * The endpoint 0 has dedicated buffer. 294 * 295 * @param[in,out] obj The USB device object 296 * 297 * @return The size allocated for endpoint 0 298 */ 299 uint32_t cyhal_usb_dev_ep0_get_max_packet(cyhal_usb_dev_t *obj); 300 301 /** 302 * Read the contents of the SETUP packet 303 * 304 * @param[in,out] obj The USB device object 305 * @param[in] buffer Buffer to fill with data 306 * @param[in] size Size of buffer passed in 307 */ 308 void cyhal_usb_dev_ep0_setup_read_result(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size); 309 310 /** 311 * Start receiving a packet of up to wMaxPacketSize on endpoint 0 312 * 313 * @param[in,out] obj The USB device object 314 * @param[in] buffer Buffer to fill with the data read 315 * @param[in] size Size of buffer 316 */ 317 void cyhal_usb_dev_ep0_read(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size); 318 319 /** 320 * Read the contents of a received packet 321 * 322 * @param[in,out] obj The USB device object 323 * 324 * @return Actual number of bytes that was read 325 */ 326 uint32_t cyhal_usb_dev_ep0_read_result(cyhal_usb_dev_t *obj); 327 328 /** 329 * Write a packet on endpoint 0 330 * 331 * @param[in,out] obj The USB device object 332 * @param[in] buffer Buffer fill with data to send 333 * @param[in] size Size of data to send 334 * 335 * @return The number of bytes that were written. 336 */ 337 uint32_t cyhal_usb_dev_ep0_write(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size); 338 339 /** 340 * Protocol stall on endpoint 0. 341 * Stall all IN and OUT packets on endpoint 0 until a SETUP packet is received. 342 * 343 * @param[in,out] obj The USB device object 344 * 345 * @note The stall is cleared automatically when a setup packet is received 346 */ 347 void cyhal_usb_dev_ep0_stall(cyhal_usb_dev_t *obj); 348 349 /** \} group_hal_usb_dev_ep0 */ 350 351 /** 352 * \addtogroup group_hal_usb_dev_endpoint 353 * \{ 354 */ 355 356 /** 357 * Configure an endpoint. 358 * 359 * @param[in,out] obj The USB device object 360 * @param[in] alloc True to allocates buffer for the endpoint, false to skip allocation 361 * @param[in] enable True to enable endpoint operation, false to skip enablement 362 * @param[in] endpoint Endpoint to configure and enable 363 * @param[in] max_packet The maximum packet size that can be sent or received 364 * @param[in] type The type of endpoint (does not care when enable parameter is false) 365 * 366 * @return The status of the endpoint add request 367 * 368 * @note 369 * - This function cannot be used to configure endpoint 0. That must be done 370 * with cyhal_usb_dev_ep0_get_max_packet. 371 * - After endpoint was enabled it must be removed with cyhal_usb_dev_endpoint_remove 372 * and then enabled again. 373 */ 374 cy_rslt_t cyhal_usb_dev_endpoint_add(cyhal_usb_dev_t *obj, bool alloc, bool enable ,cyhal_usb_dev_ep_t endpoint, uint32_t max_packet, cyhal_usb_dev_ep_type_t type); 375 376 /** 377 * Disable an endpoint 378 * 379 * @param[in,out] obj The USB device object 380 * @param[in] endpoint Endpoint to disable 381 * 382 * @return The status of the endpoint remove request 383 */ 384 cy_rslt_t cyhal_usb_dev_endpoint_remove(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint); 385 386 /** 387 * Perform a functional stall on the given endpoint 388 * 389 * Set the HALT feature for this endpoint so that all further 390 * communication is aborted. 391 * 392 * @param[in,out] obj The USB device object 393 * @param[in] endpoint Endpoint to stall 394 * 395 * @return The status of the endpoint stall request 396 */ 397 cy_rslt_t cyhal_usb_dev_endpoint_stall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint); 398 399 /** 400 * Unstall the endpoint 401 * 402 * Clear the HALT feature on this endpoint so communication can 403 * resume. 404 * 405 * @param[in,out] obj The USB device object 406 * @param[in] endpoint Endpoint to stall 407 * 408 * @return The status of the endpoint unstall request 409 */ 410 cy_rslt_t cyhal_usb_dev_endpoint_unstall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint); 411 412 /** 413 * Return the endpoint stall state 414 * 415 * @param[in,out] obj The USB device object 416 * @param[in] endpoint Endpoint to check stall state 417 * 418 * @return True if endpoint stalled, false otherwise. 419 */ 420 bool cyhal_usb_dev_endpoint_is_stalled(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint); 421 422 /** 423 * Start a read on the given endpoint 424 * 425 * @param[in,out] obj The USB device object 426 * @param[in] endpoint Endpoint to start the read on 427 * @param[in] data Buffer to fill with data 428 * @param[in] size Size of the read buffer. This must be at least 429 * the max packet size for this endpoint. 430 * 431 * @return The status of start a read operation 432 */ 433 cy_rslt_t cyhal_usb_dev_endpoint_read(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t *data, uint32_t size); 434 435 /** 436 * Finish a read on the given endpoint 437 * 438 * @param[in,out] obj The USB device object 439 * @param[in] endpoint Endpoint to check 440 * @param[out] act_size Actual number of bytes that was read 441 * 442 * @return The status of a finish read 443 */ 444 cy_rslt_t cyhal_usb_dev_endpoint_read_result(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint32_t *act_size); 445 446 /** 447 * Start a write on the given endpoint 448 * 449 * @param[in,out] obj The USB device object 450 * @param[in] endpoint Endpoint to write to 451 * @param[in] data Buffer to write 452 * @param[in] size Size of data to write 453 * 454 * @return The status of a write request 455 */ 456 cy_rslt_t cyhal_usb_dev_endpoint_write(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t const *data, uint32_t size); 457 458 /** 459 * Abort the current transfer if it has not yet been sent 460 * 461 * @param[in,out] obj The USB device object 462 * @param[in] endpoint Endpoint to abort the transfer on. It is implementation defined 463 * if this function has an effect on receive endpoints. 464 * 465 * @return The status of an abort request 466 * 467 * @note 468 * For the ISOC endpoints in pending state this function does not wait for 469 * bus activity completion because these endpoints do not have handshake and are 470 * always accessible to the Host. Therefore it is safe to call this function for 471 * ISOC endpoint when the Host will not access them during abort. 472 */ 473 cy_rslt_t cyhal_usb_dev_endpoint_abort(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint); 474 475 /** \} group_hal_usb_dev_endpoint */ 476 477 /** 478 * \addtogroup group_hal_usb_dev_common Common 479 * \{ 480 */ 481 482 /** Register a USB Device callback handler 483 * 484 * This function will be called when the USB interrupt is triggered. This interrupt can be 485 * enabled or disabled using \ref cyhal_usb_dev_irq_enable. 486 * 487 * @param[in,out] obj The USB device object 488 * @param[in] callback The event handler function which will be invoked when the event fires 489 * 490 * @return The status of the register_irq_callback request 491 */ 492 cy_rslt_t cyhal_usb_dev_register_irq_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_irq_callback_t callback); 493 494 /** 495 * Configure USB Device event enablement. 496 * 497 * When the interrupt is enabled and triggered, the function specified by \ref cyhal_usb_dev_register_irq_callback will be called. 498 * 499 * @param[in,out] obj The usb device object 500 * @param[in] enable True to turn on events, False to turn off 501 */ 502 void cyhal_usb_dev_irq_enable(cyhal_usb_dev_t *obj, bool enable); 503 504 /** 505 * Default USB Device interrupt handler. 506 * 507 * @param[in,out] obj The USB device object 508 */ 509 void cyhal_usb_dev_process_irq(cyhal_usb_dev_t *obj); 510 511 /** 512 * The USB Device endpoint complete callback handler registration 513 * 514 * @param[in,out] obj The USB device object 515 * @param[in] endpoint Endpoint to registers handler 516 * @param[in] callback The callback handler which will be invoked when the endpoint comp 517 * 518 * \ingroup group_hal_usb_dev_endpoint 519 */ 520 void cyhal_usb_dev_register_endpoint_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, cyhal_usb_dev_endpoint_callback_t callback); 521 522 /** 523 * The USB Device event complete callback handler registration. The events are defined by x type. 524 * 525 * @param[in,out] obj The USB device object 526 * @param[in] event The event that triggers the callback, see \ref cyhal_usb_dev_event_t 527 * @param[in] callback The callback handler which will be invoked when the interrupt fires 528 */ 529 void cyhal_usb_dev_register_event_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_event_t event, cyhal_usb_dev_event_callback_t callback); 530 531 /** 532 * The USB Device start of frame (SOF) complete callback handler registration. 533 * 534 * @param[in,out] obj The USB device object 535 * @param[in] callback The callback handler which will be invoked when the interrupt fires 536 */ 537 void cyhal_usb_dev_register_sof_callback( cyhal_usb_dev_t *obj, cyhal_usb_dev_sof_callback_t callback); 538 539 /** \} group_hal_usb_dev_common */ 540 541 #if defined(__cplusplus) 542 } 543 #endif 544 545 #ifdef CYHAL_USB_DEV_IMPL_HEADER 546 #include CYHAL_USB_DEV_IMPL_HEADER 547 #endif /* CYHAL_USB_DEV_IMPL_HEADER */ 548 549 /** \} group_hal_usb_dev */ 550