Browse Source

Merge pull request #1 from PaulStoffregen/master

07_feb-2019
main
WMXZ-EU 5 years ago
parent
commit
543cf825d0
No account linked to committer's email address
7 changed files with 116 additions and 53 deletions
  1. +1
    -1
      library.properties
  2. +46
    -20
      utility/KinetisSDHC.c
  3. +56
    -19
      utility/Sd2Card.cpp
  4. +5
    -5
      utility/Sd2Card.h
  5. +1
    -1
      utility/Sd2PinMap.h
  6. +2
    -2
      utility/SdFat.h
  7. +5
    -5
      utility/SdFile.cpp

+ 1
- 1
library.properties View File

name=SD name=SD
version=1.0.8
version=1.2.2
author=Arduino, SparkFun author=Arduino, SparkFun
maintainer=Paul Stoffregen maintainer=Paul Stoffregen
sentence=Enables reading and writing on SD cards. This version is optimized for Teensy. sentence=Enables reading and writing on SD cards. This version is optimized for Teensy.

+ 46
- 20
utility/KinetisSDHC.c View File

#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__MK64FX512__) || defined(__MK66FX1M0__)


#include "kinetis.h" #include "kinetis.h"
#include "core_pins.h" // testing only
//#include "core_pins.h" // testing only
//#include "HardwareSerial.h" // testing only


// Missing in Teensyduino 1.30 // Missing in Teensyduino 1.30
#ifndef MPU_CESR_VLD_MASK #ifndef MPU_CESR_VLD_MASK
SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h
}; };


/*void print_result(int n)
{
switch (n) {
case SDHC_RESULT_OK: serial_print("OK\n"); break;
case SDHC_RESULT_ERROR: serial_print("R/W Error\n"); break;
case SDHC_RESULT_WRPRT: serial_print("Write Protect\n"); break;
case SDHC_RESULT_NOT_READY: serial_print("Not Ready\n"); break;
case SDHC_RESULT_PARERR: serial_print("Invalid Param\n"); break;
case SDHC_RESULT_NO_RESPONSE: serial_print("No Response\n"); break;
default: serial_print("Unknown result\n");
}
}*/

#define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */ #define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */
#define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */ #define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */
#define SDHC_STATUS_PROTECT 0x04 /* Write protected */ #define SDHC_STATUS_PROTECT 0x04 /* Write protected */
// prescale can be 2, 4, 8, 16, 32, 64, 128, 256 // prescale can be 2, 4, 8, 16, 32, 64, 128, 256
// divisor can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 // divisor can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
#define SDHC_SYSCTL_DIVISOR(prescale, divisor) \ #define SDHC_SYSCTL_DIVISOR(prescale, divisor) \
(SDHC_SYSCTL_DVS((prescale)>>1)|SDHC_SYSCTL_SDCLKFS((divisor)-1))
(SDHC_SYSCTL_SDCLKFS((prescale)>>1)|SDHC_SYSCTL_DVS((divisor)-1))


#if (F_CPU == 240000000)
#if (F_CPU == 256000000)
#define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 400 kHz
#define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 6) // 21.3 MHz
#define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 42.6 MHz
#elif (F_CPU == 240000000)
#define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 375 kHz #define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 375 kHz
#define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 5) // 24 MHz #define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 5) // 24 MHz
#define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 40 MHz #define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 40 MHz
* Private functions * Private functions
******************************************************************************/ ******************************************************************************/


static uint8_t SDHC_Init(void);
static void SDHC_InitGPIO(void); static void SDHC_InitGPIO(void);
static void SDHC_ReleaseGPIO(void); static void SDHC_ReleaseGPIO(void);
static void SDHC_SetClock(uint32_t sysctl); static void SDHC_SetClock(uint32_t sysctl);


