Doom Boy ESP32. Вторая итерация

Так и не дождавшись DoomWatch платы сделал новый заказ с доставкой Fedex. В этот раз развел платы в KiCad. Как ни странна, Kicad понравился даже больше Eagle AutoDesk

82ldllly_prhmctl_d01gc2xv-g.png

Основная цель была попробовать распаять чип esp32d0wdq6. Не сам готовый модуль, а именно отдельно микросхемой с отдельным Flash и PSRAM. Как это сделано и работает, с видеодемками, читаете и смотрите дальше
Здесь можно прочитать про первую итерация платы

Boot


Boot Log
rst:0×1 (POWERON_RESET), boot:0×13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0×00, q_drv:0×00, d_drv:0×00, cs0_drv:0×00, hd_drv:0×00, wp_drv:0×00
mode: DIO, clock div:2
load:0×3fff0030, len:4
load:0×3fff0034, len:7076
load:0×40078000, len:14600
load:0×40080400, len:4160
0×40080400: _init at?:?

entry 0×40080684
I (28) boot: ESP-IDF v4.2-dev-2243-gcf056a7d0-dirty 2nd stage bootloader
I (29) boot: compile time 18:51:57
I (30) boot: chip revision: 1
I (33) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (52) boot.esp32: SPI Speed: 40MHz
I (53) boot.esp32: SPI Mode: DIO
I (53) boot.esp32: SPI Flash Size: 8MB
I (56) boot: Enabling RNG early entropy source…
I (62) boot: Partition Table:
I (65) boot: ## Label Usage Type ST Offset Length
I (73) boot: 0 factory factory app 00 00 00010000 000e8000
I (80) boot: 1 wifidata WiFi data 01 02 000fc000 00004000
I (88) boot: 2 wad unknown 42 06 00100000 004f4000
I (95) boot: End of partition table
I (99) boot_comm: chip revision: 1, min. application chip revision: 0
I (106) esp_image: segment 0: paddr=0×00010020 vaddr=0×3f400020 size=0×38f98 (233368) map
I (216) esp_image: segment 1: paddr=0×00048fc0 vaddr=0×3ffb0000 size=0×07058 (28760) load
I (230) esp_image: segment 2: paddr=0×00050020 vaddr=0×400d0020 size=0×86370 (549744) map
0×400d0020: _stext at?:?

I (468) esp_image: segment 3: paddr=0×000d6398 vaddr=0×3ffb7058 size=0×04ec4 (20164) load
I (478) esp_image: segment 4: paddr=0×000db264 vaddr=0×40080000 size=0×00404 (1028) load
0×40080000: _WindowOverflow4 at /esp/v3.3.2/esp-idf/components/freertos/xtensa/xtensa_vectors.S:1730

I (479) esp_image: segment 5: paddr=0×000db670 vaddr=0×40080404 size=0×12b7c (76668) load
I (538) boot: Loaded app from partition at offset 0×10000
I (538) boot: Disabling RNG early entropy source…
I (549) psram: This chip is ESP32-D0WD
I (551) spiram: Found 64MBit SPI RAM device
I (551) spiram: SPI RAM mode: flash 40m sram 40m
I (555) spiram: PSRAM initialized, cache is in low/high (2-core) mode.
I (562) cpu_start: Pro cpu up.
I (566) cpu_start: Starting app cpu, entry point is 0×4008191c
0×4008191c: start_cpu0_default at /esp/v3.3.2/esp-idf/components/esp32/cpu_start.c:466

I (0) cpu_start: App cpu up.
I (1454) spiram: SPI SRAM memory test OK
I (1462) cpu_start: Pro cpu start user code
I (1462) cpu_start: Application information:
I (1462) cpu_start: Project name: esp32_doom
I (1466) cpu_start: App version: 085f21b-dirty
I (1472) cpu_start: Compile time: Jul 26 2020 18:51:49
I (1478) cpu_start: ELF file SHA256: 9166eca39a0109f9…
I (1484) cpu_start: ESP-IDF: v4.2-dev-2243-gcf056a7d0-dirty
I (1491) heap_init: Initializing. RAM available for dynamic allocation:
I (1498) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (1504) heap_init: At 3FFCF628 len 000109D8 (66 KiB): DRAM
I (1511) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (1517) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (1524) heap_init: At 40092F80 len 0000D080 (52 KiB): IRAM
I (1530) spiram: Adding pool of 4096K of external SPI memory to heap allocator
I (1539) spi_flash: detected chip: generic
I (1543) spi_flash: flash io: dio
I (1548) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (1557) spiram: Reserving pool of 32K of internal memory for DMA/internal allocations

KiCad PCB


В KiCad как мне показалось все проще. На мой вкус конечно. Немного по другому чем в Eagle Autodesk. Главный плюс в том, что нет ограничения на размер платы если не хотите платить за лицензию. Напомню что в Eagle есть ограничение на размер 100×80 мм для бесплатной разработки. Если плата больше надо платить годовую лицензию. По моему, есть также ограничение на количество слоев

3yrxx__p68vwjw0zjvkt132eivg.png

Посмотреть 3D View в Eagle я так и не смог. Надо ставить Eagle Fusion 360. В Kicad это отдельный пункт меню. Хотя может я не там смотрел. В общем можно сказать перешел полностью на KiCad

Разделил все на модули, оставив на главной странице то что связано с ESP32 непосредственно. Сам чип и память
bb2qiinjshvkb1g8tjkwqzjruig.png


Рисовал плату в попыхах. В результате забыл вывести GPIO0. Подвел ее во внешний DAC как MCCLK, а вот вывести на кнопку режима загрузки забыл. Пришлось сдирать лак с дорожки для пайки вывода кнопки. Так же резистор в цепи кварца развел на XTAL_N, а в мануале надо на XTAL_P. Повесил резистор несколько Ом, но можно было и перемычку кинуть

Не развелись резисторы Address и Reset для MCP23017. Чипу можно задать адрес I2C тремя выводами. 0×20h когда все три вывода на земле. Все потому что не указал FootPrint
-ppeleabrgvar2rjc8rbl4xsx_0.png
На ошибку не обратил внимания

Error: Cannot add R10 (no footprint assigned).
Error: Cannot add R9 (no footprint assigned)

Перепутал i2C для ES8374. Бывает и такое. В принципе можно использовать переключив 21 → 22 и 22 → 21 выводы. Или перерезать дорожки и отскоблить лак, ну как это мы обычно делали с TX RX Uart (Грустный смайл)

wzpg0cbwf9yeqremzcoo_8hewpe.png

На удивление запаяв ESP32 и FLASH плата завелась без каких то проблем. Но поставив SPRAM получил бесконечный reboot. Оказался банальный непропай по питанию. Вот бы я искал если ESP32 не припаялся!

r2tlzemho4dbr7nwpkoshhnvpum.jpeg

Мультиплексор MCP23017


Предусмотрел возможность альтернативного опроса кнопок как через мультиплексор MCP23017 так и с помощью ЦАП. На резестивном делителе. Если нет возможности поставить мультиплексор можно задействовать внутренний ADC. По уровню напряжения на входе GPIO34 можно детектировать нажатие кнопки. Минус в том что невозможно опрашивать несколько кнопок одновременно. Плюс соответственно, что не надо дополнительной микросхемы. Только несколько резисторов
nzmuffg36y40wurfduxn-tyu18k.png
Мультиплексор имеет 2 порта по 8 выводов. Один порт, в нашем случае, можно сконфигурировать как выход и повесить на них светодиоды. Хотел предусмотреть мигание если жизни осталось меньше 20% или кончились патроны. Тогда можно будет играть без панели. Получилось реализовать. Остался один зеленый светодиод. Если в комнате нет врагов или в прямой видимости можно подсветить

tj6xg4goybmsixxbgksfmlxvp-0.png
Thread of the health and ammo indicator
void ledTask(void *arg){

    while(1){
            p = &players[cur_player];

            if (p->mo != NULL && p->mo->health < 20) {
                mcp23x17_set_level(&dev, 9, on);
            } else {
                mcp23x17_set_level(&dev, 9, true);
            }

            if(p->ammo[weaponinfo[p->readyweapon].ammo] < 5){
              mcp23x17_set_level(&dev, 10, on);
            } else {
              mcp23x17_set_level(&dev, 10, true);
            }

            printf("p->ammo[am_clip] = %d\n", p->ammo[weaponinfo[p->readyweapon].ammo]);

            if (p->mo != NULL) {
                printf("p->mo->health = %d \n", p->mo->health);
            }

            printf("Ammo N = %d\n", weaponinfo[p->readyweapon].ammo);

             on = !on;
             vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}

Аудио чип ES8374


Для звука, в качестве ЦАП и АЦП применил ES8374. Микросхема содержит встроенный усилитель низкой частоты ~ 1.25 Ватт. Она поддерживается Espressif Audio Development Framework из коробки. В маленьком корпусе QFN-28 получаем Моно ЦАП, АЦП для микрофона и УНЧ с поддержкой SDK. То что надо для такого устройства

xidgj7j-2qavwuulssrnjaaktii.png
Запустил BT Speaker из примера pipeline_bt_sink

Взял в настройках борду lyrat_v4_3. Исправил кодек на AUDIO_CODEC_ES8374_DEFAULT_HANDLE
Настроил порты GPIO

esp_err_t get_i2s_pins(i2s_port_t port, i2s_pin_config_t *i2s_config)
{
    AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL);
    if (port == I2S_NUM_0 || port == I2S_NUM_1) {
        i2s_config->bck_io_num = GPIO_NUM_18;
        i2s_config->ws_io_num = GPIO_NUM_26;
        i2s_config->data_out_num = GPIO_NUM_27;
        i2s_config->data_in_num = GPIO_NUM_35;
    } else {
        memset(i2s_config, -1, sizeof(i2s_pin_config_t));
        ESP_LOGE(TAG, "i2s port %d is not supported", port);
        return ESP_FAIL;
    }
    return ESP_OK;
}


И выкинул инициализацию audio_board_key_init и audio_board_led_init. По правильному надо определять свою кастомную плату

Гироскоп L3GD20


Решил добавить гироскоп L3GD20. Интересная особенность, что его можно подключить как SPI или I2C устройство. R27, R28 в случае подключения по I2C задают адрес

// L3GD20H addresses
#define L3GD20H_I2C_ADDRESS_1 0×6a // SDO pin is low
#define L3GD20H_I2C_ADDRESS_2 0×6b // SDO pin is high

На GitHub есть библиотека l3gd20h-esp-idf

uprbe-xlbjdbkvp9avfi8qanbxa.png
Таким образом на I2C имеем 3 устройства. Управление ADC-DAC ES8374, кнопки на MCP23017 и собственно L3GD20. Запустил все три

i2cdetect

i2c-tools> i2cdetect
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — — — — — — — — — — — — — — — —
10: 10 — — — — — — — — — — — — — — —
20: — — — — 24 — — — — — — — — — — —
30: — — — — — — — — — — — — — — — —
40: — — — — — — — — — — — — — — — —
50: — — — — — — — — — — — — — — — —
60: — — — — — — — — — — 6a — — — — —
70: — — — — — — — — — — — — — — — —

Но почемуто L3GD20 не отдает координаты. WHO_AM_I корректо отвечает 0xd4. углы не меняются. У меня нет конденсатора С1 — 10nF, попытался поставить который нашел самый близкий 100nF. Думал пусть хотя бы врет, но похоже не запускается внутрений преобразователь. И это важно

i2cdump

i2c-tools> i2cdump -c 0×6a
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: b6 5e 81 fc 05 50 31 83 c4 f9 85 d0 48 c6 00 d4?^??? P1??? H?.?
10: 1a 15 16 ea c0 b9 4f 72 07 d8 a1 21 a1 00 14 02??? Or????!.?
20: 07 00 00 80 00 00 0c 00 1a 00 13 00 16 00 00 20?…?…?.?.?.?…
30: 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 …?…
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00…
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00…
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00…
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00…

Дисплей 18 pin ILI9341

syd2iktdkntnnlozfstisdp9fnu.jpeg
Рассчитал ток подсветки так. Требуется 90mA. Поскольку падение на открытом транзисторе ~0.7V питание для светодиодов подсветки 3.3V — 0.7V = 2.6V. И по закону Ома 2.6V / 0.090A = 28.8 Ohm. Поставил 47 Ohm. Получилось немного темновато. Надо будет уменьшить сопротивление
k4qhmxmravel9qs-athp2140nvm.png

Также развел Touch XPT2046TS. SPI выводы повесил параллельно дисплею. XPT_CS выведен отдельным выводом. Есть сомнение что заработает. Если бы дисплей не завелся, сделал бы эксперименты. Для приставки он не особо нужен. Взял из примера

yhu5d84j4zgo274du5wfyj76iyg.png

Демки


Запустил демо LVGL. В настройках примера пробовал выставлять 40MHz для шины SPI. Пример заработал немного быстрее чем на видео

А вот Doom запустился и стабильно работал только на 32MHz. Хотя 26MHz для ILI9341 уже считается разгон

spi_device_interface_config_t devcfg={
        .clock_speed_hz=26000000,               //Clock out at 26 MHz. Yes, that's heavily overclocked.
        .mode=0,                                //SPI mode 0
        .spics_io_num=PIN_NUM_CS,               //CS pin
        .queue_size=NO_SIM_TRANS,               //We want to be able to queue this many transfers
        .pre_cb=ili_spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };

Заключение


Портов ввода вывода ESP32 не всегда хватает чтобы нафаршировать по максимуму. В этом плане STM32 выглядит привлекательнее. Но у нее нет встроенной поддержки Wi-Fi

В заключении отмечу, что на устройстве можно запустить Nintendo эмулятор ESP32-NESEMU, a Nintendo Entertainment System emulator for the ESP32
Я заказал Game Console с Али. Интересно будет посмотреть что там внутри. Возможно тоже ESP32

3fbjmyjctxejgvt0mytwoce6-sy.png

Обсуждение и советы жду в комментариях

© Habrahabr.ru