Addd spi flash read/write/erase
authorMichael McMaster <michael@codesrc.com>
Wed, 20 Jan 2021 12:00:16 +0000 (22:00 +1000)
committerMichael McMaster <michael@codesrc.com>
Wed, 20 Jan 2021 12:00:16 +0000 (22:00 +1000)
software/SCSI2SD/src/config.c
software/SCSI2SD/src/flash.c
software/SCSI2SD/src/sd.c
software/SCSI2SD/src/storedevice.h

index 5b4195cf5c7ab65c6e6cc276a50acb5dd715c904..953a3df45fb5d1131bb98078feff0c94c1b08cb5 100755 (executable)
@@ -222,6 +222,73 @@ deviceListCommand()
     hidPacket_send(response, pos);\r
 }\r
 \r
+static void\r
+deviceEraseCommand(const uint8_t* cmd)\r
+{\r
+    int deviceCount;\r
+    S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+    \r
+    uint32_t sectorNum =\r
+        ((uint32_t)cmd[2]) << 24 |\r
+        ((uint32_t)cmd[3]) << 16 |\r
+        ((uint32_t)cmd[4]) << 8 |\r
+        ((uint32_t)cmd[5]);\r
+\r
+    uint32_t count =\r
+        ((uint32_t)cmd[6]) << 24 |\r
+        ((uint32_t)cmd[7]) << 16 |\r
+        ((uint32_t)cmd[8]) << 8 |\r
+        ((uint32_t)cmd[9]);\r
+\r
+    devices[cmd[1]]->erase(devices[cmd[1]], sectorNum, count);\r
+    \r
+       uint8_t response[] =\r
+       {\r
+               CONFIG_STATUS_GOOD\r
+       };\r
+    hidPacket_send(response, sizeof(response));\r
+}\r
+\r
+static void\r
+deviceWriteCommand(const uint8_t* cmd)\r
+{\r
+    int deviceCount;\r
+    S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+    \r
+    uint32_t sectorNum =\r
+        ((uint32_t)cmd[2]) << 24 |\r
+        ((uint32_t)cmd[3]) << 16 |\r
+        ((uint32_t)cmd[4]) << 8 |\r
+        ((uint32_t)cmd[5]);\r
+\r
+    devices[cmd[1]]->write(devices[cmd[1]], sectorNum, 1, &cmd[6]);\r
+    \r
+       uint8_t response[] =\r
+       {\r
+               CONFIG_STATUS_GOOD\r
+       };\r
+    hidPacket_send(response, sizeof(response));\r
+}\r
+\r
+\r
+static void\r
+deviceReadCommand(const uint8_t* cmd)\r
+{\r
+    int deviceCount;\r
+    S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+    \r
+    uint32_t sectorNum =\r
+        ((uint32_t)cmd[2]) << 24 |\r
+        ((uint32_t)cmd[3]) << 16 |\r
+        ((uint32_t)cmd[4]) << 8 |\r
+        ((uint32_t)cmd[5]);\r
+\r
+    uint32_t response[512];\r
+    devices[cmd[1]]->read(devices[cmd[1]], sectorNum, 1, &response[0]);\r
+    \r
+    hidPacket_send(&response[0], 512);\r
+}\r
+\r
 static void\r
 processCommand(const uint8_t* cmd, size_t cmdSize)\r
 {\r
@@ -254,6 +321,18 @@ processCommand(const uint8_t* cmd, size_t cmdSize)
     case S2S_CMD_DEV_LIST:\r
         deviceListCommand();\r
         break;\r
+\r
+    case S2S_CMD_DEV_ERASE:\r
+        deviceEraseCommand(cmd);\r
+        break;\r
+\r
+    case S2S_CMD_DEV_WRITE:\r
+        deviceWriteCommand(cmd);\r
+        break;\r
+\r
+    case S2S_CMD_DEV_READ:\r
+        deviceReadCommand(cmd);\r
+        break;\r
         \r
        case CONFIG_NONE: // invalid\r
        default:\r
index fe493dc63e2c132e6cda9d47d8c5274b9b1eca8a..7bfaae657c384d5c37b388054e44b9a253300b9a 100644 (file)
@@ -1,19 +1,19 @@
-//     Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
+//    Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
 //
-//     This file is part of SCSI2SD.
+//    This file is part of SCSI2SD.
 //
-//     SCSI2SD is free software: you can redistribute it and/or modify
-//     it under the terms of the GNU General Public License as published by
-//     the Free Software Foundation, either version 3 of the License, or
-//     (at your option) any later version.
+//    SCSI2SD is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
 //
-//     SCSI2SD is distributed in the hope that it will be useful,
-//     but WITHOUT ANY WARRANTY; without even the implied warranty of
-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//     GNU General Public License for more details.
+//    SCSI2SD is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
 //
-//     You should have received a copy of the GNU General Public License
-//     along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
+//    You should have received a copy of the GNU General Public License
+//    along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "device.h"
 #include "flash.h"
@@ -24,9 +24,9 @@
 
 typedef struct
 {
-       S2S_Device dev;
+    S2S_Device dev;
 
-       S2S_Target targets[MAX_SCSI_TARGETS];
+    S2S_Target targets[MAX_SCSI_TARGETS];
     
     uint32_t capacity; // in 512 byte blocks
     
@@ -43,18 +43,24 @@ static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count);
 static uint32_t spiFlash_getCapacity(S2S_Device* dev);
 static int spiFlash_pollMediaChange(S2S_Device* dev);
 static void spiFlash_pollMediaBusy(S2S_Device* dev);
+static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);
+static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
+static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
 
 SpiFlash spiFlash = {
-       {
-               spiFlash_earlyInit,
+    {
+        spiFlash_earlyInit,
         spiFlash_init,
-               spiFlash_getTargets,
-               spiFlash_getCapacity,
-               spiFlash_pollMediaChange,
-               spiFlash_pollMediaBusy,
+        spiFlash_getTargets,
+        spiFlash_getCapacity,
+        spiFlash_pollMediaChange,
+        spiFlash_pollMediaBusy,
+        spiFlash_erase,
+        spiFlash_read,
+        spiFlash_write,
         0, // initial mediaState
         CONFIG_STOREDEVICE_FLASH
-       }
+    }
 };
 
 S2S_Device* spiFlashDevice = &(spiFlash.dev);
@@ -62,32 +68,32 @@ S2S_Device* spiFlashDevice = &(spiFlash.dev);
 // Read and write 1 byte.
 static uint8_t spiFlashByte(uint8_t value)
 {
-       NOR_SPI_WriteTxData(value);
-       while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
-       return NOR_SPI_ReadRxData();
+    NOR_SPI_WriteTxData(value);
+    while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+    return NOR_SPI_ReadRxData();
 }
 
 static void spiFlash_earlyInit(S2S_Device* dev)
 {
-       SpiFlash* spiFlash = (SpiFlash*)dev;
+    SpiFlash* spiFlash = (SpiFlash*)dev;
 
-       for (int i = 0; i < MAX_SCSI_TARGETS; ++i)
-       {
-               spiFlash->targets[i].device = dev;
+    for (int i = 0; i < MAX_SCSI_TARGETS; ++i)
+    {
+        spiFlash->targets[i].device = dev;
         
         const S2S_TargetCfg* cfg = getConfigByIndex(i);
         if (cfg->storageDevice == CONFIG_STOREDEVICE_FLASH)
         {
-                   spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg;
+            spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg;
         }
         else
         {
             spiFlash->targets[i].cfg = NULL;
         }
-       }
+    }
 
-       // Don't require the host to send us a START STOP UNIT command
-       spiFlash->dev.mediaState = MEDIA_STARTED;
+    // Don't require the host to send us a START STOP UNIT command
+    spiFlash->dev.mediaState = MEDIA_STARTED;
 }
 
 static void spiFlash_init(S2S_Device* dev)
@@ -95,7 +101,7 @@ static void spiFlash_init(S2S_Device* dev)
     SpiFlash* spiFlash = (SpiFlash*)dev;
     spiFlash->capacity = 0;
 
-    nNOR_WP_Write(0); // Enable Write Protect
+    nNOR_WP_Write(1); // We don't need write Protect
     nNOR_CS_Write(1); // Deselect
     
     NOR_SPI_Start();
@@ -132,20 +138,19 @@ static void spiFlash_init(S2S_Device* dev)
     // Don't bother reading the rest. Deselecting will cancel the command.
     
     nNOR_CS_Write(1); // Deselect
-
 }
 
 static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count)
 {
-       SpiFlash* spiFlash = (SpiFlash*)dev;
-       *count = MAX_SCSI_TARGETS;
-       return spiFlash->targets;
+    SpiFlash* spiFlash = (SpiFlash*)dev;
+    *count = MAX_SCSI_TARGETS;
+    return spiFlash->targets;
 }
 
 static uint32_t spiFlash_getCapacity(S2S_Device* dev)
 {
-       SpiFlash* spiFlash = (SpiFlash*)dev;
-       return spiFlash->capacity;
+    SpiFlash* spiFlash = (SpiFlash*)dev;
+    return spiFlash->capacity;
 }
 
 static int spiFlash_pollMediaChange(S2S_Device* dev)
@@ -156,6 +161,146 @@ static int spiFlash_pollMediaChange(S2S_Device* dev)
 
 static void spiFlash_pollMediaBusy(S2S_Device* dev)
 {
-       // Non-removable
+    // Non-removable
+}
+
+static void spiFlash_WaitForWIP()
+{
+    int inProgress = 1;
+    while (inProgress)
+    {
+        nNOR_CS_Write(0);
+        uint8_t status = spiFlashByte(0x05); // Read Status Register 1;
+        inProgress = status & 1;
+        nNOR_CS_Write(1);
+    }
+}
+
+static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count)
+{
+    SpiFlash* spiFlash = (SpiFlash*)dev;
+
+    nNOR_CS_Write(0); // Select
+
+    // Send the WREN - Write Enable command
+    spiFlashByte(0x06);
+
+    // We NEED to deselect the device now for writes to work
+    nNOR_CS_Write(1);
+    
+    // For now we assume 256kb sectors. This needs to be expanded to cater for 
+    // different sector sizes. We safely assume it will always be >= 512 bytes.
+    const uint32_t flashSectorSize = 256*1024;
+
+    // We don't have enough memory to do a read-modify-write cycle, so the caller
+    // had better line these up on sector boundaries.
+    for (uint32_t linearAddress = sectorNumber * 512;
+        linearAddress < (sectorNumber + count) * 512;
+        linearAddress += flashSectorSize)
+    {
+        nNOR_CS_Write(0);
+
+        spiFlashByte(0xDC);
+
+        // 4-byte address
+        spiFlashByte(linearAddress >> 24);
+        spiFlashByte(linearAddress >> 16);
+        spiFlashByte(linearAddress >> 8);
+        spiFlashByte(linearAddress);
+
+        // Initiate erase
+        nNOR_CS_Write(1)
+
+        spiFlash_WaitForWIP();
+    }
+
+    nNOR_CS_Write(0)
+
+    // Send the WREN - Write Disable command
+    spiFlashByte(0x04);
+    
+    nNOR_CS_Write(1); // Deselect
+}
+
+static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
+{
+    SpiFlash* spiFlash = (SpiFlash*)dev;
+
+    nNOR_CS_Write(0); // Select
+
+    // Send the WREN - Write Enable command
+    spiFlashByte(0x06);
+
+    // We NEED to deselect the device now for writes to work
+    nNOR_CS_Write(1);
+    
+    // We're assuming here that the page size is 512 bytes or more.
+    for (int i = 0; i < count; ++i)
+    {
+        nNOR_CS_Write(0);
+
+        spiFlashByte(0x12);
+
+        uint32_t linearAddress = (sectorNumber + i) * 512;
+        spiFlashByte(linearAddress >> 24);
+        spiFlashByte(linearAddress >> 16);
+        spiFlashByte(linearAddress >> 8);
+        spiFlashByte(linearAddress);
+
+        for (int off = 0; off < 512; ++off)
+        {
+            spiFlashByte(buffer[i * 512 + off]);
+        }
+
+        // Initiate write 
+        nNOR_CS_Write(1)
+
+        spiFlash_WaitForWIP();
+    }
+
+    nNOR_CS_Write(0)
+
+    // Send the WREN - Write Disable command
+    spiFlashByte(0x04);
+    
+    nNOR_CS_Write(1); // Deselect
+}
+
+static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
+{
+    SpiFlash* spiFlash = (SpiFlash*)dev;
+
+    nNOR_CS_Write(0); // Select
+    spiFlashByte(0x13);
+
+    uint32_t linearAddress = sectorNumber * 512;
+    spiFlashByte(linearAddress >> 24);
+    spiFlashByte(linearAddress >> 16);
+    spiFlashByte(linearAddress >> 8);
+    spiFlashByte(linearAddress);
+
+    // There's no harm in reading -extra- data, so keep the FIFO
+    // one step ahead.
+    NOR_SPI_WriteTxData(0xFF);
+    NOR_SPI_WriteTxData(0xFF);
+    NOR_SPI_WriteTxData(0xFF);
+
+    for (int off = 0; off < count * 512; ++off)
+    {
+        NOR_SPI_WriteTxData(0xFF);
+
+        while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+        buffer[off] = NOR_SPI_ReadRxData();
+    }
+
+    // Read and discard the extra bytes of data. It was only used to improve
+    // performance with a full FIFO.
+    for (int i = 0; i < 3; ++i)
+    {
+        while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+        NOR_SPI_ReadRxData();
+    }
+
+    nNOR_CS_Write(1); // Deselect
 }
 
index abeac8e60cbc7cb6121a3945d3734f4e5da2c93b..1eb563e065fa220f58022397d8e670af94280360 100755 (executable)
@@ -34,6 +34,10 @@ static S2S_Target* sd_getTargets(S2S_Device* dev, int* count);
 static uint32_t sd_getCapacity(S2S_Device* dev);\r
 static int sd_pollMediaChange(S2S_Device* dev);\r
 static void sd_pollMediaBusy(S2S_Device* dev);\r
+static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);\r
+static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);\r
+static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);\r
+\r
 \r
 // Global\r
 SdCard sdCard = {\r
@@ -44,6 +48,9 @@ SdCard sdCard = {
                sd_getCapacity,\r
                sd_pollMediaChange,\r
                sd_pollMediaBusy,\r
+        sd_erase,\r
+        sd_read,\r
+        sd_write,\r
         0, // initial mediaState\r
         CONFIG_STOREDEVICE_SD\r
        }\r
@@ -1098,3 +1105,17 @@ static void sd_pollMediaBusy(S2S_Device* dev)
        sdCardDevice->lastPollMediaTime = getTime_ms();\r
 }\r
 \r
+static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count)\r
+{\r
+    // TODO\r
+}\r
+\r
+static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)\r
+{\r
+    // TODO\r
+}\r
+\r
+static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)\r
+{\r
+    // TODO\r
+}\r
index a394ef69234447cf71178368a388104410de8316..4cd77353d6afdbaf918561f9962c6f695dd2b7d8 100644 (file)
@@ -76,6 +76,10 @@ struct S2S_DeviceStruct
        int (*pollMediaChange)(S2S_Device* dev);
        void (*pollMediaBusy)(S2S_Device* dev);
 
+    void (*erase)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);
+    void (*read)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
+    void (*write)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
+
        MEDIA_STATE mediaState;
     CONFIG_STOREDEVICE deviceType;
 };