Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/

Fork of STM32_USBDevice by Bradley Scott

Committer:
Troels Nilsson
Date:
Thu Jul 19 12:57:27 2018 +0200
Branch:
feature_WebUSB
Revision:
76:eef92651f52f
Parent:
41:0ca6eeb54b97
Added USBWebUSBSerial class

The class implements a composite device with CDC and a WebUSB compatible interface

Data is read and written from either the CDC or the WebUSB interface depending on the mode.
Default mode is CDC - it can be changed to WebUSB by sending a control message from the host.

Who changed what in which revision?

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