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

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

1.7.10のファイルに更新

File size: 14.3 KB
Line 
1/*
2 Copyright (c) 2014 Arduino LLC. All right reserved.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 See the GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18/*
19** Modified 04/04/2016 by Arduino.org development team
20*/
21
22
23
24#include <stdio.h>
25#include <stdint.h>
26#include <string.h>
27
28#include "../Arduino.h"
29#include "variant.h"
30#include "USB_host.h"
31#include "samd21_host.h"
32#include "sam.h"
33#include "wiring_digital.h"
34#include "wiring_private.h"
35
36#define HOST_DEFINED
37
38#ifdef HOST_DEFINED
39
40//#define TRACE_UOTGHS_HOST(x) x
41#define TRACE_UOTGHS_HOST(x)
42
43// Handle UOTGHS Host driver state
44static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS;
45
46__attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table[USB_EPT_NUM];
47
48extern void (*gpf_isr)(void);
49
50
51// NVM Software Calibration Area Mapping
52// USB TRANSN calibration value. Should be written to the USB PADCAL register.
53#define NVM_USB_PAD_TRANSN_POS 45
54#define NVM_USB_PAD_TRANSN_SIZE 5
55// USB TRANSP calibration value. Should be written to the USB PADCAL register.
56#define NVM_USB_PAD_TRANSP_POS 50
57#define NVM_USB_PAD_TRANSP_SIZE 5
58// USB TRIM calibration value. Should be written to the USB PADCAL register.
59#define NVM_USB_PAD_TRIM_POS 55
60#define NVM_USB_PAD_TRIM_SIZE 3
61
62static void UHD_ISR(void);
63
64/**
65 * \brief Initialize the SAMD21 host driver.
66 */
67void UHD_Init(void)
68{
69 uint32_t pad_transn;
70 uint32_t pad_transp;
71 uint32_t pad_trim;
72 uint32_t i;
73
74// USB_SetHandler(&USB_Handler);
75 USB_SetHandler(&UHD_ISR);
76
77 /* Enable USB clock */
78 PM->APBBMASK.reg |= PM_APBBMASK_USB;
79
80 /* Set up the USB DP/DM pins */
81 pinPeripheral( 33ul, PIO_COM );
82 pinPeripheral( 34ul, PIO_COM );
83
84 /* ----------------------------------------------------------------------------------------------
85 * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
86 */
87 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6
88 GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
89 GCLK_CLKCTRL_CLKEN;
90
91 while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
92 {
93 /* Wait for synchronization */
94 }
95
96 /* Reset */
97 USB->HOST.CTRLA.bit.SWRST = 1;
98 while (USB->HOST.SYNCBUSY.bit.SWRST)
99 {
100 /* Sync wait */
101 }
102
103 // uhd_enable();
104 USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE | USB_CTRLA_MODE;
105 uhd_force_host_mode();
106 while (USB->HOST.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE);
107
108 /* Load Pad Calibration */
109 pad_transn = (*((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller
110 + (NVM_USB_PAD_TRANSN_POS / 32))
111 >> (NVM_USB_PAD_TRANSN_POS % 32))
112 & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1);
113
114 if (pad_transn == 0x1F) // maximum value (31)
115 {
116 pad_transn = 5;
117 }
118
119 USB->HOST.PADCAL.bit.TRANSN = pad_transn;
120
121 pad_transp = (*((uint32_t *)(NVMCTRL_OTP4)
122 + (NVM_USB_PAD_TRANSP_POS / 32))
123 >> (NVM_USB_PAD_TRANSP_POS % 32))
124 & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1);
125
126 if (pad_transp == 0x1F) // maximum value (31)
127 {
128 pad_transp = 29;
129 }
130
131 USB->HOST.PADCAL.bit.TRANSP = pad_transp;
132
133 pad_trim = (*((uint32_t *)(NVMCTRL_OTP4)
134 + (NVM_USB_PAD_TRIM_POS / 32))
135 >> (NVM_USB_PAD_TRIM_POS % 32))
136 & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1);
137
138 if (pad_trim == 0x7) // maximum value (7)
139 {
140 pad_trim = 3;
141 }
142
143 USB->HOST.PADCAL.bit.TRIM = pad_trim;
144
145
146 /* Set the configuration */
147 uhd_run_in_standby();
148 // Set address of USB SRAM
149 USB->HOST.DESCADD.reg = (uint32_t)(&usb_pipe_table[0]);
150 // For USB_SPEED_FULL
151 uhd_force_full_speed();
152 for (i = 0; i < sizeof(usb_pipe_table); i++)
153 {
154 (*(uint32_t *)(&usb_pipe_table[0] + i)) = 0;
155 }
156
157 uhd_state = UHD_STATE_NO_VBUS;
158
159 // Put VBUS on USB port
160 pinMode( 32ul, OUTPUT );
161 digitalWrite( 32ul, HIGH );
162
163 uhd_enable_connection_int();
164
165 USB->HOST.INTENSET.reg = USB_HOST_INTENSET_DCONN;
166 USB->HOST.INTENSET.reg = USB_HOST_INTENSET_WAKEUP;
167 USB->HOST.INTENSET.reg = USB_HOST_INTENSET_DDISC;
168
169 USB->HOST.CTRLB.bit.VBUSOK = 1;
170
171 // Configure interrupts
172 NVIC_SetPriority((IRQn_Type)USB_IRQn, 0UL);
173 NVIC_EnableIRQ((IRQn_Type)USB_IRQn);
174}
175
176
177static void UHD_ISR(void)
178//void USB_Handler(void)
179{
180 uint16_t flags;
181
182 if (USB->HOST.CTRLA.bit.MODE) {
183 /*host mode ISR */
184
185 /* get interrupt flags */
186 flags = USB->HOST.INTFLAG.reg;
187
188 /* host SOF interrupt */
189 if (flags & USB_HOST_INTFLAG_HSOF)
190 {
191 /* clear the flag */
192 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_HSOF;
193 uhd_state = UHD_STATE_CONNECTED;
194 return;
195 }
196
197 /* host reset interrupt */
198 if (flags & USB_HOST_INTFLAG_RST)
199 {
200 /* clear the flag */
201 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_RST;
202 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
203 return;
204 }
205
206 /* host upstream resume interrupts */
207 if (flags & USB_HOST_INTFLAG_UPRSM)
208 {
209 /* clear the flags */
210 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_UPRSM;
211 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
212 return;
213 }
214
215 /* host downstream resume interrupts */
216 if (flags & USB_HOST_INTFLAG_DNRSM)
217 {
218 /* clear the flags */
219 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_DNRSM;
220 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
221 return;
222 }
223
224 /* host wakeup interrupts */
225 if (flags & USB_HOST_INTFLAG_WAKEUP)
226 {
227 /* clear the flags */
228 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_WAKEUP;
229 uhd_state = UHD_STATE_CONNECTED; //UHD_STATE_ERROR;
230 return;
231 }
232
233 /* host ram access interrupt */
234 if (flags & USB_HOST_INTFLAG_RAMACER)
235 {
236 /* clear the flag */
237 USB->HOST.INTFLAG.reg = USB_HOST_INTFLAG_RAMACER;
238 uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
239 return;
240 }
241
242 /* host connect interrupt */
243 if (flags & USB_HOST_INTFLAG_DCONN)
244 {
245 TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : Connection INT\r\n");
246 )
247 /* clear the flag */
248 uhd_ack_connection();
249 uhd_disable_connection_int();
250 uhd_ack_disconnection();
251 uhd_enable_disconnection_int();
252 //uhd_enable_sof();
253 uhd_state = UHD_STATE_CONNECTED;
254 return;
255 }
256
257 /* host disconnect interrupt */
258 if (flags & USB_HOST_INTFLAG_DDISC)
259 {
260 TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : Disconnection INT\r\n");
261 )
262 /* clear the flag */
263 uhd_ack_disconnection();
264 uhd_disable_disconnection_int();
265 // Stop reset signal, in case of disconnection during reset
266 uhd_stop_reset();
267 // Disable wakeup/resumes interrupts,
268 // in case of disconnection during suspend mode
269 uhd_ack_connection();
270 uhd_enable_connection_int();
271 uhd_state = UHD_STATE_DISCONNECTED;
272 return;
273 }
274 }
275 else {
276 while(1);
277 }
278}
279
280
281
282/**
283 * \brief Get VBUS state.
284 *
285 * \return VBUS status.
286 */
287uhd_vbus_state_t UHD_GetVBUSState(void)
288{
289 return uhd_state;
290}
291
292
293/**
294 * \brief Allocate FIFO for pipe 0.
295 *
296 * \param ul_add Address of remote device for pipe 0.
297 * \param ul_ep_size Actual size of the FIFO in bytes.
298 *
299 * \retval 0 success.
300 * \retval 1 error.
301 */
302uint32_t UHD_Pipe0_Alloc(uint32_t ul_add , uint32_t ul_ep_size)
303{
304 (void)(ul_add); // Unused argument
305
306 if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) )
307 ul_ep_size = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed
308 else
309 ul_ep_size = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed
310
311 USB->HOST.HostPipe[0].PCFG.bit.PTYPE = 1; //USB_HOST_PCFG_PTYPE_CTRL;
312 usb_pipe_table[0].HostDescBank[0].CTRL_PIPE.bit.PEPNUM = 0;
313 usb_pipe_table[0].HostDescBank[0].PCKSIZE.bit.SIZE = ul_ep_size;
314
315 return 0;
316}
317
318
319/**
320 * \brief Allocate a new pipe.
321 *
322 * \note UOTGHS maximum pipe number is limited to 10, meaning that only a limited
323 * amount of devices can be connected. Unfortunately, using only one pipe shared accross
324 * various endpoints and devices is not possible because the UOTGHS IP does not allow to
325 * change the data toggle value through register interface.
326 *
327 * \param ul_dev_addr Address of remote device.
328 * \param ul_dev_ep Targeted endpoint of remote device.
329 * \param ul_type Pipe type.
330 * \param ul_dir Pipe direction.
331 * \param ul_maxsize Pipe size.
332 * \param ul_interval Polling interval (if applicable to pipe type).
333 * \param ul_nb_bank Number of banks associated with this pipe.
334 *
335 * \return the newly allocated pipe number on success, 0 otherwise.
336 */
337
338// 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);
339
340uint32_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)
341//bool uhd_ep_alloc(usb_add_t add, usb_ep_desc_t *ep_desc)
342{
343 /* set pipe config */
344 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.BK = ul_nb_bank;
345 USB->HOST.HostPipe[ul_dev_ep].PCFG.reg &= ~USB_HOST_PCFG_MASK; // USB->HOST.HostPipe[0].PCFG.bit.PTYPE = 1; //USB_HOST_PCFG_PTYPE_CTRL;
346 USB->HOST.HostPipe[ul_dev_ep].PCFG.reg |= ul_type;
347 USB->HOST.HostPipe[ul_dev_ep].BINTERVAL.reg = ul_interval;
348
349 if (ul_dir & USB_EP_DIR_IN)
350 {
351 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.PTOKEN = USB_HOST_PCFG_PTOKEN_IN;
352 USB->HOST.HostPipe[ul_dev_ep].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY;
353 }
354 else
355 {
356 USB->HOST.HostPipe[ul_dev_ep].PCFG.bit.PTOKEN = USB_HOST_PCFG_PTOKEN_OUT;
357 USB->HOST.HostPipe[ul_dev_ep].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY;
358 }
359
360 if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) )
361 ul_maxsize = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed
362 else
363 ul_maxsize = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed
364
365 memset((uint8_t *)&usb_pipe_table[ul_dev_ep], 0, sizeof(usb_pipe_table[ul_dev_ep]));
366
367 usb_pipe_table[ul_dev_ep].HostDescBank[0].CTRL_PIPE.bit.PDADDR = ul_dev_addr;
368 usb_pipe_table[ul_dev_ep].HostDescBank[0].CTRL_PIPE.bit.PEPNUM = ul_dev_ep;
369 usb_pipe_table[ul_dev_ep].HostDescBank[0].PCKSIZE.bit.SIZE = ul_maxsize;
370
371 return 1;
372}
373
374
375void UHD_Pipe_CountZero(uint32_t ul_pipe)
376{
377 usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
378}
379
380/**
381 * \brief Free a pipe.
382 *
383 * \param ul_pipe Pipe number to free.
384 */
385void UHD_Pipe_Free(uint32_t ul_pipe)
386{
387 // The Pipe is frozen and no additional requests will be sent to the device on this pipe address.
388 USB->HOST.HostPipe[ul_pipe].PSTATUSSET.reg = USB_HOST_PSTATUSSET_PFREEZE;
389}
390
391
392/**
393 * \brief Read from a pipe.
394 *
395 * \param ul_pipe Pipe number.
396 * \param ul_size Maximum number of data to read.
397 * \param data Buffer to store the data.
398 *
399 * \return number of data read.
400 */
401uint32_t UHD_Pipe_Read(uint32_t pipe_num, uint32_t buf_size, uint8_t *buf)
402{
403 if (USB->HOST.HostPipe[pipe_num].PCFG.bit.PTYPE == USB_HOST_PTYPE_DIS)
404 {
405 return 0;
406 }
407
408 /* get pipe config from setting register */
409 usb_pipe_table[pipe_num].HostDescBank[0].ADDR.reg = (uint32_t)buf;
410 usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
411 usb_pipe_table[pipe_num].HostDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = buf_size;
412 USB->HOST.HostPipe[pipe_num].PCFG.bit.PTOKEN = USB_HOST_PCFG_PTOKEN_IN;
413
414 /* Start transfer */
415 USB->HOST.HostPipe[pipe_num].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY;
416
417 // Unfreeze pipe
418 USB->HOST.HostPipe[pipe_num].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_PFREEZE;
419
420 return buf_size;
421}
422
423
424/**
425 * \brief Write into a pipe.
426 *
427 * \param ul_pipe Pipe number.
428 * \param ul_size Maximum number of data to read.
429 * \param data Buffer containing data to write.
430 */
431void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t *buf)
432{
433 /* get pipe config from setting register */
434 usb_pipe_table[ul_pipe].HostDescBank[0].ADDR.reg = (uint32_t)buf;
435 usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = ul_size;
436 usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
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 USB->HOST.HostPipe[ul_pipe].PCFG.bit.PTOKEN = ul_token_type;
448
449 /* Start transfer */
450 if(ul_token_type == USB_HOST_PCFG_PTOKEN_SETUP )
451 {
452 USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TXSTP;
453 USB->HOST.HostPipe[ul_pipe].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY;
454 }
455 else if(ul_token_type == USB_HOST_PCFG_PTOKEN_IN )
456 {
457 USB->HOST.HostPipe[ul_pipe].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY;
458 }
459 else
460 {
461 USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TRCPT(1); // Transfer Complete 0
462 USB->HOST.HostPipe[ul_pipe].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY;
463 }
464
465 // Unfreeze pipe
466 uhd_unfreeze_pipe(ul_pipe);
467}
468
469#define USB_HOST_PINTFLAG_TRCPT_Pos 0 /**< \brief (USB_HOST_PINTFLAG) Transfer Complete 0/1 Interrupt Flag */
470#define USB_HOST_PINTFLAG_TRCPT_Msk (0x3u << USB_HOST_PINTFLAG_TRCPT_Pos)
471#define USB_HOST_PINTFLAG_TRCPT(value) ((USB_HOST_PINTFLAG_TRCPT_Msk & ((value) << USB_HOST_PINTFLAG_TRCPT_Pos)))
472
473/**
474 * \brief Check for pipe transfer completion.
475 *
476 * \param ul_pipe Pipe number.
477 * \param ul_token_type Token type.
478 *
479 * \retval 0 transfer is not complete.
480 * \retval 1 transfer is complete.
481 */
482uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
483{
484 // Check for transfer completion depending on token type
485 switch (ul_token_type)
486 {
487 case USB_HOST_PCFG_PTOKEN_SETUP:
488 if (Is_uhd_setup_ready(ul_pipe))
489 {
490 uhd_ack_setup_ready(ul_pipe);
491 uhd_freeze_pipe(ul_pipe);
492 return 1;
493 }
494 break;
495
496 case USB_HOST_PCFG_PTOKEN_IN:
497 if (Is_uhd_in_received(ul_pipe))
498 {
499 // IN packet received
500 uhd_ack_in_received(ul_pipe);
501 // Freeze will stop after the transfer
502 uhd_freeze_pipe(ul_pipe);
503 return 1;
504 }
505 break;
506
507 case USB_HOST_PCFG_PTOKEN_OUT:
508 if (Is_uhd_out_ready(ul_pipe))
509 {
510 // OUT packet sent
511 uhd_ack_out_ready(ul_pipe);
512 uhd_freeze_pipe(ul_pipe);
513 return 1;
514 }
515 break;
516 }
517
518 return 0;
519}
520
521#endif // HOST_DEFINED
Note: See TracBrowser for help on using the repository browser.