Merge pull request #3623 from jbrazio/cleanup/convert2unix

master
Scott Lahteine 9 years ago
commit 6d98f47d1c

@ -1,718 +1,718 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino Sd2Card Library * Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman * Copyright (C) 2009 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#include "Sd2Card.h" #include "Sd2Card.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if DISABLED(SOFTWARE_SPI) #if DISABLED(SOFTWARE_SPI)
// functions for hardware SPI // functions for hardware SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// make sure SPCR rate is in expected bits // make sure SPCR rate is in expected bits
#if (SPR0 != 0 || SPR1 != 1) #if (SPR0 != 0 || SPR1 != 1)
#error unexpected SPCR bits #error unexpected SPCR bits
#endif #endif
/** /**
* Initialize hardware SPI * Initialize hardware SPI
* Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
*/ */
static void spiInit(uint8_t spiRate) { static void spiInit(uint8_t spiRate) {
// See avr processor documentation // See avr processor documentation
SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1); SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1);
SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X); SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SPI receive a byte */ /** SPI receive a byte */
static uint8_t spiRec() { static uint8_t spiRec() {
SPDR = 0XFF; SPDR = 0XFF;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
return SPDR; return SPDR;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SPI read data - only one call so force inline */ /** SPI read data - only one call so force inline */
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t* buf, uint16_t nbyte) {
if (nbyte-- == 0) return; if (nbyte-- == 0) return;
SPDR = 0XFF; SPDR = 0XFF;
for (uint16_t i = 0; i < nbyte; i++) { for (uint16_t i = 0; i < nbyte; i++) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[i] = SPDR; buf[i] = SPDR;
SPDR = 0XFF; SPDR = 0XFF;
} }
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[nbyte] = SPDR; buf[nbyte] = SPDR;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SPI send a byte */ /** SPI send a byte */
static void spiSend(uint8_t b) { static void spiSend(uint8_t b) {
SPDR = b; SPDR = b;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SPI send block - only one call so force inline */ /** SPI send block - only one call so force inline */
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t* buf) {
SPDR = token; SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) { for (uint16_t i = 0; i < 512; i += 2) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i]; SPDR = buf[i];
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i + 1]; SPDR = buf[i + 1];
} }
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#else // SOFTWARE_SPI #else // SOFTWARE_SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** nop to tune soft SPI timing */ /** nop to tune soft SPI timing */
#define nop asm volatile ("nop\n\t") #define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Soft SPI receive byte */ /** Soft SPI receive byte */
static uint8_t spiRec() { static uint8_t spiRec() {
uint8_t data = 0; uint8_t data = 0;
// no interrupts during byte receive - about 8 us // no interrupts during byte receive - about 8 us
cli(); cli();
// output pin high - like sending 0XFF // output pin high - like sending 0XFF
fastDigitalWrite(SPI_MOSI_PIN, HIGH); fastDigitalWrite(SPI_MOSI_PIN, HIGH);
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
fastDigitalWrite(SPI_SCK_PIN, HIGH); fastDigitalWrite(SPI_SCK_PIN, HIGH);
// adjust so SCK is nice // adjust so SCK is nice
nop; nop;
nop; nop;
data <<= 1; data <<= 1;
if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
fastDigitalWrite(SPI_SCK_PIN, LOW); fastDigitalWrite(SPI_SCK_PIN, LOW);
} }
// enable interrupts // enable interrupts
sei(); sei();
return data; return data;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Soft SPI read data */ /** Soft SPI read data */
static void spiRead(uint8_t* buf, uint16_t nbyte) { static void spiRead(uint8_t* buf, uint16_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++) for (uint16_t i = 0; i < nbyte; i++)
buf[i] = spiRec(); buf[i] = spiRec();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Soft SPI send byte */ /** Soft SPI send byte */
static void spiSend(uint8_t data) { static void spiSend(uint8_t data) {
// no interrupts during byte send - about 8 us // no interrupts during byte send - about 8 us
cli(); cli();
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
fastDigitalWrite(SPI_SCK_PIN, LOW); fastDigitalWrite(SPI_SCK_PIN, LOW);
fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
data <<= 1; data <<= 1;
fastDigitalWrite(SPI_SCK_PIN, HIGH); fastDigitalWrite(SPI_SCK_PIN, HIGH);
} }
// hold SCK high for a few ns // hold SCK high for a few ns
nop; nop;
nop; nop;
nop; nop;
nop; nop;
fastDigitalWrite(SPI_SCK_PIN, LOW); fastDigitalWrite(SPI_SCK_PIN, LOW);
// enable interrupts // enable interrupts
sei(); sei();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Soft SPI send block */ /** Soft SPI send block */
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t* buf) {
spiSend(token); spiSend(token);
for (uint16_t i = 0; i < 512; i++) for (uint16_t i = 0; i < 512; i++)
spiSend(buf[i]); spiSend(buf[i]);
} }
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// send command and return error code. Return zero for OK // send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
// select card // select card
chipSelectLow(); chipSelectLow();
// wait up to 300 ms if busy // wait up to 300 ms if busy
waitNotBusy(300); waitNotBusy(300);
// send command // send command
spiSend(cmd | 0x40); spiSend(cmd | 0x40);
// send argument // send argument
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
// send CRC // send CRC
uint8_t crc = 0XFF; uint8_t crc = 0XFF;
if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
spiSend(crc); spiSend(crc);
// skip stuff byte for stop read // skip stuff byte for stop read
if (cmd == CMD12) spiRec(); if (cmd == CMD12) spiRec();
// wait for response // wait for response
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ }
return status_; return status_;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Determine the size of an SD flash memory card. * Determine the size of an SD flash memory card.
* *
* \return The number of 512 byte data blocks in the card * \return The number of 512 byte data blocks in the card
* or zero if an error occurs. * or zero if an error occurs.
*/ */
uint32_t Sd2Card::cardSize() { uint32_t Sd2Card::cardSize() {
csd_t csd; csd_t csd;
if (!readCSD(&csd)) return 0; if (!readCSD(&csd)) return 0;
if (csd.v1.csd_ver == 0) { if (csd.v1.csd_ver == 0) {
uint8_t read_bl_len = csd.v1.read_bl_len; uint8_t read_bl_len = csd.v1.read_bl_len;
uint16_t c_size = (csd.v1.c_size_high << 10) uint16_t c_size = (csd.v1.c_size_high << 10)
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
| csd.v1.c_size_mult_low; | csd.v1.c_size_mult_low;
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
} }
else if (csd.v2.csd_ver == 1) { else if (csd.v2.csd_ver == 1) {
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
return (c_size + 1) << 10; return (c_size + 1) << 10;
} }
else { else {
error(SD_CARD_ERROR_BAD_CSD); error(SD_CARD_ERROR_BAD_CSD);
return 0; return 0;
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Sd2Card::chipSelectHigh() { void Sd2Card::chipSelectHigh() {
digitalWrite(chipSelectPin_, HIGH); digitalWrite(chipSelectPin_, HIGH);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Sd2Card::chipSelectLow() { void Sd2Card::chipSelectLow() {
#if DISABLED(SOFTWARE_SPI) #if DISABLED(SOFTWARE_SPI)
spiInit(spiRate_); spiInit(spiRate_);
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
digitalWrite(chipSelectPin_, LOW); digitalWrite(chipSelectPin_, LOW);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Erase a range of blocks. /** Erase a range of blocks.
* *
* \param[in] firstBlock The address of the first block in the range. * \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range. * \param[in] lastBlock The address of the last block in the range.
* *
* \note This function requests the SD card to do a flash erase for a * \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is * range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support * either 0 or 1, depends on the card vendor. The card must support
* single block erase. * single block erase.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd; csd_t csd;
if (!readCSD(&csd)) goto fail; if (!readCSD(&csd)) goto fail;
// check for single block erase // check for single block erase
if (!csd.v1.erase_blk_en) { if (!csd.v1.erase_blk_en) {
// erase size mask // erase size mask
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area // error card can't erase specified area
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
goto fail; goto fail;
} }
} }
if (type_ != SD_CARD_TYPE_SDHC) { if (type_ != SD_CARD_TYPE_SDHC) {
firstBlock <<= 9; firstBlock <<= 9;
lastBlock <<= 9; lastBlock <<= 9;
} }
if (cardCommand(CMD32, firstBlock) if (cardCommand(CMD32, firstBlock)
|| cardCommand(CMD33, lastBlock) || cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) { || cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE); error(SD_CARD_ERROR_ERASE);
goto fail; goto fail;
} }
if (!waitNotBusy(SD_ERASE_TIMEOUT)) { if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT); error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail; goto fail;
} }
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Determine if card supports single block erase. /** Determine if card supports single block erase.
* *
* \return The value one, true, is returned if single block erase is supported. * \return The value one, true, is returned if single block erase is supported.
* The value zero, false, is returned if single block erase is not supported. * The value zero, false, is returned if single block erase is not supported.
*/ */
bool Sd2Card::eraseSingleBlockEnable() { bool Sd2Card::eraseSingleBlockEnable() {
csd_t csd; csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : false; return readCSD(&csd) ? csd.v1.erase_blk_en : false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Initialize an SD flash memory card. * Initialize an SD flash memory card.
* *
* \param[in] sckRateID SPI clock rate selector. See setSckRate(). * \param[in] sckRateID SPI clock rate selector. See setSckRate().
* \param[in] chipSelectPin SD chip select pin number. * \param[in] chipSelectPin SD chip select pin number.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. The reason for failure * the value zero, false, is returned for failure. The reason for failure
* can be determined by calling errorCode() and errorData(). * can be determined by calling errorCode() and errorData().
*/ */
bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
errorCode_ = type_ = 0; errorCode_ = type_ = 0;
chipSelectPin_ = chipSelectPin; chipSelectPin_ = chipSelectPin;
// 16-bit init start time allows over a minute // 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)millis(); uint16_t t0 = (uint16_t)millis();
uint32_t arg; uint32_t arg;
// set pin modes // set pin modes
pinMode(chipSelectPin_, OUTPUT); pinMode(chipSelectPin_, OUTPUT);
chipSelectHigh(); chipSelectHigh();
pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MISO_PIN, INPUT);
pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_MOSI_PIN, OUTPUT);
pinMode(SPI_SCK_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT);
#if DISABLED(SOFTWARE_SPI) #if DISABLED(SOFTWARE_SPI)
// SS must be in output mode even it is not chip select // SS must be in output mode even it is not chip select
pinMode(SS_PIN, OUTPUT); pinMode(SS_PIN, OUTPUT);
// set SS high - may be chip select for another SPI device // set SS high - may be chip select for another SPI device
#if SET_SPI_SS_HIGH #if SET_SPI_SS_HIGH
digitalWrite(SS_PIN, HIGH); digitalWrite(SS_PIN, HIGH);
#endif // SET_SPI_SS_HIGH #endif // SET_SPI_SS_HIGH
// set SCK rate for initialization commands // set SCK rate for initialization commands
spiRate_ = SPI_SD_INIT_RATE; spiRate_ = SPI_SD_INIT_RATE;
spiInit(spiRate_); spiInit(spiRate_);
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
// must supply min of 74 clock cycles with CS high. // must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
// command to go idle in SPI mode // command to go idle in SPI mode
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_CMD0); error(SD_CARD_ERROR_CMD0);
goto fail; goto fail;
} }
} }
// check SD version // check SD version
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
type(SD_CARD_TYPE_SD1); type(SD_CARD_TYPE_SD1);
} }
else { else {
// only need last byte of r7 response // only need last byte of r7 response
for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
if (status_ != 0XAA) { if (status_ != 0XAA) {
error(SD_CARD_ERROR_CMD8); error(SD_CARD_ERROR_CMD8);
goto fail; goto fail;
} }
type(SD_CARD_TYPE_SD2); type(SD_CARD_TYPE_SD2);
} }
// initialize card and send host supports SDHC if SD2 // initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
// check for timeout // check for timeout
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_ACMD41); error(SD_CARD_ERROR_ACMD41);
goto fail; goto fail;
} }
} }
// if SD2 read OCR register to check for SDHC card // if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) { if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) { if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58); error(SD_CARD_ERROR_CMD58);
goto fail; goto fail;
} }
if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
// discard rest of ocr - contains allowed voltage range // discard rest of ocr - contains allowed voltage range
for (uint8_t i = 0; i < 3; i++) spiRec(); for (uint8_t i = 0; i < 3; i++) spiRec();
} }
chipSelectHigh(); chipSelectHigh();
#if DISABLED(SOFTWARE_SPI) #if DISABLED(SOFTWARE_SPI)
return setSckRate(sckRateID); return setSckRate(sckRateID);
#else // SOFTWARE_SPI #else // SOFTWARE_SPI
UNUSED(sckRateID); UNUSED(sckRateID);
return true; return true;
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Read a 512 byte block from an SD card. * Read a 512 byte block from an SD card.
* *
* \param[in] blockNumber Logical block to be read. * \param[in] blockNumber Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data. * \param[out] dst Pointer to the location that will receive the data.
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
// use address if not SDHC card // use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
#if ENABLED(SD_CHECK_AND_RETRY) #if ENABLED(SD_CHECK_AND_RETRY)
uint8_t retryCnt = 3; uint8_t retryCnt = 3;
do { do {
if (!cardCommand(CMD17, blockNumber)) { if (!cardCommand(CMD17, blockNumber)) {
if (readData(dst, 512)) return true; if (readData(dst, 512)) return true;
} }
else else
error(SD_CARD_ERROR_CMD17); error(SD_CARD_ERROR_CMD17);
if (--retryCnt) break; if (--retryCnt) break;
chipSelectHigh(); chipSelectHigh();
cardCommand(CMD12, 0); // Try sending a stop command, ignore the result. cardCommand(CMD12, 0); // Try sending a stop command, ignore the result.
errorCode_ = 0; errorCode_ = 0;
} while (true); } while (true);
#else #else
if (cardCommand(CMD17, blockNumber)) if (cardCommand(CMD17, blockNumber))
error(SD_CARD_ERROR_CMD17); error(SD_CARD_ERROR_CMD17);
else else
return readData(dst, 512); return readData(dst, 512);
#endif #endif
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Read one data block in a multiple block read sequence /** Read one data block in a multiple block read sequence
* *
* \param[in] dst Pointer to the location for the data to be read. * \param[in] dst Pointer to the location for the data to be read.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::readData(uint8_t* dst) { bool Sd2Card::readData(uint8_t* dst) {
chipSelectLow(); chipSelectLow();
return readData(dst, 512); return readData(dst, 512);
} }
#if ENABLED(SD_CHECK_AND_RETRY) #if ENABLED(SD_CHECK_AND_RETRY)
static const uint16_t crctab[] PROGMEM = { static const uint16_t crctab[] PROGMEM = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
}; };
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
uint16_t crc = 0; uint16_t crc = 0;
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8); crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
} }
return crc; return crc;
} }
#endif #endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool Sd2Card::readData(uint8_t* dst, uint16_t count) { bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
// wait for start block token // wait for start block token
uint16_t t0 = millis(); uint16_t t0 = millis();
while ((status_ = spiRec()) == 0XFF) { while ((status_ = spiRec()) == 0XFF) {
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
error(SD_CARD_ERROR_READ_TIMEOUT); error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail; goto fail;
} }
} }
if (status_ != DATA_START_BLOCK) { if (status_ != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ); error(SD_CARD_ERROR_READ);
goto fail; goto fail;
} }
// transfer data // transfer data
spiRead(dst, count); spiRead(dst, count);
#if ENABLED(SD_CHECK_AND_RETRY) #if ENABLED(SD_CHECK_AND_RETRY)
{ {
uint16_t calcCrc = CRC_CCITT(dst, count); uint16_t calcCrc = CRC_CCITT(dst, count);
uint16_t recvCrc = spiRec() << 8; uint16_t recvCrc = spiRec() << 8;
recvCrc |= spiRec(); recvCrc |= spiRec();
if (calcCrc != recvCrc) { if (calcCrc != recvCrc) {
error(SD_CARD_ERROR_CRC); error(SD_CARD_ERROR_CRC);
goto fail; goto fail;
} }
} }
#else #else
// discard CRC // discard CRC
spiRec(); spiRec();
spiRec(); spiRec();
#endif #endif
chipSelectHigh(); chipSelectHigh();
// Send an additional dummy byte, required by Toshiba Flash Air SD Card // Send an additional dummy byte, required by Toshiba Flash Air SD Card
spiSend(0XFF); spiSend(0XFF);
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
// Send an additional dummy byte, required by Toshiba Flash Air SD Card // Send an additional dummy byte, required by Toshiba Flash Air SD Card
spiSend(0XFF); spiSend(0XFF);
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** read CID or CSR register */ /** read CID or CSR register */
bool Sd2Card::readRegister(uint8_t cmd, void* buf) { bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf); uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) { if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG); error(SD_CARD_ERROR_READ_REG);
goto fail; goto fail;
} }
return readData(dst, 16); return readData(dst, 16);
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Start a read multiple blocks sequence. /** Start a read multiple blocks sequence.
* *
* \param[in] blockNumber Address of first block in sequence. * \param[in] blockNumber Address of first block in sequence.
* *
* \note This function is used with readData() and readStop() for optimized * \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence. * multiple block reads. SPI chipSelect must be low for the entire sequence.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::readStart(uint32_t blockNumber) { bool Sd2Card::readStart(uint32_t blockNumber) {
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD18, blockNumber)) { if (cardCommand(CMD18, blockNumber)) {
error(SD_CARD_ERROR_CMD18); error(SD_CARD_ERROR_CMD18);
goto fail; goto fail;
} }
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** End a read multiple blocks sequence. /** End a read multiple blocks sequence.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::readStop() { bool Sd2Card::readStop() {
chipSelectLow(); chipSelectLow();
if (cardCommand(CMD12, 0)) { if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12); error(SD_CARD_ERROR_CMD12);
goto fail; goto fail;
} }
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Set the SPI clock rate. * Set the SPI clock rate.
* *
* \param[in] sckRateID A value in the range [0, 6]. * \param[in] sckRateID A value in the range [0, 6].
* *
* The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
* SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
* for \a scsRateID = 6. * for \a scsRateID = 6.
* *
* \return The value one, true, is returned for success and the value zero, * \return The value one, true, is returned for success and the value zero,
* false, is returned for an invalid value of \a sckRateID. * false, is returned for an invalid value of \a sckRateID.
*/ */
bool Sd2Card::setSckRate(uint8_t sckRateID) { bool Sd2Card::setSckRate(uint8_t sckRateID) {
if (sckRateID > 6) { if (sckRateID > 6) {
error(SD_CARD_ERROR_SCK_RATE); error(SD_CARD_ERROR_SCK_RATE);
return false; return false;
} }
spiRate_ = sckRateID; spiRate_ = sckRateID;
return true; return true;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// wait for card to go not busy // wait for card to go not busy
bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis(); uint16_t t0 = millis();
while (spiRec() != 0XFF) { while (spiRec() != 0XFF) {
if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
} }
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Writes a 512 byte block to an SD card. * Writes a 512 byte block to an SD card.
* *
* \param[in] blockNumber Logical block to be written. * \param[in] blockNumber Logical block to be written.
* \param[in] src Pointer to the location of the data to be written. * \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
// use address if not SDHC card // use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD24, blockNumber)) { if (cardCommand(CMD24, blockNumber)) {
error(SD_CARD_ERROR_CMD24); error(SD_CARD_ERROR_CMD24);
goto fail; goto fail;
} }
if (!writeData(DATA_START_BLOCK, src)) goto fail; if (!writeData(DATA_START_BLOCK, src)) goto fail;
// wait for flash programming to complete // wait for flash programming to complete
if (!waitNotBusy(SD_WRITE_TIMEOUT)) { if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT); error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail; goto fail;
} }
// response is r2 so get and check two bytes for nonzero // response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiRec()) { if (cardCommand(CMD13, 0) || spiRec()) {
error(SD_CARD_ERROR_WRITE_PROGRAMMING); error(SD_CARD_ERROR_WRITE_PROGRAMMING);
goto fail; goto fail;
} }
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write one data block in a multiple block write sequence /** Write one data block in a multiple block write sequence
* \param[in] src Pointer to the location of the data to be written. * \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::writeData(const uint8_t* src) { bool Sd2Card::writeData(const uint8_t* src) {
chipSelectLow(); chipSelectLow();
// wait for previous write to finish // wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
error(SD_CARD_ERROR_WRITE_MULTIPLE); error(SD_CARD_ERROR_WRITE_MULTIPLE);
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks // send one block of data for write block or write multiple blocks
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
spiSendBlock(token, src); spiSendBlock(token, src);
spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc
spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc
status_ = spiRec(); status_ = spiRec();
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE); error(SD_CARD_ERROR_WRITE);
goto fail; goto fail;
} }
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Start a write multiple blocks sequence. /** Start a write multiple blocks sequence.
* *
* \param[in] blockNumber Address of first block in sequence. * \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased. * \param[in] eraseCount The number of blocks to be pre-erased.
* *
* \note This function is used with writeData() and writeStop() * \note This function is used with writeData() and writeStop()
* for optimized multiple block writes. * for optimized multiple block writes.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
// send pre-erase count // send pre-erase count
if (cardAcmd(ACMD23, eraseCount)) { if (cardAcmd(ACMD23, eraseCount)) {
error(SD_CARD_ERROR_ACMD23); error(SD_CARD_ERROR_ACMD23);
goto fail; goto fail;
} }
// use address if not SDHC card // use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD25, blockNumber)) { if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25); error(SD_CARD_ERROR_CMD25);
goto fail; goto fail;
} }
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** End a write multiple blocks sequence. /** End a write multiple blocks sequence.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. * the value zero, false, is returned for failure.
*/ */
bool Sd2Card::writeStop() { bool Sd2Card::writeStop() {
chipSelectLow(); chipSelectLow();
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
spiSend(STOP_TRAN_TOKEN); spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
chipSelectHigh(); chipSelectHigh();
return true; return true;
fail: fail:
error(SD_CARD_ERROR_STOP_TRAN); error(SD_CARD_ERROR_STOP_TRAN);
chipSelectHigh(); chipSelectHigh();
return false; return false;
} }
#endif #endif

