Adafruit_ILI9341 and SPI library issues on GIGA board

Note: This is related to the thread:

However, thought maybe better to not diverge that thread, to discuss issues with SPI and the Adafruit library.

As mentioned in the other thread, I am able to get their graphics test example to run on the GIGA, using the bitbang version of SPI. That is using the constructor:

#define TFT_DC 9
#define TFT_RST 8
#define TFT_CS 10
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_CLK 13
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

And it crawls along. Note: I added the while(!Serial)... stuff to get all of the serial ourput:

ILI9341 Test!
Display Power Mode: 0x94
MADCTL Mode: 0x48
Pixel Format: 0x5
Image Format: 0x80
Self Diagnostic: 0xC0
Benchmark                Time (microseconds)
Screen fill              2330140
Text                     89649
Lines                    871911
Horiz/Vert Lines         187525
Rectangles (outline)     119800
Rectangles (filled)      4859095
Circles (filled)         505338
Circles (outline)        382055
Triangles (outline)      203516
Triangles (filled)       1561697
Rounded rects (outline)  220790
Rounded rects (filled)   4846473
Done!

However, it does not work, when I try to use the Hardware SPI version of the constructor:


Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI1, TFT_CS, TFT_DC, TFT_RST);

Note: I am using the same pins, so you need to remember that pins 11-13 are SPI1 not SPI...
Will try later to move to SPI pins, to see if that makes any differnce.

However, with current setup, the code runs, and I see data on MOSI and SCK, but it looks like the DC and CS pins are not updating correctly...
Note: the speeds are slightly faster with the hardware SPI.

Screen fill              2119396
Text                     81499
Lines                    788704
Horiz/Vert Lines         171662
Rectangles (outline)     109247
Rectangles (filled)      4403595
Circles (filled)         462761
Circles (outline)        346543
Triangles (outline)      183219
Triangles (filled)       1412849
Rounded rects (outline)  200305
Rounded rects (filled)   4377912

But that is still SLOW!
Teensy Micromod: only changes were pin numbers and uses SPI:

Benchmark                Time (microseconds)
Screen fill              901141
Text                     34237
Lines                    330354
Horiz/Vert Lines         72938
Rectangles (outline)     46338
Rectangles (filled)      1870365
Circles (filled)         195340
Circles (outline)        144792
Triangles (outline)      76872
Triangles (filled)       597816
Rounded rects (outline)  84232
Rounded rects (filled)   1857554
Done!

First test: wanted to make sure that digitalWrites of the different pins like CS, DC, Reset worked when using SPI, so wrote quick and dirty test sketch:

#include <SPI.h>
void setup() {
  // put your setup code here, to run once:
  for(uint8_t pin = 6; pin <= 10; pin++) {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
    digitalWrite(pin, LOW);
    digitalWrite(pin, HIGH);
    digitalWrite(pin, LOW);
    digitalWrite(pin, HIGH);
  }    
  SPI1.begin();
  SPI1.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0));
  for(uint8_t pin = 6; pin <= 10; pin++) {
    digitalWrite(pin, LOW);
    digitalWrite(pin, HIGH);
    digitalWrite(pin, LOW);
    digitalWrite(pin, HIGH);
    digitalWrite(pin, LOW);
    digitalWrite(pin, HIGH);
  }    
}

uint16_t loop_count = 0;
void loop() {
  // put your main code here, to run repeatedly:
  uint8_t buffer[4];
  loop_count++;
  for(uint8_t pin = 6; pin <= 10; pin++) {
    digitalWrite(pin, LOW);
    SPI1.transfer(loop_count & 0xff);
    digitalWrite(pin, HIGH);
    digitalWrite(pin, LOW);
    SPI1.transfer16(loop_count);
    digitalWrite(pin, HIGH);
    for(uint8_t i=0; i<4; i++) buffer[i] = pin;
    digitalWrite(pin, LOW);
    SPI1.transfer(buffer, 4);
    digitalWrite(pin, HIGH);


    delayMicroseconds(20);
  }

  delay(100);

}

It looks like the different pins work with it:

But you can see how much time is lost between transfers.

For example looks like Transfer16 timing, like it is done with two Transfer calls. Transfer with buffer has slightly better timings between bytes. Sure wish Arduino supported, a non-destructive buffer transfer of a buffer!

Now back to investigating why the Adafruit library does not work with Hardware SPI transfers.

1 Like

I should mention, that speed differences is not due to the speed differences of the processors, but instead how well the SPI buss is being utilized.

Note: the Micromod version is still not great as the Adafruit library just does normal SPI.transfer calls. If instead we use a library that has been optimized to use the SPI sub-system of the boards, then it can go a lot faster. Example using my ILI9341_t3n running on a Teensy 3.2 board , running at 96mhz, The times are like:

Benchmark                Time (microseconds)
Screen fill              280930
Text                     17684
Lines                    73382
Horiz/Vert Lines         23020
Rectangles (outline)     14545
Rectangles (filled)      577210
Circles (filled)         96489
Circles (outline)        78434
Triangles (outline)      17841
Triangles (filled)       196565
Rounded rects (outline)  37110
Rounded rects (filled)   633600
2 Likes

Quick updates (more talking to self :wink: )

I was able to get the GraphicTest sketch to run using hardwareSPI, if I used the six pin connector.

Although first time I hooked it up, I swapped the MOSI and SCK pins. not sure if I screwed up (probable) or diagram on the complete pin list is off. Will double check later.

ILI9341 Test!
Adafruit_SPITFT::initSPI 2 - * Use digitalWrite *
	 *** Start the SPI object ***
Display Power Mode: 0xFF
MADCTL Mode: 0xFF
Pixel Format: 0xFF
Image Format: 0xFF
Self Diagnostic: 0xFF
Benchmark                Time (microseconds)
Screen fill              2135526
Text                     82598
Lines                    798827
Horiz/Vert Lines         173503
Rectangles (outline)     110110
Rectangles (filled)      4432575
Circles (filled)         466312
Circles (outline)        350212
Triangles (outline)      185437
Triangles (filled)       1422008
Rounded rects (outline)  202505
Rounded rects (filled)   4408075
Done!

As for SPI1 not working. First issue: Most if not all of the SPI TFT libraries by Adafruit use the Adafruit_spitft code that is in the Adafruit_GFX code base. And when you call begin in the library, it calls initSPI.

This code confirms the pointer passed in by comparing the pointer to known SPI objects. This relies on the SPI_INTERFACES_COUNT being set to how many SPI interfaces that board supports.
If this is not defined it assumes only one. Note: I believe this is also not defined in the UNO R4 code base either.

// SPI
#define SPI_INTERFACES_COUNT (2) // used by libraries to know how many objects to look for

#define PIN_SPI_MISO  (89u)
...

I have tried adding this to the Variant, so far still not working. WIll double check wiring again. and try again. ...

I believe the problem is with the Adafruit library itself. It uses a very slow SPI frequency if the board defs used in the precompiler checks.

If you change the default frequency in the library you should see a big difference. It's also worth checking the Adafruit GFX library as I cannot remember where I spotted it, but I recall that SPI1 was not implemented correctly either.

Thanks,

I believe by default the library is configured for SPI to run at 24Mhz. For some other boards there is configuration stuff in the ILI9341 library, is set higher. You can change, the SPI speed in the begin method.

I mentioned in the previous post that these boards did not define the count of SPI busses, which the libraries use to know which objects that might exist.

And I mentioned that I fixed that locally, but SPI1 still did not work...

Found the problem: Notice the two constructors:

Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst)
    : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, cs, dc, rst) {}

Adafruit_ILI9341::Adafruit_ILI9341(SPIClass *spiClass, int8_t dc, int8_t cs,
                                   int8_t rst)
    : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, spiClass, cs, dc,
                      rst) {}

Notice the order of the three pins:
WIthout SPI object: cs. dc. rst
WITH SPI object: dc, cs, rst

Changed the order around in sketch like:
Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI1, TFT_DC, TFT_CS, TFT_RST);

And now it is crawling :smiley:

Edit: - I passed in 40mhz to begin and it is running faster.

enchmark                Time (microseconds)
Screen fill              1810904
Text                     70808
Lines                    689704
Horiz/Vert Lines         146988
Rectangles (outline)     93694
Rectangles (filled)      3769201
Circles (filled)         397642
Circles (outline)        302077
Triangles (outline)      160134
Triangles (filled)       1207263
Rounded rects (outline)  173611
Rounded rects (filled)   3744490
Done!

But still the majority of the time, the SPI buss is not doing anything:

You also need to evaluate Adafruit_SPITFT.h and Adafruit_SPITFT.cpp (found in Adafruit_GFX library folder).

For example, in Adafruit_SPITFT.h there is some hardware config going on, which might not be set up correctly for the Giga:

#elif defined(__arm__)
#if defined(ARDUINO_ARCH_SAMD)
// Adafruit M0, M4
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
#define USE_FAST_PINIO   ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#elif defined(CORE_TEENSY)
// PJRC Teensy 4.x
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit                                // PJRC Teensy 3.x
#else
typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit
#endif
#define USE_FAST_PINIO   ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#else
// Arduino Due?
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
// USE_FAST_PINIO not available here (yet)...Due has a totally different
// GPIO register set and will require some changes elsewhere (e.g. in
// constructors especially).
#endif
#else                                      // !ARM
// Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet)
// but don't worry about it too much...the digitalWrite() implementation
// on these platforms is reasonably efficient and already RAM-resident,
// only gotcha then is no parallel connection support for now.
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
#endif                                     // end !ARM

// Another "oops" name -- this now also handles parallel DMA.
// If DMA is enabled, Arduino sketch MUST #include <Adafruit_ZeroDMA.h>
// Estimated RAM usage:
// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis,
// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes.

#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO))
#include <Adafruit_ZeroDMA.h>
#endif

Thanks,

But that may be beyond my pay grade :laughing:

You are right that so far the library does not know anything about these boards, so it defaults to using digitalWrites and a default SPI speed, which you can overwrite in the begin method.

That is, has anyone come up with something equivalent to digitalWriteFast?

Specifically, is there code that maps a pin number to port and pin(or mask).
I believe it is doable,
that you map pin->PinName,
with the PinName you can do:

    uint32_t port_index = STM_PORT(pin);
    GPIO_TypeDef *gpio = Set_GPIO_Clock(port_index);

And we can use the

#define STM_PORT(X) (((uint32_t)(X) >> 4) & 0xF)
#define STM_PIN(X)  ((uint32_t)(X) & 0xF)

Go get the pin number. - And we can use the (GPIOx_BSRR) register to set or clear
So probably can speed it up some... May have to experiment first with digitalWriteFast
And see how well it works.

As for the SPI speed, that is trickier. All of the code funnels down to calling
SPI.transfer(some_byte);

This includes SPI.transfer16(some_word), which internally calls SPI.transfer twice for each byte. Depending on SPI mode, it will either transfer the LSB first or the MSB first.

The problem with this form of transfer is the code does not return until the complete byte has been transferred and the result byte is ready in the appropriate register and then returned to the calling code, which then can issue another byte to transfer. In between these times, the SPI buss is twiddling its thumbs doing nothing.

To get around this, most SPI hardware is setup to either be double buffered and or supports a FIFO queue for RX and TX. I am pretty sure that this hardware does have a FIFO, but I don't think it is in use here and besides the use of the single byte transfers more or less defeats it as I mentioned. Or some use DMA. Not sure how hard it would be to do either of these approaches on this hardware and then applied to this library.

But for now I will probably punt on this part.

1 Like

Note: This is a WIP or more a PIP (Play In Progress)

But for the fun of it, I tried porting over my ILI9341_t3n library that is a sped up version for Teensy 3.x and 4.x boards. The t3n library also has some other things added over the years as well...

So far I have implemented the Frame buffer part of it. Part of it will be easy, which I will probably do soon, but part of it is harder... i.e. to do update screen using DMA, as I have not seen any examples of how use DMA yet...

The current WIP (or is it Mess in progress) is up at:
KurtE/ILI9341_GIGA_n: Converted from ILI9341_t3n for the Arduino GIGA (github.com)

So far I have only checked that I have a version of GraphicTest that runs.
I have also only tried it on the M7.

There are still things to complete like:
a) I am still using digatalWrite to handle CS and DC
b) 16 bit writes are still done by 2 8 bit writes
c) Frame buffer
d) I am not handling reading stuff back yet from the hardware, like registers and pixels
...

But is showing some promise:

ILI9341 Test!
After TFT Begin
Display Power Mode: 0xFF
MADCTL Mode: 0xFF
Pixel Format: 0xFF
Image Format: 0xFF
Self Diagnostic: 0xFF
Benchmark                Time (microseconds)
Screen fill              231302
Text                     12504
Lines                    91263
Horiz/Vert Lines         18957
Rectangles (outline)     12255
Rectangles (filled)      474946
Circles (filled)         81285
Circles (outline)        68938
Triangles (outline)      21186
Triangles (filled)       161751
Rounded rects (outline)  32292
Rounded rects (filled)   522072

As you can also see by the utilization of the SPI buss.

3 Likes

Just downloaded this and it really an order of magnitude faster !!!!

Updated DEMOSAUCE to not use frame buffer etc but looks like it crashed mdedOS got the red lights of doom

Also tried one of the font test but looks like have to do something with printf since giving me an error in the .h

error: 'class ILI9341_GIGA_n' has no member named 'printf_'; did you mean 'print'?
 # define printf    printf_
                    ^
d:\Users\Merli\Documents\Arduino\libraries\LibPrintf\src/LibPrintf.h:20:20: note: in definition of macro 'printf'
 # define printf    printf_

since I have printf defined from using libprintf.h. Will look at it later but now on to other things

1 Like

Pushed up changes to enable frame buffer

You should have write access...

1 Like

Ok that got it working kind of - framebuffer is still off -seems to update only a corner of the display?

But overnight did update the ILI9341_fonts library for use with the giga

To run some of the examples you will need the following libraries
LibPrintf
ElapsedMillis

both of which you can download via library manager

Now need more coffee

1 Like

Still sort of early... But have test sketch setup to maybe see where things are going screwy at times with updating the screen and the like:
test_ili9341_GIGA_n.ino (4.7 KB)

It basically does loops of fillScreens with different colors, it also does a set of FillRects where it pauses between each and another where it doe snot pause between each...

It toggles each pass of loop to use FB or not to use.

I use another pin for debug, which brackets each update, plus if you enter something in Serial monitor it will do a HIGH, LOW, HIGH, LOW, so maybe you can find it in the Logic Analyzer run.

It also outputs a character or two to Serial1, at the start of the frames, again as hint to find what you are looking at:

This frame had a problems:

Zooming in, I see:


Which I see the frame buffer was on and it was doing X...

Now to debug

I am having some better luck slowing down the speed to ask for 20mhz instead of 30...

I also Updated the above sketch to run on either M4 or M7

Now on M4:

Note; The Serial1 output, I asked for 1mhz and it output at 640K. Believe probably same or related issue as the micros() 25mhz vs 16mhz clock issue...

It is still utilizing the SPI buss pretty well.

I can still improve on some of the larger gaps which have to do when changing the DC pin state as it is still using digitalWrite.

2 Likes

Still trying to debug some of the SPI timing issues. On why sometimes it takes a lot longer and things time out.

I am experimenting with changing a count down loop to instead check delta times.
For example could use the elapsedMicros() class (Teensy code, that I see Paul added to library manager - elapsedMillis).

Or can do it without the class. Was curious on these boards how much time is taken to call micros() or millis(), so did a quick and dirty sketch.

#include <GIGA_digitalWriteFast.h>

void setup() {
  pinMode(3, OUTPUT);
}

void loop() {
  uint32_t t __attribute__((unused));
  digitalWriteFast(3, HIGH);
  digitalWriteFast(3, LOW);
  digitalWriteFast(3, HIGH);
  digitalWriteFast(3, LOW);
  digitalWriteFast(3, HIGH);
  digitalWriteFast(3, LOW);
  digitalWriteFast(3, HIGH);
  digitalWriteFast(3, LOW);
  delayMicroseconds(2);

  digitalWriteFast(3, HIGH); t = micros();
  digitalWriteFast(3, LOW); t = micros();
  digitalWriteFast(3, HIGH); t = micros();
  digitalWriteFast(3, LOW); t = micros();
  digitalWriteFast(3, HIGH); t = micros();
  digitalWriteFast(3, LOW); t = micros();
  digitalWriteFast(3, HIGH); t = micros();
  digitalWriteFast(3, LOW); t = micros();
  delayMicroseconds(2);

  digitalWriteFast(3, HIGH); t = millis();
  digitalWriteFast(3, LOW); t = millis();
  digitalWriteFast(3, HIGH); t = millis();
  digitalWriteFast(3, LOW); t = millis();
  digitalWriteFast(3, HIGH); t = millis();
  digitalWriteFast(3, LOW); t = millis();
  digitalWriteFast(3, HIGH); t = millis();
  digitalWriteFast(3, LOW); t = millis();
  delayMicroseconds(2);

  digitalWrite(3, HIGH);
  digitalWrite(3, LOW);
  digitalWrite(3, HIGH);
  digitalWrite(3, LOW);
  digitalWrite(3, HIGH);
  digitalWrite(3, LOW);
  digitalWrite(3, HIGH);
  digitalWrite(3, LOW);

  delay(50);
}

Obviously doing more than just reading a register or global variable...

1 Like

They actually uses Mbed timers:

unsigned long millis()
{
  return duration_cast<milliseconds>(lowPowerTimer.elapsed_time()).count();
}

unsigned long micros() {
  return timer.elapsed_time().count();
}

And:

microseconds TimerBase::elapsed_time() const
{
    CriticalSectionLock lock;
    return _time + slicetime();
}

microseconds TimerBase::slicetime() const
{
    CriticalSectionLock lock;
    microseconds ret = 0us;
    if (_running) {
        ret = _ticker_data.now() - _start;
    }
    return ret;
}

Currently I would also not trust millis() as well as it is incorrect for both the M7 and M4!

You can fix this by changing in wiring.cpp

#if DEVICE_LPTICKER

to

#if DEVICE_LPTICKER_NO_THANKS

3 Likes

Now that we have USBHostGamepad operational that supports DS4 controllers decided to port over the Pacman for Arduino Due Sketch using @KurtE's updated ILI9341_GIGA_n library.

Right now it resides in my fork of @KurtE's GIGA_USBHostMbed5_devices repository.

Graphics work as well as input from the Voyee DS4 clone. Unfortunately screen FPS is extremely slow even though running at 50Mhz (anything over this seems to give me the red lights of doom),

Trying to figure out where to go from here.

1 Like

Trying to debug why the updates are slow compared to other boards I have used.

So I put together a small test sketch that just uses the keypadloop code from pacman embededed in the graphicstest sketch using the ILI9341_GIGA_n library.

//Library for Gamepad
#define USBHOST_OTHER
#include <LibPrintf.h>
#include <Arduino_USBHostMbed5.h>
#include "USBHostGamepadDevice.h"

USBHostGamepad joystick1;

/**********************************************************/
#include "SPI.h"
#include "ILI9341_GIGA_n.h"
// *************** Change to your Pin numbers ***************
#define TFT_DC 9
#define TFT_RST 8
#define TFT_CS 10

#define USE_FRAME_BUFFER 1

ILI9341_GIGA_n tft(&SPI1, TFT_CS, TFT_DC, TFT_RST);
/********************************************************/

uint32_t buttons = 0;
uint32_t buttons_prev = 0;
uint8_t ltv, rtv;
uint32_t button_time = 0;

boolean but_START = false;    //38  //8, 168 or share////100
boolean but_SELECT = false;   //40  //1 , 328 or options///200
boolean but_A = false;        //44 //32768 sqr, 262152///1
boolean but_B = false;        //42  //8192 circ, /// 4
boolean but_UP = false;       //52 //16, 0  ///10000
boolean but_DOWN = false;     //50  //64, 4 /////40000
boolean but_LEFT = false;     //48 //128, 6 /////80000
boolean but_RIGHT = false;    //46  //32, 2 /////20000

void ClearKeys() {
  but_START = false;
  but_SELECT = false;
  but_A = false;
  but_B = false;
  but_UP = false;
  but_DOWN = false;
  but_LEFT = false;
  but_RIGHT = false;
}

void KeyPadLoop() {

  if (joystick1.available()) {
    buttons = joystick1.getButtons();

  //Serial.println(buttons);
  switch (joystick1.gamepadType()) {
      case USBHostGamepad::UNKNOWN:
      case USBHostGamepad::PS4:
      {
        if (buttons == 256 ) {
          ClearKeys();   //else but_START=false;
          but_START = true;
          delay(300);
        }
        if (buttons == 512 ) {
          ClearKeys();
          but_SELECT = true;
          delay(300);
        }  else but_SELECT = false;
        if (buttons == 1 ) {
          ClearKeys();
          but_A = true;
        }  else but_A = false;
        if (buttons == 4) {
          ClearKeys();
          but_B = true;
        }  else but_B = false;
        if (buttons == 65536) {
          ClearKeys();   //else but_UP=false;
          but_UP = true;
        }
        if (buttons == 262144) {
          ClearKeys();   //else but_DOWN=false;
          but_DOWN = true;
        }
        if (buttons == 524288) {
          ClearKeys();   // else but_LEFT=false;
          but_LEFT = true;
        }
        if (buttons == 131072) {
          ClearKeys();   //else but_RIGHT=false;
          but_RIGHT = true;
        }
      }
        break;
      case USBHostGamepad::NES:
      {
      if (buttons == 0x200000 ) {
          ClearKeys();   //else but_START=false;
          but_START = true;
          delay(300);
        }
        if (buttons == 0x100000 ) {
          ClearKeys();
          but_SELECT = true;
          delay(300);
        }  else but_SELECT = false;
        if (buttons == 0x200 ) {
          ClearKeys();
          but_A = true;
        }  else but_A = false;
        if (buttons == 0x400) {
          ClearKeys();
          but_B = true;
        }  else but_B = false;
        if (buttons == 0x01) {
          ClearKeys();   //else but_UP=false;
          but_UP = true;
        }
        if (buttons == 0x04) {
          ClearKeys();   //else but_DOWN=false;
          but_DOWN = true;
        }
        if (buttons == 0x08) {
          ClearKeys();   // else but_LEFT=false;
          but_LEFT = true;
        }
        if (buttons == 0x02) {
          ClearKeys();   //else but_RIGHT=false;
          but_RIGHT = true;
        }
      }
        break;
      default:
        break;
    }
  }
  yield();
}



void setup() {

  Serial.begin(115200);
  while (!Serial && millis() < 5000) {}

  Serial.println("Starting PacMan...");

  // Enable the USBHost
  pinMode(PA_15, OUTPUT);
  digitalWrite(PA_15, HIGH);
  delay(500);
  
  while (!joystick1.connect()) {
    Serial.println("No gamepad connected");
    delay(5000);
  }

  Serial.println("Joystick connected:");

  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");

  Serial.println(F("Benchmark                Time (microseconds)"));

  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(200);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(600);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(200);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(200);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(200);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(200);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(200);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(200);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(200);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(200);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
#if USE_FRAME_BUFFER
  WaitForUserInput();

  Serial.print(F("Rectangles (filled) FB     "));
  Serial.println(testFilledRectsFB(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(200);

  WaitForUserInput();

  Serial.print(F("Rounded rects (filled) FB   "));
  Serial.println(testFilledRoundRectsFB());
  delay(200);
  tft.useFrameBuffer(0);  // turn back off

  WaitForUserInput();
#endif

}

void loop() {

  for (uint8_t rotation = 0; rotation < 4; rotation++) {
    button_time = micros();
    KeyPadLoop();
    printf("button_time: %d\n", micros() - button_time);    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}


void WaitForUserInput() {
  if (Serial) {
    Serial.println("Hit key to continue");
    while (Serial.read() == -1) ;
    while (Serial.read() != -1) ;
    Serial.println(F("Done!"));
  }
}


unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  tft.fillScreen(ILI9341_RED);
  tft.fillScreen(ILI9341_GREEN);
  tft.fillScreen(ILI9341_BLUE);
  tft.fillScreen(ILI9341_BLACK);
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(ILI9341_BLACK);

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);

  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (y = 0; y < h; y += 5) tft.drawFastHLine(0, y, w, color1);
  for (x = 0; x < w; x += 5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for (i = 2; i < n; i += 6) {
    i2 = i / 2;
    tft.drawRect(cx - i2, cy - i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height()) - 1;
  for (i = n; i > 0; i -= 6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx - i2, cy - i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx - i2, cy - i2, i, i, color2);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (x = radius; x < w; x += r2) {
    for (y = radius; y < h; y += r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                      w = tft.width()  + radius,
                      h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for (x = 0; x < w; x += r2) {
    for (y = 0; y < h; y += r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for (i = 0; i < n; i += 5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(0, 0, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (i = min(cx, cy); i > 10; i -= 5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
                     tft.color565(0, i, i));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
                     tft.color565(i, i, 0));
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height()) - 1;
  start = micros();
  for (i = 0; i < w; i += 6) {
    i2 = i / 2;
    tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (i = min(tft.width(), tft.height()) - 1; i > 20; i -= 6) {
    i2 = i / 2;
    tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, i, 0));
  }

  return micros() - start;
}

#if USE_FRAME_BUFFER
unsigned long testFilledRectsFB(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.useFrameBuffer(1);
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  n = min(tft.width(), tft.height());
  for (i = n; i > 0; i -= 6) {
    i2    = i / 2;
    tft.fillRect(cx - i2, cy - i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx - i2, cy - i2, i, i, color2);
  }
  tft.updateScreen();

  return micros() - start;
}


unsigned long testFilledRoundRectsFB() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
  tft.useFrameBuffer(1);

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (i = min(tft.width(), tft.height()); i > 20; i -= 6) {
    i2 = i / 2;
    tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, i, 0));
  }
  tft.updateScreen();
  return micros() - start;
}
#endif

As a base line I ran the graphicstest sketch:

ILI9341 Test!
After TFT Begin
Display Power Mode: 0x0
MADCTL Mode: 0x0
Pixel Format: 0x0
Image Format: 0x0
Self Diagnostic: 0x0
Benchmark                Time (microseconds)
Screen fill              230873
Text                     38240
Lines                    326527
Horiz/Vert Lines         20779
Rectangles (outline)     15141
Rectangles (filled)      474117
Circles (filled)         199044
Circles (outline)        250084
Triangles (outline)      72553
Triangles (filled)       219417
Rounded rects (outline)  95274
Rounded rects (filled)   558090

All ok so far. Now running the modified graphics test sketch what I am seeing does not look good. It keeps hitting the libraries SPI timeout code:

    if (delta_time >= TIMEOUT_US) {
      Serial.print("**TO** WTC:  ");
      Serial.print(wtcCallCount, DEC);
      Serial.print(" ");
      Serial.print(called_from, DEC);
      Serial.print(" ");
      Serial.print(sr_prev, HEX);
      Serial.print(" ");
      Serial.println(sr, HEX);
//      Serial.print(" ");
//      Serial.println(_data_sent_not_completed, DEC);
    }
    _data_sent_since_last_transmit_complete = false;
  }

with corresponding output:

Joystick connected:
**TO** WTC:  52 1 2 3007
**TO** WTC:  139 1 2 2B
**TO** WTC:  294 2 2 3007
**TO** WTC:  427 6 2001 9007
**TO** WTC:  663 2 2 3007
**TO** WTC:  816 1 1002 2A
**TO** WTC:  884 6 2007 B007
**TO** WTC:  1203 6 2007 5007
**TO** WTC:  1271 1 2 5007
**TO** WTC:  1441 1 2 2C
Benchmark                Time (microseconds)
Screen fill              2272711
Text                     **TO** WTC:  1755 1 2 7007
**TO** WTC:  1836 1 2 7007
**TO** WTC:  1868 1 2 3007
**TO** WTC:  2438 1 2 3007
**TO** WTC:  2591 6 2001 9007
**TO** WTC:  2718 1 2 2B
**TO** WTC:  3098 2 2 3007
**TO** WTC:  3190 6 2001 5007
**TO** WTC:  3346 1 2 3007
**TO** WTC:  3432 6 2007 5007
**TO** WTC:  3490 6 2007 3007
**TO** WTC:  3567 6 2001 0
**TO** WTC:  3650 2 2 3007
**TO** WTC:  3729 6 2007 7007
**TO** WTC:  3801 2 2 3007
**TO** WTC:  3873 1 2 7007
**TO** WTC:  3954 1 2 5007
**TO** WTC:  4145 1 2 7007
**TO** WTC:  4331 5 2 3007
**TO** WTC:  4732 1 2 7007
**TO** WTC:  4834 2 2 3007
**TO** WTC:  5037 1 2 5007
**TO** WTC:  5232 1 2 3007
**TO** WTC:  5325 5 2 3007
**TO** WTC:  5528 2 2 2C

.......
**TO** WTC:  320883 2 2 3007
**TO** WTC:  321097 1 4007 F047
**TO** WTC:  321170 1 4007 7007
**TO** WTC:  321226 1 2 2B
**TO** WTC:  321357 1 6007 5007
5967297
Horiz/Vert Lines         **TO** WTC:  321608 5 2001 F007
**TO** WTC:  321618 5 40 F800
**TO** WTC:  321923 1 2 7007
216005
Rectangles (outline)     **TO** WTC:  322053 2 2 7E0
**TO** WTC:  322105 2 2 3007
**TO** WTC:  322190 1 4007 9007
**TO** WTC:  322677 1 2001 0
**TO** WTC:  322724 1 2 7007
**TO** WTC:  322761 1 2001 3007
**TO** WTC:  322814 1 2007 9007
**TO** WTC:  322827 1 2 3007
184190
Rectangles (filled)      **TO** WTC:  323000 1 2 2B
**TO** WTC:  323039 1 2 2C
**TO** WTC:  323074 1 2 3007
**TO** WTC:  323146 1 1002 2B
**TO** WTC:  323182 1 2002 2B
**TO** WTC:  323436 1 2007 5007
**TO** WTC:  323570 1 2007 F007
**TO** WTC:  323856 1 2007 9007
4662442
Circles (filled)         **TO** WTC:  323923 1 2 2C

and this is not calling the keypadloop. Notice the order of magnitude increase in the time to draw.

Not sure the cause.

1 Like

@Merlin513 - I am assuming you are running either @BobTheDog version of the USBHost code or my version based on it with support for USBLS devices...

I am guessing that the system is spending a lot of the time processing USB Host.

For example, if your joystick device has end point which is type interrupt, I believe the current code is calling us back every MS Probably need to instrument some of the code to see how much time is in the different ISRs.

Short answer is yes. Think I am using @BobTheDog's branch right now.

As for instrumenting it when it actually calls the keypadloop its only spending 2 microseconds.

Will try to instrument the code or download the latest incorporated changes into USBHost since I think those PRs were incorporated. But as you said in the other thread - time to enjoy the day.

EDIT: Yep in interrupt is firing every 1ms - confirmed. Oh and I am using your lowspeed branch. Not sure how to get around this unless I use both cores.

M

Mine is based on his... I think one of his PRs was brought in, but not the main one...
At least not as of early this morning.
Fix USB Host issues by AndrewCapon · Pull Request #42 · arduino-libraries/Arduino_USBHostMbed5 (github.com)

I will go back and update mine hopefully be simpler. But should not impact his code at all, except maybe slightly at startup of the device.