Teensy LC SD Card SCK mapping broken

Status
Not open for further replies.

capricorn one

Well-known member
I've found a few posts that point to similar issues, but they look like they were addressed years ago and fixed.

The problem I'm having is trying to re-assign the SCK0 pin to 14 (default is 13). I've done this in the past without any issues, calling SPI.setSCK(14) before SD.begin(CS_PIN), however on the Teensy LC, no matter what I try, I always see the LED (pin 13) blinking trying to start the SD card.

Surprised this hasn't come up before, haven't been able to find it in the forum posts.

Thanks in advance!
 
Last edited:
Should include some more info I realized, I'm using the standard <SD.h> library with Teensyduino 1.45, Arduino 1.8.8.

I've read that the <SD.h> library doesn't work with SPI1, although that may be outdated now, either way, I'm trying to use SPI0, just change SCK to pin 14. I've used this same code and hardware with a Teensy 3.2 without issue.

If I run the CardInfo.ino example sketch, adding the line:
Code:
SPI.setSCK(14);         //Re-assign SPI SCK pin from default value
Before initializing the SD card, I see the led blinking every time I restart, meaning, the SD.h library is using pin 13 (default) not 14.
 
Last edited:
I have the same issue. This used to work with Teensy LC using Arduino 1.6.12 and Teensyduino 1.31. Something in between seem to have broken this functionality. Now with Arduino 1.8.11 and Teensyduino 1.50 it does not work anymore. I have started to debug what could be the problem.
Could you solve the problem?
 
@ rumar
I cannot replicate the issue on my side :confused:

Teensy LC
Windows 10
Arduino 1.8.10
Teensy Loader 1.49

Exemple code:
Code:
#include <SPI.h>  // include the SPI library:

// set the slaveSelectPin
const int slaveSelectPin = 10; // TEENSY LC, PIN 10 (PWM-CS0-TX2)
// set up the speed, mode and endianness of each device
SPISettings settingsA(2000000, MSBFIRST, SPI_MODE1);

void setup() {
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);


  // SPI.setSCK(13); // default 13
  SPI.setSCK(14);  //   re-assign to 14

  // initialize SPI:
  SPI.begin();
}

void loop() {
  // go through the six channels of the digital pot:
  for (int channel = 0; channel < 6; channel++) {
    // change the resistance on this channel from min to max:
    for (int level = 0; level < 255; level++) {
      digitalPotWrite(channel, level);
      delay(1);
    }
    // wait a second at the top:
    delay(10);
    // change the resistance on this channel from max to min:
    for (int level = 0; level < 255; level++) {
      digitalPotWrite(channel, 255 - level);
      delay(1);
    }
  }
}

int digitalPotWrite(int address, int value) {

  SPI.beginTransaction(settingsA);
  // take the SS pin low to select the chip:
  digitalWrite(slaveSelectPin, LOW);
  //  send in the address and value via SPI:
  SPI.transfer(address);
  SPI.transfer(value);
  // take the SS pin high to de-select the chip:
  digitalWrite(slaveSelectPin, HIGH);
  SPI.endTransaction();
}
 
Hi Chris

Thanks for looking into this. For me it always happened in combination with using the SD library. I will try your code on my side this evening and reply back
 
I have checked your Sketch on my side and it is working fine. I did not have any SPI device to test but using PIN 14 for SCK the led does not blink which indicates that the change is working. But in combination with the SD library it does not seem to work (see code below). Any idea?

Code:
/*
  SD card basic file example
 
 This example shows how to create and destroy an SD card file   
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11, pin 7 on Teensy with audio board
 ** MISO - pin 12
 ** CLK - pin 13, pin 14 on Teensy with audio board
 ** CS - pin 4, pin 10 on Teensy with audio board
 
 created   Nov 2010
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 This example code is in the public domain.
   
 */
#include <SD.h>
#include <SPI.h>

File root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy audio board: pin 10
// Teensy 3.5 & 3.6 on-board: BUILTIN_SDCARD
// Wiz820+SD board: pin 4
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
const int chipSelect = 4;

void setup()
{
  //UNCOMMENT THESE TWO LINES FOR TEENSY AUDIO BOARD:
  //SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14  
  
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  root = SD.open("/");
  
  printDirectory(root, 0);
  
  Serial.println("done!");
}

void loop()
{
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
   while(true) {
     
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       //Serial.println("**nomorefiles**");
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numTabs+1);
     } else {
       // files have sizes, directories do not
       Serial.print("\t\t");
       Serial.println(entry.size(), DEC);
     }
     entry.close();
   }
}
 
Any idea?
Well if you are not afraid of editing one file in SD library I got idea.

Edit file: Sd2Card.cpp
Location on MS WIN10: C:\Users\-- YOU --\ --- \arduino-1.8.10\hardware\teensy\avr\libraries\SD\utility
@ about line 253
My changes are marked in RED

Teensy LC hard-coded SPI CLK pin 14, untested code as I don't have SD Card connected to Teensy LC.

Code:
uint8_t Sd2Card::SD_init(uint8_t sckRateID, uint8_t chipSelectPin) {
  type_ = 0;
  chipSelectPin_ = chipSelectPin;
  // 16-bit init start time allows over a minute
  unsigned int t0 = millis();
  uint32_t arg;

  digitalWrite(chipSelectPin_, HIGH);
  pinMode(chipSelectPin_, OUTPUT);
  digitalWrite(chipSelectPin_, HIGH);

#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
  
[COLOR="#FF0000"]// ----- Teensy LC --- SET SCK PIN
#elif defined(KINETISL) && defined(__MKL26Z64__) // Teensy LC
#pragma message ( "Teensy LC hard-coded SPI CLK pin 14 ---> Sd2Card.cpp !!!!" )
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  // CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); // disable pin
  // CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); // enable pin
  SPI.setSCK(14);  // Set SCK pin 14
  pinMode(14, OUTPUT); // SCK pin
  settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
  SPI.begin();
// ^^^^^  Teensy LC ^^^ SCK pin SET[/COLOR]

#else
  // set pin modes
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  pinMode(SPI_SCK_PIN, OUTPUT);
  
  // SS must be in output mode even it is not chip select
  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
  // Enable SPI, Master, clock rate f_osc/128
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
  // clear double speed
  SPSR &= ~(1 << SPI2X);
#ifdef SPI_HAS_TRANSACTION
  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);
#endif
  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
#ifdef SPI_HAS_TRANSACTION
  SPI.endTransaction();
#endif
  chipSelectLow();
  // command to go idle in SPI mode
  while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
    unsigned int d = millis() - t0;
    if (d > SD_INIT_TIMEOUT) {
      goto fail; // SD_CARD_ERROR_CMD0
    }
  }
  // check SD version
  if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
    type_ = SD_CARD_TYPE_SD1;
  } else {
    // only need last byte of r7 response
    for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
    if (status_ != 0XAA) {
      goto fail; // SD_CARD_ERROR_CMD8
    }
    type_ = SD_CARD_TYPE_SD2;
  }
  // 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
    unsigned int d = millis() - t0;
    if (d > SD_INIT_TIMEOUT) {
      goto fail; // SD_CARD_ERROR_ACMD41
    }
  }
  // if SD2 read OCR register to check for SDHC card
  if (type_ == SD_CARD_TYPE_SD2) {
    if (cardCommand(CMD58, 0)) {
      goto fail; // SD_CARD_ERROR_CMD58
    }
    if ((spiRec() & 0XC0) == 0XC0) type_ = SD_CARD_TYPE_SDHC;
    // discard rest of ocr - contains allowed voltage range
    for (uint8_t i = 0; i < 3; i++) spiRec();
  }
  chipSelectHigh();
  return setSckRate(sckRateID);

fail:
  chipSelectHigh();
  return false;
}
 
Awesome, this is working fine for me, thanks a lot.

I was actually going through this file last night but had quite some trouble understanding it. It seems a bit odd to me that a subset of SPI library function is used but at other places there is direct access to the registers (or the teensy emulated versions).
Would you happen to know the reason for this. Is this maybe to keep it as close as possible to the original Arduino library?
I am tempted to change the SD library and use the SPI library directly.
 
Would you happen to know the reason for this. Is this maybe to keep it as close as possible to the original Arduino library?
My best guess:rolleyes: If it ain't broke don't fix it.
Because Teensy LC was not define it was basically using a AVR to ARM Teensy emulation, at least that's how I see it.
 
Just for other people who might run into the same issue as I did. I changed the SD library to always use the SPI library. This is actually already done for some other boards so there is already support there. For me it looks like one could simplify and clean up Sd2Card.cpp a bit. Anyway I have pushed my fix to https://github.com/rutmarti/SD and issued a pull request https://github.com/PaulStoffregen/SD/pull/22. A nice side effect of the change is that it increases read performance by a factor of 2 for the Teensy LC

Thanks again Chris for your support.
 
Status
Not open for further replies.
Back
Top