Commit | Line | Data |
---|---|---|
47b0bbd2 MM |
1 | /* Copyright (c) 2010-2011 mbed.org, MIT License\r |
2 | *\r | |
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software\r | |
4 | * and associated documentation files (the "Software"), to deal in the Software without\r | |
5 | * restriction, including without limitation the rights to use, copy, modify, merge, publish,\r | |
6 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the\r | |
7 | * Software is furnished to do so, subject to the following conditions:\r | |
8 | *\r | |
9 | * The above copyright notice and this permission notice shall be included in all copies or\r | |
10 | * substantial portions of the Software.\r | |
11 | *\r | |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING\r | |
13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r | |
14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r | |
15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r | |
16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
17 | */\r | |
18 | \r | |
19 | #if defined(TARGET_LPC1768) || defined (__LPC17XX__)\r | |
20 | \r | |
21 | // void setled(int, bool);\r | |
22 | #define setled(a, b) do {} while (0)\r | |
23 | \r | |
24 | #include "USBHAL.h"\r | |
25 | \r | |
26 | #include <cstdio>\r | |
27 | \r | |
28 | #include <LPC17xx.h>\r | |
29 | \r | |
30 | #ifdef MBED\r | |
31 | #include <score_cm3.h>\r | |
32 | #else\r | |
33 | #include <lpc17xx_nvic.h>\r | |
34 | #endif\r | |
35 | \r | |
36 | #include "debug.h"\r | |
37 | \r | |
38 | #ifndef ENTER_ISR\r | |
39 | #define ENTER_ISR() do {} while (0)\r | |
40 | #endif\r | |
41 | \r | |
42 | #ifndef LEAVE_ISR\r | |
43 | #define LEAVE_ISR() do {} while (0)\r | |
44 | #endif\r | |
45 | \r | |
46 | #define iprintf(...)\r | |
47 | \r | |
48 | // Get endpoint direction\r | |
49 | #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)\r | |
50 | #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)\r | |
51 | \r | |
52 | #define IN_BEP(endpoint) ((endpoint) & 0x80 ? true : false)\r | |
53 | #define OUT_BEP(endpoint) ((endpoint) & 0x80 ? false : true)\r | |
54 | \r | |
55 | // Convert physical endpoint number to register bit\r | |
56 | #define EP(endpoint) (1UL<<endpoint)\r | |
57 | \r | |
58 | #define ISOCHRONOUS_ENDPOINTS ((1UL << 3) | (1UL << 6) | (1UL << 9) | (1UL << 12))\r | |
59 | \r | |
60 | #define IS_ISOCHRONOUS(bEP) ((1UL << (bEP & 0x0F)) & ISOCHRONOUS_ENDPOINTS)\r | |
61 | \r | |
62 | // Power Control for Peripherals register\r | |
63 | #define PCUSB (1UL<<31)\r | |
64 | \r | |
65 | // USB Clock Control register\r | |
66 | #define DEV_CLK_EN (1UL<<1)\r | |
67 | #define AHB_CLK_EN (1UL<<4)\r | |
68 | \r | |
69 | // USB Clock Status register\r | |
70 | #define DEV_CLK_ON (1UL<<1)\r | |
71 | #define AHB_CLK_ON (1UL<<4)\r | |
72 | \r | |
73 | // USB Device Interupt registers\r | |
74 | #define FRAME (1UL<<0)\r | |
75 | #define EP_FAST (1UL<<1)\r | |
76 | #define EP_SLOW (1UL<<2)\r | |
77 | #define DEV_STAT (1UL<<3)\r | |
78 | #define CCEMPTY (1UL<<4)\r | |
79 | #define CDFULL (1UL<<5)\r | |
80 | #define RxENDPKT (1UL<<6)\r | |
81 | #define TxENDPKT (1UL<<7)\r | |
82 | #define EP_RLZED (1UL<<8)\r | |
83 | #define ERR_INT (1UL<<9)\r | |
84 | \r | |
85 | /* USBRxPLen bits */\r | |
86 | #define PKT_LNGTH (1<<0)\r | |
87 | #define PKT_LNGTH_MASK 0x3FF\r | |
88 | #define DV (1<<10)\r | |
89 | #define PKT_RDY (1<<11)\r | |
90 | \r | |
91 | /* Select Endpoint command read bits */\r | |
92 | #define EPSTAT_FE (1<<0)\r | |
93 | #define EPSTAT_ST (1<<1)\r | |
94 | #define EPSTAT_STP (1<<2)\r | |
95 | #define EPSTAT_PO (1<<3)\r | |
96 | #define EPSTAT_EPN (1<<4)\r | |
97 | #define EPSTAT_B1FULL (1<<5)\r | |
98 | #define EPSTAT_B2FULL (1<<6)\r | |
99 | \r | |
100 | // endpoint status sent through callback\r | |
101 | #define EP_STATUS_DATA (1<<0) /**< EP has data */\r | |
102 | #define EP_STATUS_STALLED (1<<1) /**< EP is stalled */\r | |
103 | #define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */\r | |
104 | #define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */\r | |
105 | #define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */\r | |
106 | \r | |
107 | // USB Control register\r | |
108 | #define RD_EN (1<<0)\r | |
109 | #define WR_EN (1<<1)\r | |
110 | #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)\r | |
111 | \r | |
112 | // USB Receive Packet Length register\r | |
113 | // #define DV (1UL<<10)\r | |
114 | // #define PKT_RDY (1UL<<11)\r | |
115 | // #define PKT_LNGTH_MASK (0x3ff)\r | |
116 | \r | |
117 | // Serial Interface Engine (SIE)\r | |
118 | #define SIE_WRITE (0x01)\r | |
119 | #define SIE_READ (0x02)\r | |
120 | #define SIE_COMMAND (0x05)\r | |
121 | #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))\r | |
122 | \r | |
123 | // SIE Command codes\r | |
124 | #define SIE_CMD_SET_ADDRESS (0xD0)\r | |
125 | #define SIE_CMD_CONFIGURE_DEVICE (0xD8)\r | |
126 | #define SIE_CMD_SET_MODE (0xF3)\r | |
127 | #define SIE_CMD_READ_FRAME_NUMBER (0xF5)\r | |
128 | #define SIE_CMD_READ_TEST_REGISTER (0xFD)\r | |
129 | #define SIE_CMD_SET_DEVICE_STATUS (0xFE)\r | |
130 | #define SIE_CMD_GET_DEVICE_STATUS (0xFE)\r | |
131 | #define SIE_CMD_GET_ERROR_CODE (0xFF)\r | |
132 | #define SIE_CMD_READ_ERROR_STATUS (0xFB)\r | |
133 | \r | |
134 | #define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)\r | |
135 | #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)\r | |
136 | #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)\r | |
137 | \r | |
138 | #define SIE_CMD_CLEAR_BUFFER (0xF2)\r | |
139 | #define SIE_CMD_VALIDATE_BUFFER (0xFA)\r | |
140 | \r | |
141 | // SIE Device Status register\r | |
142 | #define SIE_DS_CON (1<<0)\r | |
143 | #define SIE_DS_CON_CH (1<<1)\r | |
144 | #define SIE_DS_SUS (1<<2)\r | |
145 | #define SIE_DS_SUS_CH (1<<3)\r | |
146 | #define SIE_DS_RST (1<<4)\r | |
147 | \r | |
148 | // SIE Device Set Address register\r | |
149 | #define SIE_DSA_DEV_EN (1<<7)\r | |
150 | \r | |
151 | // SIE Configue Device register\r | |
152 | #define SIE_CONF_DEVICE (1<<0)\r | |
153 | \r | |
154 | // Select Endpoint register\r | |
155 | #define SIE_SE_FE (1<<0)\r | |
156 | #define SIE_SE_ST (1<<1)\r | |
157 | #define SIE_SE_STP (1<<2)\r | |
158 | #define SIE_SE_PO (1<<3)\r | |
159 | #define SIE_SE_EPN (1<<4)\r | |
160 | #define SIE_SE_B_1_FULL (1<<5)\r | |
161 | #define SIE_SE_B_2_FULL (1<<6)\r | |
162 | \r | |
163 | // Set Endpoint Status command\r | |
164 | #define SIE_SES_ST (1<<0)\r | |
165 | #define SIE_SES_DA (1<<5)\r | |
166 | #define SIE_SES_RF_MO (1<<6)\r | |
167 | #define SIE_SES_CND_ST (1<<7)\r | |
168 | \r | |
169 | // endpoint modes\r | |
170 | #define SIE_MODE_AP_CLK (1<<0)\r | |
171 | #define SIE_MODE_INAK_CI (1<<1)\r | |
172 | #define SIE_MODE_INAK_CO (1<<2)\r | |
173 | #define SIE_MODE_INAK_II (1<<3)\r | |
174 | #define SIE_MODE_INAK_IO (1<<4)\r | |
175 | #define SIE_MODE_INAK_BI (1<<5)\r | |
176 | #define SIE_MODE_INAK_BO (1<<6)\r | |
177 | \r | |
178 | USBHAL * USBHAL::instance;\r | |
179 | \r | |
180 | // volatile uint32_t epComplete;\r | |
181 | volatile uint32_t USBEpIntEn;\r | |
182 | uint32_t endpointStallState;\r | |
183 | \r | |
184 | static void SIECommand(uint32_t command) {\r | |
185 | // The command phase of a SIE transaction\r | |
186 | LPC_USB->USBDevIntClr = CCEMPTY;\r | |
187 | LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);\r | |
188 | setled(4, 1); while (!(LPC_USB->USBDevIntSt & CCEMPTY)); setled(4, 0);\r | |
189 | }\r | |
190 | \r | |
191 | static void SIEWriteData(uint8_t data) {\r | |
192 | // The data write phase of a SIE transaction\r | |
193 | LPC_USB->USBDevIntClr = CCEMPTY;\r | |
194 | LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);\r | |
195 | setled(4, 1); while (!(LPC_USB->USBDevIntSt & CCEMPTY)); setled(4, 0);\r | |
196 | }\r | |
197 | \r | |
198 | static uint8_t SIEReadData(uint32_t command) {\r | |
199 | // The data read phase of a SIE transaction\r | |
200 | LPC_USB->USBDevIntClr = CDFULL;\r | |
201 | LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);\r | |
202 | setled(4, 1); while (!(LPC_USB->USBDevIntSt & CDFULL)); setled(4, 0);\r | |
203 | return (uint8_t)LPC_USB->USBCmdData;\r | |
204 | }\r | |
205 | \r | |
206 | static void SIEsetDeviceStatus(uint8_t status) {\r | |
207 | // Write SIE device status register\r | |
208 | // iprintf("SIEsetDeviceStatus: %02X\n", status);\r | |
209 | SIECommand(SIE_CMD_SET_DEVICE_STATUS);\r | |
210 | // iprintf("SIEsetDeviceStatus Write\n");\r | |
211 | SIEWriteData(status);\r | |
212 | // iprintf("SIEsetDeviceStatus OK\n");\r | |
213 | }\r | |
214 | \r | |
215 | static uint8_t SIEgetDeviceStatus(void) {\r | |
216 | // Read SIE device status register\r | |
217 | SIECommand(SIE_CMD_GET_DEVICE_STATUS);\r | |
218 | return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);\r | |
219 | }\r | |
220 | \r | |
221 | static void SIEsetMode(uint8_t mode) {\r | |
222 | SIECommand(SIE_CMD_SET_MODE);\r | |
223 | SIEWriteData(mode);\r | |
224 | }\r | |
225 | \r | |
226 | static void SIEsetAddress(uint8_t address) {\r | |
227 | // Write SIE device address register\r | |
228 | SIECommand(SIE_CMD_SET_ADDRESS);\r | |
229 | SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);\r | |
230 | }\r | |
231 | \r | |
232 | static uint8_t SIEselectEndpoint(uint8_t bEP) {\r | |
233 | uint8_t endpoint = EP2IDX(bEP);\r | |
234 | \r | |
235 | // SIE select endpoint command\r | |
236 | SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));\r | |
237 | return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));\r | |
238 | }\r | |
239 | \r | |
240 | static uint8_t SIEclearBuffer(void) {\r | |
241 | // SIE clear buffer command\r | |
242 | SIECommand(SIE_CMD_CLEAR_BUFFER);\r | |
243 | return SIEReadData(SIE_CMD_CLEAR_BUFFER);\r | |
244 | }\r | |
245 | \r | |
246 | static void SIEvalidateBuffer(void) {\r | |
247 | // SIE validate buffer command\r | |
248 | SIECommand(SIE_CMD_VALIDATE_BUFFER);\r | |
249 | }\r | |
250 | \r | |
251 | static void SIEsetEndpointStatus(uint8_t bEP, uint8_t status) {\r | |
252 | uint8_t endpoint = EP2IDX(bEP);\r | |
253 | \r | |
254 | // SIE set endpoint status command\r | |
255 | SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));\r | |
256 | SIEWriteData(status);\r | |
257 | }\r | |
258 | \r | |
259 | static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));\r | |
260 | static uint16_t SIEgetFrameNumber(void) {\r | |
261 | // Read current frame number\r | |
262 | uint16_t lowByte;\r | |
263 | uint16_t highByte;\r | |
264 | \r | |
265 | SIECommand(SIE_CMD_READ_FRAME_NUMBER);\r | |
266 | lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);\r | |
267 | highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);\r | |
268 | \r | |
269 | return (highByte << 8) | lowByte;\r | |
270 | }\r | |
271 | \r | |
272 | static void SIEconfigureDevice(void) {\r | |
273 | // SIE Configure device command\r | |
274 | SIECommand(SIE_CMD_CONFIGURE_DEVICE);\r | |
275 | SIEWriteData(SIE_CONF_DEVICE);\r | |
276 | }\r | |
277 | \r | |
278 | static void SIEunconfigureDevice(void) {\r | |
279 | // SIE Configure device command\r | |
280 | SIECommand(SIE_CMD_CONFIGURE_DEVICE);\r | |
281 | SIEWriteData(0);\r | |
282 | }\r | |
283 | \r | |
284 | static void SIEconnect(void) {\r | |
285 | // Connect USB device\r | |
286 | uint8_t status;\r | |
287 | \r | |
288 | status = SIEgetDeviceStatus();\r | |
289 | // iprintf("USBHAL::SIEconnect status is %02X\n", status);\r | |
290 | SIEsetDeviceStatus(status | SIE_DS_CON);\r | |
291 | // iprintf("USBHAL::SIEconnect ok\n");\r | |
292 | }\r | |
293 | \r | |
294 | \r | |
295 | static void SIEdisconnect(void) {\r | |
296 | // Disconnect USB device\r | |
297 | uint8_t status;\r | |
298 | \r | |
299 | status = SIEgetDeviceStatus();\r | |
300 | SIEsetDeviceStatus(status & ~SIE_DS_CON);\r | |
301 | }\r | |
302 | \r | |
303 | \r | |
304 | static uint8_t selectEndpointClearInterrupt(uint8_t bEP) {\r | |
305 | uint8_t endpoint = EP2IDX(bEP);\r | |
306 | \r | |
307 | // Implemented using using EP_INT_CL\r | |
308 | LPC_USB->USBEpIntClr = EP(endpoint);\r | |
309 | setled(4, 1); while (!(LPC_USB->USBDevIntSt & CDFULL)); setled(4, 0);\r | |
310 | return (uint8_t)LPC_USB->USBCmdData;\r | |
311 | }\r | |
312 | \r | |
313 | static void enableEndpointEvent(uint8_t bEP) {\r | |
314 | uint8_t endpoint = EP2IDX(bEP);\r | |
315 | \r | |
316 | // Enable an endpoint interrupt\r | |
317 | LPC_USB->USBEpIntEn |= EP(endpoint);\r | |
318 | }\r | |
319 | \r | |
320 | static void disableEndpointEvent(uint8_t bEP) __attribute__ ((unused));\r | |
321 | static void disableEndpointEvent(uint8_t bEP) {\r | |
322 | uint8_t endpoint = EP2IDX(bEP);\r | |
323 | \r | |
324 | // Disable an endpoint interrupt\r | |
325 | LPC_USB->USBEpIntEn &= ~EP(endpoint);\r | |
326 | }\r | |
327 | \r | |
328 | static volatile uint32_t __attribute__((used)) dummyRead;\r | |
329 | \r | |
330 | \r | |
331 | uint32_t USBHAL::endpointReadcore(uint8_t bEP, uint8_t *buffer)\r | |
332 | {\r | |
333 | // Read from an OUT endpoint\r | |
334 | uint32_t size;\r | |
335 | uint32_t i;\r | |
336 | uint32_t data = 0;\r | |
337 | uint8_t offset;\r | |
338 | uint8_t endpoint = EP2IDX(bEP);\r | |
339 | \r | |
340 | uint8_t irq = NVIC_GetActive(USB_IRQn);\r | |
341 | NVIC_DisableIRQ(USB_IRQn);\r | |
342 | \r | |
343 | // iprintf("epReadCore 0x%02X = %d, 0x%02X\n", bEP, endpoint, LOG_ENDPOINT(endpoint));\r | |
344 | \r | |
345 | LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;\r | |
346 | \r | |
347 | // iprintf("0x%02lX\n", LPC_USB->USBCtrl);\r | |
348 | \r | |
349 | setled(4, 1); while (!(LPC_USB->USBRxPLen & PKT_RDY))\r | |
350 | {\r | |
351 | // iprintf("ep not ready, Waiting for data...\n");\r | |
352 | }\r | |
353 | setled(4, 0);\r | |
354 | \r | |
355 | // iprintf("0x%02lX 0x%02lX\n", LPC_USB->USBCtrl, LPC_USB->USBRxPLen);\r | |
356 | \r | |
357 | size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;\r | |
358 | \r | |
359 | if ((IS_ISOCHRONOUS(bEP) == 0) && (size > 64))\r | |
360 | {\r | |
361 | // iprintf("BOGUS SIZE FOR EP 0x%02X! Got %ld, max is 64!\n", bEP, size);\r | |
362 | size = 64;\r | |
363 | }\r | |
364 | \r | |
365 | // iprintf("Reading %ld bytes\n", size);\r | |
366 | \r | |
367 | offset = 0;\r | |
368 | \r | |
369 | if (size > 0)\r | |
370 | {\r | |
371 | for (i = 0; i < size; i++)\r | |
372 | {\r | |
373 | if (offset==0)\r | |
374 | {\r | |
375 | // Fetch up to four bytes of data as a word\r | |
376 | data = LPC_USB->USBRxData;\r | |
377 | }\r | |
378 | \r | |
379 | // extract a byte\r | |
380 | *buffer = (data>>offset) & 0xff;\r | |
381 | buffer++;\r | |
382 | \r | |
383 | // move on to the next byte\r | |
384 | offset = (offset + 8) & 24;\r | |
385 | }\r | |
386 | } else\r | |
387 | {\r | |
388 | dummyRead = LPC_USB->USBRxData;\r | |
389 | }\r | |
390 | \r | |
391 | setled(4, 1); while ((LPC_USB->USBDevIntSt & RxENDPKT) == 0)\r | |
392 | dummyRead = LPC_USB->USBRxData;\r | |
393 | setled(4, 0);\r | |
394 | \r | |
395 | // iprintf("Read %ld\n", size);\r | |
396 | \r | |
397 | if (can_transfer[endpoint] != 0)\r | |
398 | can_transfer[endpoint]--;\r | |
399 | \r | |
400 | LPC_USB->USBCtrl = 0;\r | |
401 | \r | |
402 | if (IS_ISOCHRONOUS(bEP) == 0)\r | |
403 | {\r | |
404 | // iprintf("Buffer Clear 0x%02X\n", bEP);\r | |
405 | SIEselectEndpoint(bEP);\r | |
406 | if (SIEclearBuffer())\r | |
407 | {\r | |
408 | // iprintf("EP%dIN OVERRUN\n", bEP & 0x0F);\r | |
409 | }\r | |
410 | }\r | |
411 | \r | |
412 | if (irq)\r | |
413 | NVIC_EnableIRQ(USB_IRQn);\r | |
414 | \r | |
415 | return size;\r | |
416 | }\r | |
417 | \r | |
418 | static void endpointWritecore(uint8_t bEP, uint8_t *buffer, uint32_t size)\r | |
419 | {\r | |
420 | // Write to an IN endpoint\r | |
421 | // uint32_t temp, data;\r | |
422 | // uint8_t offset;\r | |
423 | uint8_t endpoint = EP2IDX(bEP);\r | |
424 | \r | |
425 | LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;\r | |
426 | \r | |
427 | LPC_USB->USBTxPLen = size;\r | |
428 | // offset = 0;\r | |
429 | // data = 0;\r | |
430 | // iprintf("EP%d%s(%d) W:", (endpoint >> 1), ((endpoint & 1)?"IN":"OUT"), endpoint);\r | |
431 | while (LPC_USB->USBCtrl & WR_EN)\r | |
432 | {\r | |
433 | // iprintf("0x%02X 0x%02X 0x%02X 0x%02X ", buffer[0], buffer[1], buffer[2], buffer[3]);\r | |
434 | LPC_USB->USBTxData = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];\r | |
435 | buffer += 4;\r | |
436 | }\r | |
437 | \r | |
438 | // iprintf("!_(%ld)>", size);\r | |
439 | \r | |
440 | // Clear WR_EN to cover zero length packet case\r | |
441 | LPC_USB->USBCtrl = 0;\r | |
442 | \r | |
443 | SIEselectEndpoint(bEP);\r | |
444 | SIEvalidateBuffer();\r | |
445 | \r | |
446 | uint8_t status __attribute__ ((unused)) = SIEselectEndpoint(bEP);\r | |
447 | // iprintf("EP 0x%02X ST 0x%02X\n", bEP, status);\r | |
448 | }\r | |
449 | \r | |
450 | \r | |
451 | USBHAL::USBHAL(void) {\r | |
452 | instance = this;\r | |
453 | }\r | |
454 | \r | |
455 | void USBHAL::init() {\r | |
456 | // Disable IRQ\r | |
457 | NVIC_DisableIRQ(USB_IRQn);\r | |
458 | \r | |
459 | // Enable power to USB device controller\r | |
460 | LPC_SC->PCONP |= PCUSB;\r | |
461 | \r | |
462 | // Enable USB clocks\r | |
463 | LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;\r | |
464 | setled(4, 1); while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); setled(4, 0);\r | |
465 | \r | |
466 | // Configure pins P0.29 and P0.30 to be USB D+ and USB D-\r | |
467 | LPC_PINCON->PINSEL1 &= 0xc3ffffff;\r | |
468 | LPC_PINCON->PINSEL1 |= 0x14000000;\r | |
469 | \r | |
470 | // Disconnect USB device\r | |
471 | SIEdisconnect();\r | |
472 | \r | |
473 | // Configure pin P2.9 to be Connect\r | |
474 | LPC_PINCON->PINSEL4 &= 0xfffcffff;\r | |
475 | LPC_PINCON->PINSEL4 |= 0x00040000;\r | |
476 | \r | |
477 | // Connect must be low for at least 2.5uS\r | |
478 | // wait(0.3);\r | |
479 | \r | |
480 | // Set the maximum packet size for the control endpoints\r | |
481 | realiseEndpoint(IDX2EP(EP0IN), MAX_PACKET_SIZE_EP0, 0);\r | |
482 | realiseEndpoint(IDX2EP(EP0OUT), MAX_PACKET_SIZE_EP0, 0);\r | |
483 | \r | |
484 | // Attach IRQ\r | |
485 | // instance = this;\r | |
486 | // NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);\r | |
487 | // NVIC_EnableIRQ(USB_IRQn);\r | |
488 | \r | |
489 | USBEpIntEn = 0x3;\r | |
490 | \r | |
491 | // Enable interrupts for device events and EP0\r | |
492 | // LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;\r | |
493 | LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;\r | |
494 | // enableEndpointEvent(EP0IN);\r | |
495 | // enableEndpointEvent(EP0OUT);\r | |
496 | }\r | |
497 | \r | |
498 | USBHAL::~USBHAL(void) {\r | |
499 | // Ensure device disconnected\r | |
500 | SIEdisconnect();\r | |
501 | \r | |
502 | // Disable USB interrupts\r | |
503 | NVIC_DisableIRQ(USB_IRQn);\r | |
504 | }\r | |
505 | \r | |
506 | uint32_t USBHAL::getSerialNumber(int length, uint32_t *buf) {\r | |
507 | #define IAP_LOCATION 0x1FFF1FF1\r | |
508 | uint32_t command[1];\r | |
509 | uint32_t result[5];\r | |
510 | typedef void (*IAP)(uint32_t*, uint32_t*);\r | |
511 | IAP iap = (IAP) IAP_LOCATION;\r | |
512 | \r | |
b3e299cb MM |
513 | __disable_irq();\r |
514 | \r | |
47b0bbd2 MM |
515 | command[0] = 58;\r |
516 | // iprintf("Getting Serial...\n");\r | |
517 | iap(command, result);\r | |
518 | // iprintf("HW Serial Number: %08lX %08lX %08lX %08lX\n", result[1], result[2], result[3], result[4]);\r | |
519 | int i;\r | |
520 | for (i = 0; i < 4; i++) {\r | |
521 | if (i < length) {\r | |
522 | buf[i] = result[i + 1];\r | |
523 | }\r | |
524 | }\r | |
b3e299cb MM |
525 | \r |
526 | __enable_irq();\r | |
527 | \r | |
47b0bbd2 MM |
528 | return i;\r |
529 | }\r | |
530 | \r | |
531 | void USBHAL::connect(void) {\r | |
532 | // Connect USB device\r | |
533 | // iprintf("USBHAL::connect\n");\r | |
534 | NVIC_EnableIRQ(USB_IRQn);\r | |
535 | SIEconnect();\r | |
536 | // iprintf("USBHAL::connect OK\n");\r | |
537 | }\r | |
538 | \r | |
539 | void USBHAL::disconnect(void) {\r | |
540 | // Disconnect USB device\r | |
541 | SIEdisconnect();\r | |
542 | }\r | |
543 | \r | |
544 | void USBHAL::configureDevice(void) {\r | |
545 | SIEconfigureDevice();\r | |
546 | }\r | |
547 | \r | |
548 | void USBHAL::unconfigureDevice(void) {\r | |
549 | SIEunconfigureDevice();\r | |
550 | }\r | |
551 | \r | |
552 | void USBHAL::setAddress(uint8_t address) {\r | |
553 | SIEsetAddress(address);\r | |
554 | // SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO | SIE_MODE_INAK_BI | SIE_MODE_INAK_BO);\r | |
555 | SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO);\r | |
556 | }\r | |
557 | \r | |
558 | void USBHAL::EP0setup(uint8_t *buffer) {\r | |
559 | endpointReadcore(IDX2EP(EP0OUT), buffer);\r | |
560 | }\r | |
561 | \r | |
562 | void USBHAL::EP0read(void) {\r | |
563 | // Not required\r | |
564 | }\r | |
565 | \r | |
566 | uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {\r | |
567 | return endpointReadcore(IDX2EP(EP0OUT), buffer);\r | |
568 | }\r | |
569 | \r | |
570 | void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {\r | |
571 | endpointWritecore(IDX2EP(EP0IN), buffer, size);\r | |
572 | }\r | |
573 | \r | |
574 | void USBHAL::EP0getWriteResult(void) {\r | |
575 | // Not required\r | |
576 | }\r | |
577 | \r | |
578 | void USBHAL::EP0stall(void) {\r | |
579 | // This will stall both control endpoints\r | |
580 | stallEndpoint(IDX2EP(EP0OUT));\r | |
581 | }\r | |
582 | \r | |
583 | EP_STATUS USBHAL::endpointRead(uint8_t bEP, uint32_t maximumSize) {\r | |
584 | return EP_PENDING;\r | |
585 | }\r | |
586 | \r | |
587 | EP_STATUS USBHAL::endpointReadResult(uint8_t bEP, uint8_t * buffer, uint32_t *bytesRead)\r | |
588 | {\r | |
589 | uint8_t endpoint = EP2IDX(bEP);\r | |
590 | \r | |
591 | // iprintf("epReadResult 0x%02X = %d\n", bEP, endpoint);\r | |
592 | \r | |
593 | //for isochronous endpoint, we don't wait an interrupt\r | |
594 | if (IS_ISOCHRONOUS(bEP) == 0) {\r | |
595 | // iprintf("not Isochronous\n");\r | |
596 | // if (!(epComplete & EP(endpoint)))\r | |
597 | if (can_transfer[endpoint] == 0)\r | |
598 | {\r | |
599 | // iprintf("Pending\n");\r | |
600 | return EP_PENDING;\r | |
601 | }\r | |
602 | }\r | |
603 | \r | |
604 | // iprintf("reading...\n");\r | |
605 | \r | |
606 | __disable_irq();\r | |
607 | __ISB();\r | |
608 | \r | |
609 | if (can_transfer[endpoint])\r | |
610 | {\r | |
611 | can_transfer[endpoint]--;\r | |
612 | __enable_irq();\r | |
613 | *bytesRead = endpointReadcore(bEP, buffer);\r | |
614 | }\r | |
615 | else {\r | |
616 | __enable_irq();\r | |
617 | *bytesRead = 0;\r | |
618 | }\r | |
619 | // epComplete &= ~EP(endpoint);\r | |
620 | \r | |
621 | // iprintf("OK\n");\r | |
622 | \r | |
623 | return EP_COMPLETED;\r | |
624 | }\r | |
625 | \r | |
626 | EP_STATUS USBHAL::endpointWrite(uint8_t bEP, uint8_t *data, uint32_t size)\r | |
627 | {\r | |
628 | uint8_t endpoint = EP2IDX(bEP);\r | |
629 | \r | |
630 | if (getEndpointStallState(bEP)) {\r | |
631 | return EP_STALLED;\r | |
632 | }\r | |
633 | \r | |
634 | do {\r | |
635 | __disable_irq();\r | |
636 | __ISB();\r | |
637 | \r | |
638 | if (can_transfer[endpoint])\r | |
639 | {\r | |
640 | can_transfer[endpoint]--;\r | |
641 | __enable_irq();\r | |
642 | endpointWritecore(bEP, data, size);\r | |
643 | return EP_PENDING;\r | |
644 | }\r | |
645 | __enable_irq();\r | |
646 | endpointSetInterrupt(bEP, true);\r | |
647 | } while (1);\r | |
648 | }\r | |
649 | \r | |
650 | EP_STATUS USBHAL::endpointWriteResult(uint8_t bEP)\r | |
651 | {\r | |
652 | uint8_t endpoint = EP2IDX(bEP);\r | |
653 | \r | |
654 | // if (epComplete & EP(endpoint)) {\r | |
655 | if (can_transfer[endpoint] < 2) {\r | |
656 | // epComplete &= ~EP(endpoint);\r | |
657 | return EP_COMPLETED;\r | |
658 | }\r | |
659 | \r | |
660 | return EP_PENDING;\r | |
661 | }\r | |
662 | \r | |
663 | uint8_t USBHAL::endpointStatus(uint8_t bEP)\r | |
664 | {\r | |
665 | uint8_t bEPStat = SIEselectEndpoint(EP2IDX(bEP));\r | |
666 | \r | |
667 | uint8_t bStat __attribute__ ((unused))\r | |
668 | = ((bEPStat & EPSTAT_FE ) ? EP_STATUS_DATA : 0) |\r | |
669 | ((bEPStat & EPSTAT_ST ) ? EP_STATUS_STALLED : 0) |\r | |
670 | ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r | |
671 | ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r | |
672 | ((bEPStat & EPSTAT_PO ) ? EP_STATUS_ERROR : 0);\r | |
673 | \r | |
674 | return bEPStat;\r | |
675 | }\r | |
676 | \r | |
677 | bool USBHAL::realiseEndpoint(uint8_t bEP, uint32_t maxPacket, uint32_t flags)\r | |
678 | {\r | |
679 | uint8_t endpoint = EP2IDX(bEP);\r | |
680 | \r | |
681 | // Realise an endpoint\r | |
682 | LPC_USB->USBDevIntClr = EP_RLZED;\r | |
683 | LPC_USB->USBReEp |= EP(endpoint);\r | |
684 | LPC_USB->USBEpInd = endpoint;\r | |
685 | LPC_USB->USBMaxPSize = maxPacket;\r | |
686 | \r | |
687 | setled(4, 1); while (!(LPC_USB->USBDevIntSt & EP_RLZED)); setled(4, 0);\r | |
688 | LPC_USB->USBDevIntClr = EP_RLZED;\r | |
689 | \r | |
690 | // Clear stall state\r | |
691 | // endpointStallState &= ~EP(endpoint);\r | |
692 | unstallEndpoint(bEP);\r | |
693 | \r | |
694 | enableEndpointEvent(bEP);\r | |
695 | \r | |
696 | /*\r | |
697 | * if this is an OUT endpoint, enable interrupts so we can receive any\r | |
698 | * data the host sends to us.\r | |
699 | *\r | |
700 | * if this is an IN endpoint, don't enable interrupts just yet, but have\r | |
701 | * an event waiting so we can immediately interrupt later on when the\r | |
702 | * user app calls endpointSetInterrupt(bEP, true)\r | |
703 | */\r | |
704 | \r | |
705 | if (IN_BEP(bEP))\r | |
706 | {\r | |
707 | // epComplete |= EP(endpoint);\r | |
708 | can_transfer[endpoint] = 2;\r | |
709 | }\r | |
710 | else\r | |
711 | {\r | |
712 | can_transfer[endpoint] = 0;\r | |
713 | endpointSetInterrupt(bEP, true);\r | |
714 | }\r | |
715 | \r | |
716 | // iprintf("EP 0x%02X realised @%ld!\n", bEP, maxPacket);\r | |
717 | return true;\r | |
718 | }\r | |
719 | \r | |
720 | void USBHAL::stallEndpoint(uint8_t bEP)\r | |
721 | {\r | |
722 | uint8_t endpoint = EP2IDX(bEP);\r | |
723 | \r | |
724 | // Stall an endpoint\r | |
725 | if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) {\r | |
726 | // Conditionally stall both control endpoints\r | |
727 | SIEsetEndpointStatus(IDX2EP(EP0OUT), SIE_SES_CND_ST);\r | |
728 | } else {\r | |
729 | SIEsetEndpointStatus(bEP, SIE_SES_ST);\r | |
730 | \r | |
731 | // Update stall state\r | |
732 | endpointStallState |= EP(endpoint);\r | |
733 | }\r | |
734 | }\r | |
735 | \r | |
736 | void USBHAL::unstallEndpoint(uint8_t bEP)\r | |
737 | {\r | |
738 | uint8_t endpoint = EP2IDX(bEP);\r | |
739 | \r | |
740 | // Unstall an endpoint. The endpoint will also be reinitialised\r | |
741 | SIEsetEndpointStatus(bEP, 0);\r | |
742 | \r | |
743 | // Update stall state\r | |
744 | endpointStallState &= ~EP(endpoint);\r | |
745 | }\r | |
746 | \r | |
747 | bool USBHAL::getEndpointStallState(uint8_t bEP)\r | |
748 | {\r | |
749 | // Returns true if endpoint stalled\r | |
750 | return endpointStallState & EP(EP2IDX(bEP));\r | |
751 | }\r | |
752 | \r | |
753 | void USBHAL::remoteWakeup(void)\r | |
754 | {\r | |
755 | // Remote wakeup\r | |
756 | uint8_t status;\r | |
757 | \r | |
758 | // Enable USB clocks\r | |
759 | LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;\r | |
760 | setled(4, 1); while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); setled(4, 0);\r | |
761 | \r | |
762 | status = SIEgetDeviceStatus();\r | |
763 | SIEsetDeviceStatus(status & ~SIE_DS_SUS);\r | |
764 | }\r | |
765 | \r | |
766 | uint16_t USBHAL::lastFrame(void)\r | |
767 | {\r | |
768 | return SIEgetFrameNumber();\r | |
769 | }\r | |
770 | \r | |
771 | extern "C" {\r | |
772 | __attribute__ ((interrupt)) void USB_IRQHandler() {\r | |
773 | // iprintf("!0x%08lX/0x%08lX:", LPC_USB->USBDevIntSt, LPC_USB->USBDevIntEn);\r | |
774 | ENTER_ISR();\r | |
775 | USBHAL::_usbisr();\r | |
776 | LEAVE_ISR();\r | |
777 | }\r | |
778 | }\r | |
779 | \r | |
780 | void USBHAL::_usbisr(void) {\r | |
781 | instance->usbisr();\r | |
782 | }\r | |
783 | \r | |
784 | bool USBHAL::endpointSetInterrupt(uint8_t bEP, bool enabled)\r | |
785 | {\r | |
786 | uint8_t endpoint = EP2IDX(bEP);\r | |
787 | \r | |
788 | bool r = USBEpIntEn | EP(endpoint);\r | |
789 | \r | |
790 | if (enabled)\r | |
791 | {\r | |
792 | __disable_irq();\r | |
793 | USBEpIntEn |= EP(endpoint);\r | |
794 | if (can_transfer[endpoint])\r | |
795 | endpointTriggerInterrupt(bEP);\r | |
796 | // LPC_USB->USBEpIntSet = EP(endpoint);\r | |
797 | __enable_irq();\r | |
798 | }\r | |
799 | else\r | |
800 | {\r | |
801 | USBEpIntEn &= ~EP(endpoint);\r | |
802 | }\r | |
803 | \r | |
804 | return r;\r | |
805 | }\r | |
806 | \r | |
807 | bool USBHAL::endpointGetInterrupt(uint8_t bEP)\r | |
808 | {\r | |
809 | uint8_t endpoint = EP2IDX(bEP);\r | |
810 | \r | |
811 | return USBEpIntEn | EP(endpoint);\r | |
812 | }\r | |
813 | \r | |
814 | void USBHAL::endpointTriggerInterrupt(uint8_t bEP)\r | |
815 | {\r | |
816 | uint8_t endpoint = EP2IDX(bEP);\r | |
817 | \r | |
818 | LPC_USB->USBEpIntSet = EP(endpoint);\r | |
819 | }\r | |
820 | \r | |
821 | void USBHAL::usbisr(void)\r | |
822 | {\r | |
823 | uint8_t devStat;\r | |
824 | \r | |
825 | if (LPC_USB->USBDevIntSt & FRAME)\r | |
826 | {\r | |
827 | // iprintf("F");\r | |
828 | // Start of frame event\r | |
829 | // SOF(SIEgetFrameNumber());\r | |
830 | USBEvent_Frame(SIEgetFrameNumber());\r | |
831 | // Clear interrupt status flag\r | |
832 | LPC_USB->USBDevIntClr = FRAME;\r | |
833 | \r | |
834 | // static uint8_t lst;\r | |
835 | // uint8_t st = SIEselectEndpoint(0x80);\r | |
836 | // if (st != lst)\r | |
837 | // {\r | |
838 | // iprintf("EP1S:%02X\n", st);\r | |
839 | // lst = st;\r | |
840 | // }\r | |
841 | }\r | |
842 | \r | |
843 | if (LPC_USB->USBDevIntSt & DEV_STAT)\r | |
844 | {\r | |
845 | iprintf("D");\r | |
846 | // Device Status interrupt\r | |
847 | // Must clear the interrupt status flag before reading the device status from the SIE\r | |
848 | LPC_USB->USBDevIntClr = DEV_STAT;\r | |
849 | \r | |
850 | // Read device status from SIE\r | |
851 | devStat = SIEgetDeviceStatus();\r | |
852 | //printf("devStat: %d\r\n", devStat);\r | |
853 | \r | |
854 | if (devStat & SIE_DS_SUS_CH)\r | |
855 | {\r | |
856 | // Suspend status changed\r | |
857 | // if((devStat & SIE_DS_SUS) != 0) {\r | |
858 | // USBEvent_suspendStateChanged(false);\r | |
859 | // }\r | |
860 | USBEvent_suspendStateChanged(devStat & SIE_DS_SUS);\r | |
861 | }\r | |
862 | \r | |
863 | if (devStat & SIE_DS_RST)\r | |
864 | {\r | |
865 | // Bus reset\r | |
866 | // if((devStat & SIE_DS_SUS) == 0) {\r | |
867 | // USBEvent_suspendStateChanged(true);\r | |
868 | // }\r | |
869 | USBEvent_busReset();\r | |
870 | \r | |
871 | realiseEndpoint(IDX2EP(EP0IN), MAX_PACKET_SIZE_EP0, 0);\r | |
872 | realiseEndpoint(IDX2EP(EP0OUT), MAX_PACKET_SIZE_EP0, 0);\r | |
873 | \r | |
874 | SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO | SIE_MODE_INAK_BI | SIE_MODE_INAK_BO);\r | |
875 | }\r | |
876 | \r | |
877 | if (devStat & SIE_DS_CON_CH)\r | |
878 | {\r | |
879 | USBEvent_connectStateChanged(devStat & SIE_DS_CON);\r | |
880 | }\r | |
881 | }\r | |
882 | \r | |
883 | if (LPC_USB->USBDevIntSt & EP_SLOW)\r | |
884 | {\r | |
885 | // (Slow) Endpoint Interrupt\r | |
886 | \r | |
887 | // Process each endpoint interrupt\r | |
888 | if (LPC_USB->USBEpIntSt & EP(EP0OUT))\r | |
889 | {\r | |
47ebf70b MM |
890 | uint8_t bEPStat = selectEndpointClearInterrupt(IDX2EP(EP0OUT));\r |
891 | if (bEPStat & SIE_SE_STP)\r | |
47b0bbd2 MM |
892 | {\r |
893 | // this is a setup packet\r | |
894 | EP0setupCallback();\r | |
895 | }\r | |
47ebf70b | 896 | else if (bEPStat & EPSTAT_FE) // OUT endpoint, FE = 1 - data in buffer\r |
47b0bbd2 MM |
897 | {\r |
898 | EP0out();\r | |
899 | }\r | |
900 | }\r | |
901 | if (LPC_USB->USBEpIntSt & EP(EP0IN))\r | |
902 | {\r | |
47ebf70b MM |
903 | uint8_t bEPStat = selectEndpointClearInterrupt(IDX2EP(EP0IN));\r |
904 | if ((bEPStat & EPSTAT_FE) == 0) // IN endpoint, FE = 0 - empty space in buffer\r | |
905 | EP0in();\r | |
47b0bbd2 MM |
906 | }\r |
907 | \r | |
908 | if (USBEpIntEn & ~(3UL))\r | |
909 | {\r | |
910 | int i;\r | |
911 | uint32_t bitmask;\r | |
912 | \r | |
913 | for (i = 2, bitmask = 4; i < 32; i++, bitmask <<= 1)\r | |
914 | {\r | |
9f0f2c8f | 915 | uint8_t bEPStat = 255;\r |
47b0bbd2 MM |
916 | uint8_t ep = IDX2EP(i);\r |
917 | if (LPC_USB->USBEpIntSt & bitmask)\r | |
918 | {\r | |
919 | bEPStat = selectEndpointClearInterrupt(ep);\r | |
920 | if (can_transfer[i] < 2)\r | |
921 | can_transfer[i]++;\r | |
922 | }\r | |
923 | \r | |
924 | if ((USBEpIntEn & bitmask) && (can_transfer[i]))\r | |
925 | {\r | |
9f0f2c8f | 926 | if (bEPStat == 255)\r |
47b0bbd2 MM |
927 | bEPStat = SIEselectEndpoint(ep);\r |
928 | \r | |
929 | iprintf("!02X", ep);\r | |
930 | \r | |
931 | uint8_t bStat = ((bEPStat & EPSTAT_FE ) ? EP_STATUS_DATA : 0) |\r | |
932 | ((bEPStat & EPSTAT_ST ) ? EP_STATUS_STALLED : 0) |\r | |
933 | ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r | |
934 | ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r | |
935 | ((bEPStat & EPSTAT_PO ) ? EP_STATUS_ERROR : 0);\r | |
936 | \r | |
9f0f2c8f | 937 | bool r = true;\r |
47b0bbd2 MM |
938 | \r |
939 | if (IN_EP(i))\r | |
940 | {\r | |
941 | // iprintf("IN[%02X]:", IDX2EP(i));\r | |
9f0f2c8f MM |
942 | if ((bEPStat & EPSTAT_FE) == 0) // IN endpoint, FE = 0 - empty space in buffer\r |
943 | r = USBEvent_EPIn(ep, bStat);\r | |
47b0bbd2 MM |
944 | }\r |
945 | else\r | |
946 | {\r | |
947 | // iprintf("OUT[%02X]:", IDX2EP(i));\r | |
9f0f2c8f MM |
948 | if (bEPStat & EPSTAT_FE) // OUT endpoint, FE = 1 - data in buffer\r |
949 | r = USBEvent_EPOut(ep, bStat);\r | |
47b0bbd2 MM |
950 | }\r |
951 | \r | |
952 | if (!r)\r | |
953 | {\r | |
954 | USBEpIntEn &= ~bitmask;\r | |
955 | }\r | |
956 | // iprintf("\n");\r | |
957 | }\r | |
958 | }\r | |
959 | iprintf("\n");\r | |
960 | }\r | |
961 | \r | |
962 | LPC_USB->USBDevIntClr = EP_SLOW;\r | |
963 | }\r | |
964 | }\r | |
965 | \r | |
966 | #endif\r |