USBMSD SD card Hello World for Mbed platforms
Dependencies: mbed USBMSD_SD USBDevice
USBDevice/USBMSD/AT45.cpp
- Committer:
- samux
- Date:
- 2011-11-11
- Revision:
- 2:27a7e7f8d399
File content as of revision 2:27a7e7f8d399:
#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 }