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)
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
;
136 #elif defined(TARGET_INFINITY)
137 // USB clock source: FLL
138 SIM
->SOPT2
|= SIM_SOPT2_USBSRC_MASK
;
141 SIM
->SCGC4
|= SIM_SCGC4_USBOTG_MASK
;
143 // choose usb src as PLL
144 SIM
->SOPT2
&= ~SIM_SOPT2_PLLFLLSEL_MASK
;
145 SIM
->SOPT2
|= (SIM_SOPT2_USBSRC_MASK
| (1 << SIM_SOPT2_PLLFLLSEL_SHIFT
));
148 SIM
->SCGC4
|= SIM_SCGC4_USBOTG_MASK
;
153 NVIC_SetVector(USB0_IRQn
, (uint32_t)&_usbisr
);
154 NVIC_EnableIRQ(USB0_IRQn
);
156 // USB Module Configuration
158 USB0
->USBTRC0
|= USB_USBTRC0_USBRESET_MASK
;
159 while(USB0
->USBTRC0
& USB_USBTRC0_USBRESET_MASK
);
161 // Set BDT Base Register
162 USB0
->BDTPAGE1
= (uint8_t)((uint32_t)bdt
>>8);
163 USB0
->BDTPAGE2
= (uint8_t)((uint32_t)bdt
>>16);
164 USB0
->BDTPAGE3
= (uint8_t)((uint32_t)bdt
>>24);
166 // Clear interrupt flag
169 // USB Interrupt Enablers
170 USB0
->INTEN
|= USB_INTEN_TOKDNEEN_MASK
|
171 USB_INTEN_SOFTOKEN_MASK
|
172 USB_INTEN_ERROREN_MASK
|
173 USB_INTEN_USBRSTEN_MASK
;
175 // Disable weak pull downs
176 USB0
->USBCTRL
&= ~(USB_USBCTRL_PDE_MASK
| USB_USBCTRL_SUSP_MASK
);
178 USB0
->USBTRC0
|= 0x40;
181 USBHAL::~USBHAL(void) { }
183 void USBHAL::connect(void) {
185 USB0
->CTL
|= USB_CTL_USBENSOFEN_MASK
;
187 USB0
->CONTROL
|= USB_CONTROL_DPPULLUPNONOTG_MASK
;
190 void USBHAL::disconnect(void) {
192 USB0
->CTL
&= ~USB_CTL_USBENSOFEN_MASK
;
194 USB0
->CONTROL
&= ~USB_CONTROL_DPPULLUPNONOTG_MASK
;
196 //Free buffers if required:
197 for (int i
= 0; i
<(NUMBER_OF_PHYSICAL_ENDPOINTS
- 2) * 2; i
++) {
198 free(endpoint_buffer
[i
]);
199 endpoint_buffer
[i
] = NULL
;
201 free(endpoint_buffer_iso
[2]);
202 endpoint_buffer_iso
[2] = NULL
;
203 free(endpoint_buffer_iso
[0]);
204 endpoint_buffer_iso
[0] = NULL
;
207 void USBHAL::configureDevice(void) {
211 void USBHAL::unconfigureDevice(void) {
215 void USBHAL::setAddress(uint8_t address
) {
216 // we don't set the address now otherwise the usb controller does not ack
217 // we set a flag instead
218 // see usbisr when an IN token is received
223 bool USBHAL::realiseEndpoint(uint8_t endpoint
, uint32_t maxPacket
, uint32_t flags
) {
224 uint32_t handshake_flag
= 0;
227 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
231 uint32_t log_endpoint
= PHY_TO_LOG(endpoint
);
233 if ((flags
& ISOCHRONOUS
) == 0) {
234 handshake_flag
= USB_ENDPT_EPHSHK_MASK
;
235 if (IN_EP(endpoint
)) {
236 if (endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)] == NULL
)
237 endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)] = (uint8_t *) malloc (64*2);
238 buf
= &endpoint_buffer
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)][0];
240 if (endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)] == NULL
)
241 endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)] = (uint8_t *) malloc (64*2);
242 buf
= &endpoint_buffer
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)][0];
245 if (IN_EP(endpoint
)) {
246 if (endpoint_buffer_iso
[2] == NULL
)
247 endpoint_buffer_iso
[2] = (uint8_t *) malloc (1023*2);
248 buf
= &endpoint_buffer_iso
[2][0];
250 if (endpoint_buffer_iso
[0] == NULL
)
251 endpoint_buffer_iso
[0] = (uint8_t *) malloc (1023*2);
252 buf
= &endpoint_buffer_iso
[0][0];
256 // IN endpt -> device to host (TX)
257 if (IN_EP(endpoint
)) {
258 USB0
->ENDPOINT
[log_endpoint
].ENDPT
|= handshake_flag
| // ep handshaking (not if iso endpoint)
259 USB_ENDPT_EPTXEN_MASK
; // en TX (IN) tran
260 bdt
[EP_BDT_IDX(log_endpoint
, TX
, ODD
)].address
= (uint32_t) buf
;
261 bdt
[EP_BDT_IDX(log_endpoint
, TX
, EVEN
)].address
= 0;
263 // OUT endpt -> host to device (RX)
265 USB0
->ENDPOINT
[log_endpoint
].ENDPT
|= handshake_flag
| // ep handshaking (not if iso endpoint)
266 USB_ENDPT_EPRXEN_MASK
; // en RX (OUT) tran.
267 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].byte_count
= maxPacket
;
268 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].address
= (uint32_t) buf
;
269 bdt
[EP_BDT_IDX(log_endpoint
, RX
, ODD
)].info
= BD_OWN_MASK
| BD_DTS_MASK
;
270 bdt
[EP_BDT_IDX(log_endpoint
, RX
, EVEN
)].info
= 0;
273 Data1
|= (1 << endpoint
);
279 void USBHAL::EP0setup(uint8_t *buffer
) {
281 endpointReadResult(EP0OUT
, buffer
, &sz
);
284 void USBHAL::EP0readStage(void) {
285 Data1
&= ~1UL; // set DATA0
286 bdt
[0].info
= (BD_DTS_MASK
| BD_OWN_MASK
);
289 void USBHAL::EP0read(void) {
290 uint32_t idx
= EP_BDT_IDX(PHY_TO_LOG(EP0OUT
), RX
, 0);
291 bdt
[idx
].byte_count
= MAX_PACKET_SIZE_EP0
;
294 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer
) {
296 endpointReadResult(EP0OUT
, buffer
, &sz
);
300 void USBHAL::EP0write(uint8_t *buffer
, uint32_t size
) {
301 endpointWrite(EP0IN
, buffer
, size
);
304 void USBHAL::EP0getWriteResult(void) {
307 void USBHAL::EP0stall(void) {
308 stallEndpoint(EP0OUT
);
311 EP_STATUS
USBHAL::endpointRead(uint8_t endpoint
, uint32_t maximumSize
) {
312 endpoint
= PHY_TO_LOG(endpoint
);
313 uint32_t idx
= EP_BDT_IDX(endpoint
, RX
, 0);
314 bdt
[idx
].byte_count
= maximumSize
;
318 EP_STATUS
USBHAL::endpointReadResult(uint8_t endpoint
, uint8_t * buffer
, uint32_t *bytesRead
) {
319 uint32_t n
, sz
, idx
, setup
= 0;
323 uint32_t log_endpoint
= PHY_TO_LOG(endpoint
);
325 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
329 // if read on a IN endpoint -> error
330 if (IN_EP(endpoint
)) {
334 idx
= EP_BDT_IDX(log_endpoint
, RX
, 0);
335 sz
= bdt
[idx
].byte_count
;
336 not_iso
= USB0
->ENDPOINT
[log_endpoint
].ENDPT
& USB_ENDPT_EPHSHK_MASK
;
338 //for isochronous endpoint, we don't wait an interrupt
339 if ((log_endpoint
!= 0) && not_iso
&& !(epComplete
& EP(endpoint
))) {
343 if ((log_endpoint
== 0) && (TOK_PID(idx
) == SETUP_TOKEN
)) {
349 ep_buf
= endpoint_buffer
[idx
];
351 ep_buf
= endpoint_buffer_iso
[0];
354 for (n
= 0; n
< sz
; n
++) {
355 buffer
[n
] = ep_buf
[n
];
358 if (((Data1
>> endpoint
) & 1) == ((bdt
[idx
].info
>> 6) & 1)) {
359 if (setup
&& (buffer
[6] == 0)) // if no setup data stage,
360 Data1
&= ~1UL; // set DATA0
362 Data1
^= (1 << endpoint
);
365 if (((Data1
>> endpoint
) & 1)) {
366 bdt
[idx
].info
= BD_DTS_MASK
| BD_DATA01_MASK
| BD_OWN_MASK
;
369 bdt
[idx
].info
= BD_DTS_MASK
| BD_OWN_MASK
;
372 USB0
->CTL
&= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK
;
375 epComplete
&= ~EP(endpoint
);
379 EP_STATUS
USBHAL::endpointWrite(uint8_t endpoint
, uint8_t *data
, uint32_t size
) {
383 if (endpoint
> NUMBER_OF_PHYSICAL_ENDPOINTS
- 1) {
387 // if write on a OUT endpoint -> error
388 if (OUT_EP(endpoint
)) {
392 idx
= EP_BDT_IDX(PHY_TO_LOG(endpoint
), TX
, 0);
393 bdt
[idx
].byte_count
= size
;
397 if (USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
& USB_ENDPT_EPHSHK_MASK
) {
398 ep_buf
= endpoint_buffer
[idx
];
400 ep_buf
= endpoint_buffer_iso
[2];
403 for (n
= 0; n
< size
; n
++) {
407 if ((Data1
>> endpoint
) & 1) {
408 bdt
[idx
].info
= BD_OWN_MASK
| BD_DTS_MASK
;
410 bdt
[idx
].info
= BD_OWN_MASK
| BD_DTS_MASK
| BD_DATA01_MASK
;
413 Data1
^= (1 << endpoint
);
418 EP_STATUS
USBHAL::endpointWriteResult(uint8_t endpoint
) {
419 if (epComplete
& EP(endpoint
)) {
420 epComplete
&= ~EP(endpoint
);
427 void USBHAL::stallEndpoint(uint8_t endpoint
) {
428 USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
|= USB_ENDPT_EPSTALL_MASK
;
431 void USBHAL::unstallEndpoint(uint8_t endpoint
) {
432 USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
&= ~USB_ENDPT_EPSTALL_MASK
;
435 bool USBHAL::getEndpointStallState(uint8_t endpoint
) {
436 uint8_t stall
= (USB0
->ENDPOINT
[PHY_TO_LOG(endpoint
)].ENDPT
& USB_ENDPT_EPSTALL_MASK
);
437 return (stall
) ? true : false;
440 void USBHAL::remoteWakeup(void) {
445 void USBHAL::_usbisr(void) {
450 void USBHAL::usbisr(void) {
452 uint8_t istat
= USB0
->ISTAT
;
455 if (istat
& USB_ISTAT_USBRST_MASK
) {
457 for(i
= 0; i
< 16; i
++) {
458 USB0
->ENDPOINT
[i
].ENDPT
= 0x00;
461 // enable control endpoint
462 realiseEndpoint(EP0OUT
, MAX_PACKET_SIZE_EP0
, 0);
463 realiseEndpoint(EP0IN
, MAX_PACKET_SIZE_EP0
, 0);
466 USB0
->CTL
|= USB_CTL_ODDRST_MASK
;
468 USB0
->ISTAT
= 0xFF; // clear all interrupt status flags
469 USB0
->ERRSTAT
= 0xFF; // clear all error flags
470 USB0
->ERREN
= 0xFF; // enable error interrupt sources
471 USB0
->ADDR
= 0x00; // set default address
477 if (istat
& USB_ISTAT_RESUME_MASK
) {
478 USB0
->ISTAT
= USB_ISTAT_RESUME_MASK
;
482 if (istat
& USB_ISTAT_SOFTOK_MASK
) {
483 USB0
->ISTAT
= USB_ISTAT_SOFTOK_MASK
;
484 // SOF event, read frame number
490 if (USB0
->ENDPOINT
[0].ENDPT
& USB_ENDPT_EPSTALL_MASK
)
491 USB0
->ENDPOINT
[0].ENDPT
&= ~USB_ENDPT_EPSTALL_MASK
;
492 USB0
->ISTAT
|= USB_ISTAT_STALL_MASK
;
497 uint32_t num
= (USB0
->STAT
>> 4) & 0x0F;
498 uint32_t dir
= (USB0
->STAT
>> 3) & 0x01;
499 uint32_t ev_odd
= (USB0
->STAT
>> 2) & 0x01;
502 if ((num
== 0) && (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == SETUP_TOKEN
)) {
504 bdt
[EP_BDT_IDX(0, TX
, EVEN
)].info
&= ~BD_OWN_MASK
;
505 bdt
[EP_BDT_IDX(0, TX
, ODD
)].info
&= ~BD_OWN_MASK
;
507 // EP0 SETUP event (SETUP data received)
512 if (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == OUT_TOKEN
) {
516 epComplete
|= (1 << EP(num
));
517 if ((instance
->*(epCallback
[EP(num
) - 2]))()) {
518 epComplete
&= ~(1 << EP(num
));
524 if (TOK_PID((EP_BDT_IDX(num
, dir
, ev_odd
))) == IN_TOKEN
) {
528 USB0
->ADDR
= addr
& 0x7F;
533 epComplete
|= (1 << (EP(num
) + 1));
534 if ((instance
->*(epCallback
[EP(num
) + 1 - 2]))()) {
535 epComplete
&= ~(1 << (EP(num
) + 1));
541 USB0
->ISTAT
= USB_ISTAT_TOKDNE_MASK
;
546 USB0
->ISTAT
|= USB_ISTAT_SLEEP_MASK
;
550 if (istat
& USB_ISTAT_ERROR_MASK
) {
551 USB0
->ERRSTAT
= 0xFF;
552 USB0
->ISTAT
|= USB_ISTAT_ERROR_MASK
;