// initialize the SDHC Controller // initialize the SDHC Controller
// returns status of initialization(OK, nonInit, noCard, CardProtected) // returns status of initialization(OK, nonInit, noCard, CardProtected)
uint8_t SDHC_Init(void)
static uint8_t SDHC_Init(void)
{ {
int i;

// Enable clock to SDHC peripheral // Enable clock to SDHC peripheral
SIM_SCGC3 |= SIM_SCGC3_SDHC; SIM_SCGC3 |= SIM_SCGC3_SDHC;


SIM_SCGC6 |= SIM_SCGC6_DMAMUX; SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
SIM_SCGC7 |= SIM_SCGC7_DMA; SIM_SCGC7 |= SIM_SCGC7_DMA;


// Switch of MPU unit (maybe bug of silicon)
// Enable DMA access via MPU (not currently used)
MPU_CESR &= ~MPU_CESR_VLD_MASK; MPU_CESR &= ~MPU_CESR_VLD_MASK;


// De-init GPIO - to prevent unwanted clocks on bus // De-init GPIO - to prevent unwanted clocks on bus
SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN |
SDHC_IRQSTATEN_CRMSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; SDHC_IRQSTATEN_CRMSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;


/* 80 initial clocks */
SDHC_SYSCTL |= SDHC_SYSCTL_INITA;
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) { };
// initial clocks... SD spec says only 74 clocks are needed, but if Teensy rebooted
// while the card was in middle of an operation, thousands of clock cycles can be
// needed to get the card to complete a prior command and return to a usable state.
for (i=0; i < 500; i++) {
SDHC_SYSCTL |= SDHC_SYSCTL_INITA;
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) { };
}


// to do - check if this needed // to do - check if this needed
SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM;
} }


resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern
if (resR > 0) {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
}

if (resR == 0) {
if (resR == SDHC_RESULT_OK) {
if (SDHC_CMDRSP0 != 0x000001AA) { if (SDHC_CMDRSP0 != 0x000001AA) {
sdCardDesc.status = SDHC_STATUS_NOINIT; sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT; return SDHC_STATUS_NOINIT;
} }
sdCardDesc.highCapacity = 1; sdCardDesc.highCapacity = 1;
} else if (resR == SDHC_RESULT_NO_RESPONSE) {
// version 1 cards do not respond to CMD8
} else {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
} }


if (SDHC_ACMD41_SendOperationCond(0)) { if (SDHC_ACMD41_SendOperationCond(0)) {
// release the SDHC Controller signals // release the SDHC Controller signals
static void SDHC_ReleaseGPIO(void) static void SDHC_ReleaseGPIO(void)
{ {
PORTE_PCR0 = 0;
PORTE_PCR1 = 0;
PORTE_PCR2 = 0;
PORTE_PCR3 = 0;
PORTE_PCR4 = 0;
PORTE_PCR5 = 0;
PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */
PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */
PORTE_PCR2 = 0; /* SDHC.CLK */
PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */
PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */
PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */
} }





static void SDHC_SetClock(uint32_t sysctl) static void SDHC_SetClock(uint32_t sysctl)
{ {
uint32_t n, timeout; uint32_t n, timeout;

+ 56
- 19
utility/Sd2Card.cpp View File

} }
/** SPI send multiple bytes */ /** SPI send multiple bytes */
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define USE_TEENSY4_SPI
static void spiInit(uint8_t spiRate) {
switch (spiRate) {
// the top 2 speeds are set to 24 MHz, for the SD library defaults
case 0: settings = SPISettings(25200000, MSBFIRST, SPI_MODE0); break;
case 1: settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break;
case 2: settings = SPISettings(8000000, MSBFIRST, SPI_MODE0); break;
case 3: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
case 4: settings = SPISettings(3000000, MSBFIRST, SPI_MODE0); break;
case 5: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
default: settings = SPISettings(400000, MSBFIRST, SPI_MODE0);
}
SPI.begin();
}
static void spiSend(uint8_t b) {
SPI.transfer(b);
}
static uint8_t spiRec(void) {
return SPI.transfer(0xff);
}
static void spiRec(uint8_t* buf, size_t len) {
SPI.transfer(buf, len);
}
static void spiRecIgnore(size_t len) {
for (size_t i=0; i < len; i++)
SPI.transfer(0xff);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#else #else
// functions for hardware SPI // functions for hardware SPI
type_ = 0; 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();
unsigned int t0 = millis();
uint32_t arg; uint32_t arg;
digitalWrite(chipSelectPin_, HIGH); digitalWrite(chipSelectPin_, HIGH);
pinMode(chipSelectPin_, OUTPUT); pinMode(chipSelectPin_, OUTPUT);
digitalWrite(chipSelectPin_, HIGH); digitalWrite(chipSelectPin_, HIGH);
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI)
spiBegin(); spiBegin();
spiInit(6); spiInit(6);
#elif defined(USE_TEENSY4_SPI)
spiInit(6);
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
#else #else
// set pin modes // set pin modes
pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MISO_PIN, INPUT);
settings = SPISettings(250000, MSBFIRST, SPI_MODE0); settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
#endif #endif
#endif // not USE_TEENSY3_SPI #endif // not USE_TEENSY3_SPI
// must supply min of 74 clock cycles with CS high. // must supply min of 74 clock cycles with CS high.
#ifdef SPI_HAS_TRANSACTION #ifdef SPI_HAS_TRANSACTION
SPI.beginTransaction(settings); SPI.beginTransaction(settings);
#ifdef SPI_HAS_TRANSACTION #ifdef SPI_HAS_TRANSACTION
SPI.endTransaction(); SPI.endTransaction();
#endif #endif
chipSelectLow(); chipSelectLow();
// 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) {
unsigned int d = millis() - t0;
if (d > SD_INIT_TIMEOUT) {
goto fail; // SD_CARD_ERROR_CMD0 goto fail; // SD_CARD_ERROR_CMD0
} }
} }
} }
// 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) {
unsigned int d = millis() - t0;
if (d > SD_INIT_TIMEOUT) {
goto fail; // SD_CARD_ERROR_ACMD41 goto fail; // SD_CARD_ERROR_ACMD41
} }
} }
if (!waitStartBlock()) { if (!waitStartBlock()) {
goto fail; goto fail;
} }
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI) | defined(USE_TEENSY4_SPI)
spiRec(dst, 512); spiRec(dst, 512);
spiRecIgnore(2); spiRecIgnore(2);
#else // OPTIMIZE_HARDWARE_SPI #else // OPTIMIZE_HARDWARE_SPI
* false, is returned for an invalid value of \a sckRateID. * false, is returned for an invalid value of \a sckRateID.
*/ */
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI) || defined(USE_TEENSY4_SPI)
spiInit(sckRateID); spiInit(sckRateID);
return true; return true;
#else #else
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// wait for card to go not busy // wait for card to go not busy
uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
uint8_t Sd2Card::waitNotBusy(unsigned int timeoutMillis) {
unsigned int t0 = millis();
unsigned int d;
do { do {
if (spiRec() == 0XFF) return true; if (spiRec() == 0XFF) return true;
d = millis() - t0;
} }
while (((uint16_t)millis() - t0) < timeoutMillis);
while (d < timeoutMillis);
return false; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Wait for start block token */ /** Wait for start block token */
uint8_t Sd2Card::waitStartBlock(void) { uint8_t Sd2Card::waitStartBlock(void) {
uint16_t t0 = millis();
unsigned int t0 = millis();
while ((status_ = spiRec()) == 0XFF) { while ((status_ = spiRec()) == 0XFF) {
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
unsigned int d = millis() - t0;
if (d > SD_READ_TIMEOUT) {
return false; // SD_CARD_ERROR_READ_TIMEOUT return false; // SD_CARD_ERROR_READ_TIMEOUT
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks // send one block of data for write block or write multiple blocks
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
#ifdef OPTIMIZE_HARDWARE_SPI
#if defined(OPTIMIZE_HARDWARE_SPI) && !defined(USE_TEENSY4_SPI)
// send data - optimized loop // send data - optimized loop
SPDR = token; SPDR = token;
#else // OPTIMIZE_HARDWARE_SPI #else // OPTIMIZE_HARDWARE_SPI
spiSend(token); spiSend(token);
for (uint16_t i = 0; i < 512; i++) { for (uint16_t i = 0; i < 512; i++) {
spiSend(src[i]);
spiSend(src[i]);
} }
#endif // OPTIMIZE_HARDWARE_SPI #endif // OPTIMIZE_HARDWARE_SPI
spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc

+ 5
- 5
utility/Sd2Card.h View File

/** Protect block zero from write if nonzero */ /** Protect block zero from write if nonzero */
#define SD_PROTECT_BLOCK_ZERO 1 #define SD_PROTECT_BLOCK_ZERO 1
/** init timeout ms */ /** init timeout ms */
uint16_t const SD_INIT_TIMEOUT = 2000;
const unsigned int SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */ /** erase timeout ms */
uint16_t const SD_ERASE_TIMEOUT = 10000;
const unsigned int SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */ /** read timeout ms */
uint16_t const SD_READ_TIMEOUT = 300;
const unsigned int SD_READ_TIMEOUT = 300;
/** write time out ms */ /** write time out ms */
uint16_t const SD_WRITE_TIMEOUT = 600;
const unsigned int SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// card types // card types
/** Standard capacity V1 SD card */ /** Standard capacity V1 SD card */
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
void chipSelectHigh(void); void chipSelectHigh(void);
void chipSelectLow(void); void chipSelectLow(void);
uint8_t waitNotBusy(uint16_t timeoutMillis);
uint8_t waitNotBusy(unsigned int timeoutMillis);
uint8_t writeData(uint8_t token, const uint8_t* src); uint8_t writeData(uint8_t token, const uint8_t* src);
uint8_t waitStartBlock(void); uint8_t waitStartBlock(void);
uint8_t setSckRate(uint8_t sckRateID); uint8_t setSckRate(uint8_t sckRateID);

+ 1
- 1
utility/Sd2PinMap.h View File

#ifndef Sd2PinMap_h #ifndef Sd2PinMap_h
#define Sd2PinMap_h #define Sd2PinMap_h
#if defined(__arm__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__arm__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__)
#include <Arduino.h> #include <Arduino.h>

+ 2
- 2
utility/SdFat.h View File

uint8_t b; uint8_t b;
return read(&b, 1) == 1 ? b : -1; return read(&b, 1) == 1 ? b : -1;
} }
int16_t read(void* buf, uint16_t nbyte);
int32_t read(void* buf, size_t nbyte);
int8_t readDir(dir_t* dir); int8_t readDir(dir_t* dir);
static uint8_t remove(SdFile* dirFile, const char* fileName); static uint8_t remove(SdFile* dirFile, const char* fileName);
uint8_t remove(void); uint8_t remove(void);
/** \return SdVolume that contains this file. */ /** \return SdVolume that contains this file. */
SdVolume* volume(void) const {return vol_;} SdVolume* volume(void) const {return vol_;}
size_t write(uint8_t b); size_t write(uint8_t b);
size_t write(const void* buf, uint16_t nbyte);
size_t write(const void* buf, size_t nbyte);
size_t write(const char* str); size_t write(const char* str);
void write_P(PGM_P str); void write_P(PGM_P str);
void writeln_P(PGM_P str); void writeln_P(PGM_P str);

+ 5
- 5
utility/SdFile.cpp View File

* read() called before a file has been opened, corrupt file system * read() called before a file has been opened, corrupt file system
* or an I/O error occurred. * or an I/O error occurred.
*/ */
int16_t SdFile::read(void* buf, uint16_t nbyte) {
int32_t SdFile::read(void* buf, size_t nbyte) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf); uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
// error if not open or write only // error if not open or write only
if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
// amount left to read // amount left to read
uint16_t toRead = nbyte;
uint32_t toRead = nbyte;
while (toRead > 0) { while (toRead > 0) {
uint32_t block; // raw device block number uint32_t block; // raw device block number
uint16_t offset = curPosition_ & 0X1FF; // offset in block uint16_t offset = curPosition_ & 0X1FF; // offset in block
} }
block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
} }
uint16_t n = toRead;
int32_t n = toRead;
// amount to be read from current block // amount to be read from current block
if (n > (512 - offset)) n = 512 - offset; if (n > (512 - offset)) n = 512 - offset;
* 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.
* *
*/ */
size_t SdFile::write(const void* buf, uint16_t nbyte) {
size_t SdFile::write(const void* buf, size_t nbyte) {
// convert void* to uint8_t* - must be before goto statements // convert void* to uint8_t* - must be before goto statements
const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
// number of bytes left to write - must be before goto statements // number of bytes left to write - must be before goto statements
uint16_t nToWrite = nbyte;
size_t nToWrite = nbyte;
// error if not a normal file or is read-only // error if not a normal file or is read-only
if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn;

Loading…
Cancel
Save