sumotoy / TFT_ST7735

A fast driver for ST7735 displays that works with Arduino's /All Teensy's/ESP8266/SPARK
68 stars 31 forks source link

ESP8266 SPI.transfer vs SPI.write (not a issue) #3

Closed reaper7 closed 8 years ago

reaper7 commented 8 years ago

I have a question about https://github.com/sumotoy/TFT_ST7735/blob/1.0p1/TFT_ST7735.h#L536 and https://github.com/sumotoy/TFT_ST7735/blob/1.0p1/TFT_ST7735.h#L542 SPI.transfer is faster way for "only write" data to spi bus than SPI.write ?

and one more question: https://github.com/sumotoy/TFT_ST7735/blob/1.0p1/TFT_ST7735.h#L547 SPI.writePattern vs SPI.write16 maybe simple write16 will be faster?

sumotoy commented 8 years ago

Well, have to admit, is not clear to me what is going on in ESp8266 SPI! Foe example, the SPI.trasfer16 is 'awesome slow' on ESP8266. Last week I get stuck for a couple of days with SPI.writePattern that in many cases should increase a lot speed, works for chunks of 8bit but when repeating 16 bit chunks, not clear if this happen at what SPI speed. Another discover of this week is the 'weak' SCLK signal coming from the 5 ESP8266 NodeMCU.0.9 and 1.0 modules I have here, all between 1.6 and 2.2v, so weak that my 74HC125 buffer I use to isolate RA8875 don't work and this open possibilities to add compatibility to my RA8875 library Another question is:SPI.write are protected by SPI transactions? But thanks for suggestions and keep suggesting, I will look at it and let you know.

Regard your question: SPI.writePattern is pretty fast, I used extensively on fills and pixel streams. SPI.trasfer is NOT fast or better, can be much faster. The reason I'm still using is maintain compatibility with SPI bus and other possible devices, remember that SPI.transfer are protected by SPI transactions

reaper7 commented 8 years ago

see result from Your benchark example, tested with ILI9163C (from https://github.com/sumotoy/TFT_ILI9163C/tree/Pre-Release-1.0p7) NodeMCU0.9, CPU 80MHz times with original code:

Benchmark                Time (microseconds)
Screen fill              300231
Text                     14493
Text2                    42718
Lines                    129856
Horiz/Vert Lines         28162
Rectangles (outline)     23002
Rectangles (filled)      457897
Circles (filled)         87643
Circles (outline)        86561
Triangles (outline)      41060
Triangles (filled)       175108
Rounded rects (outline)  50240
Rounded rects (filled)   521248
Done!

and with SPI.write inside spiwrite original replaced by SPI.write(c); inside spiwrite16 original replaced by SPI.write16(c);

Benchmark                Time (microseconds)
Screen fill              237725
Text                     12176
Text2                    37076
Lines                    115615
Horiz/Vert Lines         22987
Rectangles (outline)     18801
Rectangles (filled)      362660
Circles (filled)         72630
Circles (outline)        73988
Triangles (outline)      34936
Triangles (filled)       143534
Rounded rects (outline)  42597
Rounded rects (filled)   415042

code for test:

        void spiwrite(uint8_t c)
        __attribute__((always_inline)) {
#if 0       
            SPI.transfer(c);
#else
            SPI.write(c);
#endif          
        }

        void spiwrite16(uint16_t c)
        __attribute__((always_inline)) {
#if 0       
            #if defined(_SPI_MULTITRANSFER)
               //last version of ESP8266 for arduino support this
                uint8_t pattern[2] = { (uint8_t)(c >> 8), (uint8_t)(c >> 0) };
                SPI.writePattern(pattern, 2, (uint8_t)1);
            #else
                SPI.transfer(c >> 8); SPI.transfer(c >> 0);
            #endif

            //SPI.transfer(c >> 8); SPI.transfer(c >> 0);
#else
            SPI.write16(c); 
#endif
        }

when I look inside SPI.cpp, difference between transfer and write is only one, transfer at the end of function return value: return (uint8_t) (SPI1W0 & 0xff);

reaper7 commented 8 years ago

and the same changes for TFT_ST7735 1.0p1 wemos d1 mini ; 160MHz

without changes:

Benchmark                Time (microseconds)
Screen fill              233058
Text                     9056
Text2                    25514
Lines                    94073
Horiz/Vert Lines         21288
Rectangles (outline)     14110
Rectangles (filled)      284433
Circles (filled)         71166
Circles (outline)        67614
Triangles (outline)      23119
Triangles (filled)       107096
Rounded rects (outline)  30484
Rounded rects (filled)   320356
Done!

and with changes (transfer -> write:

Benchmark                Time (microseconds)
Screen fill              201062
Text                     8061
Text2                    23068
Lines                    86223
Horiz/Vert Lines         18613
Rectangles (outline)     12344
Rectangles (filled)      245378
Circles (filled)         62796
Circles (outline)        60561
Triangles (outline)      21095
Triangles (filled)       93883
Rounded rects (outline)  27200
Rounded rects (filled)   277700
Done!

and additional raport...my display do not work when inside: TFT_ST7735_cpuCommons.h spi speed is set to: static const uint32_t TFT_ST7735_SPI_SPEED = 80000000; but works when speed value is 79999999 and below very strange!

sumotoy commented 8 years ago

Thanks point me this! I will up a modded version with your suggestions in a min for both libraries, in settings there's the flag to enable the trick (with your name as thanks of course). Or you prefere pull a request? Let me know. Regards the SPI speed, this is a know issue and I never understand why (if you look at closed issues in ILI library you will find). What is really strange that works at very high speed on Teensy 3.2 but not on ESP! The only thing I've noticed is that at 80Mhz (but in reality is NOT) the level of the SCLK drops even more (it's enough very weak, should be 3v3 but I've measured 1.6..2.2V) and waveform became distorted, maybe too much for the ST7735. I will try to add an high speed Schmitt trigger later and see what happen. Did you know if the internal flash uses the same SPI line?

reaper7 commented 8 years ago

Did you know if the internal flash uses the same SPI line?

You wrote about esp? in my knowledge no, "internal" esp flash uses second spi line.

Or you prefere pull a request? Let me know.

Plaese, do it. I don't want to deform so nicely developed library structure

I think something like this:

define _SPI_WRITEMOD

inside TFT_ST7735_cpuCommons.h -> at the end ESP section ?

but with a small change... for me and for compatibility inside spiwrite16 it should only apply to _SPI_MULTITRANSFER:

        void spiwrite16(uint16_t c)
        __attribute__((always_inline)) {    
            #if defined(_SPI_MULTITRANSFER)
                #if !defined(_SPI_WRITEMOD)
                   //last version of ESP8266 for arduino support this
                    uint8_t pattern[2] = { (uint8_t)(c >> 8), (uint8_t)(c >> 0) };
                    SPI.writePattern(pattern, 2, (uint8_t)1);
                #else
                    SPI.write16(c);
                #endif
            #else
                SPI.transfer(c >> 8); SPI.transfer(c >> 0);
            #endif
        }
sumotoy commented 8 years ago

Ok, put this inside settings file:


  /*--------------------------------------------------------------------------------
  - ESP8266 Faster SPI -
  This force library to use the SPI.write method instead the legacy SPI.transfer.
  As result is much faster. (Thanks Reaper7)
  Default:uncommented
  ----------------------------------------------------------------------------------*/
#if defined(ESP8266)
    #define _ESP8266_SPIFAST    
#endif

then inside .h file

        void spiwrite(uint8_t c)
        __attribute__((always_inline)) {
            #if defined(_ESP8266_SPIFAST)
                SPI.write(c);
            #else
                SPI.transfer(c);
            #endif
        }

        void spiwrite16(uint16_t c)
        __attribute__((always_inline)) {
            #if defined(_ESP8266_SPIFAST)
                SPI.write16(c);
            #else
                #if defined(_SPI_MULTITRANSFER)
                    //last version of ESP8266 for arduino support this
                    uint8_t pattern[2] = { (uint8_t)(c >> 8), (uint8_t)(c >> 0) };
                    SPI.writePattern(pattern, 2, (uint8_t)1);
                #else
                    SPI.transfer(c >> 8); SPI.transfer(c >> 0);
                #endif
            #endif
        }
reaper7 commented 8 years ago

ok, tnx!

sumotoy commented 8 years ago

Sorry, are you gonna pull a request or I update as proposed above?

reaper7 commented 8 years ago

please, do it yourself as You suggested above