Rizky Ardi Maulana / mbed-os
Committer:
calmantara186
Date:
Thu Feb 22 14:05:19 2018 +0000
Revision:
1:2b6e8130a0ac
Parent:
0:f269e3021894
mbed os

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
elessair 0:f269e3021894 2 *
elessair 0:f269e3021894 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
elessair 0:f269e3021894 4 * and associated documentation files (the "Software"), to deal in the Software without
elessair 0:f269e3021894 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
elessair 0:f269e3021894 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
elessair 0:f269e3021894 7 * Software is furnished to do so, subject to the following conditions:
elessair 0:f269e3021894 8 *
elessair 0:f269e3021894 9 * The above copyright notice and this permission notice shall be included in all copies or
elessair 0:f269e3021894 10 * substantial portions of the Software.
elessair 0:f269e3021894 11 *
elessair 0:f269e3021894 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
elessair 0:f269e3021894 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
elessair 0:f269e3021894 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
elessair 0:f269e3021894 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
elessair 0:f269e3021894 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
elessair 0:f269e3021894 17 */
elessair 0:f269e3021894 18
elessair 0:f269e3021894 19 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC2460)
elessair 0:f269e3021894 20
elessair 0:f269e3021894 21 #include "USBHAL.h"
elessair 0:f269e3021894 22
elessair 0:f269e3021894 23
elessair 0:f269e3021894 24 // Get endpoint direction
elessair 0:f269e3021894 25 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
elessair 0:f269e3021894 26 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
elessair 0:f269e3021894 27
elessair 0:f269e3021894 28 // Convert physical endpoint number to register bit
elessair 0:f269e3021894 29 #define EP(endpoint) (1UL<<endpoint)
elessair 0:f269e3021894 30
elessair 0:f269e3021894 31 // Power Control for Peripherals register
elessair 0:f269e3021894 32 #define PCUSB (1UL<<31)
elessair 0:f269e3021894 33
elessair 0:f269e3021894 34 // USB Clock Control register
elessair 0:f269e3021894 35 #define DEV_CLK_EN (1UL<<1)
elessair 0:f269e3021894 36 #define AHB_CLK_EN (1UL<<4)
elessair 0:f269e3021894 37
elessair 0:f269e3021894 38 // USB Clock Status register
elessair 0:f269e3021894 39 #define DEV_CLK_ON (1UL<<1)
elessair 0:f269e3021894 40 #define AHB_CLK_ON (1UL<<4)
elessair 0:f269e3021894 41
elessair 0:f269e3021894 42 // USB Device Interupt registers
elessair 0:f269e3021894 43 #define FRAME (1UL<<0)
elessair 0:f269e3021894 44 #define EP_FAST (1UL<<1)
elessair 0:f269e3021894 45 #define EP_SLOW (1UL<<2)
elessair 0:f269e3021894 46 #define DEV_STAT (1UL<<3)
elessair 0:f269e3021894 47 #define CCEMPTY (1UL<<4)
elessair 0:f269e3021894 48 #define CDFULL (1UL<<5)
elessair 0:f269e3021894 49 #define RxENDPKT (1UL<<6)
elessair 0:f269e3021894 50 #define TxENDPKT (1UL<<7)
elessair 0:f269e3021894 51 #define EP_RLZED (1UL<<8)
elessair 0:f269e3021894 52 #define ERR_INT (1UL<<9)
elessair 0:f269e3021894 53
elessair 0:f269e3021894 54 // USB Control register
elessair 0:f269e3021894 55 #define RD_EN (1<<0)
elessair 0:f269e3021894 56 #define WR_EN (1<<1)
elessair 0:f269e3021894 57 #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
elessair 0:f269e3021894 58
elessair 0:f269e3021894 59 // USB Receive Packet Length register
elessair 0:f269e3021894 60 #define DV (1UL<<10)
elessair 0:f269e3021894 61 #define PKT_RDY (1UL<<11)
elessair 0:f269e3021894 62 #define PKT_LNGTH_MASK (0x3ff)
elessair 0:f269e3021894 63
elessair 0:f269e3021894 64 // Serial Interface Engine (SIE)
elessair 0:f269e3021894 65 #define SIE_WRITE (0x01)
elessair 0:f269e3021894 66 #define SIE_READ (0x02)
elessair 0:f269e3021894 67 #define SIE_COMMAND (0x05)
elessair 0:f269e3021894 68 #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
elessair 0:f269e3021894 69
elessair 0:f269e3021894 70 // SIE Command codes
elessair 0:f269e3021894 71 #define SIE_CMD_SET_ADDRESS (0xD0)
elessair 0:f269e3021894 72 #define SIE_CMD_CONFIGURE_DEVICE (0xD8)
elessair 0:f269e3021894 73 #define SIE_CMD_SET_MODE (0xF3)
elessair 0:f269e3021894 74 #define SIE_CMD_READ_FRAME_NUMBER (0xF5)
elessair 0:f269e3021894 75 #define SIE_CMD_READ_TEST_REGISTER (0xFD)
elessair 0:f269e3021894 76 #define SIE_CMD_SET_DEVICE_STATUS (0xFE)
elessair 0:f269e3021894 77 #define SIE_CMD_GET_DEVICE_STATUS (0xFE)
elessair 0:f269e3021894 78 #define SIE_CMD_GET_ERROR_CODE (0xFF)
elessair 0:f269e3021894 79 #define SIE_CMD_READ_ERROR_STATUS (0xFB)
elessair 0:f269e3021894 80
elessair 0:f269e3021894 81 #define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)
elessair 0:f269e3021894 82 #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
elessair 0:f269e3021894 83 #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)
elessair 0:f269e3021894 84
elessair 0:f269e3021894 85 #define SIE_CMD_CLEAR_BUFFER (0xF2)
elessair 0:f269e3021894 86 #define SIE_CMD_VALIDATE_BUFFER (0xFA)
elessair 0:f269e3021894 87
elessair 0:f269e3021894 88 // SIE Device Status register
elessair 0:f269e3021894 89 #define SIE_DS_CON (1<<0)
elessair 0:f269e3021894 90 #define SIE_DS_CON_CH (1<<1)
elessair 0:f269e3021894 91 #define SIE_DS_SUS (1<<2)
elessair 0:f269e3021894 92 #define SIE_DS_SUS_CH (1<<3)
elessair 0:f269e3021894 93 #define SIE_DS_RST (1<<4)
elessair 0:f269e3021894 94
elessair 0:f269e3021894 95 // SIE Device Set Address register
elessair 0:f269e3021894 96 #define SIE_DSA_DEV_EN (1<<7)
elessair 0:f269e3021894 97
elessair 0:f269e3021894 98 // SIE Configue Device register
elessair 0:f269e3021894 99 #define SIE_CONF_DEVICE (1<<0)
elessair 0:f269e3021894 100
elessair 0:f269e3021894 101 // Select Endpoint register
elessair 0:f269e3021894 102 #define SIE_SE_FE (1<<0)
elessair 0:f269e3021894 103 #define SIE_SE_ST (1<<1)
elessair 0:f269e3021894 104 #define SIE_SE_STP (1<<2)
elessair 0:f269e3021894 105 #define SIE_SE_PO (1<<3)
elessair 0:f269e3021894 106 #define SIE_SE_EPN (1<<4)
elessair 0:f269e3021894 107 #define SIE_SE_B_1_FULL (1<<5)
elessair 0:f269e3021894 108 #define SIE_SE_B_2_FULL (1<<6)
elessair 0:f269e3021894 109
elessair 0:f269e3021894 110 // Set Endpoint Status command
elessair 0:f269e3021894 111 #define SIE_SES_ST (1<<0)
elessair 0:f269e3021894 112 #define SIE_SES_DA (1<<5)
elessair 0:f269e3021894 113 #define SIE_SES_RF_MO (1<<6)
elessair 0:f269e3021894 114 #define SIE_SES_CND_ST (1<<7)
elessair 0:f269e3021894 115
elessair 0:f269e3021894 116
elessair 0:f269e3021894 117 USBHAL * USBHAL::instance;
elessair 0:f269e3021894 118
elessair 0:f269e3021894 119 static volatile int epComplete;
elessair 0:f269e3021894 120 static uint32_t endpointStallState;
elessair 0:f269e3021894 121
elessair 0:f269e3021894 122 static void SIECommand(uint32_t command) {
elessair 0:f269e3021894 123 // The command phase of a SIE transaction
elessair 0:f269e3021894 124 LPC_USB->USBDevIntClr = CCEMPTY;
elessair 0:f269e3021894 125 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
elessair 0:f269e3021894 126 while (!(LPC_USB->USBDevIntSt & CCEMPTY));
elessair 0:f269e3021894 127 }
elessair 0:f269e3021894 128
elessair 0:f269e3021894 129 static void SIEWriteData(uint8_t data) {
elessair 0:f269e3021894 130 // The data write phase of a SIE transaction
elessair 0:f269e3021894 131 LPC_USB->USBDevIntClr = CCEMPTY;
elessair 0:f269e3021894 132 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
elessair 0:f269e3021894 133 while (!(LPC_USB->USBDevIntSt & CCEMPTY));
elessair 0:f269e3021894 134 }
elessair 0:f269e3021894 135
elessair 0:f269e3021894 136 static uint8_t SIEReadData(uint32_t command) {
elessair 0:f269e3021894 137 // The data read phase of a SIE transaction
elessair 0:f269e3021894 138 LPC_USB->USBDevIntClr = CDFULL;
elessair 0:f269e3021894 139 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
elessair 0:f269e3021894 140 while (!(LPC_USB->USBDevIntSt & CDFULL));
elessair 0:f269e3021894 141 return (uint8_t)LPC_USB->USBCmdData;
elessair 0:f269e3021894 142 }
elessair 0:f269e3021894 143
elessair 0:f269e3021894 144 static void SIEsetDeviceStatus(uint8_t status) {
elessair 0:f269e3021894 145 // Write SIE device status register
elessair 0:f269e3021894 146 SIECommand(SIE_CMD_SET_DEVICE_STATUS);
elessair 0:f269e3021894 147 SIEWriteData(status);
elessair 0:f269e3021894 148 }
elessair 0:f269e3021894 149
elessair 0:f269e3021894 150 static uint8_t SIEgetDeviceStatus(void) {
elessair 0:f269e3021894 151 // Read SIE device status register
elessair 0:f269e3021894 152 SIECommand(SIE_CMD_GET_DEVICE_STATUS);
elessair 0:f269e3021894 153 return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
elessair 0:f269e3021894 154 }
elessair 0:f269e3021894 155
elessair 0:f269e3021894 156 void SIEsetAddress(uint8_t address) {
elessair 0:f269e3021894 157 // Write SIE device address register
elessair 0:f269e3021894 158 SIECommand(SIE_CMD_SET_ADDRESS);
elessair 0:f269e3021894 159 SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
elessair 0:f269e3021894 160 }
elessair 0:f269e3021894 161
elessair 0:f269e3021894 162 static uint8_t SIEselectEndpoint(uint8_t endpoint) {
elessair 0:f269e3021894 163 // SIE select endpoint command
elessair 0:f269e3021894 164 SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
elessair 0:f269e3021894 165 return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
elessair 0:f269e3021894 166 }
elessair 0:f269e3021894 167
elessair 0:f269e3021894 168 static uint8_t SIEclearBuffer(void) {
elessair 0:f269e3021894 169 // SIE clear buffer command
elessair 0:f269e3021894 170 SIECommand(SIE_CMD_CLEAR_BUFFER);
elessair 0:f269e3021894 171 return SIEReadData(SIE_CMD_CLEAR_BUFFER);
elessair 0:f269e3021894 172 }
elessair 0:f269e3021894 173
elessair 0:f269e3021894 174 static void SIEvalidateBuffer(void) {
elessair 0:f269e3021894 175 // SIE validate buffer command
elessair 0:f269e3021894 176 SIECommand(SIE_CMD_VALIDATE_BUFFER);
elessair 0:f269e3021894 177 }
elessair 0:f269e3021894 178
elessair 0:f269e3021894 179 static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status) {
elessair 0:f269e3021894 180 // SIE set endpoint status command
elessair 0:f269e3021894 181 SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
elessair 0:f269e3021894 182 SIEWriteData(status);
elessair 0:f269e3021894 183 }
elessair 0:f269e3021894 184
elessair 0:f269e3021894 185 static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));
elessair 0:f269e3021894 186 static uint16_t SIEgetFrameNumber(void) {
elessair 0:f269e3021894 187 // Read current frame number
elessair 0:f269e3021894 188 uint16_t lowByte;
elessair 0:f269e3021894 189 uint16_t highByte;
elessair 0:f269e3021894 190
elessair 0:f269e3021894 191 SIECommand(SIE_CMD_READ_FRAME_NUMBER);
elessair 0:f269e3021894 192 lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
elessair 0:f269e3021894 193 highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
elessair 0:f269e3021894 194
elessair 0:f269e3021894 195 return (highByte << 8) | lowByte;
elessair 0:f269e3021894 196 }
elessair 0:f269e3021894 197
elessair 0:f269e3021894 198 static void SIEconfigureDevice(void) {
elessair 0:f269e3021894 199 // SIE Configure device command
elessair 0:f269e3021894 200 SIECommand(SIE_CMD_CONFIGURE_DEVICE);
elessair 0:f269e3021894 201 SIEWriteData(SIE_CONF_DEVICE);
elessair 0:f269e3021894 202 }
elessair 0:f269e3021894 203
elessair 0:f269e3021894 204 static void SIEunconfigureDevice(void) {
elessair 0:f269e3021894 205 // SIE Configure device command
elessair 0:f269e3021894 206 SIECommand(SIE_CMD_CONFIGURE_DEVICE);
elessair 0:f269e3021894 207 SIEWriteData(0);
elessair 0:f269e3021894 208 }
elessair 0:f269e3021894 209
elessair 0:f269e3021894 210 static void SIEconnect(void) {
elessair 0:f269e3021894 211 // Connect USB device
elessair 0:f269e3021894 212 uint8_t status = SIEgetDeviceStatus();
elessair 0:f269e3021894 213 SIEsetDeviceStatus(status | SIE_DS_CON);
elessair 0:f269e3021894 214 }
elessair 0:f269e3021894 215
elessair 0:f269e3021894 216
elessair 0:f269e3021894 217 static void SIEdisconnect(void) {
elessair 0:f269e3021894 218 // Disconnect USB device
elessair 0:f269e3021894 219 uint8_t status = SIEgetDeviceStatus();
elessair 0:f269e3021894 220 SIEsetDeviceStatus(status & ~SIE_DS_CON);
elessair 0:f269e3021894 221 }
elessair 0:f269e3021894 222
elessair 0:f269e3021894 223
elessair 0:f269e3021894 224 static uint8_t selectEndpointClearInterrupt(uint8_t endpoint) {
elessair 0:f269e3021894 225 // Implemented using using EP_INT_CLR.
elessair 0:f269e3021894 226 LPC_USB->USBEpIntClr = EP(endpoint);
elessair 0:f269e3021894 227 while (!(LPC_USB->USBDevIntSt & CDFULL));
elessair 0:f269e3021894 228 return (uint8_t)LPC_USB->USBCmdData;
elessair 0:f269e3021894 229 }
elessair 0:f269e3021894 230
elessair 0:f269e3021894 231
elessair 0:f269e3021894 232 static void enableEndpointEvent(uint8_t endpoint) {
elessair 0:f269e3021894 233 // Enable an endpoint interrupt
elessair 0:f269e3021894 234 LPC_USB->USBEpIntEn |= EP(endpoint);
elessair 0:f269e3021894 235 }
elessair 0:f269e3021894 236
elessair 0:f269e3021894 237 static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused));
elessair 0:f269e3021894 238 static void disableEndpointEvent(uint8_t endpoint) {
elessair 0:f269e3021894 239 // Disable an endpoint interrupt
elessair 0:f269e3021894 240 LPC_USB->USBEpIntEn &= ~EP(endpoint);
elessair 0:f269e3021894 241 }
elessair 0:f269e3021894 242
elessair 0:f269e3021894 243 static volatile uint32_t __attribute__((used)) dummyRead;
elessair 0:f269e3021894 244 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
elessair 0:f269e3021894 245 // Read from an OUT endpoint
elessair 0:f269e3021894 246 uint32_t size;
elessair 0:f269e3021894 247 uint32_t i;
elessair 0:f269e3021894 248 uint32_t data = 0;
elessair 0:f269e3021894 249 uint8_t offset;
elessair 0:f269e3021894 250
elessair 0:f269e3021894 251 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
elessair 0:f269e3021894 252 while (!(LPC_USB->USBRxPLen & PKT_RDY));
elessair 0:f269e3021894 253
elessair 0:f269e3021894 254 size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
elessair 0:f269e3021894 255
elessair 0:f269e3021894 256 offset = 0;
elessair 0:f269e3021894 257
elessair 0:f269e3021894 258 if (size > 0) {
elessair 0:f269e3021894 259 for (i=0; i<size; i++) {
elessair 0:f269e3021894 260 if (offset==0) {
elessair 0:f269e3021894 261 // Fetch up to four bytes of data as a word
elessair 0:f269e3021894 262 data = LPC_USB->USBRxData;
elessair 0:f269e3021894 263 }
elessair 0:f269e3021894 264
elessair 0:f269e3021894 265 // extract a byte
elessair 0:f269e3021894 266 *buffer = (data>>offset) & 0xff;
elessair 0:f269e3021894 267 buffer++;
elessair 0:f269e3021894 268
elessair 0:f269e3021894 269 // move on to the next byte
elessair 0:f269e3021894 270 offset = (offset + 8) % 32;
elessair 0:f269e3021894 271 }
elessair 0:f269e3021894 272 } else {
elessair 0:f269e3021894 273 dummyRead = LPC_USB->USBRxData;
elessair 0:f269e3021894 274 }
elessair 0:f269e3021894 275
elessair 0:f269e3021894 276 LPC_USB->USBCtrl = 0;
elessair 0:f269e3021894 277
elessair 0:f269e3021894 278 if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) {
elessair 0:f269e3021894 279 SIEselectEndpoint(endpoint);
elessair 0:f269e3021894 280 SIEclearBuffer();
elessair 0:f269e3021894 281 }
elessair 0:f269e3021894 282
elessair 0:f269e3021894 283 return size;
elessair 0:f269e3021894 284 }
elessair 0:f269e3021894 285
elessair 0:f269e3021894 286 static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size) {
elessair 0:f269e3021894 287 // Write to an IN endpoint
elessair 0:f269e3021894 288 uint32_t temp, data;
elessair 0:f269e3021894 289 uint8_t offset;
elessair 0:f269e3021894 290
elessair 0:f269e3021894 291 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
elessair 0:f269e3021894 292
elessair 0:f269e3021894 293 LPC_USB->USBTxPLen = size;
elessair 0:f269e3021894 294 offset = 0;
elessair 0:f269e3021894 295 data = 0;
elessair 0:f269e3021894 296
elessair 0:f269e3021894 297 if (size>0) {
elessair 0:f269e3021894 298 do {
elessair 0:f269e3021894 299 // Fetch next data byte into a word-sized temporary variable
elessair 0:f269e3021894 300 temp = *buffer++;
elessair 0:f269e3021894 301
elessair 0:f269e3021894 302 // Add to current data word
elessair 0:f269e3021894 303 temp = temp << offset;
elessair 0:f269e3021894 304 data = data | temp;
elessair 0:f269e3021894 305
elessair 0:f269e3021894 306 // move on to the next byte
elessair 0:f269e3021894 307 offset = (offset + 8) % 32;
elessair 0:f269e3021894 308 size--;
elessair 0:f269e3021894 309
elessair 0:f269e3021894 310 if ((offset==0) || (size==0)) {
elessair 0:f269e3021894 311 // Write the word to the endpoint
elessair 0:f269e3021894 312 LPC_USB->USBTxData = data;
elessair 0:f269e3021894 313 data = 0;
elessair 0:f269e3021894 314 }
elessair 0:f269e3021894 315 } while (size>0);
elessair 0:f269e3021894 316 } else {
elessair 0:f269e3021894 317 LPC_USB->USBTxData = 0;
elessair 0:f269e3021894 318 }
elessair 0:f269e3021894 319
elessair 0:f269e3021894 320 // Clear WR_EN to cover zero length packet case
elessair 0:f269e3021894 321 LPC_USB->USBCtrl=0;
elessair 0:f269e3021894 322
elessair 0:f269e3021894 323 SIEselectEndpoint(endpoint);
elessair 0:f269e3021894 324 SIEvalidateBuffer();
elessair 0:f269e3021894 325 }
elessair 0:f269e3021894 326
elessair 0:f269e3021894 327 USBHAL::USBHAL(void) {
elessair 0:f269e3021894 328 // Disable IRQ
elessair 0:f269e3021894 329 NVIC_DisableIRQ(USB_IRQn);
elessair 0:f269e3021894 330
elessair 0:f269e3021894 331 // fill in callback array
elessair 0:f269e3021894 332 epCallback[0] = &USBHAL::EP1_OUT_callback;
elessair 0:f269e3021894 333 epCallback[1] = &USBHAL::EP1_IN_callback;
elessair 0:f269e3021894 334 epCallback[2] = &USBHAL::EP2_OUT_callback;
elessair 0:f269e3021894 335 epCallback[3] = &USBHAL::EP2_IN_callback;
elessair 0:f269e3021894 336 epCallback[4] = &USBHAL::EP3_OUT_callback;
elessair 0:f269e3021894 337 epCallback[5] = &USBHAL::EP3_IN_callback;
elessair 0:f269e3021894 338 epCallback[6] = &USBHAL::EP4_OUT_callback;
elessair 0:f269e3021894 339 epCallback[7] = &USBHAL::EP4_IN_callback;
elessair 0:f269e3021894 340 epCallback[8] = &USBHAL::EP5_OUT_callback;
elessair 0:f269e3021894 341 epCallback[9] = &USBHAL::EP5_IN_callback;
elessair 0:f269e3021894 342 epCallback[10] = &USBHAL::EP6_OUT_callback;
elessair 0:f269e3021894 343 epCallback[11] = &USBHAL::EP6_IN_callback;
elessair 0:f269e3021894 344 epCallback[12] = &USBHAL::EP7_OUT_callback;
elessair 0:f269e3021894 345 epCallback[13] = &USBHAL::EP7_IN_callback;
elessair 0:f269e3021894 346 epCallback[14] = &USBHAL::EP8_OUT_callback;
elessair 0:f269e3021894 347 epCallback[15] = &USBHAL::EP8_IN_callback;
elessair 0:f269e3021894 348 epCallback[16] = &USBHAL::EP9_OUT_callback;
elessair 0:f269e3021894 349 epCallback[17] = &USBHAL::EP9_IN_callback;
elessair 0:f269e3021894 350 epCallback[18] = &USBHAL::EP10_OUT_callback;
elessair 0:f269e3021894 351 epCallback[19] = &USBHAL::EP10_IN_callback;
elessair 0:f269e3021894 352 epCallback[20] = &USBHAL::EP11_OUT_callback;
elessair 0:f269e3021894 353 epCallback[21] = &USBHAL::EP11_IN_callback;
elessair 0:f269e3021894 354 epCallback[22] = &USBHAL::EP12_OUT_callback;
elessair 0:f269e3021894 355 epCallback[23] = &USBHAL::EP12_IN_callback;
elessair 0:f269e3021894 356 epCallback[24] = &USBHAL::EP13_OUT_callback;
elessair 0:f269e3021894 357 epCallback[25] = &USBHAL::EP13_IN_callback;
elessair 0:f269e3021894 358 epCallback[26] = &USBHAL::EP14_OUT_callback;
elessair 0:f269e3021894 359 epCallback[27] = &USBHAL::EP14_IN_callback;
elessair 0:f269e3021894 360 epCallback[28] = &USBHAL::EP15_OUT_callback;
elessair 0:f269e3021894 361 epCallback[29] = &USBHAL::EP15_IN_callback;
elessair 0:f269e3021894 362
elessair 0:f269e3021894 363 // Enable power to USB device controller
elessair 0:f269e3021894 364 LPC_SC->PCONP |= PCUSB;
elessair 0:f269e3021894 365
elessair 0:f269e3021894 366 // Enable USB clocks
elessair 0:f269e3021894 367 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
elessair 0:f269e3021894 368 while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
elessair 0:f269e3021894 369
elessair 0:f269e3021894 370 // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
elessair 0:f269e3021894 371 LPC_PINCON->PINSEL1 &= 0xc3ffffff;
elessair 0:f269e3021894 372 LPC_PINCON->PINSEL1 |= 0x14000000;
elessair 0:f269e3021894 373
elessair 0:f269e3021894 374 // Disconnect USB device
elessair 0:f269e3021894 375 SIEdisconnect();
elessair 0:f269e3021894 376
elessair 0:f269e3021894 377 // Configure pin P2.9 to be Connect
elessair 0:f269e3021894 378 LPC_PINCON->PINSEL4 &= 0xfffcffff;
elessair 0:f269e3021894 379 LPC_PINCON->PINSEL4 |= 0x00040000;
elessair 0:f269e3021894 380
elessair 0:f269e3021894 381 // Connect must be low for at least 2.5uS
elessair 0:f269e3021894 382 wait(0.3);
elessair 0:f269e3021894 383
elessair 0:f269e3021894 384 // Set the maximum packet size for the control endpoints
elessair 0:f269e3021894 385 realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
elessair 0:f269e3021894 386 realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
elessair 0:f269e3021894 387
elessair 0:f269e3021894 388 // Attach IRQ
elessair 0:f269e3021894 389 instance = this;
elessair 0:f269e3021894 390 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
elessair 0:f269e3021894 391
elessair 0:f269e3021894 392 // Enable interrupts for device events and EP0
elessair 0:f269e3021894 393 LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;
elessair 0:f269e3021894 394 enableEndpointEvent(EP0IN);
elessair 0:f269e3021894 395 enableEndpointEvent(EP0OUT);
elessair 0:f269e3021894 396 }
elessair 0:f269e3021894 397
elessair 0:f269e3021894 398 USBHAL::~USBHAL(void) {
elessair 0:f269e3021894 399 // Ensure device disconnected
elessair 0:f269e3021894 400 SIEdisconnect();
elessair 0:f269e3021894 401 // Disable USB interrupts
elessair 0:f269e3021894 402 NVIC_DisableIRQ(USB_IRQn);
elessair 0:f269e3021894 403 }
elessair 0:f269e3021894 404
elessair 0:f269e3021894 405 void USBHAL::connect(void) {
elessair 0:f269e3021894 406 NVIC_EnableIRQ(USB_IRQn);
elessair 0:f269e3021894 407 // Connect USB device
elessair 0:f269e3021894 408 SIEconnect();
elessair 0:f269e3021894 409 }
elessair 0:f269e3021894 410
elessair 0:f269e3021894 411 void USBHAL::disconnect(void) {
elessair 0:f269e3021894 412 NVIC_DisableIRQ(USB_IRQn);
elessair 0:f269e3021894 413 // Disconnect USB device
elessair 0:f269e3021894 414 SIEdisconnect();
elessair 0:f269e3021894 415 }
elessair 0:f269e3021894 416
elessair 0:f269e3021894 417 void USBHAL::configureDevice(void) {
elessair 0:f269e3021894 418 SIEconfigureDevice();
elessair 0:f269e3021894 419 }
elessair 0:f269e3021894 420
elessair 0:f269e3021894 421 void USBHAL::unconfigureDevice(void) {
elessair 0:f269e3021894 422 SIEunconfigureDevice();
elessair 0:f269e3021894 423 }
elessair 0:f269e3021894 424
elessair 0:f269e3021894 425 void USBHAL::setAddress(uint8_t address) {
elessair 0:f269e3021894 426 SIEsetAddress(address);
elessair 0:f269e3021894 427 }
elessair 0:f269e3021894 428
elessair 0:f269e3021894 429 void USBHAL::EP0setup(uint8_t *buffer) {
elessair 0:f269e3021894 430 endpointReadcore(EP0OUT, buffer);
elessair 0:f269e3021894 431 }
elessair 0:f269e3021894 432
elessair 0:f269e3021894 433 void USBHAL::EP0read(void) {
elessair 0:f269e3021894 434 // Not required
elessair 0:f269e3021894 435 }
elessair 0:f269e3021894 436
elessair 0:f269e3021894 437 void USBHAL::EP0readStage(void) {
elessair 0:f269e3021894 438 // Not required
elessair 0:f269e3021894 439 }
elessair 0:f269e3021894 440
elessair 0:f269e3021894 441 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
elessair 0:f269e3021894 442 return endpointReadcore(EP0OUT, buffer);
elessair 0:f269e3021894 443 }
elessair 0:f269e3021894 444
elessair 0:f269e3021894 445 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
elessair 0:f269e3021894 446 endpointWritecore(EP0IN, buffer, size);
elessair 0:f269e3021894 447 }
elessair 0:f269e3021894 448
elessair 0:f269e3021894 449 void USBHAL::EP0getWriteResult(void) {
elessair 0:f269e3021894 450 // Not required
elessair 0:f269e3021894 451 }
elessair 0:f269e3021894 452
elessair 0:f269e3021894 453 void USBHAL::EP0stall(void) {
elessair 0:f269e3021894 454 // This will stall both control endpoints
elessair 0:f269e3021894 455 stallEndpoint(EP0OUT);
elessair 0:f269e3021894 456 }
elessair 0:f269e3021894 457
elessair 0:f269e3021894 458 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
elessair 0:f269e3021894 459 return EP_PENDING;
elessair 0:f269e3021894 460 }
elessair 0:f269e3021894 461
elessair 0:f269e3021894 462 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
elessair 0:f269e3021894 463
elessair 0:f269e3021894 464 //for isochronous endpoint, we don't wait an interrupt
elessair 0:f269e3021894 465 if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) {
elessair 0:f269e3021894 466 if (!(epComplete & EP(endpoint)))
elessair 0:f269e3021894 467 return EP_PENDING;
elessair 0:f269e3021894 468 }
elessair 0:f269e3021894 469
elessair 0:f269e3021894 470 *bytesRead = endpointReadcore(endpoint, buffer);
elessair 0:f269e3021894 471 epComplete &= ~EP(endpoint);
elessair 0:f269e3021894 472 return EP_COMPLETED;
elessair 0:f269e3021894 473 }
elessair 0:f269e3021894 474
elessair 0:f269e3021894 475 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
elessair 0:f269e3021894 476 if (getEndpointStallState(endpoint)) {
elessair 0:f269e3021894 477 return EP_STALLED;
elessair 0:f269e3021894 478 }
elessair 0:f269e3021894 479
elessair 0:f269e3021894 480 epComplete &= ~EP(endpoint);
elessair 0:f269e3021894 481
elessair 0:f269e3021894 482 endpointWritecore(endpoint, data, size);
elessair 0:f269e3021894 483 return EP_PENDING;
elessair 0:f269e3021894 484 }
elessair 0:f269e3021894 485
elessair 0:f269e3021894 486 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
elessair 0:f269e3021894 487 if (epComplete & EP(endpoint)) {
elessair 0:f269e3021894 488 epComplete &= ~EP(endpoint);
elessair 0:f269e3021894 489 return EP_COMPLETED;
elessair 0:f269e3021894 490 }
elessair 0:f269e3021894 491
elessair 0:f269e3021894 492 return EP_PENDING;
elessair 0:f269e3021894 493 }
elessair 0:f269e3021894 494
elessair 0:f269e3021894 495 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
elessair 0:f269e3021894 496 // Realise an endpoint
elessair 0:f269e3021894 497 LPC_USB->USBDevIntClr = EP_RLZED;
elessair 0:f269e3021894 498 LPC_USB->USBReEp |= EP(endpoint);
elessair 0:f269e3021894 499 LPC_USB->USBEpInd = endpoint;
elessair 0:f269e3021894 500 LPC_USB->USBMaxPSize = maxPacket;
elessair 0:f269e3021894 501
elessair 0:f269e3021894 502 while (!(LPC_USB->USBDevIntSt & EP_RLZED));
elessair 0:f269e3021894 503 LPC_USB->USBDevIntClr = EP_RLZED;
elessair 0:f269e3021894 504
elessair 0:f269e3021894 505 // Clear stall state
elessair 0:f269e3021894 506 endpointStallState &= ~EP(endpoint);
elessair 0:f269e3021894 507
elessair 0:f269e3021894 508 enableEndpointEvent(endpoint);
elessair 0:f269e3021894 509 return true;
elessair 0:f269e3021894 510 }
elessair 0:f269e3021894 511
elessair 0:f269e3021894 512 void USBHAL::stallEndpoint(uint8_t endpoint) {
elessair 0:f269e3021894 513 // Stall an endpoint
elessair 0:f269e3021894 514 if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) {
elessair 0:f269e3021894 515 // Conditionally stall both control endpoints
elessair 0:f269e3021894 516 SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
elessair 0:f269e3021894 517 } else {
elessair 0:f269e3021894 518 SIEsetEndpointStatus(endpoint, SIE_SES_ST);
elessair 0:f269e3021894 519
elessair 0:f269e3021894 520 // Update stall state
elessair 0:f269e3021894 521 endpointStallState |= EP(endpoint);
elessair 0:f269e3021894 522 }
elessair 0:f269e3021894 523 }
elessair 0:f269e3021894 524
elessair 0:f269e3021894 525 void USBHAL::unstallEndpoint(uint8_t endpoint) {
elessair 0:f269e3021894 526 // Unstall an endpoint. The endpoint will also be reinitialised
elessair 0:f269e3021894 527 SIEsetEndpointStatus(endpoint, 0);
elessair 0:f269e3021894 528
elessair 0:f269e3021894 529 // Update stall state
elessair 0:f269e3021894 530 endpointStallState &= ~EP(endpoint);
elessair 0:f269e3021894 531 }
elessair 0:f269e3021894 532
elessair 0:f269e3021894 533 bool USBHAL::getEndpointStallState(uint8_t endpoint) {
elessair 0:f269e3021894 534 // Returns true if endpoint stalled
elessair 0:f269e3021894 535 return endpointStallState & EP(endpoint);
elessair 0:f269e3021894 536 }
elessair 0:f269e3021894 537
elessair 0:f269e3021894 538 void USBHAL::remoteWakeup(void) {
elessair 0:f269e3021894 539 // Remote wakeup
elessair 0:f269e3021894 540 uint8_t status;
elessair 0:f269e3021894 541
elessair 0:f269e3021894 542 // Enable USB clocks
elessair 0:f269e3021894 543 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
elessair 0:f269e3021894 544 while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
elessair 0:f269e3021894 545
elessair 0:f269e3021894 546 status = SIEgetDeviceStatus();
elessair 0:f269e3021894 547 SIEsetDeviceStatus(status & ~SIE_DS_SUS);
elessair 0:f269e3021894 548 }
elessair 0:f269e3021894 549
elessair 0:f269e3021894 550 void USBHAL::_usbisr(void) {
elessair 0:f269e3021894 551 instance->usbisr();
elessair 0:f269e3021894 552 }
elessair 0:f269e3021894 553
elessair 0:f269e3021894 554
elessair 0:f269e3021894 555 void USBHAL::usbisr(void) {
elessair 0:f269e3021894 556 uint8_t devStat;
elessair 0:f269e3021894 557
elessair 0:f269e3021894 558 if (LPC_USB->USBDevIntSt & FRAME) {
elessair 0:f269e3021894 559 // Start of frame event
elessair 0:f269e3021894 560 SOF(SIEgetFrameNumber());
elessair 0:f269e3021894 561 // Clear interrupt status flag
elessair 0:f269e3021894 562 LPC_USB->USBDevIntClr = FRAME;
elessair 0:f269e3021894 563 }
elessair 0:f269e3021894 564
elessair 0:f269e3021894 565 if (LPC_USB->USBDevIntSt & DEV_STAT) {
elessair 0:f269e3021894 566 // Device Status interrupt
elessair 0:f269e3021894 567 // Must clear the interrupt status flag before reading the device status from the SIE
elessair 0:f269e3021894 568 LPC_USB->USBDevIntClr = DEV_STAT;
elessair 0:f269e3021894 569
elessair 0:f269e3021894 570 // Read device status from SIE
elessair 0:f269e3021894 571 devStat = SIEgetDeviceStatus();
elessair 0:f269e3021894 572 //printf("devStat: %d\r\n", devStat);
elessair 0:f269e3021894 573
elessair 0:f269e3021894 574 if (devStat & SIE_DS_SUS_CH) {
elessair 0:f269e3021894 575 // Suspend status changed
elessair 0:f269e3021894 576 if((devStat & SIE_DS_SUS) != 0) {
elessair 0:f269e3021894 577 suspendStateChanged(0);
elessair 0:f269e3021894 578 }
elessair 0:f269e3021894 579 }
elessair 0:f269e3021894 580
elessair 0:f269e3021894 581 if (devStat & SIE_DS_RST) {
elessair 0:f269e3021894 582 // Bus reset
elessair 0:f269e3021894 583 if((devStat & SIE_DS_SUS) == 0) {
elessair 0:f269e3021894 584 suspendStateChanged(1);
elessair 0:f269e3021894 585 }
elessair 0:f269e3021894 586 busReset();
elessair 0:f269e3021894 587 }
elessair 0:f269e3021894 588 }
elessair 0:f269e3021894 589
elessair 0:f269e3021894 590 if (LPC_USB->USBDevIntSt & EP_SLOW) {
elessair 0:f269e3021894 591 // (Slow) Endpoint Interrupt
elessair 0:f269e3021894 592
elessair 0:f269e3021894 593 // Process each endpoint interrupt
elessair 0:f269e3021894 594 if (LPC_USB->USBEpIntSt & EP(EP0OUT)) {
elessair 0:f269e3021894 595 if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
elessair 0:f269e3021894 596 // this is a setup packet
elessair 0:f269e3021894 597 EP0setupCallback();
elessair 0:f269e3021894 598 } else {
elessair 0:f269e3021894 599 EP0out();
elessair 0:f269e3021894 600 }
elessair 0:f269e3021894 601 LPC_USB->USBDevIntClr = EP_SLOW;
elessair 0:f269e3021894 602 }
elessair 0:f269e3021894 603
elessair 0:f269e3021894 604 if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
elessair 0:f269e3021894 605 selectEndpointClearInterrupt(EP0IN);
elessair 0:f269e3021894 606 LPC_USB->USBDevIntClr = EP_SLOW;
elessair 0:f269e3021894 607 EP0in();
elessair 0:f269e3021894 608 }
elessair 0:f269e3021894 609
elessair 0:f269e3021894 610 for (uint8_t num = 2; num < 16*2; num++) {
elessair 0:f269e3021894 611 if (LPC_USB->USBEpIntSt & EP(num)) {
elessair 0:f269e3021894 612 selectEndpointClearInterrupt(num);
elessair 0:f269e3021894 613 epComplete |= EP(num);
elessair 0:f269e3021894 614 LPC_USB->USBDevIntClr = EP_SLOW;
elessair 0:f269e3021894 615 if ((instance->*(epCallback[num - 2]))()) {
elessair 0:f269e3021894 616 epComplete &= ~EP(num);
elessair 0:f269e3021894 617 }
elessair 0:f269e3021894 618 }
elessair 0:f269e3021894 619 }
elessair 0:f269e3021894 620 }
elessair 0:f269e3021894 621 }
elessair 0:f269e3021894 622
elessair 0:f269e3021894 623 #endif