Go Down

Topic: how to increase SAMD SPI clock speed for my SPI TFT ? (Read 115 times) previous topic - next topic

dsyleixa

hello,
How to increase SAMD SPI clock speed for my SPI TFT ?
The Graphics output is too slow for my purposes.
(I have the 3.5" HX8357 Featherwing for Feather M4, Arduino IDE 1.8.8, library Adafruit_HX8357 )

using
SPI.beginTransaction(SPISettings(120000000, MSBFIRST, SPI_MODE0));
makes no difference for any clock speed I am paassing.

david_prentice

What MCU is used in the Feather ?

120000000 is 120MHz.   Some ARMs can do SPI @ F_CPU/2 which implies 240MHz.

Arduino Zero uses a 48MHz M0 SAMD21 which can only manage F_CPU / 4 i.e. 12MHz
Arduino Due uses a 84MHz M3 SAM3X which can do F_CPU / 2 i.e. 42MHz

I have run ILI9341 and ST7789 @ 42MHz.

I doubt if HX8357 can do 42MHz but it might.
I will give you a medal if it can handle 120MHz.

David.

dsyleixa

As stated: Feather M4, 120MHz.
But as also stated, either different value does not increase or change anything (1000, 2000, 4000, 15000, 20000, 30000, 40000, 60000, 120000) all graphic benchmarks show exactly the same results.

Quote
I doubt if HX8357 can do 42MHz but it might.
I will give you a medal if it can handle 120MHz.
Adafruit claimed it can handle that up to cpu clock, but again, slower or faster frq clock speeds don't change anything compared to defaults, using
SPI.beginTransaction(SPISettings(frq, MSBFIRST, SPI_MODE0));


Code: [Select]
// Adafruit Brickbench
// benchmark test for SoCs and MCUs
// PL: GCC,Arduino
// Autor: (C) dsyleixa 2013-2019
//
// change log:
// 2.2.G  excerpt: testing just TFT
// 2.2.   testing both 32fp and 64fp
// 2.1.1. 32bit fp tests vs. 64bit double (ARM/32bit cores, optional)
//        low-level bitRead/Write vs. digitalRead/Write (AVR cores, optional)
// 2.1 GPIO r/w
// 2.0 loop counts


#include <SPI.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_HX8357.h>
#include <Adafruit_STMPE610.h>


#ifdef ESP8266
   #define STMPE_CS 16
   #define TFT_CS   0
   #define TFT_DC   15
   #define SD_CS    2
 
#elif defined ESP32
   #define STMPE_CS 32
   #define TFT_CS   15
   #define TFT_DC   33
   #define SD_CS    14
 
#elif defined TEENSYDUINO
   #define TFT_DC   10
   #define TFT_CS   4
   #define STMPE_CS 3
   #define SD_CS    8
 
#elif defined ARDUINO_STM32_FEATHER
   #define TFT_DC   PB4
   #define TFT_CS   PA15
   #define STMPE_CS PC7
   #define SD_CS    PC5
 
#elif defined ARDUINO_FEATHER52
   #define STMPE_CS 30
   #define TFT_CS   13
   #define TFT_DC   11
   #define SD_CS    27

#elif  defined(ARDUINO_MAX32620FTHR) || defined(ARDUINO_MAX32630FTHR)
   #define TFT_DC   P5_4
   #define TFT_CS   P5_3
   #define STMPE_CS P3_3
   #define SD_CS    P3_2

// Something else!
#elif  defined (__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_FEATHER_M0) || defined (__AVR_ATmega328P__) || defined(ARDUINO_SAMD_ZERO) || defined(__SAMD51__)   
   #define STMPE_CS 6
   #define TFT_CS   9
   #define TFT_DC   10
   #define SD_CS    5

 // default
#else
   #define STMPE_CS 6
   #define TFT_CS   9
   #define TFT_DC   10
   #define SD_CS    5
#endif

#define TFT_RST -1

Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);



#define  TimerMS() millis()

unsigned long runtime[10];