@ -1,252 +1,252 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino Sd2Card Library * Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman * Copyright (C) 2009 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#ifndef Sd2Card_h #ifndef Sd2Card_h
#define Sd2Card_h #define Sd2Card_h
/** /**
* \file * \file
* \brief Sd2Card class for V2 SD/SDHC cards * \brief Sd2Card class for V2 SD/SDHC cards
*/ */
#include "SdFatConfig.h" #include "SdFatConfig.h"
#include "Sd2PinMap.h" #include "Sd2PinMap.h"
#include "SdInfo.h" #include "SdInfo.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6 // SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ /** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
uint8_t const SPI_FULL_SPEED = 0; uint8_t const SPI_FULL_SPEED = 0;
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ /** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
uint8_t const SPI_HALF_SPEED = 1; uint8_t const SPI_HALF_SPEED = 1;
/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */ /** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */
uint8_t const SPI_QUARTER_SPEED = 2; uint8_t const SPI_QUARTER_SPEED = 2;
/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */ /** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
uint8_t const SPI_EIGHTH_SPEED = 3; uint8_t const SPI_EIGHTH_SPEED = 3;
/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */ /** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
uint8_t const SPI_SIXTEENTH_SPEED = 4; uint8_t const SPI_SIXTEENTH_SPEED = 4;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** init timeout ms */ /** init timeout ms */
uint16_t const SD_INIT_TIMEOUT = 2000; uint16_t const SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */ /** erase timeout ms */
uint16_t const SD_ERASE_TIMEOUT = 10000; uint16_t const SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */ /** read timeout ms */
uint16_t const SD_READ_TIMEOUT = 300; uint16_t const SD_READ_TIMEOUT = 300;
/** write time out ms */ /** write time out ms */
uint16_t const SD_WRITE_TIMEOUT = 600; uint16_t const SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// SD card errors // SD card errors
/** timeout error for command CMD0 (initialize card in SPI mode) */ /** timeout error for command CMD0 (initialize card in SPI mode) */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1; uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
/** CMD8 was not accepted - not a valid SD card*/ /** CMD8 was not accepted - not a valid SD card*/
uint8_t const SD_CARD_ERROR_CMD8 = 0X2; uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
/** card returned an error response for CMD12 (write stop) */ /** card returned an error response for CMD12 (write stop) */
uint8_t const SD_CARD_ERROR_CMD12 = 0X3; uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
/** card returned an error response for CMD17 (read block) */ /** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X4; uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
/** card returned an error response for CMD18 (read multiple block) */ /** card returned an error response for CMD18 (read multiple block) */
uint8_t const SD_CARD_ERROR_CMD18 = 0X5; uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
/** card returned an error response for CMD24 (write block) */ /** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X6; uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
/** WRITE_MULTIPLE_BLOCKS command failed */ /** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X7; uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
/** card returned an error response for CMD58 (read OCR) */ /** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X8; uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
/** SET_WR_BLK_ERASE_COUNT failed */ /** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9; uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
/** ACMD41 initialization process timeout */ /** ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA; uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
/** card returned a bad CSR version field */ /** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB; uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
/** erase block group command failed */ /** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0XC; uint8_t const SD_CARD_ERROR_ERASE = 0XC;
/** card not capable of single block erase */ /** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD; uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
/** Erase sequence timed out */ /** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE; uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
/** card returned an error token instead of read data */ /** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF; uint8_t const SD_CARD_ERROR_READ = 0XF;
/** read CID or CSD failed */ /** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X10; uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
/** timeout while waiting for start of read data */ /** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11; uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
/** card did not accept STOP_TRAN_TOKEN */ /** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12; uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
/** card returned an error token as a response to a write operation */ /** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X13; uint8_t const SD_CARD_ERROR_WRITE = 0X13;
/** attempt to write protected block zero */ /** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
/** card did not go ready for a multiple block write */ /** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15; uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
/** card returned an error to a CMD13 status check after a write */ /** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16; uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
/** timeout occurred during write programming */ /** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17; uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
/** incorrect rate selected */ /** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18; uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
/** init() not called */ /** init() not called */
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19; uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
/** crc check error */ /** crc check error */
uint8_t const SD_CARD_ERROR_CRC = 0X20; uint8_t const SD_CARD_ERROR_CRC = 0X20;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// card types // card types
/** Standard capacity V1 SD card */ /** Standard capacity V1 SD card */
uint8_t const SD_CARD_TYPE_SD1 = 1; uint8_t const SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */ /** Standard capacity V2 SD card */
uint8_t const SD_CARD_TYPE_SD2 = 2; uint8_t const SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */ /** High Capacity SD card */
uint8_t const SD_CARD_TYPE_SDHC = 3; uint8_t const SD_CARD_TYPE_SDHC = 3;
/** /**
* define SOFTWARE_SPI to use bit-bang SPI * define SOFTWARE_SPI to use bit-bang SPI
*/ */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) #if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
#define SOFTWARE_SPI #define SOFTWARE_SPI
#elif USE_SOFTWARE_SPI #elif USE_SOFTWARE_SPI
#define SOFTWARE_SPI #define SOFTWARE_SPI
#endif // MEGA_SOFT_SPI #endif // MEGA_SOFT_SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// SPI pin definitions - do not edit here - change in SdFatConfig.h // SPI pin definitions - do not edit here - change in SdFatConfig.h
// //
#if DISABLED(SOFTWARE_SPI) #if DISABLED(SOFTWARE_SPI)
// hardware pin defs // hardware pin defs
/** The default chip select pin for the SD card is SS. */ /** The default chip select pin for the SD card is SS. */
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN; uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
// The following three pins must not be redefined for hardware SPI. // The following three pins must not be redefined for hardware SPI.
/** SPI Master Out Slave In pin */ /** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = MOSI_PIN; uint8_t const SPI_MOSI_PIN = MOSI_PIN;
/** SPI Master In Slave Out pin */ /** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = MISO_PIN; uint8_t const SPI_MISO_PIN = MISO_PIN;
/** SPI Clock pin */ /** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SCK_PIN; uint8_t const SPI_SCK_PIN = SCK_PIN;
#else // SOFTWARE_SPI #else // SOFTWARE_SPI
/** SPI chip select pin */ /** SPI chip select pin */
uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN; uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
/** SPI Master Out Slave In pin */ /** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN; uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
/** SPI Master In Slave Out pin */ /** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN; uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN;
/** SPI Clock pin */ /** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN; uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN;
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* \class Sd2Card * \class Sd2Card
* \brief Raw access to SD and SDHC flash memory cards. * \brief Raw access to SD and SDHC flash memory cards.
*/ */
class Sd2Card { class Sd2Card {
public: public:
/** Construct an instance of Sd2Card. */ /** Construct an instance of Sd2Card. */
Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {} Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
uint32_t cardSize(); uint32_t cardSize();
bool erase(uint32_t firstBlock, uint32_t lastBlock); bool erase(uint32_t firstBlock, uint32_t lastBlock);
bool eraseSingleBlockEnable(); bool eraseSingleBlockEnable();
/** /**
* Set SD error code. * Set SD error code.
* \param[in] code value for error code. * \param[in] code value for error code.
*/ */
void error(uint8_t code) {errorCode_ = code;} void error(uint8_t code) {errorCode_ = code;}
/** /**
* \return error code for last error. See Sd2Card.h for a list of error codes. * \return error code for last error. See Sd2Card.h for a list of error codes.
*/ */
int errorCode() const {return errorCode_;} int errorCode() const {return errorCode_;}
/** \return error data for last error. */ /** \return error data for last error. */
int errorData() const {return status_;} int errorData() const {return status_;}
/** /**
* Initialize an SD flash memory card with default clock rate and chip * Initialize an SD flash memory card with default clock rate and chip
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
* *
* \return true for success or false for failure. * \return true for success or false for failure.
*/ */
bool init(uint8_t sckRateID = SPI_FULL_SPEED, bool init(uint8_t sckRateID = SPI_FULL_SPEED,
uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
bool readBlock(uint32_t block, uint8_t* dst); bool readBlock(uint32_t block, uint8_t* dst);
/** /**
* Read a card's CID register. The CID contains card identification * Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial * information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date. * number and Manufacturing date.
* *
* \param[out] cid pointer to area for returned data. * \param[out] cid pointer to area for returned data.
* *
* \return true for success or false for failure. * \return true for success or false for failure.
*/ */
bool readCID(cid_t* cid) { bool readCID(cid_t* cid) {
return readRegister(CMD10, cid); return readRegister(CMD10, cid);
} }
/** /**
* Read a card's CSD register. The CSD contains Card-Specific Data that * Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents. * provides information regarding access to the card's contents.
* *
* \param[out] csd pointer to area for returned data. * \param[out] csd pointer to area for returned data.
* *
* \return true for success or false for failure. * \return true for success or false for failure.
*/ */
bool readCSD(csd_t* csd) { bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd); return readRegister(CMD9, csd);
} }
bool readData(uint8_t* dst); bool readData(uint8_t* dst);
bool readStart(uint32_t blockNumber); bool readStart(uint32_t blockNumber);
bool readStop(); bool readStop();
bool setSckRate(uint8_t sckRateID); bool setSckRate(uint8_t sckRateID);
/** Return the card type: SD V1, SD V2 or SDHC /** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/ */
int type() const {return type_;} int type() const {return type_;}
bool writeBlock(uint32_t blockNumber, const uint8_t* src); bool writeBlock(uint32_t blockNumber, const uint8_t* src);
bool writeData(const uint8_t* src); bool writeData(const uint8_t* src);
bool writeStart(uint32_t blockNumber, uint32_t eraseCount); bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
bool writeStop(); bool writeStop();
private: private:
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
uint8_t chipSelectPin_; uint8_t chipSelectPin_;
uint8_t errorCode_; uint8_t errorCode_;
uint8_t spiRate_; uint8_t spiRate_;
uint8_t status_; uint8_t status_;
uint8_t type_; uint8_t type_;
// private functions // private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0); cardCommand(CMD55, 0);
return cardCommand(cmd, arg); return cardCommand(cmd, arg);
} }
uint8_t cardCommand(uint8_t cmd, uint32_t arg); uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool readData(uint8_t* dst, uint16_t count); bool readData(uint8_t* dst, uint16_t count);
bool readRegister(uint8_t cmd, void* buf); bool readRegister(uint8_t cmd, void* buf);
void chipSelectHigh(); void chipSelectHigh();
void chipSelectLow(); void chipSelectLow();
void type(uint8_t value) {type_ = value;} void type(uint8_t value) {type_ = value;}
bool waitNotBusy(uint16_t timeoutMillis); bool waitNotBusy(uint16_t timeoutMillis);
bool writeData(uint8_t token, const uint8_t* src); bool writeData(uint8_t token, const uint8_t* src);
}; };
#endif // Sd2Card_h #endif // Sd2Card_h
#endif #endif

