ESP32-CAM Video Streaming Server Подключение I2C и SPI дисплеев

  • Tutorial
ESP-32 CAM модуль с камерой от Diymore

ESP32-CAM Video Streaming Server


Пример использования находится тут.

Предварительно надо установить библиотеки: Esp32 board in Arduino Ide Windows / Esp32 board in Arduino Ide Linux and Mac

Подробные настройки есть в статье.

В моем случае я использовал модуль AI-THINKER поэтому раскомментировал
#define CAMERA_MODEL_AI_THINKER

У меня не заработала функиональность распознования лиц. Коментарий в статье был полезен.

It seems that face recognition is no longer working (at least with the example program) when using the 1.02 ESP core. Rolling back to the 1.01 core and using the example program belonging to that core, will ‘fix’ it

Откатившись на предыдущую версию библиотеки 1.01 все заработало.


У меня есть пару диспллев I2C 128x64 и TFT SPI 128x128

Cтатья OV7670 with FIFO как подключить камеру к дисплею если у вас не CAM модуль. Support OV2640 and OV7670 cameras

На момент написания статьи у меня заработало следующее

ESP32 camera + Wifi Server + I2C Display (AdaFruit)
ESP32 camera + SPI Display 1.44" TFT 128x128 v1.1 (AdaFruit)
ESP32 camera + SPI Display 1.8" TFT 128*160 (Espressif библиотека)

WiFi драйвер конфликтует с SPI шиной. Возможное решение использовать другую библиотеку. Проблема возникала на моменте инициализации WiFi модуля.

Основная проблема, что модуль ESP32-CAM имеет ограниченное число свободных ног. Часть портов используется для камеры, часть параллельно с sd-card. sd-card разьем установлена на плате. Еще один вывод (IO4) это светодиодный фонарь.

I2C Display B/W не представляет особого интереса для реального использования с изображением полученным с камеры. TFT цветной и с большим разрешением. На нем уже можно рассмотреть лицо. На таком дисплее или чуть с большим разрешением можно сделать Дверной Глазок

Скажу сразу, что библиотека от AdaFruit не самая быстрая. Мне удалось выводить на экран пару кадров в секунду. Перспективнее использовать библиотеки которые работают на низком уровне. Но мне не удалось завести ESP32_TFT_library с моим дисплеем 1.44" 128x128 SPI V1.1. Возможно не поддерживается ILI9163. Я взял 1.8" 128*160 SPI TFT и мне удалось выжать около 12 FPS! Ссылка.

Есть еще пару библиотек которые работают быстрее. Но некоторые не портированы для esp-32 (ссылка):

4.98 sec Adafruit_ST7735
1.71 sec ST7735X_kbv
1.30 sec PDQ_ST7735

Видео выглядит впечатляюще:



При использовании двух портов один из хардварных портов HSPI или VSPI на микроконтроллере и дисплея c драйвером ILI9341 можно получить 30 кадров в секунду (ссылка).



Но как я говорил ранее в модуле ESP32-CAM свободный только один SPI. Он выведен на следующие PINS:

IO2 — DC(A0)
IO14 — CLK
IO15 — CS
IO13 — MOSI (SDA)
IO12 — MISO (Вход. Не используется)

IO0 — BCKL (Подсветка. Не используется)
IO16 — RST





Первую библитотеку, которую я попробовал это AdaFruit SSD1306

I2C 128x64 Blue OLED Display



#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display;

