Go Down

Topic: Failed SD Initialisation Makes SPI Slow Speed (Read 1 time) previous topic - next topic

tack

Jan 23, 2013, 09:50 pm Last Edit: Jan 23, 2013, 09:54 pm by tack Reason: 1
This involves both an SD Card and TFT but it's the card that seems to cause an issue so I thought this was the best place to ask.

I've got a 128x160 7735R driven colour TFT display, compatible with the AdaFruit 7735 and I'm using that library. I'm also using the SD library for the onboard SD card slot.

The Adafruit library supports a 'soft SPI' mode and a hardware SPI. With both the TFT and SD connected as hardware SPI everything works fine if the SD Card initialises properly, i.e. a card in the slot. However, if there is no card in the slot then SD initialisation fails, as expected, but the subsequent test of the TFT is in slow speed, as if it's on soft SPI mode.

I'm suspecting that the SD library is somehow leaving the SPI bus set at a slower speed, after low speed initialisation attempt. SInce TFT is already initialised at that point (I'm outputting to the screen already), it doesn't seem to look at the SPI speed to see if it's still in the same mode.

I'm sure someone can confirm if I'm on the right track, but then how to resolve this? I've not included the functions as the text was too large for a post, but it's just the standard, unmodified, functions from the test script and they all work fine if there is a card in the slot, or no SD Card included in the sketch.

Code: [Select]
/***************************************************
  This is an example sketch for the Adafruit 1.8" SPI display.
  This library works with the Adafruit 1.8" TFT Breakout w/SD card
  ----> http://www.adafruit.com/products/358
  as well as Adafruit raw 1.8" TFT display
  ----> http://www.adafruit.com/products/618

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
****************************************************/

// You can use any (4 or) 5 pins
//#define tftSCL 7 // serial clock when driving tft non-spi
//#define tftSDA 6 // serial data when driving tft non spi
#define tftCS 10 // CS pin for tft
#define tftDC 8 // DC/AO pin for tft
#define tftRST 7 // reset for tft;  or can be connected to Arduino reset

#define sdCS 4 // CS pin for SD card
#define BUFFPIXEL 20 // how many pixels to buffer when reading in bitmaps from SD card

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <SD.h>

// Option 1: use any pins but a little slower
// Adafruit_ST7735 tft = Adafruit_ST7735(tftCS, tftDC, tftSDA, tftSCL, tftRST);

// Option 2: must use the hardware SPI pins - much faster and can share  SD and other devices
Adafruit_ST7735 tft = Adafruit_ST7735(tftCS, tftDC, tftRST);

float p = 3.1415926;

void setup(void) {
  Serial.begin(115200);
  Serial.println(F("Hello!"));

  // Our supplier changed the 1.8" display slightly after Jan 10, 2012
  // so that the alignment of the TFT had to be shifted by a few pixels
  // this just means the init code is slightly different. Check the
  // color of the tab to see which init code to try. If the display is
  // cut off or has extra 'random' pixels on the top & left, try the
  // other option!

  // If your TFT's plastic wrap has a Red Tab, use the following:
  tft.initR(INITR_REDTAB);   // initialize a ST7735R chip, red tab
  // If your TFT's plastic wrap has a Green Tab, use the following:
  //tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab
 
  tft.setTextWrap(false);
  tft.fillScreen(ST7735_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ST7735_RED);
  tft.setTextSize(1);
  tft.println(F("Welcome"));
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextSize(1);
  tft.println(F("This is the 128x160"));
  tft.println(F("Test Screen"));
  tft.setTextColor(ST7735_GREEN);
  tft.setTextSize(1);
  tft.println(F("Enjoy!"));
  tft.setTextColor(ST7735_BLUE);
  tft.setTextSize(1);
  tft.println(F("Mick"));

  tft.setTextSize(1);
  tft.println();
 
  Serial.print(F("Initializing SD card..."));
  tft.println(F("Initializing SD card..."));
  if (!SD.begin(sdCS)) {
    Serial.println(F("Failed!"));
    tft.println(F("Failed!"));
    pinMode(sdCS, OUTPUT);
    digitalWrite(sdCS, HIGH);
    //return;
  }
  Serial.println(F("OK!"));
  tft.println(F("OK!"));

 
  int sec = 5;
 
  while(sec != -1)
  {
    tft.print(sec);
    tft.println(F("..."));
    sec -= 1;
    delay(1000);
  }
 
  tft.println(F("GO!!!!!!"));
  delay(2000);
 
  //bmpDraw("parrot.bmp", 0, 0);
  //delay(4000);

  uint16_t time = millis();
  tft.fillScreen(ST7735_BLACK);
  time = millis() - time;

  Serial.println(time, DEC);
  delay(500);

  // large block of text
  tft.fillScreen(ST7735_BLACK);
  testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", ST7735_WHITE);
  delay(1000);

  // tft print function!
  tftPrintTest();
  delay(4000);

  // a single pixel
  tft.drawPixel(tft.width()/2, tft.height()/2, ST7735_GREEN);
  delay(500);

  // line draw test
  testlines(ST7735_YELLOW);
  delay(500);

  // optimized lines
  testfastlines(ST7735_RED, ST7735_BLUE);
  delay(500);

  testdrawrects(ST7735_GREEN);
  delay(500);

  testfillrects(ST7735_YELLOW, ST7735_MAGENTA);
  delay(500);

  tft.fillScreen(ST7735_BLACK);
  testfillcircles(10, ST7735_BLUE);
  testdrawcircles(10, ST7735_WHITE);
  delay(500);

  testroundrects();
  delay(500);

  testtriangles();
  delay(500);

  mediabuttons();
  delay(500);

  Serial.println("done");
  delay(1000);
}

void loop()
{
  int i = 0;
 
 
  while(i<3)
  {
    tft.invertDisplay(true);
    delay(500);
    tft.invertDisplay(false);
    delay(500);
    i += 1;
  }
 
   
  //bmpDraw("parrot.bmp", 0, 0);
   
  while(1); // loop here forever; i.e stop main loop
   
}

Jaakko_Fagerlund

Yup, known 'feature' of failed SD card initialization. One option is to change the library or make your own code to check for the fail.

tack

Thanks for the reply. That was pretty much what I was expecting.

I'll give SDFatLib a try as it looks like that fixes a few issues.

fat16lib

The problem is with the TFT library.  Any library for a device on the SPI bus must set the the speed and mode before each access.  Often devices that share the SPI bus have very different needs so a library can not assume its SPI settings will be preserved between accesses to the SPI bus.

SdFat sets the mode and speed before each SPI access.  SD cards require a very slow speed for initialization so a failure during initialization will result in a slow SPI speed.  The next device will be slow and may even use the wrong SPI mode unless it initializes the bus before each access.

ariel_ba

the problem has solution.
You need to edit line 325 in Sd2Card.cpp adding:
  setSckRate(sckRateID);// Esto agregue
previus the return command.
This put the serial clock at previus value.
Sorry for my very bad english...

fat16lib

Quote
the problem has solution.
You need to edit line 325 in Sd2Card.cpp adding:
  setSckRate(sckRateID);// Esto agregue


This is not a good solution.  There is no guarantee this will be the correct SPI mode and speed for another library.

The best solution is for each library that uses the SPI bus to have a function that selects its device.  This function should set the correct SPI mode, speed, bit order, and then set chip select low for its device.  This is the only possible way to avoid problems when sharing the SPI bus between a number of devices. 

ArthurRep

Do you have a suggestion what I can do to solve the problem. I use SPI only for the TFT/SD-card module.

fat16lib

Your TFT library is not setting the SPI speed.  SD initialization occurs at a very low SPI speed so here are two possible workarounds.

Try initializing the TFT after the SD.  Maybe the TFT library sets the SPI speed during initialization.

If the initiation order doesn't  solve the problem, set the SPI speed after the SD initialization fails.  See the documentation for SPI.setClockDivider() http://arduino.cc/en/Reference/SPISetClockDivider.

Try this just after the SD initialization fails :
Code: [Select]

  SPI.setClockDivider(SPI_CLOCK_DIV4);


The Arduino company has introduced a new SPI library in the 1.5.8 IDE beta that maintains SPI settings.  This will only help if old libraries like your TFT library are updated.

Go Up