В свободное время если лень не одалеет попробую потестить...

cpp
#ifdef SAVE_MODE
uint32_t min_delay = 1; // 1 мс (1000 проверок/сек)
uint32_t max_delay = 1024; // 1024 мс
uint32_t critical_size = 3072; // 75% FIFO
#endif
При непрерывном потоке данных на максимальной скорости:
#ifdef SAVE_MODE
uint32_t min_delay = 0.5; // 0.5 мс (2000 проверок/сек)
uint32_t max_delay = 1024;
uint32_t critical_size = (SIZE_FIFO / 4) * 3;
#endif
cpp
#include <freertos/queue.h>
// Создаём очередь для UART событий
QueueHandle_t uart_queue;
uart_event_t event;
void setup() {
// Настройка прерываний UART
uart_driver_install(UART_NUM_0, SIZE_FIFO, SIZE_FIFO, 20, &uart_queue, 0);
}
// Задача для UART
void serial_reader_task(void* param) {
for (;
{
if (xQueueReceive(uart_queue, &event, portMAX_DELAY)) {
if (event.type == UART_DATA) {
size_t len = event.size;
uart_read_bytes(UART_NUM_0, buffer, len, portMAX_DELAY);
SerialBT.write(buffer, len);
}
}
}
}
Даже при частоте опроса 2000 Гц (каждые 0.5 мс) нагрузка на ядро составит:
(2000 * 50) / 240 000 000 ≈ 0.04%
Ресурсов более чем достаточно для уменьшения задержки.
Но ИИ может насоветовать так что вообще ничего работать не будет..)))
2 ядра больше жрут. Замерить бы потребление и температуру в 2 и 1 ядерном режиме. Ну а причину можно примерно понять прогнав код через ИИа китайматик на прошивке с 2 процессами иногда задумывается. причину надо еще выяснить.
Анализ скорости и частоты опроса для ESP32
Исходные данные:- Скорость UART: 921600 бод (115200 * 8)
- Тактовая частота ESP32: 240 МГц
- Размер FIFO: 4096 байт (SIZE_FIFO)
- Режим: SAVE_MODE с динамической задержкой
1.
- Битрейт UART: 921600 бит/с
- Байтрейт (с учётом старт/стоп-битов):
- 1 байт = 10 бит (8 данных + 1 старт + 1 стоп)
- Максимальная скорость:
921600 / 10 = 92160 байт/с ≈ 92.16 КБ/с
2.
Чтобы не терять данные, ESP32 должна успевать обрабатывать каждый байт.- Время передачи 1 байта:
1 / 92160 ≈ 10.85 мкс - Минимальная частота опроса:
1 / 10.85 мкс ≈ 92.16 кГц
(92 тысячи проверок в секунду)
3.
Ваш код использует динамические задержки для балансировки нагрузки:cpp
#ifdef SAVE_MODE
uint32_t min_delay = 1; // 1 мс (1000 проверок/сек)
uint32_t max_delay = 1024; // 1024 мс
uint32_t critical_size = 3072; // 75% FIFO
#endif
- При заполнении буфера > 75%:
Задержка уменьшается до 1 мс (частота опроса ≈ 1000 Гц). - При отсутствии данных:
Задержка увеличивается до 1024 мс (частота ≈ 0.98 Гц).
4.
- Теоретически требуется: 92.16 кГц
- Реализовано: до 1 кГц (при min_delay=1 мс)
- Разница: в 92 раза меньше требуемой частоты!
При непрерывном потоке данных на максимальной скорости:
- Буфер FIFO (4096 байт) заполнится за:
4096 / 92160 ≈ 44.4 мс - За это время задача выполнится всего ~44 раза (1 раз/мс), что недостаточно для своевременной очистки буфера.
5.
Чтобы успевать обрабатывать данные, нужно:- Уменьшить min_delay до 0.25-0.5 мс (2000-4000 проверок/сек)
- Использовать прерывания вместо опроса
Вариант 1: Уменьшение задержки
cpp#ifdef SAVE_MODE
uint32_t min_delay = 0.5; // 0.5 мс (2000 проверок/сек)
uint32_t max_delay = 1024;
uint32_t critical_size = (SIZE_FIFO / 4) * 3;
#endif
Вариант 2: Прерывания (рекомендуется)
Заменяем активный опрос на события:cpp
#include <freertos/queue.h>
// Создаём очередь для UART событий
QueueHandle_t uart_queue;
uart_event_t event;
void setup() {
// Настройка прерываний UART
uart_driver_install(UART_NUM_0, SIZE_FIFO, SIZE_FIFO, 20, &uart_queue, 0);
}
// Задача для UART
void serial_reader_task(void* param) {
for (;
if (xQueueReceive(uart_queue, &event, portMAX_DELAY)) {
if (event.type == UART_DATA) {
size_t len = event.size;
uart_read_bytes(UART_NUM_0, buffer, len, portMAX_DELAY);
SerialBT.write(buffer, len);
}
}
}
}
6.
- Тактовая частота ESP32: 240 МГц
- Один цикл задачи: ~50 тактов (оптимизированный код)
- Проверок в секунду:
240 000 000 / 50 = 4 800 000 (4.8 МГц)
Даже при частоте опроса 2000 Гц (каждые 0.5 мс) нагрузка на ядро составит:
(2000 * 50) / 240 000 000 ≈ 0.04%
Ресурсов более чем достаточно для уменьшения задержки.
Рекомендации:
- Уменьшите min_delay до 0.5 мс:
cpp
uint32_t min_delay = 0.5; // Для pdMS_TO_TICKS(0.5)- Убедитесь, что configTICK_RATE_HZ = 1000 в FreeRTOSConfig.h
- Используйте прерывания UART вместо Serial.available():
- Это исключит потерю данных и снизит нагрузку на CPU.
- Протестируйте пропускную способность:
cpp
// В конец задач добавьте:
static uint32_t counter = 0;
if (++counter % 1000 == 0) {
printf("Bytes sent: %d\n", bytesWrite);
}
Но ИИ может насоветовать так что вообще ничего работать не будет..)))