void init_display(){
    pinMode(14,INPUT_PULLUP);
    pinMode(15,INPUT_PULLUP);
    Wire.begin(14,15);
    display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

    ....


camera_capture()
#define BACKCOLOR 0x0000 // Black
#define PIXELCOLOR 0xFFFF  // White

#define FRAME_WIDTH 320
#define FRAME_HEIGHT 240

uint16_t pixel_color = 0;

esp_err_t camera_capture(){
    //acquire a frame
    camera_fb_t * fb = esp_camera_fb_get();
    if (!fb) {
        ESP_LOGE(TAG, "Camera Capture Failed");
        return ESP_FAIL;
    }
  int i = 0;
  
  for(int y = 0; y < SCREEN_HEIGHT; y++){
    for(int x = 0; x < SCREEN_WIDTH; x++){
      i = y * FRAME_WIDTH + x; // FRAMESIZE_QVGA // 320x240
      char ch = (char)fb->buf[i];

      if (ch > 128)
         pixel_color = WHITE;
      else 
         pixel_color = BLACK;

      // Draw a single pixel in white 
      display.drawPixel(x, y, pixel_color);
     }
  }
    display.display();

    //return the frame buffer back to the driver for reuse
    esp_camera_fb_return(fb);
    Serial.println("Capture frame ok.");
    return ESP_OK;
}


При работе в esp32 используется Software I2C эмуляция. Задействованы IO14 и IO15. Можно использовать почти любые свободные порты, используется не H/W шина.

Как подключать Monochrome 0.96" i2c OLED display. Надо обратить внимание на адрес дисплея на шине I2С. В данном случае 0x3С

SPI Display 1.8" TFT 128*160 Espressif библиотека




Схема подключения:

IO2 — A0
IO14 — SCK
IO15 — CS
IO13 — SDA
IO16 — RESET


На плате также расположен SD-card reader

Конфигурация IO:

// Configuration for other boards, set the correct values for the display used
//----------------------------------------------------------------------------
#define DISP_COLOR_BITS_24	0x66
//#define DISP_COLOR_BITS_16	0x55  // Do not use!

// #############################################
// ### Set to 1 for some displays,           ###
//     for example the one on ESP-WROWER-KIT ###
// #############################################
#define TFT_INVERT_ROTATION 0
#define TFT_INVERT_ROTATION1 0

// ################################################
// ### SET TO 0X00 FOR DISPLAYS WITH RGB MATRIX ###
// ### SET TO 0X08 FOR DISPLAYS WITH BGR MATRIX ###
// ### For ESP-WROWER-KIT set to 0x00           ###
// ################################################
#define TFT_RGB_BGR 0x08

// ##############################################################
// ### Define ESP32 SPI pins to which the display is attached ###
// ##############################################################

// The pins configured here are the native spi pins for HSPI interface
// Any other valid pin combination can be used
#define PIN_NUM_MISO 12		// SPI MISO
#define PIN_NUM_MOSI 13		// SPI MOSI
#define PIN_NUM_CLK  14		// SPI CLOCK pin
#define PIN_NUM_CS   15		// Display CS pin
#define PIN_NUM_DC   2		// Display command/data pin
#define PIN_NUM_TCS  0		// Touch screen CS pin (NOT used if USE_TOUCH=0)

// --------------------------------------------------------------
// ** Set Reset and Backlight pins to 0 if not used !
// ** If you want to use them, set them to some valid GPIO number
#define PIN_NUM_RST  0  	// GPIO used for RESET control

#define PIN_NUM_BCKL 0  	// GPIO used for backlight control
#define PIN_BCKL_ON  0  	// GPIO value for backlight ON
#define PIN_BCKL_OFF 1  	// GPIO value for backlight OFF
// --------------------------------------------------------------

// #######################################################
// Set this to 1 if you want to use touch screen functions
// #######################################################
#define USE_TOUCH	TOUCH_TYPE_NONE
// #######################################################

// #######################################################################
// Default display width (smaller dimension) and height (larger dimension)
// #######################################################################
#define DEFAULT_TFT_DISPLAY_WIDTH  128
#define DEFAULT_TFT_DISPLAY_HEIGHT 160
// #######################################################################

#define DEFAULT_GAMMA_CURVE 0
#define DEFAULT_SPI_CLOCK   32000000
#define DEFAULT_DISP_TYPE   DISP_TYPE_ST7735B
//----------------------------------------------------------------------------

#define TFT_INVERT_ROTATION         0
#define TFT_INVERT_ROTATION1        1
#define TFT_INVERT_ROTATION2        0 

Устанавливаем окружение и среду разработки от Espressif. Подробная инструкция как это сделать.

Устанавливаем библиотеку. Нужно внести два исправления, что бы собрать библиотеку.

Makefile:

+ CFLAGS += -Wno-error=tautological-compare \
+         -Wno-implicit-fallthrough \
+		  -Wno-implicit-function-declaration

components/tft/tftspi.c:

+ #include "driver/gpio.h

→ Патч

Затем устанавливаем ESP32 Camera Driver.

Конфигурируем:

#. $HOME/esp/esp-idf/export.sh
#idf.py menuconfig




Разрешаем доступ для USB порта для прошивки и мониторинга:

#sudo chmod 777 /dev/ttyUSB0

Собираем и заливаем:

#make -j4 && make flash

12FPS достигается за счет пакетной записи с помощью метода send_data. Запись идет не попиксельно, а целой линией равной ширине экрана:

esp_err_t camera_capture(){
    uint32_t tstart, t1, t2;
	tstart = clock();
    //acquire a frame
    camera_fb_t * fb = esp_camera_fb_get();
    if (!fb) {
        printf("Camera Capture Failed\n");
        return ESP_FAIL;
    }
    t1 = clock() - tstart;
    printf("Capture camera time: %u ms\r\n", t1);

    int i = 0, bufPos = 0;

    uint8_t hb, lb;
    color_t color;
    color_t *color_line = heap_caps_malloc(_width*3, MALLOC_CAP_DMA);

    tstart = clock();

    for(int y = 0; y < _height; y++)
    {
  	 bufPos = 0;
        for(int x = 0; x < _width; x++)
        {
            i = (y * FRAME_WIDTH + x) << 1;

            hb = fb->buf[i] ;
            lb = fb->buf[i + 1];
      
            color.r = (lb & 0x1F) << 3;
            color.g = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
            color.b =  hb & 0xF8;

            color_line[bufPos] = color;
            bufPos++;
//         TFT_drawPixel(0, 0, color, 1);
       }
       disp_select();
       send_data(0, y, _width-1, y, _width, color_line);
       wait_trans_finish(1);
       disp_deselect();
    }

    free(color_line);

    t1 = clock() - tstart;
    printf("Send buffer time: %u ms\r\n", t1);
    esp_camera_fb_return(fb);
    printf("Capture frame ok.\n");
    return ESP_OK;
}

Конфигурация камеры
// #if defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

void camera_init_(){
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.fb_count = 2;

// for display
  config.frame_size = FRAMESIZE_QVGA;
  config.pixel_format = PIXFORMAT_RGB565;
  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    printf("Camera init failed with error 0x%x", err);
    return;
  }

  printf("Camera init OK\n");
}


Gist

FRAME_WIDTH — это ширина кадра 320 пикселей для QVGA

config.frame_size = FRAMESIZE_QVGA; // 320x240

На самом деле мы видим на дисплее окно 128*160 от полного кадра

Log для конфигурации с одним буфером видеокамеры (config.fb_count=1)
Capture camera time: 32 ms
Send buffer time: 47 ms
Capture frame ok.


Результат
1000 / (32 + 47) = 12.65 FPS


Log для конфигурации с двумя буферами видеокамеры (config.fb_count=2)
Capture camera time: 39 ms

Send buffer time: 63 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 59 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 34 ms

Capture frame ok.
Capture camera time: 40 ms

Send buffer time: 64 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 59 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 34 ms

Capture frame ok.
Capture camera time: 40 ms

Send buffer time: 63 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 60 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 34 ms

Capture frame ok.
Capture camera time: 39 ms

Send buffer time: 63 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 60 ms

Capture frame ok.
Capture camera time: 1 ms

Send buffer time: 34 ms

Capture frame ok.
Capture camera time: 40 ms

Send buffer time: 63 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 60 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 34 ms

Capture frame ok.
Capture camera time: 40 ms

Send buffer time: 63 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 59 ms

Capture frame ok.
Capture camera time: 0 ms

Send buffer time: 35 ms

Capture frame ok.

За счет использования второго буфера видеокамеры, буфер в некоторых циклах получается мгновенно. Вначале полный цикл получается меньше чем с использованием одного буфера, но потом это время «набегает». Интервал между циклами плавает.

Несколько раз я поймал в логах «Brownout detector was triggered» поэтому отключил detector. Потому что сначала я питал подсветку дисплей от вывода 3.3V ESP32-CAM

#include "soc/rtc_cntl_reg.h"
...
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

Заключение


ESP32 недорогой функциональный модуль. Катастрофически не хватает выводов для реализованных портов в CAM версии платы, поэтому выбирайте версию CAM если вам действительно нужна камера.

Похожие публикации

Средняя зарплата в IT

120 000 ₽/мес.
Средняя зарплата по всем IT-специализациям на основании 7 283 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
Реклама
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее

Комментарии 23

    0
    У CAM версии есть жирный плюс в 4 мб PSRAM.
      0

      Это стандарт же
      Есть платы с 16мбайтами, но они дороже и форм-фактор удлиненный.

        0
        Вы путаете. Стандарт — 4 ,8 и 16 мегабайта флеша и ~500 килобайт RAM на самом чипе. Версия с 4 и 8 PSRAM называлась WROVER и стоила значительно дороже
    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        WiFi Server конфликтует с ISP.

        что есть ISP? и что есть WiFi Server?
          0
          ISP в контексте камеры должен быть Image Signal Processor.
            0
            Поправил
              0
              WiFi драйвер конфликтует с ISP шиной.

              да что же это за шина такая? :)))

                0
                Еще раз поравил))
                SPI конечно
            +1
            При использовании двух портов SPI и дисплея c драйвером ILI9341 можно получить 30 кадров в секунду (ссылка).


            Жутко интересно стало, накой два порта, когда у ILI9341 он всего один. Сходил по ссылке, где там два порта используются вообще не увидел.
              0
              Дописал. Так понятно?

                +1

                Наверное я плохо понимаю английский но сия таблица перечисляет выводы spi которые есть у есп32. Как два spi порта есп32 прикрутить к одному spi порту ili9341 решительно не понимаю.
                По той ссылке что приведена читаю следующее:


                1. у есп32 есть четыре spi. два из них доступно для пользовательских применений.
                2. при использовании выводов приведенных в таблице выше возможно их тактирование на частотах до 80 МГц. При переназначении выводов spi через матрицу ввода-вывода тактирование только до 40 МГц.
                3. ili9341 по даташиту может тактироваться по spi максимум — 10 МГц. Но экспериментально умельцы определили что переваривает и больше — в частности для 30 кадров в секунду spi тактируют 48МГц.
                4. Рисуют все программно, благо 240 МГц тактовой хватает.

                Собсно собирая все вместе — для 30 кадров в секунду:
                а) порт spi нужен один, с подключением к строго определенным ногам из hspi или vspi с использованием пдп и настройкой spi на 48МГц;
                б) рисовать придется все софтварно в памяти.

                  0
                  Спасибо за подробное обьяснение

                  Я неправильно интерпретировал
                  2. Make the flushing and rendering parallel


                  И Это
                  They say 48MHz is even possible but it’s still not a big gain compared to the 40 MHz in the previous calculation.
              +2
              Как то если честно мало понятно. Увидел железку, думал объяснят как на ней собрать что нить. И ничего увы не понял.
              0
              А разрешение у камеры-то какое? Ни где не нашел.
                0
                Драйвер поддерживает следующие разрешения

                /*
                 * FRAMESIZE_QQVGA,    // 160x120
                 * FRAMESIZE_QQVGA2,   // 128x160
                 * FRAMESIZE_QCIF,     // 176x144
                 * FRAMESIZE_HQVGA,    // 240x176
                 * FRAMESIZE_QVGA,     // 320x240
                 * FRAMESIZE_CIF,      // 400x296
                 * FRAMESIZE_VGA,      // 640x480
                 * FRAMESIZE_SVGA,     // 800x600
                 * FRAMESIZE_XGA,      // 1024x768
                 * FRAMESIZE_SXGA,     // 1280x1024
                 * FRAMESIZE_UXGA,     // 1600x1200
                 */
                

                ESP-32 поддерживает OV2640 и OV7670 камеру согласно спецификации
                0
                Чёрт, а у меня прямо какая-то беда! ((
                Есть два модуля ESP32-Cam — но оба почему-то работают очень нестабильно.
                Эпизодически — то подвисают целиком, то отваливается стриминг видео — и работат только стил-имидж…
                Причём — никак не могу понять куда копать, шил как разные устройства — и wrower, esp32 dev module. Питание подаётся нормальное — но — «что-то идёт не так». Это дома, в маленькой квартирке, так что с вайфай-сетью проблем нет. Загадка. ((
                Вообщем для меня этот модуль (брал у двух разных продавцов на али) — какие-то проблемные, глючные, сырые.
                Да, прошиваю — (с необходимой коррекцией кода) и из под ардуино иде, и из вижуал студио 2017 vMicro…
                  0
                  Я читал что WiFi на этих модулях работает нестабильно на внутренней антенне
                  Попробуйте подключить внешнюю антенну

                  Не было сообщений в консоли — Brownout detector was triggered?
                  По питанию рекомендуют добавить внешних конденсаторов и не питать ничего с модуля 3.3V

                  habr.com/ru/post/373235

                  Пока не понял в чем дело, но модуль Esp-03 практически не ловит сигнал

                  У меня была аналогичная проблема с этим модулем. Так и не удалось понять, почему керамическая антенна так плохо работает, возможно, на нее влияет расположение дорожек под модулем, или ВЧ излучение от контроллера.
                  Решение удалось найти только одно:
                  После подключения к выводу WIFI_ANT кусочка проволоки длиной 31 мм чувствительность заметно улучшилась, и стала сходной с чувствительностью ESP-01.
                    0
                    Отличная плата!
                    Хочу на ней сделать Ватериус для счетчиков воды без проводов.

                    Есть пара вопросов:
                    1. Сколько потребление у нее в deep sleep? Можно ли отключить камеру «из коробки»?
                    2. Кто-нибудь пробовал менять экспозицию камеры? Год назад это не было реализовано в драйвере =(.

                    Кто хочет помочь — велком!
                      0
                      Счётчик импульсов состоит из двух микросхем. Attiny85 считает импульсы в режиме сна и сохраняет их в EEPROM. Раз в сутки она будит ESP8266 и слушает i2c линию. ESP8266 спрашивает у Attiny85 данные и отправляет их на сервер. После этого ESP8266 засыпает, а Attiny85 продолжает считать-считать-считать...

                      Проект для ESP8266

                      По потреблению в разных режимах сна esp32, есть хорошая статья:

                      Insight Into ESP32 Sleep Modes & Their Power Consumption

                      ESP32 Deep Sleep — 10 микроампер
                      ESP32 Hibernation mode — 2.5 микроампер

                      0
                      Странно, это же перевод (и похоже, машинный) англоязычной статьи, а пометки «перевод» нету :-(
                        0
                        Ссылку на оригинал в студию, пожалуйста

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое