Teensy 3.6, after Reset SD Card does not always initialize.

oric_dan

Well-known member
Sorry if this is a well-known issue, I did do a quick search on google.

For the past 2 weeks, I've been using the T3.6 in one of my projects. Basically, capturing images from an Arducam-Mini, and displaying on LCD, and also writing BMP and JPEG files to the SD card. The T3.6 is just great for this, as I am using 3 different SPI ports for the 3 peripherals [native SD card slot of course]. I was having very little luck with this lashup previously on the T3.1, due to SPI buss conflicts, although it works very well on regular Arduinos.

All in all, I am very happy, as the monster clock on the T3.6 does image-processing quickly, and the monster RAM in the T3.6 allows me to capture complete 320x240 RGB565 images to RAM.

In any case, the problem is as described in the title of this thread. Very often, when I reboot the T3.6 after uploading a sketch, the SD card will not initialize for the new run, and/or when I press Reset when the board is already powered-up. Therefore I have to power down the board, after which the SD Card always initializes properly. I am currently running the T3.6 at 240-MHz, but don't think that's the issue, as I've also seen the problem at 180-MHz. Also, I am using Teensyduino 1.32-beta2 over top Arduino IDE 1.6.13.

FWIW, I can remember also having this same problem with the SD Card on Arduinos, going back for 2-3 years.

I am using the regular example listfiles, Cardinfo, and ReadWrite sketches that come with Teensyduino, and nothing fancy, and am embedding them into my [rather large, 81KB Flash and 172KB RAM] program.
 
Last edited:
Sorry if this is a well-known issue, I did do a quick search on google.

For the past 2 weeks, I've been using the T3.6 in one of my projects. Basically, capturing images from an Arducam-Mini, and displaying on LCD, and also writing BMP and JPEG files to the SD card. The T3.6 is just great for this, as I am using 3 different SPI ports for the 3 peripherals [native SD card slot of course]. I was having very little luck with this lashup previously on the T3.1, due to SPI buss conflicts, although it works very well on regular Arduinos.

All in all, I am very happy, as the monster clock on the T3.6 does image-processing quickly, and the monster RAM in the T3.6 allows me to capture complete 320x240 RGB565 images to RAM.

In any case, the problem is as described in the title of this thread. Very often, when I reboot the T3.6 after uploading a sketch, the SD card will not initialize for the new run, and/or when I press Reset when the board is already powered-up. Therefore I have to power down the board, after which the SD Card always initializes properly. I am currently running the T3.6 at 240-MHz, but don't think that's the issue, as I've also seen the problem at 180-MHz. Also, I am using Teensyduino 1.32-beta2 over top Arduino IDE 1.6.13.

FWIW, I can remember also having this same problem with the SD Card on Arduinos, going back for 2-3 years.

I am using the regular example listfiles, Cardinfo, and ReadWrite sketches that come with Teensyduino, and nothing fancy, and am embedding them into my [rather large, 81KB Flash and 172KB RAM] program.

Have no solution to this, but realized myself the frequent need to power toggle teensy to allow uSD card access.
IMO, this must be related to leaving uSD card to strange state. If someone knows how to truly reset uSDcard via software, please let us know. Somehow, the 'official' way that is used by everyone (80 clock cycles, cmd0 etc.) seems not always sufficient to 'truly' reset uSDcard.

Edit: As you know Teensy has no Reset button, but only Program button. Pressing button without reloading program requires power toggle to restart program.
 
Last edited:
Good to see that someone else has the same issue, and bad to see that someone else has the same issue. So I guess I'm not alone.

>>>>
Somehow, the 'official' way that is used by everyone (80 clock cycles, cmd0 etc.) seems not always sufficient to 'truly' reset uSDcard.
>>>>

If this really did work, I should have thought it would have been incorporated into the libraries already.

>>>>
Edit: As you know Teensy has no Reset button, but only Program button. Pressing button without reloading program requires power toggle to restart program.
>>>>

Actually, I am using T3.6 here, so Reset is brought to the main header.

Also FWIW, I have my own custom layout pcbs for T3.x, and I use a somewhat 'novel' approach to mounting the modules. Rather than trying to use stiff R-A male headers, I solder 3" pieces of bare wirewrap wire to the underside pads and snake these through and solder to through-hole pads on the pcb. It does make a permanent installation. but that's ok with me. So, on the T3.1 modules, I also bring out the tiny Reset pad to the pcb pad.
 
>>>>
Somehow, the 'official' way that is used by everyone (80 clock cycles, cmd0 etc.) seems not always sufficient to 'truly' reset uSDcard.
>>>>

If this really did work, I should have thought it would have been incorporated into the libraries already.

It IS in the different libraries.
Somehow I have the feeling that Teensies are too fast, after trying to reset uSDCards.

Maybe one should try to rev. eng. the way 'big' computer handle the uSDCards.
people with good logic analysers and usD adapter cards step forward, please!
 
Do you know at what stage of initialization the failure happens?

I am writing my own code for the Teensy 3.6 outside of the Arduino environment and have not seen a failure to initialize. Perhaps I haven't done enough cycles to see it. How often does it happen?

One thing that I noticed is that the loop for ACMD41 in KinetisSDHC.c isn't quite right because it repeats a fixed number of times. (100,000) The SD specification is very clear that cards could take up to one second to initialize. I handle this by waiting 50ms before retrying ACMD41 and looping 40 times.

Now if the SD clock really were set to less than 400KHz then 100,000 loops would take more than a second but it is unclear what the clock frequency really is because of an error in that code.

For example, with F_CPU = 180MHz, the values used are divide by 32 for the prescaler and divide by 15 for the divider. Except that 32 (shifted right one bit) is fed to the divider macro resulting in the divider being set to divide by 1 rather than the expected 15. The prescaler gets set to 14 and since there is more than one bit set, its operation is not documented. Assume you get lucky and it uses the most significant bit set, or divide by 16. So instead of a SD clock set to 375KHz, it is 11MHz.

On the other hand, I normally see a good response to the second ACMD41 so initialization is usually pretty quick.
 
>>>>
It IS in the different libraries.
>>>>

And yet, Resets still hang.

>>>>
Do you know at what stage of initialization the failure happens?
>>>>

I have no idea, and been ignoring the problem and concentrating on getting my Arducam code to work. I started work on this project a year and 1/2 ago, and finally have a processor in the T3.6 that can handle all the work, and not have SPI buss conflicts or else run too slowly, so I've been hammering on that code the past 2 weeks.

The SD library is such a monster, I get depressed just looking at it, 20 source files, sheesh. I was hoping someone with knowledge had a fix. In truth, I've been working with Arduinos for about 3 years now, and I swear that I've spent much more time debugging 3rd party libraries as in developing my own project code, so I'm just bummed looking at that stuff. Even so, I've had to hack 2 libraries so far, in any case.
------------

On a positive note :), I would like to re-iterate how very much I am liking the Teensy 3.6, with so many cycles and so many SPI ports, so thanks again to Paul.
 
The SD library is such a monster, I get depressed just looking at it, 20 source files, sheesh. I was hoping someone with knowledge had a fix.
The part that handles initialization is in KinetisSDHC.c and isn't that big. At least fix the clock macro bug that I identified in another thread.

One thing I don't like about the initialization code is that it returns just one error code for all errors. I write mine to return a unique code so I can tell at which stage it failed. I have written SD(HC) code more than once and I need that help while getting it to work. Especially when I don't have gdb available.
 
Thanks, I'll track down your other posts. I was already starting to look at the init code in the Sd2Card.x files. Thanks again for the feedback.
 
Last edited:
Now if the SD clock really were set to less than 400KHz then 100,000 loops would take more than a second but it is unclear what the clock frequency really is because of an error in that code.

For example, with F_CPU = 180MHz, the values used are divide by 32 for the prescaler and divide by 15 for the divider. Except that 32 (shifted right one bit) is fed to the divider macro resulting in the divider being set to divide by 1 rather than the expected 15. The prescaler gets set to 14 and since there is more than one bit set, its operation is not documented. Assume you get lucky and it uses the most significant bit set, or divide by 16. So instead of a SD clock set to 375KHz, it is 11MHz.

The code I'm using (uSDFS) is using
Code:
// get dividers from requested baud rate 
uint32_t aux=F_CPU;
uint32_t ii=0,jj=1;
uint32_t baudrate=kbaudrate*1000;

while(aux/(16*(1<<ii))>baudrate) ii++;
while(aux/(jj*(1<<ii))>baudrate) jj++;

uint32_t minpresc=(1<<ii)>>1;
uint32_t mindiv=jj-1;

m_sdhc_baudrate=F_CPU/((1<<minpresc) * (mindiv+1));

// Change dividers
sysctl = SDHC_SYSCTL & 
			(~ (SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DVS_MASK));
SDHC_SYSCTL = sysctl | 
			(SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_SDCLKFS(minpresc) | SDHC_SYSCTL_DVS(mindiv));

so IMO it should set prescaler and divider correctly.
 
Yeah, it's probably the SD card getting into some state at the moment Teensy stops running the program.

I can try to work on improving the init code, but first I need a way to reproduce this problem. Can you help me out with that part? Does just reading a file, or just repetitively querying the card info put it into the unrecoverable state? Or does it only happen if you're writing files?

To work on this, first I need a program that has a high probability of getting the card stuck when it's stopped. Ideally such a program wouldn't need to talk to any other hardware. I could put time into crafting tests... but I'm really hoping you can do that part and post a test program here.
 
Hi Paul, as mentioned earlier, the problem occurrence is hit and miss. As usual, if it occurred all the time, it'd be much easier to track down. Basically, what happens is I will upload a new sketch to the T3.6, and usually do a directory listing as the first SD access. I do this before saving or reading files. This is when it hangs. Again, if I then power down the board, then it always comes up working the first access.

I am attaching the entire .ino file that I use for SD accesses. Basically, it just combines the listfiles, CardInfo, and ReadWrite example sketches from the SD library of Teensyduino. I only ever do a single SD card initialization, since trying to do so more than once crashes the program.
 

Attachments

  • cam_sd_122916.zip
    3.2 KB · Views: 199
I have something further for you, Paul. And this happens almost all the time, and at both 180 and 240 MHz.

My program is doing an enormous amount of work, capturing images to a 153 KB RAM buffer, doing various kinds of filtering and color conversions, and writing to the LCD, and at 6 frames/sec or so. What I am noticing is that, if I do "not" immediately initialize the SD card at bootup, but just start running my imaging routines, and then after a little while try to read the SD directory, it totally hangs. No recovery without power down.

OTOH, if I immediately initialize the SD card at bootup, then I can run my imaging routines for basically any period of time, and then SD card accesses go ok. I guess there could be some kind of RAM leakage, miswriting to buffers or whatever going on, eg bad pointers, but if that were the case, you'd think it wouldn't matter when you initialize the SD card.
 
I'm looking at this now. Trying to use the code from #11. Right away, there's no setup() or loop(), and "_date" is undefined... so I'm starting out with guesswork.
 
I adapted the SD library listfiles example. After reprogramming this a few times while running, it seems to reproduce the problem. Or a similar problem... unable to tell if it's the same, but for now I'm going to go with this and try to come up with a fix. It definitely gets the card into a state were only power cycling restores functionality. If you had posted a complete ready-to-run program, I would be using it instead for testing.

Code:
#include <SD.h>
#include <SPI.h>

void setup()
{
        Serial.begin(9600);
        while (!Serial) ; // wait

        Serial.print("Initializing SD card...");
        if (!SD.begin(BUILTIN_SDCARD)) {
                while (1) {
                        Serial.println("initialization failed!");
                        delay(500);
                }
        }
        Serial.println("initialization done.");
}

void loop()
{
        File root = SD.open("/");
        printDirectory(root, 0);
        Serial.println("done!");
        root.close();
}

void printDirectory(File dir, int numTabs) {
        while(true) {
                File entry =  dir.openNextFile();
                if (! entry) {
                        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();
        }
}
 
Oh yeah, date is just used to create automatic file names for storing images. I just append an image number, ie "_1".

char *_date = "70112"; //used as part of file names for storage.

That file I posted is embedded into a very large program. It needs my Arducam setup to run. The following shows my Menu, the SD routines are called from process_key(), which is in called inside loop(). When storing, I first build a Number using case 'N' for the filename.

As mentioned, it seems to work ok if I initialize the SD card immediately, but if I run the image capture code, &etc, for a while is when it hangs. The rest of the program runs bazillions of cycles.

You don't need to store a file, but just press 'd' for directory-read or 'f' for Fat read to hang. The SD routines in the file posted last time are **straight out of** the SD library examples, except for having only a single SD init call between them.


Code:
/**********************************************/
void display_menu( void )
{
  dbg.print("\n\nCommands:");
  dbg.print("\n-misc:     ?=menu,(i)nfo,dela(y)_loop. ");
  dbg.print("\n-Submenus:   ");
  dbg.print("\n--imaging: (i)plus ?,h,f,r,g,b, ");
  dbg.print("\n-Run:     (l)oop2lcd,(o)verlay,tectu(m), ");
  dbg.print("\n          show_b(u)ff,(g)rey,star(z), ");
  dbg.print("\n-LCD:     (c)ls,(y)test/bars. ");

  dbg.print("\n-SD:      (d,D)ir,(f)at, ");
  dbg.print("\n          read(t)extFile@Num,write(T)ext@Num, ");
  dbg.print("\n          read(b)mp@Num,write(B)mp@Num. ");
  dbg.print("\n-Jpeg:    (j)pg_fmt@Num,write(J)pg2sd@Num. ");
  dbg.print("\n-BMP:     show_(r)es,(R)es@Num. ");

  dbg.print("\n-Entry:   show (n)um,(a)ddr,(s)tring, ");
  dbg.print("\n          enter (N)um,(A)ddr,(S)tring. ");

  dbg.print("\n-Classes: (1..5)show_cls,(shft1..5)ena_cls, ");
  dbg.print("\n          (x)fer_cls2buff. ");
  dbg.print("\n--C,Swgt: (0)show,(shft0,9)assign5,2@Num,Addr, ");
  dbg.print("\n--thresh: (v,V)assign:4,1/3,2@Num,Addr, ");
  dbg.print("\n          (shft6)assign5@Num. ");

  dbg.print("\n-debug:   (w)dump. ");

  nl();  send_battery();
}

/*********************************************/
void process_key( void )
{
  int ch;

  ch=dbg.read();
  switch( ch ) {
    // Imaging:  
    case 'i':  imaging_key();    return;

//    case 'p':  togflag("Duplicate",&fDup);     break;
    case 'w':  togflag("Data-Dump",&fDump);    break;
    case 'm':  togflag("Tectal-Cells",&fTect); break;
    case 'u':  xfer_buff2lcd();   break;

    case 'y':  togflag("Delay",&fDly);  break;
    case 'z':  draw_stars();   break;
    case '1':  show_class(1);  break;
    case '2':  show_class(2);  break;
    case '3':  show_class(3);  break;
    case '4':  show_class(4);  break;
    case '5':  show_class(5);  break;
    case '0':  show_parms();   break;

    case '(':  assign_cs2(hNum,hAddr);  break;
    case ')':  assign_cs5(hNum,hAddr);  break;

    case 'v':  assign_var41(hNum,hAddr);   break;
    case 'V':  assign_var32(hNum,hAddr);   break;
    case '^':  assign_var5(hNum);          break;

    case '!':  togflag("C1",&fC1);  break;
    case '@':  togflag("C2",&fC2);  break;
    case '#':  togflag("C3",&fC3);  break;
    case '$':  togflag("C4",&fC4);  break;
    case '%':  togflag("C5",&fC5);  break;

//    case 'h':  togflag("HSV",&fHSV);       break;
    case 'o':  togflag("Overlay",&fStars); break;
    case 'g':  togflag("Grey",&fGrey);      break;
    case 'x':  togflag("Xfer-Cx2buff",&fXfer); break;

    case 'N':  build_number();      return;
    case 'A':  build_address();     return;
    case 'S':  build_string();      return;
    case 'n':  case 'a':  case 's':
               show_vars();          break;

    // camera:
    //case 'i':  disp_camInfo();       
    //           disp_CPUinfo();         break;
    case 'j':  set_jpegFmt(hNum);      break;
    case 'J':  capture_jpeg2SD(hNum);  break;

    case 'B':  //capture_bmp2SD(hNum);   break;
               write_buff2SD(hNum);      break;
    case 'b':  Playback_BMPfile(hNum); break; 
    case 'R':  set_bmpRes(hNum);       break;
    case 'r':  show_bmpRes();             break;

    case 'l':  //loop capture.
               togflag((char*)"LoopCapture",&fCapBMP);  
               if( fCapBMP ) setup_bmpCapture();
               /*if( _bmpMode == BMP)*/  take_pic_PIPE1();
               break;
    //case 'h':  togflag((char*)"hold",&fHold);  break;

    // LCD:
    //case 'y':  lcd_test(); colorbars(); break; 
    case 'c':  cls();        break;

    // SD Card:
    case 'T':  write_SDtextfile(hNum,samptext);
               break;
    case 't':  //read_SDtextfile(SDfile1);  break;
               read_TextFile( (int)hNum );  break;
    case 'D':  list_SDfiles();      break;
    case 'd':  list_SDfilesRoot();        
               show_sdFiles();      break;
    case 'f':  show_SDinfo();       break; //FAT.

    case '?':  display_menu();  break;
     default:  if( ch != 13) dbg.println("\n---> Bad Key ");
               break;
  }  
}

/************************************************/
void loop()
{ 
  if( dbg.available() > 0) { process_key(); }

  //if ( !fHold ) {
  if( fCapBMP ) {
    ////take_picture(BMP);  xfer_fifo2Lcd();  
    //if( false ) {  // _bmpMode != BMPCIF) {
    //  capture_BMP2lcd_PIPE();
    //}
    //else  

    capture_bmp2buff();
 //   if( fSft )  shift_HueInBuff();
    if( fGrey ) convert_buff2Grey();
    if( fHSV )  convert_buff2Hue();

    if( fWin )  window_color( hAddr<<8+hNum );

    if( fMedi ) histo_median();
    if( fLop ) smooth_buff2(2);  //smooth buffer colors 2x2.
    if( fDup ) duplicate_4x();
    if( fRep ) replacement_filter();
    if( fSim ) simplex_filter();

    if( fRed ) convert_buff2Red();
    if( fGrn ) convert_buff2Green();
    if( fBlu ) convert_buff2Blue();

    // compute Classes,overlay img[][] buffer.
    if( fStars ) {   
      build_classes();
      if( fTect ) draw_Tclasses();
      draw_classes();
      xfer_buff2lcd();
    }
    else {      //no overlay, just draw.
      xfer_buff2lcd();
    }
  }
  if( fDly ) delay(2000);
}

/* convert ASCII char inputs into decimal number,
*  terminates when a non-number char is encountered.
* output: builtup hNum.
***************************************************/
void build_number( void ) 
{
  int ch;

  hNum=0;
  do {
    if( dbg.available() > 0) {
      ch=dbg.read();
      if( (ch >= '0') && (ch <= '9') ) {
        hNum = 10*hNum + (ch-'0');
      }
    }
  } while( (ch >= '0') && (ch <= '9') );

  dbg.print("\n-Num=");  dbg.print(hNum); 
}
 
Please give this a try. It fixes the problem for my simple listfiles test. Does it also solve the problems you're seeing?

Edit: file removed, please use the file on message #18 below.
 
Last edited:
I just copied your code from #15 into Arduino, but it also doesn't compile. :(

Please give my fix from #16 a try with your application. It definitely is working well with the code from #14. Maybe it will fully solve your problem?
 
Actually, please give this copy a try. I found some cards occasionally need even more clock pulses to clear stale state. This one also fixes a bug with clock speed configuration.
 

Attachments

  • KinetisSDHC.c
    29.9 KB · Views: 313
It does not take 1,000s of clocks to get an SD card into a usable state. The only thing that takes that many clocks is a multi block read or write and those can be terminated at any time using CMD12.

What does need to happen is issuing sufficient clocks to return the command state machine in the SD card to where it is looking for a start bit. Depending on where operations were aborted in the process of sending a command that requires far fewer clocks.

A command packet is 48 bits and the normal response is also 48 bits. Worst case is an R2 response of 136 bits. So worst case would be to receive an R2 response. But how often do you read the CID and CSD registers? Once during initialization typically and never after that.

I have never used the Arduino environment before so my ability to debug the Teensy SDHC code is limited.

After managing to get the serial_print functions to work I added some code to try and find where the problem was. To my surprise, code to print the xfertyp of each SD command was never executed when the card failed to initialize.

It turns out that SDHC_Init() returned 2. This function performs various low level initialization of the MK66 and 2 is the value of SDHC_STATUS_NODISK. This would explain why the code I wrote doesn't have a problem since I don't bother with this check. I also see that the extra clocks occur before this check is made.

Reading the data sheet on the CINS bit of the present state register makes me think that this is not a good way to detect the presence of a card. 0 indicates no card, or more importantly here, power on reset. It does say that the signal is debounced but says nothing about how.

The CRM bit in the IRQSTAT register might be a better choice. But this is really kind of a pointless check. If no card is inserted the initialization will just die later on.
 
Paul, just an interim report. I've been using your new KinetisSDHC.c file, and so far not had any hangs, with running the T3.6 to 240-MHz. So we'll see how it goes the next couple of days.
 
Good, glad it's working... cause it's in the 1.35 release! :)

For future versions I'll explore CMD12. But just increasing the number of clocks at startup was a low-risk change to add right before a non-beta release. Sending stuff like CMD12 to a freshly powered up card before CMD0 or CMD1 makes me a bit nervous. Need to really spend some time on this....

I also want to figure out how to detect if a card supports 50 MHz mode and what commands need to be sent to turn its high speed driver circuits. Right now we're only using 25 MHz clock. I know several people confirmed some of their cards worked with faster clocks with WMXZ's code, but I'm reluctant to use 50 MHz without properly detecting this stuff and configuring the card as required by the SDIO spec.
 
For future versions I'll explore CMD12.

A waste of time since the problem is with the card detect debounce logic of the SDHC interface and has nothing to do with the card. Worse, the card detection doesn't work because DAT3 is pulled high. Even worse, the internal pull down resistors are too small a value to work reliably.

I also want to figure out how to detect if a card supports 50 MHz mode and what commands need to be sent to turn its high speed driver circuits. Right now we're only using 25 MHz clock. I know several people confirmed some of their cards worked with faster clocks with WMXZ's code, but I'm reluctant to use 50 MHz without properly detecting this stuff and configuring the card as required by the SDIO spec.

To switch to high speed mode you first check to see if it is supported using CMD6 with an argument of zero. If supported you then use CMD6 to switch. Driver strength seems to be more of a UHS mode sort of thing and I am running at 40MHZ with the default driver strength without any troubles.
 
@Clem, I wanted to thank you for your comments on this thread, but they are way past anything approximating my pay scale. But I'm sure Paul can use them.

Also, I wonder if Bill Greiman can make use of any of this info, especially my initial problem.
 
Teensy 3.6:
The problem still exists, the card does not always initialize - it hangs or crashes.

I'm initializing the card (after a long startup-delay), and loading one file, then a pause for a long time (minutes to hours). After a reset, sometimes, (softimes often, sometimes not -> not reproducable) the card does not init.

Code:
#include <SD.h>
.
.
.

void SDinit(void) {
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  SDinitialized = SD.begin(SDCHIPSELECT);
  if (!SDinitialized) {
    Serial.println("Card failed, or not present");  
  } else {
    Serial.println("OK");
  }  
}
In my case, neither "Card failed, or not present" nor "OK" is printed - just nothing.
 
Last edited:
Back
Top