IJFW - IchigoJamのBASICプログラムをメモリカード(MMCまたは互換カード)に保存したり読み出したりできるプログラム。メモリカードにファームウェアのファイルを置くだけで、電源ON時に自動的に書き換える機能も搭載(一応こちらがメイン)。LPC1114FN28専用。

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FatfsIJFW.cpp Source File

FatfsIJFW.cpp

00001 #include "mbed.h"
00002 #include "ff.h"
00003 #include "FatfsIJFW.h"
00004 
00005 
00006 // Command of memory card
00007 const BYTE CMD0 = 0;            // GO_IDLE_STATE
00008 const BYTE CMD1 = 1;            // SEND_OP_COND
00009 const BYTE ACMD41 = 0x80+41;    // SEND_OP_COND
00010 const BYTE CMD8 = 8;            // SEND_IF_COND
00011 const BYTE CMD12 = 12;          // STOP_TRANSMISSION
00012 const BYTE CMD16 = 16;          // SET_BLOCKLEN
00013 const BYTE CMD17 = 17;          // READ_SINGLE_BLOCK
00014 const BYTE CMD18 = 18;          // READ_MULTIPLE_BLOCK
00015 const BYTE ACMD23 = 0x80+23;    // SET_WR_BLK_ERASE_COUNT
00016 const BYTE CMD24 = 24;          // WRITE_BLOCK
00017 const BYTE CMD25 = 25;          // WRITE_MULTIPLE_BLOCK
00018 const BYTE CMD55 = 55;          // APP_CMD
00019 const BYTE CMD58 = 58;          // READ_OCR
00020 
00021 // Card type flag
00022 int CardType;
00023 
00024 // Extern to diskio.cpp
00025 extern FatfsIJFW* _fatfs;
00026 
00027 
00028 FatfsIJFW::FatfsIJFW(SPI* _spi, DigitalOut* _cs) : spi(_spi), cs(_cs) {
00029     _fatfs = this;
00030     Stat = 0;
00031     spi->format(8, 0);
00032     f_mount(NULL, "", 0);
00033 }
00034 
00035 
00036 int FatfsIJFW::mount() {
00037     Stat = 0;
00038     FRESULT res = f_mount(&fs, "", 1);
00039     return (int)res;
00040 }
00041 
00042 
00043 int FatfsIJFW::open(const char* name, const FileMode mode) {
00044     BYTE flags;
00045 
00046     if (mode == MODE_WR) {
00047         // Write and Read
00048         flags = FA_OPEN_EXISTING | FA_READ | FA_WRITE;
00049     } else if (mode == MODE_RO) {
00050         // Read Only
00051         flags = FA_OPEN_EXISTING | FA_READ;
00052     } else if (mode == MODE_APPEND) {
00053         // Append write
00054         flags = FA_OPEN_ALWAYS | FA_WRITE;
00055     } else if (mode == MODE_OVERWRITE) {
00056         // Overwrite
00057         flags = FA_CREATE_ALWAYS | FA_WRITE;
00058     }
00059 
00060     FRESULT res = f_open(&file, name, flags);
00061 
00062     if (mode == MODE_APPEND) {
00063         f_lseek(&file, f_size(&file));
00064     }
00065     
00066     return (int)res;
00067 }
00068 
00069 
00070 int FatfsIJFW::close() {
00071     FRESULT res = f_close(&file);
00072     return (int)res;
00073 }
00074 
00075 
00076 int FatfsIJFW::remove(const char* filename) {
00077     FRESULT res = f_unlink(filename);
00078     return (int)res;
00079 }
00080 
00081 
00082 int FatfsIJFW::mkdir(const char* filename) {
00083     FRESULT res = f_mkdir(filename);
00084     return (int)res;
00085 }
00086 
00087 
00088 int FatfsIJFW::read(char* buf, const int length) {
00089     UINT br;
00090     f_read(&file, buf, (UINT)length, &br);
00091     return (int)br;
00092 }
00093 
00094 
00095 int FatfsIJFW::write(const char* buf, const int length) {
00096     UINT br;
00097     f_write(&file, buf, (UINT)length, &br);
00098     return (int)br;
00099 }
00100 
00101 
00102 int FatfsIJFW::lseek(int pos) {
00103     return (int)f_lseek(&file, (DWORD)pos);
00104 }
00105 
00106 
00107 int FatfsIJFW::filesize() {
00108     return (int)f_size(&file);
00109 }
00110 
00111 
00112 void FatfsIJFW::timerproc() {
00113     if (timerCount) {
00114         timerCount--;
00115     }
00116 }
00117 
00118 
00119 void FatfsIJFW::deselect() {
00120     cs->write(1);
00121     spi->write(0xFF);
00122 }
00123 
00124 
00125 int FatfsIJFW::select() {
00126     cs->write(0);
00127     spi->write(0xFF);
00128 
00129     // Wait for card is ready
00130     if (waitReady(500)) {
00131         return 1;
00132     }
00133 
00134     // Timerout
00135     deselect();
00136     return 0;
00137 }
00138 
00139 
00140 int FatfsIJFW::waitReady(int wait) {
00141     BYTE res;
00142 
00143     timerCount = wait;
00144     do {
00145         res = spi->write(0xFF);
00146     } while (res != 0xFF && timerCount);
00147 
00148     return (res == 0xFF);
00149 }
00150 
00151 
00152 char FatfsIJFW::sendCommand(BYTE cmd, DWORD arg) {
00153     char res;
00154 
00155     // cmd is ACMD<n>
00156     if (cmd & 0x80) {
00157         cmd &= 0x7F;
00158         res = sendCommand(CMD55, 0);
00159         if (res > 1) {
00160             return res;
00161         }
00162     }
00163 
00164     // Select the card and wait for ready except to stop multiple block read
00165     if (cmd != CMD12) {
00166         deselect();
00167         if (!select()) {
00168             return 0xFF;
00169         }
00170     }
00171 
00172     // Send command packet
00173     spi->write(0x40 | cmd);
00174     spi->write((uint8_t)(arg >> 24));
00175     spi->write((uint8_t)(arg >> 16));
00176     spi->write((uint8_t)(arg >> 8));
00177     spi->write((uint8_t)arg);
00178 
00179     // Send CRC packet
00180     BYTE crc;
00181     if (cmd == CMD0) {
00182         crc = 0x95;
00183     } else if (cmd == CMD8) {
00184         crc = 0x87;
00185     } else {
00186         crc = 0x01;
00187     }
00188     spi->write(crc);
00189 
00190     // Diacard following one byte when CMD12
00191     if (cmd == CMD12) {
00192         spi->write(0xFF);
00193     }
00194 
00195     // Wait for response
00196     for (int i = 0; i < 10; i++) {
00197         res = spi->write(0xFF);
00198         if (!(res & 0x80)) {
00199             break;
00200         }
00201     }
00202 
00203     return res;
00204 }
00205 
00206 
00207 int FatfsIJFW::rcvDataBlock(BYTE *buff, UINT btr) {
00208     BYTE token;
00209     timerCount = 200;
00210 
00211     do {
00212         token = spi->write(0xFF);
00213     } while ((token == 0xFF) && timerCount);
00214 
00215     if(token != 0xFE) {     // if invalid token or timeout
00216         return 0;
00217     }
00218 
00219     // Receive the data block
00220     WORD data;
00221     spi->format(16, 0);     // 16bit mode
00222 
00223     for (int i = 0; i < btr; i += 2) {
00224         data = spi->write(0xFFFF);
00225         buff[i] = data >> 8;
00226         buff[i + 1] = data;
00227     }
00228 
00229     spi->write(0xFFFF);     // CRC
00230     spi->format(8, 0);      // 8bit mkode
00231 
00232     return 1;
00233 }
00234 
00235 
00236 int FatfsIJFW::sendDataBlock(const BYTE *buff, BYTE token) {
00237     // Wait for card is ready
00238     if (!waitReady(500)) {
00239         return 0;       
00240     }
00241     
00242     spi->write(token);
00243     if (token != 0xFD) {        // if token is not StopTran
00244         // Send the data block
00245         spi->format(16, 0);     // 16bit mode
00246 
00247         for (int i = 0; i < 512; i += 2) {
00248             unsigned short data = (buff[i] << 8) | buff[i + 1];
00249             spi->write(data);
00250         }
00251         spi->write(0xFFFF);     // CRC
00252         spi->format(8, 0);      // 8bit mode
00253 
00254         BYTE res = spi->write(0xFF);    // Receive data response
00255         if ((res & 0x1F) != 0x05) {     // if the data packet was not accepted
00256             return 0;
00257         }
00258     }
00259 
00260     return 1;
00261 }
00262 
00263 
00264 DSTATUS FatfsIJFW::disk_initialize(BYTE drv) {
00265     if (drv) {      // drive 0 only
00266         return STA_NOINIT;
00267     }
00268 
00269     // Set spi slow clock
00270     spi->frequency(400000);
00271     cs->write(1);
00272 
00273     // Send 80 dummy clocks
00274     for (int i = 0; i < 10; i++) {
00275         spi->write(0xFF);
00276     }
00277 
00278     CardType = 0;
00279     if (sendCommand(CMD0, 0) == 1) {    // reset card
00280         timerCount = 1000;              // Timeout is 1ms
00281 
00282         if (sendCommand(CMD8, 0x1AA) == 1) {
00283             // Get value of R7 response
00284             int ocr[4];
00285             for (int i = 0; i < 4; i++) {
00286                 ocr[i] = spi->write(0xFF);
00287             }
00288 
00289             if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
00290                 // Wait for end of initialization
00291                 while (timerCount > 0 && sendCommand(ACMD41, 1UL << 30));
00292 
00293                 if (timerCount && sendCommand(CMD58, 0) == 0) {
00294                     // Check CCS bit
00295                     for (int i = 0; i < 4; i++) {
00296                         ocr[i] = spi->write(0xFF);
00297                     }
00298                     if (ocr[0] & 0x40) {
00299                         CardType = 0x04 | 0x08;
00300                     } else {
00301                         CardType = 0x04;
00302                     }
00303                 }
00304             }
00305         } else {
00306             if (sendCommand(ACMD41, 0) <= 1) {
00307                 CardType = 0x02;
00308                 while (timerCount > 0 && sendCommand(ACMD41, 0));   // initialization
00309             } else {
00310                 CardType = 0x01;
00311                 while (timerCount > 0 && sendCommand(CMD1, 0)); // initialization
00312             }
00313 
00314             if (timerCount == 0 || sendCommand(CMD16, 512) != 0) {
00315                 CardType = 0;
00316             }
00317         }
00318     }
00319 
00320     deselect();
00321 
00322     if (CardType) {
00323         spi->frequency(1000000);    // Set spi 1MHz
00324         Stat &= ~STA_NOINIT;        // Clear STA_NOINIT flag
00325     } else {
00326         select();
00327         deselect();
00328         Stat = STA_NOINIT;
00329     }
00330 
00331     return Stat;
00332 }
00333 
00334 
00335 DSTATUS FatfsIJFW::disk_status(BYTE drv) {
00336     return RES_OK;
00337 }
00338 
00339 
00340 DRESULT FatfsIJFW::disk_read(BYTE drv, BYTE *buff, DWORD sector, UINT count) {
00341     // if drive is not ready
00342     if (Stat & STA_NOINIT) {
00343         return RES_NOTRDY;
00344     }
00345 
00346     if (drv || !count) {
00347         return RES_PARERR;
00348     }
00349 
00350     // if byte address is BA
00351     if (!(CardType & 0x08)) {
00352         sector *= 512;
00353     }
00354 
00355     // Read a single block or multiple blocks
00356     BYTE cmd = count > 1 ? CMD18 : CMD17;
00357     if (sendCommand(cmd, sector) == 0) {
00358         while (count > 0) {
00359             if (!rcvDataBlock(buff, 512)) {
00360                 if (cmd == CMD18) {
00361                     sendCommand(CMD12, 0);
00362                 }
00363                 break;
00364             }
00365             buff += 512;
00366             count--;
00367         }
00368     }
00369     deselect();
00370 
00371     return count ? RES_ERROR : RES_OK;
00372 }
00373 
00374 
00375 DRESULT FatfsIJFW::disk_write(BYTE drv, const BYTE *buff, DWORD sector, UINT count) {
00376     // if drive is not ready
00377     if (Stat & STA_NOINIT) {
00378         return RES_NOTRDY;
00379     }
00380     
00381     if (drv || !count) {
00382         return RES_PARERR;
00383     }
00384 
00385     // if byte address is BA
00386     if (!(CardType & 0x08)) {
00387         sector *= 512;
00388     }
00389 
00390     // Write a single block or multiple blocks
00391     DRESULT res = RES_ERROR;
00392     if (count > 1) {
00393         if (CardType & 0x06) {
00394             sendCommand(ACMD23, count);     // Send predefine number of sectors
00395         }
00396         if (sendCommand(CMD25, sector) == 0) {
00397             while (count > 0) {
00398                 if (!sendDataBlock(buff, 0xFC)) {
00399                     break;
00400                 }
00401                 buff += 512;
00402                 count--;
00403             }
00404             if (sendDataBlock(0, 0xFD)) {
00405                 res = RES_OK;
00406             }
00407         }
00408     } else {
00409         if (sendCommand(CMD24, sector) == 0) {
00410             if (sendDataBlock(buff, 0xFE)) {
00411                 res = RES_OK;
00412             }
00413         }
00414     }
00415     deselect();
00416 
00417     return res;
00418 }
00419 
00420 
00421 DRESULT FatfsIJFW::disk_ioctl(BYTE drv, BYTE cmd, void* buff) {
00422     // ioctl is not supported
00423     return RES_ERROR;
00424 }
00425