USBMSD device (USB Flashdisk) library using AT45DBxx serial flash storage chip. Works with 2, 4, 8, 16, 32 and 64 Mbit chips within AT45DBxx series.

Dependents:   USBMSD_AT45_HelloWorld

Files at this revision

API Documentation at this revision

Comitter:
llumpu
Date:
Sat Oct 27 14:18:07 2012 +0000
Commit message:
Initial release

Changed in this revision

USBMSD_AT45.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSD_AT45.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_AT45.cpp	Sat Oct 27 14:18:07 2012 +0000
@@ -0,0 +1,659 @@
+/* Copyright (c) <2012> <llumpu>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* 
+ * Inspired by Steen Joergensen (stjo2809) and Chris Styles AT45 libraries
+ */
+
+#include "mbed.h"
+#include "USBMSD_AT45.h"
+
+
+
+#define IS_PAGE_BINARY 0x01
+#define IS_FLASH_READY 0x80
+
+#define TWO_MBIT       0x03
+#define FOUR_MBIT      0x04
+#define EIGHT_MBIT     0x05
+#define SIXTEEN_MBIT   0x06
+#define THIRTYTWO_MBIT 0x07
+#define SIXTYFOUR_MBIT 0x08
+
+DigitalOut  read_act_led(LED1); // LED indicating data are being read from storage chip
+DigitalOut write_act_led(LED2); // LED indicating data are being written to storage chip
+
+//Serial _pc(USBTX, USBRX);
+
+
+/************************************** Constructor **************************************/
+
+
+USBMSD_AT45::USBMSD_AT45(PinName mosi, PinName miso, PinName sclk, PinName ncs, int transport_block_size) :
+    _spi(mosi, miso, sclk), _ncs(ncs), _transport_block_size (transport_block_size)
+{
+  //_pc.baud(921600);
+    _spi.format(8,3);
+    _spi.frequency(24000000);
+
+    write_act_led = 0;
+    read_act_led = 0;
+
+    _init_status = 1; // memory chip is not ready, disk_initialize() will be called in connect()
+
+    connect();
+}
+
+
+/************************************ Public methods ************************************/
+
+
+// This method is called when disk_status returns 0x01 (not initialized)
+
+int USBMSD_AT45::disk_initialize()
+{
+    _initialize();      // Determine storage chip parameters 
+       
+    write_act_led = 1;
+    read_act_led = 1;
+    
+    _init_status = 0;   // Set status to 0x00 (initialized)
+
+    return _init_status;
+}
+
+// Returns size of storage chip in bytes
+
+int USBMSD_AT45::disk_size()
+{
+    return _flash_size;
+}
+
+// Returns count of sectors of storage chip
+
+int USBMSD_AT45::disk_sectors()
+{
+    return (_flash_size / _transport_block_size);
+}
+
+// Returns status of storage chip - 0x00 ready, 0x01 not initialized (disk_initialize is then called)
+
+int USBMSD_AT45::disk_status()
+{
+//_pc.printf("d_status \n\r ");
+    return _init_status;
+}
+
+// Reads block of data from storage chip. Size of block is set in constructor.
+
+int USBMSD_AT45::disk_read(char* data, int block)
+{
+    read_act_led = 0;
+    
+    //_pc.printf("r 0x%2d ", block);
+    //_pc.printf(" \n\r");
+
+    int address = block * _transport_block_size; // Start address of block
+    int count = (_transport_block_size / _flash_buffer_size);
+    int transport_address = 0;
+
+    // If block transported over USB is bigger than size of AT45 SRAM buffer.
+    // We read all parts of block one by one to SRAM 1 and SRAM 2 and then transfer them to host at once. 
+
+    if(_transport_block_size > _flash_buffer_size) { 
+
+        // We load data to first SRAM buffer and then to second SRAM buffer
+        // We do this again if block transported over USB is more than 2 x bigger than SRAM buffer is
+        
+        for(int i=0; i<(count / 2); i++) {
+        
+            
+            _busy();                 // Check if we can proceed
+            _flashread(1, address);  // Read first part of block into SRAM 1 buffer 
+            
+            _busy();           // Check if we can proceed      
+            _ncs = 0;          // Chip select
+            _spi.write(0xd4);  // Read data from SRAM 1 buffer
+            _sendaddr (0x0);   // Start address of block in SRAM buffer : 0 - We read entire buffer 
+            _spi.write (0x0);  // Don't care byte
+
+            for(int i = 0; i < _flash_buffer_size; i++) { 
+                data[transport_address + i] = _spi.write (0x0);
+            }
+            _ncs = 1;            // Chip deselect
+
+            transport_address = (transport_address + _flash_buffer_size);
+            address = (address + _flash_buffer_size);
+
+            _busy();                 // Check if we can proceed
+            _flashread(2,address);   // Read first part of block into SRAM 2 buffer 
+            
+            _busy();            // Check if we can proceed
+            _ncs = 0;           // Chip select
+            _spi.write(0xd6);   // Read data from SRAM 2 buffer
+            _sendaddr (0x0);    // Start address of block in SRAM buffer : 0 - We read entire buffer 
+            _spi.write (0x0);   // Don't care byte
+
+            for(int i = 0; i < _flash_buffer_size; i++) {
+                data[transport_address + i] = _spi.write (0x0);
+            }
+            _ncs = 1;            // Chip deselect
+
+            transport_address = (transport_address + _flash_buffer_size);
+            address = (address + _flash_buffer_size);
+        } 
+
+    }
+
+
+    // If block transported over USB equals size of AT45 SRAM buffer.
+    // We read whole block into SRAM 1 buffer and then transport it to host. 
+    
+    else if(_transport_block_size == _flash_buffer_size) {
+
+        _busy();                 // Check if we can proceed
+        _flashread(1, address);  // Read whole block into SRAM 1 buffer 
+        
+        _busy();            // Check if we can proceed 
+        _ncs = 0;           // Chip select
+        _spi.write(0xd4);   // Read data from SRAM 1 buffer
+        _sendaddr (0x0);    // Start address of block in SRAM buffer : 0 - We read entire buffer 
+        _spi.write (0x0);   // Don't care byte
+
+        for(int i = 0; i < _flash_buffer_size; i++) {
+            data[transport_address + i] = _spi.write (0x0);
+        }
+        _ncs = 1;            // Chip deselect
+
+
+    }
+
+    // If block transported over USB is smaller than size of AT45 SRAM buffer.
+    // We read whole page into SRAM 1 and then transfer only desired part of SRAM buffer. 
+
+    else if(_transport_block_size < _flash_buffer_size) {
+
+        _busy();                 // Check if we can proceed
+        _flashread(1, address);  // Read whole memory page into SRAM 1 buffer 
+        
+        _busy();            // Check if we can proceed
+        _ncs = 0;           // Chip select
+        _spi.write(0xd4);   // Read data from SRAM 1 buffer
+        _sendaddr (0x0);    // Start address of block in SRAM buffer : 0 - We read entire buffer 
+        _spi.write (0x0);   // dont care byte
+
+        for(int i = 0; i < _transport_block_size; i++) {
+            data[transport_address + i] = _spi.write (0x0);
+        }
+        _ncs = 1;            // Chip deselect
+
+
+    } 
+
+    read_act_led = 1;
+    return (0);
+
+}
+
+
+// Writes block of data to storage chip. Size of block is set in constructor
+
+int USBMSD_AT45::disk_write(const char* data, int block)
+{
+    write_act_led = 0;
+    
+    //_pc.printf("w 0x%2d ", block);
+    //_pc.printf(" \n\r");
+
+    int address = block * _transport_block_size; // This is the start address of the block
+    int count = (_transport_block_size / _flash_buffer_size);
+    int transport_address = 0;
+
+    // If block transported over USB is bigger than size of AT45 SRAM buffer.
+    // We write all parts of block one by one to SRAM 1 and SRAM 2 and then we write them to flash. 
+
+    if(_transport_block_size >_flash_buffer_size) {
+
+        // But if memory page size (and SRAM buffer size) is not binary
+        // Before each write, we must read desired block from flash to SRAM buffer first
+        // then write data from host to same SRAM buffer. After this we store whole
+        // SRAM buffer back to flash. This slows down writing speed but must be done because 
+        // SRAM buffer size is bigger than (part of) data we want to write and it would corrupt
+        // previously stored data if not done.
+
+        if(_page_size > _flash_buffer_size) {
+
+            for(int i=0; i<(count / 2); i++) {
+
+                _busy();                 // Check if we can proceed
+                _flashread(1, address);  // Read first part of block into SRAM 1 buffer
+                
+                _busy();           // Check if we can proceed
+                _ncs = 0;          // Chip select
+                _spi.write(0x84);  // Write data to SRAM 1 buffer
+                _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+                for(int i = 0; i < _flash_buffer_size; i++) {
+                    _spi.write (data[transport_address + i]);
+                }
+                _ncs = 1;          // Chip deselect
+
+                _flashwrite(1, address); // Write first part of block from SRAM 1 buffer to flash
+
+                transport_address = (transport_address + _flash_buffer_size);
+                address = (address + _flash_buffer_size);
+
+
+                _busy();                 // Check if we can proceed
+                _flashread(2, address);  // Read next part of block into SRAM 2 buffer
+                
+                _busy();           // Check if we can proceed
+                _ncs = 0;          // Chip select
+                _spi.write(0x87);  // Write data to SRAM 2 buffer
+                _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+                for(int i = 0; i < _flash_buffer_size; i++) {
+                    _spi.write (data[transport_address + i]);
+                }
+                _ncs = 1;          // Chip deselect
+
+                _flashwrite(2, address); // Write next part of block from SRAM 2 buffer to flash
+
+                transport_address = (transport_address + _flash_buffer_size);
+                address = (address + _flash_buffer_size);
+
+            }
+
+
+        }
+
+
+        // Else if memory page size (and SRAM buffer size) is binary
+        // We write all parts of block one by one to SRAM 1 and SRAM 2 and then store them to flash
+
+        else {
+        
+            for(int i=0; i<(count / 2); i++) {
+
+                _ncs = 0;          // Chip select
+                _spi.write(0x84);  // Write data to SRAM 1 buffer
+                _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+                for(int i = 0; i < _flash_buffer_size; i++) {
+                    _spi.write (data[transport_address + i]);
+                }
+                _ncs = 1;          // Chip deselect
+
+                _flashwrite(1, address); // Write first part of block from SRAM 1 buffer to flash
+
+                transport_address = (transport_address + _flash_buffer_size);
+                address = (address + _flash_buffer_size);
+
+                _ncs = 0;          // Chip select
+                _spi.write(0x87);  // Write data to SRAM 2 buffer
+                _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+                for(int i = 0; i < _flash_buffer_size; i++) {
+                    _spi.write (data[transport_address + i]);
+                }
+                _ncs = 1;          // Chip deselect
+
+                _flashwrite(2, address); // Write next part of block from SRAM 2 buffer to flash
+
+                transport_address = (transport_address + _flash_buffer_size);
+                address = (address + _flash_buffer_size);
+
+            }
+        }
+
+    }
+
+    // If block transported over USB equals size of AT45 SRAM buffer.
+    // We write whole block into SRAM 1 buffer and then we write SRAM 1 buffer to flash.
+
+    else if(_transport_block_size == _flash_buffer_size) {
+    
+        // But if memory page size (and SRAM buffer size) is not binary
+        // Before each write, we must read desired block from flash to SRAM buffer first
+        // then write data from host to same SRAM buffer. After this we store whole
+        // SRAM buffer back to flash. This slows down writing speed but must be done because 
+        // SRAM buffer size is bigger than (part of) data we want to write and it would corrupt
+        // previously stored data if not done.
+    
+        if(_page_size > _flash_buffer_size) {
+            _busy();                 // Check if we can proceed
+            _flashread(1, address);  // Read block into SRAM 1 buffer
+            
+            _busy();           // Check if we can proceed
+            _ncs = 0;          // Chip select
+            _spi.write(0x84);  // Write data to SRAM 1 buffer
+            _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+            for(int i = 0; i < _flash_buffer_size; i++) {
+                _spi.write (data[transport_address + i]);
+            }
+            _ncs = 1;          // Chip deselect
+
+            _flashwrite(1, address); // Write block from SRAM 1 buffer to flash
+
+
+        }
+        
+        // Else if memory page size (and SRAM buffer size) is binary
+        // We write whole block of data to SRAM 1 buffer and then store it to flash
+        
+        else {
+
+            _ncs = 0;          // Chip select
+            _spi.write(0x84);  // Write data to SRAM 1 buffer
+            _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+            for(int i = 0; i < _flash_buffer_size; i++) {
+                _spi.write (data[transport_address + i]);
+            }
+            _ncs = 1;          // Chip deselect
+
+            _flashwrite(1, address); // Write block from SRAM 1 buffer to flash
+        }
+
+    }
+
+    // If block transported over USB is smaller than size of AT45 SRAM buffer
+    // We always have to read block being written because we store whole SRAM buffer which is bigger 
+    // than block we want write and if not done, data in previously stored blocks will be corrupted.
+    
+    // Before each write, we must read desired block from flash to SRAM buffer first
+    // then write data from host to same SRAM buffer. After this we store whole
+    // SRAM buffer back to flash. This slows down writing speed but must be done because 
+    // SRAM buffer size is bigger than (part of) data we want to write and it would corrupt
+    // previously stored data if not done.
+
+    else if(_transport_block_size < _flash_buffer_size) {
+
+        _busy();                 // Check if we can proceed
+        _flashread(1, address);  // Read block into SRAM 1 buffer
+        
+        _busy();           // Check if we can proceed 
+        _ncs = 0;          // Chip select
+        _spi.write(0x84);  // Write data to SRAM 1 buffer
+        _sendaddr (0);     // Start address of block written to SRAM buffer : 0 - We write buffer from start
+
+        for(int i = 0; i < _transport_block_size; i++) {
+            _spi.write (data[transport_address + i]);
+        }
+        _ncs = 1;          // Chip deselect
+
+        _flashwrite(1, address); // Write block from SRAM 1 buffer to flash
+
+    }// if block smaller ends
+
+
+
+    write_act_led = 1;
+    return (0);
+
+}
+
+
+
+/************************************ Protected methods ************************************/
+
+// Determine storage chip parameters 
+
+void USBMSD_AT45::_initialize()
+{
+    _busy(); // Must be here? - Check status of storage chip
+
+    _ncs = 0;          // Chip select
+
+    _spi.write(0x9f); // Read Manufacturer ID & Device ID
+
+    int ManufacturerID = (_spi.write(0x00));
+    int DeviceID_0 = (_spi.write(0x00));
+    int DeviceID_1 = (_spi.write(0x00));
+    int ExtendedID_length = (_spi.write(0x00));
+
+    _ncs = 1;          // Chip deselect
+
+
+    int DensityCode = (DeviceID_0 & 0x1f); // Determine density of storage chip in Mbits
+
+
+    _ncs = 0;          // Chip select
+
+    _spi.write(0xd7);  // Read status of storage chip and determine if memory page size is binary 
+
+    int PageIsBinary = ((_spi.write(0x00)) & IS_PAGE_BINARY); // Check if bit 0 is set to 1
+
+    _ncs = 1;            // Chip deselect
+
+          //_pc.printf("M %x \n\r", ManufacturerID);
+          //_pc.printf("D0 %x \n\r", DeviceID_0);
+          //_pc.printf("D1 %x \n\r", DeviceID_1);
+          //_pc.printf("E %x \n\r", ExtendedID_length);
+          
+
+    if (DensityCode == TWO_MBIT) { // 2Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 262144;
+            _flash_buffer_size = 256;
+            _page_size = 256;
+
+        } else {
+
+            _flash_size = 270336;
+            _flash_buffer_size = 256;
+            _page_size = 264;
+
+        }
+    } else if (DensityCode == FOUR_MBIT) { // 4Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 524288;
+            _flash_buffer_size = 256;
+            _page_size = 256;
+
+        } else {
+
+            _flash_size = 540672;
+            _flash_buffer_size = 256;
+            _page_size = 264;
+
+        }
+    } else if (DensityCode == EIGHT_MBIT) { // 8Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 1048576;
+            _flash_buffer_size = 256;
+            _page_size = 256;
+
+        } else {
+
+            _flash_size = 1081344;
+            _flash_buffer_size = 256;
+            _page_size = 264;
+
+        }
+    } else if (DensityCode == SIXTEEN_MBIT) { // 16Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 2097152;
+            _flash_buffer_size = 512;
+            _page_size = 512;
+
+        } else {
+
+            _flash_size = 2162688;
+            _flash_buffer_size = 512;
+            _page_size = 528;
+
+        }
+    } else if (DensityCode == THIRTYTWO_MBIT) { // 32Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 4194304;
+            _flash_buffer_size = 512;
+            _page_size = 512;
+
+        } else {
+
+            _flash_size = 4325376;
+            _flash_buffer_size = 512;
+            _page_size = 528;
+
+        }
+    } else if (DensityCode == SIXTYFOUR_MBIT) { // 64Mbits
+
+        if (PageIsBinary) {
+
+            _flash_size = 8388608;
+            _flash_buffer_size = 1024;
+            _page_size = 1024;
+
+        } else {
+
+            _flash_size = 8650752;
+            _flash_buffer_size = 1024;
+            _page_size = 1056;
+
+        }
+    } else {
+
+        _flash_size = -1;
+        _flash_buffer_size = -1;
+        _page_size = -1;
+
+    }
+}
+
+
+
+void USBMSD_AT45::_busy()
+{
+    //_pc.printf("BUSY? \n\r");
+  
+    volatile int IsBusy = 1;
+    while (IsBusy) {
+        _ncs = 0;          // Chip select
+
+        _spi.write(0xd7);  // Read status register of storage chip
+
+        int IsReady = ((_spi.write(0x00)) & IS_FLASH_READY); // If bit 7 is set we can proceed
+
+        _ncs = 1;          // Chip deselect
+
+        if (IsReady) {
+            IsBusy = 0;
+
+             
+            
+        }
+    }
+}
+
+
+
+// Write and SRAM buffer to main memory
+void USBMSD_AT45::_flashwrite (int buffer, int address)
+{
+
+    int cmd = 0;
+    int paddr = _getpaddr(address); // Calculate address
+
+    _ncs = 0;          // Chip select
+
+    if (buffer == 1) {
+        cmd = 0x83;    // Write SRAM 1 buffer to flash
+    } else {
+        cmd = 0x86;    // Write SRAM 2 buffer to flash
+    }
+
+    _spi.write (cmd);
+    _sendaddr (paddr);
+    _ncs = 1;            // Chip deselect
+
+}
+
+// Read from Flash memory into SRAM buffer
+
+void USBMSD_AT45::_flashread (int buffer, int address)
+{
+
+    int cmd = 0;
+    int paddr = _getpaddr(address); // Calculate address
+   
+    _ncs = 0;          // Chip select
+
+    if (buffer == 1) {
+        cmd = 0x53;    // Read from flash to SRAM 1 buffer
+    } else {
+        cmd = 0x55;    // Read from flash to SRAM 2 buffer
+    }
+
+    _spi.write (cmd);
+    _sendaddr (paddr);
+    _ncs = 1;            // Chip deselect
+    
+}
+
+
+
+// Work out the page address
+// If we have a 2^N page size, it is just the top N bits
+// If we have non-2^N, we use the shifted address
+
+int USBMSD_AT45::_getpaddr(int address)
+{
+
+    int paddr;
+
+    if (_page_size == 256) {
+        paddr = address & 0xffffff00;
+    } else if (_page_size == 264) {
+        paddr = (address << 1) & 0xfffffe00;
+    } else if (_page_size == 512) {
+        paddr = address & 0xfffffe00;
+    } else if (_page_size == 528 ) {
+        paddr = (address << 1) & 0xfffffc00;
+    } else if (_page_size == 1024) {
+        paddr = address & 0xfffffc00;
+    } else if (_page_size == 1056 ) {
+        paddr = (address << 1) & 0xfffff800;
+    } else {
+        paddr = -1;
+    }
+
+    return (paddr);
+}
+
+
+
+// Sends the three least significant bytes of the supplied address
+
+void USBMSD_AT45::_sendaddr (int address)
+{
+    _spi.write(address >> 16);
+    _spi.write(address >> 8);
+    _spi.write(address);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_AT45.h	Sat Oct 27 14:18:07 2012 +0000
@@ -0,0 +1,158 @@
+/* Copyright (c) <2012> <llumpu>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* 
+ * Inspired by Steen Joergensen (stjo2809) and Chris Styles AT45 libraries
+ */
+
+#include "mbed.h"
+#include "USBMSD.h"
+
+#ifndef USBMSD_AT45_H
+#define USBMSD_AT45_H
+
+
+/** USBMSD device (USB flashdisk) with Atmel AT45DBxx serial flash
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "USBMSD_AT45.h"
+ *
+ * USBMSD_AT45 Flash(p5, p6, p7, p8, 512);  // Mosi, Miso, Sclk, CS, Size of block being transported over USB
+ *                                 // each time. Can be 512, 1024, 2048, 4096. Best is to select same
+ *                                 // size as AT45DBxx SRAM buffer size. If page size of flash is not
+ *                                 // binary 2^N (256, 512, 1024 bytes) but is 264, 528 or 1056 bytes
+ *                                 // before each write we read block being written to SRAM then rewrite
+ *                                 // part of them with data from host and write whole SRAM buffer back
+ *                                 // to flash. This avoids to data being rewritten in other blocks
+ *                                 // we actually do not write to.
+ * int main() {
+ *
+ *  while(1) {
+ *
+ *  // Do something else here
+ *
+ *   }
+ *  }
+ * @endcode
+ */
+
+class USBMSD_AT45 : public USBMSD
+{
+public:
+
+    /**
+    * Constructor
+    *
+    * Create an instance of the USBMSD_AT45 connected to specfied SPI pins, with the specified CHIP SELECT pin
+    *
+    * @param mosi The SPI mosi Pin (p5 or p11)
+    * @param miso The SPI miso Pin (p6 or p12)
+    * @param sclk The SPI sclk Pin (p7 or p13)
+    * @param ncs The SPI chip select Pin (any digital out pin)
+    * @param transport_block_size The size of block being transported over USB
+    */
+
+    USBMSD_AT45(PinName mosi, PinName miso, PinName sclk, PinName ncs, int transport_block_size);
+
+    /** disk_read()
+    *
+    * Reads block of data from storage chip. Size of block is set in constructor
+    *
+    * @param data Pointer to buffer where data will be read to
+    * @param block Number of requested block
+    */
+
+    virtual int disk_read(char * data, int block);
+
+    /** disk_write()
+    *
+    * Writes block of data to storage chip. Size of block is set in constructor
+    *
+    * @param data Pointer to buffer from which contains data to be written to storage chip
+    * @param block Number of block to be written to
+    */
+
+    virtual int disk_write(const char * data, int block);
+
+    /** disk_size()
+    *
+    * @param returns Size of storage chip in bytes
+    */
+
+    virtual int disk_size();
+
+    /** disk_sectors()
+    *
+    * @param returns Count of sectors of storage chip
+    */
+
+    virtual int disk_sectors();
+
+    /** disk_status()
+    *
+    * @param returns Status of storage chip - 0x00 ready, 0x01 not initialized (disk_initialize is then called)
+    */
+
+    virtual int disk_status();
+
+    /** disk_initialize()
+    *
+    * This method is called when disk_status returns 0x01 (not initialized)
+    */
+
+    virtual int disk_initialize();
+
+
+protected:
+
+// SPI bus and Chip select
+
+    SPI _spi; // SPI bus
+    DigitalOut _ncs; // Chip Select pin
+
+// Protected variables storing flash chip parameters
+
+    int _flash_size; // Total size of storage chip in bytes
+    int _flash_buffer_size; // !!! Used size of memory page (and SRAM buffer) in bytes
+
+    int _page_size; // !!! Real size of memory page (and SRAM buffer) in bytes
+    int _transport_block_size; // Size of block transported over USB in bytes
+    int _init_status; // Status of storage chip - 0x00 ready, 0x01 not initialized
+
+// Helper routines
+
+    void _initialize(); // Determine parameters of connected storage chip
+    void _busy (void);  // Check if storage chip is not busy
+
+// Transferring SRAM buffers to/from FLASH
+
+    void _flashwrite (int buffer, int paddr);
+    void _flashread (int buffer, int paddr);
+
+// Calculate page/subpage addresses
+
+    int _getpaddr (int address);
+
+// Send 3 byte address
+
+    void _sendaddr (int address);
+
+};
+#endif
\ No newline at end of file