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
Revision 0:c0dc2df7c9fe, committed 2012-10-27
- 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 |
diff -r 000000000000 -r c0dc2df7c9fe USBMSD_AT45.cpp --- /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
diff -r 000000000000 -r c0dc2df7c9fe USBMSD_AT45.h --- /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