Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed USBMSD_SD USBDevice
Diff: USBDevice/USBMSD/AT45.cpp
- Revision:
- 2:27a7e7f8d399
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBMSD/AT45.cpp Fri Nov 11 15:22:53 2011 +0000
@@ -0,0 +1,829 @@
+#include "AT45.h"
+#include "mbed.h"
+
+/* mbed Library - AT45
+ * (c)2007, cstyles
+ */
+
+
+
+/*
+ * Constructor
+ */
+
+AT45::AT45(PinName mosi, PinName miso, PinName clk, PinName ncs)
+ : _spi(mosi, miso, clk), _ncs(ncs) {
+
+ _pages = -1; // number of pages
+ _pagesize = -1; // size of pages 256/264, 512/528, 1024/1056
+ _devicesize = -1; // In bytes
+
+ _buffer1address = -1; // page address in buffer 1
+ _buffer2address = -1; // page address in buffer 2
+ _lru = -1; // leas recently used buffer (for eviction)
+
+ _reset(); // Populate all this stuff
+
+}
+
+
+
+
+
+/*
+ * This is the reset function of the constructor.
+ * Interrogate the part and set up some variables.
+ */
+
+void AT45::_reset() {
+ int _id = 0;
+ int _status = 0;
+
+ _spi.format(8,0);
+ _spi.frequency(5000000);
+
+ _id = id();
+ _status = status();
+
+ if ( (_id & 0x1f) == 0x2) { // 1Mbit
+ _devicesize = 131072; // size in bytes
+ _pages = 512; // number of pages
+ _blocks = 256; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 256;}
+ else {
+ _pagesize = 264;}
+ }
+
+ else if ( (_id & 0x1f) == 0x3) { // 2M
+ _devicesize = 262144; // Size in bytes
+ _pages = 1024; // Number of pages
+ _blocks = 512; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 256;}
+ else {
+ _pagesize = 264;}
+ }
+
+ else if ( (_id & 0x1f) == 0x4) { // 4M
+ _devicesize = 524288;
+ _pages = 2048;
+ _blocks = 1024; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 256;}
+ else {
+ _pagesize = 264;}
+ }
+
+ else if ( (_id & 0x1f) == 0x5) { // 8M
+ _devicesize = 1048576;
+ _pages = 4096;
+ _blocks = 2048; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 256;}
+ else {
+ _pagesize = 264;}
+ }
+
+ else if ( (_id & 0x1f) == 0x6) { // 16M
+ _devicesize = 2097152;
+ _pages = 4096;
+ _blocks = 4096; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 512;}
+ else {
+ _pagesize = 528;}
+ }
+
+ else if ( (_id & 0x1f) == 0x7) { // 32M
+ _devicesize = 4194304;
+ _pages = 8192;
+ _blocks = 8192; // Number of 512 byte blocks
+ if (_status & 0x1) {
+ _pagesize = 512;}
+ else {
+ _pagesize = 528;}
+ }
+
+ else if ( (_id & 0x1f) == 0x8) { // 64M
+ _devicesize = 8388608;
+ _pages = 8192;
+ _blocks = 16384;
+ if (_status & 0x1) {
+ _pagesize = 1024;}
+ else {
+ _pagesize = 1056;}
+ }
+
+ else {
+ _devicesize = -1;
+ _pages = -1;
+ _pagesize = -1;
+ }
+}
+
+
+
+
+
+/*
+ * Select pulls nCS low, but also ensure SPI channel is formatted
+ * This is so that another device sharing the same SPI pins
+ * doenst leave it in an unknown state
+ */
+
+void AT45::_select() {
+ // ensure that the SPI port is set up correctly still
+ // This allows SPI channel sharing
+ _spi.format(8,0);
+ _spi.frequency(5000000);
+ _ncs = 0;
+}
+
+
+
+
+
+/*
+ * Deselect simply returns nCS to high
+ */
+void AT45::_deselect() {
+ _ncs = 1;
+}
+
+
+
+
+
+/*
+ * 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 = 0xdeadbeef;}
+
+ 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 = 0xcafebabe;}
+
+ return (baddr);
+}
+
+
+
+
+
+/*
+ * 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) << 8 );
+ status |= _spi.write(0x00);
+ _deselect();
+ return status;
+}
+
+
+
+
+
+/*
+ * Erase the entire chip
+ */
+
+void AT45::erase() {
+
+ _pollbusy(); // make sure flash isnt already in busy.
+
+ // There are errata on this. For now, do itthe long way :-(
+ _select();
+ // 4 byte command sequence
+ _spi.write(0xc7);
+ _spi.write(0x94);
+ _spi.write(0x80);
+ _spi.write(0x9a);
+ _deselect();
+
+ _pollbusy(); // Make erase a blocking function
+
+}
+
+
+
+
+
+/*
+ * return the size of the part in bytes
+ */
+
+int AT45::size() {
+ return _devicesize;
+}
+
+
+
+
+
+/*
+ * return the page size of the part in bytes
+ */
+
+int AT45::pagesize() {
+ return _pagesize;
+}
+
+
+
+
+
+/*
+ * return the numbers of pages
+ */
+
+int AT45::pages() {
+ return _pages;
+}
+
+
+
+
+
+/*
+ * Make sure the Flash isnt already doing something
+ */
+void AT45::_pollbusy() {
+ volatile int busy = 1;
+ while (busy) {
+ // if bit 7 is set, we can proceed
+ if ( status() & 0x80 ) {
+ busy = 0;}
+ }
+}
+
+
+
+
+
+/*
+ * Make sure the Flash isnt already doing something
+ */
+
+void AT45::pollbusy() {
+ _pollbusy();
+}
+
+
+
+
+
+/*
+ * This function returns the char
+ */
+
+char AT45::read(int address) {
+ // return byte from address
+ return (_memread( address ));
+}
+
+
+
+
+
+/*
+ * This function writes the char to the address supplied
+ * Note : We pass the raw address to the underlying functions
+ */
+
+void AT45::write(int address, char data) {
+
+ _pollbusy();
+ _flashread(1,address); // read the Flash page into SRAM buffer
+ _pollbusy(); // wait for the read to complete
+ _sramwrite(1,address,data); // Write new data into SRAM
+ _pollbusy(); // Make sure flash isnt busy
+ _flashwrite(1,address); // Write back to the page address
+}
+
+
+
+
+
+/*
+ * 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;
+
+ baddr = _getbaddr(address);
+
+ _select();
+
+ if(buffer == 1)
+ {cmd = 0xd4;}
+ else
+ {cmd = 0xd6;}
+
+ _spi.write(cmd);
+ _sendaddr (baddr);
+ _spi.write (0x0); // dont care byte
+ cmd = _spi.write (0x0);
+
+ _deselect();
+
+ return (cmd);
+}
+
+
+
+
+
+
+/*
+ * 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);
+
+ _pollbusy();
+
+ _select();
+
+ if (buffer == 1)
+ {cmd = 0x84;}
+ else
+ {cmd = 0x87;}
+
+ _spi.write(cmd);
+ _sendaddr (baddr);
+ _spi.write (data);
+
+ _deselect();
+}
+
+
+
+
+
+/*
+ * Read from Flash memory into SRAM buffer
+ */
+
+void AT45::_flashread (int buffer, int address) {
+
+ int cmd = 0;
+ int paddr = _getpaddr(address); // calculate page address
+
+ _pollbusy(); // Check flash is not busy
+ _select();
+
+ if (buffer == 1)
+ {cmd = 0x53;}
+ else
+ {cmd = 0x55;}
+
+ _spi.write (cmd);
+ _sendaddr (paddr);
+ _deselect();
+
+}
+
+
+
+
+
+/*
+ * Write and SRAM buffer back to main memory
+ */
+
+void AT45::_flashwrite (int buffer, int address) {
+
+ int cmd = 0;
+ int paddr = _getpaddr(address);
+
+ _pollbusy(); // Check flash is not busy
+
+ _select();
+
+ if (buffer == 1)
+ {cmd = 0x83;}
+ else
+ {cmd = 0x86;}
+
+ _spi.write (cmd);
+ _sendaddr (paddr);
+ _deselect();
+
+ _pollbusy(); // Check flash is not busy
+
+}
+
+
+
+
+
+/*
+ * Read directly from main memory
+ */
+
+int AT45::_memread (int address) {
+
+ int data = 0;
+ int addr;
+
+ addr = _getpaddr(address) | _getbaddr(address);
+
+ _pollbusy();
+
+ _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();
+
+ _pollbusy();
+
+ return data;
+}
+
+
+
+
+
+/*
+ * 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);
+}
+
+
+
+
+
+/*
+ * Return the number of 512 byte blocks in this device
+ */
+
+int AT45::blocks(void) {
+ return _blocks;
+}
+
+
+
+
+
+/*
+ * Read the numbered block into the data array supplied
+ */
+
+int AT45::blockread (char* data, int block) {
+
+ // For 256 byte pages, we read two pages
+ if((_pagesize == 256) || (_pagesize == 264)) {
+
+ int address = block * 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
+ _pollbusy(); // Wait until First page has loaded into buffer 1
+
+ // I'll do this 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
+ _pollbusy(); // 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
+ // I'll do this 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 = block * 512; // This is the start address of the 512 byte block
+
+ _pollbusy(); // Wait until First page has loaded into buffer 1
+ _flashread(1,address); // read the first page of the block into SRAM buffer 1
+ _pollbusy(); // 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
+ // I'll do this 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(block * 512); // This is the start address of the 512 byte block
+
+ _pollbusy(); // Wait until First page has loaded into buffer 1
+
+ _flashread(1,address); // read the first page of the block into SRAM buffer 1
+
+ _pollbusy(); // 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
+ // I'll do this directly as we are reading back an entire buffer, and this can be done more optimally
+ // than using _sramread
+
+ _select();
+ _spi.write(0xd4);
+
+ if (block %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
+ }
+}
+
+
+
+
+
+/*
+ * Write the buffer to the numbered block
+ */
+
+int AT45::blockwrite(char* data, int block) {
+
+ // 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,(block*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,((block*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();
+
+ _pollbusy(); // make sure the Flahs isnt busy
+
+ // issue command to write buffer 1 to the appropraite flash page
+ _select();
+ _spi.write (0x83);
+ _sendaddr (_getpaddr(block * 512));
+ _deselect();
+ _pollbusy(); // make sure the Flahs isnt busy
+ }
+
+
+ // 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)) {
+
+ _pollbusy(); // make sure the flash isnt busy
+
+ int address = _getpaddr(block*512);
+
+ // Read the page into sram
+ _flashread(1,address);
+
+ // wait for this operation to complete
+ _pollbusy();
+
+ // Overwrite the appropriate half
+ // do this directly, for better performance
+ _select();
+ _spi.write(0x84); // writing to buffer #1
+
+ if(block%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
+ _pollbusy();
+ _flashwrite(1,address);
+
+ }
+
+
+ // Something has gone wrong
+ else {
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Return the number of 512 byte blocks in this device
+ */
+void blockerase (int block) {}
+
+
+
+/*
+ * returns the number of buffer to use
+ * If page is already open, use it
+ * If one of the buffers is unused, use it
+ * else evict the least recently used.
+
+ */
+int _allocatebuffer (int address) {
+
+ int buf = 0;
+ // is page already open in buffer 1?
+ // is page already open in buffer 2
+ // is buffer 1 unusued?
+ // is buffer 2 unused
+ // evict LRU
+
+ return (buf);
+
+}
+
+
+
+/*
+ * write the buffer back to flash
+ * set it as LRU
+ * make _bufferNaddress = -1
+ */
+void _flushbuffer (int buffer) {
+
+ // is page already open in buffer 1?
+ // is page already open in buffer 2
+ // is buffer 1 unusued?
+ // is buffer 2 unused
+ // evict LRU
+
+}
+
+
+
+
+
+
+
\ No newline at end of file