AsyncWebServer дает сброс wdt
Я использую 3 модуля Esp32. Один из них является хозяином, а два других-узлами. Узлы подключаются к AP мастера. Мастер соединен с модулем GSM для выполнения веб-api. Master esp имеет асинхронный веб-сервер, который принимает HTTP-запросы от узлов и выполняет соответствующий веб-api. Этот веб-api возвращает результат, и, наконец, этот результат отправляется обратно узлу в качестве ответа на http-запрос.
Во время выполнения этого кода случайно по любому запросу я сталкиваюсь с сбросом wdt.
Поэтому мой вопрос заключается в том, как я должен обрабатывать сбросы wdt и поддерживать мягкую работу моей программы.
E (32706) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (32706) task_wdt: - async_tcp (CPU 0/1)
E (32706) task_wdt: Tasks currently running:
E (32706) task_wdt: CPU 0: IDLE0
E (32706) task_wdt: CPU 1: async_tcp
E (32706) task_wdt: Aborting.
abort() was called at PC 0x400e1cc3 on core 0
Backtrace: 0x4008c434:0x3ffbe170 0x4008c665:0x3ffbe190 0x400e1cc3:0x3ffbe1b0 0x40084771:0x3ffbe1d0 0x4016aaf3:0x3ffbc0d0 0x400e307a:0x3ffbc0f0 0x4008a361:0x3ffbc110 0x40088b7d:0x3ffbc130
Мой фрагмент кода приведен ниже,
Мастер
HttpClient http(gsmClient, "www.mydummyserver.com", 80);
AsyncWebServer server(80);
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
IPAddress ip(192,168,5,2);
IPAddress gateway(192,168,5,1);
IPAddress subnet(255,255,255,0);
const char* PARAM_MESSAGE = "message";
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
delay(100);
WiFi.softAPConfig(ip, gateway, subnet);
WiFi.softAP(ssid, password);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", "Hello, world");
});
server.on("/myApi", HTTP_POST, [] (AsyncWebServerRequest *request) {
String message;
if (request->hasParam(PARAM_MESSAGE)) {
message = request->getParam(PARAM_MESSAGE)->value();
} else {
message = "Сообщение не отправлено";
}
http.setTimeout(20000);
String postData = "Param1=abcd&Param2=pqrs";
http.beginRequest();
http.post("http://www.mydummyserver.com/testapi.php");
http.sendHeader("Content-Type", "application/x-www-form-urlencoded");
http.sendHeader("Content-Length", postData.length());
http.beginBody();
http.print(postData);
http.endRequest();
int statusCode = http.responseStatusCode();
String response = http.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
request->send(200, "text/plain", "Response: " + message);
});
server.onNotFound(notFound);
server.begin();
}
void loop() {
}
Узел
HTTPClient httpClient;
void setup() {
Serial.begin(115200);
WiFi.begin("ESP32-Access-Point", "123456789");
Serial.print("WiFi ");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(10);
}
Serial.println("connected:" + WiFi.SSID());
}
void executeApi() {
Serial.println("Executing Api...");
httpClient.setTimeout(20000);
httpClient.begin("http://192.168.5.2/myApi");
httpClient.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
String contentStr = "Param1=abcd&Param2=pqrs";
int httpResponseCode = httpClient.POST(contentStr);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
httpClient.end();
}
String cmd = "";
void loop() {
if (Serial.available() > 0) {
cmd = (Serial.readStringUntil('\n'));
if (cmd.length() > 0) {
if (cmd == "api") {
executeApi();
}
}
}
}
Для sulutions я пробовал следующие вещи,
а. Я попытался записать это в функцию loop ().
while(true){
delay(1);
}
б. Попытался отключить wdt
disableCore0WDT()
disableCore1WDT()
но ни один из них не дает хороших результатов.
@java bee, 👍3
Обсуждение2 ответа
Следующие рекомендации, так как вы предоставляете недостаточно актуальной информации
- Установите дешифратор ESP-exeption и проанализируйте свой обратный след - разместите его здесь, чтобы мы увидели, что вызвало неопределенность wdt
- Асинхронный веб - сервер, как правило, вызывает такое поведение, если ответ, как правило, занимает много времени (), иногда помогает предотвратить это поведение-для анализа вам нужен дешифратор ESP-exeption
- поскольку loop() выполняется в core1, некоторое/отсутствие процесса (простоя) в core0 вызвало такое поведение. Вы не можете найти назначение задач ядрам, выполняемое вручную, чтобы распределить задачи (или отправить yield (), приуроченное к core0, для сброса wdt
- установка тайм-ау в сочетании со сном/глубоким сном (хотя вы, похоже, их не используете) также является причиной сброса wdt
- хитрость состоит в том, чтобы установить
CONFIG_ASYNC_TCP_USE_WDT 0
, но это нормально для тестирования
Если вы посмотрите на async_tcp возможного виновника, вы увидите одну строку
xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3,
&_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
Вот пример того, как я использую его, чтобы предотвратить сброс wdt
в настройках()
disableCore0WDT();
disableCore1WDT();
disableLoopWDT(); // Вы забыли об этом !
и из-за этой процедуры в библиотеке async_tcp
static void _async_service_task(void *pvParameters){
lwip_event_packet_t * packet = NULL;
for (;;) {
if(_get_async_event(&packet)){
#if CONFIG_ASYNC_TCP_USE_WDT
if(esp_task_wdt_add(NULL) != ESP_OK){
log_e("Failed to add async task to WDT");
}
#endif
_handle_async_event(packet);
#if CONFIG_ASYNC_TCP_USE_WDT
if(esp_task_wdt_delete(NULL) != ESP_OK){
log_e("Failed to remove loop task from WDT");
}
#endif
}
}
vTaskDelete(NULL);
_async_service_task_handle = NULL;
}
Я установил CONFIG_ASYNC_TCP_USE_WDT 0
, и до сих пор это работает.
Привет .. спасибо за подробное предложение. я тоже пробовал это, но все равно происходит та же ошибка, можете ли вы помочь мне больше ?, @java bee
также, когда я вставляю следующую ошибку, о которой я упоминал в вопросах, в декодере исключений она ничего не печатает.. Я предполагаю, что исключение четко указывает на проблему без каких-либо следов., @java bee
Вы должны вставить часть, начинающуюся после обратного хода: ==>0x4 до конца в код, в котором невозможно ничего сохранить, поэтому последовательность компилируется и загружается, последовательный пользователь ждет, пока ошибка не скопирует и не вставит кодер обратного хода ESP ->> скопируйте результат, ЧЕМ опубликуйте свой вопрос (редактировать!) Спасибо, @Codebreaker007
Привет. Я вставил вопрос о том, что показывает мой последовательный монитор. Кроме этого, никаких других данных об ошибках последовательный монитор не показывает., @java bee
ЕСЛИ ВАМ НУЖНА ПОМОЩЬ, мне нужно то, что я опубликовал выше, вы должны сделать это в своей среде, так как я не могу расшифровать обратный путь без вашего файла elf и всех ваших настроек/библиотек/пути/версии и т.д. - Пожалуйста, помогите мне помочь вам, @Codebreaker007
Короткий ответ
увеличить размер _async_queue в AsyncTCP.cpp
_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
от 32 до 64 или даже выше, если вы можете сэкономить место
Подробное (но, возможно, неверное) объяснение:
Посмотрев на вызовы ОС, я обнаружил, что в AsyncTCP.cpp
Очередь событий создается как:
_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
Позже элементы добавляются с тайм-аутом портаMAX_DELAY, например:
static inline bool _send_async_event(lwip_event_packet_t ** e){
return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS;
}
Поскольку (по крайней мере, при использовании AsyncWebserver) и постановка в очередь, и удаление из очереди выполняются для одной и той же задачи (async_tcp), как только в очереди будет 32 события в момент добавления следующего события, задача будет заблокирована на неопределенный срок, что приведет к срабатыванию TWDT.
Таким образом, решение может заключаться в том, чтобы поставить/удалить события из очереди в разных задачах (возможно, так и задумано, поскольку это уже очередь ОС) или увеличить размер очереди до значения, которое не будет достигнуто. Поскольку элементы очереди не такие большие, я просто увеличил их до 256, чтобы быть в безопасности.
Я не уверен, что это объяснение правильное, так как я не могу найти код, в котором async_tcp передает или отключает сторожевой таймер во время нормальной работы. Поэтому, если кто-то знает, как это работает, и может рассказать мне, я был бы очень признателен.
Спасибо PiffPoff, увеличение размера очереди до 256 в AsyncTCP.cpp очень помогло избавиться от ошибки ниже: > E (705728) task_wdt: Сработал сторожевой таймер задачи. Следующие задачи > вовремя не сбросил сторожевой таймер: E (705728) task_wdt: — async_tcp > (ЦП 0/1) **AsyncTCP.cpp** _async_queue = xQueueCreate(256, sizeof(lwip_event_packet_t *)); **Конфигурация** ESP32-S3 8 Мб PSRAM 16 Мб Flash Ардуино IDE ядро arduino-esp32 2.0.8 Режим Wi-Fi: точка доступа, @06userit
- esp32 Stack canary watchpoint срабатывает
- ESP32S v1.1 NodeMCU vs ESP32 DevKitV1
- esp32-cam публикует изображение в mqtt
- WindowsError(31, "Устройство, подключенное к системе, не функционирует") в arduino
- Как очистить кучу памяти в esp32
- ESP-NOW и Wi-Fi, и OTA одновременно на Отправителе и Получателе
- PN532 не обнаруживает RFID-карту при подключении к ESP32 в режиме I2C, но отлично работает с Arduino Uno
- HTTP POST от Arduino/ESP8266/ESP32 Как отправлять параметры (x-www-form-urlencoded)
Как вы проводите GSM модуль с мастером, я не вижу никакого кода в вашем мастере, связанного с настройкой или настройкой для связи с GSM. Есть ли какая-либо причина, по которой конечная точка URL-адреса узла является "testapi", в то время как она не существует на маршруте вашего мастера (у вашего мастера есть обработчик маршрута для конечной точки "MyAPI". является ли ваш узел подключается к веб-серверу непосредственно вместо главного (который является релейным/прокси-сервером)., @hcheung
@hcheung Привет, из-за проблем с конфиденциальностью я не мог поделиться реальными данными. GSM - модуль и ESP соединяются с помощью HardwareSerial. Я исправил ошибку кода для конечных точек URL. Мой узел сначала подключается к мастеру, а затем выполняет API удаленного сервера., @java bee