| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895 |
- /* --------------------------------------------------------------------------
- * Copyright (c) 2013-2016 ARM Limited. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * $Date: 02. March 2016
- * $Revision: V2.9
- *
- * Driver: Driver_USBD0
- * Configured: via RTE_Device.h configuration file
- * Project: USB Device Driver for NXP LPC18xx
- * --------------------------------------------------------------------------
- * Use the following configuration settings in the middleware component
- * to connect to this driver.
- *
- * Configuration Setting Value
- * --------------------- -----
- * Connect to hardware via Driver_USBD# = 0
- * --------------------------------------------------------------------------
- * Defines used for driver configuration (at compile time):
- *
- * USBD_MAX_ENDPOINT_NUM: defines maximum number of IN/OUT Endpoint pairs
- * that driver will support with Control Endpoint 0
- * not included, this value impacts driver memory
- * requirements
- * - default value: 5
- * - maximum value: 5
- * -------------------------------------------------------------------------- */
- /* History:
- * Version 2.9
- * Removed unnecessary __packed specifier for structures dQH_t and dTD_t
- * Version 2.8
- * Corrected PowerControl function for conditional Power full (driver must be initialized)
- * Version 2.7
- * PowerControl for Power OFF and Uninitialize functions made unconditional
- * Version 2.6
- * Corrected isochronous endpoint configuration
- * Corrected transfer procedure
- * Version 2.5
- * Corrected isochronous transfer functionality
- * Version 2.4
- * Corrected CLK_M3_USB1_CFG into CLK_M3_USB0_CFG in USBD_PowerControl
- * function
- * Version 2.3
- * Corrected PORTSC1_D_PFSC into USB_PORTSC1_D_PFSC
- * Version 2.2
- * Corrected return value in USBD_PowerControl function.
- * Version 2.1
- * Added USB_LPC18xx_USB0.h with register bit definitions
- * Pin configuration moved to USB_LPC18xx.c
- * Version 2.0
- * Updated to 2.00 API
- * Version 1.3
- * Re-implementation of the driver
- * Version 1.2
- * Updated USB1 pin configurations
- * Version 1.1
- * Based on API V1.10 (namespace prefix ARM_ added)
- * Version 1.0
- * Initial release
- */
- #include <stdint.h>
- #include <string.h>
- #include "Driver_USBD.h"
- #include "LPC18xx.h"
- #include "USB_LPC18xx.h"
- #include "RTE_Device.h"
- #include "RTE_Components.h"
- #if (RTE_USB_USB0 == 0)
- #error "USB0 is not enabled in the RTE_Device.h!"
- #endif
- #ifndef USBD_MAX_ENDPOINT_NUM
- #define USBD_MAX_ENDPOINT_NUM 5U
- #endif
- #if (USBD_MAX_ENDPOINT_NUM > 5)
- #error Too many Endpoints, maximum IN/OUT Endpoint pairs that this driver supports is 5 !!!
- #endif
- extern uint8_t USB0_role;
- extern uint8_t USB0_state;
- extern void USB0_PinsConfigure (void);
- extern void USB0_PinsUnconfigure (void);
- // USBD Driver *****************************************************************
- #define ARM_USBD_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2,9)
- // Driver Version
- static const ARM_DRIVER_VERSION usbd_driver_version = { ARM_USBD_API_VERSION, ARM_USBD_DRV_VERSION };
- // Driver Capabilities
- static const ARM_USBD_CAPABILITIES usbd_driver_capabilities = {
- 0U, // VBUS Detection
- 0U, // Event VBUS On
- 0U // Event VBUS Off
- };
- #define LPC_USBx LPC_USB0
- #define ENDPTCTRL(ep_num) (*(volatile uint32_t *)((uint32_t)(&LPC_USBx->ENDPTCTRL0) + 4U * ep_num))
- #define EP_NUM(ep_addr) (ep_addr & ARM_USB_ENDPOINT_NUMBER_MASK)
- #define EP_DIR(ep_addr) ((ep_addr >> 7) & 1U)
- #define EP_SLL(ep_addr) (EP_DIR(ep_addr) * 16U)
- #define EP_IDX(ep_addr) ((EP_NUM(ep_addr) * 2U) + ((ep_addr >> 7) & 1U))
- #define EP_MSK(ep_addr) (1UL << (EP_NUM(ep_addr) + EP_SLL(ep_addr)))
- typedef struct { // USB Device Endpoint Queue Head
- uint32_t cap;
- uint32_t curr_dTD;
- uint32_t next_dTD;
- uint32_t dTD_token;
- uint32_t buf[5];
- uint32_t reserved;
- uint32_t setup[2];
- // Use reminder of 64 bytes for transfer information
- uint8_t *data;
- uint32_t num;
- uint32_t num_transferred_total;
- uint16_t num_transferring;
- uint8_t ep_type;
- uint8_t ep_active;
- } dQH_t;
- typedef struct { // USB Device Endpoint Transfer Descriptor
- uint32_t next_dTD;
- uint32_t dTD_token;
- uint32_t buf[5];
- uint32_t reserved;
- } dTD_t;
- static ARM_USBD_SignalDeviceEvent_t SignalDeviceEvent;
- static ARM_USBD_SignalEndpointEvent_t SignalEndpointEvent;
- static ARM_USBD_STATE usbd_state;
- static uint32_t setup_packet[2]; // Setup packet data
- static volatile uint8_t setup_received; // Setup packet received
- static dQH_t __align(2048) dQH[(USBD_MAX_ENDPOINT_NUM + 1U) * 2U]; // Queue Heads
- static dTD_t __align( 32) dTD[(USBD_MAX_ENDPOINT_NUM + 1U) * 2U]; // Transfer Descriptors
- // Function prototypes
- static int32_t USBD_EndpointConfigure (uint8_t ep_addr, uint8_t ep_type, uint16_t ep_max_packet_size);
- // Auxiliary functions
- /**
- \fn void USBD_HW_EndpointFlush (uint8_t ep_addr)
- \brief Flush Endpoint.
- */
- static void USBD_HW_EndpointFlush (uint8_t ep_addr) {
- uint32_t ep_msk;
- ep_msk = EP_MSK(ep_addr);
- LPC_USBx->ENDPTFLUSH = ep_msk;
- while (LPC_USBx->ENDPTFLUSH & ep_msk);
- }
- /**
- \fn void USBD_Reset (void)
- \brief Reset USB Endpoint settings and variables.
- */
- static void USBD_Reset (void) {
- uint8_t i;
- // Reset global variables
- setup_packet[0] = 0U;
- setup_packet[1] = 0U;
- setup_received = 0U;
- memset((void *)&usbd_state, 0, sizeof(usbd_state));
- memset((void *)dQH, 0, sizeof(dQH));
- memset((void *)dTD, 0, sizeof(dTD));
- for (i = 1U; i <= USBD_MAX_ENDPOINT_NUM; i++) {
- ENDPTCTRL(i) &= ~(USB_ENDPTCTRL_RXE | USB_ENDPTCTRL_TXE);
- }
- // Clear interrupts
- LPC_USBx->ENDPTNAK = 0xFFFFFFFFUL;
- LPC_USBx->ENDPTNAKEN = 0U;
- LPC_USBx->USBSTS_D = 0xFFFFFFFFUL;
- LPC_USBx->ENDPTSETUPSTAT = LPC_USBx->ENDPTSETUPSTAT;
- LPC_USBx->ENDPTCOMPLETE = LPC_USBx->ENDPTCOMPLETE;
- while (LPC_USBx->ENDPTPRIME);
- // Clear all Primed buffers
- LPC_USBx->ENDPTFLUSH = 0xFFFFFFFFUL;
- while (LPC_USBx->ENDPTFLUSH);
- // Interrupt threshold control: no threshold
- LPC_USBx->USBCMD_D &= ~(USB_USBCMD_D_ITC(0xFFUL));
- // Default Initialize Control Endpoint 0
- if (usbd_state.speed == ARM_USB_SPEED_HIGH) { // For High-speed
- USBD_EndpointConfigure (0x00U, ARM_USB_ENDPOINT_CONTROL, 64U);
- USBD_EndpointConfigure (0x80U, ARM_USB_ENDPOINT_CONTROL, 64U);
- } else { // For Full/Low-speed
- USBD_EndpointConfigure (0x00U, ARM_USB_ENDPOINT_CONTROL, 8U);
- USBD_EndpointConfigure (0x80U, ARM_USB_ENDPOINT_CONTROL, 8U);
- }
- // Set start of endpoint list address
- LPC_USBx->ENDPOINTLISTADDR = (uint32_t)dQH;
- // Setup lockouts off
- LPC_USBx->USBMODE_D |= USB_USBMODE_D_SLOM;
- }
- /**
- \fn void USBD_HW_ReadSetupPacket (void)
- \brief Read Setup Packet to buffer.
- */
- static void USBD_HW_ReadSetupPacket (void) {
- do {
- LPC_USBx->USBCMD_D |= USB_USBCMD_D_SUTW; // Setup trip wire
- // Copy Setup Packet Data to buffer
- setup_packet[0] = dQH[0].setup[0];
- setup_packet[1] = dQH[0].setup[1];
- } while (!(LPC_USBx->USBCMD_D & LPC_USBx->USBCMD_D));
- LPC_USBx->USBCMD_D &= ~USB_USBCMD_D_SUTW; // Clear Setup trip wire
- LPC_USBx->ENDPTSETUPSTAT = 1U; // Clear Setup bit
- }
- /**
- \fn void USBD_HW_EndpointTransfer (uint8_t ep_addr)
- \brief Start transfer on Endpoint.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- */
- static void USBD_HW_EndpointTransfer (uint8_t ep_addr) {
- dQH_t *ptr_dqh;
- dTD_t *ptr_dtd;
- uint8_t *data;
- uint32_t ep_msk, num;
- uint8_t ep_idx;
- ep_idx = EP_IDX(ep_addr);
- ep_msk = EP_MSK(ep_addr);
- ptr_dqh = &dQH[ep_idx];
- ptr_dtd = &dTD[ep_idx];
- data = ptr_dqh->data + ptr_dqh->num_transferred_total;
- num = ptr_dqh->num - ptr_dqh->num_transferred_total;
- if (num > 0x4000U) { num = 0x4000U; } // Maximum transfer length is 16k
- while (LPC_USBx->ENDPTSTAT & ep_msk);
- memset (ptr_dtd, 0, sizeof(dTD_t));
- // Driver does not support linked endpoint descriptors
- // Next link pointer is not valid
- ptr_dtd->next_dTD = 1U;
- // Configure Transfer Descriptor
- ptr_dtd->dTD_token |= USB_bTD_TOKEN_TOTAL_BYTES(num) | // Bytes to transfer
- USB_bTD_TOKEN_IOC | // Interrupt on complete
- USB_bTD_TOKEN_STATUS_ACTIVE ; // Transfer Active
- // Set Buffer Addresses
- ptr_dtd->buf[0] = (uint32_t)(data );
- ptr_dtd->buf[1] = (uint32_t)(data + 0x1000U);
- ptr_dtd->buf[2] = (uint32_t)(data + 0x2000U);
- ptr_dtd->buf[3] = (uint32_t)(data + 0x3000U);
- ptr_dtd->buf[4] = (uint32_t)(data + 0x4000U);
- ptr_dqh->dTD_token &= ~USB_bTD_TOKEN_STATUS_MSK; // Clear status
- ptr_dqh->next_dTD = (uint32_t)(ptr_dtd); // Save Transfer Descriptor address to Queue Head overlay
- ptr_dqh->num_transferring = num;
- LPC_USBx->ENDPTPRIME |= ep_msk; // Prime Endpoint -> Start Transfer
- }
- // USBD Driver functions
- /**
- \fn ARM_DRIVER_VERSION USBD_GetVersion (void)
- \brief Get driver version.
- \return \ref ARM_DRIVER_VERSION
- */
- static ARM_DRIVER_VERSION USBD_GetVersion (void) { return usbd_driver_version; }
- /**
- \fn ARM_USBD_CAPABILITIES USBD_GetCapabilities (void)
- \brief Get driver capabilities.
- \return \ref ARM_USBD_CAPABILITIES
- */
- static ARM_USBD_CAPABILITIES USBD_GetCapabilities (void) { return usbd_driver_capabilities; }
- /**
- \fn int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event,
- ARM_USBD_SignalEndpointEvent_t cb_endpoint_event)
- \brief Initialize USB Device Interface.
- \param[in] cb_device_event Pointer to \ref ARM_USBD_SignalDeviceEvent
- \param[in] cb_endpoint_event Pointer to \ref ARM_USBD_SignalEndpointEvent
- \return \ref execution_status
- */
- static int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event,
- ARM_USBD_SignalEndpointEvent_t cb_endpoint_event) {
- if ((USB0_state & USBD_DRIVER_INITIALIZED) != 0U) { return ARM_DRIVER_OK; }
- SignalDeviceEvent = cb_device_event;
- SignalEndpointEvent = cb_endpoint_event;
- USB0_role = ARM_USB_ROLE_DEVICE;
- USB0_PinsConfigure ();
- USB0_state = USBD_DRIVER_INITIALIZED;
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_Uninitialize (void)
- \brief De-initialize USB Device Interface.
- \return \ref execution_status
- */
- static int32_t USBD_Uninitialize (void) {
- USB0_PinsUnconfigure ();
- USB0_role = ARM_USB_ROLE_NONE;
- USB0_state &= ~USBD_DRIVER_INITIALIZED;
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_PowerControl (ARM_POWER_STATE state)
- \brief Control USB Device Interface Power.
- \param[in] state Power state
- \return \ref execution_status
- */
- static int32_t USBD_PowerControl (ARM_POWER_STATE state) {
- switch (state) {
- case ARM_POWER_OFF:
- NVIC_DisableIRQ (USB0_IRQn); // Disable interrupt
- NVIC_ClearPendingIRQ (USB0_IRQn); // Clear pending interrupt
- USB0_state &= ~USBD_DRIVER_POWERED; // Clear powered flag
- // Reset variables
- setup_received = 0U;
- memset((void *)&usbd_state, 0, sizeof(usbd_state));
- memset((void *)dQH, 0, sizeof(dQH));
- memset((void *)dTD, 0, sizeof(dTD));
- if ((LPC_CGU->BASE_USB0_CLK & 1U) == 0U) {
- LPC_CREG->CREG0 |= (1U << 5); // Disable USB0 PHY
- LPC_CCU1->CLK_USB0_CFG &= ~1U; // Disable USB0 Base Clock
- while (LPC_CCU1->CLK_USB0_STAT & 1U);
- LPC_CCU1->CLK_M3_USB0_CFG &= ~1U; // Disable USB0 Register Interface Clock
- while (LPC_CCU1->CLK_M3_USB0_STAT & 1U);
- LPC_CGU->BASE_USB0_CLK = 1U; // Disable Base Clock
- }
- break;
- case ARM_POWER_FULL:
- if ((USB0_state & USBD_DRIVER_INITIALIZED) == 0U) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) != 0U) { return ARM_DRIVER_OK; }
- LPC_CGU->BASE_USB0_CLK = (0x01U << 11) | // Auto-block Enable
- (0x07U << 24) ; // Clock source: PLL0USB
- LPC_CCU1->CLK_M3_USB0_CFG |= 1U; // Enable USB0 Register Interface Clock
- while (!(LPC_CCU1->CLK_M3_USB0_STAT & 1U));
- LPC_CCU1->CLK_USB0_CFG |= 1U; // Enable USB0 Base Clock
- while (!(LPC_CCU1->CLK_USB0_STAT & 1U));
- // Reset USB Controller
- LPC_USBx->USBCMD_D = USB_USBCMD_D_RST;
- while ((LPC_USBx->USBCMD_D & (USB_USBCMD_D_RS | USB_USBCMD_D_RST)) != 0U);
- // Force device mode and set Setup lockouts off
- LPC_USBx->USBMODE_D = USB_USBMODE_D_CM1_0(2U) | USB_USBMODE_D_SLOM;
- LPC_CREG->CREG0 &= ~(1U << 5); // Enable USB0 PHY
- USBD_Reset (); // Reset variables and endpoint settings
- #if (RTE_USB_USB0_HS_EN)
- LPC_USBx->PORTSC1_D &= ~USB_PORTSC1_D_PFSC;
- #else
- LPC_USBx->PORTSC1_D |= USB_PORTSC1_D_PFSC;
- #endif
- // Configure OTG Register
- LPC_USBx->OTGSC = USB_OTGSC_VD | // VBUS discharge
- USB_OTGSC_OT ; // OTG termination
- // Enable interrupts
- LPC_USBx->USBINTR_D = (USB_USBINTR_D_UE | // USB interrupt enable
- USB_USBINTR_D_PCE | // Port change detect interrupt enable
- USB_USBINTR_D_SLE | // Suspend interrupt enable
- USB_USBINTR_D_URE); // Reset interrupt enable
- USB0_state |= USBD_DRIVER_POWERED; // Set powered flag
- NVIC_EnableIRQ (USB0_IRQn); // Enable interrupt
- break;
- default:
- return ARM_DRIVER_ERROR_UNSUPPORTED;
- }
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_DeviceConnect (void)
- \brief Connect USB Device.
- \return \ref execution_status
- */
- static int32_t USBD_DeviceConnect (void) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- LPC_USBx->USBCMD_D |= USB_USBCMD_D_RS; // Attach Device
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_DeviceDisconnect (void)
- \brief Disconnect USB Device.
- \return \ref execution_status
- */
- static int32_t USBD_DeviceDisconnect (void) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- LPC_USBx->USBCMD_D &= ~USB_USBCMD_D_RS; // Detach Device
- #if (RTE_USB0_IND0_PIN_EN)
- LPC_USBx->PORTSC1_D &= ~USB_PORTSC1_D_PIC1_0(1); // Clear indicator LED0
- #endif
- return ARM_DRIVER_OK;
- }
- /**
- \fn ARM_USBD_STATE USBD_DeviceGetState (void)
- \brief Get current USB Device State.
- \return Device State \ref ARM_USBD_STATE
- */
- static ARM_USBD_STATE USBD_DeviceGetState (void) {
- ARM_USBD_STATE dev_state = { 0U, 0U, 0U };
- uint32_t portsc1_d;
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return dev_state; }
- portsc1_d = LPC_USBx->PORTSC1_D;
- dev_state = usbd_state;
- dev_state.active = ((portsc1_d & USB_PORTSC1_D_CCS) != 0U) &&
- ((portsc1_d & USB_USBDSTS_D_SLI) == 0U) ;
- return dev_state;
- }
- /**
- \fn int32_t USBD_DeviceRemoteWakeup (void)
- \brief Trigger USB Remote Wakeup.
- \return \ref execution_status
- */
- static int32_t USBD_DeviceRemoteWakeup (void) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- LPC_USBx->PORTSC1_D &= ~USB_PORTSC1_D_PHCD; // Enable PHY Clock
- LPC_USBx->PORTSC1_D |= USB_PORTSC1_D_FPR; // Force Port Resume
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_DeviceSetAddress (uint8_t dev_addr)
- \brief Set USB Device Address.
- \param[in] dev_addr Device Address
- \return \ref execution_status
- */
- static int32_t USBD_DeviceSetAddress (uint8_t dev_addr) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- LPC_USBx->DEVICEADDR = (dev_addr << USB_DEVICEADDR_USBADR_POS) & USB_DEVICEADDR_USBADR_MSK;
- LPC_USBx->DEVICEADDR |= USB_DEVICEADDR_USBADRA;
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_ReadSetupPacket (uint8_t *setup)
- \brief Read setup packet received over Control Endpoint.
- \param[out] setup Pointer to buffer for setup packet
- \return \ref execution_status
- */
- static int32_t USBD_ReadSetupPacket (uint8_t *setup) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- if (setup_received == 0U) { return ARM_DRIVER_ERROR; }
- setup_received = 0U;
- memcpy(setup, setup_packet, 8);
- if (setup_received != 0U) { // If new setup packet was received while this was being read
- return ARM_DRIVER_ERROR;
- }
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_EndpointConfigure (uint8_t ep_addr,
- uint8_t ep_type,
- uint16_t ep_max_packet_size)
- \brief Configure USB Endpoint.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \param[in] ep_type Endpoint Type (ARM_USB_ENDPOINT_xxx)
- \param[in] ep_max_packet_size Endpoint Maximum Packet Size
- \return \ref execution_status
- */
- static int32_t USBD_EndpointConfigure (uint8_t ep_addr,
- uint8_t ep_type,
- uint16_t ep_max_packet_size) {
- dQH_t *ptr_dqh;
- uint32_t ep_mult;
- uint32_t ep_mps;
- uint8_t ep_num,ep_sll;
- ep_num = EP_NUM(ep_addr);
- if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- if (ptr_dqh->ep_active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
- ep_num = EP_NUM(ep_addr);
- ep_sll = EP_SLL(ep_addr);
- ep_mult = (ep_max_packet_size & ARM_USB_ENDPOINT_MICROFRAME_TRANSACTIONS_MASK) >> 11;
- ep_mps = ep_max_packet_size & ARM_USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
- // Clear Endpoint Queue Head
- memset((void *)ptr_dqh, 0, sizeof(dQH_t));
- ptr_dqh->ep_type = ep_type;
- if (ep_type == ARM_USB_ENDPOINT_ISOCHRONOUS) {
- // For isochronous endpoints number of transactions per microframe in high-speed (or frame in full-speed)
- // has to be 1 more than additional transactions per microframe for high-speed (or 1 for full-speed)
- ep_mult++;
- }
- if ((ep_mult > 1U) && (usbd_state.speed == ARM_USB_SPEED_FULL)) { ep_mult = 1U; }
- ptr_dqh->cap = ((ep_mult << USB_EPQH_CAP_MULT_POS) & USB_EPQH_CAP_MULT_MSK) |
- (USB_EPQH_CAP_MAX_PACKET_LEN(ep_mps)) |
- (USB_EPQH_CAP_ZLT) |
- ((ep_addr == 0U) * USB_EPQH_CAP_IOS);
- ptr_dqh->next_dTD = 1U;
- ptr_dqh->dTD_token = 0U;
- USBD_HW_EndpointFlush(ep_addr);
- // Clear Endpoint Control Settings
- ENDPTCTRL(ep_num) &= ~((USB_ENDPTCTRL_RXS |
- USB_ENDPTCTRL_RXT_MSK |
- USB_ENDPTCTRL_RXI |
- USB_ENDPTCTRL_RXR |
- USB_ENDPTCTRL_RXE )
- << ep_sll);
- // Set Endpoint Control Settings
- ENDPTCTRL(ep_num) |= (USB_ENDPTCTRL_RXT(ep_type) | // Endpoint Type
- USB_ENDPTCTRL_RXR | // Data Tggle Rset
- USB_ENDPTCTRL_RXE ) // Endpoint Enable
- << ep_sll;
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_EndpointUnconfigure (uint8_t ep_addr)
- \brief Unconfigure USB Endpoint.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \return \ref execution_status
- */
- static int32_t USBD_EndpointUnconfigure (uint8_t ep_addr) {
- dQH_t *ptr_dqh;
- dTD_t *ptr_dtd;
- uint8_t ep_idx, ep_num, ep_sll;
- ep_num = EP_NUM(ep_addr);
- if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- ep_idx = EP_IDX(ep_addr);
- ptr_dqh = &dQH[ep_idx];
- if (ptr_dqh->ep_active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
- ptr_dtd = &dTD[ep_idx];
- ep_sll = EP_SLL(ep_addr);
- // Clear Endpoint Control Settings
- ENDPTCTRL(ep_num) &= ~((USB_ENDPTCTRL_RXS |
- USB_ENDPTCTRL_RXT_MSK |
- USB_ENDPTCTRL_RXI |
- USB_ENDPTCTRL_RXR |
- USB_ENDPTCTRL_RXE )
- << ep_sll);
- ENDPTCTRL(ep_num) |= (USB_ENDPTCTRL_RXR << ep_sll); // Data toggle reset
- // Clear Endpoint Queue Head and Endpoint Transfer Descriptor
- memset((void *)ptr_dqh, 0, sizeof(dQH_t));
- memset((void *)ptr_dtd, 0, sizeof(dTD_t));
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_EndpointStall (uint8_t ep_addr, bool stall)
- \brief Set/Clear Stall for USB Endpoint.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \param[in] stall Operation
- - \b false Clear
- - \b true Set
- \return \ref execution_status
- */
- static int32_t USBD_EndpointStall (uint8_t ep_addr, bool stall) {
- dQH_t *ptr_dqh;
- uint8_t ep_num, ep_sll;
- ep_num = EP_NUM(ep_addr);
- if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- if (ptr_dqh->ep_active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
- ep_sll = EP_SLL(ep_addr);
- if (stall != 0U) { // Set endpoint stall
- ENDPTCTRL(ep_num) |= (USB_ENDPTCTRL_RXS << ep_sll);
- } else { // Clear endpoint stall
- ENDPTCTRL(ep_num) &= ~(USB_ENDPTCTRL_RXS << ep_sll);
- ptr_dqh->dTD_token = 0U;
- USBD_HW_EndpointFlush(ep_addr);
- ENDPTCTRL(ep_num) |= (USB_ENDPTCTRL_RXR << ep_sll); // Data toggle reset
- }
- return ARM_DRIVER_OK;
- }
- /**
- \fn int32_t USBD_EndpointTransfer (uint8_t ep_addr, uint8_t *data, uint32_t num)
- \brief Read data from or Write data to USB Endpoint.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \param[out] data Pointer to buffer for data to read or with data to write
- \param[in] num Number of data bytes to transfer
- \return \ref execution_status
- */
- static int32_t USBD_EndpointTransfer (uint8_t ep_addr, uint8_t *data, uint32_t num) {
- dQH_t *ptr_dqh;
- if (EP_NUM(ep_addr) > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- if (ptr_dqh->ep_active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
- ptr_dqh->ep_active = 1U;
- ptr_dqh->data = data;
- ptr_dqh->num = num;
- ptr_dqh->num_transferred_total = 0U;
- ptr_dqh->num_transferring = 0U;
- USBD_HW_EndpointTransfer(ep_addr); // Start transfer
- return ARM_DRIVER_OK;
- }
- /**
- \fn uint32_t USBD_EndpointTransferGetResult (uint8_t ep_addr)
- \brief Get result of USB Endpoint transfer.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \return number of successfully transferred data bytes
- */
- static uint32_t USBD_EndpointTransferGetResult (uint8_t ep_addr) {
- if (EP_NUM(ep_addr) > USBD_MAX_ENDPOINT_NUM) { return 0U; }
- return (dQH[EP_IDX(ep_addr)].num_transferred_total);
- }
- /**
- \fn int32_t USBD_EndpointTransferAbort (uint8_t ep_addr)
- \brief Abort current USB Endpoint transfer.
- \param[in] ep_addr Endpoint Address
- - ep_addr.0..3: Address
- - ep_addr.7: Direction
- \return \ref execution_status
- */
- static int32_t USBD_EndpointTransferAbort (uint8_t ep_addr) {
- dQH_t *ptr_dqh;
- uint32_t ep_msk;
- uint8_t ep_num, ep_sll;
- ep_num = EP_NUM(ep_addr);
- if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- ep_msk = EP_MSK(ep_addr);
- ep_sll = EP_SLL(ep_addr);
- USBD_HW_EndpointFlush(ep_addr);
- LPC_USBx->ENDPTCOMPLETE = ep_msk; // Clear Completed Flag
- ENDPTCTRL(ep_num) |= (USB_ENDPTCTRL_RXR << ep_sll); // Data toggle reset
- ptr_dqh->dTD_token &= ~0xFFU;
- ptr_dqh->ep_active = 0U;
- return ARM_DRIVER_OK;
- }
- /**
- \fn uint16_t USBD_GetFrameNumber (void)
- \brief Get current USB Frame Number.
- \return Frame Number
- */
- static uint16_t USBD_GetFrameNumber (void) {
- if ((USB0_state & USBD_DRIVER_POWERED) == 0U) { return 0U; }
- return ((LPC_USBx->FRINDEX_D & USB_FRINDEX_D_FRINDEX13_3_MSK) >> USB_FRINDEX_D_FRINDEX13_3_POS);
- }
- /**
- \fn void USBD0_IRQ (void)
- \brief USB0 Device Interrupt Routine (IRQ).
- */
- void USBD0_IRQ (void) {
- dQH_t *ptr_dqh;
- uint32_t sts, cmpl;
- uint16_t ep_mps, num_transferred;
- uint8_t ep_num, ep_addr;
- sts = LPC_USBx->USBSTS_D & LPC_USBx->USBINTR_D; // Read active interrupts
- cmpl = LPC_USBx->ENDPTCOMPLETE; // Read Endpoint completed status
- LPC_USBx->USBSTS_D = sts; // Clear interrupts
- LPC_USBx->ENDPTCOMPLETE = cmpl; // Clear Endpoint completed status
- if ((sts & USB_USBDSTS_D_URI) != 0U) { // Reset interrupt
- USBD_Reset();
- SignalDeviceEvent(ARM_USBD_EVENT_RESET);
- }
- if ((sts & USB_USBDSTS_D_SLI) != 0U) { // Suspend interrupt
- SignalDeviceEvent(ARM_USBD_EVENT_SUSPEND);
- #if (RTE_USB0_IND0_PIN_EN)
- LPC_USBx->PORTSC1_D &= ~USB_PORTSC1_D_PIC1_0(1); // Clear indicator LED0
- #endif
- }
- if ((sts & USB_USBDSTS_D_PCI) != 0U) { // Port change detect interrupt
- if (((LPC_USBx->PORTSC1_D & USB_PORTSC1_D_PSPD_MSK) >> USB_PORTSC1_D_PSPD_POS) == 2U) {
- usbd_state.speed = ARM_USB_SPEED_HIGH;
- SignalDeviceEvent(ARM_USBD_EVENT_HIGH_SPEED);
- } else {
- usbd_state.speed = ARM_USB_SPEED_FULL;
- }
- #if (RTE_USB0_IND0_PIN_EN)
- LPC_USBx->PORTSC1_D |= USB_PORTSC1_D_PIC1_0(1); // Set indicator LED0
- #endif
- SignalDeviceEvent(ARM_USBD_EVENT_RESUME);
- }
- if ((sts & USB_USBDSTS_D_UI) != 0U) { // USB interrupt - completed transfer
- if ((LPC_USBx->ENDPTSETUPSTAT) != 0U) { // Setup Packet Received
- USBD_HW_ReadSetupPacket();
- setup_received = 1U;
- SignalEndpointEvent(0, ARM_USBD_EVENT_SETUP);
- }
- if ((cmpl & USB_ENDPTCOMPLETE_ETCE_MSK) != 0U) { // IN Data Sent
- for (ep_num = 0U; ep_num <= USBD_MAX_ENDPOINT_NUM; ep_num++) {
- if ((cmpl & USB_ENDPTCOMPLETE_ETCE_MSK) & (1U << (ep_num + USB_ENDPTCOMPLETE_ETCE_POS))) {
- ep_addr = ep_num | ARM_USB_ENDPOINT_DIRECTION_MASK;
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- ptr_dqh->num_transferred_total += ptr_dqh->num_transferring;
- // Check if all required IN data was sent
- if (ptr_dqh->num == ptr_dqh->num_transferred_total) {
- ptr_dqh->ep_active = 0U; // Clear Endpoint busy flag
- SignalEndpointEvent(ep_addr, ARM_USBD_EVENT_IN); // Send IN event
- } else if (ptr_dqh->ep_active != 0U) {
- USBD_HW_EndpointTransfer (ep_addr); // If this was not last transfer, start next
- }
- }
- }
- }
- if ((cmpl & USB_ENDPTCOMPLETE_ERCE_MSK) != 0U) { // OUT Data Received
- for (ep_num = 0U; ep_num <= USBD_MAX_ENDPOINT_NUM; ep_num++) {
- if ((cmpl & USB_ENDPTCOMPLETE_ERCE_MSK) & (1 << ep_num)) {
- ep_addr = ep_num;
- ptr_dqh = &dQH[EP_IDX(ep_addr)];
- ep_mps = (ptr_dqh->cap & USB_EPQH_CAP_MAX_PACKET_LEN_MSK) >> USB_EPQH_CAP_MAX_PACKET_LEN_POS;
- num_transferred = ptr_dqh->num_transferring -
- ((ptr_dqh->dTD_token & USB_bTD_TOKEN_TOTAL_BYTES_MSK) >> USB_bTD_TOKEN_TOTAL_BYTES_POS);
- ptr_dqh->num_transferred_total += num_transferred;
- // Check if all OUT data was received:
- // - data terminated with ZLP or short packet or
- // - all required data received
- if (((num_transferred % ep_mps) != 0U) || (ptr_dqh->num == ptr_dqh->num_transferred_total)) {
- ptr_dqh->ep_active = 0U; // Clear Endpoint busy flag
- SignalEndpointEvent(ep_addr, ARM_USBD_EVENT_OUT); // Send OUT event
- } else if (ptr_dqh->ep_active != 0U) {
- USBD_HW_EndpointTransfer (ep_addr); // If this was not last transfer, start next
- }
- }
- }
- }
- }
- }
- ARM_DRIVER_USBD Driver_USBD0 = {
- USBD_GetVersion,
- USBD_GetCapabilities,
- USBD_Initialize,
- USBD_Uninitialize,
- USBD_PowerControl,
- USBD_DeviceConnect,
- USBD_DeviceDisconnect,
- USBD_DeviceGetState,
- USBD_DeviceRemoteWakeup,
- USBD_DeviceSetAddress,
- USBD_ReadSetupPacket,
- USBD_EndpointConfigure,
- USBD_EndpointUnconfigure,
- USBD_EndpointStall,
- USBD_EndpointTransfer,
- USBD_EndpointTransferGetResult,
- USBD_EndpointTransferAbort,
- USBD_GetFrameNumber
- };
|