USBMSD SD card Hello World for Mbed platforms

Dependencies:   mbed USBMSD_SD USBDevice

Files at this revision

API Documentation at this revision

Comitter:
samux
Date:
Fri Nov 11 16:12:21 2011 +0000
Parent:
2:27a7e7f8d399
Child:
4:980e6470dcce
Commit message:
good: we can use the sd card as mass storage device

Changed in this revision

SDcard.cpp Show diff for this revision Revisions of this file
SDcard.h Show diff for this revision Revisions of this file
USBDevice/USBMSD/AT45.cpp Show diff for this revision Revisions of this file
USBDevice/USBMSD/AT45.h Show diff for this revision Revisions of this file
USBDevice/USBMSD/USBMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBMSD/USBMSD.h Show annotated file Show diff for this revision Revisions of this file
USB_SDcard.cpp Show annotated file Show diff for this revision Revisions of this file
USB_SDcard.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/SDcard.cpp	Fri Nov 11 15:22:53 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/* mbed Microcontroller Library - SDFileSystem
- * Copyright (c) 2008-2009, sford
- *
- * Introduction
- * ------------
- * SD and MMC cards support a number of interfaces, but common to them all
- * is one based on SPI. This is the one I'm implmenting because it means
- * it is much more portable even though not so performant, and we already 
- * have the mbed SPI Interface!
- *
- * The main reference I'm using is Chapter 7, "SPI Mode" of: 
- *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
- *
- * SPI Startup
- * -----------
- * The SD card powers up in SD mode. The SPI interface mode is selected by
- * asserting CS low and sending the reset command (CMD0). The card will 
- * respond with a (R1) response.
- *
- * CMD8 is optionally sent to determine the voltage range supported, and 
- * indirectly determine whether it is a version 1.x SD/non-SD card or 
- * version 2.x. I'll just ignore this for now.
- *
- * ACMD41 is repeatedly issued to initialise the card, until "in idle"
- * (bit 0) of the R1 response goes to '0', indicating it is initialised.
- *
- * You should also indicate whether the host supports High Capicity cards,
- * and check whether the card is high capacity - i'll also ignore this
- *
- * SPI Protocol
- * ------------
- * The SD SPI protocol is based on transactions made up of 8-bit words, with
- * the host starting every bus transaction by asserting the CS signal low. The
- * card always responds to commands, data blocks and errors.
- * 
- * The protocol supports a CRC, but by default it is off (except for the 
- * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
- * I'll leave the CRC off I think! 
- * 
- * Standard capacity cards have variable data block sizes, whereas High 
- * Capacity cards fix the size of data block to 512 bytes. I'll therefore
- * just always use the Standard Capacity cards with a block size of 512 bytes.
- * This is set with CMD16.
- *
- * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
- * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
- * the card gets a read command, it responds with a response token, and then 
- * a data token or an error.
- * 
- * SPI Command Format
- * ------------------
- * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
- *
- * +---------------+------------+------------+-----------+----------+--------------+
- * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
- * +---------------+------------+------------+-----------+----------+--------------+
- *
- * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
- *
- * All Application Specific commands shall be preceded with APP_CMD (CMD55).
- *
- * SPI Response Format
- * -------------------
- * The main response format (R1) is a status byte (normally zero). Key flags:
- *  idle - 1 if the card is in an idle state/initialising 
- *  cmd  - 1 if an illegal command code was detected
- *
- *    +-------------------------------------------------+
- * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
- *    +-------------------------------------------------+
- *
- * R1b is the same, except it is followed by a busy signal (zeros) until
- * the first non-zero byte when it is ready again.
- *
- * Data Response Token
- * -------------------
- * Every data block written to the card is acknowledged by a byte 
- * response token
- *
- * +----------------------+
- * | xxx | 0 | status | 1 |
- * +----------------------+
- *              010 - OK!
- *              101 - CRC Error
- *              110 - Write Error
- *
- * Single Block Read and Write
- * ---------------------------
- *
- * Block transfers have a byte header, followed by the data, followed
- * by a 16-bit CRC. In our case, the data will always be 512 bytes.
- *  
- * +------+---------+---------+- -  - -+---------+-----------+----------+
- * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
- * +------+---------+---------+- -  - -+---------+-----------+----------+
- */
- 
-#include "SDcard.h"
-
-#define SD_COMMAND_TIMEOUT 5000
-
-SDcard::SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs) :
-  _spi(mosi, miso, sclk), _cs(cs) {
-      _cs = 1; 
-}
-
-int SDcard::disk_write(const char *buffer, int block_number) {
-    // set write address for single block (CMD24)
-    if(_cmd(24, block_number * 512) != 0) {
-        return 1;
-    }
-
-    // send the data block
-    _write(buffer, 512);    
-    return 0;    
-}
-
-int SDcard::disk_read(char *buffer, int block_number) {        
-    // set read address for single block (CMD17)
-    if(_cmd(17, block_number * 512) != 0) {
-        return 1;
-    }
-    
-    // receive the data
-    _read(buffer, 512);
-    return 0;
-}
-
-// PRIVATE FUNCTIONS
-
-int SDcard::_cmd(int cmd, int arg) {
-    _cs = 0; 
-
-    // send a command
-    _spi.write(0x40 | cmd);
-    _spi.write(arg >> 24);
-    _spi.write(arg >> 16);
-    _spi.write(arg >> 8);
-    _spi.write(arg >> 0);
-    _spi.write(0x95);
-
-    // wait for the repsonse (response[7] == 0)
-    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
-        int response = _spi.write(0xFF);
-        if(!(response & 0x80)) {
-            _cs = 1;
-            return response;
-        }
-    }
-    _cs = 1;
-    return -1; // timeout
-}
-
-int SDcard::_read(char *buffer, int length) {
-    _cs = 0;
-
-    // read until start byte (0xFF)
-    while(_spi.write(0xFF) != 0xFE);
-
-    // read data
-    for(int i=0; i<length; i++) {
-        buffer[i] = _spi.write(0xFF);
-    }
-    _spi.write(0xFF); // checksum
-    _spi.write(0xFF);
-
-    _cs = 1;    
-    return 0;
-}
-
-int SDcard::_write(const char *buffer, int length) {
-    _cs = 0;
-    
-    // indicate start of block
-    _spi.write(0xFE);
-    
-    // write the data
-    for(int i=0; i<length; i++) {
-        _spi.write(buffer[i]);
-    }
-    
-    // write the checksum
-    _spi.write(0xFF); 
-    _spi.write(0xFF);
-
-    // check the repsonse token
-    if((_spi.write(0xFF) & 0x1F) != 0x05) {
-        _cs = 1; 
-        return 1;
-    }
-
-    // wait for write to finish
-    while(_spi.write(0xFF) == 0);
-
-    _cs = 1; 
-    return 0;
-}
--- a/SDcard.h	Fri Nov 11 15:22:53 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/* mbed Microcontroller Library - SDFileSystem
- * Copyright (c) 2008-2009, sford
- */
-
-#ifndef SDCARD_H
-#define SDCARD_H
-
-#include "mbed.h"
-
-class SDcard
-{
-public:
-    SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs);
-    virtual int disk_write(const char *buffer, int block_number);
-    virtual int disk_read(char *buffer, int block_number);   
-
-protected:
-
-    int _cmd(int cmd, int arg);
-    int _read(char *buffer, int length);
-    int _write(const char *buffer, int length);
-    
-    SPI _spi;
-    DigitalOut _cs;     
-};
-
-#endif
--- a/USBDevice/USBMSD/AT45.cpp	Fri Nov 11 15:22:53 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,829 +0,0 @@
-#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
--- a/USBDevice/USBMSD/AT45.h	Fri Nov 11 15:22:53 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* mbed Library - AT45
- * Copyright (c) 2008, cstyles
-
-
-Class to make the AT45 SPI flash parts from ATMEL appear as SRAM or 512 byte block devices
-
-This class supports 011,021,041,081,161,321,641 variants of the AT45DBxxx family
-
-|| Code || Density  || Page size || Pages || Package ||
-|| 011  || 1        || 256       || 512   || 8 SOIC  ||
-|| 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 ||
-
-To do :
-
- - Check for current status on Erase Chip command not working.
-
- */
-
-#ifndef MBED_AT45_H
-#define MBED_AT45_H
- 
-#include "mbed.h"
-
-class AT45 {
-    
-    // Public functions
-    public:        
-
-        AT45(PinName mosi = p5, PinName miso = p6, PinName clk = p7, PinName ncs = p8);
-
-        void erase (void);
-
-        // Integer RAM access
-        char read (int address);  // read int from address. Automatically word-aligns address
-        void write (int address, char data); // Write int to address. Automatically world-aligns address
-
-        // Block device access
-        int blocks (void);  // returns the number of 512 byte blocks
-        int blockread (char* data, int block);  // read a block
-        int blockwrite (char* data, int block); // write a block
-        int blockerase (int block); // erase a block
-    
-        // Part interrogation
-        int size (void);      // Device size in bytes
-        int pages (void);      // Device size in bytes
-        int pagesize (void);      // Device size in bytes
- 
-        int id (void);        // ID of part
-        int status (void);    // Status register
-        void pollbusy (void); // Wait until Flash is not busy
-
-    // Private variables
-    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 512 byte blocks
-    
-        // Some flags for buffering
-        int _buffer1address;
-        int _buffer2address;
-        int _lru;
-    
-        // Helper routunes
-        void _reset();
-        void _select();
-        void _deselect();
-        void _pollbusy (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);
-
-        // Allocate buffer
-        int _allocatebuffer(int address);
-        void _flushbuffer(int buffer);
-
-        // 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
--- a/USBDevice/USBMSD/USBMSD.cpp	Fri Nov 11 15:22:53 2011 +0000
+++ b/USBDevice/USBMSD/USBMSD.cpp	Fri Nov 11 16:12:21 2011 +0000
@@ -38,7 +38,7 @@
 #define MAX_PACKET  MAX_PACKET_SIZE_EPBULK
 
 // memory size
-#define MemorySize  0x2000000
+#define MemorySize  0x200000
 
 //number of blocks
 #define BlockCount  (MemorySize / BlockSize)
@@ -51,7 +51,7 @@
 };
 
 
-USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release), mem(p5, p6, p7, p8) {
+USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
 }
 
 // Called in ISR context to process a class specific request
@@ -164,7 +164,7 @@
 
     // if the array is filled, write it in memory
     if (!((addr + size)%BlockSize))
-        mem.disk_write((char *)page, addr/BlockSize);
+        blockWrite(page, addr/BlockSize);
 
     addr += size;
     length -= size;
@@ -187,7 +187,7 @@
 
     // beginning of a new block -> load a whole block in RAM
     if (!(addr%BlockSize))
-        mem.disk_read((char *)page, addr/BlockSize);
+        blockRead(page, addr/BlockSize);
 
     // info are in RAM -> no need to re-read memory
     for (n = 0; n < size; n++) {
@@ -430,7 +430,7 @@
     }
 
     if (!(addr%BlockSize))
-        mem.disk_read((char *)page, addr/BlockSize);
+        blockRead(page, addr/BlockSize);
 
     writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
 
--- a/USBDevice/USBMSD/USBMSD.h	Fri Nov 11 15:22:53 2011 +0000
+++ b/USBDevice/USBMSD/USBMSD.h	Fri Nov 11 16:12:21 2011 +0000
@@ -5,13 +5,14 @@
 /*
 * Guide to adapt this class to your storage chip:
 *
-* - adapt the BlockSize symbol in USBMSD.h
-* - adapt the MemorySize symbol in USBMSD.cpp
-* - declare your own object to store data: here AT45 mem
-* - Be sure to provide :
-*        - mem.blockread(page, block_number);
-*        - mem.blockwrite(page, block_number);
+* - Adapt the BlockSize symbol in USBMSD.h
+* - Adapt the MemorySize symbol in USBMSD.cpp
+* - Declare a class which inherits from USBMSD
+* - Define two virtual functions:
+*        - blockRead(uint8_t * page, uint16_t block_number);
+*        - blockWrite(uint8_t * page, uint16_t block_number);
 *    These functions are used by USBMSD class to read or write data
+* - Instanciate your object
 */
 
 #ifndef USBMSD_H
@@ -23,7 +24,6 @@
 #include "USBDevice_Types.h"
 
 #include "USBDevice.h"
-#include "SDcard.h"
 
 #define DEFAULT_CONFIGURATION (1)
 
@@ -58,21 +58,7 @@
     uint8_t  Status;
 } CSW;
 
-/**
-* USBMSD example
-*
-* @code
-* #include "mbed.h"
-* #include "USBMSD.h"
-*
-* USBMSD msd;
-*
-* int main() {
-*    while(1);
-* }
-*
-* @endcode
-*/
+
 class USBMSD: public USBDevice {
 public:
 
@@ -85,9 +71,26 @@
     */
     USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
     
-
+    /*
+    * read a block on a storage chip
+    *
+    * @param data pointer where will be stored read data
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int blockRead(uint8_t * data, uint16_t block){return 1;};
+    
+    /*
+    * write a block on a storage chip
+    *
+    * @param data data to write
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int blockWrite(uint8_t * data, uint16_t block){return 1;};
+    
+protected:
 
-protected:
 
     /*
     * Get number of logical unit - 1 (here 0)
@@ -159,14 +162,6 @@
     
     // cache in RAM before writing in memory. Useful also to read a block.
     uint8_t page[BlockSize];
-    
-    // memory (Atmel AT45 family)
-    //
-    // You can change this memory to use another one (SDcard, ...)
-    // You need to provide : 
-    //    - mem.blockread(page, block_number);
-    //    - mem.blockwrite(page, block_number);
-    SDcard mem;
 
     void CBWDecode(uint8_t * buf, uint16_t size);
     void sendCSW (void);
@@ -186,4 +181,3 @@
 };
 
 #endif
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB_SDcard.cpp	Fri Nov 11 16:12:21 2011 +0000
@@ -0,0 +1,197 @@
+/* mbed Microcontroller Library - SDFileSystem
+ * Copyright (c) 2008-2009, sford
+ *
+ * Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+#include "USB_SDcard.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+USB_SDcard::USB_SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs) :
+  _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+int USB_SDcard::blockWrite(uint8_t * buffer, uint16_t block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * 512) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int USB_SDcard::blockRead(uint8_t * buffer, uint16_t block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * 512) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+// PRIVATE FUNCTIONS
+
+int USB_SDcard::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            return response;
+        }
+    }
+    _cs = 1;
+    return -1; // timeout
+}
+
+int USB_SDcard::_read(uint8_t * buffer, uint16_t length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    return 0;
+}
+
+int USB_SDcard::_write(uint8_t * buffer, uint16_t length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1; 
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB_SDcard.h	Fri Nov 11 16:12:21 2011 +0000
@@ -0,0 +1,43 @@
+/* mbed Microcontroller Library - SDFileSystem
+ * Copyright (c) 2008-2009, sford
+ */
+
+#ifndef USB_SDCARD_H
+#define USB_SDCARD_H
+
+#include "mbed.h"
+#include "USBMSD.h"
+
+class USB_SDcard: public USBMSD
+{
+public:
+    USB_SDcard(PinName mosi = p5, PinName miso = p6, PinName sclk = p7, PinName cs = p8);
+    
+    /*
+    * read a block on a storage chip
+    *
+    * @param data pointer where will be stored read data
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int blockRead(uint8_t * data, uint16_t block);
+    
+    /*
+    * write a block on a storage chip
+    *
+    * @param data data to write
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int blockWrite(uint8_t * data, uint16_t block);
+
+protected:
+    int _cmd(int cmd, int arg);
+    int _read(uint8_t * buffer, uint16_t length);
+    int _write(uint8_t * buffer, uint16_t length);
+    
+    SPI _spi;
+    DigitalOut _cs;     
+};
+
+#endif
--- a/main.cpp	Fri Nov 11 15:22:53 2011 +0000
+++ b/main.cpp	Fri Nov 11 16:12:21 2011 +0000
@@ -1,7 +1,7 @@
 #include "mbed.h"
-#include "USBMSD.h"
+#include "USB_SDcard.h"
 
-USBMSD msd;
+USB_SDcard sd;
 
 int main() {
     while(1);