Skip to content
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

Unstable response from ESP #5

Closed
m0rt3nlund opened this issue Feb 18, 2018 · 49 comments
Closed

Unstable response from ESP #5

m0rt3nlund opened this issue Feb 18, 2018 · 49 comments

Comments

@m0rt3nlund
Copy link

Hi!

I have an ESP connected to my STM32 and I have two issues.

1: My ESP does not allways appear in my routers list of clients. The ESP reports back that has successfully connected to the AP but it is not reachable by its IP or in the routers clientlist.
Disconnect/Reconnect power to ESP usually makes it work again for some time/reconnects

2: This problem may be related to the above, but the server function «avaliable» does not return a client for most of the time when i try to Connect to the esp.
Also the few times i do get a connection the client data gets read very slow concidering this is a very fast spi connection? Couple of seconds for 100-200bytes.

Any ideas on where or how i can debug this?

Thank you,
Mortem

@JiriBilek
Copy link
Owner

Hi,
you can connect serial monitor to the ESP, the ESP SDK writes sometimes a piece of information there.

@m0rt3nlund
Copy link
Author

Hi! I have finally been able to hook my ESP up to a serial to see what is happening.

This is the debug messages that is responded to me:

SPI SLAVE ver. 0.1.1
Fatal exception 3(LoadStoreErrorCause):
epc1=0x402060ce, epc2=0x00000000, epc3=0x00000000, excvaddr=0x40238512, depc=0x00000000

Exception (3):
epc1=0x402060ce epc2=0x00000000 epc3=0x00000000 excvaddr=0x40238512 depc=0x00000000

ctx: cont 
sp: 3fff0070 end: 3fff02c0 offset: 01a0

>>>stack>>>
3fff0210:  312e3020 000a312e feefeffe 3ffef290  
3fff0220:  0000002f 3ffeef48 3ffeef58 3ffef290  
3fff0230:  3fffdad0 00000000 3ffef264 4020576d  
3fff0240:  40238512 00000000 00000029 402031b2  
3fff0250:  0001c200 0000001c 3ffef264 40205891  
3fff0260:  3fffdad0 00000000 3ffeef24 402026f1  
3fff0270:  402010fc 3ffeef28 00000004 4020365d  
3fff0280:  00000000 00000000 00000000 00000000  
3fff0290:  00000000 00000000 00000000 00000000  
3fff02a0:  3fffdad0 00000000 3ffef288 40205c70  
3fff02b0:  feefeffe feefeffe 3ffef2a0 40100710  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v4ceabea9
~ld

How can I figure out what is causing this? :-)

Thank you,
Morten Lund

@JiriBilek
Copy link
Owner

Hi,
use exception decoder (https://github.com/me-no-dev/EspExceptionDecoder). At least it will tell you where exactly the exception occured.
Post the result here, please.
J.

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 6, 2018

This is the result from the decode :-)

Decoding 9 results
0x4020576d: Print::write(char const*) at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/Print.cpp line 107
0x40238512: sleep_reset_analog_rtcreg_8266 at ?? line ?
0x402031b2: WiFiSpiEspCommandProcessor::cmdGetStateTcp() at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_559429/sketch/WiFiSPICmdServer.cpp line 110
0x40205891: Print::print(char const*) at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/Print.cpp line 107
:  (inlined by) Print::println(char const*) at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/Print.cpp line 172
0x402026f1: WiFiSpiEspCommandProcessor::processCommand(unsigned char*) at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_559429/sketch/WiFiSPICmd.cpp line 173
0x402010fc: hspi_slave_begin at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_559429/sketch/hspi_slave.c line 99
0x4020365d: loop at /Users/mortenlund/Dropbox/Development/ESP8266/ESPSpi/WiFiSpiESP-master/WiFiSPIESP/WiFiSPIESP.ino line 122
0x40205c70: loop_wrapper at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57
0x40100710: cont_norm at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/cont.S line 109

This seems to be cause by this code:

WiFiSpiClient client = TCPserver.available();
  if ( client )
  {
  }

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 6, 2018

When reducing my sketch (SPI Master) to the bare minimum the debug sometimes yields this:

Decoding 10 results
0x40224bc8: ppRecycleRxPkt at ?? line ?
0x402243d1: pp_enable_noise_timer at ?? line ?
0x402244b4: pp_noise_test at ?? line ?
0x40224f17: pp_tx_idle_timeout at ?? line ?
0x4022bcb5: ets_timer_handler_isr at ?? line ?
0x4022bcfa: ets_timer_handler_isr at ?? line ?
0x40205bdf: loop_task at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57

@m0rt3nlund
Copy link
Author

I am using the latest version 2.4.0 of ESP8266 Arduino using Board manager in Arduino if that is relevant.

@JiriBilek
Copy link
Owner

I must say I am confused. I hoped the trace would help us.

@JiriBilek
Copy link
Owner

I need to reproduce the error. I assume you loaded the sketch to the ESP8266 exactly as it was.
Next, you have an app in STM32, right? It would be great if you sent me the bare minimum app (sketch) that caused the crash and all relevant info. I have here STM32F103C8 boards and one F407 so if we are lucky I'll reproduce the issue here.

@m0rt3nlund
Copy link
Author

Yes, this is the sketch i am using to test with. I had originally made everything ready in my complete application, but due to this errors I tried your example-sketch and just made some minor changes to it to test my functionality.

I am using a generic STM32, STM32F103C8, and the ESP is an ESP-201.
I am using unmodified WifiSPI sketch and unmodified ESP8266-Arduino 2.4.0.
The ESP is also powered with its own voltage regulator, not from the STM32 so it should have stable power.

Morten

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using a WiFi ESP8266 module.

 This example is written for a network using WPA encryption.

 Circuit:
   1. On ESP8266 must be running (flashed) WiFiSPIESP application.
    
   2. Connect the Arduino to the following pins on the esp8266:

            ESP8266         |
    GPIO    NodeMCU   Name  |   Uno
   ===================================
     15       D8       SS   |   D10
     13       D7      MOSI  |   D11
     12       D6      MISO  |   D12
     14       D5      SCK   |   D13

    Note: If the ESP is booting at the moment when the SPI Master (i.e. Arduino) has the Select line HIGH (deselected)
    the ESP8266 WILL FAIL to boot!
    
 original sketch for WiFi library created 13 July 2010
 by dlf (Metodo2 srl)
 modified 31 May 2012
 by Tom Igoe
 
 modified for WiFiSpi library 14 Mar 2017
 by Jiri Bilek
 */


#include <WiFiSpi.h>

char ssid[] = "MogH"; //  your network SSID (name)
char pass[] = "10042057";    // your network password (use for WPA, or use as key for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiSpiServer TCPserver(80);

void setup() {
  pinMode(PB12, OUTPUT);
  digitalWrite(PB12, HIGH);
  
  //Initialize serial and wait for port to open:
  Serial1.begin(115200);
  while (!Serial1) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // Initialize the WifiSpi library
  WiFiSpi.init();
  
  digitalWrite(PB12, LOW);
  delay(250);
  digitalWrite(PB12, HIGH);
  delay(5000);

  // check for the presence of the shield:
  if (WiFiSpi.status() == WL_NO_SHIELD) {
    Serial1.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  String fv = WiFiSpi.firmwareVersion();
  if (fv != "0.1.1") {
    Serial1.println(fv);
    Serial1.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial1.print("Attempting to connect to SSID: ");
    Serial1.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFiSpi.begin(ssid, pass);
    Serial1.println(status);
    Serial1.print("Done with begin");

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial1.println("Connected to wifi");
  printWifiStatus();

  Serial1.println("\nStarting connection to server...");
  
  TCPserver.begin();
  if ( TCPserver.status() )
  {
    Serial1.println("\nStarted server");
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  WiFiSpiClient client = TCPserver.available();
  if ( client )
  {
    /*Serial1.println("Found client");
    if ( client.connected() )
    {
      while ( client.available() ) {
        char c = client.read();
        Serial1.write(c);
      }
    }
    
    const char* responseCode = "200";
    const char* body = "Test";
    char Header[100];
    snprintf(Header, sizeof Header, PSTR("HTTP/1.1 %s OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: %i\r\n\r\n"), responseCode, (int)strlen(body)); 
    char buffer[1024];
    strncat(buffer, Header, strlen(Header));
    strncat(buffer, body, strlen(body));

    client.print(buffer);

    client.stop();*/
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial1.print("SSID: ");
  Serial1.println(WiFiSpi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFiSpi.localIP();
  Serial1.print("IP Address: ");
  Serial1.println(ip);

  // print the received signal strength:
  long rssi = WiFiSpi.RSSI();
  Serial1.print("signal strength (RSSI):");
  Serial1.print(rssi);
  Serial1.println(" dBm");
}

@m0rt3nlund
Copy link
Author

It is also wired so that the STM32 controls the CH_PD pin to reset the board. PB12 on my board.

@JiriBilek
Copy link
Owner

Thanks, I will try it soon on my "blue pill". I can test the ESP library only on ESP-12F but it should make no difference.
Jiri

Meanwhile, you could test the ESP side on freshly downloaded stuff from ESP8266-Arduino github project. I had an issue recently, although not related to our problems, and using the newest library solved it.

@m0rt3nlund
Copy link
Author

Thank you, I will try that! Thought about it but my board manager said it was up to date! But I did not think about the git repo of course :-)

@JiriBilek
Copy link
Owner

My testing stops with the exception, too. I am using the newest ESP library now.
Probably, we are in bad project now as this should be an issue of the ESP library.

@m0rt3nlund
Copy link
Author

Should I try a older version of the Arduino ESP lib? Its good to see that you have issues too as I was really looking forward to use your library as the ESP AT commands version is no good.

@JiriBilek
Copy link
Owner

JiriBilek commented Mar 7, 2018

Hi Morten,
it seems to me there is a bug in my ESP library that shows up when it receives invalid packet. I suspect SPI interface in STM32 to behave differently than in Atmel328P. Immediately after initializing SPI on STM32 I am getting tremendous load on SPI interface on ESP. The data received are obviously meaningless and the library crashes. I am working on it since noon (GMT+1 :) ).

JiriBilek referenced this issue in JiriBilek/WiFiSpiESP Mar 7, 2018
Fixed crash when comes an invalid message
Removed some unnecessary debug printing from non-debug build
@JiriBilek
Copy link
Owner

The problem was in another repo.
JiriBilek/WiFiSpiESP@19f3338

@m0rt3nlund
Copy link
Author

Hi! That sounds promising! I hope you figure this out! Really looking forward to use your library! Tell me if there is anything i can do to help!

Morten

@JiriBilek
Copy link
Owner

For STM32F1 I had to slow down the SPI. The default frequency was too fast and I got communication errors. The speed 1000000 is ok.

The additional parameter for SPI speed setting added: fd38121

@JiriBilek
Copy link
Owner

@m0rt3nlund
I tested your sketch and it is running almost perfectly. When you create a http server, you start to poll the ESP8266 quite heavily and with the default speed of STM32's SPI some communication errors appeared. The communication protocol can handle it but I'd recommend to slow down the SPI speed. I added a parameter to init() function for setting max speed.

In your code I'd rather first reset the ESP and then setup the communication (although your code runs fine). And finally, in commented out server part of your code you should copy the first string to the buffer instead of concatenating it.

    char buffer[1024];
    **strncpy**(buffer, Header, strlen(Header));
    strncat(buffer, body, strlen(body));

Also note that reading the data from the ESP byte-by-byte is rather slow as there is a couple of roundtrips on SPI bus needed. I am going to tune the protocol in future but there are serious limitations on the ESP side.

J.

@JiriBilek
Copy link
Owner

And thanks for testing on STM32 and finding a bug.

@tonton81
Copy link

tonton81 commented Mar 7, 2018

i wrote spi code that runs at 30 and 60mhz spi bus between two cortexes, jiribilek, perhaps youll like the implementation i did, it uses circular buffer sending for slave responses to master, fire & forget, and callbacks at both master/slave for 2 way communication similar to uart behaviour

@JiriBilek
Copy link
Owner

JiriBilek commented Mar 7, 2018

@tonton81 , I think it is not a matter of discarding data but rather distorting. The protocol I use on top of SPI is master-slave (I know what you think about it :) ).
I have to find out, why the message sometimes comes corrupt. I have a funny chinese logic analyzer so I hope I'll see the problem. Nevertheless my wiring on breadboard is hideous, I am surprised that it can transfer 1MHz signal.

@m0rt3nlund
Copy link
Author

Very nice work! Will test this first thing tomorrow! Thank you for your great effort!

@JiriBilek
Copy link
Owner

I used your sketch for testing and found another problem with the strings. The server part of the sketch should be

    strcpy(buffer, Header);
    strcat(buffer, body);

or you have to add +1 to strlen in order to copy the trailing '\0'. It's funny, yesterday it somehow worked :)

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 10, 2018

Hi! I have finally been able to test this again! :)

But I keep getting an exception like this one:

0x402010fc: hspi_slave_begin at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_631951/sketch/hspi_slave.c line 99
0x40203501: loop at /Users/mortenlund/Dropbox/Development/ESP8266/ESPSpi/WifiSpiESP_0.1.2/WiFiSPIESP/WiFiSPIESP.ino line 135
0x40205a25: esp_schedule at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57
0x40205a50: loop_wrapper at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57
0x40100710: cont_norm at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/cont.S line 109

@m0rt3nlund
Copy link
Author

I am using this as my init now: WiFiSpi.init(PA4,1000000);

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 10, 2018

Also, this:

Exception (0):
epc1=0x402245a1 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: sys 
sp: 3ffffdf0 end: 3fffffb0 offset: 01a0

>>>stack>>>
3fffff90:  402244a6 3fffdab0 00000000 402059bf  
3fffffa0:  3ffe9608 40000f49 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v4ceabea9
~ld

0x402244a6: ppPeocessRxPktHdr at ?? line ?
0x402059bf: loop_task at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57

@m0rt3nlund
Copy link
Author

Also, this:
3fff0178: 3ffef160 40100710 feefeffe 3ffef160

@m0rt3nlund
Copy link
Author

This is with the development branch of WifiSpi.

@m0rt3nlund
Copy link
Author

Hm.. This may have been a wiring/noise problem.. I have now forced the reset-pin HIGH and IO01 HIGH and the board is much more stable..

Wiring is now as following:

CHIP_EN - PB12 on STM
RESET - 3.3V on ESP board
IO01 - 3.3V on ESP board
IO02 - 3.3V on ESP board

Now I can request the webpage again and again with correct response..

However the response is very slow.
I have about 2.3 seconds "Time before First Byte" delay.
Is this due to the nature of reading byte-by-byte from the ESP as you described earlier?

Morten

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 10, 2018

After running for a while I got this exception:

SPI SLAVE ver. 0.1.2

Exception (9):
epc1=0x40210521 epc2=0x00000000 epc3=0x00000000 excvaddr=0x32e0c112 depc=0x00000000

ctx: cont 
sp: 3ffeff00 end: 3fff0180 offset: 01a0

>>>stack>>>
3fff00a0:  ffffffff 3fffc6fc 00000001 3ffef148  
3fff00b0:  00000000 3fffdad0 3ffef150 00000030  
3fff00c0:  00000000 3fffdad0 3fff151c 40204db6  
3fff00d0:  00000000 0000002e 3fff1c6c 3ffef150  
3fff00e0:  0000002f 3ffeee08 3ffeee18 40204832  
3fff00f0:  0000002f 3ffeee08 3ffeee18 40202c60  
3fff0100:  3ffe8bb0 00000000 00001388 40202be2  
3fff0110:  00000000 00000000 3ffeed00 3ffef150  
3fff0120:  3fffdad0 00000000 3ffeede4 40202655  
3fff0130:  402010fc 3ffeede8 00000004 402034f9  
3fff0140:  012fe0df 00ee0001 00000000 00000000  
3fff0150:  00000000 00000000 00000000 00000000  
3fff0160:  3fffdad0 00000000 3ffef148 40205a50  
3fff0170:  feefeffe feefeffe 3ffef160 40100710  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v4ceabea9
~ld

0x40204db6: WiFiServer::available(unsigned char*) at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/libraries/ESP8266WiFi/src/WiFiServer.cpp line 97
0x40204832: ClientContext::_write_some() at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/libraries/ESP8266WiFi/src/include/ClientContext.h line 421
0x40202c60: WiFiSpiEspCommandProcessor::cmdGetClientStateTcp() at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_483666/sketch/WiFiSPICmdClient.cpp line 96
0x40202be2: WiFiSpiEspCommandProcessor::cmdStopClientTcp() at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_483666/sketch/WiFiSPICmdClient.cpp line 307
0x40202655: WiFiSpiEspCommandProcessor::processCommand(unsigned char*) at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_483666/sketch/WiFiSPICmd.cpp line 123
0x402010fc: hspi_slave_begin at /var/folders/2n/sr5cmbvj7w90sb_dw0trzg100000gn/T/arduino_build_483666/sketch/hspi_slave.c line 99
0x402034f9: loop at /Users/mortenlund/Dropbox/Development/ESP8266/ESPSpi/WifiSpiESP_0.1.2/WiFiSPIESP/WiFiSPIESP.ino line 134
0x40205a50: loop_wrapper at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57
0x40100710: cont_norm at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/cont.S line 109

@JiriBilek
Copy link
Owner

Hi, thanks for testing.
Firstly, make sure you have stable power on ESP, it can draw a lot of current. I think the 3v3 from STM board is not enough. I am always powering the breadboard with external power. Don't forget to connect the ground then. Sorry if it is obvious to you.
Secondly, when giving a stack trace, please give it full. The reason of the exception is quite important to me.
I load your testing sketch and see what happens.

@m0rt3nlund
Copy link
Author

I have the ESP powered by its own voltage regulator connected to USB power (Same USB as the STM) but can try to power it totally seperatly.

I have edited the exceptions above with the full stack trace.

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 10, 2018

SPI SLAVE ver. 0.1.2
Invalid message header - message rejected.
Invalid message header - message rejected.

Exception (9):
epc1=0x4022ba52 epc2=0x00000000 epc3=0x00000000 excvaddr=0x61020365 depc=0x00000000

ctx: sys 
sp: 3ffffdd0 end: 3fffffb0 offset: 01a0

>>>stack>>>
3fffff70:  3ffeb710 3fffdcc0 3ffe9600 3ffe9600  
3fffff80:  4022bada 3fffdab0 00000000 3fffdcb0  
3fffff90:  3ffee7d0 3fffdad0 3ffef150 402059bf  
3fffffa0:  40000f49 40000f49 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v4ceabea9
~ld
0x4022bada: ets_timer_handler_isr at ?? line ?
0x402059bf: loop_task at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57

@JiriBilek
Copy link
Owner

Thanks,
and please decode the exceptions. I can see the exception code now (Exception 9: LoadStoreAlignmentCause: Load or store to an unaligned address) but my Arduino IDE apparently doesn't have the same configuration as yours, so I am getting unusable stack dump.

@m0rt3nlund
Copy link
Author

I have decoded the stack traces now, hope they help! :)

@m0rt3nlund
Copy link
Author

This seems to be the most recurring one:

SPI SLAVE ver. 0.1.2

Exception (0):
epc1=0x402245c0 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: sys 
sp: 3ffffdf0 end: 3fffffb0 offset: 01a0

>>>stack>>>
3fffff90:  00000000 3fffdad0 3ffef150 402059bf  
3fffffa0:  3ffe9610 40000f49 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v4ceabea9
~ld
Decoding 3 results
0x402059bf: loop_task at /Users/mortenlund/Library/Arduino15/packages/esp8266/hardware/esp8266/2.4.0/cores/esp8266/core_esp8266_main.cpp line 57

@JiriBilek
Copy link
Owner

Meanwhile, I have good news for you. I hope to be seeing light at the end of the tunnel, at least.
I played with delays in esp_proxy.h file and now I can send 100 requests at full SPI speed, got 100 responses and no trap on ESP8266 and no rejected messages. Also the response times are stable.
Will test further.

I slightly modified your sketch:

#include <WiFiSpi.h>

char ssid[] = "*"; //  your network SSID (name)
char pass[] = "*";    // your network password (use for WPA)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiSpiServer TCPserver(80);

void setup() {
  pinMode(PB12, OUTPUT);
  digitalWrite(PB12, HIGH);
  
  //Initialize serial and wait for port to open:
  Serial.begin(115200);
  while (!Serial.available()) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Reset ESP8266");

  // Initialize the WifiSpi library
//  WiFiSpi.init(SS, 1000000);
  
  digitalWrite(PB12, LOW);
  delay(100);
  digitalWrite(PB12, HIGH);
  delay(200);

//  WiFiSpi.init(SS, 1000000);
  WiFiSpi.init();

  // check for the presence of the shield:
  if (WiFiSpi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    WiFiSpi.status();
    // don't continue:
    while (true);
  }

  String fv = WiFiSpi.firmwareVersion();
  if (fv != "0.1.3") {
    Serial.println(fv);
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFiSpi.begin(ssid, pass);
    Serial.println(status);
    Serial.print("Done with begin");

    // wait 1 second for connection:
    delay(1000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  
  TCPserver.begin();
  if ( TCPserver.status() )
  {
    Serial.println("\nStarted server");
  }
}

void loop() {
  static uint16_t counter = 0;
  
  // if there are incoming bytes available
  // from the server, read them and print them:
  WiFiSpiClient client = TCPserver.available();
  if ( client )
  {
    Serial.println("Found client");
    
    if ( client.connected() )
    {
      while (! client.available() ) {}
      
/*      while ( client.available() ) {
        char c = client.read();
        Serial.write(c);
      }*/
      char input[400];
      uint16_t inputLen;
      while ((inputLen = client.available()) > 0) {
          if (inputLen > sizeof(input) - 1)
              inputLen = sizeof(input) - 1;
          client.read(reinterpret_cast<uint8_t*>(input), inputLen);
          input[inputLen] = 0;
          Serial.print(input);
      }
    }
    
    const uint16_t responseCode = 200;
    char buffer[1024];
    char header[100];
    char body[100];
    snprintf(body, sizeof body, PSTR("Test %d\r\n"), ++counter); 
    snprintf(header, sizeof header, PSTR("HTTP/1.1 %d OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: %i\r\n\r\n"), responseCode, (int)strlen(body)); 
    strcpy(buffer, header);
    strcat(buffer, body);

    client.print(buffer);

    client.stop();
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFiSpi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFiSpi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFiSpi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

@m0rt3nlund
Copy link
Author

Looking forward to test! :) Great work!

@m0rt3nlund
Copy link
Author

I assume the code above should be used with your next uncomitted version 0.1.3? :)

@JiriBilek
Copy link
Owner

JiriBilek commented Mar 10, 2018

Yes, check out the development branch for both projects.

My recent changes are in espspi_proxy.h only. You can try it:

... Edit 10.3.18, 21:49 GMT+1: source file deleted, see next post for a updated one ...

This runs fine. But it needs more testing.
I am testing on STM32F103C8.

@JiriBilek
Copy link
Owner

Posting espspi_proxy.h that passed my stress test (2000 http requests).

/*
  espspi_proxy.h - Library for Arduino SPI connection with ESP8266
  
  Copyright (c) 2017 Jiri Bilek. All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  -------------

    WiFi SPI Safe Master for connecting with ESP8266
    On ESP8266 must be flashed WiFiSPIESP application
    Connect the SPI Master device to the following pins on the esp8266:

            ESP8266         |
    GPIO    NodeMCU   Name  |   Uno
   ===================================
     15       D8       SS   |   D10**
     13       D7      MOSI  |   D11
     12       D6      MISO  |   D12
     14       D5      SCK   |   D13

    **) User changeable

    Based on Hristo Gochkov's SPISlave library.
*/

#ifndef _ESPSPI_PROXY_H_INCLUDED
#define _ESPSPI_PROXY_H_INCLUDED

#include <SPI.h>
#include "debug.h"

// The command codes are fixed by ESP8266 hardware
#define CMD_WRITESTATUS  0x01
#define CMD_WRITEDATA    0x02
#define CMD_READDATA     0x03
#define CMD_READSTATUS   0x04

// Message indicators
#define MESSAGE_FINISHED     0xDF
#define MESSAGE_CONTINUES    0xDC

// SPI Status
enum {
    SPISLAVE_RX_BUSY,
    SPISLAVE_RX_READY
};
enum {
    SPISLAVE_TX_NODATA,
    SPISLAVE_TX_READY,
    SPISLAVE_TX_PREPARING_DATA
};

// How long we will wait for slave to be ready
#define SLAVE_RX_READY_TIMEOUT     3000UL
#define SLAVE_TX_READY_TIMEOUT     3000UL

// How long will be SS held high when starting transmission
#define SS_PULSE_DELAY_MICROSECONDS   50


class EspSpiProxy
{
private:
    SPIClass *spi_obj;

    uint8_t _ss_pin;
    uint8_t buffer[32];
    uint8_t buflen;
    uint8_t bufpos;
    
    void _pulseSS(boolean start)
    {
        if (_ss_pin >= 0)
        {
/*            digitalWrite(_ss_pin, HIGH);
            delayMicroseconds(SS_PULSE_DELAY_MICROSECONDS);
            digitalWrite(_ss_pin, LOW);
            delayMicroseconds(SS_PULSE_DELAY_MICROSECONDS);  // Added as an attempt to get rid of false messages
            */
            if (start) {  // tested ok: 5, 15 / 5
                digitalWrite(_ss_pin, HIGH);
                delayMicroseconds(1);
                
                digitalWrite(_ss_pin, LOW);
                delayMicroseconds(15);  // 10us is low (some errors), 20 us is safe (no errors)
            }
            else {
                digitalWrite(_ss_pin, HIGH);
                delayMicroseconds(1);
                digitalWrite(_ss_pin, LOW);
            }
        }
    }
    
public:
    EspSpiProxy()
    {
       _ss_pin = -1;
       buflen = 0;
    }

    void begin(uint8_t pin, SPIClass *in_spi)
    {
        spi_obj = in_spi;

        _ss_pin = pin;
        pinMode(_ss_pin, OUTPUT);
        digitalWrite(_ss_pin, LOW);
    }

    uint32_t readStatus()
    {
        _pulseSS(true);

        spi_obj->transfer(CMD_READSTATUS);
        uint32_t status = (spi_obj->transfer(0) | ((uint32_t)(spi_obj->transfer(0)) << 8) | ((uint32_t)(spi_obj->transfer(0)) << 16) | ((uint32_t)(spi_obj->transfer(0)) << 24));
        
        _pulseSS(false);

        return status;
    }

    void writeStatus(uint32_t status)
    {
        _pulseSS(true);

        spi_obj->transfer(CMD_WRITESTATUS);
        spi_obj->transfer(status & 0xFF);
        spi_obj->transfer((status >> 8) & 0xFF);
        spi_obj->transfer((status >> 16) & 0xFF);
        spi_obj->transfer((status >> 24) & 0xFF);

        _pulseSS(false);
    }

    void readData(uint8_t* buf)
    {
        _pulseSS(true);

        spi_obj->transfer(CMD_READDATA);
        spi_obj->transfer(0x00);
        for(uint8_t i=0; i<32; i++) {
            buf[i] = spi_obj->transfer(0);  // the value is not important
        }

        _pulseSS(false);
    }

    void writeData(uint8_t * data, size_t len)
    {
        uint8_t i=0;
        _pulseSS(true);
        
        spi_obj->transfer(CMD_WRITEDATA);
        spi_obj->transfer(0x00);
        while(len-- && i < 32) {
            spi_obj->transfer(data[i++]);
        }
        while(i++ < 32) {
            spi_obj->transfer(0);
        }

        _pulseSS(false);
    }


    void flush(uint8_t indicator)
    {
        // Is buffer empty?
        if (buflen == 0)
            return;  

        // Message state indicator
        buffer[0] = indicator;
        
        // Wait for slave ready
        if (waitForSlaveRxReady() == SPISLAVE_RX_READY)  // TODO: move the waiting loop to writeByte
        {
            // Send the buffer
            writeData(buffer, buflen+1);
        }
            
        buflen = 0;
    }
    
    void writeByte(uint8_t b)
    {
        bufpos = 0;  // discard input data in the buffer
        
        if (buflen >= 31)
            flush(MESSAGE_CONTINUES);
            
        buffer[++buflen] = b;
    }

    uint8_t readByte()
    {
        buflen = 0;  // discard output data in the buffer
        
        if (bufpos >= 32)  // the buffer segment was read
        {
            if (buffer[0] != MESSAGE_CONTINUES)
              return 0;

            bufpos = 0;  // read next chunk
            
            // Wait for the slave
            waitForSlaveTxReady();
        }
        
        if (bufpos == 0)  // buffer empty
        {
            uint32_t endTime = millis() + 1000;

            do {
                readData(buffer);
            }  while (buffer[0] != MESSAGE_FINISHED && buffer[0] != MESSAGE_CONTINUES && millis() < endTime);
            
            if (buffer[0] != MESSAGE_FINISHED && buffer[0] != MESSAGE_CONTINUES)
              return 0;

            bufpos = 1;
        }
        return buffer[bufpos++];
    }

    /*
        Waits for slave receiver ready status.
        Return: status (SPISLAVE_RX_BUSY, SPISPLAVE_RX_READY or SPISLAVE_RX_PREPARING_DATA)
     */
    int8_t waitForSlaveRxReady()
    {
        uint32_t endTime = (millis() & 0x0fffffff) + SLAVE_RX_READY_TIMEOUT;
        uint32_t status = SPISLAVE_RX_BUSY;

        do
        {
            status = readStatus();

            if (((status >> 28) == SPISLAVE_RX_READY))
                return (status >> 28);  // status
            
            yield();
        } while ((millis() & 0x0fffffff) < endTime);

        WARN("Slave rx is not ready");
        WARN2("Returning: ", status >> 28);
        
        return (status >> 28);  // timeout
    }



    /*
        Waits for slave transmitter ready status.
        Return: status (SPISLAVE_TX_NODATA, SPISPLAVE_TX_READY
     */
    int8_t waitForSlaveTxReady()
    {
        uint32_t endTime = (millis() & 0x0fffffff) + SLAVE_RX_READY_TIMEOUT;
        uint32_t status = SPISLAVE_TX_NODATA;

        do
        {
            status = readStatus();

            if ((((status >> 24) & 0x0f) == SPISLAVE_TX_READY))
                return ((status >> 24) & 0x0f);  // status

            yield();
        } while ((millis() & 0x0fffffff) < endTime);

        WARN("Slave tx is not ready");
        WARN2("Returning: ", (status >> 24) & 0x0f);
        
        return ((status >> 24) & 0x0f);  // timeout
    }
    
};

extern EspSpiProxy espSpiProxy;

#endif

@m0rt3nlund
Copy link
Author

m0rt3nlund commented Mar 10, 2018

I have tested this now and it is much more stable.
I am seeing something strange though..

I am using this sketch now to time each step of the communication with the client since it takes from 100ms to 10seconds to get a response.
The strange thing is that it uses avg ~180ms from the client connects to the data is sent, but can use up to 10 seconds stopping the connection to the client (client.stop)
Other times I see it can take 2-3ms, trying to figure out a pattern! :)

0 Found client
2 Wait for data
3 Data is now avaliable
GET / HTTP/1.1
Host: 192.168.1.37
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: nb-NO,nb;q=0.9,no;q=0.8,nn;q=0.7,en-US;q=0.6,en;q=0.5

49 Done reading data
49 Return data
180 Done sending data
5672 Stopped client

Sketch:

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using a WiFi ESP8266 module.

 This example is written for a network using WPA encryption.

 Circuit:
   1. On ESP8266 must be running (flashed) WiFiSPIESP application.
    
   2. Connect the Arduino to the following pins on the esp8266:

            ESP8266         |
    GPIO    NodeMCU   Name  |   Uno
   ===================================
     15       D8       SS   |   D10
     13       D7      MOSI  |   D11
     12       D6      MISO  |   D12
     14       D5      SCK   |   D13

    Note: If the ESP is booting at the moment when the SPI Master (i.e. Arduino) has the Select line HIGH (deselected)
    the ESP8266 WILL FAIL to boot!
    
 original sketch for WiFi library created 13 July 2010
 by dlf (Metodo2 srl)
 modified 31 May 2012
 by Tom Igoe
 
 modified for WiFiSpi library 14 Mar 2017
 by Jiri Bilek
 */


#include <WiFiSpi.h>
#include <aWOT.h>

char ssid[] = "MogH"; //  your network SSID (name)
char pass[] = "10042057";    // your network password (use for WPA, or use as key for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiSpiServer TCPserver(80);

void setup() {
  pinMode(PA4, OUTPUT);
  digitalWrite(PA4, LOW);
  
  pinMode(PB12, OUTPUT);
  digitalWrite(PB12, HIGH);
  
  //Initialize serial and wait for port to open:
  Serial1.begin(115200);

  Serial1.println("Reset ESP8266");

  // Initialize the WifiSpi library
//  WiFiSpi.init(SS, 1000000);
  
  digitalWrite(PB12, LOW);
  delay(100);
  digitalWrite(PB12, HIGH);
  delay(200);

//  WiFiSpi.init(SS, 1000000);
  WiFiSpi.init(PA4, 1000000);

  // check for the presence of the shield:
  if (WiFiSpi.status() == WL_NO_SHIELD) {
    Serial1.println("WiFi shield not present");
    WiFiSpi.status();
    // don't continue:
    while (true);
  }

  String fv = WiFiSpi.firmwareVersion();
  if (fv != "0.1.2") {
    Serial1.println(fv);
    Serial1.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial1.print("Attempting to connect to SSID: ");
    Serial1.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFiSpi.begin(ssid, pass);
    Serial1.println(status);
    Serial1.print("Done with begin");

    // wait 1 second for connection:
    delay(1000);
  }
  Serial1.println("Connected to wifi");
  printWifiStatus();

  Serial1.println("\nStarting connection to server...");
  
  TCPserver.begin();
  if ( TCPserver.status() )
  {
    Serial1.println("\nStarted server");
  }
}

void loop() {
  static uint16_t counter = 0;
  
  // if there are incoming bytes available
  // from the server, read them and print them:
  WiFiSpiClient client = TCPserver.available();
  if ( client )
  {
    long startT = millis();

    Serial1.print(millis()-startT);
    Serial1.println(" Found client");
    
    if ( client.connected() )
    {
      Serial1.print(millis()-startT);
      Serial1.println(" Wait for data");
      while (! client.available() ) {
        if ( millis()-startT > 2000 )
        {
          Serial1.print(millis()-startT);
          Serial1.println(" Timeout wating for data");
          client.stop();
          return;
        }
      }
      
      Serial1.print(millis()-startT);
      Serial1.println(" Data is now avaliable");
/*      while ( client.available() ) {
        char c = client.read();
        Serial1.write(c);
      }*/
      char input[400];
      uint16_t inputLen;
      while ((inputLen = client.available()) > 0) {
          if (inputLen > sizeof(input) - 1)
              inputLen = sizeof(input) - 1;
          client.read(reinterpret_cast<uint8_t*>(input), inputLen);
          input[inputLen] = 0;
          Serial1.print(input);
      }
    }
    
    Serial1.print(millis()-startT);
    Serial1.println(" Done reading data");
    
    const uint16_t responseCode = 200;
    char buffer[1024];
    char header[100];
    char body[100];
    snprintf(body, sizeof body, PSTR("Test %d\r\n"), ++counter); 
    snprintf(header, sizeof header, PSTR("HTTP/1.1 %d OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: %i\r\n\r\n"), responseCode, (int)strlen(body)); 
    strcpy(buffer, header);
    strcat(buffer, body);
    
    Serial1.print(millis()-startT);
    Serial1.println(" Return data");
    client.print(buffer);
    
    Serial1.print(millis()-startT);
    Serial1.println(" Done sending data");
    client.stop();
    
    Serial1.print(millis()-startT);
    Serial1.println(" Stopped client");
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial1.print("SSID: ");
  Serial1.println(WiFiSpi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFiSpi.localIP();
  Serial1.print("IP Address: ");
  Serial1.println(ip);

  // print the received signal strength:
  long rssi = WiFiSpi.RSSI();
  Serial1.print("signal strength (RSSI):");
  Serial1.print(rssi);
  Serial1.println(" dBm");
}

@m0rt3nlund
Copy link
Author

I also had to add a couple of lines at the start to keep the SS pin low during the beginning as my ESP was not behaving without it.. :-)

@JiriBilek
Copy link
Owner

JiriBilek commented Mar 10, 2018

I removed it during testing, in the post it is back.

Edit: sorry, bad understanding. GPIO15 should have resistor to GND and uninitialized port should be in high impedance state. But it's good practice to set the pin explicitly to low state.

@m0rt3nlund
Copy link
Author

I removed the "client.stop()" line from the code and now I have response-time < 200ms.
I thought I needed the stop command to release the sockets to free up the connection pool which I thought was limited to 4-5 connections?

Without the line it works very well! :)

@m0rt3nlund
Copy link
Author

Been working great so far! :) Only issue is the delays between client request and getting a response, but this may be due to ESP-Arduino library maby? :) And maybe due to the "One-byte-at-a-time" transfer approach? :)

@m0rt3nlund m0rt3nlund mentioned this issue Jun 25, 2018
@JiriBilek
Copy link
Owner

Refer #9 (comment)

@JiriBilek
Copy link
Owner

Implemented new more robust protocol (48ea9f3). If you are interested, please try the new version. If the problems still persist, please open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants