Interface to the Atmel AT45 series Dataflash with Serial Interface (SPI)
Revision 0:2e9d45485414, committed 2012-01-10
- Comitter:
- stjo2809
- Date:
- Tue Jan 10 09:20:38 2012 +0000
- Commit message:
- First Release
Changed in this revision
AT45.cpp | Show annotated file Show diff for this revision Revisions of this file |
AT45.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 2e9d45485414 AT45.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AT45.cpp Tue Jan 10 09:20:38 2012 +0000 @@ -0,0 +1,986 @@ +/* mbed AT45 Library, for driving the Atmel AT45 series Dataflash with Serial Interface (SPI) + * Copyright (c) 2012, Created by Steen Joergensen (stjo2809) inspired by Chris Styles AT45 library + * + * 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. + */ + +#include "mbed.h" +#include "AT45.h" + +//============================================================================= +// Public functions +//============================================================================= + +AT45::AT45(SPI& spi, PinName ncs) : _spi(spi), _ncs(ncs) +{ + + _pages = -1; // number of pages + _pagesize = -1; // size of pages 256/264, 512/528, 1024/1056 + _devicesize = -1; // In bytes + _deep_down = true; // variable for deep power down function (awake ?) + _deep_down_onoff = false; // variable for deep power down function (On/Off) + + _initialize(); // Populate all this stuff + +} + +// This function returns the char +char AT45::read_byte(int address) +{ + // return byte from address + return (_memread( address )); +} + +int AT45::read_page(char* data, int page) +{ + int address = -1; + + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + else + { + return (-1); // something isnt configured right + } + + _busy(); + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0; i<_pagesize ;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + + return (0); +} +int AT45::read_block(char *data, int block) // under construction F�R CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if (block < _blocks || block == 0) { + page_start = block * 8; + + for (int i=0; i<8; i++) { + read_page(temp_data, page_start); + //printf("%d Read round, Data is: %d\r\n",i,*temp_data); + page_start = page_start + 1; + for (int z=0; z<_pagesize ; z++) { + data[z+(_pagesize*i)] = temp_data[z]; + } + } + } else { + //do nothing + } + //printf("Read done, Data is: %d\r\n",*data); + return (0); +} + +int AT45::read_block(char *data[], int block) // under construction F� CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if(block < _blocks || block == 0) + { + page_start = block * 8; + + for(int i=0; i<8 ;i++) // 8 pages in a block + { + read_page(temp_data, page_start); + page_start = page_start + 1; + for(int z=0; z<_pagesize ;z++) + { + data[i][z] = temp_data[z]; + } + } + } + else + { + //do nothing + } + + return (0); +} + +// This function writes the char to the address supplied +// Note : We pass the raw address to the underlying functions +void AT45::write_byte(int address, char data) +{ + _busy(); + _flashread(1,address); // read the Flash page into SRAM buffer + _busy(); // wait for the read to complete + _sramwrite(1,address,data); // Write new data into SRAM + _busy(); // Make sure flash isnt busy + _flashwrite(1,address); // Write back to the page address +} + +int AT45::write_page(char* data, int page) +{ + int address = -1; + + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + else + { + return (-1); // something isnt configured right + } + + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0; i<_pagesize ;i++) + { + _spi.write (data[i]); + } + _deselect(); + + _busy(); // make sure the Flahs isnt busy + + // issue command to write buffer 1 to the appropraite flash page + _select(); + _spi.write (0x83); + _sendaddr (_getpaddr(address)); + _deselect(); + + return (0); +} +int AT45::write_block(char *data, int block) // under construction F�R CHECK AF MIC OG LERCHE +{ + + int page_start; + char page_arr[_pagesize]; + + if (block < _blocks || block == 0) + { + page_start = block * 8; + + for (int i=0; i<8 ; i++) + { + // Copy data from *data at 0 to 511 _ 512 - 1023, and so on every round. + memcpy(page_arr, &data[_pagesize*i], _pagesize); + + write_page(page_arr, page_start); + page_start = page_start + 1; + } + } else { + //do nothing + } + + return (0); +} +int AT45::write_block(char *data[], int block) // under construction F� CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if(block < _blocks || block == 0) + { + page_start = block * 8; + + for(int i=0; i<8 ;i++) + { + for(int z=0; z<_pagesize ;z++) + { + temp_data[z] = data[i][z]; + } + write_page(temp_data, page_start); + page_start = page_start + 1; + } + } + else + { + //do nothing + } + + return (0); +} + +int AT45::FAT_read(char* data, int page) +{ + // For 256 byte pages, we read two pages + if((_pagesize == 256) || (_pagesize == 264)) + { + int address = page * 512; // This is the start address of the 512 byte block + + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<256;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + + _flashread(1,address+256); // read the second page of the block into SRAM buffer 2 + _busy(); // Wait until second page has loaded into buffer 2 + + // Now the second page is loaded, pull this out into the second half of the data buffer + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<256;i++) + { + data[256+i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + + // For 512 byte pages, we read just the single page, transfer it + else if((_pagesize == 512) || (_pagesize == 528)) + { + int address = page * 512; // This is the start address of the 512 byte block + + _busy(); // Wait until First page has loaded into buffer 1 + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // Now the page has loaded, simply transfer it from the sram buffer to the data array + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<512;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + + // For 1024 byte pages, we read just a single page, transfer half of it + else if((_pagesize == 1024) || (_pagesize == 1056)) + { + int address = _getpaddr(page * 512); // This is the start address of the 512 byte block + + _busy(); // Wait until First page has loaded into buffer 1 + + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + + _busy(); // Wait until First page has loaded into buffer 1 + + // Now the page has loaded, simply transfer it from the sram buffer to the data array + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + + _select(); + _spi.write(0xd4); + + if (page %2) // odd numbered block, read from adress 0x200 + { + _sendaddr (0x200); + } + else // even numbered block, then we are reading from sram buffer 0x0 + { + _sendaddr (0x0); + } + + _spi.write (0x0); // dont care byte + + for(int i=0;i<512;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + else + { + return (-1); // something isnt configured right + } +} + +int AT45::FAT_write(char* data, int page) +{ + // For 256 byte pages, we overwrite two pages + if((_pagesize == 256) || (_pagesize == 264)) + { + + // fill the first buffer with the first half of the block + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<256;i++) { + _spi.write (data[i]); + } + _deselect(); + + _flashwrite(1,(page*512)); + + // fill the buffer with the second half of the block + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<256;i++) { + _spi.write (data[256+i]); + } + _deselect(); + + _flashwrite(1,((page*512)+256)); + } + + // For 512 byte pages, we overwrite a single page + else if((_pagesize == 512) || (_pagesize == 528)) + { + + // fill the first buffer with the block data + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<512;i++) { + _spi.write (data[i]); + } + _deselect(); + + _busy(); // make sure the Flahs isnt busy + + // issue command to write buffer 1 to the appropraite flash page + _select(); + _spi.write (0x83); + _sendaddr (_getpaddr(page * 512)); + _deselect(); + } + + // For 1024 byte pages, we do a read modify write + // must make sure we overwrite the right half of the page! + else if((_pagesize == 1024) || (_pagesize == 1056)) + { + + _busy(); // make sure the flash isnt busy + + int address = _getpaddr(page*512); + + // Read the page into sram + _flashread(1,address); + + // wait for this operation to complete + _busy(); + + // Overwrite the appropriate half + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + + if(page%2) // this is an odd block number, overwrite second half of buffer + { + _sendaddr (0x200); // we are writing to the entire buffer + } + else // this is an even block, overwrite the first half + { + _sendaddr (0x0); // we are writing to the entire buffer + } + + for(int i=0;i<512;i++) + { + _spi.write (data[i]); + } + _deselect(); + + // Write the page back + _busy(); + _flashwrite(1,address); + } + + // Something has gone wrong + else + { + return (-1); + } + + return (0); +} + +// Erase the entire chip +void AT45::chip_erase() +{ + _busy(); // make sure flash isnt already in busy. + + _select(); + // 4 byte command sequence + _spi.write(0xc7); + _spi.write(0x94); + _spi.write(0x80); + _spi.write(0x9a); + _deselect(); + + _busy(); // Make erase a blocking function +} + +// Erase one block +void AT45::block_erase(int block) +{ + int address = -1; + + // Calculate page addresses + if(block < _blocks || block == 0) + { + if(_pagesize == 256) + { + address = block * 2048; + } + else if(_pagesize == 264) + { + address = block * 4096; + } + else if(_pagesize == 512) + { + address = block * 4096; + } + else if(_pagesize == 528) + { + address = block * 8192; + } + else if(_pagesize == 1024) + { + address = block * 8192; + } + else if(_pagesize == 1056) + { + address = block * 16384; + } + + _busy(); + _select(); + _spi.write(0x50); + _sendaddr (address); + _deselect(); + _busy(); + } + else + { + //do nothing + } +} + +// Erase one page +void AT45::page_erase(int page) +{ + int address = -1; + + // Calculate page addresses + if(page < _pages || page == 0) + { + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + + _busy(); + _select(); + _spi.write(0x81); + _sendaddr (address); + _deselect(); + _busy(); + } + else + { + //do nothing + } +} + +// return the size of the part in bytes +int AT45::device_size() +{ + return _devicesize; +} + +// return the numbers of pages +int AT45::pages() +{ + return _pages; +} + +// return the page size of the part in bytes +int AT45::pagesize() +{ + return _pagesize; +} + +// A one-time programmable configuration +void AT45::set_pageszie_to_binary() +{ + _busy(); // make sure flash isnt already in busy. + + _select(); + // 4 byte command sequence + _spi.write(0x3d); + _spi.write(0x2a); + _spi.write(0x80); + _spi.write(0xa6); + _deselect(); + + _busy(); // Make erase a blocking function +} + +// Return the number of blocks in this device in accordance with the datasheet +int AT45::blocks() +{ + return _blocks; +} + +// Return the Id of the part +int AT45::id() +{ + int id = 0; + _select(); + _spi.write(0x9f); + id = (_spi.write(0x00) << 8); + id |= _spi.write(0x00); + _deselect(); + return id; +} + +// return the Status +int AT45::status() +{ + int status = 0; + _select(); + _spi.write(0xd7); + status = (_spi.write(0x00)); + _deselect(); + return status; +} + +// Make sure the Flash isnt already doing something +void AT45::busy() +{ + _busy(); +} + +void AT45::deep_power_down(bool _deep_down_onoff) +{ + if(_deep_down_onoff == false) // Wake up from deep power down + { + _select(); + _spi.write(0xab); + _deselect(); + _deep_down = true; + // remenber to want 35uS before using the device. + } + else if(_deep_down_onoff == true) // Go to deep power down + { + _busy(); + _select(); + _spi.write(0xb9); + _deselect(); + _deep_down = false; + } + else + { + //do nothing + } +} + +bool AT45::is_it_awake() +{ + return _deep_down; +} + +//============================================================================= +// Private functions +//============================================================================= + +void AT45::_initialize() +{ + int _id = 0; + int _status = 0; + + _id = id(); + _status = status(); + + if ((_id & 0x1f) == 0x3) // 2Mbits + { + _devicesize = 262144; // Size in bytes + _pages = 1024; // Number of pages + _blocks = 128; // Number of blocks + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x4) // 4Mbits + { + _devicesize = 524288; + _pages = 2048; + _blocks = 256; + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x5) // 8Mbits + { + _devicesize = 1048576; + _pages = 4096; + _blocks = 512; + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x6) // 16Mbits + { + _devicesize = 2097152; + _pages = 4096; + _blocks = 512; + if (_status & 0x1) + { + _pagesize = 512; + } + else + { + _pagesize = 528; + } + } + else if ( (_id & 0x1f) == 0x7) // 32Mbits + { + _devicesize = 4194304; + _pages = 8192; + _blocks = 1024; + if (_status & 0x1) + { + _pagesize = 512; + } + else + { + _pagesize = 528; + } + } + else if ( (_id & 0x1f) == 0x8) // 64Mbits + { + _devicesize = 8388608; + _pages = 8192; + _blocks = 1024; + if (_status & 0x1) + { + _pagesize = 1024; + } + else + { + _pagesize = 1056; + } + } + else + { + _devicesize = -1; + _pages = -1; + _pagesize = -1; + _blocks = -1; + } +} + +void AT45::_select() +{ + _ncs = 0; +} + +void AT45::_deselect() +{ + _ncs = 1; +} + +void AT45::_busy() { + volatile int iambusy = 1; + while (iambusy) { + // if bit 7 is set, we can proceed + if ( status() & 0x80 ) { + iambusy = 0;} + } +} + +// Write to an SRAM buffer +// Note : We create buffer and page addresses in _sram and _flash +void AT45::_sramwrite(int buffer, int address, int data) +{ + + int cmd = 0; + int baddr = 0; + + baddr = _getbaddr(address); + + _busy(); + + _select(); + + if (buffer == 1) + {cmd = 0x84;} + else + {cmd = 0x87;} + + _spi.write(cmd); + _sendaddr (baddr); + _spi.write (data); + + _deselect(); +} + +// Read from an SRAM buffer +// Note : We create buffer and page addresses in _sram and _flash +int AT45::_sramread(int buffer, int address) +{ + + int cmd = 0; + int baddr = 0; + int bufdata = 0; + + baddr = _getbaddr(address); + + _select(); + + if(buffer == 1) + {cmd = 0xd4;} + else + {cmd = 0xd6;} + + _spi.write(cmd); + _sendaddr (baddr); + _spi.write (0x0); // dont care byte + bufdata = _spi.write (0x0); + + _deselect(); + + return (bufdata); +} + +// Write and SRAM buffer to main memory +void AT45::_flashwrite (int buffer, int address) +{ + + int cmd = 0; + int paddr = _getpaddr(address); + + _busy(); // Check flash is not busy + + _select(); + + if (buffer == 1) + {cmd = 0x83;} + else + {cmd = 0x86;} + + _spi.write (cmd); + _sendaddr (paddr); + _deselect(); + + _busy(); // Check flash is not busy +} + +// Read from Flash memory into SRAM buffer +void AT45::_flashread (int buffer, int address) +{ + + int cmd = 0; + int paddr = _getpaddr(address); // calculate page address + + _busy(); // Check flash is not busy + _select(); + + if (buffer == 1) + {cmd = 0x53;} + else + {cmd = 0x55;} + + _spi.write (cmd); + _sendaddr (paddr); + _deselect(); +} + +// Read directly from main memory +int AT45::_memread (int address) +{ + + int data = 0; + int addr; + + addr = _getpaddr(address) | _getbaddr(address); + + _busy(); + + _select(); + + _spi.write (0xd2); // Direct read command + _sendaddr (addr); + + // 4 dont care bytes + _spi.write (0x00); + _spi.write (0x00); + _spi.write (0x00); + _spi.write (0x00); + + // this one clocks the data + data = _spi.write (0x00); + _deselect(); + + _busy(); + + return data; +} + +// 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 AT45::_getpaddr(int address) +{ + + int paddr; + + if (_pagesize == 256) { + paddr = address & 0xffffff00;} + else if (_pagesize == 264) { + paddr = (address << 1) & 0xfffffe00;} + else if (_pagesize == 512) { + paddr = address & 0xfffffe00;} + else if (_pagesize == 528 ) { + paddr = (address << 1) & 0xfffffc00;} + else if (_pagesize == 1024) { + paddr = address & 0xfffffc00;} + else if (_pagesize == 1056 ) { + paddr = (address << 1) & 0xfffff800;} + else { + paddr = -1;} + + return (paddr); +} + +// Clean the buffer address. This is the 8/9/10 LSBs +int AT45::_getbaddr(int address) +{ + + int baddr; + + if ((_pagesize == 256) || (_pagesize == 264 )) { + baddr = address & 0xff;} + else if ((_pagesize == 512) || (_pagesize == 528 )) { + baddr = address & 0x1ff;} + else if ((_pagesize == 1024) || (_pagesize == 1056 )) { + baddr = address & 0x3ff;} + else { + baddr = -1;} + + return (baddr); +} + +// Sends the three lest significant bytes of the supplied address +void 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 2e9d45485414 AT45.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AT45.h Tue Jan 10 09:20:38 2012 +0000 @@ -0,0 +1,278 @@ +/* mbed AT45 Library, for driving the Atmel AT45 series Dataflash with Serial Interface (SPI) + * Copyright (c) 2012, Created by Steen Joergensen (stjo2809) inspired by Chris Styles AT45 library + * + * 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. + * + * + * This driver supports 021,041,081,161,321,641 variants of the AT45DBxxx family + * + * || Code || Density || Page size || Pages || Package || + * || 021 || 2 || 256 || 1024 || 8 SOIC || + * || 041 || 4 || 256 || 2048 || 8 SOIC || + * || 081 || 8 || 256 || 4096 || 8 SOIC || + * || 161 || 16 || 512 || 4096 || 8 SOIC || + * || 321 || 32 || 512 || 8192 || 8 SOIC || + * || 641 || 64 || 1024 || 8192 || 28 TSOP || + */ + +#include "mbed.h" + +#ifndef AT45_H +#define AT45_H + +//============================================================================= +// Functions Declaration +//============================================================================= + +/** Interface to the Atmel AT45 series Dataflash with Serial Interface (SPI) + * + * Using the driver: + * - remenber to setup SPI in main routine. + * - remenber to setup Chipselect in main routine. + * - remenber to use FAT functions set pagesize to binary. + * + * Limitations of using this driver: + * - can't use lockdown functions. + * - can't use protections functions. + * - can't use security functions. + * + */ +class AT45 { +public: + /** Create an instance of the AT45 connected to specfied SPI pins, with the specified address. + * + * @param spi The mbed SPI instance (make in main routine) + * @param nCs The SPI chip select pin. + */ + AT45(SPI& spi, PinName ncs); + + /** Read a byte. + * + * @param address The address of the byte to read. + * @return The data in the byte. + */ + char read_byte(int address); + + /** Read a page. + * + * @param data The data is pointer to a userdefined array that the page is read into. + * @param page The page number of the page to read (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int read_page(char* data, int page); + + /** Read a block (from 1 dimension array). + * + * @param data The data is pointer to a userdefined array that holds 4096 bytes of the data that is read into. + * @param block The block number of the block to read (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int read_block(char *data, int block); + + /** Read a block (from 2 dimension array). + * + * Then using 2 dimension array, the array shall have a starting point like "read_block(data[0],0)" + * @param data The data is pointer to a userdefined array that holds 8 x 512 bytes of the data that is read into. + * @param block The block number of the block to read (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int read_block(char *data[], int block); + + /** Write a byte. + * + * @param address The address to where the data is storage in the flash. + * @param data The data to write into the flash. + */ + void write_byte(int address, char data); + + /** Write a page. + * + * @param data The data is pointer to a userdefined array that holds the data to write into. + * @param page The page number of the page to write into (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int write_page(char* data, int page); + + /** Write a block (from 1 dimension array). + * + * @param data The data is pointer to a userdefined array that holds 4096 bytes of the data to write into. + * @param block The block number of the block to write into (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int write_block(char *data, int block); + + /** Write a block (from 2 dimension array). + * + * Then using 2 dimension array, the array shall have a starting point like "write_block(data[0],0)" + * @param data The data is pointer to a userdefined array that holds 8 x 512 bytes of the data to write into (remenber it has to be a 2 dimension array). + * @param block The block number of the block to write into (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int write_block(char *data[], int block); + + /** FAT Read (512 bits). + * + * Remenber to set page size to binary. + * @param data The data is pointer to a userdefined array that the page is read into. + * @param page The page number of the page to read (0 to device page size). + * @return Returns "0". + */ + int FAT_read(char* data, int page); + + /** FAT Write (512bits). + * + * Remenber to set page size to binary. + * @param data The data is pointer to a userdefined array that holds the data to write into. + * @param page The page number of the page to write into (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int FAT_write(char* data, int page); + + /** Function to erase the entire chip. + * + * Issue: + * In a certain percentage of units, the chip erase feature may not function correctly and may adversely affect device operation. + * Therefore, it is recommended that the chip erase commands (opcodes C7H, 94H, 80H, and 9AH) not be used. + * Workaround: + * Use block erase (opcode 50H) as an alternative. The block erase function is not affected by the chip erase issue. + * Resolution: + * The chip erase feature may be fixed with a new revision of the device. Please contact Atmel for the estimated availability of + * devices with the fix. + */ + void chip_erase(void); + + /** Function to erase the selected block. + * + * @param block The selected block to erase. + */ + void block_erase(int block); + + /** Function to erase the selected block. + * + * @param page The number of the page to erase. + */ + void page_erase(int page); + + /** Device size in mbits. + * + * @return device size. + */ + int device_size(void); + + /** Pages in flash. + * + * @return Numbers af pages. + */ + int pages(void); + + /** Page size. + * + * for 2-8 Mbits 256 or 264 + * for 16-32 Mbits 512 or 528 + * for 64 Mbits 1024 or 1056 + * + * @return Page size. + */ + int pagesize(void); + + /** Function to set the page size to binary. + * + * Remenber is a one-time programmable configuration. + * Remenber to total power down after the functions has been run. + */ + void set_pageszie_to_binary(void); + + /** blocks in flash. + * + * @return Numbers af blocks. + */ + int blocks(void); + + /** ID of the device. + * + * @return Manufacturer, Family and Density code. + */ + int id(void); + + /** Status register. + * + * @return The status register. + */ + int status(void); // Status register + + /** busy ?. + * + * Function will want to the device is not busy. + */ + void busy(void); // Wait until Flash is not busy + + /** Deep Power Down. + * + * Remenber that you have to want 35uS after the wake up to use the device. + * @param True = Activate and False = Wake Up. + */ + void deep_power_down(bool onoff); + + /** Is the device deep power down. + * + * @return True = Activate and False = Awake. + */ + bool is_it_awake(void); + +private: + + SPI _spi; + DigitalOut _ncs; + + int _pages; // Integer number of pages + int _pagesize; // page size, in bytes + int _devicesize; // device size in bytes + int _blocks; // Number of blocks + bool _deep_down; // True = the device is deep down + bool _deep_down_onoff; // variable for deep power down function (On/Off) + + // Helper routunes + void _initialize(); + void _select(); + void _deselect(); + void _busy (void); + + // accessing SRAM buffers + void _sramwrite (int buffer, int address, int data); + int _sramread (int buffer, int address); + + // Transferring SRAM buffers to/from FLASH + void _flashwrite (int buffer, int paddr); + void _flashread (int buffer, int paddr); + + // Reading FLASH directly + int _memread (int address); + + // Calculate page/subpage addresses + int _getpaddr (int); + int _getbaddr (int); + + // Send 3 byte address + void _sendaddr (int address); + +}; +#endif + + +