@ -1,453 +1,453 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino SdFat Library * Arduino SdFat Library
* Copyright (C) 2010 by William Greiman * Copyright (C) 2010 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
// Warning this file was generated by a program. // Warning this file was generated by a program.
#include "Marlin.h" #include "Marlin.h"
#include "macros.h" #include "macros.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#ifndef Sd2PinMap_h #ifndef Sd2PinMap_h
#define Sd2PinMap_h #define Sd2PinMap_h
#include <avr/io.h> #include <avr/io.h>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** struct for mapping digital pins */ /** struct for mapping digital pins */
struct pin_map_t { struct pin_map_t {
volatile uint8_t* ddr; volatile uint8_t* ddr;
volatile uint8_t* pin; volatile uint8_t* pin;
volatile uint8_t* port; volatile uint8_t* port;
uint8_t bit; uint8_t bit;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Mega #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Mega
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 20; // D1 uint8_t const SDA_PIN = 20; // D1
uint8_t const SCL_PIN = 21; // D0 uint8_t const SCL_PIN = 21; // D0
#undef MOSI_PIN #undef MOSI_PIN
#undef MISO_PIN #undef MISO_PIN
#undef SCK_PIN #undef SCK_PIN
// SPI port // SPI port
uint8_t const SS_PIN = 53; // B0 uint8_t const SS_PIN = 53; // B0
uint8_t const MOSI_PIN = 51; // B2 uint8_t const MOSI_PIN = 51; // B2
uint8_t const MISO_PIN = 50; // B3 uint8_t const MISO_PIN = 50; // B3
uint8_t const SCK_PIN = 52; // B1 uint8_t const SCK_PIN = 52; // B1
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRE, &PINE, &PORTE, 0}, // E0 0 {&DDRE, &PINE, &PORTE, 0}, // E0 0
{&DDRE, &PINE, &PORTE, 1}, // E1 1 {&DDRE, &PINE, &PORTE, 1}, // E1 1
{&DDRE, &PINE, &PORTE, 4}, // E4 2 {&DDRE, &PINE, &PORTE, 4}, // E4 2
{&DDRE, &PINE, &PORTE, 5}, // E5 3 {&DDRE, &PINE, &PORTE, 5}, // E5 3
{&DDRG, &PING, &PORTG, 5}, // G5 4 {&DDRG, &PING, &PORTG, 5}, // G5 4
{&DDRE, &PINE, &PORTE, 3}, // E3 5 {&DDRE, &PINE, &PORTE, 3}, // E3 5
{&DDRH, &PINH, &PORTH, 3}, // H3 6 {&DDRH, &PINH, &PORTH, 3}, // H3 6
{&DDRH, &PINH, &PORTH, 4}, // H4 7 {&DDRH, &PINH, &PORTH, 4}, // H4 7
{&DDRH, &PINH, &PORTH, 5}, // H5 8 {&DDRH, &PINH, &PORTH, 5}, // H5 8
{&DDRH, &PINH, &PORTH, 6}, // H6 9 {&DDRH, &PINH, &PORTH, 6}, // H6 9
{&DDRB, &PINB, &PORTB, 4}, // B4 10 {&DDRB, &PINB, &PORTB, 4}, // B4 10
{&DDRB, &PINB, &PORTB, 5}, // B5 11 {&DDRB, &PINB, &PORTB, 5}, // B5 11
{&DDRB, &PINB, &PORTB, 6}, // B6 12 {&DDRB, &PINB, &PORTB, 6}, // B6 12
{&DDRB, &PINB, &PORTB, 7}, // B7 13 {&DDRB, &PINB, &PORTB, 7}, // B7 13
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
{&DDRH, &PINH, &PORTH, 1}, // H1 16 {&DDRH, &PINH, &PORTH, 1}, // H1 16
{&DDRH, &PINH, &PORTH, 0}, // H0 17 {&DDRH, &PINH, &PORTH, 0}, // H0 17
{&DDRD, &PIND, &PORTD, 3}, // D3 18 {&DDRD, &PIND, &PORTD, 3}, // D3 18
{&DDRD, &PIND, &PORTD, 2}, // D2 19 {&DDRD, &PIND, &PORTD, 2}, // D2 19
{&DDRD, &PIND, &PORTD, 1}, // D1 20 {&DDRD, &PIND, &PORTD, 1}, // D1 20
{&DDRD, &PIND, &PORTD, 0}, // D0 21 {&DDRD, &PIND, &PORTD, 0}, // D0 21
{&DDRA, &PINA, &PORTA, 0}, // A0 22 {&DDRA, &PINA, &PORTA, 0}, // A0 22
{&DDRA, &PINA, &PORTA, 1}, // A1 23 {&DDRA, &PINA, &PORTA, 1}, // A1 23
{&DDRA, &PINA, &PORTA, 2}, // A2 24 {&DDRA, &PINA, &PORTA, 2}, // A2 24
{&DDRA, &PINA, &PORTA, 3}, // A3 25 {&DDRA, &PINA, &PORTA, 3}, // A3 25
{&DDRA, &PINA, &PORTA, 4}, // A4 26 {&DDRA, &PINA, &PORTA, 4}, // A4 26
{&DDRA, &PINA, &PORTA, 5}, // A5 27 {&DDRA, &PINA, &PORTA, 5}, // A5 27
{&DDRA, &PINA, &PORTA, 6}, // A6 28 {&DDRA, &PINA, &PORTA, 6}, // A6 28
{&DDRA, &PINA, &PORTA, 7}, // A7 29 {&DDRA, &PINA, &PORTA, 7}, // A7 29
{&DDRC, &PINC, &PORTC, 7}, // C7 30 {&DDRC, &PINC, &PORTC, 7}, // C7 30
{&DDRC, &PINC, &PORTC, 6}, // C6 31 {&DDRC, &PINC, &PORTC, 6}, // C6 31
{&DDRC, &PINC, &PORTC, 5}, // C5 32 {&DDRC, &PINC, &PORTC, 5}, // C5 32
{&DDRC, &PINC, &PORTC, 4}, // C4 33 {&DDRC, &PINC, &PORTC, 4}, // C4 33
{&DDRC, &PINC, &PORTC, 3}, // C3 34 {&DDRC, &PINC, &PORTC, 3}, // C3 34
{&DDRC, &PINC, &PORTC, 2}, // C2 35 {&DDRC, &PINC, &PORTC, 2}, // C2 35
{&DDRC, &PINC, &PORTC, 1}, // C1 36 {&DDRC, &PINC, &PORTC, 1}, // C1 36
{&DDRC, &PINC, &PORTC, 0}, // C0 37 {&DDRC, &PINC, &PORTC, 0}, // C0 37
{&DDRD, &PIND, &PORTD, 7}, // D7 38 {&DDRD, &PIND, &PORTD, 7}, // D7 38
{&DDRG, &PING, &PORTG, 2}, // G2 39 {&DDRG, &PING, &PORTG, 2}, // G2 39
{&DDRG, &PING, &PORTG, 1}, // G1 40 {&DDRG, &PING, &PORTG, 1}, // G1 40
{&DDRG, &PING, &PORTG, 0}, // G0 41 {&DDRG, &PING, &PORTG, 0}, // G0 41
{&DDRL, &PINL, &PORTL, 7}, // L7 42 {&DDRL, &PINL, &PORTL, 7}, // L7 42
{&DDRL, &PINL, &PORTL, 6}, // L6 43 {&DDRL, &PINL, &PORTL, 6}, // L6 43
{&DDRL, &PINL, &PORTL, 5}, // L5 44 {&DDRL, &PINL, &PORTL, 5}, // L5 44
{&DDRL, &PINL, &PORTL, 4}, // L4 45 {&DDRL, &PINL, &PORTL, 4}, // L4 45
{&DDRL, &PINL, &PORTL, 3}, // L3 46 {&DDRL, &PINL, &PORTL, 3}, // L3 46
{&DDRL, &PINL, &PORTL, 2}, // L2 47 {&DDRL, &PINL, &PORTL, 2}, // L2 47
{&DDRL, &PINL, &PORTL, 1}, // L1 48 {&DDRL, &PINL, &PORTL, 1}, // L1 48
{&DDRL, &PINL, &PORTL, 0}, // L0 49 {&DDRL, &PINL, &PORTL, 0}, // L0 49
{&DDRB, &PINB, &PORTB, 3}, // B3 50 {&DDRB, &PINB, &PORTB, 3}, // B3 50
{&DDRB, &PINB, &PORTB, 2}, // B2 51 {&DDRB, &PINB, &PORTB, 2}, // B2 51
{&DDRB, &PINB, &PORTB, 1}, // B1 52 {&DDRB, &PINB, &PORTB, 1}, // B1 52
{&DDRB, &PINB, &PORTB, 0}, // B0 53 {&DDRB, &PINB, &PORTB, 0}, // B0 53
{&DDRF, &PINF, &PORTF, 0}, // F0 54 {&DDRF, &PINF, &PORTF, 0}, // F0 54
{&DDRF, &PINF, &PORTF, 1}, // F1 55 {&DDRF, &PINF, &PORTF, 1}, // F1 55
{&DDRF, &PINF, &PORTF, 2}, // F2 56 {&DDRF, &PINF, &PORTF, 2}, // F2 56
{&DDRF, &PINF, &PORTF, 3}, // F3 57 {&DDRF, &PINF, &PORTF, 3}, // F3 57
{&DDRF, &PINF, &PORTF, 4}, // F4 58 {&DDRF, &PINF, &PORTF, 4}, // F4 58
{&DDRF, &PINF, &PORTF, 5}, // F5 59 {&DDRF, &PINF, &PORTF, 5}, // F5 59
{&DDRF, &PINF, &PORTF, 6}, // F6 60 {&DDRF, &PINF, &PORTF, 6}, // F6 60
{&DDRF, &PINF, &PORTF, 7}, // F7 61 {&DDRF, &PINF, &PORTF, 7}, // F7 61
{&DDRK, &PINK, &PORTK, 0}, // K0 62 {&DDRK, &PINK, &PORTK, 0}, // K0 62
{&DDRK, &PINK, &PORTK, 1}, // K1 63 {&DDRK, &PINK, &PORTK, 1}, // K1 63
{&DDRK, &PINK, &PORTK, 2}, // K2 64 {&DDRK, &PINK, &PORTK, 2}, // K2 64
{&DDRK, &PINK, &PORTK, 3}, // K3 65 {&DDRK, &PINK, &PORTK, 3}, // K3 65
{&DDRK, &PINK, &PORTK, 4}, // K4 66 {&DDRK, &PINK, &PORTK, 4}, // K4 66
{&DDRK, &PINK, &PORTK, 5}, // K5 67 {&DDRK, &PINK, &PORTK, 5}, // K5 67
{&DDRK, &PINK, &PORTK, 6}, // K6 68 {&DDRK, &PINK, &PORTK, 6}, // K6 68
{&DDRK, &PINK, &PORTK, 7} // K7 69 {&DDRK, &PINK, &PORTK, 7} // K7 69
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#elif defined(__AVR_ATmega644P__)\ #elif defined(__AVR_ATmega644P__)\
|| defined(__AVR_ATmega644__)\ || defined(__AVR_ATmega644__)\
|| defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284P__)
// Sanguino // Sanguino
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 17; // C1 uint8_t const SDA_PIN = 17; // C1
uint8_t const SCL_PIN = 18; // C2 uint8_t const SCL_PIN = 18; // C2
// SPI port // SPI port
uint8_t const SS_PIN = 4; // B4 uint8_t const SS_PIN = 4; // B4
uint8_t const MOSI_PIN = 5; // B5 uint8_t const MOSI_PIN = 5; // B5
uint8_t const MISO_PIN = 6; // B6 uint8_t const MISO_PIN = 6; // B6
uint8_t const SCK_PIN = 7; // B7 uint8_t const SCK_PIN = 7; // B7
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0 {&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1 {&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2 {&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3 {&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 4}, // B4 4 {&DDRB, &PINB, &PORTB, 4}, // B4 4
{&DDRB, &PINB, &PORTB, 5}, // B5 5 {&DDRB, &PINB, &PORTB, 5}, // B5 5
{&DDRB, &PINB, &PORTB, 6}, // B6 6 {&DDRB, &PINB, &PORTB, 6}, // B6 6
{&DDRB, &PINB, &PORTB, 7}, // B7 7 {&DDRB, &PINB, &PORTB, 7}, // B7 7
{&DDRD, &PIND, &PORTD, 0}, // D0 8 {&DDRD, &PIND, &PORTD, 0}, // D0 8
{&DDRD, &PIND, &PORTD, 1}, // D1 9 {&DDRD, &PIND, &PORTD, 1}, // D1 9
{&DDRD, &PIND, &PORTD, 2}, // D2 10 {&DDRD, &PIND, &PORTD, 2}, // D2 10
{&DDRD, &PIND, &PORTD, 3}, // D3 11 {&DDRD, &PIND, &PORTD, 3}, // D3 11
{&DDRD, &PIND, &PORTD, 4}, // D4 12 {&DDRD, &PIND, &PORTD, 4}, // D4 12
{&DDRD, &PIND, &PORTD, 5}, // D5 13 {&DDRD, &PIND, &PORTD, 5}, // D5 13
{&DDRD, &PIND, &PORTD, 6}, // D6 14 {&DDRD, &PIND, &PORTD, 6}, // D6 14
{&DDRD, &PIND, &PORTD, 7}, // D7 15 {&DDRD, &PIND, &PORTD, 7}, // D7 15
{&DDRC, &PINC, &PORTC, 0}, // C0 16 {&DDRC, &PINC, &PORTC, 0}, // C0 16
{&DDRC, &PINC, &PORTC, 1}, // C1 17 {&DDRC, &PINC, &PORTC, 1}, // C1 17
{&DDRC, &PINC, &PORTC, 2}, // C2 18 {&DDRC, &PINC, &PORTC, 2}, // C2 18
{&DDRC, &PINC, &PORTC, 3}, // C3 19 {&DDRC, &PINC, &PORTC, 3}, // C3 19
{&DDRC, &PINC, &PORTC, 4}, // C4 20 {&DDRC, &PINC, &PORTC, 4}, // C4 20
{&DDRC, &PINC, &PORTC, 5}, // C5 21 {&DDRC, &PINC, &PORTC, 5}, // C5 21
{&DDRC, &PINC, &PORTC, 6}, // C6 22 {&DDRC, &PINC, &PORTC, 6}, // C6 22
{&DDRC, &PINC, &PORTC, 7}, // C7 23 {&DDRC, &PINC, &PORTC, 7}, // C7 23
{&DDRA, &PINA, &PORTA, 7}, // A7 24 {&DDRA, &PINA, &PORTA, 7}, // A7 24
{&DDRA, &PINA, &PORTA, 6}, // A6 25 {&DDRA, &PINA, &PORTA, 6}, // A6 25
{&DDRA, &PINA, &PORTA, 5}, // A5 26 {&DDRA, &PINA, &PORTA, 5}, // A5 26
{&DDRA, &PINA, &PORTA, 4}, // A4 27 {&DDRA, &PINA, &PORTA, 4}, // A4 27
{&DDRA, &PINA, &PORTA, 3}, // A3 28 {&DDRA, &PINA, &PORTA, 3}, // A3 28
{&DDRA, &PINA, &PORTA, 2}, // A2 29 {&DDRA, &PINA, &PORTA, 2}, // A2 29
{&DDRA, &PINA, &PORTA, 1}, // A1 30 {&DDRA, &PINA, &PORTA, 1}, // A1 30
{&DDRA, &PINA, &PORTA, 0} // A0 31 {&DDRA, &PINA, &PORTA, 0} // A0 31
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#elif defined(__AVR_ATmega32U4__) #elif defined(__AVR_ATmega32U4__)
// Teensy 2.0 // Teensy 2.0
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 6; // D1 uint8_t const SDA_PIN = 6; // D1
uint8_t const SCL_PIN = 5; // D0 uint8_t const SCL_PIN = 5; // D0
// SPI port // SPI port
uint8_t const SS_PIN = 0; // B0 uint8_t const SS_PIN = 0; // B0
uint8_t const MOSI_PIN = 2; // B2 uint8_t const MOSI_PIN = 2; // B2
uint8_t const MISO_PIN = 3; // B3 uint8_t const MISO_PIN = 3; // B3
uint8_t const SCK_PIN = 1; // B1 uint8_t const SCK_PIN = 1; // B1
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0 {&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1 {&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2 {&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3 {&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 7}, // B7 4 {&DDRB, &PINB, &PORTB, 7}, // B7 4
{&DDRD, &PIND, &PORTD, 0}, // D0 5 {&DDRD, &PIND, &PORTD, 0}, // D0 5
{&DDRD, &PIND, &PORTD, 1}, // D1 6 {&DDRD, &PIND, &PORTD, 1}, // D1 6
{&DDRD, &PIND, &PORTD, 2}, // D2 7 {&DDRD, &PIND, &PORTD, 2}, // D2 7
{&DDRD, &PIND, &PORTD, 3}, // D3 8 {&DDRD, &PIND, &PORTD, 3}, // D3 8
{&DDRC, &PINC, &PORTC, 6}, // C6 9 {&DDRC, &PINC, &PORTC, 6}, // C6 9
{&DDRC, &PINC, &PORTC, 7}, // C7 10 {&DDRC, &PINC, &PORTC, 7}, // C7 10
{&DDRD, &PIND, &PORTD, 6}, // D6 11 {&DDRD, &PIND, &PORTD, 6}, // D6 11
{&DDRD, &PIND, &PORTD, 7}, // D7 12 {&DDRD, &PIND, &PORTD, 7}, // D7 12
{&DDRB, &PINB, &PORTB, 4}, // B4 13 {&DDRB, &PINB, &PORTB, 4}, // B4 13
{&DDRB, &PINB, &PORTB, 5}, // B5 14 {&DDRB, &PINB, &PORTB, 5}, // B5 14
{&DDRB, &PINB, &PORTB, 6}, // B6 15 {&DDRB, &PINB, &PORTB, 6}, // B6 15
{&DDRF, &PINF, &PORTF, 7}, // F7 16 {&DDRF, &PINF, &PORTF, 7}, // F7 16
{&DDRF, &PINF, &PORTF, 6}, // F6 17 {&DDRF, &PINF, &PORTF, 6}, // F6 17
{&DDRF, &PINF, &PORTF, 5}, // F5 18 {&DDRF, &PINF, &PORTF, 5}, // F5 18
{&DDRF, &PINF, &PORTF, 4}, // F4 19 {&DDRF, &PINF, &PORTF, 4}, // F4 19
{&DDRF, &PINF, &PORTF, 1}, // F1 20 {&DDRF, &PINF, &PORTF, 1}, // F1 20
{&DDRF, &PINF, &PORTF, 0}, // F0 21 {&DDRF, &PINF, &PORTF, 0}, // F0 21
{&DDRD, &PIND, &PORTD, 4}, // D4 22 {&DDRD, &PIND, &PORTD, 4}, // D4 22
{&DDRD, &PIND, &PORTD, 5}, // D5 23 {&DDRD, &PIND, &PORTD, 5}, // D5 23
{&DDRE, &PINE, &PORTE, 6} // E6 24 {&DDRE, &PINE, &PORTE, 6} // E6 24
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#elif defined(__AVR_AT90USB646__)\ #elif defined(__AVR_AT90USB646__)\
|| defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286__)
// Teensy++ 1.0 & 2.0 // Teensy++ 1.0 & 2.0
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 1; // D1 uint8_t const SDA_PIN = 1; // D1
uint8_t const SCL_PIN = 0; // D0 uint8_t const SCL_PIN = 0; // D0
// SPI port // SPI port
uint8_t const SS_PIN = 20; // B0 uint8_t const SS_PIN = 20; // B0
uint8_t const MOSI_PIN = 22; // B2 uint8_t const MOSI_PIN = 22; // B2
uint8_t const MISO_PIN = 23; // B3 uint8_t const MISO_PIN = 23; // B3
uint8_t const SCK_PIN = 21; // B1 uint8_t const SCK_PIN = 21; // B1
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0 {&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1 {&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2 {&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3 {&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4 {&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5 {&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6 {&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7 {&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRE, &PINE, &PORTE, 0}, // E0 8 {&DDRE, &PINE, &PORTE, 0}, // E0 8
{&DDRE, &PINE, &PORTE, 1}, // E1 9 {&DDRE, &PINE, &PORTE, 1}, // E1 9
{&DDRC, &PINC, &PORTC, 0}, // C0 10 {&DDRC, &PINC, &PORTC, 0}, // C0 10
{&DDRC, &PINC, &PORTC, 1}, // C1 11 {&DDRC, &PINC, &PORTC, 1}, // C1 11
{&DDRC, &PINC, &PORTC, 2}, // C2 12 {&DDRC, &PINC, &PORTC, 2}, // C2 12
{&DDRC, &PINC, &PORTC, 3}, // C3 13 {&DDRC, &PINC, &PORTC, 3}, // C3 13
{&DDRC, &PINC, &PORTC, 4}, // C4 14 {&DDRC, &PINC, &PORTC, 4}, // C4 14
{&DDRC, &PINC, &PORTC, 5}, // C5 15 {&DDRC, &PINC, &PORTC, 5}, // C5 15
{&DDRC, &PINC, &PORTC, 6}, // C6 16 {&DDRC, &PINC, &PORTC, 6}, // C6 16
{&DDRC, &PINC, &PORTC, 7}, // C7 17 {&DDRC, &PINC, &PORTC, 7}, // C7 17
{&DDRE, &PINE, &PORTE, 6}, // E6 18 {&DDRE, &PINE, &PORTE, 6}, // E6 18
{&DDRE, &PINE, &PORTE, 7}, // E7 19 {&DDRE, &PINE, &PORTE, 7}, // E7 19
{&DDRB, &PINB, &PORTB, 0}, // B0 20 {&DDRB, &PINB, &PORTB, 0}, // B0 20
{&DDRB, &PINB, &PORTB, 1}, // B1 21 {&DDRB, &PINB, &PORTB, 1}, // B1 21
{&DDRB, &PINB, &PORTB, 2}, // B2 22 {&DDRB, &PINB, &PORTB, 2}, // B2 22
{&DDRB, &PINB, &PORTB, 3}, // B3 23 {&DDRB, &PINB, &PORTB, 3}, // B3 23
{&DDRB, &PINB, &PORTB, 4}, // B4 24 {&DDRB, &PINB, &PORTB, 4}, // B4 24
{&DDRB, &PINB, &PORTB, 5}, // B5 25 {&DDRB, &PINB, &PORTB, 5}, // B5 25
{&DDRB, &PINB, &PORTB, 6}, // B6 26 {&DDRB, &PINB, &PORTB, 6}, // B6 26
{&DDRB, &PINB, &PORTB, 7}, // B7 27 {&DDRB, &PINB, &PORTB, 7}, // B7 27
{&DDRA, &PINA, &PORTA, 0}, // A0 28 {&DDRA, &PINA, &PORTA, 0}, // A0 28
{&DDRA, &PINA, &PORTA, 1}, // A1 29 {&DDRA, &PINA, &PORTA, 1}, // A1 29
{&DDRA, &PINA, &PORTA, 2}, // A2 30 {&DDRA, &PINA, &PORTA, 2}, // A2 30
{&DDRA, &PINA, &PORTA, 3}, // A3 31 {&DDRA, &PINA, &PORTA, 3}, // A3 31
{&DDRA, &PINA, &PORTA, 4}, // A4 32 {&DDRA, &PINA, &PORTA, 4}, // A4 32
{&DDRA, &PINA, &PORTA, 5}, // A5 33 {&DDRA, &PINA, &PORTA, 5}, // A5 33
{&DDRA, &PINA, &PORTA, 6}, // A6 34 {&DDRA, &PINA, &PORTA, 6}, // A6 34
{&DDRA, &PINA, &PORTA, 7}, // A7 35 {&DDRA, &PINA, &PORTA, 7}, // A7 35
{&DDRE, &PINE, &PORTE, 4}, // E4 36 {&DDRE, &PINE, &PORTE, 4}, // E4 36
{&DDRE, &PINE, &PORTE, 5}, // E5 37 {&DDRE, &PINE, &PORTE, 5}, // E5 37
{&DDRF, &PINF, &PORTF, 0}, // F0 38 {&DDRF, &PINF, &PORTF, 0}, // F0 38
{&DDRF, &PINF, &PORTF, 1}, // F1 39 {&DDRF, &PINF, &PORTF, 1}, // F1 39
{&DDRF, &PINF, &PORTF, 2}, // F2 40 {&DDRF, &PINF, &PORTF, 2}, // F2 40
{&DDRF, &PINF, &PORTF, 3}, // F3 41 {&DDRF, &PINF, &PORTF, 3}, // F3 41
{&DDRF, &PINF, &PORTF, 4}, // F4 42 {&DDRF, &PINF, &PORTF, 4}, // F4 42
{&DDRF, &PINF, &PORTF, 5}, // F5 43 {&DDRF, &PINF, &PORTF, 5}, // F5 43
{&DDRF, &PINF, &PORTF, 6}, // F6 44 {&DDRF, &PINF, &PORTF, 6}, // F6 44
{&DDRF, &PINF, &PORTF, 7} // F7 45 {&DDRF, &PINF, &PORTF, 7} // F7 45
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#elif defined(__AVR_ATmega168__)\ #elif defined(__AVR_ATmega168__)\
||defined(__AVR_ATmega168P__)\ ||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__) ||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos // 168 and 328 Arduinos
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 18; // C4 uint8_t const SDA_PIN = 18; // C4
uint8_t const SCL_PIN = 19; // C5 uint8_t const SCL_PIN = 19; // C5
// SPI port // SPI port
uint8_t const SS_PIN = 10; // B2 uint8_t const SS_PIN = 10; // B2
uint8_t const MOSI_PIN = 11; // B3 uint8_t const MOSI_PIN = 11; // B3
uint8_t const MISO_PIN = 12; // B4 uint8_t const MISO_PIN = 12; // B4
uint8_t const SCK_PIN = 13; // B5 uint8_t const SCK_PIN = 13; // B5
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0 {&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1 {&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2 {&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3 {&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4 {&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5 {&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6 {&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7 {&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRB, &PINB, &PORTB, 0}, // B0 8 {&DDRB, &PINB, &PORTB, 0}, // B0 8
{&DDRB, &PINB, &PORTB, 1}, // B1 9 {&DDRB, &PINB, &PORTB, 1}, // B1 9
{&DDRB, &PINB, &PORTB, 2}, // B2 10 {&DDRB, &PINB, &PORTB, 2}, // B2 10
{&DDRB, &PINB, &PORTB, 3}, // B3 11 {&DDRB, &PINB, &PORTB, 3}, // B3 11
{&DDRB, &PINB, &PORTB, 4}, // B4 12 {&DDRB, &PINB, &PORTB, 4}, // B4 12
{&DDRB, &PINB, &PORTB, 5}, // B5 13 {&DDRB, &PINB, &PORTB, 5}, // B5 13
{&DDRC, &PINC, &PORTC, 0}, // C0 14 {&DDRC, &PINC, &PORTC, 0}, // C0 14
{&DDRC, &PINC, &PORTC, 1}, // C1 15 {&DDRC, &PINC, &PORTC, 1}, // C1 15
{&DDRC, &PINC, &PORTC, 2}, // C2 16 {&DDRC, &PINC, &PORTC, 2}, // C2 16
{&DDRC, &PINC, &PORTC, 3}, // C3 17 {&DDRC, &PINC, &PORTC, 3}, // C3 17
{&DDRC, &PINC, &PORTC, 4}, // C4 18 {&DDRC, &PINC, &PORTC, 4}, // C4 18
{&DDRC, &PINC, &PORTC, 5} // C5 19 {&DDRC, &PINC, &PORTC, 5} // C5 19
}; };
#elif defined(__AVR_ATmega1281__) #elif defined(__AVR_ATmega1281__)
// Waspmote // Waspmote
// Two Wire (aka I2C) ports // Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 41; uint8_t const SDA_PIN = 41;
uint8_t const SCL_PIN = 40; uint8_t const SCL_PIN = 40;
#undef MOSI_PIN #undef MOSI_PIN
#undef MISO_PIN #undef MISO_PIN
// SPI port // SPI port
uint8_t const SS_PIN = 16; // B0 uint8_t const SS_PIN = 16; // B0
uint8_t const MOSI_PIN = 11; // B2 uint8_t const MOSI_PIN = 11; // B2
uint8_t const MISO_PIN = 12; // B3 uint8_t const MISO_PIN = 12; // B3
uint8_t const SCK_PIN = 10; // B1 uint8_t const SCK_PIN = 10; // B1
static const pin_map_t digitalPinMap[] = { static const pin_map_t digitalPinMap[] = {
{&DDRE, &PINE, &PORTE, 0}, // E0 0 {&DDRE, &PINE, &PORTE, 0}, // E0 0
{&DDRE, &PINE, &PORTE, 1}, // E1 1 {&DDRE, &PINE, &PORTE, 1}, // E1 1
{&DDRE, &PINE, &PORTE, 3}, // E3 2 {&DDRE, &PINE, &PORTE, 3}, // E3 2
{&DDRE, &PINE, &PORTE, 4}, // E4 3 {&DDRE, &PINE, &PORTE, 4}, // E4 3
{&DDRC, &PINC, &PORTC, 4}, // C4 4 {&DDRC, &PINC, &PORTC, 4}, // C4 4
{&DDRC, &PINC, &PORTC, 5}, // C5 5 {&DDRC, &PINC, &PORTC, 5}, // C5 5
{&DDRC, &PINC, &PORTC, 6}, // C6 6 {&DDRC, &PINC, &PORTC, 6}, // C6 6
{&DDRC, &PINC, &PORTC, 7}, // C7 7 {&DDRC, &PINC, &PORTC, 7}, // C7 7
{&DDRA, &PINA, &PORTA, 2}, // A2 8 {&DDRA, &PINA, &PORTA, 2}, // A2 8
{&DDRA, &PINA, &PORTA, 3}, // A3 9 {&DDRA, &PINA, &PORTA, 3}, // A3 9
{&DDRA, &PINA, &PORTA, 4}, // A4 10 {&DDRA, &PINA, &PORTA, 4}, // A4 10
{&DDRD, &PIND, &PORTD, 5}, // D5 11 {&DDRD, &PIND, &PORTD, 5}, // D5 11
{&DDRD, &PIND, &PORTD, 6}, // D6 12 {&DDRD, &PIND, &PORTD, 6}, // D6 12
{&DDRC, &PINC, &PORTC, 1}, // C1 13 {&DDRC, &PINC, &PORTC, 1}, // C1 13
{&DDRF, &PINF, &PORTF, 1}, // F1 14 {&DDRF, &PINF, &PORTF, 1}, // F1 14
{&DDRF, &PINF, &PORTF, 2}, // F2 15 {&DDRF, &PINF, &PORTF, 2}, // F2 15
{&DDRF, &PINF, &PORTF, 3}, // F3 16 {&DDRF, &PINF, &PORTF, 3}, // F3 16
{&DDRF, &PINF, &PORTF, 4}, // F4 17 {&DDRF, &PINF, &PORTF, 4}, // F4 17
{&DDRF, &PINF, &PORTF, 5}, // F5 18 {&DDRF, &PINF, &PORTF, 5}, // F5 18
{&DDRF, &PINF, &PORTF, 6}, // F6 19 {&DDRF, &PINF, &PORTF, 6}, // F6 19
{&DDRF, &PINF, &PORTF, 7}, // F7 20 {&DDRF, &PINF, &PORTF, 7}, // F7 20
{&DDRF, &PINF, &PORTF, 0}, // F0 21 {&DDRF, &PINF, &PORTF, 0}, // F0 21
{&DDRA, &PINA, &PORTA, 1}, // A1 22 {&DDRA, &PINA, &PORTA, 1}, // A1 22
{&DDRD, &PIND, &PORTD, 7}, // D7 23 {&DDRD, &PIND, &PORTD, 7}, // D7 23
{&DDRE, &PINE, &PORTE, 5}, // E5 24 {&DDRE, &PINE, &PORTE, 5}, // E5 24
{&DDRA, &PINA, &PORTA, 6}, // A6 25 {&DDRA, &PINA, &PORTA, 6}, // A6 25
{&DDRE, &PINE, &PORTE, 2}, // E2 26 {&DDRE, &PINE, &PORTE, 2}, // E2 26
{&DDRA, &PINA, &PORTA, 5}, // A5 27 {&DDRA, &PINA, &PORTA, 5}, // A5 27
{&DDRC, &PINC, &PORTC, 0}, // C0 28 {&DDRC, &PINC, &PORTC, 0}, // C0 28
{&DDRB, &PINB, &PORTB, 0}, // B0 29 {&DDRB, &PINB, &PORTB, 0}, // B0 29
{&DDRB, &PINB, &PORTB, 1}, // B1 30 {&DDRB, &PINB, &PORTB, 1}, // B1 30
{&DDRB, &PINB, &PORTB, 2}, // B2 31 {&DDRB, &PINB, &PORTB, 2}, // B2 31
{&DDRB, &PINB, &PORTB, 3}, // B3 32 {&DDRB, &PINB, &PORTB, 3}, // B3 32
{&DDRB, &PINB, &PORTB, 4}, // B4 33 {&DDRB, &PINB, &PORTB, 4}, // B4 33
{&DDRB, &PINB, &PORTB, 5}, // B5 34 {&DDRB, &PINB, &PORTB, 5}, // B5 34
{&DDRA, &PINA, &PORTA, 0}, // A0 35 {&DDRA, &PINA, &PORTA, 0}, // A0 35
{&DDRB, &PINB, &PORTB, 6}, // B6 36 {&DDRB, &PINB, &PORTB, 6}, // B6 36
{&DDRB, &PINB, &PORTB, 7}, // B7 37 {&DDRB, &PINB, &PORTB, 7}, // B7 37
{&DDRE, &PINE, &PORTE, 6}, // E6 38 {&DDRE, &PINE, &PORTE, 6}, // E6 38
{&DDRE, &PINE, &PORTE, 7}, // E7 39 {&DDRE, &PINE, &PORTE, 7}, // E7 39
{&DDRD, &PIND, &PORTD, 0}, // D0 40 {&DDRD, &PIND, &PORTD, 0}, // D0 40
{&DDRD, &PIND, &PORTD, 1}, // D1 41 {&DDRD, &PIND, &PORTD, 1}, // D1 41
{&DDRC, &PINC, &PORTC, 3}, // C3 42 {&DDRC, &PINC, &PORTC, 3}, // C3 42
{&DDRD, &PIND, &PORTD, 2}, // D2 43 {&DDRD, &PIND, &PORTD, 2}, // D2 43
{&DDRD, &PIND, &PORTD, 3}, // D3 44 {&DDRD, &PIND, &PORTD, 3}, // D3 44
{&DDRA, &PINA, &PORTA, 7}, // A7 45 {&DDRA, &PINA, &PORTA, 7}, // A7 45
{&DDRC, &PINC, &PORTC, 2}, // C2 46 {&DDRC, &PINC, &PORTC, 2}, // C2 46
{&DDRD, &PIND, &PORTD, 4}, // D4 47 {&DDRD, &PIND, &PORTD, 4}, // D4 47
{&DDRG, &PING, &PORTG, 2}, // G2 48 {&DDRG, &PING, &PORTG, 2}, // G2 48
{&DDRG, &PING, &PORTG, 1}, // G1 49 {&DDRG, &PING, &PORTG, 1}, // G1 49
{&DDRG, &PING, &PORTG, 0}, // G0 50 {&DDRG, &PING, &PORTG, 0}, // G0 50
}; };
#else // defined(__AVR_ATmega1280__) #else // defined(__AVR_ATmega1280__)
#error unknown chip #error unknown chip
#endif // defined(__AVR_ATmega1280__) #endif // defined(__AVR_ATmega1280__)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static const uint8_t digitalPinCount = COUNT(digitalPinMap); static const uint8_t digitalPinCount = COUNT(digitalPinMap);
uint8_t badPinNumber(void) uint8_t badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant"))); __attribute__((error("Pin number is too large or not a constant")));
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
bool getPinMode(uint8_t pin) { bool getPinMode(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) { if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
} }
else { else {
return badPinNumber(); return badPinNumber();
} }
} }
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
void setPinMode(uint8_t pin, uint8_t mode) { void setPinMode(uint8_t pin, uint8_t mode) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) { if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (mode) { if (mode) {
SBI(*digitalPinMap[pin].ddr, digitalPinMap[pin].bit); SBI(*digitalPinMap[pin].ddr, digitalPinMap[pin].bit);
} }
else { else {
CBI(*digitalPinMap[pin].ddr, digitalPinMap[pin].bit); CBI(*digitalPinMap[pin].ddr, digitalPinMap[pin].bit);
} }
} }
else { else {
badPinNumber(); badPinNumber();
} }
} }
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) { bool fastDigitalRead(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) { if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
} }
else { else {
return badPinNumber(); return badPinNumber();
} }
} }
static inline __attribute__((always_inline)) static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, uint8_t value) { void fastDigitalWrite(uint8_t pin, uint8_t value) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) { if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (value) { if (value) {
SBI(*digitalPinMap[pin].port, digitalPinMap[pin].bit); SBI(*digitalPinMap[pin].port, digitalPinMap[pin].bit);
} }
else { else {
CBI(*digitalPinMap[pin].port, digitalPinMap[pin].bit); CBI(*digitalPinMap[pin].port, digitalPinMap[pin].bit);
} }
} }
else { else {
badPinNumber(); badPinNumber();
} }
} }
#endif // Sd2PinMap_h #endif // Sd2PinMap_h
#endif #endif

@ -1,57 +1,57 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino SdFat Library * Arduino SdFat Library
* Copyright (C) 2008 by William Greiman * Copyright (C) 2008 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#ifndef SdFatUtil_h #ifndef SdFatUtil_h
#define SdFatUtil_h #define SdFatUtil_h
/** /**
* \file * \file
* \brief Useful utility functions. * \brief Useful utility functions.
*/ */
#include "Marlin.h" #include "Marlin.h"
#include "MarlinSerial.h" #include "MarlinSerial.h"
/** Store and print a string in flash memory.*/ /** Store and print a string in flash memory.*/
#define PgmPrint(x) SerialPrint_P(PSTR(x)) #define PgmPrint(x) SerialPrint_P(PSTR(x))
/** Store and print a string in flash memory followed by a CR/LF.*/ /** Store and print a string in flash memory followed by a CR/LF.*/
#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) #define PgmPrintln(x) SerialPrintln_P(PSTR(x))
namespace SdFatUtil { namespace SdFatUtil {
int FreeRam(); int FreeRam();
void print_P(PGM_P str); void print_P(PGM_P str);
void println_P(PGM_P str); void println_P(PGM_P str);
void SerialPrint_P(PGM_P str); void SerialPrint_P(PGM_P str);
void SerialPrintln_P(PGM_P str); void SerialPrintln_P(PGM_P str);
} }
using namespace SdFatUtil; // NOLINT using namespace SdFatUtil; // NOLINT
#endif //#define SdFatUtil_h #endif //#define SdFatUtil_h
#endif #endif

@ -1,102 +1,102 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino SdFat Library * Arduino SdFat Library
* Copyright (C) 2009 by William Greiman * Copyright (C) 2009 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#include "SdFile.h" #include "SdFile.h"
/** Create a file object and open it in the current working directory. /** Create a file object and open it in the current working directory.
* *
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened. * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
* *
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/ */
SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write data to an open file. /** Write data to an open file.
* *
* \note Data is moved to the cache but may not be written to the * \note Data is moved to the cache but may not be written to the
* storage device until sync() is called. * storage device until sync() is called.
* *
* \param[in] buf Pointer to the location of the data to be written. * \param[in] buf Pointer to the location of the data to be written.
* *
* \param[in] nbyte Number of bytes to write. * \param[in] nbyte Number of bytes to write.
* *
* \return For success write() returns the number of bytes written, always * \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors * \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called * include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error. * for a read-only file, device is full, a corrupt file system or an I/O error.
* *
*/ */
int16_t SdFile::write(const void* buf, uint16_t nbyte) { int16_t SdFile::write(const void* buf, uint16_t nbyte) {
return SdBaseFile::write(buf, nbyte); return SdBaseFile::write(buf, nbyte);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write a byte to a file. Required by the Arduino Print class. /** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written. * \param[in] b the byte to be written.
* Use writeError to check for errors. * Use writeError to check for errors.
*/ */
#if ARDUINO >= 100 #if ARDUINO >= 100
size_t SdFile::write(uint8_t b) { size_t SdFile::write(uint8_t b) {
return SdBaseFile::write(&b, 1); return SdBaseFile::write(&b, 1);
} }
#else #else
void SdFile::write(uint8_t b) { void SdFile::write(uint8_t b) {
SdBaseFile::write(&b, 1); SdBaseFile::write(&b, 1);
} }
#endif #endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write a string to a file. Used by the Arduino Print class. /** Write a string to a file. Used by the Arduino Print class.
* \param[in] str Pointer to the string. * \param[in] str Pointer to the string.
* Use writeError to check for errors. * Use writeError to check for errors.
*/ */
void SdFile::write(const char* str) { void SdFile::write(const char* str) {
SdBaseFile::write(str, strlen(str)); SdBaseFile::write(str, strlen(str));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write a PROGMEM string to a file. /** Write a PROGMEM string to a file.
* \param[in] str Pointer to the PROGMEM string. * \param[in] str Pointer to the PROGMEM string.
* Use writeError to check for errors. * Use writeError to check for errors.
*/ */
void SdFile::write_P(PGM_P str) { void SdFile::write_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write a PROGMEM string followed by CR/LF to a file. /** Write a PROGMEM string followed by CR/LF to a file.
* \param[in] str Pointer to the PROGMEM string. * \param[in] str Pointer to the PROGMEM string.
* Use writeError to check for errors. * Use writeError to check for errors.
*/ */
void SdFile::writeln_P(PGM_P str) { void SdFile::writeln_P(PGM_P str) {
write_P(str); write_P(str);
write_P(PSTR("\r\n")); write_P(PSTR("\r\n"));
} }
#endif #endif

@ -1,289 +1,289 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino Sd2Card Library * Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman * Copyright (C) 2009 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#ifndef SdInfo_h #ifndef SdInfo_h
#define SdInfo_h #define SdInfo_h
#include <stdint.h> #include <stdint.h>
// Based on the document: // Based on the document:
// //
// SD Specifications // SD Specifications
// Part 1 // Part 1
// Physical Layer // Physical Layer
// Simplified Specification // Simplified Specification
// Version 3.01 // Version 3.01
// May 18, 2010 // May 18, 2010
// //
// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs // http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// SD card commands // SD card commands
/** GO_IDLE_STATE - init card in spi mode if CS low */ /** GO_IDLE_STATE - init card in spi mode if CS low */
uint8_t const CMD0 = 0X00; uint8_t const CMD0 = 0X00;
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ /** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
uint8_t const CMD8 = 0X08; uint8_t const CMD8 = 0X08;
/** SEND_CSD - read the Card Specific Data (CSD register) */ /** SEND_CSD - read the Card Specific Data (CSD register) */
uint8_t const CMD9 = 0X09; uint8_t const CMD9 = 0X09;
/** SEND_CID - read the card identification information (CID register) */ /** SEND_CID - read the card identification information (CID register) */
uint8_t const CMD10 = 0X0A; uint8_t const CMD10 = 0X0A;
/** STOP_TRANSMISSION - end multiple block read sequence */ /** STOP_TRANSMISSION - end multiple block read sequence */
uint8_t const CMD12 = 0X0C; uint8_t const CMD12 = 0X0C;
/** SEND_STATUS - read the card status register */ /** SEND_STATUS - read the card status register */
uint8_t const CMD13 = 0X0D; uint8_t const CMD13 = 0X0D;
/** READ_SINGLE_BLOCK - read a single data block from the card */ /** READ_SINGLE_BLOCK - read a single data block from the card */
uint8_t const CMD17 = 0X11; uint8_t const CMD17 = 0X11;
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */ /** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
uint8_t const CMD18 = 0X12; uint8_t const CMD18 = 0X12;
/** WRITE_BLOCK - write a single data block to the card */ /** WRITE_BLOCK - write a single data block to the card */
uint8_t const CMD24 = 0X18; uint8_t const CMD24 = 0X18;
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ /** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
uint8_t const CMD25 = 0X19; uint8_t const CMD25 = 0X19;
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */ /** ERASE_WR_BLK_START - sets the address of the first block to be erased */
uint8_t const CMD32 = 0X20; uint8_t const CMD32 = 0X20;
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous /** ERASE_WR_BLK_END - sets the address of the last block of the continuous
range to be erased*/ range to be erased*/
uint8_t const CMD33 = 0X21; uint8_t const CMD33 = 0X21;
/** ERASE - erase all previously selected blocks */ /** ERASE - erase all previously selected blocks */
uint8_t const CMD38 = 0X26; uint8_t const CMD38 = 0X26;
/** APP_CMD - escape for application specific command */ /** APP_CMD - escape for application specific command */
uint8_t const CMD55 = 0X37; uint8_t const CMD55 = 0X37;
/** READ_OCR - read the OCR register of a card */ /** READ_OCR - read the OCR register of a card */
uint8_t const CMD58 = 0X3A; uint8_t const CMD58 = 0X3A;
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be /** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
pre-erased before writing */ pre-erased before writing */
uint8_t const ACMD23 = 0X17; uint8_t const ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and /** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */ activates the card's initialization process */
uint8_t const ACMD41 = 0X29; uint8_t const ACMD41 = 0X29;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** status for card in the ready state */ /** status for card in the ready state */
uint8_t const R1_READY_STATE = 0X00; uint8_t const R1_READY_STATE = 0X00;
/** status for card in the idle state */ /** status for card in the idle state */
uint8_t const R1_IDLE_STATE = 0X01; uint8_t const R1_IDLE_STATE = 0X01;
/** status bit for illegal command */ /** status bit for illegal command */
uint8_t const R1_ILLEGAL_COMMAND = 0X04; uint8_t const R1_ILLEGAL_COMMAND = 0X04;
/** start data token for read or write single block*/ /** start data token for read or write single block*/
uint8_t const DATA_START_BLOCK = 0XFE; uint8_t const DATA_START_BLOCK = 0XFE;
/** stop token for write multiple blocks*/ /** stop token for write multiple blocks*/
uint8_t const STOP_TRAN_TOKEN = 0XFD; uint8_t const STOP_TRAN_TOKEN = 0XFD;
/** start data token for write multiple blocks*/ /** start data token for write multiple blocks*/
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC; uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
/** mask for data response tokens after a write block operation */ /** mask for data response tokens after a write block operation */
uint8_t const DATA_RES_MASK = 0X1F; uint8_t const DATA_RES_MASK = 0X1F;
/** write data accepted token */ /** write data accepted token */
uint8_t const DATA_RES_ACCEPTED = 0X05; uint8_t const DATA_RES_ACCEPTED = 0X05;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Card IDentification (CID) register */ /** Card IDentification (CID) register */
typedef struct CID { typedef struct CID {
// byte 0 // byte 0
/** Manufacturer ID */ /** Manufacturer ID */
unsigned char mid; unsigned char mid;
// byte 1-2 // byte 1-2
/** OEM/Application ID */ /** OEM/Application ID */
char oid[2]; char oid[2];
// byte 3-7 // byte 3-7
/** Product name */ /** Product name */
char pnm[5]; char pnm[5];
// byte 8 // byte 8
/** Product revision least significant digit */ /** Product revision least significant digit */
unsigned char prv_m : 4; unsigned char prv_m : 4;
/** Product revision most significant digit */ /** Product revision most significant digit */
unsigned char prv_n : 4; unsigned char prv_n : 4;
// byte 9-12 // byte 9-12
/** Product serial number */ /** Product serial number */
uint32_t psn; uint32_t psn;
// byte 13 // byte 13
/** Manufacturing date year low digit */ /** Manufacturing date year low digit */
unsigned char mdt_year_high : 4; unsigned char mdt_year_high : 4;
/** not used */ /** not used */
unsigned char reserved : 4; unsigned char reserved : 4;
// byte 14 // byte 14
/** Manufacturing date month */ /** Manufacturing date month */
unsigned char mdt_month : 4; unsigned char mdt_month : 4;
/** Manufacturing date year low digit */ /** Manufacturing date year low digit */
unsigned char mdt_year_low : 4; unsigned char mdt_year_low : 4;
// byte 15 // byte 15
/** not used always 1 */ /** not used always 1 */
unsigned char always1 : 1; unsigned char always1 : 1;
/** CRC7 checksum */ /** CRC7 checksum */
unsigned char crc : 7; unsigned char crc : 7;
} cid_t; } cid_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** CSD for version 1.00 cards */ /** CSD for version 1.00 cards */
typedef struct CSDV1 { typedef struct CSDV1 {
// byte 0 // byte 0
unsigned char reserved1 : 6; unsigned char reserved1 : 6;
unsigned char csd_ver : 2; unsigned char csd_ver : 2;
// byte 1 // byte 1
unsigned char taac; unsigned char taac;
// byte 2 // byte 2
unsigned char nsac; unsigned char nsac;
// byte 3 // byte 3
unsigned char tran_speed; unsigned char tran_speed;
// byte 4 // byte 4
unsigned char ccc_high; unsigned char ccc_high;
// byte 5 // byte 5
unsigned char read_bl_len : 4; unsigned char read_bl_len : 4;
unsigned char ccc_low : 4; unsigned char ccc_low : 4;
// byte 6 // byte 6
unsigned char c_size_high : 2; unsigned char c_size_high : 2;
unsigned char reserved2 : 2; unsigned char reserved2 : 2;
unsigned char dsr_imp : 1; unsigned char dsr_imp : 1;
unsigned char read_blk_misalign : 1; unsigned char read_blk_misalign : 1;
unsigned char write_blk_misalign : 1; unsigned char write_blk_misalign : 1;
unsigned char read_bl_partial : 1; unsigned char read_bl_partial : 1;
// byte 7 // byte 7
unsigned char c_size_mid; unsigned char c_size_mid;
// byte 8 // byte 8
unsigned char vdd_r_curr_max : 3; unsigned char vdd_r_curr_max : 3;
unsigned char vdd_r_curr_min : 3; unsigned char vdd_r_curr_min : 3;
unsigned char c_size_low : 2; unsigned char c_size_low : 2;
// byte 9 // byte 9
unsigned char c_size_mult_high : 2; unsigned char c_size_mult_high : 2;
unsigned char vdd_w_cur_max : 3; unsigned char vdd_w_cur_max : 3;
unsigned char vdd_w_curr_min : 3; unsigned char vdd_w_curr_min : 3;
// byte 10 // byte 10
unsigned char sector_size_high : 6; unsigned char sector_size_high : 6;
unsigned char erase_blk_en : 1; unsigned char erase_blk_en : 1;
unsigned char c_size_mult_low : 1; unsigned char c_size_mult_low : 1;
// byte 11 // byte 11
unsigned char wp_grp_size : 7; unsigned char wp_grp_size : 7;
unsigned char sector_size_low : 1; unsigned char sector_size_low : 1;
// byte 12 // byte 12
unsigned char write_bl_len_high : 2; unsigned char write_bl_len_high : 2;
unsigned char r2w_factor : 3; unsigned char r2w_factor : 3;
unsigned char reserved3 : 2; unsigned char reserved3 : 2;
unsigned char wp_grp_enable : 1; unsigned char wp_grp_enable : 1;
// byte 13 // byte 13
unsigned char reserved4 : 5; unsigned char reserved4 : 5;
unsigned char write_partial : 1; unsigned char write_partial : 1;
unsigned char write_bl_len_low : 2; unsigned char write_bl_len_low : 2;
// byte 14 // byte 14
unsigned char reserved5: 2; unsigned char reserved5: 2;
unsigned char file_format : 2; unsigned char file_format : 2;
unsigned char tmp_write_protect : 1; unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1; unsigned char perm_write_protect : 1;
unsigned char copy : 1; unsigned char copy : 1;
/** Indicates the file format on the card */ /** Indicates the file format on the card */
unsigned char file_format_grp : 1; unsigned char file_format_grp : 1;
// byte 15 // byte 15
unsigned char always1 : 1; unsigned char always1 : 1;
unsigned char crc : 7; unsigned char crc : 7;
} csd1_t; } csd1_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** CSD for version 2.00 cards */ /** CSD for version 2.00 cards */
typedef struct CSDV2 { typedef struct CSDV2 {
// byte 0 // byte 0
unsigned char reserved1 : 6; unsigned char reserved1 : 6;
unsigned char csd_ver : 2; unsigned char csd_ver : 2;
// byte 1 // byte 1
/** fixed to 0X0E */ /** fixed to 0X0E */
unsigned char taac; unsigned char taac;
// byte 2 // byte 2
/** fixed to 0 */ /** fixed to 0 */
unsigned char nsac; unsigned char nsac;
// byte 3 // byte 3
unsigned char tran_speed; unsigned char tran_speed;
// byte 4 // byte 4
unsigned char ccc_high; unsigned char ccc_high;
// byte 5 // byte 5
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
unsigned char read_bl_len : 4; unsigned char read_bl_len : 4;
unsigned char ccc_low : 4; unsigned char ccc_low : 4;
// byte 6 // byte 6
/** not used */ /** not used */
unsigned char reserved2 : 4; unsigned char reserved2 : 4;
unsigned char dsr_imp : 1; unsigned char dsr_imp : 1;
/** fixed to 0 */ /** fixed to 0 */
unsigned char read_blk_misalign : 1; unsigned char read_blk_misalign : 1;
/** fixed to 0 */ /** fixed to 0 */
unsigned char write_blk_misalign : 1; unsigned char write_blk_misalign : 1;
/** fixed to 0 - no partial read */ /** fixed to 0 - no partial read */
unsigned char read_bl_partial : 1; unsigned char read_bl_partial : 1;
// byte 7 // byte 7
/** not used */ /** not used */
unsigned char reserved3 : 2; unsigned char reserved3 : 2;
/** high part of card size */ /** high part of card size */
unsigned char c_size_high : 6; unsigned char c_size_high : 6;
// byte 8 // byte 8
/** middle part of card size */ /** middle part of card size */
unsigned char c_size_mid; unsigned char c_size_mid;
// byte 9 // byte 9
/** low part of card size */ /** low part of card size */
unsigned char c_size_low; unsigned char c_size_low;
// byte 10 // byte 10
/** sector size is fixed at 64 KB */ /** sector size is fixed at 64 KB */
unsigned char sector_size_high : 6; unsigned char sector_size_high : 6;
/** fixed to 1 - erase single is supported */ /** fixed to 1 - erase single is supported */
unsigned char erase_blk_en : 1; unsigned char erase_blk_en : 1;
/** not used */ /** not used */
unsigned char reserved4 : 1; unsigned char reserved4 : 1;
// byte 11 // byte 11
unsigned char wp_grp_size : 7; unsigned char wp_grp_size : 7;
/** sector size is fixed at 64 KB */ /** sector size is fixed at 64 KB */
unsigned char sector_size_low : 1; unsigned char sector_size_low : 1;
// byte 12 // byte 12
/** write_bl_len fixed for 512 byte blocks */ /** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_high : 2; unsigned char write_bl_len_high : 2;
/** fixed value of 2 */ /** fixed value of 2 */
unsigned char r2w_factor : 3; unsigned char r2w_factor : 3;
/** not used */ /** not used */
unsigned char reserved5 : 2; unsigned char reserved5 : 2;
/** fixed value of 0 - no write protect groups */ /** fixed value of 0 - no write protect groups */
unsigned char wp_grp_enable : 1; unsigned char wp_grp_enable : 1;
// byte 13 // byte 13
unsigned char reserved6 : 5; unsigned char reserved6 : 5;
/** always zero - no partial block read*/ /** always zero - no partial block read*/
unsigned char write_partial : 1; unsigned char write_partial : 1;
/** write_bl_len fixed for 512 byte blocks */ /** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_low : 2; unsigned char write_bl_len_low : 2;
// byte 14 // byte 14
unsigned char reserved7: 2; unsigned char reserved7: 2;
/** Do not use always 0 */ /** Do not use always 0 */
unsigned char file_format : 2; unsigned char file_format : 2;
unsigned char tmp_write_protect : 1; unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1; unsigned char perm_write_protect : 1;
unsigned char copy : 1; unsigned char copy : 1;
/** Do not use always 0 */ /** Do not use always 0 */
unsigned char file_format_grp : 1; unsigned char file_format_grp : 1;
// byte 15 // byte 15
/** not used always 1 */ /** not used always 1 */
unsigned char always1 : 1; unsigned char always1 : 1;
/** checksum */ /** checksum */
unsigned char crc : 7; unsigned char crc : 7;
} csd2_t; } csd2_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** union of old and new style CSD register */ /** union of old and new style CSD register */
union csd_t { union csd_t {
csd1_t v1; csd1_t v1;
csd2_t v2; csd2_t v2;
}; };
#endif // SdInfo_h #endif // SdInfo_h
#endif #endif

@ -1,420 +1,420 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** /**
* Arduino SdFat Library * Arduino SdFat Library
* Copyright (C) 2009 by William Greiman * Copyright (C) 2009 by William Greiman
* *
* This file is part of the Arduino Sd2Card Library * This file is part of the Arduino Sd2Card Library
*/ */
#include "Marlin.h" #include "Marlin.h"
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#include "SdVolume.h" #include "SdVolume.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if !USE_MULTIPLE_CARDS #if !USE_MULTIPLE_CARDS
// raw block cache // raw block cache
uint32_t SdVolume::cacheBlockNumber_; // current block number uint32_t SdVolume::cacheBlockNumber_; // current block number
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
Sd2Card* SdVolume::sdCard_; // pointer to SD card object Sd2Card* SdVolume::sdCard_; // pointer to SD card object
bool SdVolume::cacheDirty_; // cacheFlush() will write block if true bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
#endif // USE_MULTIPLE_CARDS #endif // USE_MULTIPLE_CARDS
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// find a contiguous group of clusters // find a contiguous group of clusters
bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
// start of group // start of group
uint32_t bgnCluster; uint32_t bgnCluster;
// end of group // end of group
uint32_t endCluster; uint32_t endCluster;
// last cluster of FAT // last cluster of FAT
uint32_t fatEnd = clusterCount_ + 1; uint32_t fatEnd = clusterCount_ + 1;
// flag to save place to start next search // flag to save place to start next search
bool setStart; bool setStart;
// set search start cluster // set search start cluster
if (*curCluster) { if (*curCluster) {
// try to make file contiguous // try to make file contiguous
bgnCluster = *curCluster + 1; bgnCluster = *curCluster + 1;
// don't save new start location // don't save new start location
setStart = false; setStart = false;
} }
else { else {
// start at likely place for free cluster // start at likely place for free cluster
bgnCluster = allocSearchStart_; bgnCluster = allocSearchStart_;
// save next search start if one cluster // save next search start if one cluster
setStart = count == 1; setStart = count == 1;
} }
// end of group // end of group
endCluster = bgnCluster; endCluster = bgnCluster;
// search the FAT for free clusters // search the FAT for free clusters
for (uint32_t n = 0;; n++, endCluster++) { for (uint32_t n = 0;; n++, endCluster++) {
// can't find space checked all clusters // can't find space checked all clusters
if (n >= clusterCount_) goto fail; if (n >= clusterCount_) goto fail;
// past end - start from beginning of FAT // past end - start from beginning of FAT
if (endCluster > fatEnd) { if (endCluster > fatEnd) {
bgnCluster = endCluster = 2; bgnCluster = endCluster = 2;
} }
uint32_t f; uint32_t f;
if (!fatGet(endCluster, &f)) goto fail; if (!fatGet(endCluster, &f)) goto fail;
if (f != 0) { if (f != 0) {
// cluster in use try next cluster as bgnCluster // cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1; bgnCluster = endCluster + 1;
} }
else if ((endCluster - bgnCluster + 1) == count) { else if ((endCluster - bgnCluster + 1) == count) {
// done - found space // done - found space
break; break;
} }
} }
// mark end of chain // mark end of chain
if (!fatPutEOC(endCluster)) goto fail; if (!fatPutEOC(endCluster)) goto fail;
// link clusters // link clusters
while (endCluster > bgnCluster) { while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) goto fail; if (!fatPut(endCluster - 1, endCluster)) goto fail;
endCluster--; endCluster--;
} }
if (*curCluster != 0) { if (*curCluster != 0) {
// connect chains // connect chains
if (!fatPut(*curCluster, bgnCluster)) goto fail; if (!fatPut(*curCluster, bgnCluster)) goto fail;
} }
// return first cluster number to caller // return first cluster number to caller
*curCluster = bgnCluster; *curCluster = bgnCluster;
// remember possible next free cluster // remember possible next free cluster
if (setStart) allocSearchStart_ = bgnCluster + 1; if (setStart) allocSearchStart_ = bgnCluster + 1;
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool SdVolume::cacheFlush() { bool SdVolume::cacheFlush() {
if (cacheDirty_) { if (cacheDirty_) {
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
goto fail; goto fail;
} }
// mirror FAT tables // mirror FAT tables
if (cacheMirrorBlock_) { if (cacheMirrorBlock_) {
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
goto fail; goto fail;
} }
cacheMirrorBlock_ = 0; cacheMirrorBlock_ = 0;
} }
cacheDirty_ = 0; cacheDirty_ = 0;
} }
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) { bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
if (cacheBlockNumber_ != blockNumber) { if (cacheBlockNumber_ != blockNumber) {
if (!cacheFlush()) goto fail; if (!cacheFlush()) goto fail;
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
cacheBlockNumber_ = blockNumber; cacheBlockNumber_ = blockNumber;
} }
if (dirty) cacheDirty_ = true; if (dirty) cacheDirty_ = true;
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// return the size in bytes of a cluster chain // return the size in bytes of a cluster chain
bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) { bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
uint32_t s = 0; uint32_t s = 0;
do { do {
if (!fatGet(cluster, &cluster)) goto fail; if (!fatGet(cluster, &cluster)) goto fail;
s += 512UL << clusterSizeShift_; s += 512UL << clusterSizeShift_;
} while (!isEOC(cluster)); } while (!isEOC(cluster));
*size = s; *size = s;
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Fetch a FAT entry // Fetch a FAT entry
bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t lba; uint32_t lba;
if (cluster > (clusterCount_ + 1)) goto fail; if (cluster > (clusterCount_ + 1)) goto fail;
if (FAT12_SUPPORT && fatType_ == 12) { if (FAT12_SUPPORT && fatType_ == 12) {
uint16_t index = cluster; uint16_t index = cluster;
index += index >> 1; index += index >> 1;
lba = fatStartBlock_ + (index >> 9); lba = fatStartBlock_ + (index >> 9);
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
index &= 0X1FF; index &= 0X1FF;
uint16_t tmp = cacheBuffer_.data[index]; uint16_t tmp = cacheBuffer_.data[index];
index++; index++;
if (index == 512) { if (index == 512) {
if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
index = 0; index = 0;
} }
tmp |= cacheBuffer_.data[index] << 8; tmp |= cacheBuffer_.data[index] << 8;
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
return true; return true;
} }
if (fatType_ == 16) { if (fatType_ == 16) {
lba = fatStartBlock_ + (cluster >> 8); lba = fatStartBlock_ + (cluster >> 8);
} }
else if (fatType_ == 32) { else if (fatType_ == 32) {
lba = fatStartBlock_ + (cluster >> 7); lba = fatStartBlock_ + (cluster >> 7);
} }
else { else {
goto fail; goto fail;
} }
if (lba != cacheBlockNumber_) { if (lba != cacheBlockNumber_) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
} }
if (fatType_ == 16) { if (fatType_ == 16) {
*value = cacheBuffer_.fat16[cluster & 0XFF]; *value = cacheBuffer_.fat16[cluster & 0XFF];
} }
else { else {
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
} }
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Store a FAT entry // Store a FAT entry
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
uint32_t lba; uint32_t lba;
// error if reserved cluster // error if reserved cluster
if (cluster < 2) goto fail; if (cluster < 2) goto fail;
// error if not in FAT // error if not in FAT
if (cluster > (clusterCount_ + 1)) goto fail; if (cluster > (clusterCount_ + 1)) goto fail;
if (FAT12_SUPPORT && fatType_ == 12) { if (FAT12_SUPPORT && fatType_ == 12) {
uint16_t index = cluster; uint16_t index = cluster;
index += index >> 1; index += index >> 1;
lba = fatStartBlock_ + (index >> 9); lba = fatStartBlock_ + (index >> 9);
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// mirror second FAT // mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
index &= 0X1FF; index &= 0X1FF;
uint8_t tmp = value; uint8_t tmp = value;
if (cluster & 1) { if (cluster & 1) {
tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
} }
cacheBuffer_.data[index] = tmp; cacheBuffer_.data[index] = tmp;
index++; index++;
if (index == 512) { if (index == 512) {
lba++; lba++;
index = 0; index = 0;
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// mirror second FAT // mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
} }
tmp = value >> 4; tmp = value >> 4;
if (!(cluster & 1)) { if (!(cluster & 1)) {
tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
} }
cacheBuffer_.data[index] = tmp; cacheBuffer_.data[index] = tmp;
return true; return true;
} }
if (fatType_ == 16) { if (fatType_ == 16) {
lba = fatStartBlock_ + (cluster >> 8); lba = fatStartBlock_ + (cluster >> 8);
} }
else if (fatType_ == 32) { else if (fatType_ == 32) {
lba = fatStartBlock_ + (cluster >> 7); lba = fatStartBlock_ + (cluster >> 7);
} }
else { else {
goto fail; goto fail;
} }
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// store entry // store entry
if (fatType_ == 16) { if (fatType_ == 16) {
cacheBuffer_.fat16[cluster & 0XFF] = value; cacheBuffer_.fat16[cluster & 0XFF] = value;
} }
else { else {
cacheBuffer_.fat32[cluster & 0X7F] = value; cacheBuffer_.fat32[cluster & 0X7F] = value;
} }
// mirror second FAT // mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// free a cluster chain // free a cluster chain
bool SdVolume::freeChain(uint32_t cluster) { bool SdVolume::freeChain(uint32_t cluster) {
uint32_t next; uint32_t next;
// clear free cluster location // clear free cluster location
allocSearchStart_ = 2; allocSearchStart_ = 2;
do { do {
if (!fatGet(cluster, &next)) goto fail; if (!fatGet(cluster, &next)) goto fail;
// free cluster // free cluster
if (!fatPut(cluster, 0)) goto fail; if (!fatPut(cluster, 0)) goto fail;
cluster = next; cluster = next;
} while (!isEOC(cluster)); } while (!isEOC(cluster));
return true; return true;
fail: fail:
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Volume free space in clusters. /** Volume free space in clusters.
* *
* \return Count of free clusters for success or -1 if an error occurs. * \return Count of free clusters for success or -1 if an error occurs.
*/ */
int32_t SdVolume::freeClusterCount() { int32_t SdVolume::freeClusterCount() {
uint32_t free = 0; uint32_t free = 0;
uint16_t n; uint16_t n;
uint32_t todo = clusterCount_ + 2; uint32_t todo = clusterCount_ + 2;
if (fatType_ == 16) { if (fatType_ == 16) {
n = 256; n = 256;
} }
else if (fatType_ == 32) { else if (fatType_ == 32) {
n = 128; n = 128;
} }
else { else {
// put FAT12 here // put FAT12 here
return -1; return -1;
} }
for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
NOMORE(n, todo); NOMORE(n, todo);
if (fatType_ == 16) { if (fatType_ == 16) {
for (uint16_t i = 0; i < n; i++) { for (uint16_t i = 0; i < n; i++) {
if (cacheBuffer_.fat16[i] == 0) free++; if (cacheBuffer_.fat16[i] == 0) free++;
} }
} }
else { else {
for (uint16_t i = 0; i < n; i++) { for (uint16_t i = 0; i < n; i++) {
if (cacheBuffer_.fat32[i] == 0) free++; if (cacheBuffer_.fat32[i] == 0) free++;
} }
} }
} }
return free; return free;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Initialize a FAT volume. /** Initialize a FAT volume.
* *
* \param[in] dev The SD card where the volume is located. * \param[in] dev The SD card where the volume is located.
* *
* \param[in] part The partition to be used. Legal values for \a part are * \param[in] part The partition to be used. Legal values for \a part are
* 1-4 to use the corresponding partition on a device formatted with * 1-4 to use the corresponding partition on a device formatted with
* a MBR, Master Boot Record, or zero if the device is formatted as * a MBR, Master Boot Record, or zero if the device is formatted as
* a super floppy with the FAT boot sector in block zero. * a super floppy with the FAT boot sector in block zero.
* *
* \return The value one, true, is returned for success and * \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. Reasons for * the value zero, false, is returned for failure. Reasons for
* failure include not finding a valid partition, not finding a valid * failure include not finding a valid partition, not finding a valid
* FAT file system in the specified partition or an I/O error. * FAT file system in the specified partition or an I/O error.
*/ */
bool SdVolume::init(Sd2Card* dev, uint8_t part) { bool SdVolume::init(Sd2Card* dev, uint8_t part) {
uint32_t totalBlocks; uint32_t totalBlocks;
uint32_t volumeStartBlock = 0; uint32_t volumeStartBlock = 0;
fat32_boot_t* fbs; fat32_boot_t* fbs;
sdCard_ = dev; sdCard_ = dev;
fatType_ = 0; fatType_ = 0;
allocSearchStart_ = 2; allocSearchStart_ = 2;
cacheDirty_ = 0; // cacheFlush() will write block if true cacheDirty_ = 0; // cacheFlush() will write block if true
cacheMirrorBlock_ = 0; cacheMirrorBlock_ = 0;
cacheBlockNumber_ = 0XFFFFFFFF; cacheBlockNumber_ = 0XFFFFFFFF;
// if part == 0 assume super floppy with FAT boot sector in block zero // if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table // if part > 0 assume mbr volume with partition table
if (part) { if (part) {
if (part > 4)goto fail; if (part > 4)goto fail;
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
part_t* p = &cacheBuffer_.mbr.part[part - 1]; part_t* p = &cacheBuffer_.mbr.part[part - 1];
if ((p->boot & 0X7F) != 0 || if ((p->boot & 0X7F) != 0 ||
p->totalSectors < 100 || p->totalSectors < 100 ||
p->firstSector == 0) { p->firstSector == 0) {
// not a valid partition // not a valid partition
goto fail; goto fail;
} }
volumeStartBlock = p->firstSector; volumeStartBlock = p->firstSector;
} }
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
fbs = &cacheBuffer_.fbs32; fbs = &cacheBuffer_.fbs32;
if (fbs->bytesPerSector != 512 || if (fbs->bytesPerSector != 512 ||
fbs->fatCount == 0 || fbs->fatCount == 0 ||
fbs->reservedSectorCount == 0 || fbs->reservedSectorCount == 0 ||
fbs->sectorsPerCluster == 0) { fbs->sectorsPerCluster == 0) {
// not valid FAT volume // not valid FAT volume
goto fail; goto fail;
} }
fatCount_ = fbs->fatCount; fatCount_ = fbs->fatCount;
blocksPerCluster_ = fbs->sectorsPerCluster; blocksPerCluster_ = fbs->sectorsPerCluster;
// determine shift that is same as multiply by blocksPerCluster_ // determine shift that is same as multiply by blocksPerCluster_
clusterSizeShift_ = 0; clusterSizeShift_ = 0;
while (blocksPerCluster_ != _BV(clusterSizeShift_)) { while (blocksPerCluster_ != _BV(clusterSizeShift_)) {
// error if not power of 2 // error if not power of 2
if (clusterSizeShift_++ > 7) goto fail; if (clusterSizeShift_++ > 7) goto fail;
} }
blocksPerFat_ = fbs->sectorsPerFat16 ? blocksPerFat_ = fbs->sectorsPerFat16 ?
fbs->sectorsPerFat16 : fbs->sectorsPerFat32; fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
// count for FAT16 zero for FAT32 // count for FAT16 zero for FAT32
rootDirEntryCount_ = fbs->rootDirEntryCount; rootDirEntryCount_ = fbs->rootDirEntryCount;
// directory start for FAT16 dataStart for FAT32 // directory start for FAT16 dataStart for FAT32
rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
// data start for FAT16 and FAT32 // data start for FAT16 and FAT32
dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511) / 512); dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511) / 512);
// total blocks for FAT16 or FAT32 // total blocks for FAT16 or FAT32
totalBlocks = fbs->totalSectors16 ? totalBlocks = fbs->totalSectors16 ?
fbs->totalSectors16 : fbs->totalSectors32; fbs->totalSectors16 : fbs->totalSectors32;
// total data blocks // total data blocks
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
// divide by cluster size to get cluster count // divide by cluster size to get cluster count
clusterCount_ >>= clusterSizeShift_; clusterCount_ >>= clusterSizeShift_;
// FAT type is determined by cluster count // FAT type is determined by cluster count
if (clusterCount_ < 4085) { if (clusterCount_ < 4085) {
fatType_ = 12; fatType_ = 12;
if (!FAT12_SUPPORT) goto fail; if (!FAT12_SUPPORT) goto fail;
} }
else if (clusterCount_ < 65525) { else if (clusterCount_ < 65525) {
fatType_ = 16; fatType_ = 16;
} }
else { else {
rootDirStart_ = fbs->fat32RootCluster; rootDirStart_ = fbs->fat32RootCluster;
fatType_ = 32; fatType_ = 32;
} }
return true; return true;
fail: fail:
return false; return false;
} }
#endif #endif

@ -1,4 +1,4 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *

@ -1,4 +1,4 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *

@ -1,4 +1,4 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *

@ -1,94 +1,94 @@
# Marlin 3D Printer Firmware # Marlin 3D Printer Firmware
<img align="top" width=175 src="Documentation/Logo/Marlin%20Logo%20GitHub.png" /> <img align="top" width=175 src="Documentation/Logo/Marlin%20Logo%20GitHub.png" />
Additional documentation can be found in [The Marlin Wiki](https://github.com/MarlinFirmware/Marlin/wiki/Main-Page). Additional documentation can be found in [The Marlin Wiki](https://github.com/MarlinFirmware/Marlin/wiki/Main-Page).
## Release Candidate -- Marlin 1.1.0-RC5 - 01 April 2016 ## Release Candidate -- Marlin 1.1.0-RC5 - 01 April 2016
__Not for production use use with caution!__ __Not for production use use with caution!__
You can download earlier versions of Marlin on the [Releases page](https://github.com/MarlinFirmware/Marlin/releases). (The latest "stable" release of Marlin is 1.0.2-1.) You can download earlier versions of Marlin on the [Releases page](https://github.com/MarlinFirmware/Marlin/releases). (The latest "stable" release of Marlin is 1.0.2-1.)
You'll always find the latest Release Candidate in the ["RC" branch](https://github.com/MarlinFirmware/Marlin/tree/RC). Bugs that we find in the current Release Candidate are patched in the ["RCBugFix" branch](https://github.com/MarlinFirmware/Marlin/tree/RC), so during beta testing this is where you can always find the latest code on its way towards release. You'll always find the latest Release Candidate in the ["RC" branch](https://github.com/MarlinFirmware/Marlin/tree/RC). Bugs that we find in the current Release Candidate are patched in the ["RCBugFix" branch](https://github.com/MarlinFirmware/Marlin/tree/RC), so during beta testing this is where you can always find the latest code on its way towards release.
Future development (Marlin 1.2 and beyond) takes place in the [MarlinDev repository](https://github.com/MarlinFirmware/MarlinDev/). Future development (Marlin 1.2 and beyond) takes place in the [MarlinDev repository](https://github.com/MarlinFirmware/MarlinDev/).
## Recent Changes ## Recent Changes
- RCBugFix - RCBugFix
- Throw error if compiling with older versions (<1.60) of Arduino due to serios problems with outdated Arduino versions - Throw error if compiling with older versions (<1.60) of Arduino due to serios problems with outdated Arduino versions
- Please upgrade your IDE at least to Arduino 1.6.0. Thanks. - Please upgrade your IDE at least to Arduino 1.6.0. Thanks.
- RC5 - 01 Apr 2016 - RC5 - 01 Apr 2016
- Warn if compiling with older versions (<1.50) of Arduino - Warn if compiling with older versions (<1.50) of Arduino
- Fix various LCD menu issues - Fix various LCD menu issues
- Add formal support for MKSv1.3 and Sainsmart (RAMPS variants) - Add formal support for MKSv1.3 and Sainsmart (RAMPS variants)
- Fix bugs in M104, M109, and M190 - Fix bugs in M104, M109, and M190
- Fix broken M404 command - Fix broken M404 command
- Fix issues with M23 and "Start SD Print" - Fix issues with M23 and "Start SD Print"
- More output for M111 - More output for M111
- Rename FILAMENT_SENSOR to FILAMENT_WIDTH_SENSOR - Rename FILAMENT_SENSOR to FILAMENT_WIDTH_SENSOR
- Fix SD card bugs - Fix SD card bugs
- and a lot more - and a lot more
- see https://github.com/MarlinFirmware/Marlin/releases/tag/1.1.0-RC5 for details - see https://github.com/MarlinFirmware/Marlin/releases/tag/1.1.0-RC5 for details
- RC4 - 24 Mar 2016 - RC4 - 24 Mar 2016
- Many lingering bugs and nagging issues addressed - Many lingering bugs and nagging issues addressed
- Improvements to LCD menus, CoreXY/CoreXZ, Delta, Bed Leveling, and more… - Improvements to LCD menus, CoreXY/CoreXZ, Delta, Bed Leveling, and more…
- RC3 - 01 Dec 2015 - RC3 - 01 Dec 2015
- A number of language sensitive strings have been revised - A number of language sensitive strings have been revised
- Formatting of the LCD display has been improved to handle negative coordinates better - Formatting of the LCD display has been improved to handle negative coordinates better
- Various compiler-related issues have been corrected - Various compiler-related issues have been corrected
- RC2 - 29 Sep 2015 - RC2 - 29 Sep 2015
- File styling reverted - File styling reverted
- LCD update frequency reduced - LCD update frequency reduced
- RC1 - 19 Sep 2015 - RC1 - 19 Sep 2015
- Published for testing - Published for testing
## Submitting Patches ## Submitting Patches
Proposed patches should be submitted as a Pull Request against the [RCBugFix](https://github.com/MarlinFirmware/Marlin/tree/RCBugFix) branch. Proposed patches should be submitted as a Pull Request against the [RCBugFix](https://github.com/MarlinFirmware/Marlin/tree/RCBugFix) branch.
- Don't submit new feature proposals. The RCBugFix branch is for fixing bugs in existing features. - Don't submit new feature proposals. The RCBugFix branch is for fixing bugs in existing features.
- Do submit questions and concerns. The "naive" question is often the one we forget to ask. - Do submit questions and concerns. The "naive" question is often the one we forget to ask.
- Follow the proper coding style. Pull requests with styling errors will be delayed. See our [Coding Standards](https://github.com/MarlinFirmware/Marlin/wiki/DNE-Coding-Standards) page for more information. - Follow the proper coding style. Pull requests with styling errors will be delayed. See our [Coding Standards](https://github.com/MarlinFirmware/Marlin/wiki/DNE-Coding-Standards) page for more information.
## Current Status: Testing ## Current Status: Testing
Please test this firmware and inform us if it misbehaves in any way. Volunteers are standing by! Please test this firmware and inform us if it misbehaves in any way. Volunteers are standing by!
[![Coverity Scan Build Status](https://scan.coverity.com/projects/2224/badge.svg)](https://scan.coverity.com/projects/2224) [![Coverity Scan Build Status](https://scan.coverity.com/projects/2224/badge.svg)](https://scan.coverity.com/projects/2224)
[![Travis Build Status](https://travis-ci.org/MarlinFirmware/MarlinDev.svg)](https://travis-ci.org/MarlinFirmware/MarlinDev) [![Travis Build Status](https://travis-ci.org/MarlinFirmware/MarlinDev.svg)](https://travis-ci.org/MarlinFirmware/MarlinDev)
##### [RepRap.org Wiki Page](http://reprap.org/wiki/Marlin) ##### [RepRap.org Wiki Page](http://reprap.org/wiki/Marlin)
## Credits ## Credits
The current Marlin dev team consists of: The current Marlin dev team consists of:
- Scott Lahteine [@thinkyhead] - English - Scott Lahteine [@thinkyhead] - English
- [@Wurstnase] - Deutsch, English - [@Wurstnase] - Deutsch, English
- F. Malpartida [@fmalpartida] - English, Spanish - F. Malpartida [@fmalpartida] - English, Spanish
- Jochen Groppe [@CONSULitAS] - Deutsch, English - Jochen Groppe [@CONSULitAS] - Deutsch, English
- [@maverikou] - [@maverikou]
- Chris Palmer [@nophead] - Chris Palmer [@nophead]
- [@paclema] - [@paclema]
- Edward Patel [@epatel] - Swedish, English - Edward Patel [@epatel] - Swedish, English
- Erik van der Zalm [@ErikZalm] - Erik van der Zalm [@ErikZalm]
- David Braam [@daid] - David Braam [@daid]
- Bernhard Kubicek [@bkubicek] - Bernhard Kubicek [@bkubicek]
- Roxanne Neufeld [@Roxy-3DPrintBoard] - English - Roxanne Neufeld [@Roxy-3DPrintBoard] - English
More features have been added by: More features have been added by:
- Alberto Cotronei [@MagoKimbra] - Alberto Cotronei [@MagoKimbra]
- Lampmaker, - Lampmaker,
- Bradley Feldman, - Bradley Feldman,
- and others... - and others...
## License ## License
Marlin is published under the [GPL license](/LICENSE) because we believe in open development. The GPL comes with both rights and obligations. Whether you use Marlin firmware as the driver for your open or closed-source product, you must keep Marlin open, and you must provide your compatible Marlin source code to end users upon request. The most straightforward way to comply with the Marlin license is to make a fork of Marlin on Github, perform your modifications, and direct users to your modified fork. Marlin is published under the [GPL license](/LICENSE) because we believe in open development. The GPL comes with both rights and obligations. Whether you use Marlin firmware as the driver for your open or closed-source product, you must keep Marlin open, and you must provide your compatible Marlin source code to end users upon request. The most straightforward way to comply with the Marlin license is to make a fork of Marlin on Github, perform your modifications, and direct users to your modified fork.
While we can't prevent the use of this code in products (3D printers, CNC, etc.) that are closed source or crippled by a patent, we would prefer that you choose another firmware or, better yet, make your own. While we can't prevent the use of this code in products (3D printers, CNC, etc.) that are closed source or crippled by a patent, we would prefer that you choose another firmware or, better yet, make your own.
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ErikZalm&url=https://github.com/MarlinFirmware/Marlin&title=Marlin&language=&tags=github&category=software) [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ErikZalm&url=https://github.com/MarlinFirmware/Marlin&title=Marlin&language=&tags=github&category=software)

Loading…
Cancel
Save