OSDN Git Service

Fixed the SPI control.
authorShinichiro Nakamura <shinta.main.jp@gmail.com>
Fri, 13 Jul 2012 21:49:55 +0000 (06:49 +0900)
committerShinichiro Nakamura <shinta.main.jp@gmail.com>
Fri, 13 Jul 2012 21:49:55 +0000 (06:49 +0900)
firm/sample/sample1/os/mmc.c

index 4a2d4aa..294cb1a 100644 (file)
@@ -1,35 +1,29 @@
-/*------------------------------------------------------------------------/\r
-/  Bitbanging MMCv3/SDv1/SDv2 (in SPI mode) control module for PFF\r
-/-------------------------------------------------------------------------/\r
-/\r
-/  Copyright (C) 2010, ChaN, all right reserved.\r
-/\r
-/ * This software is a free software and there is NO WARRANTY.\r
-/ * No restriction on use. You can use, modify and redistribute it for\r
-/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.\r
-/ * Redistributions of source code must retain the above copyright notice.\r
-/\r
-/--------------------------------------------------------------------------/\r
- Features:\r
-\r
- * Very Easy to Port\r
  It uses only 4-6 bit of GPIO port. No interrupt, no SPI port is used.\r
-\r
- * Platform Independent\r
  You need to modify only a few macros to control GPIO ports.\r
-\r
-/-------------------------------------------------------------------------*/\r
-\r
+/* ------------------------------------------------------------------------\r
+ *  Bitbanging MMCv3/SDv1/SDv2 (in SPI mode) control module for PFF\r
+ * ------------------------------------------------------------------------\r
+ *\r
+ *  Copyright (C) 2010, ChaN, all right reserved.\r
+ *\r
+ * * This software is a free software and there is NO WARRANTY.\r
+ * * No restriction on use. You can use, modify and redistribute it for\r
+ *   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.\r
+ * * Redistributions of source code must retain the above copyright notice.\r
+ *\r
+ * ------------------------------------------------------------------------\r
Features:\r
+ *\r
+ * Very Easy to Port\r
* It uses only 4-6 bit of GPIO port. No interrupt, no SPI port is used.\r
+ *\r
+ * Platform Independent\r
* You need to modify only a few macros to control GPIO ports.\r
+ *\r
+ * ------------------------------------------------------------------------\r
+ */\r
 \r
 #include "diskio.h"\r
-\r
-#define H8_3069F_P4DR   ((volatile uint8 *)0xFFFFD3)\r
-#define H8_3069F_PBDR   ((volatile uint8 *)0xFFFFDA)\r
-\r
-#define PB_BIT_SCLK     (1 << 5)\r
-#define PB_BIT_MOSI     (1 << 6)\r
-#define PB_BIT_MISO     (1 << 7)\r
-#define P4_BIT_CS       (1 << 0)\r
+#include "portconf.h"\r
+#include "spi.h"\r
 \r
 /*-------------------------------------------------------------------------*/\r
 /* Platform dependent macros and functions needed to be modified           */\r
 #define DLY_US(n)      do { volatile uint32 dlycnt; for (dlycnt = 0; dlycnt < (n) * 10; dlycnt++) {} } while (0)    /* Delay n microseconds */\r
 #define FORWARD(d)     do { } while (0)    /* Data in-time processing function (depends on the project) */\r
 \r
-#define CS_H()         do { *H8_3069F_P4DR |=  P4_BIT_CS; } while (0)      /* Set MMC CS "high" */\r
-#define CS_L()         do { *H8_3069F_P4DR &= ~P4_BIT_CS; } while (0)      /* Set MMC CS "low" */\r
-#define CK_H()         do { *H8_3069F_PBDR |=  PB_BIT_SCLK; } while (0)    /* Set MMC SCLK "high" */\r
-#define CK_L()         do { *H8_3069F_PBDR &= ~PB_BIT_SCLK; } while (0)    /* Set MMC SCLK "low" */\r
-#define DI_H()         do { *H8_3069F_PBDR |=  PB_BIT_MOSI; } while (0)    /* Set MMC DI "high" */\r
-#define DI_L()         do { *H8_3069F_PBDR &= ~PB_BIT_MOSI; } while (0)    /* Set MMC DI "low" */\r
-#define DO             ((*H8_3069F_PBDR & PB_BIT_MISO) ? 1 : 0)            /* Get MMC DO value (high:true, low:false) */\r
-\r
-\r
 /*--------------------------------------------------------------------------\r
-\r
-   Module Private Functions\r
-\r
----------------------------------------------------------------------------*/\r
+  Module Private Functions\r
+  ---------------------------------------------------------------------------*/\r
 \r
 /* Definitions for MMC/SDC command */\r
 #define CMD0   (0x40+0)        /* GO_IDLE_STATE */\r
 #define CMD1   (0x40+1)        /* SEND_OP_COND (MMC) */\r
-#define        ACMD41  (0xC0+41)       /* SEND_OP_COND (SDC) */\r
+#define ACMD41 (0xC0+41)       /* SEND_OP_COND (SDC) */\r
 #define CMD8   (0x40+8)        /* SEND_IF_COND */\r
 #define CMD16  (0x40+16)       /* SET_BLOCKLEN */\r
 #define CMD17  (0x40+17)       /* READ_SINGLE_BLOCK */\r
 #define CT_SDC                         (CT_SD1|CT_SD2) /* SD */\r
 #define CT_BLOCK                       0x08    /* Block addressing */\r
 \r
-\r
-\r
-static\r
-BYTE CardType;                 /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */\r
-\r
-\r
-\r
-/*-----------------------------------------------------------------------*/\r
-/* Transmit a byte to the MMC (bitbanging)                               */\r
-/*-----------------------------------------------------------------------*/\r
-\r
-static\r
-void xmit_mmc (\r
-       BYTE d                  /* Data to be sent */\r
-)\r
-{\r
-       if (d & 0x80) DI_H(); else DI_L();      /* bit7 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x40) DI_H(); else DI_L();      /* bit6 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x20) DI_H(); else DI_L();      /* bit5 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x10) DI_H(); else DI_L();      /* bit4 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x08) DI_H(); else DI_L();      /* bit3 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x04) DI_H(); else DI_L();      /* bit2 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x02) DI_H(); else DI_L();      /* bit1 */\r
-       CK_H(); CK_L();\r
-       if (d & 0x01) DI_H(); else DI_L();      /* bit0 */\r
-       CK_H(); CK_L();\r
-}\r
-\r
-\r
-\r
-/*-----------------------------------------------------------------------*/\r
-/* Receive a byte from the MMC (bitbanging)                              */\r
-/*-----------------------------------------------------------------------*/\r
-\r
-static\r
-BYTE rcvr_mmc (void)\r
-{\r
-       BYTE r;\r
-\r
-\r
-       DI_H(); /* Send 0xFF */\r
-\r
-       r = 0;   if (DO) r++;   /* bit7 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit6 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit5 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit4 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit3 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit2 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit1 */\r
-       CK_H(); CK_L();\r
-       r <<= 1; if (DO) r++;   /* bit0 */\r
-       CK_H(); CK_L();\r
-\r
-       return r;\r
-}\r
-\r
-\r
+static BYTE CardType;                  /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */\r
 \r
 /*-----------------------------------------------------------------------*/\r
 /* Skip bytes on the MMC (bitbanging)                                    */\r
 /*-----------------------------------------------------------------------*/\r
 \r
-static\r
-void skip_mmc (\r
-       WORD n          /* Number of bytes to skip */\r
-)\r
+/* Number of bytes to skip */\r
+static void skip_mmc(WORD n)\r
 {\r
-       DI_H(); /* Send 0xFF */\r
-\r
-       do {\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-               CK_H(); CK_L();\r
-       } while (--n);\r
+    do {\r
+        spi_rx();\r
+    } while (--n);\r
 }\r
 \r
-\r
-\r
 /*-----------------------------------------------------------------------*/\r
 /* Deselect the card and release SPI bus                                 */\r
 /*-----------------------------------------------------------------------*/\r
 \r
