⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 massstorage.dir

📁 本程序是以前程序的升级
💻 DIR
📖 第 1 页 / 共 3 页
字号:
        USBD_Write(0, 0, 0, 0, 0);
    }
    else {
        USBD_Stall(0);
    }
    break;
\endcode

 !!State Machine
 ...

 !Rationale
 A state machine is necessary for #non-blocking# operation of the driver. As
 previously stated, there are three steps when processing a command:
 - Reception of the CBW
 - Processing of the command (with data transfers if required)
 - Emission of the CSW

 Without a state machine, the program execution would be stopped at each step
 to wait for transfers completion or command processing. For example, reception
 of a CBW does not always happen immediately (the host does not have to issue
 commands regularly) and can block the system for a long time.

 Developing an asynchronous design based on a state machine is made easier when
 using Atmel "AT91 USB device framework", as most methods are asynchronous. For
 example, a write operation (using the USBD_Write function) returns
 immediately; a callback function can then be invoked when the transfer
 actually completes.

 !States
 Apart from the three states corresponding to the command processing flow (CBW,
 command processing and CSW), two more can be identified. The
 reception/emission of CBW/CSW will be broken down into two different states:
 the first state is used to issue the read/write operation, while the second
 one waits for the transfer to finish. This can be done by monitoring a
 "transfer complete" flag which is set using a callback function.

 In addition, some commands can be quite complicated to process: they may
 require several consecutive data transfers mixed with media access. Each
 command thus has its own second-tier state machine. During execution of a
 command, the main state machine remains in the "processing" state, and
 proceeds to the next one (CSW emission) only when the command is complete.

 Here is the states list:
 - MSDDriver_STATE_READ_CBW: Start of CBW reception
   (initial state after reset)
 - MSDDriver_STATE_WAIT_CBW: Waiting for CBW reception
 - MSDDriver_STATE_PROCESS_CBW: Command processing
 - MSDDriver_STATE_SEND_CSW: Start of CSW emission
 - MSDDriver_STATE_WAIT_CSW: Waiting for CSW emission

 A single function, named MSDDriver_StateMachine, is provided by the driver. It
 must be called regularly during the program execution. The following
 subsections describe the actions that must be performed during each state.

 \image MSDDriverStates.png "MSD Driver State Machine"

 #MSDDriver_STATE_READ_CBW#

 As said previously, this state is used to start the reception of a new Command
 Block Wrapper. This is done using the USB_Read method of the USB framework.
 The result code of the function is checked for any error; the
 USB_STATUS_SUCCESS code indicates that the transfer has been successfully
 started.
\code
//----------------------
case MSDDriver_STATE_READ_CBW:
//----------------------
    // Start the CBW read operation
    transfer->semaphore = 0;
    status = USBD_Read(MSDDriverDescriptors_BULKOUT,
                       cbw,
                       MSD_CBW_SIZE,
                       (TransferCallback) MSDDriver_Callback,
                       (void *) transfer);

    // Check operation result code
    if (status == USBD_STATUS_SUCCESS) {

        // If the command was successful, wait for transfer
        msdDriver.state = MSDDriver_STATE_WAIT_CBW;
    }
    break;
\endcode
 A callback function to invoke when the transfer is complete is provided to the
 USBD_Read method, to update a MSDTransfer structure. This structure
 indicates the transfer completion, the returned result code and the number of
 transferred and remaining bytes.
\code
typedef struct {
    unsigned int  transferred; //!< Number of bytes transferred
    unsigned int  remaining;   //!< Number of bytes not transferred
    unsigned char semaphore;   //!< Semaphore to indicate transfer completion
    unsigned char status;      //!< Operation result code
} MSDTransfer;
\endcode
 The callback function is trivial and thus not listed here.

 #MSDDriver_STATE_WAIT_CBW#

 The first step here is to monitor the }semaphore} field of the MSDTransfer
 structure (see above); this will enable detection of the transfer end. Please
 note that this field must be declared as volatile in C, or accesses to it
 might get optimized by the compiler; this can result in endless loops.

 If the transfer is complete, then the result code must be checked to see if
 there was an error. If the operation is successful, the state machine can
 proceed to command processing. Otherwise, it returns to the READ_CBW state.
