SAMV71 Xplained Ultra Software Package 1.4

main.c

Go to the documentation of this file.
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 */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines