13 Replies Latest reply on Dec 26, 2014 6:23 AM by xblades

    How can i improve SPI speed?

    kenchen

      I used the Adafruit_ST7735 library, that write/read 1.8" TFT through SPI interface.

      But the speed is too slow. If I want to show the picture pixel by pixel, that toke about 8 minutes.

      I has traced the library code, it called the ioctl function to update data.

       

      D:\Arduino\arduino-1.5.3-Intel.1.0.3\hardware\arduino\x86\libraries\SPI\SPI.cpp

      uint8_t SPIClass::transfer(uint8_t txData)
      {
       uint8_t rxData = 0xFF;
       struct spi_ioc_transfer msg;
      memset(&msg, 0, sizeof(msg));
       
       msg.tx_buf = (__u64) &txData;
       msg.rx_buf = (__u64) &rxData;
       msg.len = sizeof(uint8_t);
       
       if (ioctl (this->fd, SPI_IOC_MESSAGE(1), &msg) < 0)
        trace_error("Failed to execute SPI transfer\n");
      return rxData;
      }
      
      
      

       

      D:\Arduino\arduino-1.5.3-Intel.1.0.3\hardware\tools\x86\i586-poky-linux-uclibc\usr\src\debug\uclibc\0.9.33+gitAUTOINC+946799cd0ce0c6c803c9cb173a84f4d607bde350-r8.4\git\libc\sysdeps\linux\common\ioctl.c

       

      /* vi: set sw=4 ts=4: */
      /*
       * ioctl() for uClibc
       *
       * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
       *
       * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
       */
      #include <sys/syscall.h>
      #include <stdarg.h>
      #include <sys/ioctl.h>
      #include <cancel.h>
      #define __NR___syscall_ioctl __NR_ioctl
      static __always_inline
      _syscall3(int, __syscall_ioctl, int, fd, unsigned long int, request, void *, arg)
      int ioctl(int fd, unsigned long int request, ...)
      {
       void *arg;
       va_list list;
      va_start(list, request);
       arg = va_arg(list, void *);
       va_end(list);
      if (SINGLE_THREAD_P)
        return __syscall_ioctl(fd, request, arg);
      #ifdef __NEW_THREADS
       int oldtype = LIBC_CANCEL_ASYNC ();
       int result = __syscall_ioctl(fd, request, arg);
       LIBC_CANCEL_RESET (oldtype);
       return result;
      #endif
      }
      lt_strong_alias(ioctl)
      lt_libc_hidden(ioctl)
      
      
      

       

       

      My circuit as below,

      1.8" TFT display  =  Intel Galileo Gen1 board

      GND                        GND

      VCC                         5V

      Reset                       DIO8

      A0(DC)                    DIO9

      SDA                         DIO11

      SCK                         DIO13

      CS                           DIO7

      LED+                       3.3V

      LED-                        GND  

       

       

       

      How can i improve this?

      Thank you.

        • 1. Re: How can i improve SPI speed?
          DiegoV_Intel

          Hi kenchen,

           

          I haven't tried it yet but did you already try using the setClockDivider() function? BTW, there is a new IDE release (1.0.4) so I'd suggest you to update yours. You can download from here: Galileo Software Downloads

           

          Regards,

          Diego.

          • 2. Re: How can i improve SPI speed?
            KurtE

            Just an FYI - I am doing anything right now with the Galileo.  I have a Gen 1 but did not do much with it, currently playing with the Edison.  I have a few different Adafruit displays.  I have one of the 1.8" versions, but I have not used it for awhile, I am mainly using the 2.8" and 2.2" displays which use the ILI9341 driver.

             

            And it too is a lot slower here than on some other processors like the Teensy 3.1.  But I have made some reasonable improvements in it's speed.  I talk more about it in the thread:

            Support for the Adafruit 2.8" TFT display for Arduino Edison

             

            Some of the main differences, is seeing that each call to SPI as well as calls to things like digitalWrite  for the chip select and the like, have to make a transition from user mode to the underlying device driver, which adds lots of overhead.

             

            So to speed things up, I tried to minimize calls whenever possible, I try to convert multiple calls to single calls. Simple examples is in many places the driver writes out a 16 bit value, by breaking the 16 bits into two bytes and doing 2 calls to SPI.transfer.  With the Intel SPI library there is a function SPI.transferBuffer, that can read/write multiple bytes at a time.

            using this knocks those calls in half...

             

            Now after doing some stuff with MRAA, I think I can speed that code up a little faster as I believe I can pass in NULL pointer for RX buffer when I am not interested in RX...

            My version of the Adafruit_ILI9341 driver with this is up on github (http://www.github.com/kurte/Adafruit_ILI9341).   Again I have not done this for the Adafruit_ST7735 library but it could be done.

             

            Kurt

            • 3. Re: How can i improve SPI speed?
              kenchen

              Hi Diego.,

               

              Yes,I had tried to modify the frequency fo SPI to (20000000 - 1). That seems to be a highest value of Galileo's SPI.

              The performace is improved a little bit. But it still has the lag .

               

              Thanks,

              • 4. Re: How can i improve SPI speed?
                kenchen

                Hi Kurt,

                 

                I also tried to use the "SPI.transferBuffer", draw the 128 pixels at a time.

                But it does not seems to be supported to draw all 128x160 at a time.

                I'm keep going to try...

                 

                Thanks,

                • 5. Re: How can i improve SPI speed?
                  KurtE

                  I am not sure yet of which version of the libraries you are using.  I downloaded the Adafruit_St7735 library from Adafruit and it did not compile.  So I hacked up a version of it, that does.  Most of it was running real real slow, so I hacked in some of the speed up code for ILI9341 driver to it and it is working quite a bit better. 

                   

                  The code is not in great shape yet, probably won't compile except on Edison maybe Galileo, but I uploaded it to a new branch on my github projects
                  https://github.com/KurtE/Adafruit-ST7735-Library/tree/Intel-Edison

                   

                  There are still more speed ups that are needed, including probably ones that you need for drawing images, but rectangles, fast lines... are much faster.

                   

                  Warning not sure yet how much I will do on this library as for the most part I use other displays, but was curious.   May try it out my Galileo V2 when it arrives.

                  • 6. Re: How can i improve SPI speed?
                    kenchen

                    Hi KurtE,

                     

                    I modified the AdafruitST7735 library,

                    1. Put the all of 128*160 pixel to buffer array[128*160],

                    2. Use the function : void SPIClass::transferBuffer(const uint16_t *txData,    uint16_t *rxData,   uint32_t len) to update the 128 pixel's colors at a time. So that I just need to call the SPI.transferBuffer at 160 times.

                     

                    The performace is better, drawing the 128*160 pixels about 209 ms.

                     

                    Thanks,

                    • 7. Re: How can i improve SPI speed?
                      KurtE

                      So a couple of days ago I received my Galileo 2,  I have been playing around with my Adafruit_ILI9341 library and it works, but I am finding the SPI clock speed to be something like: 39us or about 256khz, which is pretty slow.  My timings are something like 4 times as slow as Edison.  

                       

                      I am calling off to SPI to set the speed:

                        SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)

                        SPI.setBitOrder(MSBFIRST);

                        SPI.setDataMode(SPI_MODE0);

                       

                      I am running 1.0.4 of the IDE.  Not sure what else to try here. I am using the Shield version of the Adafruit display so: CS=10, DC=9

                      • 8. Re: How can i improve SPI speed?
                        kenchen

                        Hi KurtE,

                         

                        Do you mean that Galileo Gen2 is also slow SPI(called the ioctl function) speed ?

                         

                        I'm using Galileo Gen 1, and had tried to adjust SPI.setClockDivider() or directly "#define SPI_CLK_DEFAULT_HZ" in SPI.cpp. That has just little effect.

                         

                        Thanks,

                        • 9. Re: How can i improve SPI speed?
                          dferyance

                          One other thing to try is to have the SPI driver handle the CS line for you. In theory it should help. Although with the code I have tried it on, I found little difference in practice. It is still worth a shot. Normally the Galileo Arduino libraries select a user-controllable Cypress GPIO pin for CS but it is possible to hack it so that the CPU's CS pin is used. The driver will toggle that line automatically for any SPI communications.

                          • 10. Re: How can i improve SPI speed?
                            KurtE

                            Thanks,

                             

                            I know that they are making changes to mraa to do this, but so far I am not seeing any improvement.  Note: I am mostly working with Edison.  Also their SPIDEV does not appear to handle the control of when to set and clear the CS pin as defined as part of the transfer structure.

                             

                            Right now I am playing with some of the Edison code base to see if for example I can get the SPI speed up to 8mhz...

                            • 11. Re: How can i improve SPI speed?
                              xblades

                              Hi Kurt,

                              i play with intel edison, too. I have problems reading form spi with libmraa, because it returns always the content of the transmit buffer in the read buffer.

                              Did you ever manage to read the content of the receive line in the rx buffer ?

                              • 12. Re: How can i improve SPI speed?
                                KurtE

                                mraa_spi_transfer_buf has worked for me.  I have used it in the past to retrieve information from TFT display.

                                 

                                Not knowing any of your particulars, like code, how it is built, I can only suggest some generic things like, make sure you are running the current version of mraa.

                                several threads show how to update.  Also if you are using eclipse, make sure the headers and libraries are updated on your PC to match

                                • 13. Re: How can i improve SPI speed?
                                  xblades

                                  Thx,

                                  it works now. The FPGA connected to SPI mirrored tx back to rx when the second spi_cs was active - unfortunately it was ...