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 заработал без единого изменения!!!
 
Сверху Снизу