Quellcode durchsuchen

Merge pull request #1 from PaulStoffregen/master

07_feb-2019
main
WMXZ-EU vor 5 Jahren
Ursprung
Commit
543cf825d0
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden
7 geänderte Dateien mit 116 neuen und 53 gelöschten Zeilen
  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 Datei anzeigen

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

+ 46
- 20
utility/KinetisSDHC.c Datei anzeigen

@@ -9,7 +9,8 @@
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)

#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
#ifndef MPU_CESR_VLD_MASK
@@ -29,6 +30,19 @@ enum {
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_NODISK 0x02 /* No medium in the drive */
#define SDHC_STATUS_PROTECT 0x04 /* Write protected */
@@ -112,9 +126,13 @@ enum {
// 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
#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_25MHZ SDHC_SYSCTL_DIVISOR(2, 5) // 24 MHz
#define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 40 MHz
@@ -214,6 +232,7 @@ static SD_CARD_DESCRIPTOR sdCardDesc;
* Private functions
******************************************************************************/

static uint8_t SDHC_Init(void);
static void SDHC_InitGPIO(void);
static void SDHC_ReleaseGPIO(void);
static void SDHC_SetClock(uint32_t sysctl);
@@ -245,8 +264,10 @@ static int SDHC_ACMD41_SendOperationCond(uint32_t cond);

// initialize the SDHC Controller
// 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
SIM_SCGC3 |= SIM_SCGC3_SDHC;

@@ -256,7 +277,7 @@ uint8_t SDHC_Init(void)
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
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;

// De-init GPIO - to prevent unwanted clocks on bus
@@ -290,9 +311,13 @@ uint8_t SDHC_Init(void)
SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN |
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
SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM;
@@ -339,17 +364,17 @@ uint8_t KinetisSDHC_InitCard(void)
}

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) {
sdCardDesc.status = SDHC_STATUS_NOINIT;
return SDHC_STATUS_NOINIT;
}
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)) {
@@ -540,15 +565,16 @@ static void SDHC_InitGPIO(void)
// release the SDHC Controller signals
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)
{
uint32_t n, timeout;

+ 56
- 19
utility/Sd2Card.cpp Datei anzeigen

@@ -143,8 +143,40 @@ static void spiSend(uint8_t b) {
}
/** 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
// functions for hardware SPI
@@ -224,16 +256,20 @@ uint8_t Sd2Card::SD_init(uint8_t sckRateID, uint8_t chipSelectPin) {
type_ = 0;
chipSelectPin_ = chipSelectPin;
// 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)millis();
unsigned int t0 = millis();
uint32_t arg;
digitalWrite(chipSelectPin_, HIGH);
pinMode(chipSelectPin_, OUTPUT);
digitalWrite(chipSelectPin_, HIGH);
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI)
spiBegin();
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
// set pin modes
pinMode(SPI_MISO_PIN, INPUT);
@@ -250,7 +286,6 @@ uint8_t Sd2Card::SD_init(uint8_t sckRateID, uint8_t chipSelectPin) {
settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
#endif
#endif // not USE_TEENSY3_SPI
// must supply min of 74 clock cycles with CS high.
#ifdef SPI_HAS_TRANSACTION
SPI.beginTransaction(settings);
@@ -259,12 +294,11 @@ uint8_t Sd2Card::SD_init(uint8_t sckRateID, uint8_t chipSelectPin) {
#ifdef SPI_HAS_TRANSACTION
SPI.endTransaction();
#endif
chipSelectLow();
// command to go idle in SPI mode
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
}
}
@@ -281,10 +315,10 @@ uint8_t Sd2Card::SD_init(uint8_t sckRateID, uint8_t chipSelectPin) {
}
// initialize card and send host supports SDHC if SD2
arg = (type_ == SD_CARD_TYPE_SD2) ? 0X40000000 : 0;
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
// 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
}
}
@@ -325,7 +359,7 @@ uint8_t Sd2Card::SD_readBlock(uint32_t block, uint8_t* dst)
if (!waitStartBlock()) {
goto fail;
}
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI) | defined(USE_TEENSY4_SPI)
spiRec(dst, 512);
spiRecIgnore(2);
#else // OPTIMIZE_HARDWARE_SPI
@@ -373,7 +407,7 @@ uint8_t Sd2Card::SD_readBlock(uint32_t block, uint8_t* dst)
* false, is returned for an invalid value of \a sckRateID.
*/
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
#ifdef USE_TEENSY3_SPI
#if defined(USE_TEENSY3_SPI) || defined(USE_TEENSY4_SPI)
spiInit(sckRateID);
return true;
#else
@@ -403,20 +437,23 @@ uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
}
//------------------------------------------------------------------------------
// 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 {
if (spiRec() == 0XFF) return true;
d = millis() - t0;
}
while (((uint16_t)millis() - t0) < timeoutMillis);
while (d < timeoutMillis);
return false;
}
//------------------------------------------------------------------------------
/** Wait for start block token */
uint8_t Sd2Card::waitStartBlock(void) {
uint16_t t0 = millis();
unsigned int t0 = millis();
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
}
}
@@ -468,7 +505,7 @@ uint8_t Sd2Card::SD_writeBlock(uint32_t blockNumber, const uint8_t* src) {
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
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
SPDR = token;
@@ -487,7 +524,7 @@ uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
#else // OPTIMIZE_HARDWARE_SPI
spiSend(token);
for (uint16_t i = 0; i < 512; i++) {
spiSend(src[i]);
spiSend(src[i]);
}
#endif // OPTIMIZE_HARDWARE_SPI
spiSend(0xff); // dummy crc

+ 5
- 5
utility/Sd2Card.h Datei anzeigen

@@ -58,13 +58,13 @@ uint8_t const SPI_SCK_PIN = SCK_PIN;
/** Protect block zero from write if nonzero */
#define SD_PROTECT_BLOCK_ZERO 1
/** init timeout ms */
uint16_t const SD_INIT_TIMEOUT = 2000;
const unsigned int SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */
uint16_t const SD_ERASE_TIMEOUT = 10000;
const unsigned int SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */
uint16_t const SD_READ_TIMEOUT = 300;
const unsigned int SD_READ_TIMEOUT = 300;
/** write time out ms */
uint16_t const SD_WRITE_TIMEOUT = 600;
const unsigned int SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
@@ -141,7 +141,7 @@ class Sd2Card {
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
void chipSelectHigh(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 waitStartBlock(void);
uint8_t setSckRate(uint8_t sckRateID);

+ 1
- 1
utility/Sd2PinMap.h Datei anzeigen

@@ -21,7 +21,7 @@
#ifndef 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>

+ 2
- 2
utility/SdFat.h Datei anzeigen

@@ -238,7 +238,7 @@ class SdFile : public Print {
uint8_t b;
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);
static uint8_t remove(SdFile* dirFile, const char* fileName);
uint8_t remove(void);
@@ -284,7 +284,7 @@ class SdFile : public Print {
/** \return SdVolume that contains this file. */
SdVolume* volume(void) const {return vol_;}
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);
void write_P(PGM_P str);
void writeln_P(PGM_P str);

+ 5
- 5
utility/SdFile.cpp Datei anzeigen

@@ -657,7 +657,7 @@ void SdFile::printTwoDigits(uint8_t v) {
* read() called before a file has been opened, corrupt file system
* 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);
// error if not open or write only
@@ -667,7 +667,7 @@ int16_t SdFile::read(void* buf, uint16_t nbyte) {
if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
// amount left to read
uint16_t toRead = nbyte;
uint32_t toRead = nbyte;
while (toRead > 0) {
uint32_t block; // raw device block number
uint16_t offset = curPosition_ & 0X1FF; // offset in block
@@ -687,7 +687,7 @@ int16_t SdFile::read(void* buf, uint16_t nbyte) {
}
block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
}
uint16_t n = toRead;
int32_t n = toRead;
// amount to be read from current block
if (n > (512 - offset)) n = 512 - offset;
@@ -1120,12 +1120,12 @@ uint8_t SdFile::truncate(uint32_t length) {
* 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
const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
// 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
if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn;

Laden…
Abbrechen
Speichern