• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP32 + W5500 + SPIFFS

workpage

New member
Долго бьюсь над проблемой. Не могу заставить нормально работать ethernet на esp32.
Подключен внешний ethernet чип на w5500 через spi.
Распиновка следующая:
MOSI:23
MISO:19
SCK:18
SS:5
RESET:21
Простейшие web серверы работают. С этим проблем нет.
Но если брать большую страницу, то нужно внешнее хранилище. SPIFFS, в данном случае.
А вот тут затык. Не работает одновременно spiffs и ethernet.
Точнее функция streamfile (Код ниже). Соединение устанавливается, а данные не идут. Ни одного байта. Всё тоже самое через wifi работает аж бегом.
Сделал костыль. Читаю сначала файл в строковую переменную, а затем отправляю в полёт. Но всё упирается в размер буфера w5500 - 2кб.
Если файл меньше 2кб - всё работает. Если больше - загружается только первые 2 кб. Фигня короче... Были мысли пауз навтыкать в библиотеку - но это сначала надо в ней разобраться, и потом костыль же... Надо нормальное решение.
Кто-нибудь делал web сервер на esp32 + ethernet (ЛЮБОЙ!!!). Напишите. Идеи кончились.

C++:
#include <FS.h>  // Библиотека для работы с файловой системой
#include <SPIFFS.h>
#include <SPI.h>
#include <Ethernet.h>
bool tcp_session = false;
bool EthernetUsable = false;  // W5500 found??

String temp;
  char temp2;

//#define W5500_RST_PORT   21
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
#define EthernetLinkUP_Retries  10  //

#include <EthernetWebServer.h>
EthernetWebServer HTTP(80);

void setup()
{

  Serial.begin(115200);                                                   // Инициализируем вывод данных на серийный порт со скоростью 9600 бод
  SPIFFS.begin();                                                       // Инициализируем работу с файловой системой                         
 
  Serial.println("Used/default ESP32 pinout:");
  Serial.print("MOSI:");
  Serial.println(MOSI);
  Serial.print("MISO:");
  Serial.println(MISO);
  Serial.print("SCK:");
  Serial.println(SCK);
  Serial.print("SS:");
  Serial.println(SS);
  //  Serial.println(RST);
  Serial.print("Reset:");
  //Serial.println(W5500_RST_PORT);

  SPI.begin();

  Serial.println("Resetting WizNet for consistent results");
 // pinMode(W5500_RST_PORT, OUTPUT);
 // digitalWrite(W5500_RST_PORT, LOW);
 // delayMicroseconds(500);
 // digitalWrite(W5500_RST_PORT, HIGH);
  delayMicroseconds(1000);

  Ethernet.init(SS);

  Serial.println("Starting ethernet");
  // https://www.arduino.cc/en/Reference/EthernetBegin
  // Ethernet.begin takes about 60 seconds when cable is not connected ...... This is not always acceptable..
  // https://stackoverflow.com/questions/8530102/ethernet-begin-blocks-for-60-seconds-if-theres-no-ethernet-cable
  // DHCP seems to hold a 60 second timeout....
  Ethernet.begin(mac);
  //Ethernet.begin(mac,ip);
  //delay(1000);
  vTaskDelay(1000 / portTICK_RATE_MS);

  switch (Ethernet.hardwareStatus()) {
    case EthernetNoHardware:
      Serial.println("Ethernet Hardware was not found, can't continue...");
      EthernetUsable = false;
      break;
    case EthernetW5100:
      Serial.println("W5100 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5200:
      Serial.println("W5200 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5500:
      Serial.println("W5500 hardware found");
      EthernetUsable = true;
      break;
    default:
      Serial.print("Undefined hardware found:");
      Serial.println(Ethernet.hardwareStatus());
      Serial.print("No Hardware value::");
      Serial.println(EthernetNoHardware);
      EthernetUsable = false;  // not acceptable

      break;
  }

  int retries = 0;
  do {
    //delay(500);
    vTaskDelay(500 / portTICK_RATE_MS);

    switch (Ethernet.linkStatus()) {
      case Unknown:
        Serial.println("Unknown link status");
        EthernetUsable = false;
        break;
      case LinkOFF:
        Serial.println("LinkOFF");
        EthernetUsable = false;
        break;
      case LinkON:
        Serial.println("LinkON");
        EthernetUsable = true;
        break;
      default:
        EthernetUsable = false;
        Serial.println("Undefined link status");
    }
  } while ( (Ethernet.linkStatus() != LinkON ) && retries++ < EthernetLinkUP_Retries );


  if (EthernetUsable == true) {
    // https://www.pjrc.com/arduino-ethernet-library-2-0-0/
    Serial.print("LocalIP:");
    Serial.println(Ethernet.localIP());

    Serial.print("GW:");
    Serial.println(Ethernet.gatewayIP());

    Serial.print("Subnet Netmask:");
    Serial.println(Ethernet.subnetMask());

    Serial.print("DNS Server IP:");
    Serial.println(Ethernet.dnsServerIP());

    //Serial.print("MAC:");
    //Serial.println(Ethernet.MACAddress());

  }

  HTTP.begin();

 HTTP.on("/", [](){                                       
    if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
      HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)                 
  });




  HTTP.on("/index.html", [](){                                       
    if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
      HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)                 
  });

  HTTP.onNotFound([](){                                                 // Описываем действия при событии "Не найдено"
  if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
      HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)
  });

}

