Cleanups to the MassStorage Device demos, and the MassStorage Device Class driver.
[pub/USBasp.git] / Demos / Device / ClassDriver / MassStorage / Lib / DataflashManager.c
index 4ec52c3..6646278 100644 (file)
  *  the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes\r
  *  them to the dataflash in Dataflash page sized blocks.\r
  *\r
- *  \param MSInterfaceInfo  Pointer to a Mass Storage class state structure for the Mass Storage interface being used\r
- *  \param BlockAddress  Data block starting address for the write sequence\r
- *  \param TotalBlocks   Number of blocks of data to write\r
+ *  \param[in] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state\r
+ *  \param[in] BlockAddress  Data block starting address for the write sequence\r
+ *  \param[in] TotalBlocks   Number of blocks of data to write\r
  */\r
-void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)\r
+void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)\r
 {\r
        uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);\r
        uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);\r
        uint8_t  CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);\r
+       bool     UsingSecondBuffer   = false;\r
 \r
-       /* Copy selected dataflash's current page contents to the dataflash buffer */\r
+       /* Select the correct starting Dataflash IC for the block requested */\r
        Dataflash_SelectChipFromPage(CurrDFPage);\r
+\r
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)\r
+       /* Copy selected dataflash's current page contents to the dataflash buffer */\r
        Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);\r
        Dataflash_SendAddressBytes(CurrDFPage, 0);\r
        Dataflash_WaitWhileBusy();\r
+#endif\r
 \r
        /* Send the dataflash buffer write command */\r
-       Dataflash_ToggleSelectedChipCS();\r
        Dataflash_SendByte(DF_CMD_BUFF1WRITE);\r
        Dataflash_SendAddressBytes(0, CurrDFPageByte);\r
 \r
        /* Wait until endpoint is ready before continuing */\r
-       while (!(Endpoint_IsReadWriteAllowed()));\r
+       if (Endpoint_WaitUntilReady())\r
+         return;\r
 \r
        while (TotalBlocks)\r
        {\r
@@ -81,41 +86,44 @@ void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uin
                                Endpoint_ClearOUT();\r
                                \r
                                /* Wait until the host has sent another packet */\r
-                               while (!(Endpoint_IsReadWriteAllowed()));\r
+                               if (Endpoint_WaitUntilReady())\r
+                                 return;\r
                        }\r
 \r
                        /* Check if end of dataflash page reached */\r
                        if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))\r
                        {\r
                                /* Write the dataflash buffer contents back to the dataflash page */\r
-                               Dataflash_ToggleSelectedChipCS();\r
-                               Dataflash_SendByte(DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
+                               Dataflash_WaitWhileBusy();\r
+                               Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
                                Dataflash_SendAddressBytes(CurrDFPage, 0);\r
 \r
                                /* Reset the dataflash buffer counter, increment the page counter */\r
                                CurrDFPageByteDiv16 = 0;\r
                                CurrDFPage++;\r
 \r
+                               /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */\r
+                               if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))\r
+                                 UsingSecondBuffer = !(UsingSecondBuffer);\r
+\r
                                /* Select the next dataflash chip based on the new dataflash page index */\r
                                Dataflash_SelectChipFromPage(CurrDFPage);\r
-                               Dataflash_WaitWhileBusy();\r
 \r
 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)\r
                                /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */\r
                                if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))\r
                                {\r
                                        /* Copy selected dataflash's current page contents to the dataflash buffer */\r
-                                       Dataflash_ToggleSelectedChipCS();\r
-                                       Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);\r
+                                       Dataflash_WaitWhileBusy();\r
+                                       Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);\r
                                        Dataflash_SendAddressBytes(CurrDFPage, 0);\r
                                        Dataflash_WaitWhileBusy();\r
                                }\r
 #endif\r
 \r
                                /* Send the dataflash buffer write command */\r
-                               Dataflash_ToggleSelectedChipCS();\r
-                               Dataflash_SendByte(DF_CMD_BUFF1WRITE);\r
-                               Dataflash_SendAddressBytes(0, 0);\r
+                               Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);\r
+                               Dataflash_SendAddressBytes(0, 0);                               \r
                        }\r
 \r
                        /* Write one 16-byte chunk of data to the dataflash */\r
@@ -143,7 +151,7 @@ void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uin
                        BytesInBlockDiv16++;\r
 \r
                        /* Check if the current command is being aborted by the host */\r
-                       if (MSInterfaceInfo->IsMassStoreReset)\r
+                       if (MSInterfaceInfo->State.IsMassStoreReset)\r
                          return;                       \r
                }\r
                        \r
@@ -152,8 +160,8 @@ void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uin
        }\r
 \r
        /* Write the dataflash buffer contents back to the dataflash page */\r
-       Dataflash_ToggleSelectedChipCS();\r
-       Dataflash_SendByte(DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
+       Dataflash_WaitWhileBusy();\r
+       Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
        Dataflash_SendAddressBytes(CurrDFPage, 0x00);\r
        Dataflash_WaitWhileBusy();\r
 \r
@@ -169,18 +177,20 @@ void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uin
  *  the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash\r
  *  and writes them in OS sized blocks to the endpoint.\r
  *\r
- *  \param MSInterfaceInfo  Pointer to a Mass Storage class state structure for the Mass Storage interface being used\r
- *  \param BlockAddress  Data block starting address for the read sequence\r
- *  \param TotalBlocks   Number of blocks of data to read\r
+ *  \param[in] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state\r
+ *  \param[in] BlockAddress  Data block starting address for the read sequence\r
+ *  \param[in] TotalBlocks   Number of blocks of data to read\r
  */\r
-void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)\r
+void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)\r
 {\r
        uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);\r
        uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);\r
        uint8_t  CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);\r
 \r
-       /* Send the dataflash main memory page read command */\r
+       /* Select the correct starting Dataflash IC for the block requested */\r
        Dataflash_SelectChipFromPage(CurrDFPage);\r
+\r
+       /* Send the dataflash main memory page read command */\r
        Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);\r
        Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);\r
        Dataflash_SendByte(0x00);\r
@@ -189,7 +199,8 @@ void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint
        Dataflash_SendByte(0x00);\r
        \r
        /* Wait until endpoint is ready before continuing */\r
-       while (!(Endpoint_IsReadWriteAllowed()));\r
+       if (Endpoint_WaitUntilReady())\r
+         return;\r
        \r
        while (TotalBlocks)\r
        {\r
@@ -205,7 +216,8 @@ void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint
                                Endpoint_ClearIN();\r
                                \r
                                /* Wait until the endpoint is ready for more data */\r
-                               while (!(Endpoint_IsReadWriteAllowed()));\r
+                               if (Endpoint_WaitUntilReady())\r
+                                 return;\r
                        }\r
                        \r
                        /* Check if end of dataflash page reached */\r
@@ -252,7 +264,7 @@ void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint
                        BytesInBlockDiv16++;\r
 \r
                        /* Check if the current command is being aborted by the host */\r
-                       if (MSInterfaceInfo->IsMassStoreReset)\r
+                       if (MSInterfaceInfo->State.IsMassStoreReset)\r
                          return;\r
                }\r
                \r
@@ -273,27 +285,31 @@ void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint
  *  dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the\r
  *  dataflash.\r
  *\r
- *  \param BlockAddress  Data block starting address for the write sequence\r
- *  \param TotalBlocks   Number of blocks of data to write\r
- *  \param BufferPtr     Pointer to the data source RAM buffer\r
+ *  \param[in] BlockAddress  Data block starting address for the write sequence\r
+ *  \param[in] TotalBlocks   Number of blocks of data to write\r
+ *  \param[in] BufferPtr     Pointer to the data source RAM buffer\r
  */\r
 void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)\r
 {\r
        uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);\r
        uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);\r
        uint8_t  CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);\r
+       bool     UsingSecondBuffer   = false;\r
 \r
-       /* Copy selected dataflash's current page contents to the dataflash buffer */\r
+       /* Select the correct starting Dataflash IC for the block requested */\r
        Dataflash_SelectChipFromPage(CurrDFPage);\r
+\r
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)\r
+       /* Copy selected dataflash's current page contents to the dataflash buffer */\r
        Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);\r
        Dataflash_SendAddressBytes(CurrDFPage, 0);\r
        Dataflash_WaitWhileBusy();\r
+#endif\r
 \r
        /* Send the dataflash buffer write command */\r
-       Dataflash_ToggleSelectedChipCS();\r
        Dataflash_SendByte(DF_CMD_BUFF1WRITE);\r
        Dataflash_SendAddressBytes(0, CurrDFPageByte);\r
-\r
+       \r
        while (TotalBlocks)\r
        {\r
                uint8_t BytesInBlockDiv16 = 0;\r
@@ -305,25 +321,28 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota
                        if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))\r
                        {\r
                                /* Write the dataflash buffer contents back to the dataflash page */\r
-                               Dataflash_ToggleSelectedChipCS();\r
-                               Dataflash_SendByte(DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
+                               Dataflash_WaitWhileBusy();\r
+                               Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
                                Dataflash_SendAddressBytes(CurrDFPage, 0);\r
 \r
                                /* Reset the dataflash buffer counter, increment the page counter */\r
                                CurrDFPageByteDiv16 = 0;\r
                                CurrDFPage++;\r
 \r
+                               /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */\r
+                               if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))\r
+                                 UsingSecondBuffer = !(UsingSecondBuffer);\r
+\r
                                /* Select the next dataflash chip based on the new dataflash page index */\r
                                Dataflash_SelectChipFromPage(CurrDFPage);\r
-                               Dataflash_WaitWhileBusy();\r
 \r
 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)\r
                                /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */\r
                                if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))\r
                                {\r
                                        /* Copy selected dataflash's current page contents to the dataflash buffer */\r
-                                       Dataflash_ToggleSelectedChipCS();\r
-                                       Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);\r
+                                       Dataflash_WaitWhileBusy();\r
+                                       Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);\r
                                        Dataflash_SendAddressBytes(CurrDFPage, 0);\r
                                        Dataflash_WaitWhileBusy();\r
                                }\r
@@ -351,8 +370,8 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota
        }\r
 \r
        /* Write the dataflash buffer contents back to the dataflash page */\r
-       Dataflash_ToggleSelectedChipCS();\r
-       Dataflash_SendByte(DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
+       Dataflash_WaitWhileBusy();\r
+       Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);\r
        Dataflash_SendAddressBytes(CurrDFPage, 0x00);\r
        Dataflash_WaitWhileBusy();\r
 \r
@@ -365,9 +384,9 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota
  *  and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read\r
  *  the files stored on the dataflash.\r
  *\r
- *  \param BlockAddress  Data block starting address for the read sequence\r
- *  \param TotalBlocks   Number of blocks of data to read\r
- *  \param BufferPtr     Pointer to the data destination RAM buffer\r
+ *  \param[in] BlockAddress  Data block starting address for the read sequence\r
+ *  \param[in] TotalBlocks   Number of blocks of data to read\r
+ *  \param[out] BufferPtr    Pointer to the data destination RAM buffer\r
  */\r
 void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)\r
 {\r
@@ -375,8 +394,10 @@ void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t Total
        uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);\r
        uint8_t  CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);\r
 \r
-       /* Send the dataflash main memory page read command */\r
+       /* Select the correct starting Dataflash IC for the block requested */\r
        Dataflash_SelectChipFromPage(CurrDFPage);\r
+\r
+       /* Send the dataflash main memory page read command */\r
        Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);\r
        Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);\r
        Dataflash_SendByte(0x00);\r
@@ -469,3 +490,36 @@ void DataflashManager_ResetDataflashProtections(void)
        /* Deselect current dataflash chip */\r
        Dataflash_DeselectChip();\r
 }\r
+\r
+/** Performs a simple test on the attached Dataflash IC(s) to ensure that they are working.\r
+ *\r
+ *  \return Boolean true if all media chips are working, false otherwise\r
+ */\r
+bool DataflashManager_CheckDataflashOperation(void)\r
+{\r
+       uint8_t ReturnByte;\r
+\r
+       /* Test first Dataflash IC is present and responding to commands */\r
+       Dataflash_SelectChip(DATAFLASH_CHIP1);\r
+       Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);\r
+       ReturnByte = Dataflash_ReceiveByte();\r
+       Dataflash_DeselectChip();\r
+\r
+       /* If returned data is invalid, fail the command */\r
+       if (ReturnByte != DF_MANUFACTURER_ATMEL)\r
+         return false;\r
+\r
+       #if (DATAFLASH_TOTALCHIPS == 2)\r
+       /* Test second Dataflash IC is present and responding to commands */\r
+       Dataflash_SelectChip(DATAFLASH_CHIP2);\r
+       Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);\r
+       ReturnByte = Dataflash_ReceiveByte();\r
+       Dataflash_DeselectChip();\r
+\r
+       /* If returned data is invalid, fail the command */\r
+       if (ReturnByte != DF_MANUFACTURER_ATMEL)\r
+         return false;\r
+       #endif\r
+       \r
+       return true;\r
+}\r