IJFW - IchigoJamのBASICプログラムをメモリカード(MMCまたは互換カード)に保存したり読み出したりできるプログラム。メモリカードにファームウェアのファイルを置くだけで、電源ON時に自動的に書き換える機能も搭載(一応こちらがメイン)。LPC1114FN28専用。
参考URL http://www.cyberchabudai.org/index.php/entry?tag=IJFW
Diff: FatfsIJFW/FatfsIJFW.cpp
- Revision:
- 0:43cce7b453d0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FatfsIJFW/FatfsIJFW.cpp Thu Apr 28 11:23:24 2016 +0000 @@ -0,0 +1,425 @@ +#include "mbed.h" +#include "ff.h" +#include "FatfsIJFW.h" + + +// Command of memory card +const BYTE CMD0 = 0; // GO_IDLE_STATE +const BYTE CMD1 = 1; // SEND_OP_COND +const BYTE ACMD41 = 0x80+41; // SEND_OP_COND +const BYTE CMD8 = 8; // SEND_IF_COND +const BYTE CMD12 = 12; // STOP_TRANSMISSION +const BYTE CMD16 = 16; // SET_BLOCKLEN +const BYTE CMD17 = 17; // READ_SINGLE_BLOCK +const BYTE CMD18 = 18; // READ_MULTIPLE_BLOCK +const BYTE ACMD23 = 0x80+23; // SET_WR_BLK_ERASE_COUNT +const BYTE CMD24 = 24; // WRITE_BLOCK +const BYTE CMD25 = 25; // WRITE_MULTIPLE_BLOCK +const BYTE CMD55 = 55; // APP_CMD +const BYTE CMD58 = 58; // READ_OCR + +// Card type flag +int CardType; + +// Extern to diskio.cpp +extern FatfsIJFW* _fatfs; + + +FatfsIJFW::FatfsIJFW(SPI* _spi, DigitalOut* _cs) : spi(_spi), cs(_cs) { + _fatfs = this; + Stat = 0; + spi->format(8, 0); + f_mount(NULL, "", 0); +} + + +int FatfsIJFW::mount() { + Stat = 0; + FRESULT res = f_mount(&fs, "", 1); + return (int)res; +} + + +int FatfsIJFW::open(const char* name, const FileMode mode) { + BYTE flags; + + if (mode == MODE_WR) { + // Write and Read + flags = FA_OPEN_EXISTING | FA_READ | FA_WRITE; + } else if (mode == MODE_RO) { + // Read Only + flags = FA_OPEN_EXISTING | FA_READ; + } else if (mode == MODE_APPEND) { + // Append write + flags = FA_OPEN_ALWAYS | FA_WRITE; + } else if (mode == MODE_OVERWRITE) { + // Overwrite + flags = FA_CREATE_ALWAYS | FA_WRITE; + } + + FRESULT res = f_open(&file, name, flags); + + if (mode == MODE_APPEND) { + f_lseek(&file, f_size(&file)); + } + + return (int)res; +} + + +int FatfsIJFW::close() { + FRESULT res = f_close(&file); + return (int)res; +} + + +int FatfsIJFW::remove(const char* filename) { + FRESULT res = f_unlink(filename); + return (int)res; +} + + +int FatfsIJFW::mkdir(const char* filename) { + FRESULT res = f_mkdir(filename); + return (int)res; +} + + +int FatfsIJFW::read(char* buf, const int length) { + UINT br; + f_read(&file, buf, (UINT)length, &br); + return (int)br; +} + + +int FatfsIJFW::write(const char* buf, const int length) { + UINT br; + f_write(&file, buf, (UINT)length, &br); + return (int)br; +} + + +int FatfsIJFW::lseek(int pos) { + return (int)f_lseek(&file, (DWORD)pos); +} + + +int FatfsIJFW::filesize() { + return (int)f_size(&file); +} + + +void FatfsIJFW::timerproc() { + if (timerCount) { + timerCount--; + } +} + + +void FatfsIJFW::deselect() { + cs->write(1); + spi->write(0xFF); +} + + +int FatfsIJFW::select() { + cs->write(0); + spi->write(0xFF); + + // Wait for card is ready + if (waitReady(500)) { + return 1; + } + + // Timerout + deselect(); + return 0; +} + + +int FatfsIJFW::waitReady(int wait) { + BYTE res; + + timerCount = wait; + do { + res = spi->write(0xFF); + } while (res != 0xFF && timerCount); + + return (res == 0xFF); +} + + +char FatfsIJFW::sendCommand(BYTE cmd, DWORD arg) { + char res; + + // cmd is ACMD<n> + if (cmd & 0x80) { + cmd &= 0x7F; + res = sendCommand(CMD55, 0); + if (res > 1) { + return res; + } + } + + // Select the card and wait for ready except to stop multiple block read + if (cmd != CMD12) { + deselect(); + if (!select()) { + return 0xFF; + } + } + + // Send command packet + spi->write(0x40 | cmd); + spi->write((uint8_t)(arg >> 24)); + spi->write((uint8_t)(arg >> 16)); + spi->write((uint8_t)(arg >> 8)); + spi->write((uint8_t)arg); + + // Send CRC packet + BYTE crc; + if (cmd == CMD0) { + crc = 0x95; + } else if (cmd == CMD8) { + crc = 0x87; + } else { + crc = 0x01; + } + spi->write(crc); + + // Diacard following one byte when CMD12 + if (cmd == CMD12) { + spi->write(0xFF); + } + + // Wait for response + for (int i = 0; i < 10; i++) { + res = spi->write(0xFF); + if (!(res & 0x80)) { + break; + } + } + + return res; +} + + +int FatfsIJFW::rcvDataBlock(BYTE *buff, UINT btr) { + BYTE token; + timerCount = 200; + + do { + token = spi->write(0xFF); + } while ((token == 0xFF) && timerCount); + + if(token != 0xFE) { // if invalid token or timeout + return 0; + } + + // Receive the data block + WORD data; + spi->format(16, 0); // 16bit mode + + for (int i = 0; i < btr; i += 2) { + data = spi->write(0xFFFF); + buff[i] = data >> 8; + buff[i + 1] = data; + } + + spi->write(0xFFFF); // CRC + spi->format(8, 0); // 8bit mkode + + return 1; +} + + +int FatfsIJFW::sendDataBlock(const BYTE *buff, BYTE token) { + // Wait for card is ready + if (!waitReady(500)) { + return 0; + } + + spi->write(token); + if (token != 0xFD) { // if token is not StopTran + // Send the data block + spi->format(16, 0); // 16bit mode + + for (int i = 0; i < 512; i += 2) { + unsigned short data = (buff[i] << 8) | buff[i + 1]; + spi->write(data); + } + spi->write(0xFFFF); // CRC + spi->format(8, 0); // 8bit mode + + BYTE res = spi->write(0xFF); // Receive data response + if ((res & 0x1F) != 0x05) { // if the data packet was not accepted + return 0; + } + } + + return 1; +} + + +DSTATUS FatfsIJFW::disk_initialize(BYTE drv) { + if (drv) { // drive 0 only + return STA_NOINIT; + } + + // Set spi slow clock + spi->frequency(400000); + cs->write(1); + + // Send 80 dummy clocks + for (int i = 0; i < 10; i++) { + spi->write(0xFF); + } + + CardType = 0; + if (sendCommand(CMD0, 0) == 1) { // reset card + timerCount = 1000; // Timeout is 1ms + + if (sendCommand(CMD8, 0x1AA) == 1) { + // Get value of R7 response + int ocr[4]; + for (int i = 0; i < 4; i++) { + ocr[i] = spi->write(0xFF); + } + + if (ocr[2] == 0x01 && ocr[3] == 0xAA) { + // Wait for end of initialization + while (timerCount > 0 && sendCommand(ACMD41, 1UL << 30)); + + if (timerCount && sendCommand(CMD58, 0) == 0) { + // Check CCS bit + for (int i = 0; i < 4; i++) { + ocr[i] = spi->write(0xFF); + } + if (ocr[0] & 0x40) { + CardType = 0x04 | 0x08; + } else { + CardType = 0x04; + } + } + } + } else { + if (sendCommand(ACMD41, 0) <= 1) { + CardType = 0x02; + while (timerCount > 0 && sendCommand(ACMD41, 0)); // initialization + } else { + CardType = 0x01; + while (timerCount > 0 && sendCommand(CMD1, 0)); // initialization + } + + if (timerCount == 0 || sendCommand(CMD16, 512) != 0) { + CardType = 0; + } + } + } + + deselect(); + + if (CardType) { + spi->frequency(1000000); // Set spi 1MHz + Stat &= ~STA_NOINIT; // Clear STA_NOINIT flag + } else { + select(); + deselect(); + Stat = STA_NOINIT; + } + + return Stat; +} + + +DSTATUS FatfsIJFW::disk_status(BYTE drv) { + return RES_OK; +} + + +DRESULT FatfsIJFW::disk_read(BYTE drv, BYTE *buff, DWORD sector, UINT count) { + // if drive is not ready + if (Stat & STA_NOINIT) { + return RES_NOTRDY; + } + + if (drv || !count) { + return RES_PARERR; + } + + // if byte address is BA + if (!(CardType & 0x08)) { + sector *= 512; + } + + // Read a single block or multiple blocks + BYTE cmd = count > 1 ? CMD18 : CMD17; + if (sendCommand(cmd, sector) == 0) { + while (count > 0) { + if (!rcvDataBlock(buff, 512)) { + if (cmd == CMD18) { + sendCommand(CMD12, 0); + } + break; + } + buff += 512; + count--; + } + } + deselect(); + + return count ? RES_ERROR : RES_OK; +} + + +DRESULT FatfsIJFW::disk_write(BYTE drv, const BYTE *buff, DWORD sector, UINT count) { + // if drive is not ready + if (Stat & STA_NOINIT) { + return RES_NOTRDY; + } + + if (drv || !count) { + return RES_PARERR; + } + + // if byte address is BA + if (!(CardType & 0x08)) { + sector *= 512; + } + + // Write a single block or multiple blocks + DRESULT res = RES_ERROR; + if (count > 1) { + if (CardType & 0x06) { + sendCommand(ACMD23, count); // Send predefine number of sectors + } + if (sendCommand(CMD25, sector) == 0) { + while (count > 0) { + if (!sendDataBlock(buff, 0xFC)) { + break; + } + buff += 512; + count--; + } + if (sendDataBlock(0, 0xFD)) { + res = RES_OK; + } + } + } else { + if (sendCommand(CMD24, sector) == 0) { + if (sendDataBlock(buff, 0xFE)) { + res = RES_OK; + } + } + } + deselect(); + + return res; +} + + +DRESULT FatfsIJFW::disk_ioctl(BYTE drv, BYTE cmd, void* buff) { + // ioctl is not supported + return RES_ERROR; +} +