void loop() {
    HTTP.handleClient(); 
}

bool handleFileRead(String path){                                       // Функция работы с файловой системой

  String temp;   //ЭТО КОСТЫЛЬ!!!!!!!!!!!!!!!!
  char temp2;    //И ЭТО ТОЖЕ!!!!!!!!!!!!!!!!!
  //Serial.println(HTTP.uri());
  if(path.endsWith("/")) path += "index.html";                          // Если устройство вызывается по корневому адресу, то должен вызываться файл index.html (добавляем его в конец адреса)
  String contentType = getContentType(path);                            // С помощью функции getContentType (описана ниже) определяем по типу файла (в адресе обращения) какой заголовок необходимо возвращать по его вызову
  if(SPIFFS.exists(path)){                                              // Если в файловой системе существует файл по адресу обращения
    File file = SPIFFS.open(path, "r");                                 //  Открываем файл для чтения
    Serial.print("path=");
    Serial.println(path);
    Serial.print("filesize=");
    Serial.println(file.size());
    Serial.print("content=");
    Serial.println(contentType);
    while(file.available())
    {
        temp2=file.read();        //ЭТО КОСТЫЛЬ!!!!!!!!!!!!!
        //Serial.write(temp2);
        temp=temp+temp2;
    }
    HTTP.send(200, contentType, temp);     //ЭТО КОСТЫЛЬ!!!!!!!!!!!
    //size_t sent = HTTP.streamFile(file, contentType);  //ДОЛЖО БЫТЬ ТАК!!!!!!!!!       //  Выводим содержимое файла по HTTP, указывая заголовок типа содержимого contentType
    file.close();                                                       //  Закрываем файл
    return true;                                                        //  Завершаем выполнение функции, возвращая результатом ее исполнения true (истина)
  }
  return false;                                                         // Завершаем выполнение функции, возвращая результатом ее исполнения false (если не обработалось предыдущее условие)
}

String getContentType(String filename){                                 // Функция, возвращающая необходимый заголовок типа содержимого в зависимости от расширения файла
  if (filename.endsWith(".html")) return "text/html";                   // Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
  //if (filename.endsWith(".html")) return "text/plain";                   // Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
  else if (filename.endsWith(".css")) return "text/css";                // Если файл заканчивается на ".css", то возвращаем заголовок "text/css" и завершаем выполнение функции
  else if (filename.endsWith(".js")) return "application/javascript";   // Если файл заканчивается на ".js", то возвращаем заголовок "application/javascript" и завершаем выполнение функции
  else if (filename.endsWith(".png")) return "image/png";               // Если файл заканчивается на ".png", то возвращаем заголовок "image/png" и завершаем выполнение функции
  else if (filename.endsWith(".jpg")) return "image/jpeg";              // Если файл заканчивается на ".jpg", то возвращаем заголовок "image/jpg" и завершаем выполнение функции
  else if (filename.endsWith(".gif")) return "image/gif";               // Если файл заканчивается на ".gif", то возвращаем заголовок "image/gif" и завершаем выполнение функции
  else if (filename.endsWith(".ico")) return "image/x-icon";            // Если файл заканчивается на ".ico", то возвращаем заголовок "image/x-icon" и завершаем выполнение функции
  return "text/plain";                                                  // Если ни один из типов файла не совпал, то считаем что содержимое файла текстовое, отдаем соответствующий заголовок и завершаем выполнение функции
}
 

dmitrodev

New member
Нашли решение проблемы? У меня стоит такая же задача, так же сижу и бьюсь над проблемой! Буду благодарен за информацию
 

workpage

New member
Нашли решение проблемы? У меня стоит такая же задача, так же сижу и бьюсь над проблемой! Буду благодарен за информацию
Дружище, послушай мой совет. Выкидывай этот 5500 в помойку. Я потратил три недели, но так и не заставил его нормально работать.
Передел проект на lan8720. Это официально рекомендованный чип для esp. Полная программная поддержка. Да да. Webserver.h завелся с полтычка со всеми его плюшками. Через час у меня уже всё работало.
Небольшое дополнение. 8720 Ооочень капризный в плане разводки печатной платы. Нельзя отступать от мануала ни на йоту.
 

dmitrodev

New member
Спасибо за совет. Так и сделаю. Еще бы ссылку на мануал по подключению) если не трудно
 

workpage

New member
Спасибо за совет. Так и сделаю. Еще бы ссылку на мануал по подключению) если не трудно
Смотри тут:
и тут
Настоятельно рекомендую использовать тактирование от GPIO17.
Этим мы освобождаем GPIO0 для последующего прораммирования. Кварц при этом надо отключать...
 

dmitrodev

New member
Огромное спасибо! Запустил от 17. AsyncWebServer заработал без единого изменения!!!
 

Evgeni61

New member
Простейшие web серверы работают. С этим проблем нет.
Здравствуйте. А подскажите пожалуйста какую библиотеку вы использовали. У меня что то не компилируется с родной <Ethernet.h>?
C++:
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177);

EthernetServer server(80);

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  //Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);     // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
    Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.println("Ethernet WebServer Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}
 
Сверху Снизу