00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2014, Atmel Corporation 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the disclaimer below. 00013 * 00014 * Atmel's name may not be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00020 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00023 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00024 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00025 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00026 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 * ---------------------------------------------------------------------------- 00028 */ 00029 /** \cond usb_hid_msd 00030 * \page usb_hid_msd USB HID(Keyboard)+MSD Example 00031 * 00032 * \section Purpose 00033 * 00034 * The USB COMPOSITE Project will help you to get familiar with the 00035 * USB Device Port(UDP)interface and also some of the other interfaces in 00036 * SAMv7 Microcontrollers. Also it can help you to be familiar with the USB 00037 * Framework that is used for rapid development of USB-compliant class 00038 * drivers such as USB Communication Device class (CDC), and how to combine 00039 * two USB functions to a single composite device (such as CDC + MSD). 00040 * 00041 * \section Requirements 00042 * 00043 * This package can be used with some of Atmel Xplained board that have UDP 00044 * interface, depending on the functions included. 00045 * 00046 * \section win_drv_update Windows Driver Update 00047 * 00048 * The composite device is generally supported by Microsoft windows, but some 00049 * patches are needed for muti-interface functions such as CDC & Audio. 00050 * 00051 * \section Description 00052 * 00053 * The demo simulates a USB composite device with HID Keyboard function and 00054 * USB Disk function integrated. 00055 * 00056 * When an Xplained running this program connected to a host (PC for example), 00057 * with USB cable, host will notice the attachment of a USB device. No device 00058 * driver offered for the device now. 00059 * 00060 * \section Usage 00061 * 00062 * -# Build the program and download it inside the SAM V71 Xplained Ultra board. 00063 * Please refer to the Getting Started with SAM V71 Microcontrollers.pdf 00064 * -# On the computer, open and configure a terminal application 00065 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 00066 * - 115200 bauds 00067 * - 8 bits of data 00068 * - No parity 00069 * - 1 stop bit 00070 * - No flow control 00071 * -# Start the application. 00072 * -# In the terminal window, the following text should appear: 00073 * \code 00074 * -- USB HIDMSD Device Project xxx -- 00075 * -- SAMxxxxx-xx 00076 * -- Compiled: xxx xx xxxx xx:xx:xx -- 00077 * \endcode 00078 * -# When connecting USB cable to windows, the LED blinks, and the host 00079 * reports a new USB device attachment. 00080 * -# For the windows driver installation and the test functions, please 00081 * refer to "USB HID Keyboard Project" & 00082 * "USB Device Mass Storage Project". 00083 * 00084 * \section References 00085 * - usb_hid_msd/main.c 00086 * - pio: Pin configurations and peripheral configure. 00087 * - memories: Storage Media interface for MSD 00088 * - usb: USB Device Framework, USB CDC driver and UDP interface driver 00089 * - \ref usbd_framework 00090 * - \ref usbd_api 00091 * - \ref usbd_composite "composite" 00092 * - \ref usbd_composite_drv 00093 * - \ref usbd_hid "hid" \\ \ref usbd_hid_key "hid-keyboard" 00094 * - \ref usbd_hid_kbd_drv 00095 * - \ref usbd_msd "massstorage" 00096 * - \ref usbd_msd_drv 00097 * - projects: 00098 * - \ref usb_hid_keyboard 00099 * - \ref usb_massstorage 00100 * 00101 */ 00102 00103 /** 00104 * \file 00105 * 00106 * This file contains all the specific code for the 00107 * usb_hid_msd 00108 * 00109 * \section Contents 00110 * 00111 * The code can be roughly broken down as follows: 00112 * - Configuration functions 00113 * - VBus_Configure 00114 * - PIO configurations in start of main 00115 * - Interrupt handlers 00116 * - ISR_Vbus 00117 * - Callback functions 00118 * - USBDCallbacks_RequestReceived 00119 * - The main function, which implements the program behaviour 00120 */ 00121 00122 /*---------------------------------------------------------------------------- 00123 * Headers 00124 *----------------------------------------------------------------------------*/ 00125 00126 #include "board.h" 00127 00128 #include "libstoragemedia.h" 00129 00130 #include <USBD_Config.h> 00131 #include <USBD_LEDs.h> 00132 00133 #include <HIDMSDDriver.h> 00134 #include <HIDDKeyboard.h> 00135 #include <MSDFunction.h> 00136 00137 #include <string.h> 00138 #include <stdbool.h> 00139 #include <stdint.h> 00140 #include <stdio.h> 00141 00142 /*--------------------------------------------------------------------------- 00143 * Definitions 00144 *---------------------------------------------------------------------------*/ 00145 00146 #define NO_PUSHBUTTON 00147 00148 /** Master clock frequency in Hz */ 00149 #define MCK BOARD_MCK 00150 00151 /** Number of keys used in the example. */ 00152 #define NUM_KEYS 2 00153 00154 /** Number of non-modifiers keys. */ 00155 #define NUM_NORMAL_KEYS 1 00156 00157 /** Number of modifier keys. */ 00158 #define NUM_MODIFIER_KEYS (NUM_KEYS - NUM_NORMAL_KEYS) 00159 00160 /** Num lock LED index. */ 00161 #define LED_NUMLOCK USBD_LEDOTHER 00162 00163 00164 /** Maximum number of LUNs which can be defined. */ 00165 #define MAX_LUNS 1 00166 /** Media index for different disks */ 00167 #define DRV_RAMDISK 0 /**< RAM disk */ 00168 #define DRV_SDMMC 1 /**< SD card */ 00169 #define DRV_NAND 2 /**< Nand flash */ 00170 00171 /** Size of one block in bytes. */ 00172 #define BLOCK_SIZE 512 00173 00174 /** Size of the MSD IO buffer in bytes (6K, more the better). */ 00175 #define MSD_BUFFER_SIZE (12*BLOCK_SIZE) 00176 00177 /** Ramdisk size: 20K (WinXP can not format the disk if lower than 20K) */ 00178 #define RAMDISK_SIZE 128*1024 00179 00180 COMPILER_SECTION("ramdisk_region") static uint8_t ramdisk_reserved[RAMDISK_SIZE]; 00181 #define RAMDISK_BASE_ADDR ((uint32_t)ramdisk_reserved) 00182 00183 /** Delay loop for MSD refresh */ 00184 #define MSD_REFRESH_LOOP 0 00185 00186 00187 /*---------------------------------------------------------------------------- 00188 * External variables 00189 *----------------------------------------------------------------------------*/ 00190 00191 /** Descriptor list for device enumeration */ 00192 extern const USBDDriverDescriptors hidmsddDriverDescriptors; 00193 00194 /*---------------------------------------------------------------------------- 00195 * Global variables 00196 *----------------------------------------------------------------------------*/ 00197 00198 /*- HID */ 00199 00200 #ifdef NO_PUSHBUTTON 00201 #else 00202 /** List of pinsPushButtons to configure for the application. */ 00203 static Pin pinsPushButtons[] = {PINS_PUSHBUTTONS}; 00204 #endif 00205 00206 /** Array of key codes produced by each button. */ 00207 static uint8_t keyCodes[NUM_KEYS] = { 00208 HIDKeypad_A, 00209 HIDKeypad_NUMLOCK, 00210 }; 00211 00212 /** Current status (pressed or not) for each key. */ 00213 static uint8_t keyStatus[NUM_KEYS]; 00214 00215 /*- MSD */ 00216 /** Available media. */ 00217 sMedia medias[MAX_LUNS]; 00218 00219 /** Device LUNs. */ 00220 MSDLun luns[MAX_LUNS]; 00221 00222 /** LUN read/write buffer. */ 00223 uint8_t msdBuffer[MSD_BUFFER_SIZE]; 00224 00225 /** Total data write to disk */ 00226 uint32_t msdWriteTotal = 0; 00227 /** Delay for data write refresh */ 00228 uint32_t msdRefreshDelay = MSD_REFRESH_LOOP; 00229 00230 /*----------------------------------------------------------------------------- 00231 * Callback re-implementation 00232 *----------------------------------------------------------------------------*/ 00233 /** 00234 * Invoked when the configuration of the device changes. Parse used endpoints. 00235 * \param cfgnum New configuration number. 00236 */ 00237 void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) 00238 { 00239 HIDMSDDriver_ConfigurationChangedHandler(cfgnum); 00240 } 00241 00242 /** 00243 * Invoked when a new SETUP request is received from the host. Forwards the 00244 * request to the Mass Storage device driver handler function. 00245 * \param request Pointer to a USBGenericRequest instance. 00246 */ 00247 void USBDCallbacks_RequestReceived(const USBGenericRequest *request) 00248 { 00249 HIDMSDDriver_RequestHandler(request); 00250 } 00251 00252 /*---------------------------------------------------------------------------- 00253 * Callbacks 00254 *----------------------------------------------------------------------------*/ 00255 00256 /** 00257 * Invoked when the MSD finish a READ/WRITE. 00258 * \param flowDirection 1 - device to host (READ10) 00259 * 0 - host to device (WRITE10) 00260 * \param dataLength Length of data transferred in bytes. 00261 * \param fifoNullCount Times that FIFO is NULL to wait 00262 * \param fifoFullCount Times that FIFO is filled to wait 00263 */ 00264 static void MSDCallbacks_Data(uint8_t flowDirection, 00265 uint32_t dataLength, 00266 uint32_t fifoNullCount, 00267 uint32_t fifoFullCount) 00268 { 00269 fifoNullCount = fifoNullCount; /*dummy */ 00270 fifoFullCount = fifoFullCount; /*dummy */ 00271 if (!flowDirection) { 00272 msdWriteTotal += dataLength; 00273 } 00274 } 00275 00276 /*--------------------------------------------------------------------------- 00277 * Internal functions 00278 *---------------------------------------------------------------------------*/ 00279 /** 00280 * Configure USB settings for USB device 00281 */ 00282 static void _ConfigureUotghs(void) 00283 { 00284 /* UTMI parallel mode, High/Full/Low Speed */ 00285 /* UUSBCK not used in this configuration (High Speed) */ 00286 PMC->PMC_SCDR = PMC_SCDR_USBCLK; 00287 /* USB clock register: USB Clock Input is UTMI PLL */ 00288 PMC->PMC_USB = PMC_USB_USBS; 00289 /* Enable peripheral clock for USBHS */ 00290 PMC_EnablePeripheral(ID_USBHS); 00291 USBHS->USBHS_CTRL = USBHS_CTRL_UIMOD_DEVICE; 00292 /* Enable PLL 480 MHz */ 00293 PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0xF); 00294 /* Wait that PLL is considered locked by the PMC */ 00295 while( !(PMC->PMC_SR & PMC_SR_LOCKU) ); 00296 00297 /* IRQ */ 00298 NVIC_EnableIRQ(USBHS_IRQn) ; 00299 } 00300 /** 00301 * Invoked when the status of the keyboard LEDs changes. Turns the num. lock 00302 * LED on or off. 00303 * \param numLockStatus Indicates the current status of the num. lock key. 00304 * \param capsLockStatus Indicates the current status of the caps lock key. 00305 * \param scrollLockStatus Indicates the current status of the scroll lock key 00306 */ 00307 void HIDDKeyboardCallbacks_LedsChanged( 00308 uint8_t numLockStatus, 00309 uint8_t capsLockStatus, 00310 uint8_t scrollLockStatus) 00311 { 00312 capsLockStatus = capsLockStatus; /*dummy */ 00313 scrollLockStatus = scrollLockStatus; /*dummy */ 00314 /* Num. lock */ 00315 if (numLockStatus) { 00316 LED_Set(LED_NUMLOCK); 00317 } else { 00318 LED_Clear(LED_NUMLOCK); 00319 } 00320 } 00321 00322 /*--------------------------------------------------------------------------- 00323 * Internal functions 00324 *---------------------------------------------------------------------------*/ 00325 00326 /** 00327 * Monitor keyboard buttons & Update key status in HID driver 00328 */ 00329 static void HIDDKeyboardProcessKeys(void) 00330 { 00331 uint32_t i; 00332 uint8_t pressedKeys[NUM_KEYS]; 00333 uint8_t pressedKeysSize = 0; 00334 uint8_t releasedKeys[NUM_KEYS]; 00335 uint8_t releasedKeysSize = 0; 00336 00337 /* Monitor buttons */ 00338 #ifdef NO_PUSHBUTTON 00339 if (DBG_IsRxReady()) { 00340 uint8_t key = DBG_GetChar(); 00341 switch(key) { 00342 case '1': case '2': 00343 i = key - '1'; 00344 if (keyStatus[i]) { 00345 /* Key press simulation */ 00346 TRACE_INFO("Key %u pressed\n\r", (unsigned int)i); 00347 keyStatus[i] = 0; 00348 pressedKeys[pressedKeysSize] = keyCodes[i]; 00349 pressedKeysSize ++; 00350 HIDDKeyboard_RemoteWakeUp(); 00351 } else { 00352 /* Key release simulation */ 00353 TRACE_INFO("Key %u released\n\r", (unsigned int)i); 00354 keyStatus[i] = 1; 00355 releasedKeys[releasedKeysSize] = keyCodes[i]; 00356 releasedKeysSize++; 00357 } 00358 break; 00359 default: DBG_PutChar(key); 00360 } 00361 } 00362 #else 00363 for (i=0; i < PIO_LISTSIZE(pinsPushButtons); i++) { 00364 /* Check if button state has changed */ 00365 uint8_t isButtonPressed = PIO_Get(&(pinsPushButtons[i])); 00366 if (isButtonPressed != keyStatus[i]) { 00367 /* Update button state */ 00368 if (!isButtonPressed) { 00369 /* Key has been pressed */ 00370 TRACE_INFO("Key %u has been pressed\n\r", i); 00371 keyStatus[i] = 0; 00372 pressedKeys[pressedKeysSize] = keyCodes[i]; 00373 pressedKeysSize++; 00374 HIDDKeyboard_RemoteWakeUp(); 00375 } else { 00376 /* Key has been released */ 00377 TRACE_INFO("Key %u has been released\n\r", i); 00378 keyStatus[i] = 1; 00379 releasedKeys[releasedKeysSize] = keyCodes[i]; 00380 releasedKeysSize++; 00381 } 00382 } 00383 } 00384 #endif 00385 /* Update key status in the HID driver if necessary */ 00386 if ((pressedKeysSize != 0) || (releasedKeysSize != 0)) { 00387 uint8_t status; 00388 do { 00389 status = HIDDKeyboard_ChangeKeys(pressedKeys, 00390 pressedKeysSize, 00391 releasedKeys, 00392 releasedKeysSize); 00393 } while (status != USBD_STATUS_SUCCESS); 00394 } 00395 } 00396 00397 /** 00398 * Initialize SDRAM to assign ramdisk block 00399 */ 00400 static void RamDiskInit(void) 00401 { 00402 printf("RamDisk @ %x, size %d\n\r", RAMDISK_BASE_ADDR , RAMDISK_SIZE); 00403 00404 BOARD_ConfigureSdram(); 00405 MEDRamDisk_Initialize(&(medias[DRV_RAMDISK]), 00406 BLOCK_SIZE, 00407 RAMDISK_BASE_ADDR / BLOCK_SIZE, 00408 RAMDISK_SIZE / BLOCK_SIZE, 00409 1); 00410 LUN_Init(&(luns[DRV_RAMDISK]), 00411 &(medias[DRV_RAMDISK]), 00412 msdBuffer, MSD_BUFFER_SIZE, 00413 0, 0, 0, 0, 00414 MSDCallbacks_Data); 00415 gNbMedias = 1; 00416 } 00417 00418 /** 00419 * Initialize MSD Media & LUNs 00420 */ 00421 static void _MemoriesInitialize(void) 00422 { 00423 uint32_t i ; 00424 00425 /* Reset all LUNs */ 00426 for (i = 0; i < MAX_LUNS; i ++) 00427 LUN_Init(&luns[i], 0, 0, 0, 0, 0, 0, 0, 0); 00428 00429 /* TODO: Add LUN Init here */ 00430 00431 /* RAM disk initialize */ 00432 RamDiskInit(); 00433 /* Nand Flash Init */ 00434 /* SD Card Init */ 00435 } 00436 00437 /*--------------------------------------------------------------------------- 00438 * Main 00439 *---------------------------------------------------------------------------*/ 00440 00441 /** 00442 * Initializes drivers and start the USB composite device. 00443 */ 00444 int main(void) 00445 { 00446 uint8_t usbConnected = 0; 00447 00448 /* Disable watchdog */ 00449 WDT_Disable(WDT); 00450 00451 SCB_EnableICache(); 00452 SCB_EnableDCache(); 00453 00454 printf("-- USB HIDMSD Device Project %s --\n\r", SOFTPACK_VERSION); 00455 printf("-- %s\n\r", BOARD_NAME); 00456 printf( "-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__ , COMPILER_NAME) ; 00457 00458 00459 /* If they are present, configure Vbus & Wake-up pins */ 00460 PIO_InitializeInterrupts(0); 00461 00462 /* Initialize all USB power (off) */ 00463 _ConfigureUotghs(); 00464 00465 /* ----- HID Function Initialize */ 00466 #ifdef NO_PUSHBUTTON 00467 printf( "-- : DBG key 1 2 used as buttons\n\r" ); 00468 printf( "-- : 1st press to push, 2nd press to release\n\r" ); 00469 #else 00470 /* Initialize key statuses and configure push buttons */ 00471 PIO_Configure(pinsPushButtons, PIO_LISTSIZE(pinsPushButtons)); 00472 #endif 00473 memset(keyStatus, 1, NUM_KEYS); 00474 00475 /* Configure LEDs */ 00476 LED_Configure(LED_NUMLOCK); 00477 00478 _MemoriesInitialize(); 00479 00480 /* USB COMPOSITE driver initialization */ 00481 HIDMSDDriver_Initialize(&hidmsddDriverDescriptors, luns, MAX_LUNS); 00482 00483 /* connect if needed */ 00484 USBD_Connect(); 00485 00486 /* Driver loop */ 00487 while (1) { 00488 /* Device is not configured */ 00489 if (USBD_GetState() < USBD_STATE_CONFIGURED) { 00490 if (usbConnected) { 00491 printf("-I- USB Disconnect/Suspend\n\r"); 00492 usbConnected = 0; 00493 } 00494 } else { 00495 if (usbConnected == 0) { 00496 printf("-I- USB Connect\n\r"); 00497 usbConnected = 1; 00498 } 00499 HIDDKeyboardProcessKeys(); 00500 MSDFunction_StateMachine(); 00501 00502 if (msdRefreshDelay -- > 0) { 00503 msdRefreshDelay = MSD_REFRESH_LOOP; 00504 if (msdWriteTotal < 5 * 1024) { 00505 // Flush Disk Media 00506 } 00507 msdWriteTotal = 0; 00508 } 00509 } 00510 } 00511 } 00512 /** \endcond */