-
Notifications
You must be signed in to change notification settings - Fork 13.3k
SPI methods are inconsistent with Arduino AVR SPI #2677
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
sorry to be picky but what's big problem with that ? writeBytes much faster than normal transfer function |
The standard Arduino SPI library does not have a I am not saying there is a need to remove writeBytes; but at least expose the standard of a transfer that takes a buffer and count of bytes. |
According to the writeBytes method comment the data has to be aligned to 32 bits - so it differs significantly from the transfer method that ships with the Arduino. |
My improved performance Ethernet library doesn't compile on ESP8266, only because SPI.transfer(data, size) is missing. Here's a quick implementation I added in SPI.h for testing. Maybe something like this could be merged, so Arduino sketches and libraries using this well established Arduino API can compile and run on ESP8266?
|
The above comments are right, off-topic: |
No, not if you want to be compatible with Arduino programs. According to Arduino's documentation "In case of buffer transfers the received data is stored in the buffer in-place (the old data is replaced with the data received)." https://www.arduino.cc/en/Reference/SPITransfer The reason to implement SPI.transfer(buffer, size) is for compatibility with Arduino programs. |
Yes I was just realizing that. The esp8266/arduino devs did things right. |
@PaulStoffregen |
Tried it just now. Seems to work fine, at least testing with my Ethernet lib. However, the performance is not as good as the memcpy-based code. But they're similar. With the memcpy version, I get 609.6 kbytes/sec overall speed fetching a web page from a fast Linux server on the same LAN, using a W5500 (Adafruit's Featherwing Ethernet). With this optimized version I get 582.9 kbytes/sec. I ran each a few times. The speeds are very consistent. FWIW, ESP32's speed is 964.0 kbytes/sec on this test, using this in ESP32's SPI.h:
Unfortunately this doesn't work on ESP8266. Seems using the same pointer for read and write isn't allowed? |
Here's the exact code I tested in SPI.cpp.
|
esp8266's I'll work on this as soon as I can. Thanks for your feedback. |
Maybe my buffers are always aligned to 32 bit boundaries? Some are small buffers on the stack. Others are pointers to buffers from the user's sketch code, but in this test I'm only using a couple of those. Maybe they are aligned only by luck? (or because the first local variable in a function gets aligned?) Anyway, the performance is similar. Probably not worth a lot of work for such a small difference. Maybe best to use the code which for-sure handles unaligned data? |
Aren't stack variables always 32bit-aligned? => buf[40] would always have an aligned base. |
The issue will be in class/struct members. You will need to test something like this...
|
I tried placing my data at an offset within the buffer. Both seem to work fine. Does transferBytes() allow pointers to be unaligned from 32 bit word boundaries? |
The optimized version of #4925 is good enough. I'd recommend merging it. More optimization can always be done later. As things are now, libraries written for Arduino (like my recent work to speed up W5X00 Ethernet) are incompatible with ESP8266, only because this well documented Arduino API is missing. |
I released Arduino Ethernet 2.0.0 today. It requires this issue fixed to compile for ESP8266. Users can of course still use the old versions, or Adafruit's Ethernet2 or others... without the improvement performance and new features. |
#4925 is merged. |
I think if we were careful, we could implement SPI::writebytes() to support unaligned pointers for just a few cycles more per call. Would this be worth it? By sending a few single bytes, we could get the read-pointer aligned on 32-bits, then chuck the (hopefully) large amount of remaining data through the fast 32-bit function. Basically like this:
If we wanted to get faster, we could remove the FIFO synchronization from the end of writeBytes_() and just check it once when returning from writeBytes(). |
Basic Infos
APIs across platforms should try to be consistent so that library writers don't have to pepper their code with ifdefs and custom calls for standard uses.
The Esp8266 SPI has method names for functions that are inconsistent with AVR SPI but are functionally the same.
on AVR
void transfer(void *buf, size_t count)
is the same as on Esp8266
void writeBytes(uint8_t * data, uint32_t size);
The text was updated successfully, but these errors were encountered: