Pages: [1]   Go Down
Author Topic: Nokia 5110 works until I add SD library (also SPI)  (Read 3896 times)
0 Members and 1 Guest are viewing this topic.
California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry for cross posting in multiple forums, but I wasn't getting any replies in the networking forum.

So I have my Nokia 5110 LCD working and the SD card shield working; I just can't seem to get the LCD working when I initialize the SD library.  I've already hacked the PCD8544 to allow me to define all the SPI pins to use to be the same SPI pins as the SD library (11-13 on my Uno), but something about the SD library is breaking the SPI bus for the 5110.  Note: It doesn't matter if the SD shield is connected or not.  The SD card seems to work just fine (I can write files).

If you're curious, my hacked version of the PCD8544 library is here: http://synfin.net/arduino/PCD8544/

Ideas?

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

#define SPI_CLK         13 /* SPI CLK */
#define SPI_MISO        12 /* SPI MISO */
#define SPI_MOSI        11 /* SPI MOSI */
#define SD_SELECT       10 /* SD Card SPI Select */
#define LCD_SELECT      9  /* LCD SPI Select */
#define LCD_DC          8  /* LCD data/command */
#define LCD_RESET       7  /* LCD Reset */


PCD8544 LCD;

void setup() {
    pinMode(LCD_SELECT, OUTPUT);
    pinMode(SD_SELECT, OUTPUT);

    Serial.begin(9600);

    Serial.println("Starting LCD");

    /* initialize LCD */
    LCD.begin_custpins(84, 48, SPI_CLK, SPI_MOSI, LCD_DC,
            LCD_RESET, LCD_SELECT);

    // don't talk to LCD while we init the SD
    digitalWrite(LCD_SELECT, HIGH);

    /* initialize SD Card on SPI Bus */
    if (!SD.begin(SD_SELECT)) {
        Serial.println("SD card initialize failed, or not present");
    } else {
        Serial.println("SD card initialize success!");
    }

    LCD.setCursor(0, 0);
    LCD.print("Started LCD!");
}

void loop() {
    delay(1000);
    LCD.println("LCD is running!");  // this does nothing when the SD library is initalized
}
Logged

Sweden
Offline Offline
Full Member
***
Karma: 11
Posts: 237
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do you ever the the LCD_SELECT pin back to LOW before writing to the LCD? Try this:
Code:
#include <PCD8544.h>
#include <SD.h>

#define SPI_CLK         13 /* SPI CLK */
#define SPI_MISO        12 /* SPI MISO */
#define SPI_MOSI        11 /* SPI MOSI */
#define SD_SELECT       10 /* SD Card SPI Select */
#define LCD_SELECT      9  /* LCD SPI Select */
#define LCD_DC          8  /* LCD data/command */
#define LCD_RESET       7  /* LCD Reset */


PCD8544 LCD;

void setup() {
    pinMode(LCD_SELECT, OUTPUT);
    pinMode(SD_SELECT, OUTPUT);

    Serial.begin(9600);

    Serial.println("Starting LCD");

    /* initialize LCD */
    LCD.begin_custpins(84, 48, SPI_CLK, SPI_MOSI, LCD_DC,
            LCD_RESET, LCD_SELECT);

    // don't talk to LCD while we init the SD
    digitalWrite(LCD_SELECT, HIGH);
    digitalWrite(SD_SELECT, LOW);

    /* initialize SD Card on SPI Bus */
    if (!SD.begin(SD_SELECT)) {
        Serial.println("SD card initialize failed, or not present");
    } else {
        Serial.println("SD card initialize success!");
    }
   
    digitalWrite(LCD_SELECT, LOW);
    digitalWrite(SD_SELECT, HIGH);

    LCD.setCursor(0, 0);
    LCD.print("Started LCD!");
    digitalWrite(LCD_SELECT, HIGH);
    digitalWrite(SD_SELECT, LOW);
}

void loop() {
    digitalWrite(LCD_SELECT, LOW);
    digitalWrite(SD_SELECT, HIGH);
    delay(1000);
    LCD.println("LCD is running!");  // this does nothing when the SD library is initalized
    digitalWrite(LCD_SELECT, HIGH);
    digitalWrite(SD_SELECT, LOW);
}

The only thing I've done is what I've added digitalWrites at some places to be sure what the SD_SELECT and the LCD_SELECT always are talked to if they should, but not if the other one is talked to.

JanD
Logged

Katowice POLAND
Offline Offline
Full Member
***
Karma: 2
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

what type of atmega are you using? if at8 or 168 Your problem is lack of RAM (sd card uses 512b and lcd also uses 512b)
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

JanD: that was good advice, but doesn't seem to help any. smiley-sad

zachwiej: It's an Arduino Uno board.  I believe they have 2K of RAM?
Logged

Sweden
Offline Offline
Full Member
***
Karma: 11
Posts: 237
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

At least I think the problem is in that.

JanD
Logged

Katowice POLAND
Offline Offline
Full Member
***
Karma: 2
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

yes. Do You use the same SS pin (device select) ?
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

For SS, I use pin 10 for the SD and pin 9 for the LCD.
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well I tracked this problem down to the SD library.  Specifically  Sd2Card::init() in Sd2Card.cpp.  I tried finding a specific line or lines, but the answer seems to be "most of them"- even those which appear at first glance to be talking to the SD card (the SD select pin is set low).

Anyone have any experience getting the SD library working with any other SPI device on the bus? Trying to figure out if this issue is specific to this LCD or a common problem with the SD library.
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, i'm pretty sure I understand what is going on now...

The PCD8544 library uses *software* SPI via shiftOut() while the SD library uses *hardware* SPI via spiSend() and spiRec().  I'm still digging through the Atmega spec sheet, but I'd have a hard time believing you can run both hardware and software SPI over the same pins at the same time.

Anyone know why all the PCD8544 libraries use software SPI?  Is there a problem with hardware SPI and this device?  I figure I could just port the code to use the SPI library... shouldn't be that hard.  As it is, I'm pretty low on pins for my project- I may have to rethink it if I can't share the SPI clock/miso/mosi pins.
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Happy to say that was it.  Fixing the PCD8544 library (the one from google code) was pretty easy. 

1. First change the #define's for the SPI pins in PCD8544.h to match the hardware SPI pins.  Make sure your SPI select pin is different from the SD card library (default 10).

2. Rewrite the PCD8544::send() method to use the hardware SPI method of sending data:
Code:
void PCD8544::send(unsigned char type, unsigned char data)
{
    digitalWrite(this->dc, type);
 
    digitalWrite(this->sce, LOW);
    SPDR = data;
    while (!(SPSR & (1 << SPIF)));
    digitalWrite(this->sce, HIGH);
}

3. Initialize the SD library before PCD8544 so it can configure the HW SPI bus.  It doesn't matter if the SD library initializes properly (ie: you don't need a SD card inserted).
Logged

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oops, shoulda done a full test I guesss.

Turns out there's a 4th step:

4. You may also need to edit SD/SD.cpp to lower the SPI speed since the LCD max speed is 4.0Mhz and the SD default speed is 1/2 clock rate, so for the Arduino Uno which has a default clock rate of 16Mhz you need to drop the SPI speed to 1/4 clock:

Code:
boolean SDClass::begin(uint8_t csPin) {
  /*

    Performs the initialisation required by the sdfatlib library.

    Return true if initialization succeeds, false otherwise.

   */
  return card.init(SPI_QUARTER_SPEED, csPin) &&
      volume.init(card) &&
      root.openRoot(volume);
}

I will say I'm kinda disappointed in many of the Arduino libraries... I know they're designed to be easy to use, but there are so many hard coded values (which pins to use, speeds, etc) it really makes it hard to consider them as "reusable" across multiple projects.  Not to mention for SPI related libraries, it would be nice to see a consistent use of hw vs. sw SPI to reduce the number of pins required without significant debugging & hacking.  Not to say I don't appreciate the effort the library authors have put in (after reading the data sheet for the LCD I'm amazed anyone can figure out how to program it), but I guess it would be nice if the Arduino community came up with a set of standards for how libraries should be configured that authors could follow.
Logged

Pages: [1]   Go Up
Jump to: