summaryrefslogtreecommitdiff
path: root/usb-device-massstorage-project/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb-device-massstorage-project/main.c')
-rw-r--r--usb-device-massstorage-project/main.c1154
1 files changed, 1154 insertions, 0 deletions
diff --git a/usb-device-massstorage-project/main.c b/usb-device-massstorage-project/main.c
new file mode 100644
index 0000000..2af5346
--- /dev/null
+++ b/usb-device-massstorage-project/main.c
@@ -0,0 +1,1154 @@
+/*----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//-----------------------------------------------------------------------------
+/// \dir "USB Device Mass Storage Project"
+///
+/// !!!Purpose
+///
+/// The USB Massstorage Project will help you to get familiar with the
+/// USB Device Port(UDP) on AT91SAM microcontrollers. Also
+/// it can help you to be familiar with the USB Framework that is used for
+/// rapid development of USB-compliant class drivers such as USB Mass
+/// Storage class (MSD).
+///
+/// You can find following information depends on your needs:
+/// - Sample usage of USB MSD driver.
+/// - USB MSD driver development based on the AT91 USB Framework.
+/// - USB enumerate sequence, the standard and class-specific descriptors and
+/// requests handling.
+/// - The initialize sequence and usage of UDP interface.
+///
+/// !See
+/// - memories: Storage Media interface for MSD
+/// - usb: USB Framework, USB MSD driver and UDP interface driver
+/// - "AT91 USB device framework"
+/// - "USBD API"
+/// - "massstorage"
+/// - "USB MSD Driver"
+///
+/// !!!Requirements
+///
+/// This package can be used with all Atmel evaluation kits that have USB interface
+///
+/// !!!Description
+///
+/// When an EK running this program connected to a host (PC for example), with
+/// USB cable, the EK appears as a USB Disk for the host. Then the host can
+/// format/read/write on the disk.
+///
+/// If there is SDRAM on the EK, the disk can be up to 10M so that read/write
+/// speed can be tested.
+///
+/// If there is no SDRAM but only internal flash, the disk is about 30K and
+/// only small file can be tested.
+///
+/// !!!Usage
+///
+/// -# Build the program and download it inside the evaluation board. Please
+/// refer to the
+/// <a href="http://www.atmel.com/dyn/resources/prod_documents/doc6224.pdf">
+/// SAM-BA User Guide</a>, the
+/// <a href="http://www.atmel.com/dyn/resources/prod_documents/doc6310.pdf">
+/// GNU-Based Software Development</a> application note or to the
+/// <a href="ftp://ftp.iar.se/WWWfiles/arm/Guides/EWARM_UserGuide.ENU.pdf">
+/// IAR EWARM User Guide</a>, depending on your chosen solution.
+/// -# On the computer, open and configure a terminal application
+/// (e.g. HyperTerminal on Microsoft Windows) with these settings:
+/// - 115200 bauds
+/// - 8 bits of data
+/// - No parity
+/// - 1 stop bit
+/// - No flow control
+/// -# Start the application.
+/// -# In the terminal window, the following text should appear:
+/// \code
+/// -- USB Device Mass Storage Project xxx --
+/// -- AT91xxxxxx-xx
+/// -- Compiled: xxx xx xxxx xx:xx:xx --
+/// \endcode
+/// -# When connecting USB cable to windows, the LED blinks, and the host
+/// reports a new USB %device attachment and Disk installation.
+/// . Then new "USB Mass Storage Device" and
+/// "ATMEL Mass Storage MSD USB Device" and "Generic volume" appear in
+/// hardware %device list.
+/// -# You can find the new disk on host, and to create/write file to it.
+///
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// This file contains all the specific code for the
+/// usb-device-massstorage-project
+///
+/// !Contents
+///
+/// The code can be roughly broken down as follows:
+/// - Configuration functions
+/// - VBus_Configure
+/// - ConfigurePit
+/// - ConfigureWakeUp
+/// - PIO & Timer configurations in start of main
+/// - Interrupt handlers
+/// - ISR_Vbus
+/// - ISR_Pit
+/// - WakeUpHandler
+/// - ISR_Media
+/// - The main function, which implements the program behavior
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <board_lowlevel.h>
+#include <board_memories.h>
+#include <pio/pio.h>
+#include <pio/pio_it.h>
+#ifdef AT91C_BASE_PITC
+#include <pit/pit.h>
+#endif
+#include <irq/irq.h>
+#include <tc/tc.h>
+#include <dbgu/dbgu.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/led.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <memories/Media.h>
+#if defined(AT91C_EBI_SDRAM)
+#include <memories/MEDSdram.h>
+#endif
+#if defined(AT91C_BASE_DDR2C)
+#include <memories/MEDDdram.h>
+#endif
+#if defined(BOARD_SD_MCI_BASE)
+#include <memories/MEDSdcard.h>
+#endif
+#if defined(CHIP_FLASH_EFC) || defined(CHIP_FLASH_EEFC) && !defined(cortexm3)
+#include <memories/MEDFlash.h>
+#endif
+#if defined(at91sam3uek)
+#include <memories/MEDRamDisk.h>
+#endif
+#if 0
+#include <memories/MEDNandFlash.h>
+#include <memories/nandflash/RawNandFlash.h>
+#include <memories/nandflash/TranslatedNandFlash.h>
+#endif
+
+#include <pmc/pmc.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Maximum number of LUNs which can be defined.
+#define MAX_LUNS 3
+
+/// Media index for different disks
+#define DRV_RAMDISK 0 /// RAM disk
+#define DRV_IFLASH 0 /// Internal flash, if no RAM disk
+#define DRV_SDMMC 1 /// SD card, if there is
+#define DRV_NAND 2 /// Nand flash, if there is
+
+/// Delay for pushbutton debouncing (ms)
+#define DEBOUNCE_TIME 10
+
+/// PIT period value (seconds)
+#define PIT_PERIOD 1000
+
+/// Delay for display view update (*250ms)
+#define UPDATE_DELAY 4
+
+/// Delay for waiting DBGU input (*250ms)
+#define INPUT_DELAY 20
+
+#if defined(at91sam3uek)
+/// No reserved space for code in PSRAM
+#define CODE_SIZE (0)
+/// Size of the RAM disk in bytes (512K).
+#define RAMDISK_SIZE (512*1024)
+#else
+/// Maximum code size 100K reserved for running in SDRAM and FLASH
+#define CODE_SIZE (100*1024)
+/// Size of the RAM disk in bytes (10M).
+#define RAMDISK_SIZE (10*1024*1024)
+#endif
+
+/// Size of the reserved Nand Flash (4M)
+#define NF_RESERVE_SIZE (4*1024*1024)
+
+/// Size of the managed Nand Flash (128M)
+#define NF_MANAGED_SIZE (128*1024*1024)
+
+/// Size of one block in bytes.
+#define BLOCK_SIZE 512
+
+/// Size of the MSD IO buffer in bytes (2K, more the better).
+#define MSD_BUFFER_SIZE (12*BLOCK_SIZE)
+
+/// Use for power management
+#define STATE_IDLE 0
+/// The USB device is in suspend state
+#define STATE_SUSPEND 4
+/// The USB device is in resume state
+#define STATE_RESUME 5
+
+/// Retry 3 times when SD is inserted
+#define SD_INIT_RETRY 3
+
+//------------------------------------------------------------------------------
+// Global variables
+//------------------------------------------------------------------------------
+
+/// Available medias.
+Media medias[MAX_LUNS];
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+/// Device LUNs.
+MSDLun luns[MAX_LUNS];
+
+/// LUN read/write buffer.
+unsigned char msdBuffer[MSD_BUFFER_SIZE];
+
+/// Total data read/write by MSD
+unsigned int msdReadTotal = 0;
+unsigned int msdWriteTotal = 0;
+unsigned short msdFullCnt = 0;
+unsigned short msdNullCnt = 0;
+
+/// Update delay counter, tick is 250ms
+unsigned int updateDelay = UPDATE_DELAY;
+
+/// Flag to update Display View
+unsigned char updateView = 0;
+
+/// State of USB, for suspend and resume
+unsigned char USBState = STATE_IDLE;
+
+#if 0//#ifdef PINS_NANDFLASH
+/// Pins used to access to nandflash.
+static const Pin pPinsNf[] = {PINS_NANDFLASH};
+/// Nandflash device structure.
+static struct TranslatedNandFlash translatedNf;
+/// Address for transferring command bytes to the nandflash.
+static unsigned int cmdBytesAddr = BOARD_NF_COMMAND_ADDR;
+/// Address for transferring address bytes to the nandflash.
+static unsigned int addrBytesAddr = BOARD_NF_ADDRESS_ADDR;
+/// Address for transferring data bytes to the nandflash.
+static unsigned int dataBytesAddr = BOARD_NF_DATA_ADDR;
+/// Nandflash chip enable pin.
+static const Pin nfCePin = BOARD_NF_CE_PIN;
+/// Nandflash ready/busy pin.
+static const Pin nfRbPin = BOARD_NF_RB_PIN;
+#endif
+
+//------------------------------------------------------------------------------
+// Remote wake-up support (optional)
+//------------------------------------------------------------------------------
+#if (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_BUSPOWERED_RWAKEUP) \
+ || (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_SELFPOWERED_RWAKEUP)
+
+#define WAKEUP_CONFIGURE() ConfigureWakeUp()
+
+/// Button for Wake-UP the USB device.
+static const Pin pinWakeUp = PIN_PUSHBUTTON_1;
+
+//------------------------------------------------------------------------------
+/// Interrupt service routine for the PIT. Debounces the wake-up pin input.
+//------------------------------------------------------------------------------
+#if defined (AT91C_BASE_PITC)
+static void ISR_Pit(void)
+{
+ static unsigned long debounceCounter = DEBOUNCE_TIME;
+ unsigned long pisr = 0;
+
+ // Read the PISR
+ pisr = PIT_GetStatus() & AT91C_PITC_PITS;
+
+ if (pisr != 0) {
+
+ // Read the PIVR. It acknowledges the IT
+ PIT_GetPIVR();
+ }
+
+ // Button released
+ if (PIO_Get(&pinWakeUp)) {
+
+ debounceCounter = DEBOUNCE_TIME;
+ }
+ // Button still pressed
+ else {
+
+ debounceCounter--;
+ }
+
+ // End of debounce time
+ if (debounceCounter == 0) {
+
+ debounceCounter = DEBOUNCE_TIME;
+ PIT_DisableIT();
+ AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITEN;
+ MSDDriver_RemoteWakeUp();
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures the PIT to generate 1ms ticks.
+//------------------------------------------------------------------------------
+static void ConfigurePit(void)
+{
+ // Initialize and enable the PIT
+ PIT_Init(PIT_PERIOD, BOARD_MCK / 1000000);
+
+ // Disable the interrupt on the interrupt controller
+ IRQ_DisableIT(AT91C_ID_SYS);
+
+ // Configure the AIC for PIT interrupts
+ IRQ_ConfigureIT(AT91C_ID_SYS, 0, ISR_Pit);
+
+ // Enable the interrupt on the interrupt controller
+ IRQ_EnableIT(AT91C_ID_SYS);
+
+ // Enable the interrupt on the pit
+ PIT_EnableIT();
+
+ // Enable the pit
+ PIT_Enable();
+}
+#endif // AT91C_BASE_PITC
+
+//------------------------------------------------------------------------------
+/// Interrupt service routine for the remote wake-up pin. Starts the debouncing
+/// sequence.
+//------------------------------------------------------------------------------
+static void WakeUpHandler(const Pin *pin)
+{
+ TRACE_DEBUG("Wake-up handler\n\r");
+
+ // Check current level on the remote wake-up pin
+ if (!PIO_Get(&pinWakeUp)) {
+#ifdef AT91C_BASE_PITC
+ ConfigurePit();
+#endif // AT91C_BASE_PITC
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures the wake-up pin to generate interrupts.
+//------------------------------------------------------------------------------
+static void ConfigureWakeUp(void)
+{
+ TRACE_INFO("Wake-up configuration\n\r");
+
+ // Configure PIO
+ PIO_Configure(&pinWakeUp, 1);
+ PIO_ConfigureIt(&pinWakeUp, WakeUpHandler);
+ PIO_EnableIt(&pinWakeUp);
+}
+
+#else
+ #define WAKEUP_CONFIGURE()
+#endif
+
+//------------------------------------------------------------------------------
+// VBus monitoring (optional)
+//------------------------------------------------------------------------------
+#if defined(PIN_USB_VBUS)
+
+#define VBUS_CONFIGURE() VBus_Configure()
+
+/// VBus pin instance.
+static const Pin pinVbus = PIN_USB_VBUS;
+
+//------------------------------------------------------------------------------
+/// Handles interrupts coming from PIO controllers.
+//------------------------------------------------------------------------------
+void ISR_Vbus(const Pin *pPin)
+{
+ // Check current level on VBus
+ if (PIO_Get(&pinVbus)) {
+
+ TRACE_INFO("VBUS conn\n\r");
+ USBD_Connect();
+ }
+ else {
+
+ TRACE_INFO("VBUS discon\n\r");
+ USBD_Disconnect();
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures the VBus pin to trigger an interrupt when the level on that pin
+/// changes.
+//------------------------------------------------------------------------------
+static void VBus_Configure( void )
+{
+ TRACE_INFO("VBus configuration\n\r");
+
+ // Configure PIO
+ PIO_Configure(&pinVbus, 1);
+ PIO_ConfigureIt(&pinVbus, ISR_Vbus);
+ PIO_EnableIt(&pinVbus);
+
+ // Check current level on VBus
+ if (PIO_Get(&pinVbus)) {
+
+ // if VBUS present, force the connect
+ TRACE_INFO("conn\n\r");
+ USBD_Connect();
+ }
+ else {
+ USBD_Disconnect();
+ }
+}
+
+#else
+ #define VBUS_CONFIGURE() USBD_Connect()
+#endif //#if defined(PIN_USB_VBUS)
+
+
+//------------------------------------------------------------------------------
+// Callbacks (re)-implementation
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Invoked when the USB device leaves the Suspended state. By default,
+/// configures the LEDs.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Resumed(void)
+{
+ // Initialize LEDs
+ LED_Configure(USBD_LEDPOWER);
+ LED_Set(USBD_LEDPOWER);
+ LED_Configure(USBD_LEDUSB);
+ LED_Clear(USBD_LEDUSB);
+ USBState = STATE_RESUME;
+}
+
+//------------------------------------------------------------------------------
+/// Invoked when the USB device gets suspended. By default, turns off all LEDs.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Suspended(void)
+{
+ // Turn off LEDs
+ LED_Clear(USBD_LEDPOWER);
+ LED_Clear(USBD_LEDUSB);
+ USBState = STATE_SUSPEND;
+}
+
+//------------------------------------------------------------------------------
+/// Invoked when the MSD finish a READ/WRITE.
+/// \param flowDirection 1 - device to host (READ10)
+/// 0 - host to device (WRITE10)
+/// \param dataLength Length of data transferred in bytes.
+/// \param fifoNullCount Times that FIFO is NULL to wait
+/// \param fifoFullCount Times that FIFO is filled to wait
+//------------------------------------------------------------------------------
+void MSDCallbacks_Data(unsigned char flowDirection,
+ unsigned int dataLength,
+ unsigned int fifoNullCount,
+ unsigned int fifoFullCount)
+{
+ if (flowDirection) {
+
+ msdReadTotal += dataLength;
+ }
+ else {
+
+ msdWriteTotal += dataLength;
+ }
+
+ msdFullCnt += fifoFullCount;
+ msdNullCnt += fifoNullCount;
+}
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Interrupt handler for timer.
+//------------------------------------------------------------------------------
+void TC0_IrqHandler(void)
+{
+ volatile unsigned int dummy;
+ // Clear status bit to acknowledge interrupt
+ dummy = AT91C_BASE_TC0->TC_SR;
+
+ if (-- updateDelay == 0) {
+
+ updateDelay = UPDATE_DELAY;
+ updateView = 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configure Timer Counter 0 to generate an interrupt every 250ms.
+//------------------------------------------------------------------------------
+void ConfigureTc0(void)
+{
+ unsigned int div;
+ unsigned int tcclks;
+
+ // Enable peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;
+
+ // Configure TC for a 4Hz frequency and trigger on RC compare
+ TC_FindMckDivisor(4, BOARD_MCK, &div, &tcclks);
+ TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
+ AT91C_BASE_TC0->TC_RC = (BOARD_MCK / div) / 4; // timerFreq / desiredFreq
+
+ // Configure and enable interrupt on RC compare
+ IRQ_ConfigureIT(AT91C_ID_TC0, 3, TC0_IrqHandler);
+ AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
+ IRQ_EnableIT(AT91C_ID_TC0);
+
+ TC_Start(AT91C_BASE_TC0);
+}
+
+//------------------------------------------------------------------------------
+/// Interrupt handler for all media types.
+//------------------------------------------------------------------------------
+void ISR_Media(void)
+{
+ MED_HandleAll(medias, numMedias);
+}
+
+#if defined(BOARD_SD_MCI_BASE)
+//------------------------------------------------------------------------------
+/// SD card connection/disconnection handler, to initialize and link SD Media
+/// to corresponding LUN or unlink it.
+/// \param inserted SD card is inserted/ejected.
+//------------------------------------------------------------------------------
+static unsigned char SDConnectionUpdate(unsigned char inserted)
+{
+ unsigned char rc;
+ if (inserted) {
+ #if 1
+ // Faster, non-blocked SD access function
+ rc = MEDSdusb_Initialize(&(medias[DRV_SDMMC]), 0);
+ #else
+ // Blocked SD access function
+ rc = MEDSdcard_Initialize(&(medias[DRV_SDMMC]), 0);
+ #endif
+ if(rc) {
+ LUN_Init(&(luns[DRV_SDMMC]), &(medias[DRV_SDMMC]),
+ msdBuffer, MSD_BUFFER_SIZE,
+ 0, 0, 0, 0,
+ MSDCallbacks_Data);
+ return 1;
+ }
+ }
+ else {
+ LUN_Eject(&luns[DRV_SDMMC]);
+ }
+ return 0;
+}
+#endif
+
+#if 0//defined(PINS_NANDFLASH)
+#define NandFlash_Configure(nfBusWidth) BOARD_ConfigureNandFlash(nfBusWidth)
+
+//------------------------------------------------------------------------------
+/// Initialize Nand Flash for LUN
+//------------------------------------------------------------------------------
+static void NandFlashInitialize(void)
+{
+ unsigned char nfBusWidth = 16, nfRc;
+ unsigned short nfBaseBlock = 0;
+ struct RawNandFlash *pRaw = (struct RawNandFlash*)&translatedNf;
+ struct NandFlashModel *pModel = (struct NandFlashModel*)&translatedNf;
+ unsigned int nfMamagedSize;
+
+ // Configure SMC for NandFlash
+ NandFlash_Configure(nfBusWidth);
+ // Configure PIO for Nand Flash
+ PIO_Configure(pPinsNf, PIO_LISTSIZE(pPinsNf));
+
+ // Nand Flash Initialize (ALL flash mapped)
+ nfRc = RawNandFlash_Initialize(pRaw,
+ 0,
+ cmdBytesAddr,
+ addrBytesAddr,
+ dataBytesAddr,
+ nfCePin,
+ nfRbPin);
+ if (nfRc) {
+ printf("Nand not found\n\r");
+ return;
+ }
+ else {
+ printf("NF\tNb Blocks %d\n\r",
+ NandFlashModel_GetDeviceSizeInBlocks(pModel));
+ printf("\tBlock Size %dK\n\r",
+ NandFlashModel_GetBlockSizeInBytes(pModel)/1024);
+ printf("\tPage Size %d\n\r",
+ NandFlashModel_GetPageDataSize(pModel));
+ nfBaseBlock =
+ NF_RESERVE_SIZE / NandFlashModel_GetBlockSizeInBytes(pModel);
+ }
+ printf("NF disk will use area from %dM(B%d)\n\r",
+ NF_RESERVE_SIZE/1024/1024, nfBaseBlock);
+ printf("!! Erase the NF Disk? (y/n):");
+ updateDelay = INPUT_DELAY;
+ updateView = 0;
+ while(1) {
+ if(DBGU_IsRxReady()) {
+ char key = DBGU_GetChar();
+ DBGU_PutChar(key);
+ if (key == 'y') {
+ if (nfRc == 0) {
+ unsigned int block;
+ printf(" Erase from %d ... ", nfBaseBlock);
+ for (block = nfBaseBlock;
+ block < NandFlashModel_GetDeviceSizeInBlocks(pModel);
+ block ++) {
+ RawNandFlash_EraseBlock(pRaw, block);
+ }
+ printf("OK");
+ }
+ }
+ printf("\n\r");
+ break;
+ }
+ if (updateView) {
+ printf("No\n\r");
+ break;
+ }
+ }
+ nfMamagedSize = ((NandFlashModel_GetDeviceSizeInMBytes(pModel) - NF_RESERVE_SIZE/1024/1024) > NF_MANAGED_SIZE/1024/1024) ? \
+ NF_MANAGED_SIZE/1024/1024 : (NandFlashModel_GetDeviceSizeInMBytes(pModel) - NF_RESERVE_SIZE/1024/1024);
+ if (TranslatedNandFlash_Initialize(&translatedNf,
+ 0,
+ cmdBytesAddr,
+ addrBytesAddr,
+ dataBytesAddr,
+ nfCePin,
+ nfRbPin,
+ nfBaseBlock, nfMamagedSize * 1024 * 1024/NandFlashModel_GetBlockSizeInBytes(pModel))) {
+ printf("Nand init error\n\r");
+ return;
+ }
+ // Check the data bus width of the NandFlash
+ nfBusWidth =
+ NandFlashModel_GetDataBusWidth(pModel);
+ NandFlash_Configure(nfBusWidth);
+
+ // Media initialize
+ MEDNandFlash_Initialize(&medias[DRV_NAND], &translatedNf);
+
+ // Initialize LUN
+ LUN_Init(&(luns[DRV_NAND]), &(medias[DRV_NAND]),
+ msdBuffer, MSD_BUFFER_SIZE,
+ 0, 0, 0, 0,
+ MSDCallbacks_Data);
+
+ numMedias ++;
+}
+#endif
+
+#if !defined(cortexm3)
+
+//------------------------------------------------------------------------------
+/// Initialize memory for LUN
+//------------------------------------------------------------------------------
+static void MemoryInitialization(void)
+{
+ unsigned int i;
+ for (i = 0; i < MAX_LUNS; i ++)
+ LUN_Init(&luns[i], 0, 0, 0, 0, 0, 0, 0, 0);
+
+ // Memory initialization
+#if defined(AT91C_BASE_DDR2C)
+ TRACE_INFO("MEM: DDR2\n\r");
+ BOARD_ConfigureDdram(0, BOARD_DDRAM_BUSWIDTH); // Micron, 16 bit data bus size
+
+ MEDDdram_Initialize(&(medias[DRV_RAMDISK]),
+ BLOCK_SIZE,
+ (unsigned int)(AT91C_DDR2 + CODE_SIZE) / BLOCK_SIZE,
+ RAMDISK_SIZE / BLOCK_SIZE);
+ LUN_Init(&(luns[DRV_RAMDISK]), &(medias[DRV_RAMDISK]),
+ msdBuffer, MSD_BUFFER_SIZE,
+ 0, 0, 0, 0,
+ MSDCallbacks_Data);
+ numMedias = 1;
+
+#elif defined(AT91C_EBI_SDRAM)
+
+ TRACE_INFO("MEM: SDRAM\n\r");
+#if !defined(sdram)
+ BOARD_ConfigureSdram(BOARD_SDRAM_BUSWIDTH);
+#endif
+
+ MEDSdram_Initialize(&(medias[DRV_RAMDISK]),
+ BLOCK_SIZE,
+ (unsigned int)(AT91C_EBI_SDRAM + CODE_SIZE)/BLOCK_SIZE,
+ RAMDISK_SIZE / BLOCK_SIZE);
+ LUN_Init(&(luns[DRV_RAMDISK]),
+ &(medias[DRV_RAMDISK]),
+ msdBuffer, MSD_BUFFER_SIZE,
+ 0, 0, 0, 0,
+ MSDCallbacks_Data);
+ numMedias = 1;
+
+#endif // AT91C_EBI_SDRAM
+
+ // SD Card
+#if defined(BOARD_SD_MCI_BASE)
+ TRACE_DEBUG("MEM: SD Card\n\r");
+ SDConnectionUpdate(1);
+ numMedias = 2;
+#endif
+
+ // Flash
+#if defined(CHIP_FLASH_EFC) || defined(CHIP_FLASH_EEFC)
+ TRACE_INFO("MEM: Flash\n\r");
+ if (numMedias == 0) {
+
+ FLA_Initialize(&(medias[DRV_IFLASH]), AT91C_BASE_EFC);
+ LUN_Init(&(luns[DRV_IFLASH]),
+ &(medias[DRV_IFLASH]),
+ msdBuffer, MSD_BUFFER_SIZE,
+ CODE_SIZE,
+ AT91C_IFLASH_SIZE - CODE_SIZE,
+ BLOCK_SIZE,
+ 0,
+ MSDCallbacks_Data);
+ numMedias = 1;
+ }
+#endif // #if defined(CHIP_FLASH_EFC) || defined(CHIP_FLASH_EEFC)
+}
+#else
+static void MemoryInitialization(void)
+{
+ unsigned int i;
+ for (i = 0; i < MAX_LUNS; i ++)
+ LUN_Init(&luns[i], 0, 0, 0, 0, 0, 0, 0, 0);
+
+ #if defined(AT91C_EBI_PSRAM)
+ // Currently working on Sam3u-PSRAM
+ BOARD_ConfigurePsram();
+
+ // Initialize 10M for ram disk & code.
+ if (1 != MEDRamDisk_Initialize(&(medias[DRV_RAMDISK]),
+ BLOCK_SIZE,
+ (AT91C_EBI_PSRAM + CODE_SIZE) / BLOCK_SIZE,
+ RAMDISK_SIZE / BLOCK_SIZE)) {
+ TRACE_ERROR("FAIL!\n\r");
+ return;
+ }
+ // 512k Disk
+ LUN_Init(&(luns[DRV_RAMDISK]), &(medias[DRV_RAMDISK]), msdBuffer,
+ MSD_BUFFER_SIZE, 0, 0, 0, 0 , MSDCallbacks_Data);
+ #endif
+
+ // SD Disk
+ // SDConnectionUpdate(1);
+ numMedias = 2;
+
+ // Nand flash
+ //NandFlashInitialize();
+}
+#endif
+
+#if defined (CP15_PRESENT)
+//------------------------------------------------------------------------------
+/// Put the CPU in 32kHz, disable PLL, main oscillator
+/// Put voltage regulator in standby mode
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+ PMC_CPUInIdleMode();
+}
+//------------------------------------------------------------------------------
+/// Put voltage regulator in normal mode
+/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+}
+
+#elif defined(at91sam7a3)
+//------------------------------------------------------------------------------
+/// Put the CPU in 32kHz, disable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+ // MCK=48MHz to MCK=32kHz
+ // MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=SLCK : then change prescaler
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // disable PLL
+ AT91C_BASE_PMC->PMC_PLLR = 0;
+ // Disable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = 0;
+
+ PMC_DisableProcessorClock();
+}
+//------------------------------------------------------------------------------
+/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+ // MCK=32kHz to MCK=48MHz
+ // enable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
+
+ // enable PLL@96MHz
+ AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
+ (AT91C_CKGR_PLLCOUNT & (28<<8)) |
+ (AT91C_CKGR_MUL & (0x48<<16)));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
+ // MCK=SLCK/2 : change prescaler first
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=PLLCK/2 : then change source
+ AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+}
+
+#elif defined (at91sam7se)
+//------------------------------------------------------------------------------
+/// Put the CPU in 32kHz, disable PLL, main oscillator
+/// Put voltage regulator in standby mode
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+ // MCK=48MHz to MCK=32kHz
+ // MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=SLCK : then change prescaler
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // disable PLL
+ AT91C_BASE_PMC->PMC_PLLR = 0;
+ // Disable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = 0;
+
+ // Voltage regulator in standby mode : Enable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
+
+ PMC_DisableProcessorClock();
+}
+//------------------------------------------------------------------------------
+/// Put voltage regulator in normal mode
+/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+ // Voltage regulator in normal mode : Disable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
+
+ // MCK=32kHz to MCK=48MHz
+ // enable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
+
+ // enable PLL@96MHz
+ AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
+ (AT91C_CKGR_PLLCOUNT & (28<<8)) |
+ (AT91C_CKGR_MUL & (0x48<<16)));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
+ // MCK=SLCK/2 : change prescaler first
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=PLLCK/2 : then change source
+ AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+}
+
+#elif defined (at91sam7s)
+//------------------------------------------------------------------------------
+/// Put the CPU in 32kHz, disable PLL, main oscillator
+/// Put voltage regulator in standby mode
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+ // MCK=48MHz to MCK=32kHz
+ // MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=SLCK : then change prescaler
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // disable PLL
+ AT91C_BASE_PMC->PMC_PLLR = 0;
+ // Disable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = 0;
+
+ // Voltage regulator in standby mode : Enable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
+
+ PMC_DisableProcessorClock();
+}
+
+//------------------------------------------------------------------------------
+/// Put voltage regulator in normal mode
+/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+ // Voltage regulator in normal mode : Disable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
+
+ // MCK=32kHz to MCK=48MHz
+ // enable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
+
+ // enable PLL@96MHz
+ AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
+ (AT91C_CKGR_PLLCOUNT & (28<<8)) |
+ (AT91C_CKGR_MUL & (0x48<<16)));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
+ // MCK=SLCK/2 : change prescaler first
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=PLLCK/2 : then change source
+ AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+
+}
+
+#elif defined (at91sam7x) || defined (at91sam7xc)
+//------------------------------------------------------------------------------
+/// Put the CPU in 32kHz, disable PLL, main oscillator
+/// Put voltage regulator in standby mode
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+ // MCK=48MHz to MCK=32kHz
+ // MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=SLCK : then change prescaler
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // disable PLL
+ AT91C_BASE_PMC->PMC_PLLR = 0;
+ // Disable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = 0;
+
+ // Voltage regulator in standby mode : Enable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
+
+ PMC_DisableProcessorClock();
+}
+
+//------------------------------------------------------------------------------
+/// Put voltage regulator in normal mode
+/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+ // Voltage regulator in normal mode : Disable VREG Low Power Mode
+ AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
+
+ // MCK=32kHz to MCK=48MHz
+ // enable Main Oscillator
+ AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
+
+ // enable PLL@96MHz
+ AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
+ (AT91C_CKGR_PLLCOUNT & (28<<8)) |
+ (AT91C_CKGR_MUL & (0x48<<16)));
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
+ // MCK=SLCK/2 : change prescaler first
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+ // MCK=PLLCK/2 : then change source
+ AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
+ while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
+}
+#else
+//------------------------------------------------------------------------------
+/// Put the CPU in low power mode (for customer)
+//------------------------------------------------------------------------------
+static void LowPowerMode(void)
+{
+}
+
+//------------------------------------------------------------------------------
+/// Return the CPU to normal speed (for customer)
+//------------------------------------------------------------------------------
+static void NormalPowerMode(void)
+{
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Initializes the Mass Storage driver and runs it.
+//------------------------------------------------------------------------------
+int main(void)
+{
+ unsigned char sdConnected = 0;
+ unsigned char sdInitErrorCnt = 0, sdInitExecDelay = 0;
+
+ TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
+ printf("-- USB Device Mass Storage Project %s --\n\r", SOFTPACK_VERSION);
+ printf("-- %s\n\r", BOARD_NAME);
+ printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__);
+
+ // If they are present, configure Vbus & Wake-up pins
+ PIO_InitializeInterrupts(0);
+
+ // If there is on board power, switch it off
+ #ifdef PIN_USB_POWER_ENB
+ { const Pin pinUsbPwr = PIN_USB_POWER_ENB;
+ PIO_Configure(&pinUsbPwr, 1);
+ }
+ #endif
+
+ WAKEUP_CONFIGURE();
+
+ // Start TC for timing & status update
+ ConfigureTc0();
+
+ MemoryInitialization();
+
+ ASSERT(numMedias > 0, "Error: No media defined.\n\r");
+ TRACE_INFO("%u medias defined\n\r", numMedias);
+
+ // BOT driver initialization
+ MSDDriver_Initialize(luns, numMedias);
+
+ // connect if needed
+ VBUS_CONFIGURE();
+
+ while (USBD_GetState() < USBD_STATE_CONFIGURED);
+
+
+ // Infinite loop
+ updateDelay = UPDATE_DELAY;
+ updateView = 0;
+ while (1) {
+
+ #if defined(BOARD_SD_MCI_BASE)
+ // SD Card disconnection
+ if (MEDSdcard_Detect(&medias[DRV_SDMMC], 0)) {
+ if (sdConnected == 0) {
+ // Try several times
+ if (sdInitExecDelay == 0) {
+ sdInitExecDelay = sdInitErrorCnt + 1;
+ }
+ }
+ }
+ else if (sdConnected) {
+ sdConnected = 0;
+ sdInitErrorCnt = 0;
+ SDConnectionUpdate(0);
+ printf("\n\r** SD removed!\n\r");
+ }
+ #endif
+
+ // Mass storage state machine
+ if (USBD_GetState() < USBD_STATE_CONFIGURED){}
+ else MSDDriver_StateMachine();
+
+ if( USBState == STATE_SUSPEND ) {
+ TRACE_DEBUG("suspend !\n\r");
+ LowPowerMode();
+ USBState = STATE_IDLE;
+ }
+ if( USBState == STATE_RESUME ) {
+ // Return in normal MODE
+ TRACE_DEBUG("resume !\n\r");
+ NormalPowerMode();
+ USBState = STATE_IDLE;
+ }
+
+ // Update status view
+ if (updateView) {
+
+ updateView = 0;
+ #if 0
+ if (msdWriteTotal < 50 * 1000)
+ MED_Flush(&medias[DRV_NAND]);
+ #endif
+
+ printf("Read %5dK, Write %5dK, IO %5dK; Null %4d, Full %4d\r",
+ msdReadTotal/(UPDATE_DELAY*250),
+ msdWriteTotal/(UPDATE_DELAY*250),
+ (msdReadTotal+msdWriteTotal)/(UPDATE_DELAY*250),
+ msdNullCnt, msdFullCnt);
+
+ msdReadTotal = 0;
+ msdWriteTotal = 0;
+ msdNullCnt = 0;
+ msdFullCnt = 0;
+
+ #if defined(BOARD_SD_MCI_BASE)
+ if (sdInitExecDelay) {
+ if (0 == --sdInitExecDelay) {
+ sdConnected = SDConnectionUpdate(1);
+ if (!sdConnected) {
+ if (SD_INIT_RETRY <= sdInitErrorCnt++) {
+ printf("\n\r** SD inserted but init fail!\n\r");
+ sdConnected = 1;
+ }
+ }
+ }
+ }
+ #endif
+ }
+ }
+}
+
personal git repositories of Harald Welte. Your mileage may vary