-
Notifications
You must be signed in to change notification settings - Fork 13.3k
SPI slow performance #2624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
You're trying to set up SPI-frequency and such before you have initialized the SPI-peripheral in the first place. Call SPI.begin() first, then set the frequency. |
@WereCatf I did but still slow and far beyond expectation
|
In addition to the time taken by SPI to transfer data your measurments include the delay between loop() iterations, and the time it takes to Serial.printf. Furthermore, you may only be able to achieve maximum SPI throughput if you use transfer32 function to transfer one word at a time. |
Indeed, like igrr says, you're not counting the time it takes to transfer a byte over SPI, you're counting the time it takes to run the whole loop()! Of course you'll get entirely different values. You could try something like e.g. the following to get a better look at how long 200 transfers took:
|
thanks to both of you @igrr , @WereCatf , but still don't get how to get the max possible speed ?
let me explain my target project for requesting such feature , in fact I've tried to inject the byte array in size of
please if you know an example which is used the correct way , I really appreciated |
How long it takes to run through your whole loop()-function obviously depends on what else you do in there. You have to remember that e.g. Serial.printf() also takes some time to execute -- it doesn't just magically spit out bytes without taking any time at all. Just transferring 470 bytes at 16MHz over SPI, with totally non-optimized code, took 845uS on my ESP, I just tested it. With optimized code it could be shaved down some more, though the theoretical minimum would be 235uS. So, the SPI-speed is not the problem. Also, if I modify your code a bit and remove that Serial.printf() from there each iteration of loop() takes about ~900uS -- with those 470 bytes transferred over the SPI-bus -- and thus way below your 40mS requirement. |
@WereCatf you mean just remove the void loop()
{
if(!SHOW ) server.handleClient();
webSocket.loop();
if(SHOW)
{
if( (millis()- OpenlastTime) >DURATION[image_index]*1000) // just to change the image number
{
image_index++;
if(image_index>=IMAGE_NUM) image_index=0;
_memory_pointer=start_address_of_imagefile[image_index];
Current_imageLine=0;
OpenlastTime=millis();
}
ESP.flashRead(_memory_pointer,(uint32_t *) LED_BUFFER,NUM_LEDS*3 );
Spi.write();// optimized SPI writing method
_memory_pointer+=(NUM_LEDS*3);
Current_imageLine++;
if(Current_imageLine>=IMAGES_LINES )// just to repeat the image frame
{
// Serial.printf("\nFrame took %u ms line=%d RPM=%d\n", micros() - frame_time,Current_imageLine,RPM*IMAGES_LINES);
Current_imageLine=0;
_memory_pointer=start_address_of_imagefile[image_index-1];
frame_time=micros();
}
}
} |
No, I already told you SPI-speed is not the problem. The problem was your Serial.printf()-call and the way you calculated the time it took to execute whole loop(). Writing 470 bytes over SPI at 16MHz didn't even take a whole 1ms, even when just using a simple for()-clause. Don't do something as stupid as writing things over Serial on every loop()-iteration and it will run a lot faster. |
hi again @WereCatf , @igrr , I've went after your suggestions , but I'm so surprise not big changes happened , even as per Ivan suggestion, use #include "SPI.h"
#include <Arduino.h>
#include <ESP8266WiFi.h>
IPAddress apIP(192, 168, 4, 1);
void setup() {
Serial.begin(115200);
delay(500);
SPI.begin();
SPI.setFrequency(16000000L);
SPI.setBitOrder(MSBFIRST);
delay(500);
// WiFi.mode(WIFI_AP);
// WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
// WiFi.softAP("ESP_SPI","12345678");
// delay(500);
// Serial.print("AP IP address: ");Serial.println(WiFi.softAPIP());
}
void loop()
{
uint32_t timerStart=micros();
for (int i = 0; i < 200; i++) {for (int j = 0; j < 470; j++) SPI.transfer(0xE0); delay(0);}
uint32_t timerEnd=micros();
Serial.printf("200 SPI-transfers took %u us \n", timerEnd - timerStart);
} enable wifi setting ets Jan 8 2013,rst cause:4, boot mode:(3,7) wdt reset
200 SPI-transfers took 265329 us
|
so... you delay every 470 bytes... Obviously we can not explain it in a way that you will understand it, but for reference I want to tell you that I can push 220x240x2 bytes through SPI for 27ms, you do the math ;) |
if your code runs as it should, it in perfect world take 47ms to transfer the bytes. |
@mkeyno Take a look at this example: #include <ESP8266WiFi.h>
#include <SPI.h>
void setup() {
WiFi.mode(WIFI_STA);
WiFi.begin("SSID", "password");
Serial.begin(115200);
delay(500);
Serial.println("Begin...");
Serial.print("Connecting to wifi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected.");
SPI.begin();
SPI.setFrequency(16000000L);
SPI.setBitOrder(MSBFIRST);
}
uint32_t loopStart;
uint32_t loopEnd;
uint8_t spiBuffer[470];
void loop() {
loopStart = micros();
for (int i = 0; i < 200; i++) {for (int j = 0; j < 470; j++) SPI.transfer(0xE0); delay(0);}
loopEnd = micros();
Serial.printf("Run 1 took %duS.\n", loopEnd - loopStart);
loopStart = micros();
for (int i = 0; i < 200; i++) {for (int j = 0; j < 470; j++) SPI.transfer(0xE0); }
delay(1);
loopEnd = micros();
Serial.printf("Run 2 took %duS.\n", loopEnd - loopStart);
loopStart = micros();
for(int i=0; i<=470; i++) spiBuffer[i]=0xE0; //Fill the buffer with whatever you want
for (int i = 0; i < 200; i++) SPI.writeBytes(spiBuffer, 470);
delay(1);
loopEnd = micros();
Serial.printf("Run 3 took %duS.\n", loopEnd - loopStart);
loopStart = micros();
spiBuffer[0]=0xE0;
SPI.writePattern(spiBuffer, 1, 200 * 470); //Write a pattern of 1 byte 200*470 times
//Only good for writing patterns up to 64 bytes. DOES NOT WORK FOR BIGGER PATTERNS
delay(1);
loopEnd = micros();
Serial.printf("Run 4 took %duS.\n\n", loopEnd - loopStart);
delay(2000); //Delay for 2 seconds, just so it's easier to follow Serial-output. Can be removed.
} It gives me the results: As you can see, using writeBytes() is much faster. writePattern() may or may not work for your needs, I do not know. I am only including it so you can decide for yourself if it works for you or not. Now, there is another way of speeding things up, too, and that is by changing the IDE-settings: Results with 80MHz Flash, QIO-mode, 160MHz CPU: |
Also, I do have to ask: have you simply tried to use faster SPI-frequency? How high SPI-frequency your LED-strip can handle depends on the LED-strip, obviously, but the ESP8266 can drive an SPI-bus up to 80MHz. |
no dear @me-no-dev , please check my notes again which is mentioned if I remover delay(0); its drop from 265 to 258 ms which is not big deal , I really appreciated if all gentleman here, upload my sketch to check it by himself , and please if any one can share a simple fast spi example code I really really thanks you to use it in my sketch |
uhmmm... did you read the above from @WereCatf ? Do you notice how his fourth run gives about the time from my calculations? |
I know that @WereCatf and test it up to 80MHz, although I expected at least 50% higher speed when double the SPI speed but in practical it was below the 25% and it dwindling when set to max SPI speed (less than 10% ), however I can't use higher than 16MHz because my LED strip goes to noisy for higher SPI frequency |
oh man.... you have loops, jumps and so may things behind the scenes calling SPI-transfer... really pointless to try to explain further. I know that you want us to write the function for you so you can write faster to the SPI, but I do not want to at all ;) we are not here to write you the code or fix your own coding problems. We are here to ensure that everything works as it should, so you can be sure that the problem is in your code and not ESP-Arduino itself. |
@mkeyno Of course it's going to be noisy with your original code, it's just way too slow. Look at my example, use SPI.writeBytes() like I did in it, and set the IDE-settings to 80MHz Flash, QIO-mode, 160MHz CPU. Then test with higher SPI-frequency, like e.g. 24MHz. There isn't really much else to be said about this, you have to look at the examples I've given and try to understand. |
thanks @WereCatf ,I was so terrified that I did somethings so stupid , but as you said I should use the faster function which was so unknown for me or probably ordinary user . In my project I use pointer to byte array instead of |
@me-no-dev I really appreciated for all your time to spare in gitter room and here to reply my unprofessional questions but believe me I don't have any intention to ask anyone to write the code for me although you did me favor sometime and help me out , but I think the way I use the codes in github it may related to my practical application , for example I'm sure no body use yet ESP-Arduino for POV project which is need high speed SPI, hence every body thought I was mistaken about using the SPI, but the @WereCatf result shows it kindda naturally slow due to somethings in behind , I did test same program with Arduino uno and tennsy3.1 and surprisingly was so faster than ESP, for example I could easily reach to 152ms with 8MHz in Arduino uno |
@mkeyno AVR is 8 bit and you can only write bytes to it (SPI.transfer) with two lines. |
55000uS in theory 47000uS much closer uint8_t buf[470]; void loop() SPI.writeBytes(buf, 470); On Wed, Oct 26, 2016 at 9:38 AM, Me No Dev [email protected] wrote:
|
Hardware
Hardware: ?ESP-12F
Core Version: 2.2.0-rc2
Description
following is the simple sketch to test HW SPI speed , According to loop function in sketch , 470 byte has been written to SPI and take time stamp each 200th. With pre set SPI frequency ,whereas it suppose to reach around 200*(470/16)=6ms but I got unexpected result (1000 ms) for all data writing
is there any setting missing ?
thanks
Settings in IDE
Module: ?Generic ESP8266 Module?
Flash Size: 2MB/1MB
CPU Frequency: 80Mhz
Flash Mode: qio
Flash Frequency: 40Mhz
Upload Using: SERIAL
Reset Method: ck
Sketch
Write took 1095536 us
Write took 1095480 us
Write took 1095398 us
Write took 1095614 us
Write took 1095517 us
Write took 1095447 us
Write took 1095493 us
Write took 1095544 us
Write took 1095542 us
Write took 1095443 us
Write took 1095496 us
The text was updated successfully, but these errors were encountered: