Go Down

Topic: LCD + SD on SPI (Read 7974 times) previous topic - next topic

_frank_

Sep 02, 2013, 06:41 pm Last Edit: Sep 02, 2013, 08:35 pm by _frank_ Reason: 1
Hello,

I try to get Display and an SD-Card working on one SPI-bus (with 2 CS-Pins). The other  3 Pins (MOSI/MISO/SCLK) are connected to both.

If i add the code for the SD-Card, the Display stops working.

Any Idea?
Maybe the both SPI-Implementations disturbing each other.

Regards Frank

_frank_


nickgammon

You could bit-bang the LCD SPI.

Make sure that the relevant SS (slave select) lines are brought low at the right time. Only one at a time.

http://www.gammon.com.au/spi
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

_frank_

in my own class, i take care of that and disable the client after sending data:
Code: [Select]
  void send(uint8_t value, uint8_t command)
  {
    //Serial.println("send()");
    // take the SS pin low to select the chip:
    digitalWrite(slaveSelectPin,LOW);
   
//sending data...

    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
  }


i've looked in sd2card.h/cpp, but don't understand how they initialize the bus. maybe SPI-Speed, bitorder or datamode is incompatible to the display

kowalski


i've looked in sd2card.h/cpp, but don't understand how they initialize the bus. maybe SPI-Speed, bitorder or datamode is incompatible to the display


@_frank_

Yes, that is the problem (as I see it). Below is a snippet of the SD init code:
Code: [Select]

uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
  errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
  chipSelectPin_ = chipSelectPin;
  // 16-bit init start time allows over a minute
  uint16_t t0 = (uint16_t)millis();
  uint32_t arg;

  // set pin modes
  pinMode(chipSelectPin_, OUTPUT);
  chipSelectHigh();
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  pinMode(SPI_SCK_PIN, OUTPUT);

#ifndef SOFTWARE_SPI
  // 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);
#endif  // SOFTWARE_SPI
...
}

As you can see it uses the SPI hardware very different than your display. The "easy" way around this is to do as Nick said and use software SPI for one of them.

This shows one of the problems with the Arduino SPI implementation and how this ripples into libraries and basically makes it a single SPI device software interface. The current implementation is also very difficult to use with interrupts and threads (i.e. concurrent programming).

Cheers!

_frank_

Which options are different and which value (const)? Maybe i can set my values after access the sdcard.

SurferTim

What LCD are you using? A link to the datasheet might help.

majenko

SD cards do not usually play nicely with other devices on an SPI bus.  While they have an "SPI compatible" mode of operation that is not 100% true SPI.  There are times when the SD card requires SPI clocks with the CS pin deasserted, for example.  Also it doesn't always cleanly release the SPI bus when you want to use it for some other device.

It is recommended that if you wish to share the SPI bus between an SD card and any other device that you isolate the SD card from the rest of the bus via a tri-state buffer, like a 74HC245.

Also, sharing disparate devices on an SPI bus with the control structures as simple as the Arduino has them is troublesome at best.  If two devices require different data modes, or operate at different speeds, you will need to wrap each and every call to SPI.transfer() (or whatever method the library in question uses) with code to set the right mode, otherwise one device will, as you have seen, stop the other from working.

SurferTim

Quote
SD cards do not usually play nicely with other devices on an SPI bus.  While they have an "SPI compatible" mode of operation that is not 100% true SPI.  There are times when the SD card requires SPI clocks with the CS pin deasserted, for example.  Also it doesn't always cleanly release the SPI bus when you want to use it for some other device.

I do not agree. I use mine with my w5100 all the time, as does zoomkat and several others here. There are some SD shields and breakout boards that do not play well with other devices because they do not have a logic level converter, but that is not the fault of the SD card or library.

The SPI mode and bit order can be changed on the fly easily. I've helped many people on the forum with this. Here is the latest:
http://forum.arduino.cc/index.php?topic=185306.0

majenko


Quote
SD cards do not usually play nicely with other devices on an SPI bus.  While they have an "SPI compatible" mode of operation that is not 100% true SPI.  There are times when the SD card requires SPI clocks with the CS pin deasserted, for example.  Also it doesn't always cleanly release the SPI bus when you want to use it for some other device.

I do not agree. I use mine with my w5100 all the time, as does zoomkat and several others here. There are some SD shields and breakout boards that do not play well with other devices because they do not have a logic level converter, but that is not the fault of the SD card or library.

The SPI mode and bit order can be changed on the fly easily. I've helped many people on the forum with this. Here is the latest:
http://forum.arduino.cc/index.php?topic=185306.0


That logic level conversion acts as a crude form of buffer and helps to keep the SD separated from the rest of the bus.  Ideally for proper isolation and combined level shifting you'd use a proper dual supply buffer, like a 74LVC8T245.

As long as enough time is given between finishing an SD card transaction and the next SPI transaction with another device to give the SD card time to release the bus (the time required depends on the card, not the shield - some do it faster than others, and some are a right pain) then it is possible to get away with no buffering at all - but that impacts your maximum throughput rate of the SPI bus.

In general, on systems that run at 3.3v so don't need any level shifting, I tend to dedicate an SPI bus to the SD card and use a second bus for all other devices.  But then on the devices I use at 3.3v I have 4 SPI busses at my disposal anyway...

SurferTim

I don't agree with any of that either, except the part about the 3.3v Arduinos not needing a converter.


majenko


I don't agree with any of that either, except the part about the 3.3v Arduinos not needing a converter.

Well, I'm sorry you feel that way, I really am.  But this isn't about opinions, this is about cold hard facts.  The fact is that some cards, cheap ones especially, do not play nicely on shared busses.  It's not an opinion, it's a fact.  Better shields take this into account and incorporate buffering with their level translation.  Cheaper shields don't.

On the Arduino it's less of a problem anyway because it is too slow to matter.  The Arduino isn't capable of communicating at the full speed of an SD card, so by the time the next SPI transaction comes along the SD card has had a chance to settle anyway.

Oh, and the newer specifications for the SD one-bit interface specify that cards should be connected separately, even though the bus was envisaged to allow up to 30 cards to be ganged together.

SurferTim

I'm good with differing opinions. Now the test. If _frank_ posts a link to the device with a datasheet...

_frank_

#13
Sep 04, 2013, 12:51 pm Last Edit: Sep 04, 2013, 12:57 pm by _frank_ Reason: 1
with code of lcd and SD enabled, the SD-Card works correctly, but the display ist not showing anything. disabling the init-code of the SD-Card...and the display works

so it seems really that different SPI-Modes used...so my thought that i can set the mode of the device before using it in my code without building a separate SPI-Bus (more cables and Ports blocked)
but i cannot decode the Modes (SPI-Mode,Data-Mode) used for SD-Card from the code

Datasheet of display:
http://www.lcd-module.de/eng/pdf/doma/dip204-4e.pdf

SPI-Modes I'm using:
Code: [Select]
    SPI.setBitOrder(LSBFIRST);
    SPI.setDataMode(SPI_MODE3);
    SPI.setClockDivider(SPI_CLOCK_DIV64);

SurferTim

#14
Sep 04, 2013, 01:02 pm Last Edit: Sep 04, 2013, 01:05 pm by SurferTim Reason: 1
That is correct. Mode 3 and LSBFIRST for the LCD display. Mode 0 and MSBFIRST for the SD. I like this datasheet better. It has all the SPI timing stuff that I needed.
http://www.lcd-module.de/eng/pdf/zubehoer/ks0073.pdf

So to use both together, I suggest changing the mode and bit order before each LCD transfer, and changing it back when complete. I try to leave the SPI bus in default when finished with any SPI bus functions, which is MODE0 and MSBFIRST.

Code: [Select]
   // change to LCD settings
   SPI.setDataMode(SPI_MODE3);
   SPI.setBitOrder(LSBFIRST);

   // do your LCD stuff

   // change back to default (SD, w5100 etc) settings
   SPI.setDataMode(SPI_MODE0);
   SPI.setBitOrder(MSBFIRST);
 

edit: I forgot to mention that all SPI devices should be disabled (all SS pins HIGH) when changing the mode and bit order, or you will have problems.

Go Up