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