#define tpin1  11  // GPIO test pins digitalWrite
#define tpin2  12  // GPIO test pins digitalWrite
#define tpin3  13  // GPIO test pins digitalRead


void TFTprint(char sbuf[], int16_t x, int16_t y) {
  tft.setCursor(x, y);
  tft.print(sbuf);
}

int a[500], b[500], c[500], t[500];


   
//--------------------------------------------
inline void displayValues() {

  char buf[120];
  tft.fillScreen(0x0000); // clrscr()

    sprintf (buf, "%3d %9ld  int_Add",    0, runtime[0]); TFTprint(buf, 0, 9);
    sprintf (buf, "%3d %9ld  int_Mult",   1, runtime[1]); TFTprint(buf, 0,18);
    sprintf (buf, "%3d %9ld  fp32_op",    2, runtime[2]); TFTprint(buf, 0,27);
    sprintf (buf, "%3d %9ld  fp64_op",    3, runtime[3]); TFTprint(buf, 0,36);
    sprintf (buf, "%3d %9ld  randomize",  4, runtime[4]); TFTprint(buf, 0,45);
    sprintf (buf, "%3d %9ld  matrx_algb", 5, runtime[5]); TFTprint(buf, 0,54);
    sprintf (buf, "%3d %9ld  arr_sort",   6, runtime[6]); TFTprint(buf, 0,63);
    sprintf (buf, "%3d %9ld  GPIO_togg",  7, runtime[7]); TFTprint(buf, 0,72);
    sprintf (buf, "%3d %9ld  Graphics",   8, runtime[8]); TFTprint(buf, 0,80);
}

//--------------------------------------------
int32_t test_TextOut(){
  int  y;
  char buf[120];
 
  for(y=0;y<10;++y) {   
    tft.fillScreen(0x0000); // clrscr()
    sprintf (buf, "%3d %9d  int_Add",    y, 1000);  TFTprint(buf, 0, 9);
    sprintf (buf, "%3d %9d  int_Mult",   0, 1010);  TFTprint(buf, 0,18);
    sprintf (buf, "%3d %9d  fp32_op",    0, 1032);  TFTprint(buf, 0,27);
    sprintf (buf, "%3d %9d  fp64_op",    0, 1064);  TFTprint(buf, 0,36);
    sprintf (buf, "%3d %9d  randomize",  0, 1040);  TFTprint(buf, 0,45);
    sprintf (buf, "%3d %9d  matrx_algb", 0, 1050);  TFTprint(buf, 0,54);
    sprintf (buf, "%3d %9d  GPIO_togg",  0, 1060);  TFTprint(buf, 0,63);
    sprintf (buf, "%3d %9d  Graphics",   0, 1070);  TFTprint(buf, 0,72);
    sprintf (buf, "%3d %9d  testing...", 0, 1080);  TFTprint(buf, 0,80);
  }
  return y;
}


//--------------------------------------------
int32_t test_graphics(){
  int y;
  char buf[120];
 
 
  for(y=0;y<10;++y) {
    tft.fillScreen(0x0000);
    sprintf (buf, "%3d", y);  TFTprint(buf, 0,80); // outcomment for downwards compatibility

    tft.drawCircle(50, 40, 10, 0xFFFF);
    tft.fillCircle(30, 24, 10, 0xFFFF);
    tft.drawLine(10, 10, 60, 60, 0xFFFF);
    tft.drawLine(50, 20, 90, 70, 0xFFFF);
    tft.drawRect(20, 20, 40, 40, 0xFFFF);
    tft.fillRect(65, 25, 20, 30, 0xFFFF);
    tft.drawCircle(70, 30, 15, 0xFFFF);

  }
  return y;
}


//--------------------------------------------
long test(){
 unsigned long time0, x, y;
  double s;
  char  buf[120];
  int   i;
  float f;

 

  Serial.println("start test");
  tft.println("start test");
  delay(10);

  // computational benchmark tests 0...7 skipped

  // lcd display text / graphs
  time0=TimerMS();
  s=test_TextOut();
  s=test_graphics();
  runtime[8]=TimerMS()-time0;
  sprintf (buf, "%3d %9ld  Graphics   ", 8, runtime[8]);
  Serial.println( buf);
  tft.println( buf);

  Serial.println();
 
  y = 0;
  for (x = 0; x < 9; ++x) {
      y += runtime[x];
  }
 
  displayValues();
  sprintf (buf, "runtime ges.:  %-9ld ", y);
  Serial.println( buf);   TFTprint(buf, 0,90);
 
  x=50000000.0/y;
  sprintf (buf, "benchmark:     %-9ld ", x);
  Serial.println( buf);   TFTprint(buf, 0,100);


  return 1;
}

//--------------------------------------------
void setup() {
 
  Serial.begin(115200);
  Serial.println("starting Serial()");
  while(!Serial);

  // Setup the LCD
  //tft.begin(HX8357D);
  tft.begin();
  SPI.beginTransaction(SPISettings(120000000, MSBFIRST, SPI_MODE0)); // <~~~~~~~~~~~~
  tft.setRotation(3);
  tft.fillScreen(0x0000);
  tft.setTextColor(0xFFFF); tft.setTextSize(1);
  Serial.println("tft started");

  pinMode(tpin1, OUTPUT);
  pinMode(tpin2, OUTPUT);
  pinMode(tpin3, INPUT_PULLUP);


  char  buf[120];
  test();
  sprintf (buf, "Ende Arduino brickbench");   
  Serial.println( buf);
  TFTprint(buf, 0, 110);
}

void loop() {

}

dsyleixa

So how to increase SAMD SPI clock speed for my SPI TFT correctly?

david_prentice

Your Feather M4 has a SAMD51 chip running at 120MHz.

The datasheet will tell you whether the SPI can be clocked at F_CPU/2 or F_CPU/4
F_CPU/4 is 30MHz which is as much as I would expect any TFT controller to handle.

You can set 30MHz in your SPI.beginTransaction() setting.
Whether your Core SPI will accept 30MHz is your job to find out.

And whether your Core SPI library is well written or not.
And whether your TFT library uses the SPI class wisely.

Look at Marek Buriak's ILI9341_Due library.    It is impressive.   Just using an 84MHz ARM with DMA.

I don't have a Feather M4.   I don't want to install "yet another" Core.  Especially if I don't have any suitable Targets.

Incidentally,   polled SPI can give a pretty good performance.    It all comes down to how successful the Core authors have been when attempting to cripple the SPI performance.

David.

ZinggJM

If you use the library Adafruit_HX8357 you need to pass the SPI speed as parameter of the begin(uint32_t freq = 0) method.

The trick with calling SPI.beginTransaction(SPISettings(120000000, MSBFIRST, SPI_MODE0)); just once works with some processors, but not with all, and not if the library itself uses SPI transactions.

To the best of my knowledge, without digging deeper.

Code: [Select]
void Adafruit_HX8357::begin(uint32_t freq) {

  // Older version of this library accepted a display type as the only

  // argument (HX8357D or HX8357B), but SPITFT (part of GFX lib) REQUIRES

  // the begin() function instead accept an SPI bitrate (or 0 for default),

  // so display type was moved to the constructor.  Examples will be

  // updated, but just in case there's old code around, we pull shenanigans

  // here...the values for HX8357D and HX8357B (0xD and 0xB, respectively)

  // would make for absurd SPI bitrates...so if we receive one of those

  // values, assume it's old code intending to pass the display type.

  // Override the displayType value that was set in the constructor with

  // the value passed here, and use the default SPI bitrate for platform.

  if(freq == HX8357D) {

    displayType = freq;

    freq        = 0; // Use default SPI frequency

  } else if(HX8357B) {

    displayType = freq;

    freq        = 0; // Use default SPI frequency

  }



  if(!freq) freq = SPI_DEFAULT_FREQ;

  initSPI(freq);

No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

dsyleixa

If you use the library Adafruit_HX8357 you need to pass the SPI speed as parameter of the begin(uint32_t freq = 0) method.

The trick with calling SPI.beginTransaction(SPISettings(120000000, MSBFIRST, SPI_MODE0)); just once works with some processors, but not with all, and not if the library itself uses SPI transactions.

To the best of my knowledge, without digging deeper.

Code: [Select]
void Adafruit_HX8357::begin(uint32_t freq) {

  // Older version of this library accepted a display type as the only

  // argument (HX8357D or HX8357B), but SPITFT (part of GFX lib) REQUIRES

  // the begin() function instead accept an SPI bitrate (or 0 for default),

  // so display type was moved to the constructor.  Examples will be

  // updated, but just in case there's old code around, we pull shenanigans

  // here...the values for HX8357D and HX8357B (0xD and 0xB, respectively)

  // would make for absurd SPI bitrates...so if we receive one of those

  // values, assume it's old code intending to pass the display type.

  // Override the displayType value that was set in the constructor with

  // the value passed here, and use the default SPI bitrate for platform.

  if(freq == HX8357D) {

    displayType = freq;

    freq        = 0; // Use default SPI frequency

  } else if(HX8357B) {

    displayType = freq;

    freq        = 0; // Use default SPI frequency

  }



  if(!freq) freq = SPI_DEFAULT_FREQ;

  initSPI(freq);


I tried that already, but that also don't work.
I had passed several values to tft.begin(), e.g.
(void), 1, 2, 3, 4, 10, 11, 12, 13, 20, 50, 100, 1000, 2000, 4000, 10000, 20000, 30000, 40000, 60000, 120000, 20000000, 30000000, 40000000,
and I also had patched the freq variant directly in Adafruit_HX8357.cpp
:
no changes to display output speed, all the same.

Interestingly, in some examples Adafruit passes
HX8357B (==11) or HX8357D(==13) to tft.begin() which also is not very elucidating, tbh -
nonetheless, it all stays all the same finally.

 
edit:
I also have updated the Arduino SAMD (1.6.21) and the Adafruit SAMD (1.4.1) cores:
still no changes to either method or value


so how to solve that riddle?
:?



ZinggJM

Then I would start bottom-up: write a simple SPI testprogram that continuously sends over SPI with different settings, and observe SPI SCK with a scope or logic analyzer.

Post the results in the Processors section and ask for help there, if you don't get different SPI speeds.
Else check e.g. Adafruit_SPITFT.
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

dsyleixa

Then I would start bottom-up: write a simple SPI testprogram that continuously sends over SPI with different settings, and observe SPI SCK with a scope or logic analyzer.

Post the results in the Processors section and ask for help there, if you don't get different SPI speeds.
Else check e.g. Adafruit_SPITFT.
I don't talk about home-brewed SPI programs - I don't ever do that at all, I just use libs which are ready to use.

After all, my TO question is just about how to fix that SPI issue for the SAMD and my SPI TFT.


Any concrete proposals by anybody?

ZinggJM

Yes, follow David's recommendation and try with a different library. But this may not be concrete enough.

I tried to help you; sorry for the disturbance. Bye.
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

dsyleixa

#10
May 11, 2019, 10:22 am Last Edit: May 11, 2019, 10:34 am by dsyleixa
Yes, follow David's recommendation and try with a different library. But this may not be concrete enough.

I tried to help you; sorry for the disturbance. Bye.
I need the Adafruit_HX8357 lib because I always also use the corresponding  Adafruit_GFX lib for all of my TFTs (ILI9341, OLEDs, ILI9225), providing also shapes and fonts and touch screen features, and the GFX lib itself has dependencies to the touch lib Adafruit_STMPE610.
So I'm afraid, switching to a different TFT lib would cause too many incompatibilities.
OTOH, my HX8357 is a Adafruit Featherwing shield, stacked especially to my Adafruit Feather M4 (SAMD51), and just this set has to be made faster by SPI TFT output.

That's why I want to fix that SPI issue just for my SAMD and my SPI TFT.

Go Up