Pages: [1]   Go Down
Author Topic: [SOLVED] Communicating with ILI9341 using new DUE SPI functions  (Read 1474 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dear All,

Many apologies if this is an awfully n00b question – I’ve only just started working with Arduinos and have come a cropper on my first project.

I am trying to communicate with a cheap ILI9431 board using SPI.  I can communicate with it fine using the old SPI functions, but whenever I use the ones for the DUE board, I break it.

Below is an example of the problem.  You can comment/uncomment the #defines for “FastSPI” and “FastDigital” to switch between the old and new functions.

It works fine with FastDigital defined or undefined, but will never work with the FastSPI (DUE functions) defined.

I’m guessing it’s a n00b mistake with pin set-ups or I’ve failed to see a delay requirement in the ILI9431 datasheet (though I’ve tried liberally scattering delays throughout my code trying dumb luck and ignorance as my guide  smiley).

If anyone has experience with DUE SPI and can offer some help, I’d be very grateful.

Many thanks.

Code:
/*  
    Arduino DUE attached to ILI9341 board (3.3v)                                                                                                                                                                                                                                  
*/

// *******************************************************
// Comment/Uncomment to test DUE SPI and Fast digitalWrite
// *******************************************************
#define FastDigital
#define FastSPI
// *******************************************************

// Connection to TFT
#define TFT_CS  10
#define TFT_LED 9
#define TFT_DC  8
#define TFT_RST 7

#include <SPI.h>

// Try to get more speed than from original digitalWrite function
inline void digitalWrite2(int pin, boolean dat)
{
if(dat) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
delayMicroseconds(2); // found this minimum delay was needed for code to work
}

// Send command to TFT
void sendCMD(uint8_t index)
{
// Set DC for command
#ifdef FastDigital
digitalWrite2(TFT_DC,LOW);
#else
digitalWrite(TFT_DC,LOW);
#endif

// Send index
#ifdef FastSPI
SPI.transfer(TFT_CS, index);
#else
digitalWrite(TFT_CS, LOW);
SPI.transfer(index);
   digitalWrite(TFT_CS, HIGH);
#endif

// Set DC back to data
#ifdef FastDigital
   digitalWrite2(TFT_DC, HIGH);
#else
   digitalWrite(TFT_DC, HIGH);
#endif
}

// Read TFT register & parameter
uint8_t readREG(uint8_t addr, uint8_t param)
{
uint8_t data=0;

sendCMD(0xD9);                                                  

#ifdef FastSPI
   SPI.transfer(TFT_CS, 0x10+param);
#else
   digitalWrite(TFT_CS, LOW);
   SPI.transfer(0x10+param);                                
   digitalWrite(TFT_CS, HIGH);
#endif

// Set DC for command
#ifdef FastDigital
   digitalWrite2(TFT_DC,LOW);
#else
   digitalWrite(TFT_DC,LOW);
#endif

// Transfer address and get data
#ifdef FastSPI
   SPI.transfer(TFT_CS, addr, SPI_CONTINUE);
   //delay(10);  // tried adding delay here but doesn't help
   data = SPI.transfer(TFT_CS, 0x00);
#else
   digitalWrite(TFT_CS, LOW);
   SPI.transfer(addr);
   data = SPI.transfer(0x00);
digitalWrite(TFT_CS, HIGH);
#endif

// Set DC back to data
#ifdef FastDigital
digitalWrite2(TFT_DC, HIGH);
#else
digitalWrite(TFT_DC, HIGH);
#endif

return data;
}

// Attempt reading the TFT's version - tries 5 times in case
// communications were not stable to start
uint32_t readID(uint32_t expected)
{
uint32_t lastID;

for (uint32_t tries=0; tries<5; tries++){
// Get three byte value from register D3 which holds the ID
lastID =          readREG(0xD3,1) << 16;
lastID = lastID | readREG(0xD3,2) << 8;
lastID = lastID | readREG(0xD3,3);

if (lastID==expected) return lastID;
}
return lastID;
}


void setup()
{
    uint32_t myID;

// Print the mode selected from un/commening the defines
#ifdef FastSPI
Serial.println("Running with fast SPI");
#else
Serial.println("Running with slow SPI");
#endif

#ifdef FastDigital
   Serial.println("Running with fast digitialWrite");
#else
   Serial.println("Running with slow digitalWrite");
#endif

// Setup pin directions
pinMode(TFT_CS,OUTPUT);
pinMode(TFT_DC,OUTPUT);
pinMode(TFT_LED,OUTPUT);
pinMode(TFT_RST,OUTPUT);
pinMode(13,OUTPUT);

// Output default values
digitalWrite(TFT_DC,LOW);
digitalWrite(TFT_LED,HIGH);
digitalWrite(TFT_CS, HIGH);

// Reset TFT
digitalWrite(TFT_RST,LOW);
delay(100);
digitalWrite(TFT_RST,HIGH);

// Initialise SPI
#ifdef FastSPI
SPI.begin(TFT_CS);
SPI.setClockDivider(21); // 4Mhz, same as default "slow" SPI
#else
SPI.begin();
    #endif

myID = readID(0x9341);  // the ID we're expecting from ILI9341
if (myID != 0x9341) {
// Print error
Serial.println("************");
Serial.print("Wrong TFT ID: expected 0x9341 but found 0x");
Serial.println(myID,HEX);
Serial.println("************");
} else {
// Print success
Serial.print("Success! TFT ID = 0x");
Serial.println(myID,HEX);
}

}

// Just blink the LED to prove it is alive
void loop()
{
digitalWrite2(13, HIGH);
delay(500);
digitalWrite2(13, LOW);
delay(500);
}

« Last Edit: December 07, 2013, 03:45:12 pm by daxj » Logged

Poole, Dorset, UK
Offline Offline
Edison Member
*
Karma: 52
Posts: 2395
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The big difference between the Uno (etc) and the Due wrt SPI is that the Due controls the CS for you. Look at the difference in the two SPI lib's.

Mark
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Mark.

I think I've accounted for that, though, I've left the CS unaffected when using the Due functions but have driven it low and high when testing it with the old code (only when #define FastSPI has been commented out)


For example, in my code I have sections like this:

#ifdef FastSPI
      SPI.transfer(TFT_CS, index);     // Using the Due SPI function without affecting CS
#else
      digitalWrite(TFT_CS, LOW);      // Drive CS low
      SPI.transfer(index);                 // Old school SPI function
           digitalWrite(TFT_CS, HIGH);     // Drive CS high
#endif

Cheers,

Dax
Logged

0
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12725
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have a problem here:

Code:
// Setup pin directions
pinMode(TFT_CS,OUTPUT);   // <------ here
pinMode(TFT_DC,OUTPUT);
pinMode(TFT_LED,OUTPUT);
pinMode(TFT_RST,OUTPUT);
pinMode(13,OUTPUT);

The TFT_CS pin is managed by the Due hardware exclusively - if you set it
also as an output GPIO pin as with the line pinMode(TFT_CS,OUTPUT)
then you have the SPI hardware actually fighting the GPIO hardware and
risk damaging the Due.  (put a 'scope on the CS line and you'll see it go from
3.3V down to 1.6V or so....)

This ought to be better documented as its not obvious, and its a real case where
you might be able to fry a Due without atttaching anything to the pins, since it
seems there are duplicate output drivers on some pins (rather than doing it properly
with a gate or selector).

With the Due you avoid setting pinMode for any SPI pin, just use the SPI library.

I believe the examples with the Due SPI library are broken (but happen to work
by accident).

[edit:  No, its more complicated than that - if you use just SPI.begin(), then
you seem to be OK with the pinMode declaration, but if you use SPI.begin (10), and
then SPI.transfer (10, ...) you get the behaviour whereby using pinMode is dangerous....

When pinMode clashes with the SPI hardware the current consumption jumps about 30mA,
so its a definitely two drivers fighting.  So far I haven't fried my Due, but its a worry
]
« Last Edit: December 07, 2013, 02:49:54 pm by MarkT » Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Very many thanks for your help with this, MarkT - you've solved it!

After removing the pinMode line that you've kindly identified, the code now works with either library.  I guess this means I was lucky and it didn't fry the board.

I'd agree that, given it's potential consequence, this potential error could do with being made a little more obvious in the library reference.  Surely I can't have been the only numpty to do this on their first project  smiley-red

It might be nice if the Arduino gurus could rewrite the SPI.begin(CS) function to ensure the CS pin is in the necessary HiZ from the GPIO driver.

Thanks again,

Dax
Logged

0
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12725
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Aha, a little more perusing things has discovered the true cause of the SPI CS
failing.

Arduino pin 4 is connected to both PA29 and PC26 (package pins 112, 137)
Arduino pin 10 is connected to both PA28 and PC29 (package pins 111, 102)
Arduino pin 52 is not connected to  PA30 (the SPI CS2) since that pin is not
present on the package at all.

Thus these outputs can indeed fight if pinMode is selected as output
(pin 4 maps to PC26 for non-SPI uses, pin 10 to PC29)

Arduino pin 52 cannot be used for SPI as far as I can tell.
Logged

[ I won't respond to messages, use the forum please ]

Pages: [1]   Go Up
Jump to: