ESP8266 native SPI hardware driver - Page 1
Forum section: electronics / general

author: metalphreak
author_rank: Frequent Contributor
timestamp: April 19, 2015, 01:11:13 pm
content: I keep seeing ESP8266 projects where they're simply being sent data from an external microcontroller, or people are attaching peripheral devices via bit-banged i2c. The ESP8266 has a hardware SPI module capable of 80MHz! Nobody is/was using it because the SPI hardware is not documented anywhere, and the Espressif driver code is very limited (send data only).I want (need!) to use SPI to do what I need for my projects, so I spent a few days during my break to investigate the various SPI control registers. I've mostly worked it out and created a much more functional SPI driver code library.I've done a few blog posts with my investigation findings and some other useful info:http://d.av.id.au/blog/SPI Driver Code:https://github.com/MetalPhreak/ESP8266_SPI_DriverAn example of using the SPI driver is my microwire eeprom library:https://github.com/MetalPhreak/ESP8266_Microwire_EEPROMThought some of you guys might find this handy. There's so much more choice for external ADC/DAC/IO Expansion etc with SPI and it's way faster than bit-banging i2c!

author: Howardlong
author_rank: Super Contributor
timestamp: April 19, 2015, 10:54:05 pm
content: What is your toolchain for this? I have some ESP8266 dev boards, but on the short evaluation I did with them a few weeks ago it looked like I was limited to AT commands or Lua. Being able to program these devices in C would make them far more valuable to me.I didn't look very hard at your code, but does this support FIFO buffers, interrupts and/or DMA?Without significant FIFO buffers or DMA, attaining a sustained 80MHz SPI clock rate is going to be interesting!

author: metalphreak
author_rank: Frequent Contributor
timestamp: April 20, 2015, 09:06:28 am
content: There's very little documentation on the SPI hardware at the moment.There are 16 SPI-Wx registers that each hold 32bits, which can be used for sending/receiving data. The code at the moment only uses SPI_W0 for up to 32bits, but writing a few additional functions to pass in a pointer to an array of data, using the full 16x32bits is easy.I've not looked at the interrupts yet, but they are there (somewhat documented for SPI Slave mode in the espressif code).No DMA that i'm aware of (but could possibly be there in the hardware). If it's not exposed in the register definitions by espressif, I have no way of finding it.https://github.com/pfalcon/esp-open-sdkUsing the esp-open-sdk and the sdk files from espressif is pretty easy to setup under linux.Using the AT firmware with an external microcontroller limits you to both the AT functions and the UART speed.Lua limits you to what functions are provided by NodeMCU firmware as well. Although NodeMCU does pack in quite a lot of the current functionality.

author: ralphd
author_rank: Frequent Contributor
timestamp: April 20, 2015, 02:28:43 pm
content: Both esp8266/Arduino and SMING support the native SPI.https://github.com/esp8266/ArduinoSPI master is limited to CPU clock/2 (like most MCUs), so at the default 80Mhz clock, SPI runs at 40Mhz.

author: metalphreak
author_rank: Frequent Contributor
timestamp: April 21, 2015, 08:07:01 am
content: You can run the core at 160MHzThe Arduino code for SPI seems ok, but is still limited to simple 8/16/32 bit writes. I suppose for most purposes, it works ok.It would be good if the Arduino guys behind the ESP8266 port took a look at my SPI code to see if it could be integrated. I'm all for any implementation that gets people working on the ESP8266 natively rather than a 'wifi addon' to another microcontroller. There's just so much potential if you're happy to build onto it with peripherals.I'm working on writing a library that uses the MCP23S08/MCP23S17 GPIO expansion chips over SPI (10MHz max on these ICs). Trying to keep the commands as similar to the current espressif GPIO manipulation commands so it can be easily integrated.You can use 8x MCP23S17 chips on a single SPI bus using one common CS line, for a total of 128 GPIO. They use addressing as part of the command byte to select chips.

author: Muxr
author_rank: Super Contributor
timestamp: April 22, 2015, 04:39:12 am
content: Quote from: metalphreak on April 21, 2015, 08:07:01 amNice work!Also you could fork and make a Pull Request to the Arduino ESP8266 proj, they will probably merge it.

author: kripton2035
author_rank: Super Contributor
timestamp: April 22, 2015, 04:07:29 pm
content: is there any lua module for SPI on the esp8266 ? thk

author: metalphreak
author_rank: Frequent Contributor
timestamp: April 24, 2015, 10:59:47 am
content: https://github.com/MetalPhreak/ESP8266_MCP23S17WorksCode:mcp23s17_init();mcp23s17_REG_SET(IODIR_CTRL, PORT0, 0x0000);uint16 portval = 0x0000;while(1) {sGPIO_SET(PORT0, portval);portval++;os_delay_us(10000); //10ms delay so you can actually see it counting :D}

author: Muxr
author_rank: Super Contributor
timestamp: April 30, 2015, 09:15:37 pm
content: is the SPI lib supposed to work within Arduino IDE? I am not able to get it going.When I clone from the git repo and add the directory as a lib in the arduino IDE I get a following error:Code:/Documents/Arduino/libraries/ESP8266_SPI_Driver/spi.c:26:24: fatal error: driver/spi.h: No such file or directory#include "driver/spi.h"^compilation terminated.Error compiling.I tried flattening the dirs into a single directory and adding that as the lib to the Arduino IDE, the imports then work but I run into a different issue:Code:In file included from /Users/temp1/Documents/Arduino/libraries/esp8266_jsnkdjnsfkndfnsk/spi.h:29:0,from sketch_esp_wifi_test_adafruit.ino:1:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:94:20: error: 'size_t' was not declared in this scopevoid *pvPortMalloc(size_t xWantedSize);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:95:32: error: 'size_t' has not been declaredvoid *pvPortRealloc(void* ptr, size_t xWantedSize);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:97:19: error: 'size_t' was not declared in this scopevoid *vPortMalloc(size_t xWantedSize);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:99:47: error: 'size_t' has not been declaredvoid *ets_memcpy(void *dest, const void *src, size_t n);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:100:34: error: 'size_t' has not been declaredvoid *ets_memset(void *s, int c, size_t n);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:109:48: error: 'size_t' has not been declaredchar *ets_strncpy(char *dest, const char *src, size_t n);^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:112:28: error: 'size_t' has not been declaredint os_snprintf(char *str, size_t size, const char *format, ...) __attribute__ ((format (printf, 3, 4)));^/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:104:5: error: previous declaration of 'int atoi(const ch>int atoi(const char *nptr);^In file included from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/xtensa-lx106-elf/xtensa-lx106-elf/include/stdint.h:12:0,from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.2/include/s>from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/c_types.h:8,from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:11,from /Users/temp1/Documents/Arduino/libraries/esp8266_jsnkdjnsfkndfnsk/spi.h:29,from sketch_esp_wifi_test_adafruit.ino:1:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/xtensa-lx106-elf/xtensa-lx106-elf/include/stdlib.h:70:5: error: conflicts with >int _EXFUN(atoi,(const char *__nptr));^In file included from /Users/temp1/Documents/Arduino/libraries/esp8266_jsnkdjnsfkndfnsk/spi.h:29:0,from sketch_esp_wifi_test_adafruit.ino:1:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:119:6: error: previous declaration of 'void ets_intr_loc>void ets_intr_lock();^In file included from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h:24:0,from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h:32,from sketch_esp_wifi_test_adafruit.ino:8:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h:80:20: error: conflicts with new declaration with >void ets_intr_lock();^In file included from /Users/temp1/Documents/Arduino/libraries/esp8266_jsnkdjnsfkndfnsk/spi.h:29:0,from sketch_esp_wifi_test_adafruit.ino:1:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/tools/esp8266/sdk//include/ets_sys.h:120:6: error: previous declaration of 'void ets_intr_unl>void ets_intr_unlock();^In file included from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h:24:0,from /Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h:32,from sketch_esp_wifi_test_adafruit.ino:8:/Users/temp1/Downloads/esp8266/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h:81:22: error: conflicts with new declaration with >void ets_intr_unlock();^Error compiling.

author: metalphreak
author_rank: Frequent Contributor
timestamp: May 01, 2015, 08:39:13 am
content: My code is written for the Espressif SDK and it's the only thing I've tested it with.The arduino IDE has quite a different style of coding to the Espressif SDK, so they've probably rewritten some of it to make it work with the Arduino IDE style.Best option would be to write to the ESP8266 Arduino IDE guys and see if they can port the code across to work with their setup.Try removing these lines from spi.h:#include "ets_sys.h"#include "osapi.h"#include "os_type.h"

author: Muxr
author_rank: Super Contributor
timestamp: May 01, 2015, 01:51:24 pm
content: Ah, that makes sense, thanks!I was actually able to get the SPI working using the Arduino/ESP8266 libs. The downloadable version doesn't have the complete SPI support, but I cloned the latest repo and just imported the SPI lib and got it to work.Thanks for the response. I should give the SDK a try.edit: I pretty much followed the adafruit guide on getting Arduino with esp8266 going.https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout/using-arduino-ide

author: Parsec
author_rank: Newbie
timestamp: November 22, 2015, 07:59:15 pm
content: Hello Muxr,I'm trying to tackle the same issue you described- using the same Adafruit Huzzah board, using Arduino ESP8266 libraries and attempting to use Metalphreak's MCP23S17 driver. I'm using the latest Arduino v1.6.6 IDE, using the latest Arduino ESP8266 package/board manager and I'm trying to interface an MCP23S17 with the ESP8266.Regarding SPI, below when you said "but I cloned the latest repo and just imported the SPI lib and got it to work", do you mind expanding on that? I'm curious how you got his MCP23S17 driver working.Did you mean:1. You were trying to use Metalphreak's spi driver but abandoned that and are using the SPI library that comes with the Arduino-ESP8266 package exclusively for SPI communication?2. or you have retrofitted Metalphreak's spi driver to use assets in the Arduino-ESP8266 SPI library, which enabled his MCP23S17 driver to function?3. or did you roll your own spi driver which is called upon by Metalphreak's MCP23S17 driver?Thanks again!

author: JoeO
author_rank: Frequent Contributor
timestamp: November 22, 2015, 09:37:49 pm
content: "I beleive only 1.6.5 is supported.... one step at a time people..... "http://www.esp8266.com/viewtopic.php?f=26&t=6375

author: Parsec
author_rank: Newbie
timestamp: November 23, 2015, 01:37:24 pm
content: Reverted back to Arduino 1.6.5 IDE, this isn't the root cause. My previous questions are still valid.Without boring everyone with a bunch of WDT Reset messages, has anyone out there using the Adafruit Huzzah ESP8266-12 board (or equivalent) with the Arduino ESP8266 1.6.5-947-g39819f0 build had successful SPI communication experiences using MetalPhreak's SPI Driver and MCP23S17 driver?Many thanks!

author: Ariel.international
author_rank: Newbie
timestamp: November 23, 2015, 10:52:28 pm
content: Hello,I am trying to use the ESP8266-12E as a SPI slave to an Arduino.Is this feasible or absolutely out of question?What I do is sending collected data through WiFi to a database.I would like the ESP8266 do all the connection and Handling and the Arduino to send just data and commands.I know that I will have to program the ESP8266 to do that, but the basic question is: is there any absolute reason why this can't be done?My capabilities in hardware and programming are average to somewhat advanced.

author: Parsec
author_rank: Newbie
timestamp: November 24, 2015, 12:04:12 am
content: Hello Ariel,I've been down the exact path you're describing, starting a design that was Arduino-centric and wanting to interface it with other peripherals that were more comparatively more powerful, e.g. the Arduino Uno is running at 16MHz w/32K flash mem and 2K RAM and the ESP8266-12 is 80MHz, up to 16MB flash mem and ~36K RAM. The ESP is significantly more powerful beast.You certainly could communicate with the ESP8266 from the Arduino with SPI in the way you're describing. Implement a simple program on the Arduino to read whatever inputs you're interested in, buffer or cache them, and prep a routine to exchange this data with the ESP via the nice Arduino SPI library. You will have to roll your own code for the ESP. You could likely leverage the nice SPI driver that MetalPhreak published on Github, mentioned in this forum thread. Essentially you will need to manage two codebases- whatever you write for the Arduino and then get your hands on the ESP IoT SDK and compose code for the ESP. You could simplify your design (and coding headaches) further by running all of your proposed code on the ESP8266 exclusively, which is what I did on my most recent project. If your design allows for you to run exclusively on the ESP, I'd go for that direction. Again, this is just my opinion based on what simple requirements you have described.Here's the only catch, one that I've learned over days of research and trial and error- unless you're really, I mean really good with C or C++, toss the idea of writing native code for the ESP out the window. I personally haven't touched C and C++ in 15 years, Java and .NET have spoiled me to death. The Arduino's IDE and codebase are incredibly simple. This is what has attracted me to Arduino- very short concept to design time, the Arduino's elegance is its simplicity. The guys at the ESP8266 Community have done an incredible job porting & reimplementing the Arduino's core codebase to run on the ESP. It works really well, with a few exceptions, but no port is perfect. If you want to deviate outward into more complex I/O scenarios then your experience will only be as good as the libraries out in the field that others have generously written and left behind for us "mid-grade" users to take advantage ofI have usedhttps://github.com/esp8266/Arduinothis port with great success on the ESP8266-12. The battle I'm fighting now is to communicate via SPI to an MCP23S17. The SPI driver & subsequent MCP23S17 driver written by MetalPhreak is code native to the ESP- it was written to be compiled and uploaded to that device. To mate these driver classes with an ESP which is running the ESP8266-Arduino "stack" if you will, will require a good bit of research and refactoring, which I'm currently trying to avoid, but may not have much choice if some generous soul doesn't reply back on this thread.Sorry for writing a whole book here, hope it helps!

author: boriz
author_rank: Newbie
timestamp: December 03, 2015, 05:31:36 pm
content: Greetings metalphreak,I am developing under the open sdk also, which work great, have made anirc bot in one of my esp8266 modules that connects automatically to a known wifiwhen it boots up and then it logs on to an irc channel where it can be controlledwith various commands.Anyway, my esp also have SPI and the pins are exposed on the ESP-12 board I gotfrom ebay, but my understanding is that the SPI is not available for use, as its alreadyused to control the external eeprom?Am I in the wrong about this?Best regardsBoriz

author: metalphreak
author_rank: Frequent Contributor
timestamp: December 08, 2015, 04:56:04 pm
content: Quote from: boriz on December 03, 2015, 05:31:36 pmThere are two SPI modules. The flash eeprom uses the SDIO/SPI interface. The HSPI module is available for use and uses a separate set of pins.=========The Arduino system uses C++ with object oriented programming, while the Espressif SDK uses basically plain C code. I don't use Aruduino so can't help rewriting the code to work, but I doubt you can simply include it as is and get it going due to the different coding styles.

author: Chaz
author_rank: Newbie
timestamp: February 15, 2016, 11:19:08 am
content: Quote from: metalphreak on April 21, 2015, 08:07:01 amAnd since there are several available discrete pins you can use for CS, you should be able to have several strings of 128 GPIOs. (you can share the CLK/SDI/SDO across all of them, so long as only one CS is low at a time). I've done this on a previous project with 40 MCP23S17 chips! (not with an ESP8266 though - I was using an FPGA). This was along with several ADCs & DACs (8 of each, I think) which would give 56 chips all using the same CLK/SDI/SDO, with 5 CS lines for the MCP23S17s and 16 CS lines for the ADCs & DACs. If I were doing that circuit again, I think I'd use several sets of CLK/SDI/SDO though. Maybe one for each class of chip.Please let me tell you about a "gotcha" with the MCP23S17 though. This only matters if you're planning to use several on one SPI bus, and you're planning on using addresses 4-7. There is a datasheet addendum on Microchip's website (http://ww1.microchip.com/downloads/en/DeviceDoc/80311a.pdf) which says:Quote from: Microchip.comThis is important because initially all the chips on a string will have HAEN=0. The first thing you'll do is send to address 0 the command to set HAEN = 1, and all the chips will "see" this instruction, and all will now have Hardware Eddressing Enabled -OH NO THEY WON'T!!- only addresses 0-3 will. You must send the same command again, but this time using address 4 (100 in binary) so that the chips with address 4-7 will "see" the instruction. After that all is good, and every chip will respond only to instructions sent to it's own address.As an experiment I also tried using one MCP23S17 to generate the CS lines for other strings of MCP23S17s. This worked fine, although obviously a bit more complicated and theoretically slower (1 instruction to set the CS-controlling chip, then another instruction to set the target chip). I'm sure there must be a limit to the number of chips you can connect to the same CLK/SDI/SDO, but it'd depend on the impedence of those pins versus the driving current. I suppose capacitance would come into play at some point too if the tracks were long enough.

author: captbill
author_rank: Contributor
timestamp: February 16, 2016, 10:22:02 am
content: Quote from: Ariel.international on November 23, 2015, 10:52:28 pmAll you need is a "uart-bridge" setup. Flash the "ESP-Link" software from Jeelabs. Wire the Tx and Rx to the ESP8266 from your mcu and it is seen as a COM port. No need for SPI here.https://github.com/jeelabs/esp-linkI think this SPI library would be an excellent addition to have combined with the 'uart-bridge' concept though, for sure. These ESP8266's are amazingly powerful and could easily drive the RA8875 video lcd drivers with ease.https://youtu.be/cwCxkLZRuN0

author: metalphreak
author_rank: Frequent Contributor
timestamp: February 16, 2016, 11:50:26 am
content: Chaz: thanks for the heads-up. I haven't tried multiple chips yet (haven't needed to). That errata should be fixed in all of the current chips I have but I might add a routine in to the driver to take care of that RevA silicon.