source: rtos_arduino/trunk/arduino_lib/hardware/arduino/samd/cores/arduino/USB/samd21_host.c@ 136

Last change on this file since 136 was 136, checked in by ertl-honda, 8 years ago

ライブラリとOS及びベーシックなサンプルの追加.

File size: 14.3 KB
Line 
1/* ----------------------------------------------------------------------------
2 * SAM Software Package License
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2011-2012, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following condition is met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30#include <stdio.h>
31
32#ifdef HOST_DEFINED
33
34//#define TRACE_UOTGHS_HOST(x) x
35#define TRACE_UOTGHS_HOST(x)
36
37//extern void (*gpf_isr)(void);
38
39// Handle UOTGHS Host driver state
40static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS;
41
42 __attribute__((__aligned__(4))) UsbHostDescriptor usb_pipe_table[USB_EPT_NUM];
43
44
45// NVM Software Calibration Area Mapping
46// USB TRANSN calibration value. Should be written to the USB PADCAL register.
47#define NVM_USB_PAD_TRANSN_POS 45
48#define NVM_USB_PAD_TRANSN_SIZE 5
49// USB TRANSP calibration value. Should be written to the USB PADCAL register.
50#define NVM_USB_PAD_TRANSP_POS 50
51#define NVM_USB_PAD_TRANSP_SIZE 5
52// USB TRIM calibration value. Should be written to the USB PADCAL register.
53#define NVM_USB_PAD_TRIM_POS 55
54#define NVM_USB_PAD_TRIM_SIZE 3
55
56/**
57 * \brief Initialize the SAMD21 host driver.
58 */
59void UHD_Init(void)
60{
61 uint32_t pad_transn;
62 uint32_t pad_transp;
63 uint32_t pad_trim;
64
65 /* Enable USB clock */
66 PM->APBBMASK.reg |= PM_APBBMASK_USB;
67
68 /* Set up the USB DP/DN pins */
69 PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1;
70 PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u)));
71 PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u));
72 PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1;
73 PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u)));
74 PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u));
75
76 /* ----------------------------------------------------------------------------------------------
77 * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
78 */
79 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6
80 GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
81 GCLK_CLKCTRL_CLKEN ;
82
83 while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
84 {
85 /* Wait for synchronization */
86 }
87
88 /* Reset */
89 USB->HOST.CTRLA.bit.SWRST = 1;
90 while (USB->HOST.SYNCBUSY.bit.SWRST) {
91 /* Sync wait */
92 }
93
94 udd_enable();
95
96 /* Load Pad Calibration */
97 pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller
98 + (NVM_USB_PAD_TRANSN_POS / 32))
99 >> (NVM_USB_PAD_TRANSN_POS % 32))
100 & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1);
101
102 if (pad_transn == 0x1F) { // maximum value (31)
103 pad_transn = 5;
104 }
105
106 USB->HOST.PADCAL.bit.TRANSN = pad_transn;
107
108 pad_transp =( *((uint32_t *)(NVMCTRL_OTP4)
109 + (NVM_USB_PAD_TRANSP_POS / 32))
110 >> (NVM_USB_PAD_TRANSP_POS % 32))
111 & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1);
112
113 if (pad_transp == 0x1F) { // maximum value (31)
114 pad_transp = 29;
115 }
116
117 USB->HOST.PADCAL.bit.TRANSP = pad_transp;
118
119 pad_trim =( *((uint32_t *)(NVMCTRL_OTP4)
120 + (NVM_USB_PAD_TRIM_POS / 32))
121 >> (NVM_USB_PAD_TRIM_POS % 32))
122 & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1);
123
124 if (pad_trim == 0x7) { // maximum value (7)
125 pad_trim = 3;
126 }
127
128 USB->HOST.PADCAL.bit.TRIM = pad_trim;
129
130 /* Set the configuration */
131 udd_force_host_mode();
132 udd_device_run_in_standby();
133 // Set address of USB SRAM
134 USB->HOST.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]);
135 // For USB_SPEED_FULL
136 udd_force_full_speed();
137 for (uint32_t i = 0; i < sizeof(usb_endpoint_table); i++) {
138 (*(uint32_t *)(&usb_endpoint_table[0]+i)) = 0;
139 }
140
141 uhd_state = UHD_STATE_NO_VBUS;
142
143 USB->HOST.CTRLB.bit.VBUSOK = 1;
144
145 // Configure interrupts
146 NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL);
147 NVIC_EnableIRQ((IRQn_Type) USB_IRQn);
148}
149
150//static void UHD_ISR(void)
151void USB_Handler(void)
152{
153 uint16_t flags;
154 uint8_t i;
155 uint8_t ept_int;
156
157 ept_int = udd_endpoint_interrupt();
158
159 /* Not endpoint interrupt */
160 if (0 == ept_int)
161 {
162
163
164 }
165 else
166 {
167 /* host interrupts */
168
169 /* get interrupt flags */
170 flags = USB->HOST.INTFLAG.reg;
171
172 /* host SOF interrupt */
173 if (flags & USB_HOST_INTFLAG_HSOF) {
174 /* clear the flag */
175 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_HSOF;
176 uhd_state = UHD_STATE_CONNECTED;
177 return;
178 }
179
180 /* host reset interrupt */
181 if (flags & USB_HOST_INTFLAG_RST) {
182 /* clear the flag */
183 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_RST;
184 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
185 return;
186 }
187
188 /* host upstream resume interrupts */
189 if (flags & USB_HOST_INTFLAG_UPRSM) {
190 /* clear the flags */
191 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_UPRSM;
192 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
193 return;
194 }
195
196 /* host downstream resume interrupts */
197 if (flags & USB_HOST_INTFLAG_DNRSM) {
198 /* clear the flags */
199 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_DNRSM;
200 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
201 return;
202 }
203
204 /* host wakeup interrupts */
205 if (flags & USB_HOST_INTFLAG_WAKEUP) {
206 /* clear the flags */
207 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_WAKEUP;
208 uhd_state = UHD_STATE_CONNECTED; //UHD_STATE_ERROR;
209 return;
210 }
211
212 /* host ram access interrupt */
213 if (flags & USB_HOST_INTFLAG_RAMACER) {
214 /* clear the flag */
215 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_RAMACER;
216 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
217 return;
218 }
219
220 /* host connect interrupt */
221 if (flags & USB_HOST_INTFLAG_DCONN) {
222 TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : Connection INT\r\n");)
223 /* clear the flag */
224 uhd_ack_connection();
225 uhd_disable_connection_int();
226 uhd_ack_disconnection();
227 uhd_enable_disconnection_int();
228 //uhd_enable_sof();
229 uhd_state = UHD_STATE_CONNECTED;
230 return;
231 }
232
233 /* host disconnect interrupt */
234 if (flags & USB_HOST_INTFLAG_DDISC) {
235 TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : Disconnection INT\r\n");)
236 /* clear the flag */
237 uhd_ack_disconnection();
238 uhd_disable_disconnection_int();
239 // Stop reset signal, in case of disconnection during reset
240 uhd_stop_reset();
241 // Disable wakeup/resumes interrupts,
242 // in case of disconnection during suspend mode
243 uhd_ack_connection();
244 uhd_enable_connection_int();
245 uhd_state = UHD_STATE_DISCONNECTED;
246 return;
247 }
248
249 }
250
251}
252
253
254
255
256/**
257 * \brief Trigger a USB bus reset.
258 */
259void UHD_BusReset(void)
260{
261 USB->HOST.CTRLB.bit.BUSRESET = 1;;
262}
263
264/**
265 * \brief Get VBUS state.
266 *
267 * \return VBUS status.
268 */
269uhd_vbus_state_t UHD_GetVBUSState(void)
270{
271 return uhd_state;
272}
273
274
275
276/**
277 * \brief Allocate FIFO for pipe 0.
278 *
279 * \param ul_add Address of remote device for pipe 0.
280 * \param ul_ep_size Actual size of the FIFO in bytes.
281 *
282 * \retval 0 success.
283 * \retval 1 error.
284 */
285uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size)
286{
287 struct usb_host_pipe_config cfg;
288
289 if (ep_size < 8)
290 {
291 return 0;
292 }
293
294 /* set pipe config */
295 USB->HOST.HostPipe[0].PCFG.bit.BK = 0;
296 USB->HOST.HostPipe[0].PCFG.bit.PTYPE = USB_HOST_PIPE_TYPE_CONTROL;
297 USB->HOST.HostPipe[0].BINTERVAL.reg = 0;
298 USB->HOST.HostPipe[0].PCFG.bit.PTOKEN = USB_HOST_PIPE_TOKEN_SETUP;
299
300 memset((uint8_t *)&usb_pipe_table[pipe_num], 0, sizeof(usb_pipe_table[0]));
301 usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR = 0;
302 usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PEPNUM = 0;
303 usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.SIZE = 0x03; // 64 bytes
304
305 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_TRCPT_Msk;
306 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_TRFAIL | USB_HOST_PINTENSET_PERR;
307 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_TXSTP;
308 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_STALL;
309
310 return 1;
311}
312
313/**
314 * \brief Allocate a new pipe.
315 *
316 * \note UOTGHS maximum pipe number is limited to 10, meaning that only a limited
317 * amount of devices can be connected. Unfortunately, using only one pipe shared accross
318 * various endpoints and devices is not possible because the UOTGHS IP does not allow to
319 * change the data toggle value through register interface.
320 *
321 * \param ul_dev_addr Address of remote device.
322 * \param ul_dev_ep Targeted endpoint of remote device.
323 * \param ul_type Pipe type.
324 * \param ul_dir Pipe direction.
325 * \param ul_maxsize Pipe size.
326 * \param ul_interval Polling interval (if applicable to pipe type).
327 * \param ul_nb_bank Number of banks associated with this pipe.
328 *
329 * \return the newly allocated pipe number on success, 0 otherwise.
330 */
331
332// pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_BLK, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, 0, UOTGHS_HSTPIPCFG_PBK_1_BANK);
333
334uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank)
335//bool uhd_ep_alloc(usb_add_t add, usb_ep_desc_t *ep_desc)
336{
337 /* set pipe config */
338 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.BK = ul_nb_bank;
339 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.PTYPE = ul_type;
340 USB->HOST.HostPipe[ul_dev_ep].BINTERVAL.reg = ul_interval;
341
342 if (ul_dir & USB_EP_DIR_IN)
343 {
344 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.PTOKEN = USB_HOST_PIPE_TOKEN_IN;
345 USB->HOST.HostPipe[ul_dev_ep].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY;
346 }
347 else
348 {
349 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.PTOKEN = USB_HOST_PIPE_TOKEN_OUT;
350 USB->HOST.HostPipe[ul_dev_ep].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY;
351 }
352
353 memset((uint8_t *)&usb_descriptor_table.usb_pipe_table[ul_dev_ep], 0, sizeof(usb_pipe_table[ul_dev_ep]));
354
355 usb_descriptor_table.usb_pipe_table[ul_dev_ep].HostDescBank[0].CTRL_PIPE.bit.PDADDR = ul_dev_addr;
356 usb_descriptor_table.usb_pipe_table[ul_dev_ep].HostDescBank[0].CTRL_PIPE.bit.PEPNUM = ul_dev_ep;
357 usb_descriptor_table.usb_pipe_table[ul_dev_ep].HostDescBank[0].PCKSIZE.bit.SIZE = 0x03; // 64 bytes
358
359 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_TRCPT_Msk;
360 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_TRFAIL | USB_HOST_PINTENSET_PERR;
361 USB->HOST.HostPipe[pipe_num].PINTENSET.reg = USB_HOST_PINTENSET_STALL;
362
363 return 1;
364}
365
366
367/**
368 * \brief Free a pipe.
369 *
370 * \param ul_pipe Pipe number to free.
371 */
372void UHD_Pipe_Free(uint32_t ul_pipe)
373{
374 // Unalloc pipe
375 uhd_disable_pipe(ul_pipe);
376 uhd_unallocate_memory(ul_pipe);
377 uhd_reset_pipe(ul_pipe);
378
379 // The Pipe is frozen and no additional requests will be sent to the device on this pipe address.
380 USB->HOST.HostPipe[pipe_num].PSTATUSSET.reg = USB_HOST_PSTATUSSET_PFREEZE;
381}
382
383/**
384 * \brief Read from a pipe.
385 *
386 * \param ul_pipe Pipe number.
387 * \param ul_size Maximum number of data to read.
388 * \param data Buffer to store the data.
389 *
390 * \return number of data read.
391 */
392uint32_t UHD_Pipe_Read(uint32_t pipe_num, uint32_t buf_size, uint8_t* buf)
393{
394 if (USB->HOST.HostPipe[pipe_num].PCFG.bit.PTYPE == USB_HOST_PIPE_TYPE_DISABLE)
395 {
396 return 0;
397 }
398
399 /* get pipe config from setting register */
400 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].ADDR.reg = (uint32_t)buf;
401 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
402 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = buf_size;
403 USB->HOST.HostPipe[pipe_num].PCFG.bit.PTOKEN = USB_HOST_PIPE_TOKEN_IN;
404
405 /* Start transfer */
406 USB->HOST.HostPipe[pipe_num].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY;
407
408 // Unfreeze pipe
409 USB->HOST.HostPipe[pipe_num].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_PFREEZE;
410
411 return buf_size;
412}
413
414/**
415 * \brief Write into a pipe.
416 *
417 * \param ul_pipe Pipe number.
418 * \param ul_size Maximum number of data to read.
419 * \param data Buffer containing data to write.
420 */
421void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data)
422{
423
424 if (USB->HOST.HostPipe[pipe_num].PCFG.bit.PTYPE == USB_HOST_PIPE_TYPE_DISABLE)
425 {
426 return 0;
427 }
428
429 /* get pipe config from setting register */
430 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].ADDR.reg = (uint32_t)buf;
431 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = buf_size;
432 usb_descriptor_table.usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
433 USB->HOST.HostPipe[pipe_num].PCFG.bit.PTOKEN = USB_HOST_PIPE_TOKEN_OUT;
434
435
436 return 1;
437}
438
439/**
440 * \brief Send a pipe content.
441 *
442 * \param ul_pipe Pipe number.
443 * \param ul_token_type Token type.
444 */
445void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type)
446{
447 /* Start transfer */
448 USB->HOST.HostPipe[pipe_num].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY;
449
450 // Unfreeze pipe
451 USB->HOST.HostPipe[pipe_num].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_PFREEZE;
452}
453
454/**
455 * \brief Check for pipe transfer completion.
456 *
457 * \param ul_pipe Pipe number.
458 * \param ul_token_type Token type.
459 *
460 * \retval 0 transfer is not complete.
461 * \retval 1 transfer is complete.
462 */
463uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
464{
465
466 // Freeze pipe
467 USB->HOST.HostPipe[pipe_num].PSTATUSSET.reg = USB_HOST_PSTATUSSET_PFREEZE;
468 switch(uhd_ctrl_request_phase) {
469 case UHD_CTRL_REQ_PHASE_DATA_IN:
470 _uhd_ctrl_phase_data_in(p_callback_para->transfered_size);
471 break;
472 case UHD_CTRL_REQ_PHASE_ZLP_IN:
473 _uhd_ctrl_request_end(UHD_TRANS_NOERROR);
474 break;
475 case UHD_CTRL_REQ_PHASE_DATA_OUT:
476 _uhd_ctrl_phase_data_out();
477 break;
478 case UHD_CTRL_REQ_PHASE_ZLP_OUT:
479 _uhd_ctrl_request_end(UHD_TRANS_NOERROR);
480 break;
481 }
482 return 0;
483}
484
485#endif
486
Note: See TracBrowser for help on using the repository browser.