iSDIO library for FlashAir

Dependents:   FlashAir_iSDIO_sample FlashAir_iSDIO_16seg_ADT7410_step1 FlashAir_iSDIO_16seg_ADT7410 FlashAir_iSDIO_sample_OS5_ ... more

iSDIO.cpp

Committer:
hogejun
Date:
2019-01-19
Revision:
2:b8b33621e7fe
Parent:
1:dc888b9028cf

File content as of revision 2:b8b33621e7fe:

/* mbed SD iSDIO Library
 * Copyright (C) 2018 by Junichi SHIBA, PIAX Inc.
 *
 * Arduino Sdio Library
 * Copyright (C) 2014 by Munehiro Doi
 *
 * This file is an SD extension of the Arduino Sd2Card Library
 * Copyright (C) 2009 by William Greiman
 *
 * This Library 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 3 of the License, or
 * (at your option) any later version.
 *
 * This Library 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Arduino Sd2Card Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include "mbed.h"
#include "iSDIO.h"

//------------------------------------------------------------------------------
// SD extension commands
/** EXTENSION READ - Extension Register Read Command (Single Block) */
uint8_t const CMD48 = 0X30;
/** EXTENSION WRITE - Extension Register Write Command (Single Block) */
uint8_t const CMD49 = 0X31;
/** EXTENSION READ - Extension Register Read Command (Multi Block) */
uint8_t const CMD17 = 17;
/** EXTENSION READ - Extension Register Read Command (Multi Block) */
uint8_t const CMD24 = 24;

//------------------------------------------------------------------------------
// SD extension error codes.
/** card returned an error response for CMD48 (read extension block) */
uint8_t const SD_CARD_ERROR_CMD48 = 0X80;
/** card returned an error response for CMD49 (write extension block) */
uint8_t const SD_CARD_ERROR_CMD49 = 0X81;
//------------------------------------------------------------------------------

iSDIO::iSDIO(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, Serial* console) :
    SDFileSystem(mosi, miso, sclk, cs, name)
{
    instance = this;
    _console = console;
    sequenceId = 0;
    if (_console != NULL)
    _console->printf("new iSDIO\n");
}

iSDIO::~iSDIO(void) {}

iSDIO* iSDIO::instance = 0;

iSDIO* iSDIO::getInstance()
{
    return iSDIO::instance;
}

uint32_t iSDIO::getSequenceId()
{
    if (_console != NULL)
    _console->printf("sequenceId: %d\n", sequenceId);
    return sequenceId;
}

uint32_t iSDIO::getNextSequenceId()
{
    sequenceId++;
    if (_console != NULL)
    _console->printf("Next sequenceId: %d\n", sequenceId);
    return sequenceId;
}

uint8_t const   DATA_START_BLOCK = 0XFE ;
uint8_t const   DATA_RES_MASK = 0X1F ;
uint8_t const   DATA_RES_ACCEPTED = 0X05 ;

//------------------------------------------------------------------------------
/** Perform Extention Read. */
uint8_t iSDIO::readExt(uint32_t arg, uint8_t* dst, uint16_t count)
{
    uint16_t i;
    // send command and argument.
    if (_cmd(CMD48, arg) && _cmd(CMD17, arg)) {
        error("SD_CARD_ERROR_CMD48");
        _cs = 1;
        return false;
    }

    _cs = 0;

    // wait for start block token.
    while (_spi.write(0xFF) == 0xFF);

    // receive data
    for (i = 0; i < count; ++i) {
        dst[i] = _spi.write(0xFF);
    }
    // skip dummy bytes and 16-bit crc.
    for (; i < 514; ++i) {
        _spi.write(0xFF);
    }
    _cs = 1;
    _spi.write(0xFF); // dummy clock to force FlashAir finish the command.
    return true;
}

//------------------------------------------------------------------------------
/** Perform Extention Write. */
uint8_t iSDIO::writeExt(uint32_t arg, const uint8_t* src, uint16_t count)
{
    uint16_t i;
    uint8_t status;
    // send command and argument.
    if (_cmd(CMD49, arg) && _cmd(CMD24, arg)) {
        error("SD_CARD_ERROR_CMD49");
        _cs = 1;
        return false;
    }

    _cs = 0;

    // send start block token.
    _spi.write(DATA_START_BLOCK);
    //////_spi.write(0xFE);
    // send data
    for (i = 0; i < count; ++i) {
        _spi.write(src[i]);
    }
    // send dummy bytes until 512 bytes.
    for (; i < 512; ++i) {
        _spi.write(0xFF);
    }
    // dummy 16-bit crc
    _spi.write(0xFF);
    _spi.write(0xFF);
    // wait a data response token
    status = _spi.write(0xFF);
    if ((status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
    //////if ((status & 0x1F) != 0x05) {
        error("SD_CARD_ERROR_WRITE");
        _cs = 1;
        return false;
    }
    // wait for flash programming to complete
    while (_spi.write(0xFF) == 0);

    _cs = 1;
    return true;
}

//------------------------------------------------------------------------------
/**
 * Read a 512 byte data port in an extension register space.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.
 */
uint8_t iSDIO::readExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, uint8_t* dst)
{
    uint32_t arg =
        (((uint32_t)mio & 0x1) << 31) |
        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
        (((uint32_t)addr & 0x1FE00) << 9);
    return readExt(arg, dst, 512);
}

