diff --git a/Makefile b/Makefile
index 4af847029ee7b2667fb9c14747e3825eb1196688..6c8092c395ce60ea16c806f71d2a1011ae067d4a 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
 ## Makefile for Miosix np embedded OS
 ## TFT:Terraneo Federico Technlogies
 ##
+MAKEFILE_VERSION := 1.01
 include miosix/config/Makefile.inc
 
 ##
@@ -33,15 +34,15 @@ INCLUDE_DIRS :=
 OBJ := $(addsuffix .o, $(basename $(SRC)))
 
 ## Includes the miosix base directory for C/C++
-CXXFLAGS  := $(CXXFLAGS_BASE) -I. -I./miosix -I./miosix/$(ARCH_INC) \
-             -I./miosix/$(BOARD_INC) $(INCLUDE_DIRS)
-CFLAGS    := $(CFLAGS_BASE)   -I. -I./miosix -I./miosix/$(ARCH_INC) \
-             -I./miosix/$(BOARD_INC) $(INCLUDE_DIRS)
+CXXFLAGS  := $(CXXFLAGS_BASE) -I. -Imiosix -Imiosix/arch/common \
+             -Imiosix/$(ARCH_INC) -Imiosix/$(BOARD_INC) $(INCLUDE_DIRS)
+CFLAGS    := $(CFLAGS_BASE)   -I. -Imiosix -Imiosix/arch/common \
+             -Imiosix/$(ARCH_INC) -Imiosix/$(BOARD_INC) $(INCLUDE_DIRS)
 AFLAGS    := $(AFLAGS_BASE)
 LFLAGS    := $(LFLAGS_BASE)
 
-LINK_LIBS := $(LIBS) -Wl,--start-group -L./miosix -lmiosix -lstdc++ -lc -lm \
-    -lg -lgcc -Wl,--end-group
+LINK_LIBS := $(LIBS) -L./miosix -Wl,--start-group -lmiosix -lstdc++ -lc -lm \
+    -lgcc -Wl,--end-group
 
 all: all-recursive main
 
@@ -70,8 +71,7 @@ main: main.elf
 
 main.elf: $(OBJ) miosix/libmiosix.a
 	@ echo "linking"
-	$(CXX) $(LFLAGS) -o main.elf $(OBJ) miosix/$(BOOT_FILE) \
-	miosix/kernel/syscalls.o $(LINK_LIBS)
+	$(CXX) $(LFLAGS) -o main.elf $(OBJ) miosix/$(BOOT_FILE) $(LINK_LIBS)
 
 %.o: %.s
 	$(AS) $(AFLAGS) $< -o $@
diff --git a/miosix/Makefile b/miosix/Makefile
index 73a59a75192a793ec4fd161f51cf98cb6a005362..99dcedb8b24303825cef4b723d6dd676bb6c0a3e 100644
--- a/miosix/Makefile
+++ b/miosix/Makefile
@@ -3,6 +3,7 @@
 ## TFT:Terraneo Federico Technlogies
 ## This makefile builds the whole kernel
 ##
+MAKEFILE_VERSION := 1.01
 include config/Makefile.inc
 
 ## List of all Miosix OS source files that have no special requirements
@@ -15,6 +16,7 @@ kernel/error.cpp                                                           \
 kernel/pthread.cpp                                                         \
 kernel/unistd.cpp                                                          \
 kernel/stage_2_boot.cpp                                                    \
+kernel/syscalls.cpp                                                        \
 kernel/scheduler/priority/priority_scheduler.cpp                           \
 kernel/scheduler/control/control_scheduler.cpp                             \
 kernel/scheduler/edf/edf_scheduler.cpp                                     \
@@ -34,18 +36,18 @@ SRC += $(ARCH_SRC)
 OBJ := $(addsuffix .o, $(basename $(SRC)))
 
 ## Includes the miosix base directory for C/C++
-CXXFLAGS := $(CXXFLAGS_BASE) -I. -I./$(ARCH_INC) -I./$(BOARD_INC)
-CFLAGS   :=  $(CFLAGS_BASE)  -I. -I./$(ARCH_INC) -I./$(BOARD_INC)
+CXXFLAGS := $(CXXFLAGS_BASE) -I. -Iarch/common -I$(ARCH_INC) -I$(BOARD_INC)
+CFLAGS   :=  $(CFLAGS_BASE)  -I. -Iarch/common -I$(ARCH_INC) -I$(BOARD_INC)
 AFLAGS   :=  $(AFLAGS_BASE)
 
-## Build libmiosix.a, syscalls.o and stage_1_boot.o (whose path is in BOOT_FILE)
-## The files syscalls.o and stage_1_boot.o are compiled separately because
-## they must not end up in libmiosix.a
-all: $(OBJ) $(BOOT_FILE) kernel/syscalls.o
+## Build libmiosix.a and stage_1_boot.o (whose path is in BOOT_FILE)
+## The file stage_1_boot.o is compiled separately because
+## it must not end up in libmiosix.a
+all: $(OBJ) $(BOOT_FILE)
 	$(AR) rcs libmiosix.a $(OBJ)
 
 clean:
-	rm $(OBJ) $(BOOT_FILE) kernel/syscalls.o libmiosix.a
+	rm $(OBJ) $(BOOT_FILE) libmiosix.a
 
 %.o: %.s
 	$(AS) $(AFLAGS) $< -o $@
diff --git a/miosix/arch/cortexM3_stm32/common/drivers/dcc.cpp b/miosix/arch/common/drivers/dcc.cpp
similarity index 100%
rename from miosix/arch/cortexM3_stm32/common/drivers/dcc.cpp
rename to miosix/arch/common/drivers/dcc.cpp
diff --git a/miosix/arch/cortexM3_stm32/common/drivers/dcc.h b/miosix/arch/common/drivers/dcc.h
similarity index 100%
rename from miosix/arch/cortexM3_stm32/common/drivers/dcc.h
rename to miosix/arch/common/drivers/dcc.h
diff --git a/miosix/arch/cortexM3_stm32/stm32f103ve_mp3v2/interfaces-impl/disk.cpp b/miosix/arch/cortexM3_stm32/common/interfaces-impl/disk.cpp
similarity index 99%
rename from miosix/arch/cortexM3_stm32/stm32f103ve_mp3v2/interfaces-impl/disk.cpp
rename to miosix/arch/cortexM3_stm32/common/interfaces-impl/disk.cpp
index 5bc803ee745c2354913d2155390df9b658edf07a..e8073292bec55d342f3022e49f6befe80c64245f 100644
--- a/miosix/arch/cortexM3_stm32/stm32f103ve_mp3v2/interfaces-impl/disk.cpp
+++ b/miosix/arch/cortexM3_stm32/common/interfaces-impl/disk.cpp
@@ -1,4 +1,3 @@
-
 /***************************************************************************
  *   Copyright (C) 2010 by Terraneo Federico                               *
  *                                                                         *
diff --git a/miosix/arch/cortexM3_stm32/stm32f103ve_strive_mini/interfaces-impl/disk.cpp b/miosix/arch/cortexM3_stm32/stm32f103ve_strive_mini/interfaces-impl/disk.cpp
deleted file mode 100644
index 5bc803ee745c2354913d2155390df9b658edf07a..0000000000000000000000000000000000000000
--- a/miosix/arch/cortexM3_stm32/stm32f103ve_strive_mini/interfaces-impl/disk.cpp
+++ /dev/null
@@ -1,1390 +0,0 @@
-
-/***************************************************************************
- *   Copyright (C) 2010 by Terraneo Federico                               *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/
-
-#include "interfaces/disk.h"
-#include "CMSIS/stm32f10x.h"
-#include "CMSIS/core_cm3.h"
-#include "interfaces/bsp.h"
-#include "interfaces/delays.h"
-#include "kernel/kernel.h"
-#include <cstdio>
-#include <cstring>
-
-//Note: enabling debugging might cause deadlock when using sleep() or reboot()
-//The bug won't be fixed because debugging is only useful for driver development
-///\internal Debug macro, for normal conditions
-//#define DBG iprintf
-#define DBG(x,...) ;
-///\internal Debug macro, for errors only
-//#define DBGERR iprintf
-#define DBGERR(x,...) ;
-
-namespace miosix {
-
-/*
- * Operating voltage of device. It is sent to the SD card to check if it can
- * work at this voltage. Range *must* be within 28..36
- * Example 33=3.3v
- */
-const unsigned char VOLTAGE=33;
-const unsigned int VOLTAGE_MASK=1<<(VOLTAGE-13); //See OCR register in SD spec
-
-/**
- * \internal
- * Possible state of the cardType variable.
- */
-enum CardType
-{
-    Invalid=0, ///<\internal Invalid card type
-    MMC=1<<0,  ///<\internal if(cardType==MMC) card is an MMC
-    SDv1=1<<1, ///<\internal if(cardType==SDv1) card is an SDv1
-    SDv2=1<<2, ///<\internal if(cardType==SDv2) card is an SDv2
-    SDHC=1<<3  ///<\internal if(cardType==SDHC) card is an SDHC
-};
-
-///\internal Type of card. This variable is set in Disk::init()
-static CardType cardType=Invalid;
-
-//SD card GPIOs
-typedef Gpio<GPIOC_BASE,8>  sdD0;
-typedef Gpio<GPIOC_BASE,9>  sdD1;
-typedef Gpio<GPIOC_BASE,10> sdD2;
-typedef Gpio<GPIOC_BASE,11> sdD3;
-typedef Gpio<GPIOC_BASE,12> sdCLK;
-typedef Gpio<GPIOD_BASE,2>  sdCMD;
-
-//
-// Class BufferConverter
-//
-
-/**
- * \internal
- * Convert a single buffer of *fixed* and predetermined size to and from
- * word-aligned. To do so, if the buffer is already word aligned a cast is made,
- * otherwise a new buffer is allocated.
- * Note that this class allocates at most ONE buffer at any given time.
- * Therefore any call to toWordAligned(), toWordAlignedWithoutCopy(),
- * toOriginalBuffer() or deallocateBuffer() invalidates the buffer previousy
- * returned by toWordAligned() and toWordAlignedWithoutCopy()
- */
-class BufferConverter
-{
-public:
-    /**
-     * \internal
-     * The buffer will be of this size only.
-     */
-    static const int BUFFER_SIZE=512;
-
-    /**
-     * \internal
-     * \return true if the pointer is word aligned
-     */
-    static bool isWordAligned(const unsigned char *x)
-    {
-        return (reinterpret_cast<const unsigned int>(x) & 0x3)==0;
-    }
-
-    /**
-     * \internal
-     * Convert from a constunsigned char* buffer of size BUFFER_SIZE to a
-     * const unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it copies the data on the original buffer to a word aligned
-     * buffer. Useful if subseqent code will read from the buffer.
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with the same data of the given buffer
-     */
-    static const unsigned int *toWordAligned(const unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert from an unsigned char* buffer of size BUFFER_SIZE to an
-     * unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it returns a new buffer which *does not* contain the data
-     * on the original buffer. Useful if subseqent code will write to the
-     * buffer. To move the written data to the original buffer, use
-     * toOriginalBuffer()
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with undefined content.
-     */
-    static unsigned int *toWordAlignedWithoutCopy(unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert the buffer got through toWordAlignedWithoutCopy() to the
-     * original buffer. If the original buffer was word aligned, nothing
-     * happens, otherwise a memcpy is done.
-     * Note that this function does not work on buffers got through
-     * toWordAligned().
-     */
-    static void toOriginalBuffer();
-
-    /**
-     * \internal
-     * Can be called to deallocate the buffer
-     */
-    static void deallocateBuffer();
-
-private:
-    static unsigned char *originalBuffer;
-    static unsigned int *wordAlignedBuffer;
-};
-
-const unsigned int *BufferConverter::toWordAligned(const unsigned char *buffer)
-{
-    originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-    if(isWordAligned(buffer))
-    {
-        return reinterpret_cast<const unsigned int*>(buffer);
-    } else {
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        std::memcpy(wordAlignedBuffer,buffer,BUFFER_SIZE);
-        return wordAlignedBuffer;
-    }
-}
-
-unsigned int *BufferConverter::toWordAlignedWithoutCopy(
-    unsigned char *buffer)
-{
-    if(isWordAligned(buffer))
-    {
-        originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-        return reinterpret_cast<unsigned int*>(buffer);
-    } else {
-        originalBuffer=buffer; //Save original pointer for toOriginalBuffer()
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        return wordAlignedBuffer;
-    }
-}
-
-void BufferConverter::toOriginalBuffer()
-{
-    if(originalBuffer==0) return;
-    std::memcpy(originalBuffer,wordAlignedBuffer,BUFFER_SIZE);
-    originalBuffer=0;
-}
-
-void BufferConverter::deallocateBuffer()
-{
-    originalBuffer=0; //Invalidate also original buffer
-    if(wordAlignedBuffer!=0)
-    {
-        delete[] wordAlignedBuffer;
-        wordAlignedBuffer=0;
-    }
-}
-
-unsigned char *BufferConverter::originalBuffer=0;
-unsigned int *BufferConverter::wordAlignedBuffer=0;
-
-//
-// Class CmdResult
-//
-
-/**
- * \internal
- * Contains the result of an SD/MMC command
- */
-class CmdResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending a command
-     */
-    enum Error
-    {
-        Ok=0,        /// No errors
-        Timeout,     /// Timeout while waiting command reply
-        CRCFail,     /// CRC check failed in command reply
-        RespNotMatch,/// Response index does not match command index
-        ACMDFail     /// Sending CMD55 failed
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    CmdResult(): cmd(0), error(Ok), response(0) {}
-
-    /**
-     * \internal
-     * Constructor,  set the response data
-     * \param cmd command index of command that was sent
-     * \param result result of command
-     */
-    CmdResult(unsigned char cmd, Error error): cmd(cmd), error(error),
-            response(SDIO->RESP1) {}
-
-    /**
-     * \internal
-     * \return the 32 bit of the response.
-     * May not be valid if getError()!=Ok or the command does not send a
-     * response, such as CMD0
-     */
-    unsigned int getResponse() { return response; }
-
-    /**
-     * \internal
-     * \return command index
-     */
-    unsigned char getCmdIndex() { return cmd; }
-
-    /**
-     * \internal
-     * \return the error flags of the response
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending the command.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R1 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR1Response();
-
-    /**
-     * \internal
-     * Same as validateR1Response, but can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    bool IRQvalidateR1Response();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R6 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR6Response();
-
-    /**
-     * \internal
-     * \return the card state from an R1 or R6 resonse
-     */
-    unsigned char getState();
-
-private:
-    unsigned char cmd; ///<\internal Command index that was sent
-    Error error; ///<\internal possible error that occurred
-    unsigned int response; ///<\internal 32bit response
-};
-
-bool CmdResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("CMD%d: Timeout\n",cmd);
-            break;
-        case CRCFail:
-            DBGERR("CMD%d: CRC Fail\n",cmd);
-            break;
-        case RespNotMatch:
-            DBGERR("CMD%d: Response does not match\n",cmd);
-            break;
-        case ACMDFail:
-            DBGERR("CMD%d: ACMD Fail\n",cmd);
-            break;
-    }
-    return false;
-}
-
-bool CmdResult::validateR1Response()
-{
-    if(error!=Ok) return validateError();
-    //Note: this number is obtained with all the flags of R1 which are errors
-    //(flagged as E in the SD specification), plus CARD_IS_LOCKED because
-    //locked card are not supported by this software driver
-    if((response & 0xfff98008)==0) return true;
-    DBGERR("CMD%d: R1 response error(s):\n",cmd);
-    if(response & (1<<31)) DBGERR("Out of range\n");
-    if(response & (1<<30)) DBGERR("ADDR error\n");
-    if(response & (1<<29)) DBGERR("BLOCKLEN error\n");
-    if(response & (1<<28)) DBGERR("ERASE SEQ error\n");
-    if(response & (1<<27)) DBGERR("ERASE param\n");
-    if(response & (1<<26)) DBGERR("WP violation\n");
-    if(response & (1<<25)) DBGERR("card locked\n");
-    if(response & (1<<24)) DBGERR("LOCK_UNLOCK failed\n");
-    if(response & (1<<23)) DBGERR("command CRC failed\n");
-    if(response & (1<<22)) DBGERR("illegal command\n");
-    if(response & (1<<21)) DBGERR("ECC fail\n");
-    if(response & (1<<20)) DBGERR("card controller error\n");
-    if(response & (1<<19)) DBGERR("unknown error\n");
-    if(response & (1<<16)) DBGERR("CSD overwrite\n");
-    if(response & (1<<15)) DBGERR("WP ERASE skip\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-bool CmdResult::IRQvalidateR1Response()
-{
-    if(error!=Ok) return false;
-    if(response & 0xfff98008) return false;
-    return true;
-}
-
-bool CmdResult::validateR6Response()
-{
-    if(error!=Ok) return validateError();
-    if((response & 0xe008)==0) return true;
-    DBGERR("CMD%d: R6 response error(s):\n",cmd);
-    if(response & (1<<15)) DBGERR("command CRC failed\n");
-    if(response & (1<<14)) DBGERR("illegal command\n");
-    if(response & (1<<13)) DBGERR("unknown error\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-unsigned char CmdResult::getState()
-{
-    unsigned char result=(response>>9) & 0xf;
-    DBG("CMD%d: State: ",cmd);
-    switch(result)
-    {
-        case 0:  DBG("Idle\n");  break;
-        case 1:  DBG("Ready\n"); break;
-        case 2:  DBG("Ident\n"); break;
-        case 3:  DBG("Stby\n"); break;
-        case 4:  DBG("Tran\n"); break;
-        case 5:  DBG("Data\n"); break;
-        case 6:  DBG("Rcv\n"); break;
-        case 7:  DBG("Prg\n"); break;
-        case 8:  DBG("Dis\n"); break;
-        case 9:  DBG("Btst\n"); break;
-        default: DBG("Unknown\n"); break;
-    }
-    return result;
-}
-
-//
-// Class Command
-//
-
-/**
- * \internal
- * This class allows sending commands to an SD or MMC
- */
-class Command
-{
-public:
-
-    /**
-     * \internal
-     * SD/MMC commands
-     * - bit #7 is @ 1 if a command is an ACMDxx. send() will send the
-     *   sequence CMD55, CMDxx
-     * - bit from #0 to #5 indicate command index (CMD0..CMD63)
-     * - bit #6 is don't care
-     */
-    enum CommandType
-    {
-        CMD0=0,           //GO_IDLE_STATE
-        CMD2=2,           //ALL_SEND_CID
-        CMD3=3,           //SEND_RELATIVE_ADDR
-        ACMD6=0x80 | 6,   //SET_BUS_WIDTH
-        CMD7=7,           //SELECT_DESELECT_CARD
-        ACMD41=0x80 | 41, //SEND_OP_COND (SD)
-        CMD8=8,           //SEND_IF_COND
-        CMD9=9,           //SEND_CSD
-        CMD12=12,         //STOP_TRANSMISSION
-        CMD13=13,         //SEND_STATUS
-        CMD16=16,         //SET_BLOCKLEN
-        CMD17=17,         //READ_SINGLE_BLOCK
-        CMD18=18,         //READ_MULTIPLE_BLOCK
-        ACMD23=0x80 | 23, //SET_WR_BLK_ERASE_COUNT (SD)
-        CMD24=24,         //WRITE_BLOCK
-        CMD25=25,         //WRITE_MULTIPLE_BLOCK
-        CMD55=55          //APP_CMD
-    };
-
-    /**
-     * \internal
-     * Send a command.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult send(CommandType cmd, unsigned int arg)
-    {
-        if(static_cast<unsigned char>(cmd) & 0x80)
-        {
-            DBG("ACMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        } else {
-            DBG("CMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        }
-        return IRQsend(cmd,arg);
-    }
-
-    /**
-     * \internal
-     * Send a command. Can be called with interrupts disabled as it does not
-     * print any debug information.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult IRQsend(CommandType cmd, unsigned int arg);
-
-    /**
-     * \internal
-     * Set the relative card address, obtained during initialization.
-     * \param r the card's rca
-     */
-    static void setRca(unsigned short r) { rca=r; }
-
-    /**
-     * \internal
-     * \return the card's rca, as set by setRca
-     */
-    static unsigned int getRca() { return static_cast<unsigned int>(rca); }
-
-private:
-    static unsigned short rca;///<\internal Card's relative address
-};
-
-CmdResult Command::IRQsend(CommandType cmd, unsigned int arg)
-{
-    unsigned char cc=static_cast<unsigned char>(cmd);
-    //Handle ACMDxx as CMD55, CMDxx
-    if(cc & 0x80)
-    {
-        CmdResult r=IRQsend(CMD55,(static_cast<unsigned int>(rca))<<16);
-        if(r.IRQvalidateR1Response()==false)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-        //Bit 5 @ 1 = next command will be interpreted as ACMD
-        if((r.getResponse() & (1<<5))==0)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-    }
-
-    //Send command
-    cc &= 0x3f;
-    unsigned int command=SDIO_CMD_CPSMEN | static_cast<unsigned int>(cc);
-    if(cc!=CMD0) command |= SDIO_CMD_WAITRESP_0; //CMD0 has no response
-    if(cc==CMD2) command |= SDIO_CMD_WAITRESP_1; //CMD2 has long response
-    if(cc==CMD9) command |= SDIO_CMD_WAITRESP_1; //CMD9 has long response
-    SDIO->ARG=arg;
-    SDIO->CMD=command;
-
-    //CMD0 has no response, so wait until it is sent
-    if(cc==CMD0)
-    {
-        for(int i=0;i<500;i++)
-        {
-            if(SDIO->STA & SDIO_STA_CMDSENT)
-            {
-                SDIO->ICR=0x7ff;//Clear flags
-                return CmdResult(cc,CmdResult::Ok);
-            }
-            delayUs(1);
-        }
-        SDIO->ICR=0x7ff;//Clear flags
-        return CmdResult(cc,CmdResult::Timeout);
-    }
-
-    //Command is not CMD0, so wait a reply
-    for(int i=0;i<500;i++)
-    {
-        unsigned int status=SDIO->STA;
-        if(status & SDIO_STA_CMDREND)
-        {
-            SDIO->ICR=0x7ff;//Clear flags
-            if(SDIO->RESPCMD==cc) return CmdResult(cc,CmdResult::Ok);
-            else return CmdResult(cc,CmdResult::RespNotMatch);
-        }
-        if(status & SDIO_STA_CCRCFAIL)
-        {
-            SDIO->ICR=SDIO_ICR_CCRCFAILC;
-            return CmdResult(cc,CmdResult::CRCFail);
-        }
-        if(status & SDIO_STA_CTIMEOUT) break;
-        delayUs(1);
-    }
-    SDIO->ICR=SDIO_ICR_CTIMEOUTC;
-    return CmdResult(cc,CmdResult::Timeout);
-}
-
-unsigned short Command::rca=0;
-
-//
-// Class DataResult
-//
-
-/**
- * \internal
- * Contains the result of sending/receiving a data block
- */
-class DataResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending or receiving data
-     */
-    enum Error
-    {
-        Ok=0,
-        Timeout,
-        CRCFail,
-        RXOverrun,
-        TXUnderrun,
-        StartBitFail
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    DataResult(): error(Ok) {}
-
-    /**
-     * \internal
-     * Constructor,  set the result.
-     * \param error error type
-     */
-    DataResult(Error error): error(error) {}
-
-    /**
-     * \internal
-     * \return the error flags
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending/receiving data.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-    
-private:
-    Error error;
-};
-
-
-bool DataResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("Data Timeout\n");
-            break;
-        case CRCFail:
-            DBGERR("Data CRC Fail\n");
-            break;
-        case RXOverrun:
-            DBGERR("Data overrun\n");
-            break;
-        case TXUnderrun:
-            DBGERR("Data underrun\n");
-            break;
-        case StartBitFail:
-            DBGERR("Data start bit Fail\n");
-            break;
-    }
-    return false;
-}
-
-//
-// Class ClockController
-//
-
-/**
- * \internal
- * This class controls the clock speed of the SDIO peripheral. The SDIO
- * peripheral, when used in polled mode, requires two timing critical pieces of
- * code: the one to send and the one to receive a data block. This because
- * the peripheral has a 128 byte fifo while the block size is 512 byte, and
- * if fifo underrun/overrun occurs the peripheral does not pause communcation,
- * instead it simply aborts the data transfer. Since the speed of the code to
- * read/write a data block depends on too many factors, such as compiler
- * optimizations, code running from internal flash or external ram, and the
- * cpu clock speed, a dynamic clocking approach was chosen.
- */
-class ClockController
-{
-public:
-
-    /**
-     * \internal. Set a low clock speed of 400KHz or less, used for
-     * detecting SD/MMC cards. This function as a side effect enables 1bit bus
-     * width, and disables clock powersave, since it is not allowed by SD spec.
-     */
-    static void setLowSpeedClock()
-    {
-        clockReductionAvailable=0;
-        // No hardware flow control, SDIO_CK generated on rising edge, 1bit bus
-        // width, no clock bypass, no powersave.
-        // Set low clock speed 400KHz, 72MHz/400KHz-2=178
-        SDIO->CLKCR=CLOCK_400KHz;
-        SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
-    }
-
-    /**
-     * \internal
-     * Automatically select the data speed.
-     * Since the maximum speed depends on many factors, such as code running in
-     * internal or external RAM, compiler optimizations etc. this routine
-     * selects the highest sustainable data transfer speed.
-     * This is done by binary search until the highest clock speed that causes
-     * no errors is found.
-     * This function as a side effect enables 4bit bus width, and clock
-     * powersave.
-     */
-    static void calibrateClockSpeed();
-
-    /**
-     * \internal
-     * Since clock speed is set dynamically by bynary search at runtime, a
-     * corner case might be that of a clock speed which results in unreliable
-     * data transfer, that sometimes succeeds, and sometimes fail.
-     * For maximum robustness, this function is provided to reduce the clock
-     * speed slightly in case a data transfer should fail after clock
-     * calibration. To avoid inadvertently considering other kind of issues as
-     * clock issues, this function can be called only MAX_ALLOWED_REDUCTIONS
-     * times after clock calibration, subsequent calls will fail. This will
-     * avoid other issues causing an ever decreasing clock speed.
-     * Can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    static bool IRQreduceClockSpeed();
-
-    /**
-     * \internal
-     * Read and write operation do retry during normal use for robustness, but
-     * during clock claibration they must not retry for speed reasons. This
-     * member function returns 1 during clock claibration and MAX_RETRY during
-     * normal use.
-     */
-    static unsigned char getRetryCount() { return retries; }
-
-private:
-    
-    /**
-     * \internal
-     * Value of SDIO->CLKCR that will give a 400KHz clock, depending on cpu
-     * clock speed.
-     */
-    #ifdef SYSCLK_FREQ_72MHz
-    static const unsigned int CLOCK_400KHz=178;
-    #elif SYSCLK_FREQ_56MHz
-    static const unsigned int CLOCK_400KHz=138;
-    #elif SYSCLK_FREQ_48MHz
-    static const unsigned int CLOCK_400KHz=118;
-    #elif SYSCLK_FREQ_36MHz
-    static const unsigned int CLOCK_400KHz=88;
-    #elif SYSCLK_FREQ_24MHz
-    static const unsigned int CLOCK_400KHz=58;
-    #else
-    static const unsigned int CLOCK_400KHz=18;
-    #endif
-
-    ///\internal Clock enabled, bus width 4bit, clock powersave enabled.
-    static const unsigned int CLKCR_FLAGS=SDIO_CLKCR_CLKEN |
-        SDIO_CLKCR_WIDBUS_0 | SDIO_CLKCR_PWRSAV;
-
-    ///\internal Maximum number of calls to IRQreduceClockSpeed() allowed
-    static const unsigned char MAX_ALLOWED_REDUCTIONS=5;
-
-    ///\internl value returned by getRetryCount() while *not* calibrating clock.
-    static const unsigned char MAX_RETRY=3;
-
-    ///\internal Used to allow only one call to reduceClockSpeed()
-    static unsigned char clockReductionAvailable;
-
-    static unsigned char retries;
-};
-
-void ClockController::calibrateClockSpeed()
-{
-    //During calibration we call Disk::read which will call reduceClockSpeed()
-    //so not to invalidate calibration clock reduction must not be available
-    clockReductionAvailable=0;
-    retries=1;
-
-    DBG("Automatic speed calibration\n");
-    unsigned int buffer[512/sizeof(unsigned int)];
-    unsigned int minFreq=CLOCK_400KHz; //400KHz, independent of CPU clock
-    unsigned int maxFreq=1;            //24MHz  with CPU running @ 72MHz
-    unsigned int selected;
-    while(minFreq-maxFreq>1)
-    {
-        selected=(minFreq+maxFreq)/2;
-        DBG("Trying CLKCR=%d\n",selected);
-        SDIO->CLKCR=selected;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-            minFreq=selected;
-        else maxFreq=selected;
-    }
-    //Last round of algorithm
-    SDIO->CLKCR=maxFreq;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-    {
-        DBG("Optimal CLKCR=%d\n",maxFreq);
-    } else {
-        SDIO->CLKCR=minFreq;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        DBG("Optimal CLKCR=%d\n",minFreq);
-    }
-
-    //Make clock reduction available
-    clockReductionAvailable=MAX_ALLOWED_REDUCTIONS;
-    retries=MAX_RETRY;
-}
-
-bool ClockController::IRQreduceClockSpeed()
-{
-    //Ensure this function can be called only twice per calibration
-    if(clockReductionAvailable==0) return false;
-    clockReductionAvailable--;
-
-    unsigned int currentClkcr=SDIO->CLKCR & 0xff;
-    if(currentClkcr==CLOCK_400KHz) return false; //No lower than this value
-
-    //If the value of clockcr is low, increasing it by one is enough since
-    //frequency changes a lot, otherwise increase by 2.
-    if(currentClkcr<10) currentClkcr++;
-    else currentClkcr+=2;
-
-    SDIO->CLKCR=currentClkcr;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    return true;
-}
-
-unsigned char ClockController::clockReductionAvailable=false;
-unsigned char ClockController::retries=ClockController::MAX_RETRY;
-
-//
-// Data send/receive functions
-//
-
-/**
- * \internal
- * Receive a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes)
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQreceiveDataBlock(unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQsendDataBlock(), otherwise IRQsendDataBlock()
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_RXOVERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_RXFIFOHF) && (buffer!=bufend))
-        {
-            //Read 8 words from the fifo, loop entirely unrolled for speed
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_RXOVERR) return DataResult(DataResult::RXOverrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    //Read eventual data left in the FIFO
-    for(;;)
-    {
-        if((SDIO->STA & SDIO_STA_RXDAVL)==0) break;
-        *buffer=SDIO->FIFO; buffer++;
-    }
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Send a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes).
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQsendDataBlock(const unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQreceiveDataBlock(), otherwise this function
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_TXUNDERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_TXFIFOHE) && (buffer!=bufend))
-        {
-            //Write 8 words to the fifo, loop entirely unrolled for speed
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_TXUNDERR) return DataResult(DataResult::TXUnderrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Wait until the card is ready for data transfer.
- * Can be called independently of the card being selected.
- * \return true on success, false on failure
- */
-bool waitForCardReady()
-{
-    for(int i=0;i<300;i++) //Timeout 1.5 second
-    {
-        CmdResult cr=Command::send(Command::CMD13,Command::getRca()<<16);
-        if(cr.validateR1Response()==false) return false;
-        //Bit 8 in R1 response means ready for data.
-        if(cr.getResponse() & (1<<8)) return true;
-        Thread::sleep(5);
-    }
-    DBGERR("Timeout waiting card ready\n");
-    return false;
-}
-
-/**
- * \internal
- * Read a single block of 512 bytes from an SD/MMC card.
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to read.
- */
-static bool singleBlockRead(unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block read
-    unsigned int* newBuf=BufferConverter::toWordAlignedWithoutCopy(buffer);
-    CmdResult cr;
-    DataResult dr;
-    bool failed=true;
-    for(;;)
-    {
-        // Since we read with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        SDIO->DTIMER=1048576;
-        SDIO->DLEN=512;
-        //Block size 512 bytes, block data xfer, from card to controller
-        SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN;
-
-        cr=Command::IRQsend(Command::CMD17,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            dr=IRQreceiveDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-            
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::RXOverrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    BufferConverter::toOriginalBuffer();
-    return true;
-}
-
-/**
- * \internal
- * Write a single block of 512 bytes to an SD/MMC card
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to write.
- */
-static bool singleBlockWrite(const unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block write
-    const unsigned int* newBuf=BufferConverter::toWordAligned(buffer);
-    bool failed=true;
-    CmdResult cr;
-    DataResult dr;
-    for(;;)
-    {
-        // Since we write with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        cr=Command::IRQsend(Command::CMD24,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            SDIO->DTIMER=1048576;
-            SDIO->DLEN=512;
-            //Block size 512 bytes, block data xfer, from controller to card
-            SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTEN;
-
-            dr=IRQsendDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::TXUnderrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    return true;
-}
-
-//
-// Class CardSelector
-//
-
-/**
- * \internal
- * Simple RAII class for selecting an SD/MMC card an automatically deselect it
- * at the end of the scope.
- */
-class CardSelector
-{
-public:
-    /**
-     * \internal
-     * Constructor. Selects the card.
-     * The result of the select operation is available through its succeded()
-     * member function
-     */
-    explicit CardSelector()
-    {
-        success=Command::send(
-                Command::CMD7,Command::getRca()<<16).validateR1Response();
-    }
-
-    /**
-     * \internal
-     * \return true if the card was selected, false on error
-     */
-    bool succeded() { return success; }
-
-    /**
-     * \internal
-     * Destructor, ensures that the card is deselected
-     */
-    ~CardSelector()
-    {
-        Command::send(Command::CMD7,0); //Deselect card. This will timeout
-    }
-
-private:
-    bool success;
-};
-
-//
-// Initialization helper functions
-//
-
-/**
- * \internal
- * Datasheet says that there must be at least seven clock cycles between
- * two accesses to SDIO->POWER, and this ensures this constraint.
- */
-static inline void sevenNop()
-{
-    __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
-}
-
-/**
- * \internal
- * Initialzes the SDIO peripheral in the STM32
- */
-static void initSDIOPeripheral()
-{
-    {
-        //Doing read-modify-write on RCC->APBENR2 and gpios, better be safe
-        FastInterruptDisableLock lock;
-        RCC->APB2ENR |= RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN;
-        RCC->AHBENR |= RCC_AHBENR_SDIOEN;
-        sdD0::mode(Mode::ALTERNATE);
-        sdD1::mode(Mode::ALTERNATE);
-        sdD2::mode(Mode::ALTERNATE);
-        sdD3::mode(Mode::ALTERNATE);
-        sdCLK::mode(Mode::ALTERNATE);
-        sdCMD::mode(Mode::ALTERNATE);
-    }
-
-    SDIO->POWER=0; //Power off state
-    SDIO->CLKCR=0;
-    SDIO->CMD=0;
-    SDIO->DCTRL=0;
-    SDIO->ICR=0xc007ff;
-    sevenNop();
-    SDIO->POWER=SDIO_POWER_PWRCTRL_1 | SDIO_POWER_PWRCTRL_0; //Power on state
-    ClockController::setLowSpeedClock();
-    sevenNop();
-}
-
-/**
- * \internal
- * Detect if the card is an SDHC, SDv2, SDv1, MMC
- * \return Type of card: (1<<0)=MMC (1<<1)=SDv1 (1<<2)=SDv2 (1<<2)|(1<<3)=SDHC
- * or Invalid if card detect failed.
- */
-static CardType detectCardType()
-{
-    const int INIT_TIMEOUT=200; //200*10ms= 2 seconds
-    CmdResult r=Command::send(Command::CMD8,0x1aa);
-    if(r.validateError())
-    {
-        //We have an SDv2 card connected
-        if(r.getResponse()!=0x1aa)
-        {
-            DBGERR("CMD8 validation: voltage range fail\n");
-            return Invalid;
-        }
-        for(int i=0;i<INIT_TIMEOUT;i++)
-        {
-            //Bit 30 @ 1 = tell the card we like SDHCs
-            r=Command::send(Command::ACMD41,(1<<30) | VOLTAGE_MASK);
-            //ACMD41 sends R3 as response, whose CRC is wrong.
-            if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-            {
-                r.validateError();
-                return Invalid;
-            }
-            if((r.getResponse() & (1<<31))==0) //Busy bit
-            {
-                Thread::sleep(10);
-                continue;
-            }
-            if((r.getResponse() & VOLTAGE_MASK)==0)
-            {
-                DBGERR("ACMD41 validation: voltage range fail\n");
-                return Invalid;
-            }
-            DBG("ACMD41 validation: looped %d times\n",i);
-            if(r.getResponse() & (1<<30))
-            {
-                DBG("SDHC\n");
-                return SDHC;
-            } else {
-                DBG("SDv2\n");
-                return SDv2;
-            }
-        }
-        DBGERR("ACMD41 validation: looped until timeout\n");
-        return Invalid;
-    } else {
-        //We have an SDv1 or MMC
-        r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-        //ACMD41 sends R3 as response, whose CRC is wrong.
-        if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-        {
-            //MMC card
-            DBG("MMC card\n");
-            return MMC;
-        } else {
-            //SDv1 card
-            for(int i=0;i<INIT_TIMEOUT;i++)
-            {
-                //ACMD41 sends R3 as response, whose CRC is wrong.
-                if(r.getError()!=CmdResult::Ok &&
-                        r.getError()!=CmdResult::CRCFail)
-                {
-                    r.validateError();
-                    return Invalid;
-                }
-                if((r.getResponse() & (1<<31))==0) //Busy bit
-                {
-                    Thread::sleep(10);
-                    //Send again command
-                    r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-                    continue;
-                }
-                if((r.getResponse() & VOLTAGE_MASK)==0)
-                {
-                    DBGERR("ACMD41 validation: voltage range fail\n");
-                    return Invalid;
-                }
-                DBG("ACMD41 validation: looped %d times\nSDv1\n",i);
-                return SDv1;
-            }
-            DBGERR("ACMD41 validation: looped until timeout\n");
-            return Invalid;
-        }
-    }
-}
-
-//
-// Disk class
-//
-
-bool Disk::isAvailable()
-{
-    bool result=sdCardSense();
-    DBG("Disk::isAvailable(): %d\n",result);
-    return result;
-}
-
-void Disk::init()
-{
-    initSDIOPeripheral();
-
-    // This is more important than it seems, since CMD55 requires the card's RCA
-    // as argument. During initalization, after CMD0 the card has an RCA of zero
-    // so without this line ACMD41 will fail and the card won't be initialized.
-    Command::setRca(0);
-
-    //Send card reset command
-    CmdResult r=Command::send(Command::CMD0,0);
-    if(r.validateError()==false) return;
-
-    cardType=detectCardType();
-    if(cardType==Invalid) return; //Card detect failed
-    if(cardType==MMC) return; //MMC cards currently unsupported
-
-    // Now give an RCA to the card. In theory we should loop and enumerate all
-    // the cards but this driver supports only one card.
-    r=Command::send(Command::CMD2,0);
-    //CMD2 sends R2 response, whose CMDINDEX field is wrong
-    if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::RespNotMatch)
-    {
-        r.validateError();
-        return;
-    }
-    r=Command::send(Command::CMD3,0);
-    if(r.validateR6Response()==false) return;
-    Command::setRca(r.getResponse()>>16);
-    DBG("Got RCA=%u\n",Command::getRca());
-    if(Command::getRca()==0)
-    {
-        //RCA=0 can't be accepted, since it is used to deselect cards
-        DBGERR("RCA=0 is invalid\n");
-        return;
-    }
-
-    //Lastly, try selecting the card and configure the latest bits
-    {
-        CardSelector selector;
-        if(selector.succeded()==false) return;
-
-        r=Command::send(Command::CMD13,Command::getRca()<<16);//Get status
-        if(r.validateR1Response()==false) return;
-        if(r.getState()!=4) //4=Tran state
-        {
-            DBGERR("CMD7 was not able to select card\n");
-            return;
-        }
-
-        r=Command::send(Command::ACMD6,2);   //Set 4 bit bus width
-        if(r.validateR1Response()==false) return;
-
-        if(cardType!=SDHC)
-        {
-            r=Command::send(Command::CMD16,512); //Set 512Byte block length
-            if(r.validateR1Response()==false) return;
-        }
-    }
-
-    // Now that card is initialized, perform self calibration of maximum
-    // possible read/write speed. This as a side effect enables 4bit bus width.
-    ClockController::calibrateClockSpeed();
-
-    DBG("Disk::init(): Success\n");
-    diskInitialized=true;
-}
-
-bool Disk::read(unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::read(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockRead(buffer,lba)==false) continue;
-        } else {
-            // Multiple block read
-            // Currently implemented with N calls to single block read
-            unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockRead(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Read: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::write(const unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::write(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockWrite(buffer,lba)==false) continue;
-        } else {
-            // Multiple block write
-            // Currently implemented with N calls to single block write
-            const unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockWrite(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Write: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::sync()
-{
-    DBG("Disk::sync()\n");
-    //Note: no need to select card, since status can be queried even with card
-    //not selected.
-    return waitForCardReady();
-}
-
-bool Disk::diskInitialized=false;
-
-} //namespace miosix
diff --git a/miosix/arch/cortexM3_stm32/stm32f103ze_redbull_v2/interfaces-impl/disk.cpp b/miosix/arch/cortexM3_stm32/stm32f103ze_redbull_v2/interfaces-impl/disk.cpp
deleted file mode 100644
index 5bc803ee745c2354913d2155390df9b658edf07a..0000000000000000000000000000000000000000
--- a/miosix/arch/cortexM3_stm32/stm32f103ze_redbull_v2/interfaces-impl/disk.cpp
+++ /dev/null
@@ -1,1390 +0,0 @@
-
-/***************************************************************************
- *   Copyright (C) 2010 by Terraneo Federico                               *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/
-
-#include "interfaces/disk.h"
-#include "CMSIS/stm32f10x.h"
-#include "CMSIS/core_cm3.h"
-#include "interfaces/bsp.h"
-#include "interfaces/delays.h"
-#include "kernel/kernel.h"
-#include <cstdio>
-#include <cstring>
-
-//Note: enabling debugging might cause deadlock when using sleep() or reboot()
-//The bug won't be fixed because debugging is only useful for driver development
-///\internal Debug macro, for normal conditions
-//#define DBG iprintf
-#define DBG(x,...) ;
-///\internal Debug macro, for errors only
-//#define DBGERR iprintf
-#define DBGERR(x,...) ;
-
-namespace miosix {
-
-/*
- * Operating voltage of device. It is sent to the SD card to check if it can
- * work at this voltage. Range *must* be within 28..36
- * Example 33=3.3v
- */
-const unsigned char VOLTAGE=33;
-const unsigned int VOLTAGE_MASK=1<<(VOLTAGE-13); //See OCR register in SD spec
-
-/**
- * \internal
- * Possible state of the cardType variable.
- */
-enum CardType
-{
-    Invalid=0, ///<\internal Invalid card type
-    MMC=1<<0,  ///<\internal if(cardType==MMC) card is an MMC
-    SDv1=1<<1, ///<\internal if(cardType==SDv1) card is an SDv1
-    SDv2=1<<2, ///<\internal if(cardType==SDv2) card is an SDv2
-    SDHC=1<<3  ///<\internal if(cardType==SDHC) card is an SDHC
-};
-
-///\internal Type of card. This variable is set in Disk::init()
-static CardType cardType=Invalid;
-
-//SD card GPIOs
-typedef Gpio<GPIOC_BASE,8>  sdD0;
-typedef Gpio<GPIOC_BASE,9>  sdD1;
-typedef Gpio<GPIOC_BASE,10> sdD2;
-typedef Gpio<GPIOC_BASE,11> sdD3;
-typedef Gpio<GPIOC_BASE,12> sdCLK;
-typedef Gpio<GPIOD_BASE,2>  sdCMD;
-
-//
-// Class BufferConverter
-//
-
-/**
- * \internal
- * Convert a single buffer of *fixed* and predetermined size to and from
- * word-aligned. To do so, if the buffer is already word aligned a cast is made,
- * otherwise a new buffer is allocated.
- * Note that this class allocates at most ONE buffer at any given time.
- * Therefore any call to toWordAligned(), toWordAlignedWithoutCopy(),
- * toOriginalBuffer() or deallocateBuffer() invalidates the buffer previousy
- * returned by toWordAligned() and toWordAlignedWithoutCopy()
- */
-class BufferConverter
-{
-public:
-    /**
-     * \internal
-     * The buffer will be of this size only.
-     */
-    static const int BUFFER_SIZE=512;
-
-    /**
-     * \internal
-     * \return true if the pointer is word aligned
-     */
-    static bool isWordAligned(const unsigned char *x)
-    {
-        return (reinterpret_cast<const unsigned int>(x) & 0x3)==0;
-    }
-
-    /**
-     * \internal
-     * Convert from a constunsigned char* buffer of size BUFFER_SIZE to a
-     * const unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it copies the data on the original buffer to a word aligned
-     * buffer. Useful if subseqent code will read from the buffer.
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with the same data of the given buffer
-     */
-    static const unsigned int *toWordAligned(const unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert from an unsigned char* buffer of size BUFFER_SIZE to an
-     * unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it returns a new buffer which *does not* contain the data
-     * on the original buffer. Useful if subseqent code will write to the
-     * buffer. To move the written data to the original buffer, use
-     * toOriginalBuffer()
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with undefined content.
-     */
-    static unsigned int *toWordAlignedWithoutCopy(unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert the buffer got through toWordAlignedWithoutCopy() to the
-     * original buffer. If the original buffer was word aligned, nothing
-     * happens, otherwise a memcpy is done.
-     * Note that this function does not work on buffers got through
-     * toWordAligned().
-     */
-    static void toOriginalBuffer();
-
-    /**
-     * \internal
-     * Can be called to deallocate the buffer
-     */
-    static void deallocateBuffer();
-
-private:
-    static unsigned char *originalBuffer;
-    static unsigned int *wordAlignedBuffer;
-};
-
-const unsigned int *BufferConverter::toWordAligned(const unsigned char *buffer)
-{
-    originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-    if(isWordAligned(buffer))
-    {
-        return reinterpret_cast<const unsigned int*>(buffer);
-    } else {
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        std::memcpy(wordAlignedBuffer,buffer,BUFFER_SIZE);
-        return wordAlignedBuffer;
-    }
-}
-
-unsigned int *BufferConverter::toWordAlignedWithoutCopy(
-    unsigned char *buffer)
-{
-    if(isWordAligned(buffer))
-    {
-        originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-        return reinterpret_cast<unsigned int*>(buffer);
-    } else {
-        originalBuffer=buffer; //Save original pointer for toOriginalBuffer()
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        return wordAlignedBuffer;
-    }
-}
-
-void BufferConverter::toOriginalBuffer()
-{
-    if(originalBuffer==0) return;
-    std::memcpy(originalBuffer,wordAlignedBuffer,BUFFER_SIZE);
-    originalBuffer=0;
-}
-
-void BufferConverter::deallocateBuffer()
-{
-    originalBuffer=0; //Invalidate also original buffer
-    if(wordAlignedBuffer!=0)
-    {
-        delete[] wordAlignedBuffer;
-        wordAlignedBuffer=0;
-    }
-}
-
-unsigned char *BufferConverter::originalBuffer=0;
-unsigned int *BufferConverter::wordAlignedBuffer=0;
-
-//
-// Class CmdResult
-//
-
-/**
- * \internal
- * Contains the result of an SD/MMC command
- */
-class CmdResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending a command
-     */
-    enum Error
-    {
-        Ok=0,        /// No errors
-        Timeout,     /// Timeout while waiting command reply
-        CRCFail,     /// CRC check failed in command reply
-        RespNotMatch,/// Response index does not match command index
-        ACMDFail     /// Sending CMD55 failed
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    CmdResult(): cmd(0), error(Ok), response(0) {}
-
-    /**
-     * \internal
-     * Constructor,  set the response data
-     * \param cmd command index of command that was sent
-     * \param result result of command
-     */
-    CmdResult(unsigned char cmd, Error error): cmd(cmd), error(error),
-            response(SDIO->RESP1) {}
-
-    /**
-     * \internal
-     * \return the 32 bit of the response.
-     * May not be valid if getError()!=Ok or the command does not send a
-     * response, such as CMD0
-     */
-    unsigned int getResponse() { return response; }
-
-    /**
-     * \internal
-     * \return command index
-     */
-    unsigned char getCmdIndex() { return cmd; }
-
-    /**
-     * \internal
-     * \return the error flags of the response
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending the command.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R1 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR1Response();
-
-    /**
-     * \internal
-     * Same as validateR1Response, but can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    bool IRQvalidateR1Response();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R6 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR6Response();
-
-    /**
-     * \internal
-     * \return the card state from an R1 or R6 resonse
-     */
-    unsigned char getState();
-
-private:
-    unsigned char cmd; ///<\internal Command index that was sent
-    Error error; ///<\internal possible error that occurred
-    unsigned int response; ///<\internal 32bit response
-};
-
-bool CmdResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("CMD%d: Timeout\n",cmd);
-            break;
-        case CRCFail:
-            DBGERR("CMD%d: CRC Fail\n",cmd);
-            break;
-        case RespNotMatch:
-            DBGERR("CMD%d: Response does not match\n",cmd);
-            break;
-        case ACMDFail:
-            DBGERR("CMD%d: ACMD Fail\n",cmd);
-            break;
-    }
-    return false;
-}
-
-bool CmdResult::validateR1Response()
-{
-    if(error!=Ok) return validateError();
-    //Note: this number is obtained with all the flags of R1 which are errors
-    //(flagged as E in the SD specification), plus CARD_IS_LOCKED because
-    //locked card are not supported by this software driver
-    if((response & 0xfff98008)==0) return true;
-    DBGERR("CMD%d: R1 response error(s):\n",cmd);
-    if(response & (1<<31)) DBGERR("Out of range\n");
-    if(response & (1<<30)) DBGERR("ADDR error\n");
-    if(response & (1<<29)) DBGERR("BLOCKLEN error\n");
-    if(response & (1<<28)) DBGERR("ERASE SEQ error\n");
-    if(response & (1<<27)) DBGERR("ERASE param\n");
-    if(response & (1<<26)) DBGERR("WP violation\n");
-    if(response & (1<<25)) DBGERR("card locked\n");
-    if(response & (1<<24)) DBGERR("LOCK_UNLOCK failed\n");
-    if(response & (1<<23)) DBGERR("command CRC failed\n");
-    if(response & (1<<22)) DBGERR("illegal command\n");
-    if(response & (1<<21)) DBGERR("ECC fail\n");
-    if(response & (1<<20)) DBGERR("card controller error\n");
-    if(response & (1<<19)) DBGERR("unknown error\n");
-    if(response & (1<<16)) DBGERR("CSD overwrite\n");
-    if(response & (1<<15)) DBGERR("WP ERASE skip\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-bool CmdResult::IRQvalidateR1Response()
-{
-    if(error!=Ok) return false;
-    if(response & 0xfff98008) return false;
-    return true;
-}
-
-bool CmdResult::validateR6Response()
-{
-    if(error!=Ok) return validateError();
-    if((response & 0xe008)==0) return true;
-    DBGERR("CMD%d: R6 response error(s):\n",cmd);
-    if(response & (1<<15)) DBGERR("command CRC failed\n");
-    if(response & (1<<14)) DBGERR("illegal command\n");
-    if(response & (1<<13)) DBGERR("unknown error\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-unsigned char CmdResult::getState()
-{
-    unsigned char result=(response>>9) & 0xf;
-    DBG("CMD%d: State: ",cmd);
-    switch(result)
-    {
-        case 0:  DBG("Idle\n");  break;
-        case 1:  DBG("Ready\n"); break;
-        case 2:  DBG("Ident\n"); break;
-        case 3:  DBG("Stby\n"); break;
-        case 4:  DBG("Tran\n"); break;
-        case 5:  DBG("Data\n"); break;
-        case 6:  DBG("Rcv\n"); break;
-        case 7:  DBG("Prg\n"); break;
-        case 8:  DBG("Dis\n"); break;
-        case 9:  DBG("Btst\n"); break;
-        default: DBG("Unknown\n"); break;
-    }
-    return result;
-}
-
-//
-// Class Command
-//
-
-/**
- * \internal
- * This class allows sending commands to an SD or MMC
- */
-class Command
-{
-public:
-
-    /**
-     * \internal
-     * SD/MMC commands
-     * - bit #7 is @ 1 if a command is an ACMDxx. send() will send the
-     *   sequence CMD55, CMDxx
-     * - bit from #0 to #5 indicate command index (CMD0..CMD63)
-     * - bit #6 is don't care
-     */
-    enum CommandType
-    {
-        CMD0=0,           //GO_IDLE_STATE
-        CMD2=2,           //ALL_SEND_CID
-        CMD3=3,           //SEND_RELATIVE_ADDR
-        ACMD6=0x80 | 6,   //SET_BUS_WIDTH
-        CMD7=7,           //SELECT_DESELECT_CARD
-        ACMD41=0x80 | 41, //SEND_OP_COND (SD)
-        CMD8=8,           //SEND_IF_COND
-        CMD9=9,           //SEND_CSD
-        CMD12=12,         //STOP_TRANSMISSION
-        CMD13=13,         //SEND_STATUS
-        CMD16=16,         //SET_BLOCKLEN
-        CMD17=17,         //READ_SINGLE_BLOCK
-        CMD18=18,         //READ_MULTIPLE_BLOCK
-        ACMD23=0x80 | 23, //SET_WR_BLK_ERASE_COUNT (SD)
-        CMD24=24,         //WRITE_BLOCK
-        CMD25=25,         //WRITE_MULTIPLE_BLOCK
-        CMD55=55          //APP_CMD
-    };
-
-    /**
-     * \internal
-     * Send a command.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult send(CommandType cmd, unsigned int arg)
-    {
-        if(static_cast<unsigned char>(cmd) & 0x80)
-        {
-            DBG("ACMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        } else {
-            DBG("CMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        }
-        return IRQsend(cmd,arg);
-    }
-
-    /**
-     * \internal
-     * Send a command. Can be called with interrupts disabled as it does not
-     * print any debug information.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult IRQsend(CommandType cmd, unsigned int arg);
-
-    /**
-     * \internal
-     * Set the relative card address, obtained during initialization.
-     * \param r the card's rca
-     */
-    static void setRca(unsigned short r) { rca=r; }
-
-    /**
-     * \internal
-     * \return the card's rca, as set by setRca
-     */
-    static unsigned int getRca() { return static_cast<unsigned int>(rca); }
-
-private:
-    static unsigned short rca;///<\internal Card's relative address
-};
-
-CmdResult Command::IRQsend(CommandType cmd, unsigned int arg)
-{
-    unsigned char cc=static_cast<unsigned char>(cmd);
-    //Handle ACMDxx as CMD55, CMDxx
-    if(cc & 0x80)
-    {
-        CmdResult r=IRQsend(CMD55,(static_cast<unsigned int>(rca))<<16);
-        if(r.IRQvalidateR1Response()==false)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-        //Bit 5 @ 1 = next command will be interpreted as ACMD
-        if((r.getResponse() & (1<<5))==0)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-    }
-
-    //Send command
-    cc &= 0x3f;
-    unsigned int command=SDIO_CMD_CPSMEN | static_cast<unsigned int>(cc);
-    if(cc!=CMD0) command |= SDIO_CMD_WAITRESP_0; //CMD0 has no response
-    if(cc==CMD2) command |= SDIO_CMD_WAITRESP_1; //CMD2 has long response
-    if(cc==CMD9) command |= SDIO_CMD_WAITRESP_1; //CMD9 has long response
-    SDIO->ARG=arg;
-    SDIO->CMD=command;
-
-    //CMD0 has no response, so wait until it is sent
-    if(cc==CMD0)
-    {
-        for(int i=0;i<500;i++)
-        {
-            if(SDIO->STA & SDIO_STA_CMDSENT)
-            {
-                SDIO->ICR=0x7ff;//Clear flags
-                return CmdResult(cc,CmdResult::Ok);
-            }
-            delayUs(1);
-        }
-        SDIO->ICR=0x7ff;//Clear flags
-        return CmdResult(cc,CmdResult::Timeout);
-    }
-
-    //Command is not CMD0, so wait a reply
-    for(int i=0;i<500;i++)
-    {
-        unsigned int status=SDIO->STA;
-        if(status & SDIO_STA_CMDREND)
-        {
-            SDIO->ICR=0x7ff;//Clear flags
-            if(SDIO->RESPCMD==cc) return CmdResult(cc,CmdResult::Ok);
-            else return CmdResult(cc,CmdResult::RespNotMatch);
-        }
-        if(status & SDIO_STA_CCRCFAIL)
-        {
-            SDIO->ICR=SDIO_ICR_CCRCFAILC;
-            return CmdResult(cc,CmdResult::CRCFail);
-        }
-        if(status & SDIO_STA_CTIMEOUT) break;
-        delayUs(1);
-    }
-    SDIO->ICR=SDIO_ICR_CTIMEOUTC;
-    return CmdResult(cc,CmdResult::Timeout);
-}
-
-unsigned short Command::rca=0;
-
-//
-// Class DataResult
-//
-
-/**
- * \internal
- * Contains the result of sending/receiving a data block
- */
-class DataResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending or receiving data
-     */
-    enum Error
-    {
-        Ok=0,
-        Timeout,
-        CRCFail,
-        RXOverrun,
-        TXUnderrun,
-        StartBitFail
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    DataResult(): error(Ok) {}
-
-    /**
-     * \internal
-     * Constructor,  set the result.
-     * \param error error type
-     */
-    DataResult(Error error): error(error) {}
-
-    /**
-     * \internal
-     * \return the error flags
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending/receiving data.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-    
-private:
-    Error error;
-};
-
-
-bool DataResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("Data Timeout\n");
-            break;
-        case CRCFail:
-            DBGERR("Data CRC Fail\n");
-            break;
-        case RXOverrun:
-            DBGERR("Data overrun\n");
-            break;
-        case TXUnderrun:
-            DBGERR("Data underrun\n");
-            break;
-        case StartBitFail:
-            DBGERR("Data start bit Fail\n");
-            break;
-    }
-    return false;
-}
-
-//
-// Class ClockController
-//
-
-/**
- * \internal
- * This class controls the clock speed of the SDIO peripheral. The SDIO
- * peripheral, when used in polled mode, requires two timing critical pieces of
- * code: the one to send and the one to receive a data block. This because
- * the peripheral has a 128 byte fifo while the block size is 512 byte, and
- * if fifo underrun/overrun occurs the peripheral does not pause communcation,
- * instead it simply aborts the data transfer. Since the speed of the code to
- * read/write a data block depends on too many factors, such as compiler
- * optimizations, code running from internal flash or external ram, and the
- * cpu clock speed, a dynamic clocking approach was chosen.
- */
-class ClockController
-{
-public:
-
-    /**
-     * \internal. Set a low clock speed of 400KHz or less, used for
-     * detecting SD/MMC cards. This function as a side effect enables 1bit bus
-     * width, and disables clock powersave, since it is not allowed by SD spec.
-     */
-    static void setLowSpeedClock()
-    {
-        clockReductionAvailable=0;
-        // No hardware flow control, SDIO_CK generated on rising edge, 1bit bus
-        // width, no clock bypass, no powersave.
-        // Set low clock speed 400KHz, 72MHz/400KHz-2=178
-        SDIO->CLKCR=CLOCK_400KHz;
-        SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
-    }
-
-    /**
-     * \internal
-     * Automatically select the data speed.
-     * Since the maximum speed depends on many factors, such as code running in
-     * internal or external RAM, compiler optimizations etc. this routine
-     * selects the highest sustainable data transfer speed.
-     * This is done by binary search until the highest clock speed that causes
-     * no errors is found.
-     * This function as a side effect enables 4bit bus width, and clock
-     * powersave.
-     */
-    static void calibrateClockSpeed();
-
-    /**
-     * \internal
-     * Since clock speed is set dynamically by bynary search at runtime, a
-     * corner case might be that of a clock speed which results in unreliable
-     * data transfer, that sometimes succeeds, and sometimes fail.
-     * For maximum robustness, this function is provided to reduce the clock
-     * speed slightly in case a data transfer should fail after clock
-     * calibration. To avoid inadvertently considering other kind of issues as
-     * clock issues, this function can be called only MAX_ALLOWED_REDUCTIONS
-     * times after clock calibration, subsequent calls will fail. This will
-     * avoid other issues causing an ever decreasing clock speed.
-     * Can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    static bool IRQreduceClockSpeed();
-
-    /**
-     * \internal
-     * Read and write operation do retry during normal use for robustness, but
-     * during clock claibration they must not retry for speed reasons. This
-     * member function returns 1 during clock claibration and MAX_RETRY during
-     * normal use.
-     */
-    static unsigned char getRetryCount() { return retries; }
-
-private:
-    
-    /**
-     * \internal
-     * Value of SDIO->CLKCR that will give a 400KHz clock, depending on cpu
-     * clock speed.
-     */
-    #ifdef SYSCLK_FREQ_72MHz
-    static const unsigned int CLOCK_400KHz=178;
-    #elif SYSCLK_FREQ_56MHz
-    static const unsigned int CLOCK_400KHz=138;
-    #elif SYSCLK_FREQ_48MHz
-    static const unsigned int CLOCK_400KHz=118;
-    #elif SYSCLK_FREQ_36MHz
-    static const unsigned int CLOCK_400KHz=88;
-    #elif SYSCLK_FREQ_24MHz
-    static const unsigned int CLOCK_400KHz=58;
-    #else
-    static const unsigned int CLOCK_400KHz=18;
-    #endif
-
-    ///\internal Clock enabled, bus width 4bit, clock powersave enabled.
-    static const unsigned int CLKCR_FLAGS=SDIO_CLKCR_CLKEN |
-        SDIO_CLKCR_WIDBUS_0 | SDIO_CLKCR_PWRSAV;
-
-    ///\internal Maximum number of calls to IRQreduceClockSpeed() allowed
-    static const unsigned char MAX_ALLOWED_REDUCTIONS=5;
-
-    ///\internl value returned by getRetryCount() while *not* calibrating clock.
-    static const unsigned char MAX_RETRY=3;
-
-    ///\internal Used to allow only one call to reduceClockSpeed()
-    static unsigned char clockReductionAvailable;
-
-    static unsigned char retries;
-};
-
-void ClockController::calibrateClockSpeed()
-{
-    //During calibration we call Disk::read which will call reduceClockSpeed()
-    //so not to invalidate calibration clock reduction must not be available
-    clockReductionAvailable=0;
-    retries=1;
-
-    DBG("Automatic speed calibration\n");
-    unsigned int buffer[512/sizeof(unsigned int)];
-    unsigned int minFreq=CLOCK_400KHz; //400KHz, independent of CPU clock
-    unsigned int maxFreq=1;            //24MHz  with CPU running @ 72MHz
-    unsigned int selected;
-    while(minFreq-maxFreq>1)
-    {
-        selected=(minFreq+maxFreq)/2;
-        DBG("Trying CLKCR=%d\n",selected);
-        SDIO->CLKCR=selected;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-            minFreq=selected;
-        else maxFreq=selected;
-    }
-    //Last round of algorithm
-    SDIO->CLKCR=maxFreq;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-    {
-        DBG("Optimal CLKCR=%d\n",maxFreq);
-    } else {
-        SDIO->CLKCR=minFreq;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        DBG("Optimal CLKCR=%d\n",minFreq);
-    }
-
-    //Make clock reduction available
-    clockReductionAvailable=MAX_ALLOWED_REDUCTIONS;
-    retries=MAX_RETRY;
-}
-
-bool ClockController::IRQreduceClockSpeed()
-{
-    //Ensure this function can be called only twice per calibration
-    if(clockReductionAvailable==0) return false;
-    clockReductionAvailable--;
-
-    unsigned int currentClkcr=SDIO->CLKCR & 0xff;
-    if(currentClkcr==CLOCK_400KHz) return false; //No lower than this value
-
-    //If the value of clockcr is low, increasing it by one is enough since
-    //frequency changes a lot, otherwise increase by 2.
-    if(currentClkcr<10) currentClkcr++;
-    else currentClkcr+=2;
-
-    SDIO->CLKCR=currentClkcr;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    return true;
-}
-
-unsigned char ClockController::clockReductionAvailable=false;
-unsigned char ClockController::retries=ClockController::MAX_RETRY;
-
-//
-// Data send/receive functions
-//
-
-/**
- * \internal
- * Receive a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes)
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQreceiveDataBlock(unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQsendDataBlock(), otherwise IRQsendDataBlock()
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_RXOVERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_RXFIFOHF) && (buffer!=bufend))
-        {
-            //Read 8 words from the fifo, loop entirely unrolled for speed
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_RXOVERR) return DataResult(DataResult::RXOverrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    //Read eventual data left in the FIFO
-    for(;;)
-    {
-        if((SDIO->STA & SDIO_STA_RXDAVL)==0) break;
-        *buffer=SDIO->FIFO; buffer++;
-    }
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Send a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes).
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQsendDataBlock(const unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQreceiveDataBlock(), otherwise this function
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_TXUNDERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_TXFIFOHE) && (buffer!=bufend))
-        {
-            //Write 8 words to the fifo, loop entirely unrolled for speed
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_TXUNDERR) return DataResult(DataResult::TXUnderrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Wait until the card is ready for data transfer.
- * Can be called independently of the card being selected.
- * \return true on success, false on failure
- */
-bool waitForCardReady()
-{
-    for(int i=0;i<300;i++) //Timeout 1.5 second
-    {
-        CmdResult cr=Command::send(Command::CMD13,Command::getRca()<<16);
-        if(cr.validateR1Response()==false) return false;
-        //Bit 8 in R1 response means ready for data.
-        if(cr.getResponse() & (1<<8)) return true;
-        Thread::sleep(5);
-    }
-    DBGERR("Timeout waiting card ready\n");
-    return false;
-}
-
-/**
- * \internal
- * Read a single block of 512 bytes from an SD/MMC card.
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to read.
- */
-static bool singleBlockRead(unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block read
-    unsigned int* newBuf=BufferConverter::toWordAlignedWithoutCopy(buffer);
-    CmdResult cr;
-    DataResult dr;
-    bool failed=true;
-    for(;;)
-    {
-        // Since we read with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        SDIO->DTIMER=1048576;
-        SDIO->DLEN=512;
-        //Block size 512 bytes, block data xfer, from card to controller
-        SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN;
-
-        cr=Command::IRQsend(Command::CMD17,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            dr=IRQreceiveDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-            
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::RXOverrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    BufferConverter::toOriginalBuffer();
-    return true;
-}
-
-/**
- * \internal
- * Write a single block of 512 bytes to an SD/MMC card
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to write.
- */
-static bool singleBlockWrite(const unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block write
-    const unsigned int* newBuf=BufferConverter::toWordAligned(buffer);
-    bool failed=true;
-    CmdResult cr;
-    DataResult dr;
-    for(;;)
-    {
-        // Since we write with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        cr=Command::IRQsend(Command::CMD24,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            SDIO->DTIMER=1048576;
-            SDIO->DLEN=512;
-            //Block size 512 bytes, block data xfer, from controller to card
-            SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTEN;
-
-            dr=IRQsendDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::TXUnderrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    return true;
-}
-
-//
-// Class CardSelector
-//
-
-/**
- * \internal
- * Simple RAII class for selecting an SD/MMC card an automatically deselect it
- * at the end of the scope.
- */
-class CardSelector
-{
-public:
-    /**
-     * \internal
-     * Constructor. Selects the card.
-     * The result of the select operation is available through its succeded()
-     * member function
-     */
-    explicit CardSelector()
-    {
-        success=Command::send(
-                Command::CMD7,Command::getRca()<<16).validateR1Response();
-    }
-
-    /**
-     * \internal
-     * \return true if the card was selected, false on error
-     */
-    bool succeded() { return success; }
-
-    /**
-     * \internal
-     * Destructor, ensures that the card is deselected
-     */
-    ~CardSelector()
-    {
-        Command::send(Command::CMD7,0); //Deselect card. This will timeout
-    }
-
-private:
-    bool success;
-};
-
-//
-// Initialization helper functions
-//
-
-/**
- * \internal
- * Datasheet says that there must be at least seven clock cycles between
- * two accesses to SDIO->POWER, and this ensures this constraint.
- */
-static inline void sevenNop()
-{
-    __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
-}
-
-/**
- * \internal
- * Initialzes the SDIO peripheral in the STM32
- */
-static void initSDIOPeripheral()
-{
-    {
-        //Doing read-modify-write on RCC->APBENR2 and gpios, better be safe
-        FastInterruptDisableLock lock;
-        RCC->APB2ENR |= RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN;
-        RCC->AHBENR |= RCC_AHBENR_SDIOEN;
-        sdD0::mode(Mode::ALTERNATE);
-        sdD1::mode(Mode::ALTERNATE);
-        sdD2::mode(Mode::ALTERNATE);
-        sdD3::mode(Mode::ALTERNATE);
-        sdCLK::mode(Mode::ALTERNATE);
-        sdCMD::mode(Mode::ALTERNATE);
-    }
-
-    SDIO->POWER=0; //Power off state
-    SDIO->CLKCR=0;
-    SDIO->CMD=0;
-    SDIO->DCTRL=0;
-    SDIO->ICR=0xc007ff;
-    sevenNop();
-    SDIO->POWER=SDIO_POWER_PWRCTRL_1 | SDIO_POWER_PWRCTRL_0; //Power on state
-    ClockController::setLowSpeedClock();
-    sevenNop();
-}
-
-/**
- * \internal
- * Detect if the card is an SDHC, SDv2, SDv1, MMC
- * \return Type of card: (1<<0)=MMC (1<<1)=SDv1 (1<<2)=SDv2 (1<<2)|(1<<3)=SDHC
- * or Invalid if card detect failed.
- */
-static CardType detectCardType()
-{
-    const int INIT_TIMEOUT=200; //200*10ms= 2 seconds
-    CmdResult r=Command::send(Command::CMD8,0x1aa);
-    if(r.validateError())
-    {
-        //We have an SDv2 card connected
-        if(r.getResponse()!=0x1aa)
-        {
-            DBGERR("CMD8 validation: voltage range fail\n");
-            return Invalid;
-        }
-        for(int i=0;i<INIT_TIMEOUT;i++)
-        {
-            //Bit 30 @ 1 = tell the card we like SDHCs
-            r=Command::send(Command::ACMD41,(1<<30) | VOLTAGE_MASK);
-            //ACMD41 sends R3 as response, whose CRC is wrong.
-            if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-            {
-                r.validateError();
-                return Invalid;
-            }
-            if((r.getResponse() & (1<<31))==0) //Busy bit
-            {
-                Thread::sleep(10);
-                continue;
-            }
-            if((r.getResponse() & VOLTAGE_MASK)==0)
-            {
-                DBGERR("ACMD41 validation: voltage range fail\n");
-                return Invalid;
-            }
-            DBG("ACMD41 validation: looped %d times\n",i);
-            if(r.getResponse() & (1<<30))
-            {
-                DBG("SDHC\n");
-                return SDHC;
-            } else {
-                DBG("SDv2\n");
-                return SDv2;
-            }
-        }
-        DBGERR("ACMD41 validation: looped until timeout\n");
-        return Invalid;
-    } else {
-        //We have an SDv1 or MMC
-        r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-        //ACMD41 sends R3 as response, whose CRC is wrong.
-        if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-        {
-            //MMC card
-            DBG("MMC card\n");
-            return MMC;
-        } else {
-            //SDv1 card
-            for(int i=0;i<INIT_TIMEOUT;i++)
-            {
-                //ACMD41 sends R3 as response, whose CRC is wrong.
-                if(r.getError()!=CmdResult::Ok &&
-                        r.getError()!=CmdResult::CRCFail)
-                {
-                    r.validateError();
-                    return Invalid;
-                }
-                if((r.getResponse() & (1<<31))==0) //Busy bit
-                {
-                    Thread::sleep(10);
-                    //Send again command
-                    r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-                    continue;
-                }
-                if((r.getResponse() & VOLTAGE_MASK)==0)
-                {
-                    DBGERR("ACMD41 validation: voltage range fail\n");
-                    return Invalid;
-                }
-                DBG("ACMD41 validation: looped %d times\nSDv1\n",i);
-                return SDv1;
-            }
-            DBGERR("ACMD41 validation: looped until timeout\n");
-            return Invalid;
-        }
-    }
-}
-
-//
-// Disk class
-//
-
-bool Disk::isAvailable()
-{
-    bool result=sdCardSense();
-    DBG("Disk::isAvailable(): %d\n",result);
-    return result;
-}
-
-void Disk::init()
-{
-    initSDIOPeripheral();
-
-    // This is more important than it seems, since CMD55 requires the card's RCA
-    // as argument. During initalization, after CMD0 the card has an RCA of zero
-    // so without this line ACMD41 will fail and the card won't be initialized.
-    Command::setRca(0);
-
-    //Send card reset command
-    CmdResult r=Command::send(Command::CMD0,0);
-    if(r.validateError()==false) return;
-
-    cardType=detectCardType();
-    if(cardType==Invalid) return; //Card detect failed
-    if(cardType==MMC) return; //MMC cards currently unsupported
-
-    // Now give an RCA to the card. In theory we should loop and enumerate all
-    // the cards but this driver supports only one card.
-    r=Command::send(Command::CMD2,0);
-    //CMD2 sends R2 response, whose CMDINDEX field is wrong
-    if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::RespNotMatch)
-    {
-        r.validateError();
-        return;
-    }
-    r=Command::send(Command::CMD3,0);
-    if(r.validateR6Response()==false) return;
-    Command::setRca(r.getResponse()>>16);
-    DBG("Got RCA=%u\n",Command::getRca());
-    if(Command::getRca()==0)
-    {
-        //RCA=0 can't be accepted, since it is used to deselect cards
-        DBGERR("RCA=0 is invalid\n");
-        return;
-    }
-
-    //Lastly, try selecting the card and configure the latest bits
-    {
-        CardSelector selector;
-        if(selector.succeded()==false) return;
-
-        r=Command::send(Command::CMD13,Command::getRca()<<16);//Get status
-        if(r.validateR1Response()==false) return;
-        if(r.getState()!=4) //4=Tran state
-        {
-            DBGERR("CMD7 was not able to select card\n");
-            return;
-        }
-
-        r=Command::send(Command::ACMD6,2);   //Set 4 bit bus width
-        if(r.validateR1Response()==false) return;
-
-        if(cardType!=SDHC)
-        {
-            r=Command::send(Command::CMD16,512); //Set 512Byte block length
-            if(r.validateR1Response()==false) return;
-        }
-    }
-
-    // Now that card is initialized, perform self calibration of maximum
-    // possible read/write speed. This as a side effect enables 4bit bus width.
-    ClockController::calibrateClockSpeed();
-
-    DBG("Disk::init(): Success\n");
-    diskInitialized=true;
-}
-
-bool Disk::read(unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::read(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockRead(buffer,lba)==false) continue;
-        } else {
-            // Multiple block read
-            // Currently implemented with N calls to single block read
-            unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockRead(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Read: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::write(const unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::write(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockWrite(buffer,lba)==false) continue;
-        } else {
-            // Multiple block write
-            // Currently implemented with N calls to single block write
-            const unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockWrite(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Write: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::sync()
-{
-    DBG("Disk::sync()\n");
-    //Note: no need to select card, since status can be queried even with card
-    //not selected.
-    return waitForCardReady();
-}
-
-bool Disk::diskInitialized=false;
-
-} //namespace miosix
diff --git a/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/disk.cpp b/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/disk.cpp
deleted file mode 100644
index 5bc803ee745c2354913d2155390df9b658edf07a..0000000000000000000000000000000000000000
--- a/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/disk.cpp
+++ /dev/null
@@ -1,1390 +0,0 @@
-
-/***************************************************************************
- *   Copyright (C) 2010 by Terraneo Federico                               *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/
-
-#include "interfaces/disk.h"
-#include "CMSIS/stm32f10x.h"
-#include "CMSIS/core_cm3.h"
-#include "interfaces/bsp.h"
-#include "interfaces/delays.h"
-#include "kernel/kernel.h"
-#include <cstdio>
-#include <cstring>
-
-//Note: enabling debugging might cause deadlock when using sleep() or reboot()
-//The bug won't be fixed because debugging is only useful for driver development
-///\internal Debug macro, for normal conditions
-//#define DBG iprintf
-#define DBG(x,...) ;
-///\internal Debug macro, for errors only
-//#define DBGERR iprintf
-#define DBGERR(x,...) ;
-
-namespace miosix {
-
-/*
- * Operating voltage of device. It is sent to the SD card to check if it can
- * work at this voltage. Range *must* be within 28..36
- * Example 33=3.3v
- */
-const unsigned char VOLTAGE=33;
-const unsigned int VOLTAGE_MASK=1<<(VOLTAGE-13); //See OCR register in SD spec
-
-/**
- * \internal
- * Possible state of the cardType variable.
- */
-enum CardType
-{
-    Invalid=0, ///<\internal Invalid card type
-    MMC=1<<0,  ///<\internal if(cardType==MMC) card is an MMC
-    SDv1=1<<1, ///<\internal if(cardType==SDv1) card is an SDv1
-    SDv2=1<<2, ///<\internal if(cardType==SDv2) card is an SDv2
-    SDHC=1<<3  ///<\internal if(cardType==SDHC) card is an SDHC
-};
-
-///\internal Type of card. This variable is set in Disk::init()
-static CardType cardType=Invalid;
-
-//SD card GPIOs
-typedef Gpio<GPIOC_BASE,8>  sdD0;
-typedef Gpio<GPIOC_BASE,9>  sdD1;
-typedef Gpio<GPIOC_BASE,10> sdD2;
-typedef Gpio<GPIOC_BASE,11> sdD3;
-typedef Gpio<GPIOC_BASE,12> sdCLK;
-typedef Gpio<GPIOD_BASE,2>  sdCMD;
-
-//
-// Class BufferConverter
-//
-
-/**
- * \internal
- * Convert a single buffer of *fixed* and predetermined size to and from
- * word-aligned. To do so, if the buffer is already word aligned a cast is made,
- * otherwise a new buffer is allocated.
- * Note that this class allocates at most ONE buffer at any given time.
- * Therefore any call to toWordAligned(), toWordAlignedWithoutCopy(),
- * toOriginalBuffer() or deallocateBuffer() invalidates the buffer previousy
- * returned by toWordAligned() and toWordAlignedWithoutCopy()
- */
-class BufferConverter
-{
-public:
-    /**
-     * \internal
-     * The buffer will be of this size only.
-     */
-    static const int BUFFER_SIZE=512;
-
-    /**
-     * \internal
-     * \return true if the pointer is word aligned
-     */
-    static bool isWordAligned(const unsigned char *x)
-    {
-        return (reinterpret_cast<const unsigned int>(x) & 0x3)==0;
-    }
-
-    /**
-     * \internal
-     * Convert from a constunsigned char* buffer of size BUFFER_SIZE to a
-     * const unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it copies the data on the original buffer to a word aligned
-     * buffer. Useful if subseqent code will read from the buffer.
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with the same data of the given buffer
-     */
-    static const unsigned int *toWordAligned(const unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert from an unsigned char* buffer of size BUFFER_SIZE to an
-     * unsigned int* word aligned buffer.
-     * If the original buffer is already word aligned it only does a cast,
-     * otherwise it returns a new buffer which *does not* contain the data
-     * on the original buffer. Useful if subseqent code will write to the
-     * buffer. To move the written data to the original buffer, use
-     * toOriginalBuffer()
-     * \param a buffer of size BUFFER_SIZE. Can be word aligned or not.
-     * \return a word aligned buffer with undefined content.
-     */
-    static unsigned int *toWordAlignedWithoutCopy(unsigned char *buffer);
-
-    /**
-     * \internal
-     * Convert the buffer got through toWordAlignedWithoutCopy() to the
-     * original buffer. If the original buffer was word aligned, nothing
-     * happens, otherwise a memcpy is done.
-     * Note that this function does not work on buffers got through
-     * toWordAligned().
-     */
-    static void toOriginalBuffer();
-
-    /**
-     * \internal
-     * Can be called to deallocate the buffer
-     */
-    static void deallocateBuffer();
-
-private:
-    static unsigned char *originalBuffer;
-    static unsigned int *wordAlignedBuffer;
-};
-
-const unsigned int *BufferConverter::toWordAligned(const unsigned char *buffer)
-{
-    originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-    if(isWordAligned(buffer))
-    {
-        return reinterpret_cast<const unsigned int*>(buffer);
-    } else {
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        std::memcpy(wordAlignedBuffer,buffer,BUFFER_SIZE);
-        return wordAlignedBuffer;
-    }
-}
-
-unsigned int *BufferConverter::toWordAlignedWithoutCopy(
-    unsigned char *buffer)
-{
-    if(isWordAligned(buffer))
-    {
-        originalBuffer=0; //Tell toOriginalBuffer() that there's nothing to do
-        return reinterpret_cast<unsigned int*>(buffer);
-    } else {
-        originalBuffer=buffer; //Save original pointer for toOriginalBuffer()
-        if(wordAlignedBuffer==0)
-            wordAlignedBuffer=new unsigned int[BUFFER_SIZE/sizeof(unsigned int)];
-        return wordAlignedBuffer;
-    }
-}
-
-void BufferConverter::toOriginalBuffer()
-{
-    if(originalBuffer==0) return;
-    std::memcpy(originalBuffer,wordAlignedBuffer,BUFFER_SIZE);
-    originalBuffer=0;
-}
-
-void BufferConverter::deallocateBuffer()
-{
-    originalBuffer=0; //Invalidate also original buffer
-    if(wordAlignedBuffer!=0)
-    {
-        delete[] wordAlignedBuffer;
-        wordAlignedBuffer=0;
-    }
-}
-
-unsigned char *BufferConverter::originalBuffer=0;
-unsigned int *BufferConverter::wordAlignedBuffer=0;
-
-//
-// Class CmdResult
-//
-
-/**
- * \internal
- * Contains the result of an SD/MMC command
- */
-class CmdResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending a command
-     */
-    enum Error
-    {
-        Ok=0,        /// No errors
-        Timeout,     /// Timeout while waiting command reply
-        CRCFail,     /// CRC check failed in command reply
-        RespNotMatch,/// Response index does not match command index
-        ACMDFail     /// Sending CMD55 failed
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    CmdResult(): cmd(0), error(Ok), response(0) {}
-
-    /**
-     * \internal
-     * Constructor,  set the response data
-     * \param cmd command index of command that was sent
-     * \param result result of command
-     */
-    CmdResult(unsigned char cmd, Error error): cmd(cmd), error(error),
-            response(SDIO->RESP1) {}
-
-    /**
-     * \internal
-     * \return the 32 bit of the response.
-     * May not be valid if getError()!=Ok or the command does not send a
-     * response, such as CMD0
-     */
-    unsigned int getResponse() { return response; }
-
-    /**
-     * \internal
-     * \return command index
-     */
-    unsigned char getCmdIndex() { return cmd; }
-
-    /**
-     * \internal
-     * \return the error flags of the response
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending the command.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R1 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR1Response();
-
-    /**
-     * \internal
-     * Same as validateR1Response, but can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    bool IRQvalidateR1Response();
-
-    /**
-     * \internal
-     * interprets this->getResponse() as an R6 response, and checks if there are
-     * errors, or everything is ok
-     * \return true on success, false on failure
-     */
-    bool validateR6Response();
-
-    /**
-     * \internal
-     * \return the card state from an R1 or R6 resonse
-     */
-    unsigned char getState();
-
-private:
-    unsigned char cmd; ///<\internal Command index that was sent
-    Error error; ///<\internal possible error that occurred
-    unsigned int response; ///<\internal 32bit response
-};
-
-bool CmdResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("CMD%d: Timeout\n",cmd);
-            break;
-        case CRCFail:
-            DBGERR("CMD%d: CRC Fail\n",cmd);
-            break;
-        case RespNotMatch:
-            DBGERR("CMD%d: Response does not match\n",cmd);
-            break;
-        case ACMDFail:
-            DBGERR("CMD%d: ACMD Fail\n",cmd);
-            break;
-    }
-    return false;
-}
-
-bool CmdResult::validateR1Response()
-{
-    if(error!=Ok) return validateError();
-    //Note: this number is obtained with all the flags of R1 which are errors
-    //(flagged as E in the SD specification), plus CARD_IS_LOCKED because
-    //locked card are not supported by this software driver
-    if((response & 0xfff98008)==0) return true;
-    DBGERR("CMD%d: R1 response error(s):\n",cmd);
-    if(response & (1<<31)) DBGERR("Out of range\n");
-    if(response & (1<<30)) DBGERR("ADDR error\n");
-    if(response & (1<<29)) DBGERR("BLOCKLEN error\n");
-    if(response & (1<<28)) DBGERR("ERASE SEQ error\n");
-    if(response & (1<<27)) DBGERR("ERASE param\n");
-    if(response & (1<<26)) DBGERR("WP violation\n");
-    if(response & (1<<25)) DBGERR("card locked\n");
-    if(response & (1<<24)) DBGERR("LOCK_UNLOCK failed\n");
-    if(response & (1<<23)) DBGERR("command CRC failed\n");
-    if(response & (1<<22)) DBGERR("illegal command\n");
-    if(response & (1<<21)) DBGERR("ECC fail\n");
-    if(response & (1<<20)) DBGERR("card controller error\n");
-    if(response & (1<<19)) DBGERR("unknown error\n");
-    if(response & (1<<16)) DBGERR("CSD overwrite\n");
-    if(response & (1<<15)) DBGERR("WP ERASE skip\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-bool CmdResult::IRQvalidateR1Response()
-{
-    if(error!=Ok) return false;
-    if(response & 0xfff98008) return false;
-    return true;
-}
-
-bool CmdResult::validateR6Response()
-{
-    if(error!=Ok) return validateError();
-    if((response & 0xe008)==0) return true;
-    DBGERR("CMD%d: R6 response error(s):\n",cmd);
-    if(response & (1<<15)) DBGERR("command CRC failed\n");
-    if(response & (1<<14)) DBGERR("illegal command\n");
-    if(response & (1<<13)) DBGERR("unknown error\n");
-    if(response & (1<<3)) DBGERR("AKE_SEQ error\n");
-    return false;
-}
-
-unsigned char CmdResult::getState()
-{
-    unsigned char result=(response>>9) & 0xf;
-    DBG("CMD%d: State: ",cmd);
-    switch(result)
-    {
-        case 0:  DBG("Idle\n");  break;
-        case 1:  DBG("Ready\n"); break;
-        case 2:  DBG("Ident\n"); break;
-        case 3:  DBG("Stby\n"); break;
-        case 4:  DBG("Tran\n"); break;
-        case 5:  DBG("Data\n"); break;
-        case 6:  DBG("Rcv\n"); break;
-        case 7:  DBG("Prg\n"); break;
-        case 8:  DBG("Dis\n"); break;
-        case 9:  DBG("Btst\n"); break;
-        default: DBG("Unknown\n"); break;
-    }
-    return result;
-}
-
-//
-// Class Command
-//
-
-/**
- * \internal
- * This class allows sending commands to an SD or MMC
- */
-class Command
-{
-public:
-
-    /**
-     * \internal
-     * SD/MMC commands
-     * - bit #7 is @ 1 if a command is an ACMDxx. send() will send the
-     *   sequence CMD55, CMDxx
-     * - bit from #0 to #5 indicate command index (CMD0..CMD63)
-     * - bit #6 is don't care
-     */
-    enum CommandType
-    {
-        CMD0=0,           //GO_IDLE_STATE
-        CMD2=2,           //ALL_SEND_CID
-        CMD3=3,           //SEND_RELATIVE_ADDR
-        ACMD6=0x80 | 6,   //SET_BUS_WIDTH
-        CMD7=7,           //SELECT_DESELECT_CARD
-        ACMD41=0x80 | 41, //SEND_OP_COND (SD)
-        CMD8=8,           //SEND_IF_COND
-        CMD9=9,           //SEND_CSD
-        CMD12=12,         //STOP_TRANSMISSION
-        CMD13=13,         //SEND_STATUS
-        CMD16=16,         //SET_BLOCKLEN
-        CMD17=17,         //READ_SINGLE_BLOCK
-        CMD18=18,         //READ_MULTIPLE_BLOCK
-        ACMD23=0x80 | 23, //SET_WR_BLK_ERASE_COUNT (SD)
-        CMD24=24,         //WRITE_BLOCK
-        CMD25=25,         //WRITE_MULTIPLE_BLOCK
-        CMD55=55          //APP_CMD
-    };
-
-    /**
-     * \internal
-     * Send a command.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult send(CommandType cmd, unsigned int arg)
-    {
-        if(static_cast<unsigned char>(cmd) & 0x80)
-        {
-            DBG("ACMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        } else {
-            DBG("CMD%d\n",static_cast<unsigned char>(cmd) & 0x3f);
-        }
-        return IRQsend(cmd,arg);
-    }
-
-    /**
-     * \internal
-     * Send a command. Can be called with interrupts disabled as it does not
-     * print any debug information.
-     * \param cmd command index (CMD0..CMD63) or ACMDxx command
-     * \param arg the 32 bit argument to the command
-     * \return a CmdResult object
-     */
-    static CmdResult IRQsend(CommandType cmd, unsigned int arg);
-
-    /**
-     * \internal
-     * Set the relative card address, obtained during initialization.
-     * \param r the card's rca
-     */
-    static void setRca(unsigned short r) { rca=r; }
-
-    /**
-     * \internal
-     * \return the card's rca, as set by setRca
-     */
-    static unsigned int getRca() { return static_cast<unsigned int>(rca); }
-
-private:
-    static unsigned short rca;///<\internal Card's relative address
-};
-
-CmdResult Command::IRQsend(CommandType cmd, unsigned int arg)
-{
-    unsigned char cc=static_cast<unsigned char>(cmd);
-    //Handle ACMDxx as CMD55, CMDxx
-    if(cc & 0x80)
-    {
-        CmdResult r=IRQsend(CMD55,(static_cast<unsigned int>(rca))<<16);
-        if(r.IRQvalidateR1Response()==false)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-        //Bit 5 @ 1 = next command will be interpreted as ACMD
-        if((r.getResponse() & (1<<5))==0)
-            return CmdResult(cc & 0x3f,CmdResult::ACMDFail);
-    }
-
-    //Send command
-    cc &= 0x3f;
-    unsigned int command=SDIO_CMD_CPSMEN | static_cast<unsigned int>(cc);
-    if(cc!=CMD0) command |= SDIO_CMD_WAITRESP_0; //CMD0 has no response
-    if(cc==CMD2) command |= SDIO_CMD_WAITRESP_1; //CMD2 has long response
-    if(cc==CMD9) command |= SDIO_CMD_WAITRESP_1; //CMD9 has long response
-    SDIO->ARG=arg;
-    SDIO->CMD=command;
-
-    //CMD0 has no response, so wait until it is sent
-    if(cc==CMD0)
-    {
-        for(int i=0;i<500;i++)
-        {
-            if(SDIO->STA & SDIO_STA_CMDSENT)
-            {
-                SDIO->ICR=0x7ff;//Clear flags
-                return CmdResult(cc,CmdResult::Ok);
-            }
-            delayUs(1);
-        }
-        SDIO->ICR=0x7ff;//Clear flags
-        return CmdResult(cc,CmdResult::Timeout);
-    }
-
-    //Command is not CMD0, so wait a reply
-    for(int i=0;i<500;i++)
-    {
-        unsigned int status=SDIO->STA;
-        if(status & SDIO_STA_CMDREND)
-        {
-            SDIO->ICR=0x7ff;//Clear flags
-            if(SDIO->RESPCMD==cc) return CmdResult(cc,CmdResult::Ok);
-            else return CmdResult(cc,CmdResult::RespNotMatch);
-        }
-        if(status & SDIO_STA_CCRCFAIL)
-        {
-            SDIO->ICR=SDIO_ICR_CCRCFAILC;
-            return CmdResult(cc,CmdResult::CRCFail);
-        }
-        if(status & SDIO_STA_CTIMEOUT) break;
-        delayUs(1);
-    }
-    SDIO->ICR=SDIO_ICR_CTIMEOUTC;
-    return CmdResult(cc,CmdResult::Timeout);
-}
-
-unsigned short Command::rca=0;
-
-//
-// Class DataResult
-//
-
-/**
- * \internal
- * Contains the result of sending/receiving a data block
- */
-class DataResult
-{
-public:
-
-    /**
-     * \internal
-     * Possible outcomes of sending or receiving data
-     */
-    enum Error
-    {
-        Ok=0,
-        Timeout,
-        CRCFail,
-        RXOverrun,
-        TXUnderrun,
-        StartBitFail
-    };
-
-    /**
-     * \internal
-     * Default constructor
-     */
-    DataResult(): error(Ok) {}
-
-    /**
-     * \internal
-     * Constructor,  set the result.
-     * \param error error type
-     */
-    DataResult(Error error): error(error) {}
-
-    /**
-     * \internal
-     * \return the error flags
-     */
-    Error getError() { return error; }
-
-    /**
-     * \internal
-     * Checks if errors occurred while sending/receiving data.
-     * \return true if no errors, false otherwise
-     */
-    bool validateError();
-    
-private:
-    Error error;
-};
-
-
-bool DataResult::validateError()
-{
-    switch(error)
-    {
-        case Ok:
-            return true;
-        case Timeout:
-            DBGERR("Data Timeout\n");
-            break;
-        case CRCFail:
-            DBGERR("Data CRC Fail\n");
-            break;
-        case RXOverrun:
-            DBGERR("Data overrun\n");
-            break;
-        case TXUnderrun:
-            DBGERR("Data underrun\n");
-            break;
-        case StartBitFail:
-            DBGERR("Data start bit Fail\n");
-            break;
-    }
-    return false;
-}
-
-//
-// Class ClockController
-//
-
-/**
- * \internal
- * This class controls the clock speed of the SDIO peripheral. The SDIO
- * peripheral, when used in polled mode, requires two timing critical pieces of
- * code: the one to send and the one to receive a data block. This because
- * the peripheral has a 128 byte fifo while the block size is 512 byte, and
- * if fifo underrun/overrun occurs the peripheral does not pause communcation,
- * instead it simply aborts the data transfer. Since the speed of the code to
- * read/write a data block depends on too many factors, such as compiler
- * optimizations, code running from internal flash or external ram, and the
- * cpu clock speed, a dynamic clocking approach was chosen.
- */
-class ClockController
-{
-public:
-
-    /**
-     * \internal. Set a low clock speed of 400KHz or less, used for
-     * detecting SD/MMC cards. This function as a side effect enables 1bit bus
-     * width, and disables clock powersave, since it is not allowed by SD spec.
-     */
-    static void setLowSpeedClock()
-    {
-        clockReductionAvailable=0;
-        // No hardware flow control, SDIO_CK generated on rising edge, 1bit bus
-        // width, no clock bypass, no powersave.
-        // Set low clock speed 400KHz, 72MHz/400KHz-2=178
-        SDIO->CLKCR=CLOCK_400KHz;
-        SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
-    }
-
-    /**
-     * \internal
-     * Automatically select the data speed.
-     * Since the maximum speed depends on many factors, such as code running in
-     * internal or external RAM, compiler optimizations etc. this routine
-     * selects the highest sustainable data transfer speed.
-     * This is done by binary search until the highest clock speed that causes
-     * no errors is found.
-     * This function as a side effect enables 4bit bus width, and clock
-     * powersave.
-     */
-    static void calibrateClockSpeed();
-
-    /**
-     * \internal
-     * Since clock speed is set dynamically by bynary search at runtime, a
-     * corner case might be that of a clock speed which results in unreliable
-     * data transfer, that sometimes succeeds, and sometimes fail.
-     * For maximum robustness, this function is provided to reduce the clock
-     * speed slightly in case a data transfer should fail after clock
-     * calibration. To avoid inadvertently considering other kind of issues as
-     * clock issues, this function can be called only MAX_ALLOWED_REDUCTIONS
-     * times after clock calibration, subsequent calls will fail. This will
-     * avoid other issues causing an ever decreasing clock speed.
-     * Can be called with interrupts disabled.
-     * \return true on success, false on failure
-     */
-    static bool IRQreduceClockSpeed();
-
-    /**
-     * \internal
-     * Read and write operation do retry during normal use for robustness, but
-     * during clock claibration they must not retry for speed reasons. This
-     * member function returns 1 during clock claibration and MAX_RETRY during
-     * normal use.
-     */
-    static unsigned char getRetryCount() { return retries; }
-
-private:
-    
-    /**
-     * \internal
-     * Value of SDIO->CLKCR that will give a 400KHz clock, depending on cpu
-     * clock speed.
-     */
-    #ifdef SYSCLK_FREQ_72MHz
-    static const unsigned int CLOCK_400KHz=178;
-    #elif SYSCLK_FREQ_56MHz
-    static const unsigned int CLOCK_400KHz=138;
-    #elif SYSCLK_FREQ_48MHz
-    static const unsigned int CLOCK_400KHz=118;
-    #elif SYSCLK_FREQ_36MHz
-    static const unsigned int CLOCK_400KHz=88;
-    #elif SYSCLK_FREQ_24MHz
-    static const unsigned int CLOCK_400KHz=58;
-    #else
-    static const unsigned int CLOCK_400KHz=18;
-    #endif
-
-    ///\internal Clock enabled, bus width 4bit, clock powersave enabled.
-    static const unsigned int CLKCR_FLAGS=SDIO_CLKCR_CLKEN |
-        SDIO_CLKCR_WIDBUS_0 | SDIO_CLKCR_PWRSAV;
-
-    ///\internal Maximum number of calls to IRQreduceClockSpeed() allowed
-    static const unsigned char MAX_ALLOWED_REDUCTIONS=5;
-
-    ///\internl value returned by getRetryCount() while *not* calibrating clock.
-    static const unsigned char MAX_RETRY=3;
-
-    ///\internal Used to allow only one call to reduceClockSpeed()
-    static unsigned char clockReductionAvailable;
-
-    static unsigned char retries;
-};
-
-void ClockController::calibrateClockSpeed()
-{
-    //During calibration we call Disk::read which will call reduceClockSpeed()
-    //so not to invalidate calibration clock reduction must not be available
-    clockReductionAvailable=0;
-    retries=1;
-
-    DBG("Automatic speed calibration\n");
-    unsigned int buffer[512/sizeof(unsigned int)];
-    unsigned int minFreq=CLOCK_400KHz; //400KHz, independent of CPU clock
-    unsigned int maxFreq=1;            //24MHz  with CPU running @ 72MHz
-    unsigned int selected;
-    while(minFreq-maxFreq>1)
-    {
-        selected=(minFreq+maxFreq)/2;
-        DBG("Trying CLKCR=%d\n",selected);
-        SDIO->CLKCR=selected;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-            minFreq=selected;
-        else maxFreq=selected;
-    }
-    //Last round of algorithm
-    SDIO->CLKCR=maxFreq;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    if(Disk::read(reinterpret_cast<unsigned char*>(buffer),0,1))
-    {
-        DBG("Optimal CLKCR=%d\n",maxFreq);
-    } else {
-        SDIO->CLKCR=minFreq;
-        SDIO->CLKCR |= CLKCR_FLAGS;
-        DBG("Optimal CLKCR=%d\n",minFreq);
-    }
-
-    //Make clock reduction available
-    clockReductionAvailable=MAX_ALLOWED_REDUCTIONS;
-    retries=MAX_RETRY;
-}
-
-bool ClockController::IRQreduceClockSpeed()
-{
-    //Ensure this function can be called only twice per calibration
-    if(clockReductionAvailable==0) return false;
-    clockReductionAvailable--;
-
-    unsigned int currentClkcr=SDIO->CLKCR & 0xff;
-    if(currentClkcr==CLOCK_400KHz) return false; //No lower than this value
-
-    //If the value of clockcr is low, increasing it by one is enough since
-    //frequency changes a lot, otherwise increase by 2.
-    if(currentClkcr<10) currentClkcr++;
-    else currentClkcr+=2;
-
-    SDIO->CLKCR=currentClkcr;
-    SDIO->CLKCR |= CLKCR_FLAGS;
-    return true;
-}
-
-unsigned char ClockController::clockReductionAvailable=false;
-unsigned char ClockController::retries=ClockController::MAX_RETRY;
-
-//
-// Data send/receive functions
-//
-
-/**
- * \internal
- * Receive a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes)
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQreceiveDataBlock(unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQsendDataBlock(), otherwise IRQsendDataBlock()
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_RXOVERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_RXFIFOHF) && (buffer!=bufend))
-        {
-            //Read 8 words from the fifo, loop entirely unrolled for speed
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-            *buffer=SDIO->FIFO; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_RXOVERR) return DataResult(DataResult::RXOverrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    //Read eventual data left in the FIFO
-    for(;;)
-    {
-        if((SDIO->STA & SDIO_STA_RXDAVL)==0) break;
-        *buffer=SDIO->FIFO; buffer++;
-    }
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Send a data block. The end of the data block must be told to the SDIO
- * peripheral in SDIO->DLEN and must match the size parameter given to this
- * function.
- * \param buffer buffer where to store received data. Its size must be >=size
- * \param buffer size, which *must* be multiple of 8 words (32bytes).
- * Note that the size parameter must be expressed in word (4bytes), while
- * the value in SDIO->DLEN is expressed in bytes.
- * \return a DataResult object
- */
-static DataResult IRQsendDataBlock(const unsigned int *buffer, unsigned int size)
-{
-    // A note on speed.
-    // Due to the auto calibration of SDIO clock speed being done with
-    // IRQreceiveDataBlock(), the speed of this function must be comparable
-    // with the speed of IRQreceiveDataBlock(), otherwise this function
-    // will fail because of data underrun.
-    const unsigned int *bufend=buffer+size;
-    unsigned int status;
-    for(;;)
-    {
-        status=SDIO->STA;
-        if(status & (SDIO_STA_TXUNDERR | SDIO_STA_DCRCFAIL |
-            SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR | SDIO_STA_DBCKEND)) break;
-        if((status & SDIO_STA_TXFIFOHE) && (buffer!=bufend))
-        {
-            //Write 8 words to the fifo, loop entirely unrolled for speed
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-            SDIO->FIFO=*buffer; buffer++;
-        }
-    }
-    SDIO->ICR=0x7ff;//Clear flags
-    if(status & SDIO_STA_TXUNDERR) return DataResult(DataResult::TXUnderrun);
-    if(status & SDIO_STA_DCRCFAIL) return DataResult(DataResult::CRCFail);
-    if(status & SDIO_STA_DTIMEOUT) return DataResult(DataResult::Timeout);
-    if(status & SDIO_STA_STBITERR) return DataResult(DataResult::StartBitFail);
-    return DataResult(DataResult::Ok);
-}
-
-/**
- * \internal
- * Wait until the card is ready for data transfer.
- * Can be called independently of the card being selected.
- * \return true on success, false on failure
- */
-bool waitForCardReady()
-{
-    for(int i=0;i<300;i++) //Timeout 1.5 second
-    {
-        CmdResult cr=Command::send(Command::CMD13,Command::getRca()<<16);
-        if(cr.validateR1Response()==false) return false;
-        //Bit 8 in R1 response means ready for data.
-        if(cr.getResponse() & (1<<8)) return true;
-        Thread::sleep(5);
-    }
-    DBGERR("Timeout waiting card ready\n");
-    return false;
-}
-
-/**
- * \internal
- * Read a single block of 512 bytes from an SD/MMC card.
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to read.
- */
-static bool singleBlockRead(unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block read
-    unsigned int* newBuf=BufferConverter::toWordAlignedWithoutCopy(buffer);
-    CmdResult cr;
-    DataResult dr;
-    bool failed=true;
-    for(;;)
-    {
-        // Since we read with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        SDIO->DTIMER=1048576;
-        SDIO->DLEN=512;
-        //Block size 512 bytes, block data xfer, from card to controller
-        SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN;
-
-        cr=Command::IRQsend(Command::CMD17,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            dr=IRQreceiveDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-            
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::RXOverrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    BufferConverter::toOriginalBuffer();
-    return true;
-}
-
-/**
- * \internal
- * Write a single block of 512 bytes to an SD/MMC card
- * Card must be selected prior to caling this function.
- * \param buffer, a buffer whose size is >=512 bytes
- * \param lba logical block address of the block to write.
- */
-static bool singleBlockWrite(const unsigned char *buffer, unsigned int lba)
-{
-    if(cardType!=SDHC) lba*=512; // Convert to byte address if not SDHC
-
-    if(waitForCardReady()==false) return false;
-
-    // Single block write
-    const unsigned int* newBuf=BufferConverter::toWordAligned(buffer);
-    bool failed=true;
-    CmdResult cr;
-    DataResult dr;
-    for(;;)
-    {
-        // Since we write with polling, a context switch or interrupt here
-        // would cause a fifo overrun, so we disable interrupts.
-        FastInterruptDisableLock dLock;
-
-        cr=Command::IRQsend(Command::CMD24,lba);
-        if(cr.IRQvalidateR1Response())
-        {
-            SDIO->DTIMER=1048576;
-            SDIO->DLEN=512;
-            //Block size 512 bytes, block data xfer, from controller to card
-            SDIO->DCTRL=(9<<4) | SDIO_DCTRL_DTEN;
-
-            dr=IRQsendDataBlock(newBuf,512/sizeof(unsigned int));
-            SDIO->DCTRL=0; //Disable data path state machine
-
-            //If failed because too slow check if it is possible to reduce speed
-            if(dr.getError()==DataResult::TXUnderrun)
-            {
-                if(ClockController::IRQreduceClockSpeed())
-                {
-                    //Disabling interrupts for too long is bad
-                    FastInterruptEnableLock eLock(dLock);
-                    //After an error during data xfer the card might be a little
-                    //confused. So send STOP_TRANSMISSION command to reassure it
-                    cr=Command::send(Command::CMD12,0);
-                    if(cr.validateR1Response()) continue;
-                }
-            }
-
-            if(dr.getError()==DataResult::Ok) failed=false;
-        }
-        break;
-    }
-    if(failed)
-    {
-        cr.validateR1Response();
-        dr.validateError();
-        //After an error during data xfer the card might be a little
-        //confused. So send STOP_TRANSMISSION command to reassure it
-        cr=Command::send(Command::CMD12,0);
-        cr.validateR1Response();
-        return false;
-    }
-    return true;
-}
-
-//
-// Class CardSelector
-//
-
-/**
- * \internal
- * Simple RAII class for selecting an SD/MMC card an automatically deselect it
- * at the end of the scope.
- */
-class CardSelector
-{
-public:
-    /**
-     * \internal
-     * Constructor. Selects the card.
-     * The result of the select operation is available through its succeded()
-     * member function
-     */
-    explicit CardSelector()
-    {
-        success=Command::send(
-                Command::CMD7,Command::getRca()<<16).validateR1Response();
-    }
-
-    /**
-     * \internal
-     * \return true if the card was selected, false on error
-     */
-    bool succeded() { return success; }
-
-    /**
-     * \internal
-     * Destructor, ensures that the card is deselected
-     */
-    ~CardSelector()
-    {
-        Command::send(Command::CMD7,0); //Deselect card. This will timeout
-    }
-
-private:
-    bool success;
-};
-
-//
-// Initialization helper functions
-//
-
-/**
- * \internal
- * Datasheet says that there must be at least seven clock cycles between
- * two accesses to SDIO->POWER, and this ensures this constraint.
- */
-static inline void sevenNop()
-{
-    __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
-}
-
-/**
- * \internal
- * Initialzes the SDIO peripheral in the STM32
- */
-static void initSDIOPeripheral()
-{
-    {
-        //Doing read-modify-write on RCC->APBENR2 and gpios, better be safe
-        FastInterruptDisableLock lock;
-        RCC->APB2ENR |= RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN;
-        RCC->AHBENR |= RCC_AHBENR_SDIOEN;
-        sdD0::mode(Mode::ALTERNATE);
-        sdD1::mode(Mode::ALTERNATE);
-        sdD2::mode(Mode::ALTERNATE);
-        sdD3::mode(Mode::ALTERNATE);
-        sdCLK::mode(Mode::ALTERNATE);
-        sdCMD::mode(Mode::ALTERNATE);
-    }
-
-    SDIO->POWER=0; //Power off state
-    SDIO->CLKCR=0;
-    SDIO->CMD=0;
-    SDIO->DCTRL=0;
-    SDIO->ICR=0xc007ff;
-    sevenNop();
-    SDIO->POWER=SDIO_POWER_PWRCTRL_1 | SDIO_POWER_PWRCTRL_0; //Power on state
-    ClockController::setLowSpeedClock();
-    sevenNop();
-}
-
-/**
- * \internal
- * Detect if the card is an SDHC, SDv2, SDv1, MMC
- * \return Type of card: (1<<0)=MMC (1<<1)=SDv1 (1<<2)=SDv2 (1<<2)|(1<<3)=SDHC
- * or Invalid if card detect failed.
- */
-static CardType detectCardType()
-{
-    const int INIT_TIMEOUT=200; //200*10ms= 2 seconds
-    CmdResult r=Command::send(Command::CMD8,0x1aa);
-    if(r.validateError())
-    {
-        //We have an SDv2 card connected
-        if(r.getResponse()!=0x1aa)
-        {
-            DBGERR("CMD8 validation: voltage range fail\n");
-            return Invalid;
-        }
-        for(int i=0;i<INIT_TIMEOUT;i++)
-        {
-            //Bit 30 @ 1 = tell the card we like SDHCs
-            r=Command::send(Command::ACMD41,(1<<30) | VOLTAGE_MASK);
-            //ACMD41 sends R3 as response, whose CRC is wrong.
-            if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-            {
-                r.validateError();
-                return Invalid;
-            }
-            if((r.getResponse() & (1<<31))==0) //Busy bit
-            {
-                Thread::sleep(10);
-                continue;
-            }
-            if((r.getResponse() & VOLTAGE_MASK)==0)
-            {
-                DBGERR("ACMD41 validation: voltage range fail\n");
-                return Invalid;
-            }
-            DBG("ACMD41 validation: looped %d times\n",i);
-            if(r.getResponse() & (1<<30))
-            {
-                DBG("SDHC\n");
-                return SDHC;
-            } else {
-                DBG("SDv2\n");
-                return SDv2;
-            }
-        }
-        DBGERR("ACMD41 validation: looped until timeout\n");
-        return Invalid;
-    } else {
-        //We have an SDv1 or MMC
-        r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-        //ACMD41 sends R3 as response, whose CRC is wrong.
-        if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::CRCFail)
-        {
-            //MMC card
-            DBG("MMC card\n");
-            return MMC;
-        } else {
-            //SDv1 card
-            for(int i=0;i<INIT_TIMEOUT;i++)
-            {
-                //ACMD41 sends R3 as response, whose CRC is wrong.
-                if(r.getError()!=CmdResult::Ok &&
-                        r.getError()!=CmdResult::CRCFail)
-                {
-                    r.validateError();
-                    return Invalid;
-                }
-                if((r.getResponse() & (1<<31))==0) //Busy bit
-                {
-                    Thread::sleep(10);
-                    //Send again command
-                    r=Command::send(Command::ACMD41,VOLTAGE_MASK);
-                    continue;
-                }
-                if((r.getResponse() & VOLTAGE_MASK)==0)
-                {
-                    DBGERR("ACMD41 validation: voltage range fail\n");
-                    return Invalid;
-                }
-                DBG("ACMD41 validation: looped %d times\nSDv1\n",i);
-                return SDv1;
-            }
-            DBGERR("ACMD41 validation: looped until timeout\n");
-            return Invalid;
-        }
-    }
-}
-
-//
-// Disk class
-//
-
-bool Disk::isAvailable()
-{
-    bool result=sdCardSense();
-    DBG("Disk::isAvailable(): %d\n",result);
-    return result;
-}
-
-void Disk::init()
-{
-    initSDIOPeripheral();
-
-    // This is more important than it seems, since CMD55 requires the card's RCA
-    // as argument. During initalization, after CMD0 the card has an RCA of zero
-    // so without this line ACMD41 will fail and the card won't be initialized.
-    Command::setRca(0);
-
-    //Send card reset command
-    CmdResult r=Command::send(Command::CMD0,0);
-    if(r.validateError()==false) return;
-
-    cardType=detectCardType();
-    if(cardType==Invalid) return; //Card detect failed
-    if(cardType==MMC) return; //MMC cards currently unsupported
-
-    // Now give an RCA to the card. In theory we should loop and enumerate all
-    // the cards but this driver supports only one card.
-    r=Command::send(Command::CMD2,0);
-    //CMD2 sends R2 response, whose CMDINDEX field is wrong
-    if(r.getError()!=CmdResult::Ok && r.getError()!=CmdResult::RespNotMatch)
-    {
-        r.validateError();
-        return;
-    }
-    r=Command::send(Command::CMD3,0);
-    if(r.validateR6Response()==false) return;
-    Command::setRca(r.getResponse()>>16);
-    DBG("Got RCA=%u\n",Command::getRca());
-    if(Command::getRca()==0)
-    {
-        //RCA=0 can't be accepted, since it is used to deselect cards
-        DBGERR("RCA=0 is invalid\n");
-        return;
-    }
-
-    //Lastly, try selecting the card and configure the latest bits
-    {
-        CardSelector selector;
-        if(selector.succeded()==false) return;
-
-        r=Command::send(Command::CMD13,Command::getRca()<<16);//Get status
-        if(r.validateR1Response()==false) return;
-        if(r.getState()!=4) //4=Tran state
-        {
-            DBGERR("CMD7 was not able to select card\n");
-            return;
-        }
-
-        r=Command::send(Command::ACMD6,2);   //Set 4 bit bus width
-        if(r.validateR1Response()==false) return;
-
-        if(cardType!=SDHC)
-        {
-            r=Command::send(Command::CMD16,512); //Set 512Byte block length
-            if(r.validateR1Response()==false) return;
-        }
-    }
-
-    // Now that card is initialized, perform self calibration of maximum
-    // possible read/write speed. This as a side effect enables 4bit bus width.
-    ClockController::calibrateClockSpeed();
-
-    DBG("Disk::init(): Success\n");
-    diskInitialized=true;
-}
-
-bool Disk::read(unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::read(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockRead(buffer,lba)==false) continue;
-        } else {
-            // Multiple block read
-            // Currently implemented with N calls to single block read
-            unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockRead(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Read: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::write(const unsigned char *buffer, unsigned int lba,
-        unsigned char nSectors)
-{
-    DBG("Disk::write(): nSectors=%d\n",nSectors);
-    if(!BufferConverter::isWordAligned(buffer)) DBG("Buffer misaligned\n");
-
-    for(int i=0;i<ClockController::getRetryCount();i++)
-    {
-        //Select card
-        CardSelector selector;
-        if(selector.succeded()==false) continue;
-
-        if(nSectors==1)
-        {
-            if(singleBlockWrite(buffer,lba)==false) continue;
-        } else {
-            // Multiple block write
-            // Currently implemented with N calls to single block write
-            const unsigned char *tempBuffer=buffer;
-            unsigned int tempLba=lba;
-            for(unsigned int i=0;i<nSectors;i++)
-            {
-                if(singleBlockWrite(tempBuffer,tempLba)==false) continue;
-                tempBuffer+=512;
-                tempLba++;
-            }
-        }
-        if(i>0) DBGERR("Write: required %d retries\n",i);
-        return true;
-    }
-    return false;
-}
-
-bool Disk::sync()
-{
-    DBG("Disk::sync()\n");
-    //Note: no need to select card, since status can be queried even with card
-    //not selected.
-    return waitForCardReady();
-}
-
-bool Disk::diskInitialized=false;
-
-} //namespace miosix
diff --git a/miosix/arch/cortexM4_stm32/common/drivers/dcc.cpp b/miosix/arch/cortexM4_stm32/common/drivers/dcc.cpp
deleted file mode 100644
index cc50138b51110a678cadb45c49aaae18ffa6f1d4..0000000000000000000000000000000000000000
--- a/miosix/arch/cortexM4_stm32/common/drivers/dcc.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2011 by Terraneo Federico                               *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/ 
-
-/*
- * DCC support inspired by dcc_stdio.c in OpenOCD
- */
-
-#include <algorithm>
-#include <cstring>
-#include "pthread.h"
-#include "miosix.h"
-#include "dcc.h"
-
-using namespace std;
-
-/**
- * Send data to the host
- */
-static void send(unsigned char c)
-{
-    const unsigned int busy=1;
-    while(CoreDebug->DCRDR & busy) ;
-    CoreDebug->DCRDR=(static_cast<unsigned int>(c)<<8) | busy;
-}
-
-/**
- * Send a line of text to the host.
- * OpenOCD will insert a \n after each line, unfortunately,
- * as this complicates things.
- */
-void debugStr(const char *str, int length)
-{
-    //If not being debugged, don't print anything
-    if((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)==0) return;
-
-    if(length<0) length=strlen(str);
-    if(length>0 && str[0]=='\r') str++, length--; //TODO: better \r\n removal
-    if(length>0 && str[0]=='\n') str++, length--;
-    if(length==0) return;
-    send(1); //1=sending a string
-    send(0);
-    send(length & 0xff);
-    send(length>>8);
-    for(int i=0;i<length;i++) send(*str++);
-    //OpenOCD expects data in 4 byte blocks, so send trailing zeros to align
-    int remaining=4-(length & 3);
-    if(remaining<4) for(int i=0;i<remaining;i++) send(0);
-}
-
-/// Mutex for locking concurrent access to debug channel
-static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
-
-void debugWrite(const char *str, unsigned int len)
-{
-    pthread_mutex_lock(&mutex);
-    debugStr(str,len);
-    pthread_mutex_unlock(&mutex);
-}
-
-void IRQdebugWrite(const char *str)
-{
-    //Actually, there is a race condition if IRQdebugWrite is called from an
-    //interrupt while the main code is printing with debugWrite, but it is
-    //not such an issue since IRQdebugWrite is called only
-    //- at boot before the kernel is started, so there are no other threads
-    //- in case of a serious error, to print what went wrong before rebooting
-    //In the second case, which is rare, the data may not be printed correctly
-    debugStr(str,-1);
-}
diff --git a/miosix/arch/cortexM4_stm32/common/drivers/dcc.h b/miosix/arch/cortexM4_stm32/common/drivers/dcc.h
deleted file mode 100644
index 88abbb3bc10d6a646ef56f24644b7a994436fb8c..0000000000000000000000000000000000000000
--- a/miosix/arch/cortexM4_stm32/common/drivers/dcc.h
+++ /dev/null
@@ -1,46 +0,0 @@
- /***************************************************************************
- *   Copyright (C) 2011 by Terraneo Federico                               *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   As a special exception, if other files instantiate templates or use   *
- *   macros or inline functions from this file, or you compile this file   *
- *   and link it with other works to produce a work based on this file,    *
- *   this file does not by itself cause the resulting work to be covered   *
- *   by the GNU General Public License. However the source code for this   *
- *   file must still be made available in accordance with the GNU General  *
- *   Public License. This exception does not invalidate any other reasons  *
- *   why a work based on this file might be covered by the GNU General     *
- *   Public License.                                                       *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
- ***************************************************************************/
- 
-#ifndef DCC_H
-#define DCC_H
- 
- /**
-  * Write debugging data. If a OpenOCD is connected via JTAG or SWD,
-  * data will be printed on the console
-  * \param str string, can also be not null terminated
-  * \param len string length
-  */
-void debugWrite(const char *str, unsigned int len);
- 
- /**
-  * Write debugging data from within an interrupt or with interrupts disabled.
-  * If a OpenOCD is connected via JTAG or SWD, data will be printed on the console
-  * \param str string, needs to be null terminated
-  */
-void IRQdebugWrite(const char *str);
-
-#endif //DCC_H
diff --git a/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/bsp_impl.h b/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/bsp_impl.h
index d290929a515115a96e2fc04d8a22aaac22bf4ede..f2a82c9087e17a230a91aa41d4646c9f7bdadfdb 100644
--- a/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/bsp_impl.h
+++ b/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/bsp_impl.h
@@ -60,13 +60,13 @@ inline void ledOff()
 }
 
 ///\internal Pin connected to SD card detect
-//TODO: no filesystem typedef Gpio<GPIOA_BASE,8> sdCardDetect;
+//no filesystem typedef Gpio<GPIOA_BASE,8> sdCardDetect;
 
 /**
  * Polls the SD card sense GPIO
  * \return true if there is an uSD card in the socket.
  */
-/*TODO: no filesystem
+/*no filesystem
 inline bool sdCardSense()
 {
     return sdCardDetect::value()==0;
diff --git a/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/console.cpp b/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/console.cpp
index fc7c3521124596b1182072143369bab6f4905bf3..43fad164e9ffaac70e3973483e5033e47c7f3043 100644
--- a/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/console.cpp
+++ b/miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery/interfaces-impl/console.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2010 by Terraneo Federico                               *
+ *   Copyright (C) 2010, 2011, 2012 by Terraneo Federico                   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
diff --git a/miosix/config/Makefile.inc b/miosix/config/Makefile.inc
index 4c719acf5666536532e45872629c56873e4a2ded..1b536101930b001d2ce2aaa36d76eab7022e8886 100644
--- a/miosix/config/Makefile.inc
+++ b/miosix/config/Makefile.inc
@@ -18,7 +18,7 @@ OPT_BOARD := stm32f103ze_stm3210e-eval
 #OPT_BOARD := stm32f100rb_stm32vldiscovery
 #OPT_BOARD := stm32f103ve_strive_mini
 #OPT_BOARD := stm32f103ze_redbull_v2
-àOPT_BOARD := stm32f407vg_stm32f4discovery
+#OPT_BOARD := stm32f407vg_stm32f4discovery
 
 ##
 ## Optimization flags, choose one.
@@ -143,6 +143,11 @@ endif
 ## a new board or porting Miosix to a new architecture                    ##
 ############################################################################
 
+ifneq ($(MAKEFILE_VERSION),1.01)
+    $(error You are using an incompatible makefile. Make sure it matches \
+      the one distributed with the current version of the kernel)
+endif
+
 ##
 ## First, auto guess architecture name from board name
 ##
@@ -183,6 +188,8 @@ CXXFLAGS_BASE := -D_MIOSIX=\"$(OPT_BOARD)\"
 ## ARCHITECTURE: arm7_lpc2000
 ##
 ifeq ($(ARCH),arm7_lpc2000)
+    ## Base directory with header files for this board
+    ARCH_INC := arch/arm7_lpc2000/common
 
     ##-------------------------------------------------------------------------
     ## BOARD: lpc2138_miosix_board
@@ -240,9 +247,6 @@ ifeq ($(ARCH),arm7_lpc2000)
                      -Wl,-T./miosix/$(LINKER_SCRIPT) $(OPT_EXCEPT)           \
                       $(OPT_OPTIMIZATION) -nostdlib
 
-    ## Base directory with header files for this board
-    ARCH_INC := arch/arm7_lpc2000/common
-
     ## Select architecture specific files
     ## These are the files in arch/<arch name>/common
     #ARCH_SRC += Nothing to add
@@ -257,6 +261,8 @@ ifeq ($(ARCH),arm7_lpc2000)
 ## ARCHITECTURE: cortexM3_stm32
 ##
 else ifeq ($(ARCH),cortexM3_stm32)
+    ## Base directory with header files for this board
+    ARCH_INC := arch/cortexM3_stm32/common
 
     ##-------------------------------------------------------------------------
     ## BOARD: stm32f103ze_stm3210e-eval
@@ -275,7 +281,7 @@ else ifeq ($(ARCH),cortexM3_stm32)
         ## These are the files in arch/<arch name>/<board name>
         ARCH_SRC :=                                  \
         $(BOARD_INC)/interfaces-impl/console.cpp     \
-        $(BOARD_INC)/interfaces-impl/disk.cpp        \
+        $(ARCH_INC)/interfaces-impl/disk.cpp         \
         $(BOARD_INC)/interfaces-impl/bsp.cpp
 
         ## Add a #define to allow querying board name
@@ -308,7 +314,7 @@ else ifeq ($(ARCH),cortexM3_stm32)
         ## These are the files in arch/<arch name>/<board name>
         ARCH_SRC :=                                  \
         $(BOARD_INC)/interfaces-impl/console.cpp     \
-        $(BOARD_INC)/interfaces-impl/disk.cpp        \
+        $(ARCH_INC)/interfaces-impl/disk.cpp         \
         $(BOARD_INC)/interfaces-impl/bsp.cpp
 
         ## Add a #define to allow querying board name
@@ -381,7 +387,7 @@ else ifeq ($(ARCH),cortexM3_stm32)
         ## These are the files in arch/<arch name>/<board name>
         ARCH_SRC :=                                  \
         $(BOARD_INC)/interfaces-impl/console.cpp     \
-        $(BOARD_INC)/interfaces-impl/disk.cpp        \
+        $(ARCH_INC)/interfaces-impl/disk.cpp         \
         $(BOARD_INC)/interfaces-impl/bsp.cpp
 
         ## Add a #define to allow querying board name
@@ -416,7 +422,7 @@ else ifeq ($(ARCH),cortexM3_stm32)
         ## These are the files in arch/<arch name>/<board name>
         ARCH_SRC :=                                  \
         $(BOARD_INC)/interfaces-impl/console.cpp     \
-        $(BOARD_INC)/interfaces-impl/disk.cpp        \
+        $(ARCH_INC)/interfaces-impl/disk.cpp         \
         $(BOARD_INC)/interfaces-impl/bsp.cpp
 
         ## Add a #define to allow querying board name
@@ -469,15 +475,12 @@ else ifeq ($(ARCH),cortexM3_stm32)
                      -Wl,-T./miosix/$(LINKER_SCRIPT) $(OPT_EXCEPT)           \
                      $(OPT_OPTIMIZATION) -nostdlib
 
-    ## Base directory with header files for this board
-    ARCH_INC := arch/cortexM3_stm32/common
-
     ## Select architecture specific files
     ## These are the files in arch/<arch name>/common
     ARCH_SRC +=                                  \
+    arch/common/drivers/dcc.cpp                  \
     $(ARCH_INC)/core/interrupts.cpp              \
     $(ARCH_INC)/drivers/serial.cpp               \
-    $(ARCH_INC)/drivers/dcc.cpp                  \
     $(ARCH_INC)/interfaces-impl/portability.cpp  \
     $(ARCH_INC)/interfaces-impl/delays.cpp       \
     $(ARCH_INC)/CMSIS/core_cm3.c                 \
@@ -487,6 +490,8 @@ else ifeq ($(ARCH),cortexM3_stm32)
 ## ARCHITECTURE: cortexM4_stm32
 ##
 else ifeq ($(ARCH),cortexM4_stm32)
+    ## Base directory with else header files for this board
+    ARCH_INC := arch/cortexM4_stm32/common
 
     ##-------------------------------------------------------------------------
     ## BOARD: stm32f4discovery
@@ -554,14 +559,11 @@ else ifeq ($(ARCH),cortexM4_stm32)
                      -Wl,-T./miosix/$(LINKER_SCRIPT) $(OPT_EXCEPT)           \
                      $(OPT_OPTIMIZATION) -nostdlib
 
-    ## Base directory with else header files for this board
-    ARCH_INC := arch/cortexM4_stm32/common
-
     ## Select architecture specific files
     ## These are the files in arch/<arch name>/common
     ARCH_SRC +=                                              \
+    arch/common/drivers/dcc.cpp                              \
     $(ARCH_INC)/core/interrupts.cpp                          \
-    $(ARCH_INC)/drivers/dcc.cpp                              \
     $(ARCH_INC)/interfaces-impl/portability.cpp              \
     $(ARCH_INC)/interfaces-impl/delays.cpp                   \
     $(ARCH_INC)/interfaces-impl/gpio_impl.cpp                \
diff --git a/miosix/config/miosix_settings.h b/miosix/config/miosix_settings.h
index d451d2b913f9e4f66d6c759f73e4f21f9adfccaf..879e4424ba23ff24ee989c90f4a4da29d74a0f90 100644
--- a/miosix/config/miosix_settings.h
+++ b/miosix/config/miosix_settings.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2008, 2009, 2010, 2011 by Terraneo Federico             *
+ *   Copyright (C) 2008, 2009, 2010, 2011, 2012 by Terraneo Federico       *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
diff --git a/miosix/doc/textdoc/Changelog.txt b/miosix/doc/textdoc/Changelog.txt
index b0fdb28751edf33d9fa75e8b284ed5e307a36f6a..d883c645d4cf975dea08ad067cafbd6fa84d0bf6 100644
--- a/miosix/doc/textdoc/Changelog.txt
+++ b/miosix/doc/textdoc/Changelog.txt
@@ -1,6 +1,14 @@
 Changelog for Miosix np embedded OS
 
+v1.60
+- Refactored the arch/ directory to avoid code duplication
+- Breaking change in the Makefiles
 v1.59
+- Added arch/cortexM4_stm32 architecture. The current GCC used to build Miosix
+  does not yet support the M4 but since the instruction set is backward
+  compatible the kernel is currently compiled with -mcpu=cortex-m3. This
+  means that floating point operations are still emulated in software, and will
+  be fixed when the compiler is upgraded.
 - Added a couple of examples, including one using BufferQueue to synchronize
   between a thread and a DMA.
 - Added test to testsuite for BufferQueue
diff --git a/miosix/doc/textdoc/Directories.txt b/miosix/doc/textdoc/Directories.txt
index 53105b93cff27f079309d112a3df2cee5872e1a0..586d283879ada2be902e10bb78a41392ad160134 100644
--- a/miosix/doc/textdoc/Directories.txt
+++ b/miosix/doc/textdoc/Directories.txt
@@ -1,53 +1,60 @@
 Miosix 1.50+ directory tree
+Directories marked with [x] contain code or configuration files that are used to
+build the kernel while directories marked with [ ] contain other stuff
+(documentation, examples).
 
-[ ] //Root directory, contains main.cpp and in general the application code
+[x] //Root directory, contains main.cpp and in general the application code
  |
- +--[ ] miosix //Contains all Miosix OS code
+ +--[x] miosix //Contains all Miosix OS code
      |
-     +--[ ] config //Contains arch-independent configuration files
+     +--[x] config //Contains arch-independent configuration files
      |
-     +--[ ] util //Contains utility code, architcture independent
+     +--[x] util //Contains utility code, architcture independent
      |
-     +--[ ] kernel //Contains the architecture independent kernel part
+     +--[x] kernel //Contains the architecture independent kernel part
      |   |
-     |   +--[ ] filesystem //filesystem code
+     |   +--[x] filesystem //Filesystem code
      |   |
-     |   +--[ ] schedulers //Contains the various schedulers
+     |   +--[x] schedulers //Contains the various schedulers
      |       |
-     |       +--[ ] priority
+     |       +--[x] priority
      |       |
-     |       +--[ ] control_based
+     |       +--[x] control_based
      |       |
-     |       +--[ ] edf
+     |       +--[x] edf
      |
      +--[ ] doc //Kernel documentation (doxygen + pdf + txt)
      |
-     +--[ ] interfaces //Contains interfaces between kernel and architecture
+     +--[x] interfaces //Contains interfaces between kernel and architecture
      |                 //dependent code
      |
-     +--[ ] arch //Contains architecture dependent code
+     +--[ ] compiler //Contains scripts used to build GCC with the patches
+     |               //required to compile the kernel
+     |
+     +--[ ] examples //Contains some example applications
+     |
+     +--[ ] testsuite //Contains the kernel testsuite
+     |
+     +--[ ] temp //Contains miscellaneous stuff
+     |
+     +--[ ] bootloaders //Contain custom bootloaders for some boards
+     |
+     +--[x] arch //Contains architecture dependent code
+         |
+         +--[x] common //Contains drivers that are usable across multiple arch
          |
-         +--[ ] arm7_lpc2000 //Name of folder is 'cpu model' + 'mcu family'
+         +--[x] arm7_lpc2000 //Name of folder is 'cpu model' + 'mcu family'
          |   |
-         |   +--[ ] common //Common code for this architecture
+         |   +--[x] common //Common code for this architecture
          |   |
-         |   +--[ ] lpc2138_miosix_board //Name is 'chip name'+'_'+'board name'
+         |   +--[x] lpc2138_miosix_board //Name is 'chip name'+'_'+'board name'
          |       |
-         |       +--[ ] interfaces-impl //Implmentation of miosix/interfaces
+         |       +--[x] interfaces-impl //Implmentation of miosix/interfaces
          |       |
-         |       +--[ ] drivers //Serial ports, board support package, etc.
+         |       +--[x] drivers //Serial ports, board support package, etc.
          |       |
-         |       +--[ ] core //Boot and exception handling code
+         |       +--[x] core //Boot and exception handling code
          |
-         +--[ ] cortexM3_stm32
-             |
-             +--[ ] common
-             |
-             +--[ ] stm32f103ze_stm3210e-eval
-                 |
-                 +--[ ] interfaces-impl
-                 |
-                 +--[ ] drivers
-                 |
-                 +--[ ] core
-      
\ No newline at end of file
+         .
+         .  Other target architectures
+         .
diff --git a/miosix/examples/sad_trombone/Makefile b/miosix/examples/sad_trombone/Makefile
index 2da45e6fa530e5e999cc5a636a585a46860395d8..9b484b4da268f9aa561a5e9c3f78b365117e79e3 100644
--- a/miosix/examples/sad_trombone/Makefile
+++ b/miosix/examples/sad_trombone/Makefile
@@ -2,6 +2,7 @@
 ## Makefile for Miosix np embedded OS
 ## TFT:Terraneo Federico Technlogies
 ##
+MAKEFILE_VERSION := 1.01
 include miosix/config/Makefile.inc
 
 ##
@@ -33,15 +34,15 @@ INCLUDE_DIRS :=
 OBJ := $(addsuffix .o, $(basename $(SRC)))
 
 ## Includes the miosix base directory for C/C++
-CXXFLAGS  := $(CXXFLAGS_BASE) -I. -I./miosix -I./miosix/$(ARCH_INC) \
-             -I./miosix/$(BOARD_INC) $(INCLUDE_DIRS)
-CFLAGS    := $(CFLAGS_BASE)   -I. -I./miosix -I./miosix/$(ARCH_INC) \
-             -I./miosix/$(BOARD_INC) $(INCLUDE_DIRS)
+CXXFLAGS  := $(CXXFLAGS_BASE) -I. -Imiosix -Imiosix/arch/common \
+             -Imiosix/$(ARCH_INC) -Imiosix/$(BOARD_INC) $(INCLUDE_DIRS)
+CFLAGS    := $(CFLAGS_BASE)   -I. -Imiosix -Imiosix/arch/common \
+             -Imiosix/$(ARCH_INC) -Imiosix/$(BOARD_INC) $(INCLUDE_DIRS)
 AFLAGS    := $(AFLAGS_BASE)
 LFLAGS    := $(LFLAGS_BASE)
 
-LINK_LIBS := $(LIBS) -Wl,--start-group -L./miosix -lmiosix -lstdc++ -lc -lm \
-    -lg -lgcc -Wl,--end-group
+LINK_LIBS := $(LIBS) -L./miosix -Wl,--start-group -lmiosix -lstdc++ -lc -lm \
+    -lgcc -Wl,--end-group
 
 all: all-recursive main
 
@@ -70,8 +71,7 @@ main: main.elf
 
 main.elf: $(OBJ) miosix/libmiosix.a
 	@ echo "linking"
-	$(CXX) $(LFLAGS) -o main.elf $(OBJ) miosix/$(BOOT_FILE) \
-	miosix/kernel/syscalls.o $(LINK_LIBS)
+	$(CXX) $(LFLAGS) -o main.elf $(OBJ) miosix/$(BOOT_FILE) $(LINK_LIBS)
 
 %.o: %.s
 	$(AS) $(AFLAGS) $< -o $@
diff --git a/miosix/testsuite/testsuite.cpp b/miosix/testsuite/testsuite.cpp
index 5075d55f8dfe52964417a4822ab2934c63e5d0b7..4a288cf80752d0ce5224271e6ae4b43fe8503167 100644
--- a/miosix/testsuite/testsuite.cpp
+++ b/miosix/testsuite/testsuite.cpp
@@ -2963,7 +2963,7 @@ static void benchmark_1()
     t.start();
     extern unsigned long _data asm("_data");
     char *data=reinterpret_cast<char*>(&_data);
-    #ifdef _ARCH_CORTEXM3_STM32
+    #if defined(_ARCH_CORTEXM3_STM32) || defined(_ARCH_CORTEXM4_STM32)
     memDump(data,2048);
     t.stop();
     //every line dumps 16 bytes, and is 81 char long (considering \r\n)
@@ -2981,7 +2981,7 @@ static void benchmark_1()
             t.interval()*1000)/TICK_FREQ);
     unsigned int baudrate=165888*10000/((t.interval()*1000)/TICK_FREQ);
     iprintf("Effective baud rate =%u\n",baudrate);
-    #endif //_ARCH_CORTEXM3_STM32
+    #endif //_ARCH_CORTEXM3_STM32 || _ARCH_CORTEXM4_STM32
 }
 
 //
diff --git a/miosix/util/version.cpp b/miosix/util/version.cpp
index f59c4e058a3f6389a10437b90ffb3ef9adce7b4b..747097702db88783daeabd1e28eb76db65ddba8b 100644
--- a/miosix/util/version.cpp
+++ b/miosix/util/version.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2010, 2011 by Terraneo Federico                         *
+ *   Copyright (C) 2010, 2011, 2012 by Terraneo Federico                   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -37,7 +37,7 @@ namespace miosix {
 #define AU
 #endif
 
-const char AU ver[]="Miosix v1.59 (" _MIOSIX ", " __DATE__ " " __TIME__ CV ")";
+const char AU ver[]="Miosix v1.60 (" _MIOSIX ", " __DATE__ " " __TIME__ CV ")";
 
 const char *getMiosixVersion()
 {
diff --git a/miosix_np_2/nbproject/configurations.xml b/miosix_np_2/nbproject/configurations.xml
index 8e1a4edea8b146fa0628279f167a2ff88dfc3d6f..d27495a61bccaac30109b2bc88171727433bfa77 100644
--- a/miosix_np_2/nbproject/configurations.xml
+++ b/miosix_np_2/nbproject/configurations.xml
@@ -36,6 +36,12 @@
               <in>board_settings.h</in>
             </df>
           </df>
+          <df name="common">
+            <df name="drivers">
+              <in>dcc.cpp</in>
+              <in>dcc.h</in>
+            </df>
+          </df>
           <df name="cortexM3_stm32">
             <df name="common">
               <df name="CMSIS">
@@ -50,14 +56,13 @@
                 <in>interrupts.h</in>
               </df>
               <df name="drivers">
-                <in>dcc.cpp</in>
-                <in>dcc.h</in>
                 <in>serial.cpp</in>
                 <in>serial.h</in>
               </df>
               <df name="interfaces-impl">
                 <in>arch_registers_impl.h</in>
                 <in>delays.cpp</in>
+                <in>disk.cpp</in>
                 <in>endianness_impl.h</in>
                 <in>gpio_impl.h</in>
                 <in>portability.cpp</in>
@@ -84,7 +89,6 @@
                 <in>bsp.cpp</in>
                 <in>bsp_impl.h</in>
                 <in>console.cpp</in>
-                <in>disk.cpp</in>
                 <in>hwmapping.h</in>
               </df>
               <in>board_settings.h</in>
@@ -97,7 +101,6 @@
                 <in>bsp.cpp</in>
                 <in>bsp_impl.h</in>
                 <in>console.cpp</in>
-                <in>disk.cpp</in>
                 <in>hwmapping.h</in>
               </df>
               <in>board_settings.h</in>
@@ -110,7 +113,6 @@
                 <in>bsp.cpp</in>
                 <in>bsp_impl.h</in>
                 <in>console.cpp</in>
-                <in>disk.cpp</in>
                 <in>hwmapping.h</in>
               </df>
               <in>board_settings.h</in>
@@ -123,7 +125,6 @@
                 <in>bsp.cpp</in>
                 <in>bsp_impl.h</in>
                 <in>console.cpp</in>
-                <in>disk.cpp</in>
               </df>
               <in>board_settings.h</in>
             </df>
@@ -132,11 +133,19 @@
             <df name="common">
               <df name="CMSIS">
                 <df name="Documentation">
+                  <in>CMSIS-SVD_Schema_1_0.xsd</in>
+                  <in>CMSIS_CM4_SIMD.htm</in>
+                  <in>CMSIS_Core.htm</in>
+                  <in>CMSIS_DebugSupport.htm</in>
+                  <in>CMSIS_History.htm</in>
+                  <in>CMSIS_Logo_Final.jpg</in>
+                  <in>CMSIS_System_View_Description.htm</in>
                 </df>
                 <in>core_cm4.h</in>
                 <in>core_cm4_simd.h</in>
                 <in>core_cmFunc.h</in>
                 <in>core_cmInstr.h</in>
+                <in>index.htm</in>
                 <in>stm32f4xx.h</in>
                 <in>system_stm32f4xx.c</in>
                 <in>system_stm32f4xx.h</in>
@@ -146,8 +155,6 @@
                 <in>interrupts.h</in>
               </df>
               <df name="drivers">
-                <in>dcc.cpp</in>
-                <in>dcc.h</in>
               </df>
               <df name="interfaces-impl">
                 <in>arch_registers_impl.h</in>
@@ -171,6 +178,9 @@
                 <in>console.cpp</in>
               </df>
               <in>board_settings.h</in>
+              <in>stm32_1m+192k_ram.ld</in>
+              <in>stm32_1m+192k_rom.ld</in>
+              <in>stm32f4discovery.cfg</in>
             </df>
           </df>
         </df>
@@ -272,7 +282,6 @@
       <df name="miosix_np_2">
       </df>
       <in>main.cpp</in>
-      <in>testsuite.cpp</in>
     </df>
     <logicalFolder name="ExternalFiles"
                    displayName="Important Files"
@@ -302,8 +311,11 @@
             <incDir>
               <pElem>..</pElem>
               <pElem>../miosix</pElem>
+              <pElem>../miosix/arch/common</pElem>
               <pElem>../miosix/arch/cortexM3_stm32/common</pElem>
               <pElem>../miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval</pElem>
+              <pElem>../miosix/arch/cortexM4_stm32/common</pElem>
+              <pElem>../miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery</pElem>
               <pElem>../miosix/arch/arm7_lpc2000/common</pElem>
               <pElem>../miosix/arch/arm7_lpc2000/lpc2138_miosix_board</pElem>
             </incDir>
@@ -316,8 +328,11 @@
             <incDir>
               <pElem>..</pElem>
               <pElem>../miosix</pElem>
+              <pElem>../miosix/arch/common</pElem>
               <pElem>../miosix/arch/cortexM3_stm32/common</pElem>
               <pElem>../miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval</pElem>
+              <pElem>../miosix/arch/cortexM4_stm32/common</pElem>
+              <pElem>../miosix/arch/cortexM4_stm32/stm32f407vg_stm32f4discovery</pElem>
               <pElem>../miosix/arch/arm7_lpc2000/common</pElem>
               <pElem>../miosix/arch/arm7_lpc2000/lpc2138_miosix_board</pElem>
             </incDir>
diff --git a/miosix_np_2/nbproject/private/configurations.xml b/miosix_np_2/nbproject/private/configurations.xml
index ceed23356da1cb8dcffeb4a5ed02c74315d8ac50..20f1d270a8caf82d9e288f7b45572454f4be2ff8 100644
--- a/miosix_np_2/nbproject/private/configurations.xml
+++ b/miosix_np_2/nbproject/private/configurations.xml
@@ -20,6 +20,7 @@
         <gdb_buildfirst gdb_buildfirst_overriden="false" gdb_buildfirst_old="false"/>
       </dbx_gdbdebugger>
       <gizmo_options version="3">
+        <configurationname>GizmoSimple</configurationname>
       </gizmo_options>
       <nativedebugger version="1">
         <engine>gdb</engine>