Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 15 of 15

Thread: SPI.transfer() send multiple bytes, array? (teensy 3.2)

  1. #1

    SPI.transfer() send multiple bytes, array? (teensy 3.2)

    Hello,

    I need to transfer via SPI many bytes at once and without delay between every byte.

    If I do:

    Code:
     SPI.transfer(byte1);
     SPI.transfer(byte2);
     SPI.transfer(byte3);
    etc..
    I have a delay of aprox 500ns between every bytes... with follow SPISettings settingsA(30000000, MSBFIRST, SPI_MODE0) and 96MHz

    if I try follow:

    Code:
    uint8_t rgb[]={5,6,3};
    
    for(x=0; x<=76800; x++)
    {
    SPI.transfer(rgb, sizeof(rgb));
    }
    result is as follow: 5,6,3 0,0,0 0,0,0 etc.....

    but I need:
    5,6,3 5,6,3 5,6,3 5,6,3 etc...

    Why the bytes are cleared after the first cycle?
    I don't understand that....

    thank you very much

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    6,969
    SPI provides a bidirectional transfer - it writes and read at the same time. The function used is sending a pointer to data and is overwritten with the data read - which is zero's.

    try this? :: SPI.transfer(rgb, 0, sizeof(rgb)); // Line #143 >> \hardware\teensy\avr\libraries\SPI\SPI.cpp

    Using this 3 param function with a NULL as the second param will have the return data discarded.

  3. #3
    Quote Originally Posted by defragster View Post
    SPI provides a bidirectional transfer - it writes and read at the same time. The function used is sending a pointer to data and is overwritten with the data read - which is zero's.

    try this? :: SPI.transfer(rgb, 0, sizeof(rgb)); // Line #143 >> \hardware\teensy\avr\libraries\SPI\SPI.cpp

    Using this 3 param function with a NULL as the second param will have the return data discarded.
    thank you that works... but unfortunately the SPI speed is still not such high as expected.
    I'm writing to a 240x320 Frame-Buffer from a Display.

    I think that the SPI transfer functions still has some delay between every byte or between every third byte.. :-(

    Is there another function, or setting to minimize delay between bytes? Respectively a fast way to transfer multiple bytes?

    thank you very much

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,672
    If you are using the SPI.transfer(buf, retbuf, cnt)... like transfer, it should keep the SPI running at full speed, without gaps...

    Works fine for my 320x240 type output, although you have to be careful on byte orders... Also the speed will obviously depend on what speed you are telling SPI to work at...
    Not sure what that is as I don't see any complete code here...

  5. #5
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,797
    You might want to look at the optimized ILI9341 library for inspiration. As long as you use the hardware CS pins for both CS and DC, the code will use DMA to transfer data as fast as possible.

    The optimized CS pins for the Teensy 3.2 are (note, pins on the same line represent the same internal hardware resource, so you could use pin 2 as an optimized SPI pin or pin 10, but you can't use them at the same time):
    • Pin 2 or pin 10
    • Pin 6 or pin 9
    • Pin 15/A1
    • Pin 20/A6 or pin 23/A9
    • Pin 21/A7 or pin 22/A8


    Further reading:


    And note, it is possible to have the processor go too fast and overwhelm the device. I play around with the 128x128 color OLED displays (for the Adafruit uncanny eyes project), and I've found that I can no longer get the 3.2 to work without flickering. In the past I was able to set the Teensy clock speed down so it would work fine, but something has changed in the last year or so, and even if I set the Teensy bus speed to extremely slow, and a low SPI bus speed, it still flickers.

    So I now use the Teensy 3.5. I've found I need to set the SPI bus speed to 11Mhz or slower to allow the Adafruit OLED display to work and 18Mhz for the waveshare and newhaven displays. With a SPI bus speed set, I can run the Teensy 3.5 at full speed (120Mh), or even over-clocked. The TFT displays can run fine with a 24Mhz SPI clock speed and the 3.5 running at full 120Mhz.

    I use the SPIsettings with SPI transactions to set the SPI bus speed.

  6. #6
    Quote Originally Posted by MichaelMeissner View Post
    You might want to look at the optimized ILI9341 library for inspiration. As long as you use the hardware CS pins for both CS and DC, the code will use DMA to transfer data as fast as possible.
    ...

    So I now use the Teensy 3.5. I've found I need to set the SPI bus speed to 11Mhz or slower to allow the Adafruit OLED display to work and 18Mhz for the waveshare and newhaven displays. With a SPI bus speed set, I can run the Teensy 3.5 at full speed (120Mh), or even over-clocked. The TFT displays can run fine with a 24Mhz SPI clock speed and the 3.5 running at full 120Mhz.

    I use the SPIsettings with SPI transactions to set the SPI bus speed.
    hmm thankyou.
    At the moment I try to write from an array with 240*320*3 Bytes x-D ...with SPI.transfer(rgb, 0, sizeof(rgb)); ... but it doesn't works as expected. :-((
    I think the spi-function cannot handle such big arrays?? Can you confirm that?

    My setting, 96MHz (overclocked),
    SPISettings settingsA(30000000, MSBFIRST, SPI_MODE0);
    Maximum clock I can measure now in real is aprox 20MHz....

    Code:
    void color(uint8_t r, uint8_t g, uint8_t b) //red, green, blue Byte value
    {
    	writecommand(0x2A); //x pixel-position 
    	writedata(0x00); //start-position
    	writedata(0x00); //start-position
    
    	writecommand(0x2B); //y pixel-positon
    	writedata(0x00); //start-position
    	writedata(0x00); //start-position
    
    	writecommand(0x2C); //Write to RAM
    	
      uint8_t rgb[230399];
      long int x;
      for(x=0; x<76800; x++)
      {
        rgb[x*3+0]=r;
        rgb[x*3+1]=g;
        rgb[x*3+2]=b;
      }   
    
      digitalWrite(CS0, 0);
      digitalWrite(DC, 1); //Command = 0, Data = 1
      SPI.transfer(rgb, 0, sizeof(rgb));
      digitalWrite(CS0, 1);
    }

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,502
    Does adding "__attribute__ ((aligned (4)))" to the array make any difference?

    For example:

    Code:
    uint8_t rgb[230400] __attribute__ ((aligned (4)));
    Also consider this array uses nearly all the RAM on Teensy 3.6. If you try this on Teensy 3.2 or 3.5, of course it will fail. It should not even manage to compile.

    If you're creating the array with malloc (we can't see that part of your code... so some guesswork here) then you could get a pointer but there simply isn't that much memory.

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    6,969
    OP Title says (teensy 3.2) - so that can't be in RAM.

    Paul - as of TD_1.42 don't T_3.5 and T_3.6 have the same RAM ( less 4 bytes? )?

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,502
    Oh yeah, we're now supporting 256K RAM (less 8 bytes) on Teensy 3.5.

  10. #10
    Quote Originally Posted by PaulStoffregen View Post
    Does adding "__attribute__ ((aligned (4)))" to the array make any difference?

    Oh yeah, we're now supporting 256K RAM (less 8 bytes) on Teensy 3.5.

    what is the max. Array limit for the SPI.transfer function?
    I just have try some values, I think the maximum is aprox 60'000? with 65000 it is not working anymore??

    Code:
    void color(uint8_t r, uint8_t g, uint8_t b)
    {
    	writecommand(0x2A); //x pixel-position anfahren
    	writedata(0x00); //start-position
    	writedata(0x00); //start-position
    
    	writecommand(0x2B); //y pixel-positon anfahren
    	writedata(0x00); //start-position
    	writedata(0x00); //start-position
    
    	writecommand(0x2C); //RAM Daten senden
    	
    	uint8_t rgb[60000] // OK, but with 65000 NOT OK!!
      long int x;
      for(x=0; x<20000; x++)
      {
        rgb[x*3+0]=r;
        rgb[x*3+1]=g;
        rgb[x*3+2]=b;
      }   
    
      digitalWrite(CS0, 0);
      digitalWrite(DC, 1); //Command = 0, Data = 1
      SPI.transfer(rgb, 0, sizeof(rgb));
      digitalWrite(CS0, 1);
    }
    BTW: Regarding __attribute__ ((aligned (4))); I could not find a difference.

    See below the max. speed I have with SPI according my settings. How can I setup 120MHz?

    Click image for larger version. 

Name:	spi_speed 30Mhz, 96MHz.jpg 
Views:	10 
Size:	22.9 KB 
ID:	14165
    Last edited by epikao; 07-11-2018 at 09:21 AM.

  11. #11
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    6,969
    The SPI.transfer code is not limiting - it uses 32 bit counters and addressing so it will happily work well beyond available RAM on any Teensy.

    First post noted a T_3.2 is being used. It only has 65K of total RAM. The RAM used is noted when the compile completes, and using 100% of RAM - or even almost - can cause failure.

  12. #12
    Quote Originally Posted by defragster View Post
    The SPI.transfer code is not limiting - it uses 32 bit counters and addressing so it will happily work well beyond available RAM on any Teensy.

    First post noted a T_3.2 is being used. It only has 65K of total RAM. The RAM used is noted when the compile completes, and using 100% of RAM - or even almost - can cause failure.
    ah ok. understand, compiling results shows only the memory usage of global variables...

    To my other question: What can I do to get 30MHz SPI clock? Or how do I set the Systemclock to 120Mhz?
    + is it possible to store the array to static RAM/flash? instead to the dynamic RAM and have DMA?

    thanks
    Last edited by epikao; 07-11-2018 at 10:25 AM.

  13. #13
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,672
    As mentioned by others, that support a frame buffer on the ILI9341 are Frank's and mine (ili9341_t3n) only support it on T3.6 and at least mine now 3.5
    As 320x240*2=153600 bytes and on yours you are using 3 bytes per pixel versus 2 so 230400 bytes which may still fit on T3.6, but I have not tried it.

    As for 20mhz, I believe if you set the T3.2 to 120mhz CPU speed, by default the F_BUS will be set to 60MHZ and in SPI fastest mode is F_BUS/2=30mhz
    You might be able to go faster and edit kinetisk.h in hardware\teensy\avr\cores\teensy3... and edit where F_CPU == 120000000 and uncomment the line #define line with
    setting F_BUS 120000000 (personally I have not tried running the bus at that speed...) So no idea if you might run into issues.

    Memory on these CPU only has one address range (unlike the 8 bit AVR boards). So yes you should be able to read from FLASH... However again remember this is still a finite resource (256K)
    https://www.pjrc.com/teensy/techspecs.html

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,502
    Quote Originally Posted by epikao View Post
    What can I do to get 30MHz SPI clock?
    Use SPI.beginTransaction with SPISettings 30000000 for the clock.

    However, the SPI clock can only be an integer division of F_BUS, and the smallest integer is 2. So if F_BUS is 48 MHz (the default with 96 MHz CPU), then 24 MHz is the max SPI speed. SPISettings will automatically use the highest if can that is less than or equal to the clock you request.

    Or how do I set the Systemclock to 120Mhz?
    Click Tools > CPU Speed and select the 120 MHz option.

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,502
    More overclocking options are available if you edit kinetis.h. The comments in that file explain your options.

    NXP rates the MK20 chip on 3.2 for 50 MHz max on F_BUS, and the MK64 & MK66 chips on 3.5 & 3.6 for 60 MHz max F_BUS. Frank and others have reported success with overclocking F_BUS, but going over those ratings is overclocking which comes with all the usual caveats of running faster than the manufacturer's spec.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •