Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
FatFS/diskio.cpp@0:f24ba3a89ec1, 2015-09-30 (annotated)
- Committer:
- danghuutoan
- Date:
- Wed Sep 30 10:12:16 2015 +0000
- Revision:
- 0:f24ba3a89ec1
read and write file successfully
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| danghuutoan | 0:f24ba3a89ec1 | 1 | /*------------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 2 | /* STM32F100: MMCv3/SDv1/SDv2 (SPI mode) control module */ |
| danghuutoan | 0:f24ba3a89ec1 | 3 | /*------------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 4 | /* |
| danghuutoan | 0:f24ba3a89ec1 | 5 | / Copyright (C) 2014, ChaN, all right reserved. |
| danghuutoan | 0:f24ba3a89ec1 | 6 | / |
| danghuutoan | 0:f24ba3a89ec1 | 7 | / * This software is a free software and there is NO WARRANTY. |
| danghuutoan | 0:f24ba3a89ec1 | 8 | / * No restriction on use. You can use, modify and redistribute it for |
| danghuutoan | 0:f24ba3a89ec1 | 9 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. |
| danghuutoan | 0:f24ba3a89ec1 | 10 | / * Redistributions of source code must retain the above copyright notice. |
| danghuutoan | 0:f24ba3a89ec1 | 11 | / |
| danghuutoan | 0:f24ba3a89ec1 | 12 | /-------------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 13 | #include "mbed.h" |
| danghuutoan | 0:f24ba3a89ec1 | 14 | |
| danghuutoan | 0:f24ba3a89ec1 | 15 | SPI device(PA_7, PA_6, PA_5); |
| danghuutoan | 0:f24ba3a89ec1 | 16 | DigitalOut cs(PB_5); |
| danghuutoan | 0:f24ba3a89ec1 | 17 | #define SPI_CH 1 /* SPI channel to use = 1: SPI1, 11: SPI1/remap, 2: SPI2 */ |
| danghuutoan | 0:f24ba3a89ec1 | 18 | |
| danghuutoan | 0:f24ba3a89ec1 | 19 | #define FCLK_SLOW() { device.frequency(1000000); } /* Set SCLK = PCLK / 64 */ |
| danghuutoan | 0:f24ba3a89ec1 | 20 | #define FCLK_FAST() { device.frequency(1000000); } /* Set SCLK = PCLK / 2 */ |
| danghuutoan | 0:f24ba3a89ec1 | 21 | |
| danghuutoan | 0:f24ba3a89ec1 | 22 | /* PA4:MMC_CS, PA5:MMC_SCLK, PA6:MMC_DO, PA7:MMC_DI, PC4:MMC_CD */ |
| danghuutoan | 0:f24ba3a89ec1 | 23 | #define CS_HIGH() cs = 1 |
| danghuutoan | 0:f24ba3a89ec1 | 24 | #define CS_LOW() cs = 0 |
| danghuutoan | 0:f24ba3a89ec1 | 25 | #define MMC_CD 1 /* Card detect (yes:true, no:false, default:true) */ |
| danghuutoan | 0:f24ba3a89ec1 | 26 | #define MMC_WP 0 /* Write protected (yes:true, no:false, default:false) */ |
| danghuutoan | 0:f24ba3a89ec1 | 27 | |
| danghuutoan | 0:f24ba3a89ec1 | 28 | #define SPIxENABLE() {\ |
| danghuutoan | 0:f24ba3a89ec1 | 29 | cs = 1; \ |
| danghuutoan | 0:f24ba3a89ec1 | 30 | device.format(8,0); \ |
| danghuutoan | 0:f24ba3a89ec1 | 31 | device.frequency(400000); \ |
| danghuutoan | 0:f24ba3a89ec1 | 32 | } |
| danghuutoan | 0:f24ba3a89ec1 | 33 | |
| danghuutoan | 0:f24ba3a89ec1 | 34 | /*-------------------------------------------------------------------------- |
| danghuutoan | 0:f24ba3a89ec1 | 35 | |
| danghuutoan | 0:f24ba3a89ec1 | 36 | Module Private Functions |
| danghuutoan | 0:f24ba3a89ec1 | 37 | |
| danghuutoan | 0:f24ba3a89ec1 | 38 | ---------------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 39 | |
| danghuutoan | 0:f24ba3a89ec1 | 40 | |
| danghuutoan | 0:f24ba3a89ec1 | 41 | #include "diskio.h" |
| danghuutoan | 0:f24ba3a89ec1 | 42 | |
| danghuutoan | 0:f24ba3a89ec1 | 43 | |
| danghuutoan | 0:f24ba3a89ec1 | 44 | /* MMC/SD command */ |
| danghuutoan | 0:f24ba3a89ec1 | 45 | #define CMD0 (0) /* GO_IDLE_STATE */ |
| danghuutoan | 0:f24ba3a89ec1 | 46 | #define CMD1 (1) /* SEND_OP_COND (MMC) */ |
| danghuutoan | 0:f24ba3a89ec1 | 47 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ |
| danghuutoan | 0:f24ba3a89ec1 | 48 | #define CMD8 (8) /* SEND_IF_COND */ |
| danghuutoan | 0:f24ba3a89ec1 | 49 | #define CMD9 (9) /* SEND_CSD */ |
| danghuutoan | 0:f24ba3a89ec1 | 50 | #define CMD10 (10) /* SEND_CID */ |
| danghuutoan | 0:f24ba3a89ec1 | 51 | #define CMD12 (12) /* STOP_TRANSMISSION */ |
| danghuutoan | 0:f24ba3a89ec1 | 52 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ |
| danghuutoan | 0:f24ba3a89ec1 | 53 | #define CMD16 (16) /* SET_BLOCKLEN */ |
| danghuutoan | 0:f24ba3a89ec1 | 54 | #define CMD17 (17) /* READ_SINGLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 55 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 56 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ |
| danghuutoan | 0:f24ba3a89ec1 | 57 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ |
| danghuutoan | 0:f24ba3a89ec1 | 58 | #define CMD24 (24) /* WRITE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 59 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 60 | #define CMD32 (32) /* ERASE_ER_BLK_START */ |
| danghuutoan | 0:f24ba3a89ec1 | 61 | #define CMD33 (33) /* ERASE_ER_BLK_END */ |
| danghuutoan | 0:f24ba3a89ec1 | 62 | #define CMD38 (38) /* ERASE */ |
| danghuutoan | 0:f24ba3a89ec1 | 63 | #define CMD55 (55) /* APP_CMD */ |
| danghuutoan | 0:f24ba3a89ec1 | 64 | #define CMD58 (58) /* READ_OCR */ |
| danghuutoan | 0:f24ba3a89ec1 | 65 | |
| danghuutoan | 0:f24ba3a89ec1 | 66 | |
| danghuutoan | 0:f24ba3a89ec1 | 67 | static volatile |
| danghuutoan | 0:f24ba3a89ec1 | 68 | DSTATUS Stat = STA_NOINIT; /* Physical drive status */ |
| danghuutoan | 0:f24ba3a89ec1 | 69 | |
| danghuutoan | 0:f24ba3a89ec1 | 70 | static volatile |
| danghuutoan | 0:f24ba3a89ec1 | 71 | UINT Timer1, Timer2; /* 1kHz decrement timer stopped at zero (disk_timerproc()) */ |
| danghuutoan | 0:f24ba3a89ec1 | 72 | |
| danghuutoan | 0:f24ba3a89ec1 | 73 | static |
| danghuutoan | 0:f24ba3a89ec1 | 74 | BYTE CardType; /* Card type flags */ |
| danghuutoan | 0:f24ba3a89ec1 | 75 | |
| danghuutoan | 0:f24ba3a89ec1 | 76 | |
| danghuutoan | 0:f24ba3a89ec1 | 77 | |
| danghuutoan | 0:f24ba3a89ec1 | 78 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 79 | /* SPI controls (Platform dependent) */ |
| danghuutoan | 0:f24ba3a89ec1 | 80 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 81 | |
| danghuutoan | 0:f24ba3a89ec1 | 82 | /* Initialize MMC interface */ |
| danghuutoan | 0:f24ba3a89ec1 | 83 | static |
| danghuutoan | 0:f24ba3a89ec1 | 84 | void init_spi (void) |
| danghuutoan | 0:f24ba3a89ec1 | 85 | { |
| danghuutoan | 0:f24ba3a89ec1 | 86 | SPIxENABLE(); /* Enable SPI function */ |
| danghuutoan | 0:f24ba3a89ec1 | 87 | CS_HIGH(); /* Set CS# high */ |
| danghuutoan | 0:f24ba3a89ec1 | 88 | |
| danghuutoan | 0:f24ba3a89ec1 | 89 | for (Timer1 = 10; Timer1; ) ; /* 10ms */ |
| danghuutoan | 0:f24ba3a89ec1 | 90 | } |
| danghuutoan | 0:f24ba3a89ec1 | 91 | |
| danghuutoan | 0:f24ba3a89ec1 | 92 | |
| danghuutoan | 0:f24ba3a89ec1 | 93 | /* Exchange a byte */ |
| danghuutoan | 0:f24ba3a89ec1 | 94 | static |
| danghuutoan | 0:f24ba3a89ec1 | 95 | BYTE xchg_spi ( |
| danghuutoan | 0:f24ba3a89ec1 | 96 | BYTE dat /* Data to send */ |
| danghuutoan | 0:f24ba3a89ec1 | 97 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 98 | { |
| danghuutoan | 0:f24ba3a89ec1 | 99 | return (BYTE)device.write(dat); |
| danghuutoan | 0:f24ba3a89ec1 | 100 | } |
| danghuutoan | 0:f24ba3a89ec1 | 101 | |
| danghuutoan | 0:f24ba3a89ec1 | 102 | |
| danghuutoan | 0:f24ba3a89ec1 | 103 | /* Receive multiple byte */ |
| danghuutoan | 0:f24ba3a89ec1 | 104 | static |
| danghuutoan | 0:f24ba3a89ec1 | 105 | void rcvr_spi_multi ( |
| danghuutoan | 0:f24ba3a89ec1 | 106 | BYTE *buff, /* Pointer to data buffer */ |
| danghuutoan | 0:f24ba3a89ec1 | 107 | UINT btr /* Number of bytes to receive (even number) */ |
| danghuutoan | 0:f24ba3a89ec1 | 108 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 109 | { |
| danghuutoan | 0:f24ba3a89ec1 | 110 | WORD d; |
| danghuutoan | 0:f24ba3a89ec1 | 111 | |
| danghuutoan | 0:f24ba3a89ec1 | 112 | |
| danghuutoan | 0:f24ba3a89ec1 | 113 | |
| danghuutoan | 0:f24ba3a89ec1 | 114 | device.format(16,0); /* Set SPI to 16-bit mode */ |
| danghuutoan | 0:f24ba3a89ec1 | 115 | btr -= 2; |
| danghuutoan | 0:f24ba3a89ec1 | 116 | do { /* Receive the data block into buffer */ |
| danghuutoan | 0:f24ba3a89ec1 | 117 | |
| danghuutoan | 0:f24ba3a89ec1 | 118 | d = device.write(0xFFFF); |
| danghuutoan | 0:f24ba3a89ec1 | 119 | buff[1] = d; buff[0] = d >> 8; |
| danghuutoan | 0:f24ba3a89ec1 | 120 | buff += 2; |
| danghuutoan | 0:f24ba3a89ec1 | 121 | } while (btr -= 2); |
| danghuutoan | 0:f24ba3a89ec1 | 122 | d = device.write(0xFFFF); |
| danghuutoan | 0:f24ba3a89ec1 | 123 | buff[1] = d; buff[0] = d >> 8; |
| danghuutoan | 0:f24ba3a89ec1 | 124 | |
| danghuutoan | 0:f24ba3a89ec1 | 125 | device.format(8,0); /* Set SPI to 16-bit mode */ |
| danghuutoan | 0:f24ba3a89ec1 | 126 | } |
| danghuutoan | 0:f24ba3a89ec1 | 127 | |
| danghuutoan | 0:f24ba3a89ec1 | 128 | |
| danghuutoan | 0:f24ba3a89ec1 | 129 | #if _USE_WRITE |
| danghuutoan | 0:f24ba3a89ec1 | 130 | /* Send multiple byte */ |
| danghuutoan | 0:f24ba3a89ec1 | 131 | static |
| danghuutoan | 0:f24ba3a89ec1 | 132 | void xmit_spi_multi ( |
| danghuutoan | 0:f24ba3a89ec1 | 133 | const BYTE *buff, /* Pointer to the data */ |
| danghuutoan | 0:f24ba3a89ec1 | 134 | UINT btx /* Number of bytes to send (even number) */ |
| danghuutoan | 0:f24ba3a89ec1 | 135 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 136 | { |
| danghuutoan | 0:f24ba3a89ec1 | 137 | WORD d; |
| danghuutoan | 0:f24ba3a89ec1 | 138 | |
| danghuutoan | 0:f24ba3a89ec1 | 139 | |
| danghuutoan | 0:f24ba3a89ec1 | 140 | device.format(16,0); /* Set SPI to 16-bit mode */ |
| danghuutoan | 0:f24ba3a89ec1 | 141 | |
| danghuutoan | 0:f24ba3a89ec1 | 142 | d = buff[0] << 8 | buff[1]; |
| danghuutoan | 0:f24ba3a89ec1 | 143 | device.write(d); |
| danghuutoan | 0:f24ba3a89ec1 | 144 | buff += 2; |
| danghuutoan | 0:f24ba3a89ec1 | 145 | btx -= 2; |
| danghuutoan | 0:f24ba3a89ec1 | 146 | do { /* Receive the data block into buffer */ |
| danghuutoan | 0:f24ba3a89ec1 | 147 | d = buff[0] << 8 | buff[1]; |
| danghuutoan | 0:f24ba3a89ec1 | 148 | device.write(d); |
| danghuutoan | 0:f24ba3a89ec1 | 149 | buff += 2; |
| danghuutoan | 0:f24ba3a89ec1 | 150 | } while (btx -= 2); |
| danghuutoan | 0:f24ba3a89ec1 | 151 | |
| danghuutoan | 0:f24ba3a89ec1 | 152 | device.format(8,0); /* Set SPI to 8-bit mode */ |
| danghuutoan | 0:f24ba3a89ec1 | 153 | } |
| danghuutoan | 0:f24ba3a89ec1 | 154 | #endif |
| danghuutoan | 0:f24ba3a89ec1 | 155 | |
| danghuutoan | 0:f24ba3a89ec1 | 156 | |
| danghuutoan | 0:f24ba3a89ec1 | 157 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 158 | /* Wait for card ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 159 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 160 | |
| danghuutoan | 0:f24ba3a89ec1 | 161 | static |
| danghuutoan | 0:f24ba3a89ec1 | 162 | int wait_ready ( /* 1:Ready, 0:Timeout */ |
| danghuutoan | 0:f24ba3a89ec1 | 163 | UINT wt /* Timeout [ms] */ |
| danghuutoan | 0:f24ba3a89ec1 | 164 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 165 | { |
| danghuutoan | 0:f24ba3a89ec1 | 166 | BYTE d; |
| danghuutoan | 0:f24ba3a89ec1 | 167 | |
| danghuutoan | 0:f24ba3a89ec1 | 168 | |
| danghuutoan | 0:f24ba3a89ec1 | 169 | Timer2 = wt; |
| danghuutoan | 0:f24ba3a89ec1 | 170 | do { |
| danghuutoan | 0:f24ba3a89ec1 | 171 | d = xchg_spi(0xFF); |
| danghuutoan | 0:f24ba3a89ec1 | 172 | /* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */ |
| danghuutoan | 0:f24ba3a89ec1 | 173 | } while (d != 0xFF && Timer2); /* Wait for card goes ready or timeout */ |
| danghuutoan | 0:f24ba3a89ec1 | 174 | |
| danghuutoan | 0:f24ba3a89ec1 | 175 | return (d == 0xFF) ? 1 : 0; |
| danghuutoan | 0:f24ba3a89ec1 | 176 | } |
| danghuutoan | 0:f24ba3a89ec1 | 177 | |
| danghuutoan | 0:f24ba3a89ec1 | 178 | |
| danghuutoan | 0:f24ba3a89ec1 | 179 | |
| danghuutoan | 0:f24ba3a89ec1 | 180 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 181 | /* Deselect card and release SPI */ |
| danghuutoan | 0:f24ba3a89ec1 | 182 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 183 | |
| danghuutoan | 0:f24ba3a89ec1 | 184 | static |
| danghuutoan | 0:f24ba3a89ec1 | 185 | void deselect (void) |
| danghuutoan | 0:f24ba3a89ec1 | 186 | { |
| danghuutoan | 0:f24ba3a89ec1 | 187 | CS_HIGH(); /* Set CS# high */ |
| danghuutoan | 0:f24ba3a89ec1 | 188 | xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */ |
| danghuutoan | 0:f24ba3a89ec1 | 189 | |
| danghuutoan | 0:f24ba3a89ec1 | 190 | } |
| danghuutoan | 0:f24ba3a89ec1 | 191 | |
| danghuutoan | 0:f24ba3a89ec1 | 192 | |
| danghuutoan | 0:f24ba3a89ec1 | 193 | |
| danghuutoan | 0:f24ba3a89ec1 | 194 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 195 | /* Select card and wait for ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 196 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 197 | |
| danghuutoan | 0:f24ba3a89ec1 | 198 | static |
| danghuutoan | 0:f24ba3a89ec1 | 199 | int select (void) /* 1:OK, 0:Timeout */ |
| danghuutoan | 0:f24ba3a89ec1 | 200 | { |
| danghuutoan | 0:f24ba3a89ec1 | 201 | CS_LOW(); /* Set CS# low */ |
| danghuutoan | 0:f24ba3a89ec1 | 202 | xchg_spi(0xFF); /* Dummy clock (force DO enabled) */ |
| danghuutoan | 0:f24ba3a89ec1 | 203 | if (wait_ready(500)) return 1; /* Wait for card ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 204 | |
| danghuutoan | 0:f24ba3a89ec1 | 205 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 206 | return 0; /* Timeout */ |
| danghuutoan | 0:f24ba3a89ec1 | 207 | } |
| danghuutoan | 0:f24ba3a89ec1 | 208 | |
| danghuutoan | 0:f24ba3a89ec1 | 209 | |
| danghuutoan | 0:f24ba3a89ec1 | 210 | |
| danghuutoan | 0:f24ba3a89ec1 | 211 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 212 | /* Receive a data packet from the MMC */ |
| danghuutoan | 0:f24ba3a89ec1 | 213 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 214 | |
| danghuutoan | 0:f24ba3a89ec1 | 215 | static |
| danghuutoan | 0:f24ba3a89ec1 | 216 | int rcvr_datablock ( /* 1:OK, 0:Error */ |
| danghuutoan | 0:f24ba3a89ec1 | 217 | BYTE *buff, /* Data buffer */ |
| danghuutoan | 0:f24ba3a89ec1 | 218 | UINT btr /* Data block length (byte) */ |
| danghuutoan | 0:f24ba3a89ec1 | 219 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 220 | { |
| danghuutoan | 0:f24ba3a89ec1 | 221 | BYTE token; |
| danghuutoan | 0:f24ba3a89ec1 | 222 | |
| danghuutoan | 0:f24ba3a89ec1 | 223 | |
| danghuutoan | 0:f24ba3a89ec1 | 224 | Timer1 = 200; |
| danghuutoan | 0:f24ba3a89ec1 | 225 | do { /* Wait for DataStart token in timeout of 200ms */ |
| danghuutoan | 0:f24ba3a89ec1 | 226 | token = xchg_spi(0xFF); |
| danghuutoan | 0:f24ba3a89ec1 | 227 | /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */ |
| danghuutoan | 0:f24ba3a89ec1 | 228 | } while ((token == 0xFF) && Timer1); |
| danghuutoan | 0:f24ba3a89ec1 | 229 | if(token != 0xFE) return 0; /* Function fails if invalid DataStart token or timeout */ |
| danghuutoan | 0:f24ba3a89ec1 | 230 | |
| danghuutoan | 0:f24ba3a89ec1 | 231 | rcvr_spi_multi(buff, btr); /* Store trailing data to the buffer */ |
| danghuutoan | 0:f24ba3a89ec1 | 232 | xchg_spi(0xFF); xchg_spi(0xFF); /* Discard CRC */ |
| danghuutoan | 0:f24ba3a89ec1 | 233 | |
| danghuutoan | 0:f24ba3a89ec1 | 234 | return 1; /* Function succeeded */ |
| danghuutoan | 0:f24ba3a89ec1 | 235 | } |
| danghuutoan | 0:f24ba3a89ec1 | 236 | |
| danghuutoan | 0:f24ba3a89ec1 | 237 | |
| danghuutoan | 0:f24ba3a89ec1 | 238 | |
| danghuutoan | 0:f24ba3a89ec1 | 239 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 240 | /* Send a data packet to the MMC */ |
| danghuutoan | 0:f24ba3a89ec1 | 241 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 242 | |
| danghuutoan | 0:f24ba3a89ec1 | 243 | #if _USE_WRITE |
| danghuutoan | 0:f24ba3a89ec1 | 244 | static |
| danghuutoan | 0:f24ba3a89ec1 | 245 | int xmit_datablock ( /* 1:OK, 0:Failed */ |
| danghuutoan | 0:f24ba3a89ec1 | 246 | const BYTE *buff, /* Ponter to 512 byte data to be sent */ |
| danghuutoan | 0:f24ba3a89ec1 | 247 | BYTE token /* Token */ |
| danghuutoan | 0:f24ba3a89ec1 | 248 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 249 | { |
| danghuutoan | 0:f24ba3a89ec1 | 250 | BYTE resp; |
| danghuutoan | 0:f24ba3a89ec1 | 251 | |
| danghuutoan | 0:f24ba3a89ec1 | 252 | |
| danghuutoan | 0:f24ba3a89ec1 | 253 | if (!wait_ready(500)) return 0; /* Wait for card ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 254 | |
| danghuutoan | 0:f24ba3a89ec1 | 255 | xchg_spi(token); /* Send token */ |
| danghuutoan | 0:f24ba3a89ec1 | 256 | if (token != 0xFD) { /* Send data if token is other than StopTran */ |
| danghuutoan | 0:f24ba3a89ec1 | 257 | xmit_spi_multi(buff, 512); /* Data */ |
| danghuutoan | 0:f24ba3a89ec1 | 258 | xchg_spi(0xFF); xchg_spi(0xFF); /* Dummy CRC */ |
| danghuutoan | 0:f24ba3a89ec1 | 259 | |
| danghuutoan | 0:f24ba3a89ec1 | 260 | resp = xchg_spi(0xFF); /* Receive data resp */ |
| danghuutoan | 0:f24ba3a89ec1 | 261 | if ((resp & 0x1F) != 0x05) /* Function fails if the data packet was not accepted */ |
| danghuutoan | 0:f24ba3a89ec1 | 262 | return 0; |
| danghuutoan | 0:f24ba3a89ec1 | 263 | } |
| danghuutoan | 0:f24ba3a89ec1 | 264 | return 1; |
| danghuutoan | 0:f24ba3a89ec1 | 265 | } |
| danghuutoan | 0:f24ba3a89ec1 | 266 | #endif |
| danghuutoan | 0:f24ba3a89ec1 | 267 | |
| danghuutoan | 0:f24ba3a89ec1 | 268 | |
| danghuutoan | 0:f24ba3a89ec1 | 269 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 270 | /* Send a command packet to the MMC */ |
| danghuutoan | 0:f24ba3a89ec1 | 271 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 272 | |
| danghuutoan | 0:f24ba3a89ec1 | 273 | static |
| danghuutoan | 0:f24ba3a89ec1 | 274 | BYTE send_cmd ( /* Return value: R1 resp (bit7==1:Failed to send) */ |
| danghuutoan | 0:f24ba3a89ec1 | 275 | BYTE cmd, /* Command index */ |
| danghuutoan | 0:f24ba3a89ec1 | 276 | DWORD arg /* Argument */ |
| danghuutoan | 0:f24ba3a89ec1 | 277 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 278 | { |
| danghuutoan | 0:f24ba3a89ec1 | 279 | BYTE n, res; |
| danghuutoan | 0:f24ba3a89ec1 | 280 | |
| danghuutoan | 0:f24ba3a89ec1 | 281 | |
| danghuutoan | 0:f24ba3a89ec1 | 282 | if (cmd & 0x80) { /* Send a CMD55 prior to ACMD<n> */ |
| danghuutoan | 0:f24ba3a89ec1 | 283 | cmd &= 0x7F; |
| danghuutoan | 0:f24ba3a89ec1 | 284 | res = send_cmd(CMD55, 0); |
| danghuutoan | 0:f24ba3a89ec1 | 285 | if (res > 1) return res; |
| danghuutoan | 0:f24ba3a89ec1 | 286 | } |
| danghuutoan | 0:f24ba3a89ec1 | 287 | |
| danghuutoan | 0:f24ba3a89ec1 | 288 | /* Select the card and wait for ready except to stop multiple block read */ |
| danghuutoan | 0:f24ba3a89ec1 | 289 | if (cmd != CMD12) { |
| danghuutoan | 0:f24ba3a89ec1 | 290 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 291 | if (!select()) return 0xFF; |
| danghuutoan | 0:f24ba3a89ec1 | 292 | } |
| danghuutoan | 0:f24ba3a89ec1 | 293 | |
| danghuutoan | 0:f24ba3a89ec1 | 294 | /* Send command packet */ |
| danghuutoan | 0:f24ba3a89ec1 | 295 | xchg_spi(0x40 | cmd); /* Start + command index */ |
| danghuutoan | 0:f24ba3a89ec1 | 296 | xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ |
| danghuutoan | 0:f24ba3a89ec1 | 297 | xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ |
| danghuutoan | 0:f24ba3a89ec1 | 298 | xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ |
| danghuutoan | 0:f24ba3a89ec1 | 299 | xchg_spi((BYTE)arg); /* Argument[7..0] */ |
| danghuutoan | 0:f24ba3a89ec1 | 300 | n = 0x01; /* Dummy CRC + Stop */ |
| danghuutoan | 0:f24ba3a89ec1 | 301 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 302 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ |
| danghuutoan | 0:f24ba3a89ec1 | 303 | xchg_spi(n); |
| danghuutoan | 0:f24ba3a89ec1 | 304 | |
| danghuutoan | 0:f24ba3a89ec1 | 305 | /* Receive command resp */ |
| danghuutoan | 0:f24ba3a89ec1 | 306 | if (cmd == CMD12) xchg_spi(0xFF); /* Diacard following one byte when CMD12 */ |
| danghuutoan | 0:f24ba3a89ec1 | 307 | n = 10; /* Wait for response (10 bytes max) */ |
| danghuutoan | 0:f24ba3a89ec1 | 308 | do |
| danghuutoan | 0:f24ba3a89ec1 | 309 | res = xchg_spi(0xFF); |
| danghuutoan | 0:f24ba3a89ec1 | 310 | while ((res & 0x80) && --n); |
| danghuutoan | 0:f24ba3a89ec1 | 311 | |
| danghuutoan | 0:f24ba3a89ec1 | 312 | return res; /* Return received response */ |
| danghuutoan | 0:f24ba3a89ec1 | 313 | } |
| danghuutoan | 0:f24ba3a89ec1 | 314 | |
| danghuutoan | 0:f24ba3a89ec1 | 315 | |
| danghuutoan | 0:f24ba3a89ec1 | 316 | |
| danghuutoan | 0:f24ba3a89ec1 | 317 | /*-------------------------------------------------------------------------- |
| danghuutoan | 0:f24ba3a89ec1 | 318 | |
| danghuutoan | 0:f24ba3a89ec1 | 319 | Public Functions |
| danghuutoan | 0:f24ba3a89ec1 | 320 | |
| danghuutoan | 0:f24ba3a89ec1 | 321 | ---------------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 322 | |
| danghuutoan | 0:f24ba3a89ec1 | 323 | |
| danghuutoan | 0:f24ba3a89ec1 | 324 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 325 | /* Initialize disk drive */ |
| danghuutoan | 0:f24ba3a89ec1 | 326 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 327 | |
| danghuutoan | 0:f24ba3a89ec1 | 328 | DSTATUS disk_initialize ( |
| danghuutoan | 0:f24ba3a89ec1 | 329 | BYTE drv /* Physical drive number (0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 330 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 331 | { |
| danghuutoan | 0:f24ba3a89ec1 | 332 | BYTE n, cmd, ty, ocr[4]; |
| danghuutoan | 0:f24ba3a89ec1 | 333 | |
| danghuutoan | 0:f24ba3a89ec1 | 334 | |
| danghuutoan | 0:f24ba3a89ec1 | 335 | if (drv) return STA_NOINIT; /* Supports only drive 0 */ |
| danghuutoan | 0:f24ba3a89ec1 | 336 | init_spi(); /* Initialize SPI */ |
| danghuutoan | 0:f24ba3a89ec1 | 337 | |
| danghuutoan | 0:f24ba3a89ec1 | 338 | if (Stat & STA_NODISK) return Stat; /* Is card existing in the soket? */ |
| danghuutoan | 0:f24ba3a89ec1 | 339 | |
| danghuutoan | 0:f24ba3a89ec1 | 340 | FCLK_SLOW(); |
| danghuutoan | 0:f24ba3a89ec1 | 341 | for (n = 10; n; n--) xchg_spi(0xFF); /* Send 80 dummy clocks */ |
| danghuutoan | 0:f24ba3a89ec1 | 342 | |
| danghuutoan | 0:f24ba3a89ec1 | 343 | ty = 0; |
| danghuutoan | 0:f24ba3a89ec1 | 344 | if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */ |
| danghuutoan | 0:f24ba3a89ec1 | 345 | Timer1 = 1000; /* Initialization timeout = 1 sec */ |
| danghuutoan | 0:f24ba3a89ec1 | 346 | if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ |
| danghuutoan | 0:f24ba3a89ec1 | 347 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */ |
| danghuutoan | 0:f24ba3a89ec1 | 348 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */ |
| danghuutoan | 0:f24ba3a89ec1 | 349 | while (Timer1 && send_cmd(ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */ |
| danghuutoan | 0:f24ba3a89ec1 | 350 | if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ |
| danghuutoan | 0:f24ba3a89ec1 | 351 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); |
| danghuutoan | 0:f24ba3a89ec1 | 352 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */ |
| danghuutoan | 0:f24ba3a89ec1 | 353 | } |
| danghuutoan | 0:f24ba3a89ec1 | 354 | } |
| danghuutoan | 0:f24ba3a89ec1 | 355 | } else { /* Not SDv2 card */ |
| danghuutoan | 0:f24ba3a89ec1 | 356 | if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */ |
| danghuutoan | 0:f24ba3a89ec1 | 357 | ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */ |
| danghuutoan | 0:f24ba3a89ec1 | 358 | } else { |
| danghuutoan | 0:f24ba3a89ec1 | 359 | ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */ |
| danghuutoan | 0:f24ba3a89ec1 | 360 | } |
| danghuutoan | 0:f24ba3a89ec1 | 361 | while (Timer1 && send_cmd(cmd, 0)) ; /* Wait for end of initialization */ |
| danghuutoan | 0:f24ba3a89ec1 | 362 | if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */ |
| danghuutoan | 0:f24ba3a89ec1 | 363 | ty = 0; |
| danghuutoan | 0:f24ba3a89ec1 | 364 | } |
| danghuutoan | 0:f24ba3a89ec1 | 365 | } |
| danghuutoan | 0:f24ba3a89ec1 | 366 | CardType = ty; /* Card type */ |
| danghuutoan | 0:f24ba3a89ec1 | 367 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 368 | |
| danghuutoan | 0:f24ba3a89ec1 | 369 | if (ty) { /* OK */ |
| danghuutoan | 0:f24ba3a89ec1 | 370 | FCLK_FAST(); /* Set fast clock */ |
| danghuutoan | 0:f24ba3a89ec1 | 371 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */ |
| danghuutoan | 0:f24ba3a89ec1 | 372 | } else { /* Failed */ |
| danghuutoan | 0:f24ba3a89ec1 | 373 | Stat = STA_NOINIT; |
| danghuutoan | 0:f24ba3a89ec1 | 374 | } |
| danghuutoan | 0:f24ba3a89ec1 | 375 | |
| danghuutoan | 0:f24ba3a89ec1 | 376 | return Stat; |
| danghuutoan | 0:f24ba3a89ec1 | 377 | } |
| danghuutoan | 0:f24ba3a89ec1 | 378 | |
| danghuutoan | 0:f24ba3a89ec1 | 379 | |
| danghuutoan | 0:f24ba3a89ec1 | 380 | |
| danghuutoan | 0:f24ba3a89ec1 | 381 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 382 | /* Get disk status */ |
| danghuutoan | 0:f24ba3a89ec1 | 383 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 384 | |
| danghuutoan | 0:f24ba3a89ec1 | 385 | DSTATUS disk_status ( |
| danghuutoan | 0:f24ba3a89ec1 | 386 | BYTE drv /* Physical drive number (0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 387 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 388 | { |
| danghuutoan | 0:f24ba3a89ec1 | 389 | if (drv) return STA_NOINIT; /* Supports only drive 0 */ |
| danghuutoan | 0:f24ba3a89ec1 | 390 | |
| danghuutoan | 0:f24ba3a89ec1 | 391 | return Stat; /* Return disk status */ |
| danghuutoan | 0:f24ba3a89ec1 | 392 | } |
| danghuutoan | 0:f24ba3a89ec1 | 393 | |
| danghuutoan | 0:f24ba3a89ec1 | 394 | |
| danghuutoan | 0:f24ba3a89ec1 | 395 | |
| danghuutoan | 0:f24ba3a89ec1 | 396 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 397 | /* Read sector(s) */ |
| danghuutoan | 0:f24ba3a89ec1 | 398 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 399 | |
| danghuutoan | 0:f24ba3a89ec1 | 400 | DRESULT disk_read ( |
| danghuutoan | 0:f24ba3a89ec1 | 401 | BYTE drv, /* Physical drive number (0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 402 | BYTE *buff, /* Pointer to the data buffer to store read data */ |
| danghuutoan | 0:f24ba3a89ec1 | 403 | DWORD sector, /* Start sector number (LBA) */ |
| danghuutoan | 0:f24ba3a89ec1 | 404 | UINT count /* Number of sectors to read (1..128) */ |
| danghuutoan | 0:f24ba3a89ec1 | 405 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 406 | { |
| danghuutoan | 0:f24ba3a89ec1 | 407 | if (drv || !count) return RES_PARERR; /* Check parameter */ |
| danghuutoan | 0:f24ba3a89ec1 | 408 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 409 | |
| danghuutoan | 0:f24ba3a89ec1 | 410 | if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */ |
| danghuutoan | 0:f24ba3a89ec1 | 411 | |
| danghuutoan | 0:f24ba3a89ec1 | 412 | if (count == 1) { /* Single sector read */ |
| danghuutoan | 0:f24ba3a89ec1 | 413 | if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 414 | && rcvr_datablock(buff, 512)) |
| danghuutoan | 0:f24ba3a89ec1 | 415 | count = 0; |
| danghuutoan | 0:f24ba3a89ec1 | 416 | } |
| danghuutoan | 0:f24ba3a89ec1 | 417 | else { /* Multiple sector read */ |
| danghuutoan | 0:f24ba3a89ec1 | 418 | if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 419 | do { |
| danghuutoan | 0:f24ba3a89ec1 | 420 | if (!rcvr_datablock(buff, 512)) break; |
| danghuutoan | 0:f24ba3a89ec1 | 421 | buff += 512; |
| danghuutoan | 0:f24ba3a89ec1 | 422 | } while (--count); |
| danghuutoan | 0:f24ba3a89ec1 | 423 | send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ |
| danghuutoan | 0:f24ba3a89ec1 | 424 | } |
| danghuutoan | 0:f24ba3a89ec1 | 425 | } |
| danghuutoan | 0:f24ba3a89ec1 | 426 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 427 | |
| danghuutoan | 0:f24ba3a89ec1 | 428 | return count ? RES_ERROR : RES_OK; /* Return result */ |
| danghuutoan | 0:f24ba3a89ec1 | 429 | } |
| danghuutoan | 0:f24ba3a89ec1 | 430 | |
| danghuutoan | 0:f24ba3a89ec1 | 431 | |
| danghuutoan | 0:f24ba3a89ec1 | 432 | |
| danghuutoan | 0:f24ba3a89ec1 | 433 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 434 | /* Write sector(s) */ |
| danghuutoan | 0:f24ba3a89ec1 | 435 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 436 | |
| danghuutoan | 0:f24ba3a89ec1 | 437 | #if _USE_WRITE |
| danghuutoan | 0:f24ba3a89ec1 | 438 | DRESULT disk_write ( |
| danghuutoan | 0:f24ba3a89ec1 | 439 | BYTE drv, /* Physical drive number (0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 440 | const BYTE *buff, /* Ponter to the data to write */ |
| danghuutoan | 0:f24ba3a89ec1 | 441 | DWORD sector, /* Start sector number (LBA) */ |
| danghuutoan | 0:f24ba3a89ec1 | 442 | UINT count /* Number of sectors to write (1..128) */ |
| danghuutoan | 0:f24ba3a89ec1 | 443 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 444 | { |
| danghuutoan | 0:f24ba3a89ec1 | 445 | if (drv || !count) return RES_PARERR; /* Check parameter */ |
| danghuutoan | 0:f24ba3a89ec1 | 446 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ |
| danghuutoan | 0:f24ba3a89ec1 | 447 | if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */ |
| danghuutoan | 0:f24ba3a89ec1 | 448 | |
| danghuutoan | 0:f24ba3a89ec1 | 449 | if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */ |
| danghuutoan | 0:f24ba3a89ec1 | 450 | |
| danghuutoan | 0:f24ba3a89ec1 | 451 | if (count == 1) { /* Single sector write */ |
| danghuutoan | 0:f24ba3a89ec1 | 452 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 453 | && xmit_datablock(buff, 0xFE)) |
| danghuutoan | 0:f24ba3a89ec1 | 454 | count = 0; |
| danghuutoan | 0:f24ba3a89ec1 | 455 | } |
| danghuutoan | 0:f24ba3a89ec1 | 456 | else { /* Multiple sector write */ |
| danghuutoan | 0:f24ba3a89ec1 | 457 | if (CardType & CT_SDC) send_cmd(ACMD23, count); /* Predefine number of sectors */ |
| danghuutoan | 0:f24ba3a89ec1 | 458 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ |
| danghuutoan | 0:f24ba3a89ec1 | 459 | do { |
| danghuutoan | 0:f24ba3a89ec1 | 460 | if (!xmit_datablock(buff, 0xFC)) break; |
| danghuutoan | 0:f24ba3a89ec1 | 461 | buff += 512; |
| danghuutoan | 0:f24ba3a89ec1 | 462 | } while (--count); |
| danghuutoan | 0:f24ba3a89ec1 | 463 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ |
| danghuutoan | 0:f24ba3a89ec1 | 464 | count = 1; |
| danghuutoan | 0:f24ba3a89ec1 | 465 | } |
| danghuutoan | 0:f24ba3a89ec1 | 466 | } |
| danghuutoan | 0:f24ba3a89ec1 | 467 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 468 | |
| danghuutoan | 0:f24ba3a89ec1 | 469 | return count ? RES_ERROR : RES_OK; /* Return result */ |
| danghuutoan | 0:f24ba3a89ec1 | 470 | } |
| danghuutoan | 0:f24ba3a89ec1 | 471 | #endif |
| danghuutoan | 0:f24ba3a89ec1 | 472 | |
| danghuutoan | 0:f24ba3a89ec1 | 473 | |
| danghuutoan | 0:f24ba3a89ec1 | 474 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 475 | /* Miscellaneous drive controls other than data read/write */ |
| danghuutoan | 0:f24ba3a89ec1 | 476 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 477 | |
| danghuutoan | 0:f24ba3a89ec1 | 478 | #if _USE_IOCTL |
| danghuutoan | 0:f24ba3a89ec1 | 479 | DRESULT disk_ioctl ( |
| danghuutoan | 0:f24ba3a89ec1 | 480 | BYTE drv, /* Physical drive number (0) */ |
| danghuutoan | 0:f24ba3a89ec1 | 481 | BYTE cmd, /* Control command code */ |
| danghuutoan | 0:f24ba3a89ec1 | 482 | void *buff /* Pointer to the conrtol data */ |
| danghuutoan | 0:f24ba3a89ec1 | 483 | ) |
| danghuutoan | 0:f24ba3a89ec1 | 484 | { |
| danghuutoan | 0:f24ba3a89ec1 | 485 | DRESULT res; |
| danghuutoan | 0:f24ba3a89ec1 | 486 | BYTE n, csd[16]; |
| danghuutoan | 0:f24ba3a89ec1 | 487 | DWORD *dp, st, ed, csize; |
| danghuutoan | 0:f24ba3a89ec1 | 488 | |
| danghuutoan | 0:f24ba3a89ec1 | 489 | |
| danghuutoan | 0:f24ba3a89ec1 | 490 | if (drv) return RES_PARERR; /* Check parameter */ |
| danghuutoan | 0:f24ba3a89ec1 | 491 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ |
| danghuutoan | 0:f24ba3a89ec1 | 492 | |
| danghuutoan | 0:f24ba3a89ec1 | 493 | res = RES_ERROR; |
| danghuutoan | 0:f24ba3a89ec1 | 494 | |
| danghuutoan | 0:f24ba3a89ec1 | 495 | switch (cmd) { |
| danghuutoan | 0:f24ba3a89ec1 | 496 | case CTRL_SYNC : /* Wait for end of internal write process of the drive */ |
| danghuutoan | 0:f24ba3a89ec1 | 497 | if (select()) res = RES_OK; |
| danghuutoan | 0:f24ba3a89ec1 | 498 | break; |
| danghuutoan | 0:f24ba3a89ec1 | 499 | |
| danghuutoan | 0:f24ba3a89ec1 | 500 | case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */ |
| danghuutoan | 0:f24ba3a89ec1 | 501 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { |
| danghuutoan | 0:f24ba3a89ec1 | 502 | if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ |
| danghuutoan | 0:f24ba3a89ec1 | 503 | csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; |
| danghuutoan | 0:f24ba3a89ec1 | 504 | *(DWORD*)buff = csize << 10; |
| danghuutoan | 0:f24ba3a89ec1 | 505 | } else { /* SDC ver 1.XX or MMC ver 3 */ |
| danghuutoan | 0:f24ba3a89ec1 | 506 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; |
| danghuutoan | 0:f24ba3a89ec1 | 507 | csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; |
| danghuutoan | 0:f24ba3a89ec1 | 508 | *(DWORD*)buff = csize << (n - 9); |
| danghuutoan | 0:f24ba3a89ec1 | 509 | } |
| danghuutoan | 0:f24ba3a89ec1 | 510 | res = RES_OK; |
| danghuutoan | 0:f24ba3a89ec1 | 511 | } |
| danghuutoan | 0:f24ba3a89ec1 | 512 | break; |
| danghuutoan | 0:f24ba3a89ec1 | 513 | |
| danghuutoan | 0:f24ba3a89ec1 | 514 | case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ |
| danghuutoan | 0:f24ba3a89ec1 | 515 | if (CardType & CT_SD2) { /* SDC ver 2.00 */ |
| danghuutoan | 0:f24ba3a89ec1 | 516 | if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ |
| danghuutoan | 0:f24ba3a89ec1 | 517 | xchg_spi(0xFF); |
| danghuutoan | 0:f24ba3a89ec1 | 518 | if (rcvr_datablock(csd, 16)) { /* Read partial block */ |
| danghuutoan | 0:f24ba3a89ec1 | 519 | for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */ |
| danghuutoan | 0:f24ba3a89ec1 | 520 | *(DWORD*)buff = 16UL << (csd[10] >> 4); |
| danghuutoan | 0:f24ba3a89ec1 | 521 | res = RES_OK; |
| danghuutoan | 0:f24ba3a89ec1 | 522 | } |
| danghuutoan | 0:f24ba3a89ec1 | 523 | } |
| danghuutoan | 0:f24ba3a89ec1 | 524 | } else { /* SDC ver 1.XX or MMC */ |
| danghuutoan | 0:f24ba3a89ec1 | 525 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ |
| danghuutoan | 0:f24ba3a89ec1 | 526 | if (CardType & CT_SD1) { /* SDC ver 1.XX */ |
| danghuutoan | 0:f24ba3a89ec1 | 527 | *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); |
| danghuutoan | 0:f24ba3a89ec1 | 528 | } else { /* MMC */ |
| danghuutoan | 0:f24ba3a89ec1 | 529 | *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); |
| danghuutoan | 0:f24ba3a89ec1 | 530 | } |
| danghuutoan | 0:f24ba3a89ec1 | 531 | res = RES_OK; |
| danghuutoan | 0:f24ba3a89ec1 | 532 | } |
| danghuutoan | 0:f24ba3a89ec1 | 533 | } |
| danghuutoan | 0:f24ba3a89ec1 | 534 | break; |
| danghuutoan | 0:f24ba3a89ec1 | 535 | |
| danghuutoan | 0:f24ba3a89ec1 | 536 | case CTRL_TRIM : /* Erase a block of sectors (used when _USE_ERASE == 1) */ |
| danghuutoan | 0:f24ba3a89ec1 | 537 | if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */ |
| danghuutoan | 0:f24ba3a89ec1 | 538 | if (disk_ioctl(drv, MMC_GET_CSD, csd)) break; /* Get CSD */ |
| danghuutoan | 0:f24ba3a89ec1 | 539 | if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */ |
| danghuutoan | 0:f24ba3a89ec1 | 540 | dp =(DWORD*) buff; st = dp[0]; ed = dp[1]; /* Load sector block */ |
| danghuutoan | 0:f24ba3a89ec1 | 541 | if (!(CardType & CT_BLOCK)) { |
| danghuutoan | 0:f24ba3a89ec1 | 542 | st *= 512; ed *= 512; |
| danghuutoan | 0:f24ba3a89ec1 | 543 | } |
| danghuutoan | 0:f24ba3a89ec1 | 544 | if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) /* Erase sector block */ |
| danghuutoan | 0:f24ba3a89ec1 | 545 | res = RES_OK; /* FatFs does not check result of this command */ |
| danghuutoan | 0:f24ba3a89ec1 | 546 | break; |
| danghuutoan | 0:f24ba3a89ec1 | 547 | |
| danghuutoan | 0:f24ba3a89ec1 | 548 | default: |
| danghuutoan | 0:f24ba3a89ec1 | 549 | res = RES_PARERR; |
| danghuutoan | 0:f24ba3a89ec1 | 550 | } |
| danghuutoan | 0:f24ba3a89ec1 | 551 | |
| danghuutoan | 0:f24ba3a89ec1 | 552 | deselect(); |
| danghuutoan | 0:f24ba3a89ec1 | 553 | |
| danghuutoan | 0:f24ba3a89ec1 | 554 | return res; |
| danghuutoan | 0:f24ba3a89ec1 | 555 | } |
| danghuutoan | 0:f24ba3a89ec1 | 556 | #endif |
| danghuutoan | 0:f24ba3a89ec1 | 557 | |
| danghuutoan | 0:f24ba3a89ec1 | 558 | |
| danghuutoan | 0:f24ba3a89ec1 | 559 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 560 | /* Device timer function */ |
| danghuutoan | 0:f24ba3a89ec1 | 561 | /*-----------------------------------------------------------------------*/ |
| danghuutoan | 0:f24ba3a89ec1 | 562 | /* This function must be called from timer interrupt routine in period |
| danghuutoan | 0:f24ba3a89ec1 | 563 | / of 1 ms to generate card control timing. |
| danghuutoan | 0:f24ba3a89ec1 | 564 | */ |
| danghuutoan | 0:f24ba3a89ec1 | 565 | |
| danghuutoan | 0:f24ba3a89ec1 | 566 | void disk_timerproc (void) |
| danghuutoan | 0:f24ba3a89ec1 | 567 | { |
| danghuutoan | 0:f24ba3a89ec1 | 568 | WORD n; |
| danghuutoan | 0:f24ba3a89ec1 | 569 | BYTE s; |
| danghuutoan | 0:f24ba3a89ec1 | 570 | |
| danghuutoan | 0:f24ba3a89ec1 | 571 | |
| danghuutoan | 0:f24ba3a89ec1 | 572 | n = Timer1; /* 1kHz decrement timer stopped at 0 */ |
| danghuutoan | 0:f24ba3a89ec1 | 573 | if (n) Timer1 = --n; |
| danghuutoan | 0:f24ba3a89ec1 | 574 | n = Timer2; |
| danghuutoan | 0:f24ba3a89ec1 | 575 | if (n) Timer2 = --n; |
| danghuutoan | 0:f24ba3a89ec1 | 576 | |
| danghuutoan | 0:f24ba3a89ec1 | 577 | s = Stat; |
| danghuutoan | 0:f24ba3a89ec1 | 578 | if (MMC_WP) /* Write protected */ |
| danghuutoan | 0:f24ba3a89ec1 | 579 | s |= STA_PROTECT; |
| danghuutoan | 0:f24ba3a89ec1 | 580 | else /* Write enabled */ |
| danghuutoan | 0:f24ba3a89ec1 | 581 | s &= ~STA_PROTECT; |
| danghuutoan | 0:f24ba3a89ec1 | 582 | if (MMC_CD) /* Card is in socket */ |
| danghuutoan | 0:f24ba3a89ec1 | 583 | s &= ~STA_NODISK; |
| danghuutoan | 0:f24ba3a89ec1 | 584 | else /* Socket empty */ |
| danghuutoan | 0:f24ba3a89ec1 | 585 | s |= (STA_NODISK | STA_NOINIT); |
| danghuutoan | 0:f24ba3a89ec1 | 586 | Stat = s; |
| danghuutoan | 0:f24ba3a89ec1 | 587 | } |
| danghuutoan | 0:f24ba3a89ec1 | 588 | /** |
| danghuutoan | 0:f24ba3a89ec1 | 589 | * @brief Gets Time from RTC |
| danghuutoan | 0:f24ba3a89ec1 | 590 | * @param None |
| danghuutoan | 0:f24ba3a89ec1 | 591 | * @retval Time in DWORD |
| danghuutoan | 0:f24ba3a89ec1 | 592 | */ |
| danghuutoan | 0:f24ba3a89ec1 | 593 | DWORD get_fattime (void) |
| danghuutoan | 0:f24ba3a89ec1 | 594 | { |
| danghuutoan | 0:f24ba3a89ec1 | 595 | return 0; |
| danghuutoan | 0:f24ba3a89ec1 | 596 | } |