-static\r
-void release_spi (void)\r
+static void release_spi(void)\r
 {\r
-       CS_H();\r
-       rcvr_mmc();\r
+    spi_deselect();\r
+    spi_rx();\r
 }\r
 \r
 \r
@@ -183,52 +84,52 @@ void release_spi (void)
 /* Send a command packet to MMC                                          */\r
 /*-----------------------------------------------------------------------*/\r
 \r
-static\r
+    static\r
 BYTE send_cmd (\r
-       BYTE cmd,               /* Command byte */\r
-       DWORD arg               /* Argument */\r
-)\r
+        BYTE cmd,              /* Command byte */\r
+        DWORD arg              /* Argument */\r
+        )\r
 {\r
-       BYTE n, res;\r
-\r
-\r
-       if (cmd & 0x80) {       /* ACMD<n> is the command sequense of CMD55-CMD<n> */\r
-               cmd &= 0x7F;\r
-               res = send_cmd(CMD55, 0);\r
-               if (res > 1) return res;\r
-       }\r
-\r
-       /* Select the card */\r
-       CS_H(); rcvr_mmc();\r
-       CS_L(); rcvr_mmc();\r
-\r
-       /* Send a command packet */\r
-       xmit_mmc(cmd);                                  /* Start + Command index */\r
-       xmit_mmc((BYTE)(arg >> 24));    /* Argument[31..24] */\r
-       xmit_mmc((BYTE)(arg >> 16));    /* Argument[23..16] */\r
-       xmit_mmc((BYTE)(arg >> 8));             /* Argument[15..8] */\r
-       xmit_mmc((BYTE)arg);                    /* Argument[7..0] */\r
-       n = 0x01;                                               /* Dummy CRC + Stop */\r
-       if (cmd == CMD0) n = 0x95;              /* Valid CRC for CMD0(0) */\r
-       if (cmd == CMD8) n = 0x87;              /* Valid CRC for CMD8(0x1AA) */\r
-       xmit_mmc(n);\r
-\r
-       /* Receive a command response */\r
-       n = 10;                                                         /* Wait for a valid response in timeout of 10 attempts */\r
-       do {\r
-               res = rcvr_mmc();\r
-       } while ((res & 0x80) && --n);\r
-\r
-       return res;                     /* Return with the response value */\r
+    BYTE n, res;\r
+\r
+\r
+    if (cmd & 0x80) {  /* ACMD<n> is the command sequense of CMD55-CMD<n> */\r
+        cmd &= 0x7F;\r
+        res = send_cmd(CMD55, 0);\r
+        if (res > 1) return res;\r
+    }\r
+\r
+    /* Select the card */\r
+    spi_deselect(); spi_rx();\r
+    spi_select(SpiTarget_SDCARD); spi_rx();\r
+\r
+    /* Send a command packet */\r
+    spi_tx(cmd);                                       /* Start + Command index */\r
+    spi_tx((BYTE)(arg >> 24)); /* Argument[31..24] */\r
+    spi_tx((BYTE)(arg >> 16)); /* Argument[23..16] */\r
+    spi_tx((BYTE)(arg >> 8));          /* Argument[15..8] */\r
+    spi_tx((BYTE)arg);                 /* Argument[7..0] */\r
+    n = 0x01;                                          /* Dummy CRC + Stop */\r
+    if (cmd == CMD0) n = 0x95;         /* Valid CRC for CMD0(0) */\r
+    if (cmd == CMD8) n = 0x87;         /* Valid CRC for CMD8(0x1AA) */\r
+    spi_tx(n);\r
+\r
+    /* Receive a command response */\r
+    n = 10;                                                            /* Wait for a valid response in timeout of 10 attempts */\r
+    do {\r
+        res = spi_rx();\r
+    } while ((res & 0x80) && --n);\r
+\r
+    return res;                        /* Return with the response value */\r
 }\r
 \r
 \r
 \r
 /*--------------------------------------------------------------------------\r
 \r
-   Public Functions\r
+  Public Functions\r
 \r
----------------------------------------------------------------------------*/\r
+  ---------------------------------------------------------------------------*/\r
 \r
 \r
 /*-----------------------------------------------------------------------*/\r
@@ -237,47 +138,46 @@ BYTE send_cmd (
 \r
 DSTATUS disk_initialize (void)\r
 {\r
-       BYTE n, cmd, ty, buf[4];\r
-       UINT tmr;\r
-\r
-\r
-       INIT_PORT();\r
-\r
-       CS_H();\r
-       skip_mmc(10);                   /* Dummy clocks */\r
-\r
-       ty = 0;\r
-       if (send_cmd(CMD0, 0) == 1) {                   /* Enter Idle state */\r
-               if (send_cmd(CMD8, 0x1AA) == 1) {       /* SDv2 */\r
-                       for (n = 0; n < 4; n++) buf[n] = rcvr_mmc();    /* Get trailing return value of R7 resp */\r
-                       if (buf[2] == 0x01 && buf[3] == 0xAA) {                 /* The card can work at vdd range of 2.7-3.6V */\r
-                               for (tmr = 1000; tmr; tmr--) {                          /* Wait for leaving idle state (ACMD41 with HCS bit) */\r
-                                       if (send_cmd(ACMD41, 1UL << 30) == 0) break;\r
-                                       DLY_US(1000);\r
-                               }\r
-                               if (tmr && send_cmd(CMD58, 0) == 0) {           /* Check CCS bit in the OCR */\r
-                                       for (n = 0; n < 4; n++) buf[n] = rcvr_mmc();\r
-                                       ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;      /* SDv2 (HC or SC) */\r
-                               }\r
-                       }\r
-               } else {                                                        /* SDv1 or MMCv3 */\r
-                       if (send_cmd(ACMD41, 0) <= 1)   {\r
-                               ty = CT_SD1; cmd = ACMD41;      /* SDv1 */\r
-                       } else {\r
-                               ty = CT_MMC; cmd = CMD1;        /* MMCv3 */\r
-                       }\r
-                       for (tmr = 1000; tmr; tmr--) {                  /* Wait for leaving idle state */\r
-                               if (send_cmd(ACMD41, 0) == 0) break;\r
-                               DLY_US(1000);\r
-                       }\r
-                       if (!tmr || send_cmd(CMD16, 512) != 0)                  /* Set R/W block length to 512 */\r
-                               ty = 0;\r
-               }\r
-       }\r
-       CardType = ty;\r
-       release_spi();\r
-\r
-       return ty ? 0 : STA_NOINIT;\r
+    BYTE n, cmd, ty, buf[4];\r
+    UINT tmr;\r
+\r
+    INIT_PORT();\r
+\r
+    spi_deselect();\r
+    skip_mmc(10);                      /* Dummy clocks */\r
+\r
+    ty = 0;\r
+    if (send_cmd(CMD0, 0) == 1) {                      /* Enter Idle state */\r
+        if (send_cmd(CMD8, 0x1AA) == 1) {      /* SDv2 */\r
+            for (n = 0; n < 4; n++) buf[n] = spi_rx(); /* Get trailing return value of R7 resp */\r
+            if (buf[2] == 0x01 && buf[3] == 0xAA) {                    /* The card can work at vdd range of 2.7-3.6V */\r
+                for (tmr = 1000; tmr; tmr--) {                         /* Wait for leaving idle state (ACMD41 with HCS bit) */\r
+                    if (send_cmd(ACMD41, 1UL << 30) == 0) break;\r
+                    DLY_US(1000);\r
+                }\r
+                if (tmr && send_cmd(CMD58, 0) == 0) {          /* Check CCS bit in the OCR */\r
+                    for (n = 0; n < 4; n++) buf[n] = spi_rx();\r
+                    ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */\r
+                }\r
+            }\r
+        } else {                                                       /* SDv1 or MMCv3 */\r
+            if (send_cmd(ACMD41, 0) <= 1)      {\r
+                ty = CT_SD1; cmd = ACMD41;     /* SDv1 */\r
+            } else {\r
+                ty = CT_MMC; cmd = CMD1;       /* MMCv3 */\r
+            }\r
+            for (tmr = 1000; tmr; tmr--) {                     /* Wait for leaving idle state */\r
+                if (send_cmd(ACMD41, 0) == 0) break;\r
+                DLY_US(1000);\r
+            }\r
+            if (!tmr || send_cmd(CMD16, 512) != 0)                     /* Set R/W block length to 512 */\r
+                ty = 0;\r
+        }\r
+    }\r
+    CardType = ty;\r
+    release_spi();\r
+\r
+    return ty ? 0 : STA_NOINIT;\r
 }\r
 \r
 \r
@@ -287,56 +187,56 @@ DSTATUS disk_initialize (void)
 /*-----------------------------------------------------------------------*/\r
 \r
 DRESULT disk_readp (\r
-       BYTE *buff,             /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */\r
-       DWORD lba,              /* Sector number (LBA) */\r
-       WORD ofs,               /* Byte offset to read from (0..511) */\r
-       WORD cnt                /* Number of bytes to read (ofs + cnt mus be <= 512) */\r
-)\r
+        BYTE *buff,            /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */\r
+        DWORD lba,             /* Sector number (LBA) */\r
+        WORD ofs,              /* Byte offset to read from (0..511) */\r
+        WORD cnt               /* Number of bytes to read (ofs + cnt mus be <= 512) */\r
+        )\r
 {\r
-       DRESULT res;\r
-       BYTE d;\r
-       WORD bc, tmr;\r
+    DRESULT res;\r
+    BYTE d;\r
+    WORD bc, tmr;\r
 \r
 \r
-       if (!(CardType & CT_BLOCK)) lba *= 512;         /* Convert to byte address if needed */\r
+    if (!(CardType & CT_BLOCK)) lba *= 512;            /* Convert to byte address if needed */\r
 \r
-       res = RES_ERROR;\r
-       if (send_cmd(CMD17, lba) == 0) {                /* READ_SINGLE_BLOCK */\r
+    res = RES_ERROR;\r
+    if (send_cmd(CMD17, lba) == 0) {           /* READ_SINGLE_BLOCK */\r
 \r
-               tmr = 1000;\r
-               do {                                                    /* Wait for data packet in timeout of 100ms */\r
-                       DLY_US(100);\r
-                       d = rcvr_mmc();\r
-               } while (d == 0xFF && --tmr);\r
+        tmr = 1000;\r
+        do {                                                   /* Wait for data packet in timeout of 100ms */\r
+            DLY_US(100);\r
+            d = spi_rx();\r
+        } while (d == 0xFF && --tmr);\r
 \r
-               if (d == 0xFE) {                                /* A data packet arrived */\r
-                       bc = 514 - ofs - cnt;\r
+        if (d == 0xFE) {                               /* A data packet arrived */\r
+            bc = 514 - ofs - cnt;\r
 \r
-                       /* Skip leading bytes */\r
-                       if (ofs) skip_mmc(ofs);\r
+            /* Skip leading bytes */\r
+            if (ofs) skip_mmc(ofs);\r
 \r
-                       /* Receive a part of the sector */\r
-                       if (buff) {     /* Store data to the memory */\r
-                               do\r
-                                       *buff++ = rcvr_mmc();\r
-                               while (--cnt);\r
-                       } else {        /* Forward data to the outgoing stream */\r
-                               do {\r
-                                       d = rcvr_mmc();\r
-                                       FORWARD(d);\r
-                               } while (--cnt);\r
-                       }\r
+            /* Receive a part of the sector */\r
+            if (buff) {        /* Store data to the memory */\r
+                do\r
+                    *buff++ = spi_rx();\r
+                while (--cnt);\r
+            } else {   /* Forward data to the outgoing stream */\r
+                do {\r
+                    d = spi_rx();\r
+                    FORWARD(d);\r
+                } while (--cnt);\r
+            }\r
 \r
-                       /* Skip trailing bytes and CRC */\r
-                       skip_mmc(bc);\r
+            /* Skip trailing bytes and CRC */\r
+            skip_mmc(bc);\r
 \r
-                       res = RES_OK;\r
-               }\r
-       }\r
+            res = RES_OK;\r
+        }\r
+    }\r
 \r
-       release_spi();\r
+    release_spi();\r
 \r
-       return res;\r
+    return res;\r
 }\r
 \r
 \r
@@ -347,44 +247,44 @@ DRESULT disk_readp (
 #if _USE_WRITE\r
 \r
 DRESULT disk_writep (\r
-       const BYTE *buff,       /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */\r
-       DWORD sa                        /* Number of bytes to send, Sector number (LBA) or zero */\r
-)\r
+        const BYTE *buff,      /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */\r
+        DWORD sa                       /* Number of bytes to send, Sector number (LBA) or zero */\r
+        )\r
 {\r
-       DRESULT res;\r
-       WORD bc, tmr;\r
-       static WORD wc;\r
-\r
-\r
-       res = RES_ERROR;\r
-\r
-       if (buff) {             /* Send data bytes */\r
-               bc = (WORD)sa;\r
-               while (bc && wc) {              /* Send data bytes to the card */\r
-                       xmit_mmc(*buff++);\r
-                       wc--; bc--;\r
-               }\r
-               res = RES_OK;\r
-       } else {\r
-               if (sa) {       /* Initiate sector write process */\r
-                       if (!(CardType & CT_BLOCK)) sa *= 512;  /* Convert to byte address if needed */\r
-                       if (send_cmd(CMD24, sa) == 0) {                 /* WRITE_SINGLE_BLOCK */\r
-                               xmit_mmc(0xFF); xmit_mmc(0xFE);         /* Data block header */\r
-                               wc = 512;                                                       /* Set byte counter */\r
-                               res = RES_OK;\r
-                       }\r
-               } else {        /* Finalize sector write process */\r
-                       bc = wc + 2;\r
-                       while (bc--) xmit_mmc(0);       /* Fill left bytes and CRC with zeros */\r
-                       if ((rcvr_mmc() & 0x1F) == 0x05) {      /* Receive data resp and wait for end of write process in timeout of 300ms */\r
-                               for (tmr = 10000; rcvr_mmc() != 0xFF && tmr; tmr--)     /* Wait for ready (max 1000ms) */\r
-                                       DLY_US(100);\r
-                               if (tmr) res = RES_OK;\r
-                       }\r
-                       release_spi();\r
-               }\r
-       }\r
-\r
-       return res;\r
+    DRESULT res;\r
+    WORD bc, tmr;\r
+    static WORD wc;\r
+\r
+\r
+    res = RES_ERROR;\r
+\r
+    if (buff) {                /* Send data bytes */\r
+        bc = (WORD)sa;\r
+        while (bc && wc) {             /* Send data bytes to the card */\r
+            spi_tx(*buff++);\r
+            wc--; bc--;\r
+        }\r
+        res = RES_OK;\r
+    } else {\r
+        if (sa) {      /* Initiate sector write process */\r
+            if (!(CardType & CT_BLOCK)) sa *= 512;     /* Convert to byte address if needed */\r
+            if (send_cmd(CMD24, sa) == 0) {                    /* WRITE_SINGLE_BLOCK */\r
+                spi_tx(0xFF); spi_tx(0xFE);            /* Data block header */\r
+                wc = 512;                                                      /* Set byte counter */\r
+                res = RES_OK;\r
+            }\r
+        } else {       /* Finalize sector write process */\r
+            bc = wc + 2;\r
+            while (bc--) spi_tx(0);    /* Fill left bytes and CRC with zeros */\r
+            if ((spi_rx() & 0x1F) == 0x05) {   /* Receive data resp and wait for end of write process in timeout of 300ms */\r
+                for (tmr = 10000; spi_rx() != 0xFF && tmr; tmr--)      /* Wait for ready (max 1000ms) */\r
+                    DLY_US(100);\r
+                if (tmr) res = RES_OK;\r
+            }\r
+            release_spi();\r
+        }\r
+    }\r
+\r
+    return res;\r
 }\r
 #endif\r