1 /* Copyright (c) 2010-2011 mbed.org, MIT License
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without
5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 #if defined(TARGET_KL25Z) | defined(TARGET_KL43Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D50M) | defined(TARGET_K64F) | defined(TARGET_K22F) | defined(TARGET_TEENSY3_1)
23 USBHAL
* USBHAL::instance
;
25 static volatile int epComplete
= 0;
27 // Convert physical endpoint number to register bit
28 #define EP(endpoint) (1<<(endpoint))
30 // Convert physical to logical
31 #define PHY_TO_LOG(endpoint) ((endpoint)>>1)
33 // Get endpoint direction
34 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
35 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
37 #define BD_OWN_MASK (1<<7)
38 #define BD_DATA01_MASK (1<<6)
39 #define BD_KEEP_MASK (1<<5)
40 #define BD_NINC_MASK (1<<4)
41 #define BD_DTS_MASK (1<<3)
42 #define BD_STALL_MASK (1<<2)
48 // this macro waits a physical endpoint number
49 #define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 * odd)))
51 #define SETUP_TOKEN 0x0D
53 #define OUT_TOKEN 0x01
54 #define TOK_PID(idx) ((bdt[idx].info >> 2) & 0x0F)
56 // for each endpt: 8 bytes
58 uint8_t info
; // BD[0:7]
59 uint8_t dummy
; // RSVD: BD[8:15]
60 uint16_t byte_count
; // BD[16:32]
61 uint32_t address
; // Addr
66 // * 16 bidirectionnal endpt -> 32 physical endpt
67 // * as there are ODD and EVEN buffer -> 32*2 bdt
68 __attribute__((__aligned__(512))) BDT bdt
[NUMBER_OF_PHYSICAL_ENDPOINTS
* 2];
69 uint8_t * endpoint_buffer
[(NUMBER_OF_PHYSICAL_ENDPOINTS
- 2) * 2];
70 uint8_t * endpoint_buffer_iso
[2*2];
72 static uint8_t set_addr
= 0;
73 static uint8_t addr
= 0;
75 static uint32_t Data1
= 0x55555555;
77 static uint32_t frameNumber() {
78 return((USB0
->FRMNUML
| (USB0
->FRMNUMH
<< 8)) & 0x07FF);
81 uint32_t USBHAL::endpointReadcore(uint8_t endpoint
, uint8_t *buffer
) {
85 USBHAL::USBHAL(void) {
87 NVIC_DisableIRQ(USB0_IRQn
);
89 #if defined(TARGET_K64F)
92 // fill in callback array
93 epCallback
[0] = &USBHAL::EP1_OUT_callback
;
94 epCallback
[1] = &USBHAL::EP1_IN_callback
;
95 epCallback
[2] = &USBHAL::EP2_OUT_callback
;
96 epCallback
[3] = &USBHAL::EP2_IN_callback
;
97 epCallback
[4] = &USBHAL::EP3_OUT_callback
;
98 epCallback
[5] = &USBHAL::EP3_IN_callback
;
99 epCallback
[6] = &USBHAL::EP4_OUT_callback
;
100 epCallback
[7] = &USBHAL::EP4_IN_callback
;
101 epCallback
[8] = &USBHAL::EP5_OUT_callback
;
102 epCallback
[9] = &USBHAL::EP5_IN_callback
;
103 epCallback
[10] = &USBHAL::EP6_OUT_callback
;
104 epCallback
[11] = &USBHAL::EP6_IN_callback
;
105 epCallback
[12] = &USBHAL::EP7_OUT_callback
;
106 epCallback
[13] = &USBHAL::EP7_IN_callback
;
107 epCallback
[14] = &USBHAL::EP8_OUT_callback
;
108 epCallback
[15] = &USBHAL::EP8_IN_callback
;
109 epCallback
[16] = &USBHAL::EP9_OUT_callback
;
110 epCallback
[17] = &USBHAL::EP9_IN_callback
;
111 epCallback
[18] = &USBHAL::EP10_OUT_callback
;
112 epCallback
[19] = &USBHAL::EP10_IN_callback
;
113 epCallback
[20] = &USBHAL::EP11_OUT_callback
;
114 epCallback
[21] = &USBHAL::EP11_IN_callback
;
115 epCallback
[22] = &USBHAL::EP12_OUT_callback
;
116 epCallback
[23] = &USBHAL::EP12_IN_callback
;
117 epCallback
[24] = &USBHAL::EP13_OUT_callback
;
118 epCallback
[25] = &USBHAL::EP13_IN_callback
;
119 epCallback
[26] = &USBHAL::EP14_OUT_callback
;
120 epCallback
[27] = &USBHAL::EP14_IN_callback
;
121 epCallback
[28] = &USBHAL::EP15_OUT_callback
;
122 epCallback
[29] = &USBHAL::EP15_IN_callback
;
124 #if defined(TARGET_KL43Z)
125 // enable USBFS clock
126 SIM
->SCGC4
|= SIM_SCGC4_USBFS_MASK
;
128 // enable the IRC48M clock
129 USB0
->CLK_RECOVER_IRC_EN
|= USB_CLK_RECOVER_IRC_EN_IRC_EN_MASK
;
131 // enable the USB clock recovery tuning
132 USB0
->CLK_RECOVER_CTRL
|= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK
;
134 // choose usb src clock
135 SIM
->SOPT2
|= SIM_SOPT2_USBSRC_MASK
;
137 // choose usb src as PLL
138 SIM
->SOPT2
&= ~SIM_SOPT2_PLLFLLSEL_MASK
;
139 SIM
->SOPT2
|= (SIM_SOPT2_USBSRC_MASK
| (1 << SIM_SOPT2_PLLFLLSEL_SHIFT
));
142 SIM
->SCGC4
|= SIM_SCGC4_USBOTG_MASK
;
147 NVIC_SetVector(USB0_IRQn
, (uint32_t)&_usbisr
);
148 NVIC_EnableIRQ(USB0_IRQn
);
150 // USB Module Configuration
152 USB0
->USBTRC0
|= USB_USBTRC0_USBRESET_MASK
;
153 while(USB0
->USBTRC0
& USB_USBTRC0_USBRESET_MASK
);
155 // Set BDT Base Register
156 USB0
->BDTPAGE1
= (uint8_t)((uint32_t)bdt
>>8);
157 USB0
->BDTPAGE2
= (uint8_t)((uint32_t)bdt
>>16);
158 USB0
->BDTPAGE3
= (uint8_t)((uint32_t)bdt
>>24);
160 // Clear interrupt flag
163 // USB Interrupt Enablers
164 USB0
->INTEN
|= USB_INTEN_TOKDNEEN_MASK
|
165 USB_INTEN_SOFTOKEN_MASK
|
166 USB_INTEN_ERROREN_MASK
|
167 USB_INTEN_USBRSTEN_MASK
;
169 // Disable weak pull downs
170 USB0
->USBCTRL
&= ~(USB_USBCTRL_PDE_MASK
| USB_USBCTRL_SUSP_MASK
);
172 USB0
->USBTRC0
|= 0x40;
175 USBHAL::~USBHAL(void) { }
177 void USBHAL::connect(void) {
179 USB0
->CTL
|= USB_CTL_USBENSOFEN_MASK
;
181 USB0
->CONTROL
|= USB_CONTROL_DPPULLUPNONOTG_MASK
;
184 void USBHAL::disconnect(void) {
186 USB0
->CTL
&= ~USB_CTL_USBENSOFEN_MASK
;
188 USB0
->CONTROL
&= ~USB_CONTROL_DPPULLUPNONOTG_MASK
;
190 //Free buffers if required:
191 for (int i
= 0; i
<(NUMBER_OF_PHYSICAL_ENDPOINTS
- 2) * 2; i
++) {
192 free(endpoint_buffer
[i
]);
193 endpoint_buffer
[i
] = NULL
;
195 free(endpoint_buffer_iso
[2]);
196 endpoint_buffer_iso
[2] = NULL
;
197 free(endpoint_buffer_iso
[0]);
198 endpoint_buffer_iso
[0] = NULL
;
201 void USBHAL::configureDevice(void) {
205 void USBHAL::unconfigureDevice(void) {
209 void USBHAL::setAddress(uint8_t address
) {
210 // we don't set the address now otherwise the usb controller does not ack
211 // we set a flag instead
212 // see usbisr when an IN token is received
217 bool USBHAL::realiseEndpoint(uint8_t endpoint
, uint32_t maxPacket
, uint32_t flags
) {
218 uint32_t handshake_flag
= 0;
221 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
225 uint32_t log_endpoint
= PHY_TO_LOG(endpoint
);
227 if ((flags
& ISOCHRONOUS
) == 0) {
228 handshake_flag
= USB_ENDPT_EPHSHK_MASK
;
229 if (IN_EP(endpoint
)) {
230 if (endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)] == NULL
)
231 endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)] = (uint8_t *) malloc (64*2);
232 buf
= &endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)][0];
234 if (endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)] == NULL
)
235 endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)] = (uint8_t *) malloc (64*2);
236 buf
= &endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)][0];
239 if (IN_EP(endpoint
)) {
240 if (endpoint_buffer_iso
[2] == NULL
)
241 endpoint_buffer_iso
[2] = (uint8_t *) malloc (1023*2);
242 buf
= &endpoint_buffer_iso
[2][0];
244 if (endpoint_buffer_iso
[0] == NULL
)
245 endpoint_buffer_iso
[0] = (uint8_t *) malloc (1023*2);
246 buf
= &endpoint_buffer_iso
[0][0];
250 // IN endpt -> device to host (TX)
251 if (IN_EP(endpoint
)) {
252 USB0
->ENDPOINT
[log_endpoint
].ENDPT
|= handshake_flag
| // ep handshaking (not if iso endpoint)
253 USB_ENDPT_EPTXEN_MASK
; // en TX (IN) tran
254 bdt
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)].address
= (uint32_t) buf
;
255 bdt
[EP_BDT_IDX(log_endpoint
, TX
, EVEN
)].address
= 0;
257 // OUT endpt -> host to device (RX)
259 USB0
->ENDPOINT
[log_endpoint
].ENDPT
|= handshake_flag
| // ep handshaking (not if iso endpoint)
260 USB_ENDPT_EPRXEN_MASK
; // en RX (OUT) tran.
261 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].byte_count
= maxPacket
;
262 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].address
= (uint32_t) buf
;
263 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].info
= BD_OWN_MASK
| BD_DTS_MASK
;
264 bdt
[EP_BDT_IDX(log_endpoint
, RX
, EVEN
)].info
= 0;
267 Data1
|= (1 << endpoint
);
273 void USBHAL::EP0setup(uint8_t *buffer
) {
275 endpointReadResult(EP0OUT
, buffer
, &sz
);
278 void USBHAL::EP0readStage(void) {
279 Data1
&= ~1UL; // set DATA0
280 bdt
[0].info
= (BD_DTS_MASK
| BD_OWN_MASK
);
283 void USBHAL::EP0read(void) {
284 uint32_t idx
= EP_BDT_IDX(PHY_TO_LOG(EP0OUT
), RX
, 0);
285 bdt
[idx
].byte_count
= MAX_PACKET_SIZE_EP0
;
288 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer
) {
290 endpointReadResult(EP0OUT
, buffer
, &sz
);
294 void USBHAL::EP0write(uint8_t *buffer
, uint32_t size
) {
295 endpointWrite(EP0IN
, buffer
, size
);
298 void USBHAL::EP0getWriteResult(void) {
301 void USBHAL::EP0stall(void) {
302 stallEndpoint(EP0OUT
);
305 EP_STATUS
USBHAL::endpointRead(uint8_t endpoint
, uint32_t maximumSize
) {
306 endpoint
= PHY_TO_LOG(endpoint
);
307 uint32_t idx
= EP_BDT_IDX(endpoint
, RX
, 0);
308 bdt
[idx
].byte_count
= maximumSize
;
312 EP_STATUS
USBHAL::endpointReadResult(uint8_t endpoint
, uint8_t * buffer
, uint32_t *bytesRead
) {
313 uint32_t n
, sz
, idx
, setup
= 0;
317 uint32_t log_endpoint
= PHY_TO_LOG(endpoint
);
319 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
323 // if read on a IN endpoint -> error
324 if (IN_EP(endpoint
)) {
328 idx
= EP_BDT_IDX(log_endpoint
, RX
, 0);
329 sz
= bdt
[idx
].byte_count
;
330 not_iso
= USB0
->ENDPOINT
[log_endpoint
].ENDPT
& USB_ENDPT_EPHSHK_MASK
;
332 //for isochronous endpoint, we don't wait an interrupt
333 if ((log_endpoint
!= 0) && not_iso
&& !(epComplete
& EP(endpoint
))) {
337 if ((log_endpoint
== 0) && (TOK_PID(idx
) == SETUP_TOKEN
)) {
343 ep_buf
= endpoint_buffer
[idx
];
345 ep_buf
= endpoint_buffer_iso
[0];
348 for (n
= 0; n
< sz
; n
++) {
349 buffer
[n
] = ep_buf
[n
];
352 if (((Data1
>> endpoint
) & 1) == ((bdt
[idx
].info
>> 6) & 1)) {
353 if (setup
&& (buffer
[6] == 0)) // if no setup data stage,
354 Data1
&= ~1UL; // set DATA0
356 Data1
^= (1 << endpoint
);
359 if (((Data1
>> endpoint
) & 1)) {
360 bdt
[idx
].info
= BD_DTS_MASK
| BD_DATA01_MASK
| BD_OWN_MASK
;
363 bdt
[idx
].info
= BD_DTS_MASK
| BD_OWN_MASK
;
366 USB0
->CTL
&= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK
;
369 epComplete
&= ~EP(endpoint
);
373 EP_STATUS
USBHAL::endpointWrite(uint8_t endpoint
, uint8_t *data
, uint32_t size
) {
377 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
381 // if write on a OUT endpoint -> error
382 if (OUT_EP(endpoint
)) {
386 idx
= EP_BDT_IDX(PHY_TO_LOG(endpoint
), TX
, 0);
387 bdt
[idx
].byte_count
= size
;
391 if (USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
& USB_ENDPT_EPHSHK_MASK
) {
392 ep_buf
= endpoint_buffer
[idx
];
394 ep_buf
= endpoint_buffer_iso
[2];
397 for (n
= 0; n
< size
; n
++) {
401 if ((Data1
>> endpoint
) & 1) {
402 bdt
[idx
].info
= BD_OWN_MASK
| BD_DTS_MASK
;
404 bdt
[idx
].info
= BD_OWN_MASK
| BD_DTS_MASK
| BD_DATA01_MASK
;
407 Data1
^= (1 << endpoint
);
412 EP_STATUS
USBHAL::endpointWriteResult(uint8_t endpoint
) {
413 if (epComplete
& EP(endpoint
)) {
414 epComplete
&= ~EP(endpoint
);
421 void USBHAL::stallEndpoint(uint8_t endpoint
) {
422 USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
|= USB_ENDPT_EPSTALL_MASK
;
425 void USBHAL::unstallEndpoint(uint8_t endpoint
) {
426 USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
&= ~USB_ENDPT_EPSTALL_MASK
;
429 bool USBHAL::getEndpointStallState(uint8_t endpoint
) {
430 uint8_t stall
= (USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
& USB_ENDPT_EPSTALL_MASK
);
431 return (stall
) ? true : false;
434 void USBHAL::remoteWakeup(void) {
439 void USBHAL::_usbisr(void) {
444 void USBHAL::usbisr(void) {
446 uint8_t istat
= USB0
->ISTAT
;
449 if (istat
& USB_ISTAT_USBRST_MASK
) {
451 for(i
= 0; i
< 16; i
++) {
452 USB0
->ENDPOINT
[i
].ENDPT
= 0x00;
455 // enable control endpoint
456 realiseEndpoint(EP0OUT
, MAX_PACKET_SIZE_EP0
, 0);
457 realiseEndpoint(EP0IN
, MAX_PACKET_SIZE_EP0
, 0);
460 USB0
->CTL
|= USB_CTL_ODDRST_MASK
;
462 USB0
->ISTAT
= 0xFF; // clear all interrupt status flags
463 USB0
->ERRSTAT
= 0xFF; // clear all error flags
464 USB0
->ERREN
= 0xFF; // enable error interrupt sources
465 USB0
->ADDR
= 0x00; // set default address
471 if (istat
& USB_ISTAT_RESUME_MASK
) {
472 USB0
->ISTAT
= USB_ISTAT_RESUME_MASK
;
476 if (istat
& USB_ISTAT_SOFTOK_MASK
) {
477 USB0
->ISTAT
= USB_ISTAT_SOFTOK_MASK
;
478 // SOF event, read frame number
484 if (USB0
->ENDPOINT
[0].ENDPT
& USB_ENDPT_EPSTALL_MASK
)
485 USB0
->ENDPOINT
[0].ENDPT
&= ~USB_ENDPT_EPSTALL_MASK
;
486 USB0
->ISTAT
|= USB_ISTAT_STALL_MASK
;
491 uint32_t num
= (USB0
->STAT
>> 4) & 0x0F;
492 uint32_t dir
= (USB0
->STAT
>> 3) & 0x01;
493 uint32_t ev_odd
= (USB0
->STAT
>> 2) & 0x01;
496 if ((num
== 0) && (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == SETUP_TOKEN
)) {
498 bdt
[EP_BDT_IDX(0, TX
, EVEN
)].info
&= ~BD_OWN_MASK
;
499 bdt
[EP_BDT_IDX(0, TX
, ODD
)].info
&= ~BD_OWN_MASK
;
501 // EP0 SETUP event (SETUP data received)
506 if (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == OUT_TOKEN
) {
510 epComplete
|= (1 << EP(num
));
511 if ((instance
->*(epCallback
[EP(num
) - 2]))()) {
512 epComplete
&= ~(1 << EP(num
));
518 if (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == IN_TOKEN
) {
522 USB0
->ADDR
= addr
& 0x7F;
527 epComplete
|= (1 << (EP(num
) + 1));
528 if ((instance
->*(epCallback
[EP(num
) + 1 - 2]))()) {
529 epComplete
&= ~(1 << (EP(num
) + 1));
535 USB0
->ISTAT
= USB_ISTAT_TOKDNE_MASK
;
540 USB0
->ISTAT
|= USB_ISTAT_SLEEP_MASK
;
544 if (istat
& USB_ISTAT_ERROR_MASK
) {
545 USB0
->ERRSTAT
= 0xFF;
546 USB0
->ISTAT
|= USB_ISTAT_ERROR_MASK
;