\code
//----------------------
case MSDDriver_STATE_WAIT_CBW:
//----------------------
    // Check transfer semaphore
    if (transfer->semaphore > 0) {

        // Take semaphore and terminate transfer
        transfer->semaphore--;

        // Check if transfer was successful
        if (transfer->status == USBD_STATUS_SUCCESS) {

            // Process received command
            msdDriver.state = MSDDriver_STATE_PROCESS_CBW;
        }
        else if (transfer->status == USBD_STATUS_RESET) {

            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
        else {

            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
    }
    break;
\endcode

 #MSDDriver_STATE_PROCESS_CBW#

 Once the CBW has been received, its validity must be checked. A CBW is not
 valid if:
 - it has not been received right after a CSW was sent or a reset occured or
 - it is not exactly 31 bytes long or
 - its signature field is not equal to 43425355h

 The state machine prevents the first case from happening, so only the two
 other cases have to be verified.

 The number of bytes transferred during a USBD_Read operation is passed as an
 argument to the callback function, if one has been specified. As stated
 previously, such a function is used to fill a MSDTransfer structure.
 Therefore, it is trivial to check that the CBW is indeed 31 bytes by verifying
 that the number of bytes transferred is 31, and that there are no remaining
 bytes. The following table illustrates the three cases which may happen:
||Number of bytes transferred||Number of bytes remaining||Meaning
|transferred<31|remaining==0|CBW is too short
|transferred==31|remaining>0|CBW is too long
|transferred==31|remaining==0|CBW length is correct

 Checking the signature is simply done by comparing the dCBWSignature field
 with the expected value (43425355h).

 If the CBW is not valid, then the device must immediately halt both Bulk
 endpoints, to STALL further traffic from the host. In addition, it should stay
 in this state until a Reset Recovery is performed by the host. This is done by
 setting the waitResetRecovery flag in the MSDDriver structure. Finally, the
 CSW status is set to report an error, and the state machine is returned to
 MSDDriver_STATE_READ_CBW.

 Otherwise, if the CBW is correct, then the command can be processed. Remember
 the CBW tag must be copied regardless of the validity of the CBW.

 Note that these steps are only necessary for a new command (remember commands
 are asynchronous and are carried out in several calls, so a check can be
 performed to avoid useless processing. A value of zero for the internal
 command state indicates a new command.
\code
//-------------------------
case MSDDriver_STATE_PROCESS_CBW:
//-------------------------
    // Check if this is a new command
    if (commandState->state == 0) {

        // Copy the CBW tag
        csw->dCSWTag = cbw->dCBWTag;

        // Check that the CBW is 31 bytes long
        if ((transfer->transferred != MSD_CBW_SIZE) ||
            (transfer->remaining != 0)) {

            // Wait for a reset recovery
            msdDriver.waitResetRecovery = 1;

            // Halt the Bulk-IN and Bulk-OUT pipes
            USBD_Halt(MSDDriverDescriptors_BULKOUT);
            USBD_Halt(MSDDriverDescriptors_BULKIN);

            csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
            msdDriver.state = MSDDriver_STATE_READ_CBW;

        }
        // Check the CBW Signature
        else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) {

            // Wait for a reset recovery
            msdDriver.waitResetRecovery = 1;

            // Halt the Bulk-IN and Bulk-OUT pipes
            USBD_Halt(MSDDriverDescriptors_BULKOUT);
            USBD_Halt(MSDDriverDescriptors_BULKIN);

            csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
        else {

            // Pre-process command
            MSDDriver_PreProcessCommand();
        }
    }

    // Process command
    if (csw->bCSWStatus == MSDDriver_STATUS_SUCCESS) {

        if (MSDDriver_ProcessCommand()) {

            // Post-process command if it is finished
            MSDDriver_PostProcessCommand();
            msdDriver.state = MSDDriver_STATE_SEND_CSW;
        }
    }

    break;
\endcode

 #MSDDriver_STATE_SEND_CSW#

 This state is similar to MSDDriver_STATE_READ_CBW, except that a write
 operation is performed instead of a read and the CSW is sent, not the CBW. The
 same callback function is used to fill the transfer structure, which is
 checked in the next state:
\code
//----------------------
case MSDDriver_STATE_SEND_CSW:
//----------------------
    // Set signature
    csw->dCSWSignature = MSD_CSW_SIGNATURE;

    // Start the CSW write operation
    status = USBD_Write(MSDDriverDescriptors_BULKIN,
                        csw,
                        MSD_CSW_SIZE,
                        (TransferCallback) MSDDriver_Callback,
                        (void *) transfer);

    // Check operation result code
    if (status == USBD_STATUS_SUCCESS) {

        // Wait for end of transfer
        msdDriver.state = MSDDriver_STATE_WAIT_CSW;
    }
    break;
\endcode

 #MSDDriver_STATE_WAIT_CSW#

 Again, this state is very similar to MSDDriver_STATE_WAIT_CBW. The only
 difference is that the state machine is set to MSDDriver_STATE_READ_CBW
 regardless of the operation result code:
\code
//----------------------
case MSDDriver_STATE_WAIT_CSW:
//----------------------
    // Check transfer semaphore
    if (transfer->semaphore > 0) {

        // Take semaphore and terminate transfer
        transfer->semaphore--;

        // Read new CBW
        msdDriver.state = MSDDriver_STATE_READ_CBW;
    }
    break;
\endcode

 !!Media

 USB MSD Media access is three-level abstraction.

 \image MSDMediaArch.png "Media Architecture"

 The bottom level is the specific driver for each media type (See memories).

 In the middle, a structure Media is used to hide which specific driver a media
 instance is using. This enables transparent use of any media driver once it
 has been initialized (See _Media).

 Finally, a LUN abstraction is made over the media structure to allow multiple
 partitions over one media. This also makes it possible to place the LUN at any
 address and use any block size. When performing a write or read operation on a
 LUN, it forwards the operation to the underlying media while translating it to
 the correct address and length.

 !Media Drivers
 A media driver must provide several functions for:
 - Reading data from the media
 - Writing data on the media
 - Handling interrupts on the media
 The last function may be empty if the media does not require interrupts for
 asynchronous operation, or if synchronous operation produces an acceptable
 delay.

 In addition, it should also define a function for initializing a Media
 structure with the correct values, as well as perform the necessary step for
 the media to be useable.

 For the drivers see:
 - MEDSdram.h: }Internal Flash Driver}
 - MEDFlash.h: }SDRAM disk driver}

 !!SCSI Commands

 The example software described in this application note uses SCSI commands
 with the MSD class, since this is the most appropriate setting for a Flash
 device. This section details how SCSI commands are processed.

 !Documents

 There are several documents covering SCSI commands. In this application note,
 the reference document used is SCSI Block Commands - 3 (SBC-3). However, it
 makes many references to another SCSI document, SCSI Primary Commands - 4
 (SPC-4). Both are needed for full details on required commands.

 !Endianness

 SCSI commands use the big-endian format for storing word- and double word-
 sized data. This means the Most Significant Bit (MSB) is stored at the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -