usb device

Committer:
ppo
Date:
Sat May 14 17:24:10 2022 +0000
Revision:
0:c1e89c49eae5
commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ppo 0:c1e89c49eae5 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
ppo 0:c1e89c49eae5 2 *
ppo 0:c1e89c49eae5 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ppo 0:c1e89c49eae5 4 * and associated documentation files (the "Software"), to deal in the Software without
ppo 0:c1e89c49eae5 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
ppo 0:c1e89c49eae5 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
ppo 0:c1e89c49eae5 7 * Software is furnished to do so, subject to the following conditions:
ppo 0:c1e89c49eae5 8 *
ppo 0:c1e89c49eae5 9 * The above copyright notice and this permission notice shall be included in all copies or
ppo 0:c1e89c49eae5 10 * substantial portions of the Software.
ppo 0:c1e89c49eae5 11 *
ppo 0:c1e89c49eae5 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ppo 0:c1e89c49eae5 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ppo 0:c1e89c49eae5 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ppo 0:c1e89c49eae5 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ppo 0:c1e89c49eae5 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ppo 0:c1e89c49eae5 17 */
ppo 0:c1e89c49eae5 18
ppo 0:c1e89c49eae5 19 #ifdef TARGET_LPC11U24
ppo 0:c1e89c49eae5 20
ppo 0:c1e89c49eae5 21 #include "USBHAL.h"
ppo 0:c1e89c49eae5 22
ppo 0:c1e89c49eae5 23 USBHAL * USBHAL::instance;
ppo 0:c1e89c49eae5 24
ppo 0:c1e89c49eae5 25
ppo 0:c1e89c49eae5 26 // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
ppo 0:c1e89c49eae5 27 #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
ppo 0:c1e89c49eae5 28
ppo 0:c1e89c49eae5 29 // Convert physical endpoint number to register bit
ppo 0:c1e89c49eae5 30 #define EP(endpoint) (1UL<<endpoint)
ppo 0:c1e89c49eae5 31
ppo 0:c1e89c49eae5 32 // Convert physical to logical
ppo 0:c1e89c49eae5 33 #define PHY_TO_LOG(endpoint) ((endpoint)>>1)
ppo 0:c1e89c49eae5 34
ppo 0:c1e89c49eae5 35 // Get endpoint direction
ppo 0:c1e89c49eae5 36 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
ppo 0:c1e89c49eae5 37 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
ppo 0:c1e89c49eae5 38
ppo 0:c1e89c49eae5 39 // USB RAM
ppo 0:c1e89c49eae5 40 #define USB_RAM_START (0x20004000)
ppo 0:c1e89c49eae5 41 #define USB_RAM_SIZE (0x00000800)
ppo 0:c1e89c49eae5 42
ppo 0:c1e89c49eae5 43 // SYSAHBCLKCTRL
ppo 0:c1e89c49eae5 44 #define CLK_USB (1UL<<14)
ppo 0:c1e89c49eae5 45 #define CLK_USBRAM (1UL<<27)
ppo 0:c1e89c49eae5 46
ppo 0:c1e89c49eae5 47 // USB Information register
ppo 0:c1e89c49eae5 48 #define FRAME_NR(a) ((a) & 0x7ff) // Frame number
ppo 0:c1e89c49eae5 49
ppo 0:c1e89c49eae5 50 // USB Device Command/Status register
ppo 0:c1e89c49eae5 51 #define DEV_ADDR_MASK (0x7f) // Device address
ppo 0:c1e89c49eae5 52 #define DEV_ADDR(a) ((a) & DEV_ADDR_MASK)
ppo 0:c1e89c49eae5 53 #define DEV_EN (1UL<<7) // Device enable
ppo 0:c1e89c49eae5 54 #define SETUP (1UL<<8) // SETUP token received
ppo 0:c1e89c49eae5 55 #define PLL_ON (1UL<<9) // PLL enabled in suspend
ppo 0:c1e89c49eae5 56 #define DCON (1UL<<16) // Device status - connect
ppo 0:c1e89c49eae5 57 #define DSUS (1UL<<17) // Device status - suspend
ppo 0:c1e89c49eae5 58 #define DCON_C (1UL<<24) // Connect change
ppo 0:c1e89c49eae5 59 #define DSUS_C (1UL<<25) // Suspend change
ppo 0:c1e89c49eae5 60 #define DRES_C (1UL<<26) // Reset change
ppo 0:c1e89c49eae5 61 #define VBUSDEBOUNCED (1UL<<28) // Vbus detected
ppo 0:c1e89c49eae5 62
ppo 0:c1e89c49eae5 63 // Endpoint Command/Status list
ppo 0:c1e89c49eae5 64 #define CMDSTS_A (1UL<<31) // Active
ppo 0:c1e89c49eae5 65 #define CMDSTS_D (1UL<<30) // Disable
ppo 0:c1e89c49eae5 66 #define CMDSTS_S (1UL<<29) // Stall
ppo 0:c1e89c49eae5 67 #define CMDSTS_TR (1UL<<28) // Toggle Reset
ppo 0:c1e89c49eae5 68 #define CMDSTS_RF (1UL<<27) // Rate Feedback mode
ppo 0:c1e89c49eae5 69 #define CMDSTS_TV (1UL<<27) // Toggle Value
ppo 0:c1e89c49eae5 70 #define CMDSTS_T (1UL<<26) // Endpoint Type
ppo 0:c1e89c49eae5 71 #define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes
ppo 0:c1e89c49eae5 72 #define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address
ppo 0:c1e89c49eae5 73
ppo 0:c1e89c49eae5 74 #define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer
ppo 0:c1e89c49eae5 75
ppo 0:c1e89c49eae5 76 // USB Non-endpoint interrupt sources
ppo 0:c1e89c49eae5 77 #define FRAME_INT (1UL<<30)
ppo 0:c1e89c49eae5 78 #define DEV_INT (1UL<<31)
ppo 0:c1e89c49eae5 79
ppo 0:c1e89c49eae5 80 static volatile int epComplete = 0;
ppo 0:c1e89c49eae5 81
ppo 0:c1e89c49eae5 82 // One entry for a double-buffered logical endpoint in the endpoint
ppo 0:c1e89c49eae5 83 // command/status list. Endpoint 0 is single buffered, out[1] is used
ppo 0:c1e89c49eae5 84 // for the SETUP packet and in[1] is not used
ppo 0:c1e89c49eae5 85 typedef __packed struct {
ppo 0:c1e89c49eae5 86 uint32_t out[2];
ppo 0:c1e89c49eae5 87 uint32_t in[2];
ppo 0:c1e89c49eae5 88 } EP_COMMAND_STATUS;
ppo 0:c1e89c49eae5 89
ppo 0:c1e89c49eae5 90 typedef __packed struct {
ppo 0:c1e89c49eae5 91 uint8_t out[MAX_PACKET_SIZE_EP0];
ppo 0:c1e89c49eae5 92 uint8_t in[MAX_PACKET_SIZE_EP0];
ppo 0:c1e89c49eae5 93 uint8_t setup[SETUP_PACKET_SIZE];
ppo 0:c1e89c49eae5 94 } CONTROL_TRANSFER;
ppo 0:c1e89c49eae5 95
ppo 0:c1e89c49eae5 96 typedef __packed struct {
ppo 0:c1e89c49eae5 97 uint32_t maxPacket;
ppo 0:c1e89c49eae5 98 uint32_t buffer[2];
ppo 0:c1e89c49eae5 99 uint32_t options;
ppo 0:c1e89c49eae5 100 } EP_STATE;
ppo 0:c1e89c49eae5 101
ppo 0:c1e89c49eae5 102 static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS];
ppo 0:c1e89c49eae5 103
ppo 0:c1e89c49eae5 104 // Pointer to the endpoint command/status list
ppo 0:c1e89c49eae5 105 static EP_COMMAND_STATUS *ep = NULL;
ppo 0:c1e89c49eae5 106
ppo 0:c1e89c49eae5 107 // Pointer to endpoint 0 data (IN/OUT and SETUP)
ppo 0:c1e89c49eae5 108 static CONTROL_TRANSFER *ct = NULL;
ppo 0:c1e89c49eae5 109
ppo 0:c1e89c49eae5 110 // Shadow DEVCMDSTAT register to avoid accidentally clearing flags or
ppo 0:c1e89c49eae5 111 // initiating a remote wakeup event.
ppo 0:c1e89c49eae5 112 static volatile uint32_t devCmdStat;
ppo 0:c1e89c49eae5 113
ppo 0:c1e89c49eae5 114 // Pointers used to allocate USB RAM
ppo 0:c1e89c49eae5 115 static uint32_t usbRamPtr = USB_RAM_START;
ppo 0:c1e89c49eae5 116 static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here
ppo 0:c1e89c49eae5 117
ppo 0:c1e89c49eae5 118 #define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m))
ppo 0:c1e89c49eae5 119
ppo 0:c1e89c49eae5 120 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size);
ppo 0:c1e89c49eae5 121 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) {
ppo 0:c1e89c49eae5 122 if (size > 0) {
ppo 0:c1e89c49eae5 123 do {
ppo 0:c1e89c49eae5 124 *dst++ = *src++;
ppo 0:c1e89c49eae5 125 } while (--size > 0);
ppo 0:c1e89c49eae5 126 }
ppo 0:c1e89c49eae5 127 }
ppo 0:c1e89c49eae5 128
ppo 0:c1e89c49eae5 129
ppo 0:c1e89c49eae5 130 USBHAL::USBHAL(void) {
ppo 0:c1e89c49eae5 131 NVIC_DisableIRQ(USB_IRQn);
ppo 0:c1e89c49eae5 132
ppo 0:c1e89c49eae5 133 // nUSB_CONNECT output
ppo 0:c1e89c49eae5 134 LPC_IOCON->PIO0_6 = 0x00000001;
ppo 0:c1e89c49eae5 135
ppo 0:c1e89c49eae5 136 // Enable clocks (USB registers, USB RAM)
ppo 0:c1e89c49eae5 137 LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM;
ppo 0:c1e89c49eae5 138
ppo 0:c1e89c49eae5 139 // Ensure device disconnected (DCON not set)
ppo 0:c1e89c49eae5 140 LPC_USB->DEVCMDSTAT = 0;
ppo 0:c1e89c49eae5 141
ppo 0:c1e89c49eae5 142 // to ensure that the USB host sees the device as
ppo 0:c1e89c49eae5 143 // disconnected if the target CPU is reset.
ppo 0:c1e89c49eae5 144 wait(0.3);
ppo 0:c1e89c49eae5 145
ppo 0:c1e89c49eae5 146 // Reserve space in USB RAM for endpoint command/status list
ppo 0:c1e89c49eae5 147 // Must be 256 byte aligned
ppo 0:c1e89c49eae5 148 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256);
ppo 0:c1e89c49eae5 149 ep = (EP_COMMAND_STATUS *)usbRamPtr;
ppo 0:c1e89c49eae5 150 usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS);
ppo 0:c1e89c49eae5 151 LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00;
ppo 0:c1e89c49eae5 152
ppo 0:c1e89c49eae5 153 // Reserve space in USB RAM for Endpoint 0
ppo 0:c1e89c49eae5 154 // Must be 64 byte aligned
ppo 0:c1e89c49eae5 155 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64);
ppo 0:c1e89c49eae5 156 ct = (CONTROL_TRANSFER *)usbRamPtr;
ppo 0:c1e89c49eae5 157 usbRamPtr += sizeof(CONTROL_TRANSFER);
ppo 0:c1e89c49eae5 158 LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000;
ppo 0:c1e89c49eae5 159
ppo 0:c1e89c49eae5 160 // Setup command/status list for EP0
ppo 0:c1e89c49eae5 161 ep[0].out[0] = 0;
ppo 0:c1e89c49eae5 162 ep[0].in[0] = 0;
ppo 0:c1e89c49eae5 163 ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup);
ppo 0:c1e89c49eae5 164
ppo 0:c1e89c49eae5 165 // Route all interrupts to IRQ, some can be routed to
ppo 0:c1e89c49eae5 166 // USB_FIQ if you wish.
ppo 0:c1e89c49eae5 167 LPC_USB->INTROUTING = 0;
ppo 0:c1e89c49eae5 168
ppo 0:c1e89c49eae5 169 // Set device address 0, enable USB device, no remote wakeup
ppo 0:c1e89c49eae5 170 devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS;
ppo 0:c1e89c49eae5 171 LPC_USB->DEVCMDSTAT = devCmdStat;
ppo 0:c1e89c49eae5 172
ppo 0:c1e89c49eae5 173 // Enable interrupts for device events and EP0
ppo 0:c1e89c49eae5 174 LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT;
ppo 0:c1e89c49eae5 175 instance = this;
ppo 0:c1e89c49eae5 176
ppo 0:c1e89c49eae5 177 //attach IRQ handler and enable interrupts
ppo 0:c1e89c49eae5 178 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
ppo 0:c1e89c49eae5 179 }
ppo 0:c1e89c49eae5 180
ppo 0:c1e89c49eae5 181 USBHAL::~USBHAL(void) {
ppo 0:c1e89c49eae5 182 // Ensure device disconnected (DCON not set)
ppo 0:c1e89c49eae5 183 LPC_USB->DEVCMDSTAT = 0;
ppo 0:c1e89c49eae5 184
ppo 0:c1e89c49eae5 185 // Disable USB interrupts
ppo 0:c1e89c49eae5 186 NVIC_DisableIRQ(USB_IRQn);
ppo 0:c1e89c49eae5 187 }
ppo 0:c1e89c49eae5 188
ppo 0:c1e89c49eae5 189 void USBHAL::connect(void) {
ppo 0:c1e89c49eae5 190 NVIC_EnableIRQ(USB_IRQn);
ppo 0:c1e89c49eae5 191 devCmdStat |= DCON;
ppo 0:c1e89c49eae5 192 LPC_USB->DEVCMDSTAT = devCmdStat;
ppo 0:c1e89c49eae5 193 }
ppo 0:c1e89c49eae5 194
ppo 0:c1e89c49eae5 195 void USBHAL::disconnect(void) {
ppo 0:c1e89c49eae5 196 NVIC_DisableIRQ(USB_IRQn);
ppo 0:c1e89c49eae5 197 devCmdStat &= ~DCON;
ppo 0:c1e89c49eae5 198 LPC_USB->DEVCMDSTAT = devCmdStat;
ppo 0:c1e89c49eae5 199 }
ppo 0:c1e89c49eae5 200
ppo 0:c1e89c49eae5 201 void USBHAL::configureDevice(void) {
ppo 0:c1e89c49eae5 202 }
ppo 0:c1e89c49eae5 203
ppo 0:c1e89c49eae5 204 void USBHAL::unconfigureDevice(void) {
ppo 0:c1e89c49eae5 205 }
ppo 0:c1e89c49eae5 206
ppo 0:c1e89c49eae5 207 void USBHAL::EP0setup(uint8_t *buffer) {
ppo 0:c1e89c49eae5 208 // Copy setup packet data
ppo 0:c1e89c49eae5 209 USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE);
ppo 0:c1e89c49eae5 210 }
ppo 0:c1e89c49eae5 211
ppo 0:c1e89c49eae5 212
ppo 0:c1e89c49eae5 213 void USBHAL::EP0read(void) {
ppo 0:c1e89c49eae5 214 // Start an endpoint 0 read
ppo 0:c1e89c49eae5 215
ppo 0:c1e89c49eae5 216 // The USB ISR will call USBDevice_EP0out() when a packet has been read,
ppo 0:c1e89c49eae5 217 // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to
ppo 0:c1e89c49eae5 218 // read the data.
ppo 0:c1e89c49eae5 219
ppo 0:c1e89c49eae5 220 ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \
ppo 0:c1e89c49eae5 221 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
ppo 0:c1e89c49eae5 222 }
ppo 0:c1e89c49eae5 223
ppo 0:c1e89c49eae5 224 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
ppo 0:c1e89c49eae5 225 // Complete an endpoint 0 read
ppo 0:c1e89c49eae5 226 uint32_t bytesRead;
ppo 0:c1e89c49eae5 227
ppo 0:c1e89c49eae5 228 // Find how many bytes were read
ppo 0:c1e89c49eae5 229 bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]);
ppo 0:c1e89c49eae5 230
ppo 0:c1e89c49eae5 231 // Copy data
ppo 0:c1e89c49eae5 232 USBMemCopy(buffer, ct->out, bytesRead);
ppo 0:c1e89c49eae5 233 return bytesRead;
ppo 0:c1e89c49eae5 234 }
ppo 0:c1e89c49eae5 235
ppo 0:c1e89c49eae5 236 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
ppo 0:c1e89c49eae5 237 // Start and endpoint 0 write
ppo 0:c1e89c49eae5 238
ppo 0:c1e89c49eae5 239 // The USB ISR will call USBDevice_EP0in() when the data has
ppo 0:c1e89c49eae5 240 // been written, the USBDevice layer then calls
ppo 0:c1e89c49eae5 241 // USBBusInterface_EP0getWriteResult() to complete the transaction.
ppo 0:c1e89c49eae5 242
ppo 0:c1e89c49eae5 243 // Copy data
ppo 0:c1e89c49eae5 244 USBMemCopy(ct->in, buffer, size);
ppo 0:c1e89c49eae5 245
ppo 0:c1e89c49eae5 246 // Start transfer
ppo 0:c1e89c49eae5 247 ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \
ppo 0:c1e89c49eae5 248 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in);
ppo 0:c1e89c49eae5 249 }
ppo 0:c1e89c49eae5 250
ppo 0:c1e89c49eae5 251
ppo 0:c1e89c49eae5 252 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
ppo 0:c1e89c49eae5 253 uint8_t bf = 0;
ppo 0:c1e89c49eae5 254 uint32_t flags = 0;
ppo 0:c1e89c49eae5 255
ppo 0:c1e89c49eae5 256 //check which buffer must be filled
ppo 0:c1e89c49eae5 257 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
ppo 0:c1e89c49eae5 258 // Double buffered
ppo 0:c1e89c49eae5 259 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 260 bf = 1;
ppo 0:c1e89c49eae5 261 } else {
ppo 0:c1e89c49eae5 262 bf = 0;
ppo 0:c1e89c49eae5 263 }
ppo 0:c1e89c49eae5 264 }
ppo 0:c1e89c49eae5 265
ppo 0:c1e89c49eae5 266 // if isochronous endpoint, T = 1
ppo 0:c1e89c49eae5 267 if(endpointState[endpoint].options & ISOCHRONOUS)
ppo 0:c1e89c49eae5 268 {
ppo 0:c1e89c49eae5 269 flags |= CMDSTS_T;
ppo 0:c1e89c49eae5 270 }
ppo 0:c1e89c49eae5 271
ppo 0:c1e89c49eae5 272 //Active the endpoint for reading
ppo 0:c1e89c49eae5 273 ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \
ppo 0:c1e89c49eae5 274 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags;
ppo 0:c1e89c49eae5 275 return EP_PENDING;
ppo 0:c1e89c49eae5 276 }
ppo 0:c1e89c49eae5 277
ppo 0:c1e89c49eae5 278 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) {
ppo 0:c1e89c49eae5 279
ppo 0:c1e89c49eae5 280 uint8_t bf = 0;
ppo 0:c1e89c49eae5 281
ppo 0:c1e89c49eae5 282 if (!(epComplete & EP(endpoint)))
ppo 0:c1e89c49eae5 283 return EP_PENDING;
ppo 0:c1e89c49eae5 284 else {
ppo 0:c1e89c49eae5 285 epComplete &= ~EP(endpoint);
ppo 0:c1e89c49eae5 286
ppo 0:c1e89c49eae5 287 //check which buffer has been filled
ppo 0:c1e89c49eae5 288 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
ppo 0:c1e89c49eae5 289 // Double buffered (here we read the previous buffer which was used)
ppo 0:c1e89c49eae5 290 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 291 bf = 0;
ppo 0:c1e89c49eae5 292 } else {
ppo 0:c1e89c49eae5 293 bf = 1;
ppo 0:c1e89c49eae5 294 }
ppo 0:c1e89c49eae5 295 }
ppo 0:c1e89c49eae5 296
ppo 0:c1e89c49eae5 297 // Find how many bytes were read
ppo 0:c1e89c49eae5 298 *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf]));
ppo 0:c1e89c49eae5 299
ppo 0:c1e89c49eae5 300 // Copy data
ppo 0:c1e89c49eae5 301 USBMemCopy(data, ct->out, *bytesRead);
ppo 0:c1e89c49eae5 302 return EP_COMPLETED;
ppo 0:c1e89c49eae5 303 }
ppo 0:c1e89c49eae5 304 }
ppo 0:c1e89c49eae5 305
ppo 0:c1e89c49eae5 306 void USBHAL::EP0getWriteResult(void) {
ppo 0:c1e89c49eae5 307 // Complete an endpoint 0 write
ppo 0:c1e89c49eae5 308
ppo 0:c1e89c49eae5 309 // Nothing required for this target
ppo 0:c1e89c49eae5 310 return;
ppo 0:c1e89c49eae5 311 }
ppo 0:c1e89c49eae5 312
ppo 0:c1e89c49eae5 313 void USBHAL::EP0stall(void) {
ppo 0:c1e89c49eae5 314 ep[0].in[0] = CMDSTS_S;
ppo 0:c1e89c49eae5 315 ep[0].out[0] = CMDSTS_S;
ppo 0:c1e89c49eae5 316 }
ppo 0:c1e89c49eae5 317
ppo 0:c1e89c49eae5 318 void USBHAL::setAddress(uint8_t address) {
ppo 0:c1e89c49eae5 319 devCmdStat &= ~DEV_ADDR_MASK;
ppo 0:c1e89c49eae5 320 devCmdStat |= DEV_ADDR(address);
ppo 0:c1e89c49eae5 321 LPC_USB->DEVCMDSTAT = devCmdStat;
ppo 0:c1e89c49eae5 322 }
ppo 0:c1e89c49eae5 323
ppo 0:c1e89c49eae5 324 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
ppo 0:c1e89c49eae5 325 uint32_t flags = 0;
ppo 0:c1e89c49eae5 326 uint32_t bf;
ppo 0:c1e89c49eae5 327
ppo 0:c1e89c49eae5 328 // Validate parameters
ppo 0:c1e89c49eae5 329 if (data == NULL) {
ppo 0:c1e89c49eae5 330 return EP_INVALID;
ppo 0:c1e89c49eae5 331 }
ppo 0:c1e89c49eae5 332
ppo 0:c1e89c49eae5 333 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
ppo 0:c1e89c49eae5 334 return EP_INVALID;
ppo 0:c1e89c49eae5 335 }
ppo 0:c1e89c49eae5 336
ppo 0:c1e89c49eae5 337 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
ppo 0:c1e89c49eae5 338 return EP_INVALID;
ppo 0:c1e89c49eae5 339 }
ppo 0:c1e89c49eae5 340
ppo 0:c1e89c49eae5 341 if (size > endpointState[endpoint].maxPacket) {
ppo 0:c1e89c49eae5 342 return EP_INVALID;
ppo 0:c1e89c49eae5 343 }
ppo 0:c1e89c49eae5 344
ppo 0:c1e89c49eae5 345 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
ppo 0:c1e89c49eae5 346 // Double buffered
ppo 0:c1e89c49eae5 347 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 348 bf = 1;
ppo 0:c1e89c49eae5 349 } else {
ppo 0:c1e89c49eae5 350 bf = 0;
ppo 0:c1e89c49eae5 351 }
ppo 0:c1e89c49eae5 352 } else {
ppo 0:c1e89c49eae5 353 // Single buffered
ppo 0:c1e89c49eae5 354 bf = 0;
ppo 0:c1e89c49eae5 355 }
ppo 0:c1e89c49eae5 356
ppo 0:c1e89c49eae5 357 // Check if already active
ppo 0:c1e89c49eae5 358 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
ppo 0:c1e89c49eae5 359 return EP_INVALID;
ppo 0:c1e89c49eae5 360 }
ppo 0:c1e89c49eae5 361
ppo 0:c1e89c49eae5 362 // Check if stalled
ppo 0:c1e89c49eae5 363 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
ppo 0:c1e89c49eae5 364 return EP_STALLED;
ppo 0:c1e89c49eae5 365 }
ppo 0:c1e89c49eae5 366
ppo 0:c1e89c49eae5 367 // Copy data to USB RAM
ppo 0:c1e89c49eae5 368 USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size);
ppo 0:c1e89c49eae5 369
ppo 0:c1e89c49eae5 370 // Add options
ppo 0:c1e89c49eae5 371 if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) {
ppo 0:c1e89c49eae5 372 flags |= CMDSTS_RF;
ppo 0:c1e89c49eae5 373 }
ppo 0:c1e89c49eae5 374
ppo 0:c1e89c49eae5 375 if (endpointState[endpoint].options & ISOCHRONOUS) {
ppo 0:c1e89c49eae5 376 flags |= CMDSTS_T;
ppo 0:c1e89c49eae5 377 }
ppo 0:c1e89c49eae5 378
ppo 0:c1e89c49eae5 379 // Add transfer
ppo 0:c1e89c49eae5 380 ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \
ppo 0:c1e89c49eae5 381 endpointState[endpoint].buffer[bf]) \
ppo 0:c1e89c49eae5 382 | CMDSTS_NBYTES(size) | CMDSTS_A | flags;
ppo 0:c1e89c49eae5 383
ppo 0:c1e89c49eae5 384 return EP_PENDING;
ppo 0:c1e89c49eae5 385 }
ppo 0:c1e89c49eae5 386
ppo 0:c1e89c49eae5 387 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
ppo 0:c1e89c49eae5 388 uint32_t bf;
ppo 0:c1e89c49eae5 389 // Validate parameters
ppo 0:c1e89c49eae5 390
ppo 0:c1e89c49eae5 391 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
ppo 0:c1e89c49eae5 392 return EP_INVALID;
ppo 0:c1e89c49eae5 393 }
ppo 0:c1e89c49eae5 394
ppo 0:c1e89c49eae5 395 if (OUT_EP(endpoint)) {
ppo 0:c1e89c49eae5 396 return EP_INVALID;
ppo 0:c1e89c49eae5 397 }
ppo 0:c1e89c49eae5 398
ppo 0:c1e89c49eae5 399 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
ppo 0:c1e89c49eae5 400 // Double buffered // TODO: FIX THIS
ppo 0:c1e89c49eae5 401 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 402 bf = 1;
ppo 0:c1e89c49eae5 403 } else {
ppo 0:c1e89c49eae5 404 bf = 0;
ppo 0:c1e89c49eae5 405 }
ppo 0:c1e89c49eae5 406 } else {
ppo 0:c1e89c49eae5 407 // Single buffered
ppo 0:c1e89c49eae5 408 bf = 0;
ppo 0:c1e89c49eae5 409 }
ppo 0:c1e89c49eae5 410
ppo 0:c1e89c49eae5 411 // Check if endpoint still active
ppo 0:c1e89c49eae5 412 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
ppo 0:c1e89c49eae5 413 return EP_PENDING;
ppo 0:c1e89c49eae5 414 }
ppo 0:c1e89c49eae5 415
ppo 0:c1e89c49eae5 416 // Check if stalled
ppo 0:c1e89c49eae5 417 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
ppo 0:c1e89c49eae5 418 return EP_STALLED;
ppo 0:c1e89c49eae5 419 }
ppo 0:c1e89c49eae5 420
ppo 0:c1e89c49eae5 421 return EP_COMPLETED;
ppo 0:c1e89c49eae5 422 }
ppo 0:c1e89c49eae5 423
ppo 0:c1e89c49eae5 424 void USBHAL::stallEndpoint(uint8_t endpoint) {
ppo 0:c1e89c49eae5 425
ppo 0:c1e89c49eae5 426 // TODO: should this clear active bit?
ppo 0:c1e89c49eae5 427
ppo 0:c1e89c49eae5 428 if (IN_EP(endpoint)) {
ppo 0:c1e89c49eae5 429 ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
ppo 0:c1e89c49eae5 430 ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
ppo 0:c1e89c49eae5 431 } else {
ppo 0:c1e89c49eae5 432 ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S;
ppo 0:c1e89c49eae5 433 ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S;
ppo 0:c1e89c49eae5 434 }
ppo 0:c1e89c49eae5 435 }
ppo 0:c1e89c49eae5 436
ppo 0:c1e89c49eae5 437 void USBHAL::unstallEndpoint(uint8_t endpoint) {
ppo 0:c1e89c49eae5 438 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
ppo 0:c1e89c49eae5 439 // Double buffered
ppo 0:c1e89c49eae5 440 if (IN_EP(endpoint)) {
ppo 0:c1e89c49eae5 441 ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0
ppo 0:c1e89c49eae5 442 ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
ppo 0:c1e89c49eae5 443
ppo 0:c1e89c49eae5 444 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 445 ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
ppo 0:c1e89c49eae5 446 } else {
ppo 0:c1e89c49eae5 447 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
ppo 0:c1e89c49eae5 448 }
ppo 0:c1e89c49eae5 449 } else {
ppo 0:c1e89c49eae5 450 ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
ppo 0:c1e89c49eae5 451 ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
ppo 0:c1e89c49eae5 452
ppo 0:c1e89c49eae5 453 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 454 ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
ppo 0:c1e89c49eae5 455 } else {
ppo 0:c1e89c49eae5 456 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
ppo 0:c1e89c49eae5 457 }
ppo 0:c1e89c49eae5 458 }
ppo 0:c1e89c49eae5 459 } else {
ppo 0:c1e89c49eae5 460 // Single buffered
ppo 0:c1e89c49eae5 461 if (IN_EP(endpoint)) {
ppo 0:c1e89c49eae5 462 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
ppo 0:c1e89c49eae5 463 } else {
ppo 0:c1e89c49eae5 464 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
ppo 0:c1e89c49eae5 465 }
ppo 0:c1e89c49eae5 466 }
ppo 0:c1e89c49eae5 467 }
ppo 0:c1e89c49eae5 468
ppo 0:c1e89c49eae5 469 bool USBHAL::getEndpointStallState(unsigned char endpoint) {
ppo 0:c1e89c49eae5 470 if (IN_EP(endpoint)) {
ppo 0:c1e89c49eae5 471 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 472 if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) {
ppo 0:c1e89c49eae5 473 return true;
ppo 0:c1e89c49eae5 474 }
ppo 0:c1e89c49eae5 475 } else {
ppo 0:c1e89c49eae5 476 if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) {
ppo 0:c1e89c49eae5 477 return true;
ppo 0:c1e89c49eae5 478 }
ppo 0:c1e89c49eae5 479 }
ppo 0:c1e89c49eae5 480 } else {
ppo 0:c1e89c49eae5 481 if (LPC_USB->EPINUSE & EP(endpoint)) {
ppo 0:c1e89c49eae5 482 if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) {
ppo 0:c1e89c49eae5 483 return true;
ppo 0:c1e89c49eae5 484 }
ppo 0:c1e89c49eae5 485 } else {
ppo 0:c1e89c49eae5 486 if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) {
ppo 0:c1e89c49eae5 487 return true;
ppo 0:c1e89c49eae5 488 }
ppo 0:c1e89c49eae5 489 }
ppo 0:c1e89c49eae5 490 }
ppo 0:c1e89c49eae5 491
ppo 0:c1e89c49eae5 492 return false;
ppo 0:c1e89c49eae5 493 }
ppo 0:c1e89c49eae5 494
ppo 0:c1e89c49eae5 495 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) {
ppo 0:c1e89c49eae5 496 uint32_t tmpEpRamPtr;
ppo 0:c1e89c49eae5 497
ppo 0:c1e89c49eae5 498 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
ppo 0:c1e89c49eae5 499 return false;
ppo 0:c1e89c49eae5 500 }
ppo 0:c1e89c49eae5 501
ppo 0:c1e89c49eae5 502 // Not applicable to the control endpoints
ppo 0:c1e89c49eae5 503 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
ppo 0:c1e89c49eae5 504 return false;
ppo 0:c1e89c49eae5 505 }
ppo 0:c1e89c49eae5 506
ppo 0:c1e89c49eae5 507 // Allocate buffers in USB RAM
ppo 0:c1e89c49eae5 508 tmpEpRamPtr = epRamPtr;
ppo 0:c1e89c49eae5 509
ppo 0:c1e89c49eae5 510 // Must be 64 byte aligned
ppo 0:c1e89c49eae5 511 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
ppo 0:c1e89c49eae5 512
ppo 0:c1e89c49eae5 513 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
ppo 0:c1e89c49eae5 514 // Out of memory
ppo 0:c1e89c49eae5 515 return false;
ppo 0:c1e89c49eae5 516 }
ppo 0:c1e89c49eae5 517
ppo 0:c1e89c49eae5 518 // Allocate first buffer
ppo 0:c1e89c49eae5 519 endpointState[endpoint].buffer[0] = tmpEpRamPtr;
ppo 0:c1e89c49eae5 520 tmpEpRamPtr += maxPacket;
ppo 0:c1e89c49eae5 521
ppo 0:c1e89c49eae5 522 if (!(options & SINGLE_BUFFERED)) {
ppo 0:c1e89c49eae5 523 // Must be 64 byte aligned
ppo 0:c1e89c49eae5 524 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
ppo 0:c1e89c49eae5 525
ppo 0:c1e89c49eae5 526 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
ppo 0:c1e89c49eae5 527 // Out of memory
ppo 0:c1e89c49eae5 528 return false;
ppo 0:c1e89c49eae5 529 }
ppo 0:c1e89c49eae5 530
ppo 0:c1e89c49eae5 531 // Allocate second buffer
ppo 0:c1e89c49eae5 532 endpointState[endpoint].buffer[1] = tmpEpRamPtr;
ppo 0:c1e89c49eae5 533 tmpEpRamPtr += maxPacket;
ppo 0:c1e89c49eae5 534 }
ppo 0:c1e89c49eae5 535
ppo 0:c1e89c49eae5 536 // Commit to this USB RAM allocation
ppo 0:c1e89c49eae5 537 epRamPtr = tmpEpRamPtr;
ppo 0:c1e89c49eae5 538
ppo 0:c1e89c49eae5 539 // Remaining endpoint state values
ppo 0:c1e89c49eae5 540 endpointState[endpoint].maxPacket = maxPacket;
ppo 0:c1e89c49eae5 541 endpointState[endpoint].options = options;
ppo 0:c1e89c49eae5 542
ppo 0:c1e89c49eae5 543 // Enable double buffering if required
ppo 0:c1e89c49eae5 544 if (options & SINGLE_BUFFERED) {
ppo 0:c1e89c49eae5 545 LPC_USB->EPBUFCFG &= ~EP(endpoint);
ppo 0:c1e89c49eae5 546 } else {
ppo 0:c1e89c49eae5 547 // Double buffered
ppo 0:c1e89c49eae5 548 LPC_USB->EPBUFCFG |= EP(endpoint);
ppo 0:c1e89c49eae5 549 }
ppo 0:c1e89c49eae5 550
ppo 0:c1e89c49eae5 551 // Enable interrupt
ppo 0:c1e89c49eae5 552 LPC_USB->INTEN |= EP(endpoint);
ppo 0:c1e89c49eae5 553
ppo 0:c1e89c49eae5 554 // Enable endpoint
ppo 0:c1e89c49eae5 555 unstallEndpoint(endpoint);
ppo 0:c1e89c49eae5 556 return true;
ppo 0:c1e89c49eae5 557 }
ppo 0:c1e89c49eae5 558
ppo 0:c1e89c49eae5 559 void USBHAL::remoteWakeup(void) {
ppo 0:c1e89c49eae5 560 // Clearing DSUS bit initiates a remote wakeup if the
ppo 0:c1e89c49eae5 561 // device is currently enabled and suspended - otherwise
ppo 0:c1e89c49eae5 562 // it has no effect.
ppo 0:c1e89c49eae5 563 LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS;
ppo 0:c1e89c49eae5 564 }
ppo 0:c1e89c49eae5 565
ppo 0:c1e89c49eae5 566
ppo 0:c1e89c49eae5 567 static void disableEndpoints(void) {
ppo 0:c1e89c49eae5 568 uint32_t logEp;
ppo 0:c1e89c49eae5 569
ppo 0:c1e89c49eae5 570 // Ref. Table 158 "When a bus reset is received, software
ppo 0:c1e89c49eae5 571 // must set the disable bit of all endpoints to 1".
ppo 0:c1e89c49eae5 572
ppo 0:c1e89c49eae5 573 for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) {
ppo 0:c1e89c49eae5 574 ep[logEp].out[0] = CMDSTS_D;
ppo 0:c1e89c49eae5 575 ep[logEp].out[1] = CMDSTS_D;
ppo 0:c1e89c49eae5 576 ep[logEp].in[0] = CMDSTS_D;
ppo 0:c1e89c49eae5 577 ep[logEp].in[1] = CMDSTS_D;
ppo 0:c1e89c49eae5 578 }
ppo 0:c1e89c49eae5 579
ppo 0:c1e89c49eae5 580 // Start of USB RAM for endpoints > 0
ppo 0:c1e89c49eae5 581 epRamPtr = usbRamPtr;
ppo 0:c1e89c49eae5 582 }
ppo 0:c1e89c49eae5 583
ppo 0:c1e89c49eae5 584
ppo 0:c1e89c49eae5 585
ppo 0:c1e89c49eae5 586 void USBHAL::_usbisr(void) {
ppo 0:c1e89c49eae5 587 instance->usbisr();
ppo 0:c1e89c49eae5 588 }
ppo 0:c1e89c49eae5 589
ppo 0:c1e89c49eae5 590 void USBHAL::usbisr(void) {
ppo 0:c1e89c49eae5 591 // Start of frame
ppo 0:c1e89c49eae5 592 if (LPC_USB->INTSTAT & FRAME_INT) {
ppo 0:c1e89c49eae5 593 // Clear SOF interrupt
ppo 0:c1e89c49eae5 594 LPC_USB->INTSTAT = FRAME_INT;
ppo 0:c1e89c49eae5 595
ppo 0:c1e89c49eae5 596 // SOF event, read frame number
ppo 0:c1e89c49eae5 597 SOF(FRAME_NR(LPC_USB->INFO));
ppo 0:c1e89c49eae5 598 }
ppo 0:c1e89c49eae5 599
ppo 0:c1e89c49eae5 600 // Device state
ppo 0:c1e89c49eae5 601 if (LPC_USB->INTSTAT & DEV_INT) {
ppo 0:c1e89c49eae5 602 LPC_USB->INTSTAT = DEV_INT;
ppo 0:c1e89c49eae5 603
ppo 0:c1e89c49eae5 604 if (LPC_USB->DEVCMDSTAT & DSUS_C) {
ppo 0:c1e89c49eae5 605 // Suspend status changed
ppo 0:c1e89c49eae5 606 LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C;
ppo 0:c1e89c49eae5 607 if((LPC_USB->DEVCMDSTAT & DSUS) != 0) {
ppo 0:c1e89c49eae5 608 suspendStateChanged(1);
ppo 0:c1e89c49eae5 609 }
ppo 0:c1e89c49eae5 610 }
ppo 0:c1e89c49eae5 611
ppo 0:c1e89c49eae5 612 if (LPC_USB->DEVCMDSTAT & DRES_C) {
ppo 0:c1e89c49eae5 613 // Bus reset
ppo 0:c1e89c49eae5 614 LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C;
ppo 0:c1e89c49eae5 615
ppo 0:c1e89c49eae5 616 suspendStateChanged(0);
ppo 0:c1e89c49eae5 617
ppo 0:c1e89c49eae5 618 // Disable endpoints > 0
ppo 0:c1e89c49eae5 619 disableEndpoints();
ppo 0:c1e89c49eae5 620
ppo 0:c1e89c49eae5 621 // Bus reset event
ppo 0:c1e89c49eae5 622 busReset();
ppo 0:c1e89c49eae5 623 }
ppo 0:c1e89c49eae5 624 }
ppo 0:c1e89c49eae5 625
ppo 0:c1e89c49eae5 626 // Endpoint 0
ppo 0:c1e89c49eae5 627 if (LPC_USB->INTSTAT & EP(EP0OUT)) {
ppo 0:c1e89c49eae5 628 // Clear EP0OUT/SETUP interrupt
ppo 0:c1e89c49eae5 629 LPC_USB->INTSTAT = EP(EP0OUT);
ppo 0:c1e89c49eae5 630
ppo 0:c1e89c49eae5 631 // Check if SETUP
ppo 0:c1e89c49eae5 632 if (LPC_USB->DEVCMDSTAT & SETUP) {
ppo 0:c1e89c49eae5 633 // Clear Active and Stall bits for EP0
ppo 0:c1e89c49eae5 634 // Documentation does not make it clear if we must use the
ppo 0:c1e89c49eae5 635 // EPSKIP register to achieve this, Fig. 16 and NXP reference
ppo 0:c1e89c49eae5 636 // code suggests we can just clear the Active bits - check with
ppo 0:c1e89c49eae5 637 // NXP to be sure.
ppo 0:c1e89c49eae5 638 ep[0].in[0] = 0;
ppo 0:c1e89c49eae5 639 ep[0].out[0] = 0;
ppo 0:c1e89c49eae5 640
ppo 0:c1e89c49eae5 641 // Clear EP0IN interrupt
ppo 0:c1e89c49eae5 642 LPC_USB->INTSTAT = EP(EP0IN);
ppo 0:c1e89c49eae5 643
ppo 0:c1e89c49eae5 644 // Clear SETUP (and INTONNAK_CI/O) in device status register
ppo 0:c1e89c49eae5 645 LPC_USB->DEVCMDSTAT = devCmdStat | SETUP;
ppo 0:c1e89c49eae5 646
ppo 0:c1e89c49eae5 647 // EP0 SETUP event (SETUP data received)
ppo 0:c1e89c49eae5 648 EP0setupCallback();
ppo 0:c1e89c49eae5 649 } else {
ppo 0:c1e89c49eae5 650 // EP0OUT ACK event (OUT data received)
ppo 0:c1e89c49eae5 651 EP0out();
ppo 0:c1e89c49eae5 652 }
ppo 0:c1e89c49eae5 653 }
ppo 0:c1e89c49eae5 654
ppo 0:c1e89c49eae5 655 if (LPC_USB->INTSTAT & EP(EP0IN)) {
ppo 0:c1e89c49eae5 656 // Clear EP0IN interrupt
ppo 0:c1e89c49eae5 657 LPC_USB->INTSTAT = EP(EP0IN);
ppo 0:c1e89c49eae5 658
ppo 0:c1e89c49eae5 659 // EP0IN ACK event (IN data sent)
ppo 0:c1e89c49eae5 660 EP0in();
ppo 0:c1e89c49eae5 661 }
ppo 0:c1e89c49eae5 662
ppo 0:c1e89c49eae5 663 if (LPC_USB->INTSTAT & EP(EP1IN)) {
ppo 0:c1e89c49eae5 664 // Clear EP1IN interrupt
ppo 0:c1e89c49eae5 665 LPC_USB->INTSTAT = EP(EP1IN);
ppo 0:c1e89c49eae5 666 epComplete |= EP(EP1IN);
ppo 0:c1e89c49eae5 667 if (EP1_IN_callback())
ppo 0:c1e89c49eae5 668 epComplete &= ~EP(EP1IN);
ppo 0:c1e89c49eae5 669 }
ppo 0:c1e89c49eae5 670
ppo 0:c1e89c49eae5 671 if (LPC_USB->INTSTAT & EP(EP1OUT)) {
ppo 0:c1e89c49eae5 672 // Clear EP1OUT interrupt
ppo 0:c1e89c49eae5 673 LPC_USB->INTSTAT = EP(EP1OUT);
ppo 0:c1e89c49eae5 674 epComplete |= EP(EP1OUT);
ppo 0:c1e89c49eae5 675 if (EP1_OUT_callback())
ppo 0:c1e89c49eae5 676 epComplete &= ~EP(EP1OUT);
ppo 0:c1e89c49eae5 677 }
ppo 0:c1e89c49eae5 678
ppo 0:c1e89c49eae5 679 if (LPC_USB->INTSTAT & EP(EP2IN)) {
ppo 0:c1e89c49eae5 680 // Clear EPBULK_IN interrupt
ppo 0:c1e89c49eae5 681 LPC_USB->INTSTAT = EP(EP2IN);
ppo 0:c1e89c49eae5 682 epComplete |= EP(EP2IN);
ppo 0:c1e89c49eae5 683 if (EP2_IN_callback())
ppo 0:c1e89c49eae5 684 epComplete &= ~EP(EP2IN);
ppo 0:c1e89c49eae5 685 }
ppo 0:c1e89c49eae5 686
ppo 0:c1e89c49eae5 687 if (LPC_USB->INTSTAT & EP(EP2OUT)) {
ppo 0:c1e89c49eae5 688 // Clear EPBULK_OUT interrupt
ppo 0:c1e89c49eae5 689 LPC_USB->INTSTAT = EP(EP2OUT);
ppo 0:c1e89c49eae5 690 epComplete |= EP(EP2OUT);
ppo 0:c1e89c49eae5 691 //Call callback function. If true, clear epComplete
ppo 0:c1e89c49eae5 692 if (EP2_OUT_callback())
ppo 0:c1e89c49eae5 693 epComplete &= ~EP(EP2OUT);
ppo 0:c1e89c49eae5 694 }
ppo 0:c1e89c49eae5 695
ppo 0:c1e89c49eae5 696 if (LPC_USB->INTSTAT & EP(EP3IN)) {
ppo 0:c1e89c49eae5 697 // Clear EP3_IN interrupt
ppo 0:c1e89c49eae5 698 LPC_USB->INTSTAT = EP(EP3IN);
ppo 0:c1e89c49eae5 699 epComplete |= EP(EP3IN);
ppo 0:c1e89c49eae5 700 if (EP3_IN_callback())
ppo 0:c1e89c49eae5 701 epComplete &= ~EP(EP3IN);
ppo 0:c1e89c49eae5 702 }
ppo 0:c1e89c49eae5 703
ppo 0:c1e89c49eae5 704 if (LPC_USB->INTSTAT & EP(EP3OUT)) {
ppo 0:c1e89c49eae5 705 // Clear EP3_OUT interrupt
ppo 0:c1e89c49eae5 706 LPC_USB->INTSTAT = EP(EP3OUT);
ppo 0:c1e89c49eae5 707 epComplete |= EP(EP3OUT);
ppo 0:c1e89c49eae5 708 //Call callback function. If true, clear epComplete
ppo 0:c1e89c49eae5 709 if (EP3_OUT_callback())
ppo 0:c1e89c49eae5 710 epComplete &= ~EP(EP3OUT);
ppo 0:c1e89c49eae5 711 }
ppo 0:c1e89c49eae5 712 }
ppo 0:c1e89c49eae5 713
ppo 0:c1e89c49eae5 714 #endif