//------------------------------------------------------------------------------
/**
 * Read an extension register space.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.
 */
uint8_t iSDIO::readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst)
{
    uint32_t offset = addr & 0x1FF;
    if (offset + count > 512) count = 512 - offset;
    if (count == 0) return true;
    uint32_t arg =
        (((uint32_t)mio & 0x1) << 31) |
        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
        ((addr & 0x1FFFF) << 9) |
        ((count - 1) & 0x1FF);
    return readExt(arg, dst, count);
}

//------------------------------------------------------------------------------
/**
 * Write a 512 byte data port into an extension register space.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.
 */
uint8_t iSDIO::writeExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, const uint8_t* src)
{
    uint32_t arg =
        (((uint32_t)mio & 0x1) << 31) |
        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
        (((uint32_t)addr & 0x1FE00) << 9);
        if (_console != NULL)
        _console->printf("arg = %08x\n", arg);
    return writeExt(arg, src, 512);
}

//------------------------------------------------------------------------------
/**
 * Write an extension register space.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.
 */
uint8_t iSDIO::writeExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, const uint8_t* src)
{
    uint32_t arg =
        (((uint32_t)mio & 0x1) << 31) |
        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
        ((addr & 0x1FFFF) << 9) |
        ((count - 1) & 0x1FF);
        if (_console != NULL) {
        _console->printf("writeExtMemory: ");
        _console->printf("          addr: %08x\n", addr);
        _console->printf("           src: ");
        }
        printHex((uint8_t*)src, (uint32_t)count);
        if (_console != NULL)
        _console->printf("         count: %d\n", count);
    return writeExt(arg, src, count);
}

//------------------------------------------------------------------------------
/**
 * Writes a byte-data with mask into an extension register space.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.
 */
uint8_t iSDIO::writeExtMask(uint8_t mio, uint8_t func, uint32_t addr, uint8_t mask, const uint8_t* src)
{
    uint32_t arg =
        (((uint32_t)mio & 0x1) << 31) |
        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
        (0x1 << 26) |
        ((addr & 0x1FFFF) << 9) |
        mask;
    return writeExt(arg, src, 1);
}


uint8_t iSDIO::waitResponse(uint32_t sequenceId)
{
    uint8_t buffer[ISDIO_STATUS_QUEUE_SIZE];
    if(_console != NULL)
    _console->printf("\nWaiting response ");
    uint8_t prev = 0xFF;
    for (int i = 0; i < 20; ++i) {
        memset(buffer, 0, ISDIO_STATUS_QUEUE_SIZE);
        // Read command response status.
        if (!readExtMemory(MIO_IO, FUNC1, ISDIO_STATUS_QUEUE, ISDIO_STATUS_QUEUE_SIZE, buffer)) {
            return false;
        }
        uint8_t resp = get_u8(buffer + 8);
        if (sequenceId == get_u32(buffer + 4)) {
            if (prev != resp) {
                switch (resp) {
                    case 0x00:
                        if (_console != NULL)
                        _console->printf("\n  Initial");
                        break;
                    case 0x01:
                        if (_console != NULL)
                        _console->printf("\n  Command Processing");
                        break;
                    case 0x02:
                        if (_console != NULL)
                        _console->printf("\n  Command Rejected");
                        return false;
                    case 0x03:
                        if (_console != NULL)
                        _console->printf("\n  Process Succeeded");
                        return true;
                    case 0x04:
                        if (_console != NULL)
                        _console->printf("\n  Process Terminated");
                        return false;
                    default:
                        if (_console != NULL) {
                        _console->printf("\n  Process Failed ");
                        _console->printf("%x", resp);
                        }
                        return false;
                }
                prev = resp;
            }
        }
        if (_console != NULL)
        _console->printf(".");
        wait_ms(1000);
    }
    return false;
}



void iSDIO::printByte(uint8_t value)
{
    if (_console != NULL) {
    _console->printf("%x", value >> 4);
    _console->printf("%x", value & 0xF);
    }
}
void iSDIO::printBytes(uint8_t* p, uint32_t len)
{
    for (int i = 0; i < len; ++i) {
        printByte(p[i]);
    }
}
void iSDIO::printHex(uint8_t* p, uint32_t len) {
  int i = 0;
  while (i < len) {
    if ((i & 0xf) == 0) {
      if (_console != NULL)
      _console->printf("\n");
      printByte(i >> 4);
      if (_console != NULL)
      _console->printf(": ");
    }
    printByte(*p++);
    i++;
  }
  if (_console != NULL)
  _console->printf("\n");
}