30 March

DOOM Watch на ESP32. Часть 1

Programming microcontrollersCircuit designManufacture and development of electronicsDIY
Попробовав разработку с готовыми модулями ESP32 захотелось сделать что-то маленькое и нативное. Решил сделать часы. Сначала подумал о ESP32-PICO-D4. Поскольку в ней только 4Mb flash под программу, решил сделать полноценную версию с расширением до 16Mb flash и 8Mb SRAM. Что бы на часах можно запустить первый Doom. В общем чтобы было все на полном фарше!



Что не сделано или требует доработки:

  1. Индикатор батареи
  2. Схема барьера зарядки реализована на Schottky диоде
  3. Антена расположена не совсем удачно и на другом слое от ESP32

Не туториал!



По дисплею




Я применил цветной дисплей на контроллере ST7789 с разрешением 240x240. Он довольно компактный и дешевый. В сети все больше появляется драйверов и портов. Например есть порт для LittlevGL, но на этом дисплее нет тача. Думаю его можно докупить и приклеить. Может у кого-то есть опыт? Поделитесь

Я разработал на ST7789 одну плату и она «завелась» без каких либо проблем



LittlevGL esp32


По заливке программ и debug


Я использовал USB-TO-UART BRIDGE преобразователь CP2102. Во первых он компактный и во вторых схема подключения очень простая и почти не требуется дополнительных деталей.
Option 2: A 4.7 μF capacitor can be added if powering other devices from the on-chip regulator.
Если подключить REGIN и VBUS к питанию USB 5V то потребуется только шунтирующий конденсатор на входе. Хотя думаю может работать и без него. VDD на чипе в этом случае это выход! Я сделал ошибку и подключил его к 3.3V питания схемы и не мог понять почему у меня на питании 4.65V ?!

По ссылке в документации внизу есть варианты подключения к 3.3V питания. Но думаю совершенно не надо питать CP2102 когда нам не надо заливать или дебажить девайс



По модулю зарядки батареи


Резистор на LTC4054 устанавливает ток зарядки:



По питанию


Питание осуществляется от батарей 3.7V со стабилизатором HT7833. Выходной ток 500mA. Он имеет малое ~300mV падение напряжения. LD1117-3.3 имеет «немного» больше.

Замечание про выводы VDD_SDIO. Этот пин выход питания 1.8V или 3.3V в зависимости от того в каком состоянии находится IO12 микроконтроллера при старте. 3.3V GPIO12 is 0 (default)
VDD_SDIO works as the power supply for the related IO, and also for an external device.

When VDD_SDIO operates at 1.8 V, it can be generated from ESP32’s internal LDO. The maximum currentthis LDO can offer is 40 mA, and the output voltage range is 1.65 V~2.0 V.

When the VDD_SDIO outputs 1.8 V, the value of GPIO12 should be set to 1 when the chip boots and it is recommended that users add a2 kΩ ground resistor and a 4.7 mF filter capacitor close to VDD_SDIO.

When VDD_SDIO operates at 3.3 V, it is driven directly by VDD3P3_RTC through a 6Ωresistor, therefore,there will be some voltage drop from VDD3P3_RTC.

When the VDD_SDIO outputs 3.3 V, the value of GPIO12 is 0 (default) when the chip boots and it is recommended that users add a 1mF capacitor close to VDD_SDIO

Это очень удобно если у вас flash 1.8V. Но в моем случае я забил на этот вывод и подключил мою 3V3 flash и PSRAM к общему питанию

Некоторые модули ESP32 используют VDD_SDIO поэтому на IO12 нельзя ничего вешать из перефирии при старте. Можно например повесить кнопку. В одном из моих решений я повесил на IO12 ногу SPI и модуль не стартовал. Видимо на IO12 попала единица с этого порта SPI, а нужен был 0 или наоборот. Это надо учитывать!

All together:

image

8MB PSRAM


8MB PSRAM Upgrade Mod
Support for external RAM
PSRAM /CE (pin 1) > ESP32 GPIO 16
PSRAM SO (pin 2) > flash DO
PSRAM SIO[2] (pin 3) > flash WP
PSRAM SI (pin 5) > flash DI
PSRAM SCLK (pin 6) > ESP32 GPIO 17
PSRAM SIO[3] (pin 7) > flash HOLD
PSRAM Vcc (pin 8) > ESP32 VCC_SDIO


PCB antenna


Я использовал Small Size 2.4 GHz PCB antenna. Она есть в библиотеке Eagle Autodesk и занимает небольшую площадь. Можно наверное применить CERAMIC DIELECTRIC ANTENNA но ее надо покупать, а цена PCB антенны это немного бОльшее занимаемое место. Однако керамическая антенна менее эффективна. Для проверки концепта подойдет любой вариант

Antenna Selection Quick Guide

image

Antenna Design and RF Layout Guidelines

Немного о согласовании антенны




В документации ESP32 Hardware Design Guidelines на стр 7 дается рекомендация по реализации RF фильтра:
The output impedance of the RF pins of ESP32 (QFN 6*6) and ESP32 (QFN 5*5) are (30+j10) Ω and (35+j10) Ω, respectively
Для расчета воспользуемся Online Smith Chart Tool. Основная идея попасть в центр круга при (30+j10). Однако это расчетные данные и на реальное использование параметров может повлиять толщина дорожек и текстолита, а также расположение относительно других компонентов схемы



Это не единственная схема согласования антенны. Например согласование на плате esp32-pic выполнено немного иначе:

esp32-pico-kit-v4_schematic

Smith Chart and Impedance Matching

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



Вторая часть будет посвящена самой плате а третья портированию софта. Возможно все уместится в одну.

Я немного забегу вперед по порту Doom от компании производителя Espressif Systems. В порте применяется ILI9341 у нас ST7789. Но поскольку инициализация и вывод буфера вынесен в отдельный файл и разбит на отдельные методы, адаптация под мой дисплей не должно вызвать большие сложности.

  • За инициализацию дисплея отвечает ili_init и displayTask
  • За отображения на дисплее отвечает displayTask

displayTask
void IRAM_ATTR displayTask(void *arg) {
	int x, i;
	int idx=0;
	int inProgress=0;
	static uint16_t *dmamem[NO_SIM_TRANS];
	spi_transaction_t trans[NO_SIM_TRANS];
	spi_transaction_t *rtrans;

    esp_err_t ret;
    spi_bus_config_t buscfg={
        .miso_io_num=-1,
        .mosi_io_num=PIN_NUM_MOSI,
        .sclk_io_num=PIN_NUM_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=(MEM_PER_TRANS*2)+16
    };
    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
    };

	printf("*** Display task starting.\n");

    //Initialize the SPI bus
    ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
    assert(ret==ESP_OK);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
    assert(ret==ESP_OK);
    //Initialize the LCD
    ili_init(spi);

	//We're going to do a fair few transfers in parallel. Set them all up.
	for (x=0; x<NO_SIM_TRANS; x++) {
		dmamem[x]=pvPortMallocCaps(MEM_PER_TRANS*2, MALLOC_CAP_DMA);
		assert(dmamem[x]);
		memset(&trans[x], 0, sizeof(spi_transaction_t));
		trans[x].length=MEM_PER_TRANS*2;
		trans[x].user=(void*)1;
		trans[x].tx_buffer=&dmamem[x];
	}
	xSemaphoreGive(dispDoneSem);

	while(1) {
		xSemaphoreTake(dispSem, portMAX_DELAY);
//		printf("Display task: frame.\n");
#ifndef DOUBLE_BUFFER
		uint8_t *myData=(uint8_t*)currFbPtr;
#endif

		send_header_start(spi, 0, 0, 320, 240);
		send_header_cleanup(spi);
		for (x=0; x<320*240; x+=MEM_PER_TRANS) {
#ifdef DOUBLE_BUFFER
			for (i=0; i<MEM_PER_TRANS; i+=4) {
				uint32_t d=currFbPtr[(x+i)/4];
				dmamem[idx][i+0]=lcdpal[(d>>0)&0xff];
				dmamem[idx][i+1]=lcdpal[(d>>8)&0xff];
				dmamem[idx][i+2]=lcdpal[(d>>16)&0xff];
				dmamem[idx][i+3]=lcdpal[(d>>24)&0xff];
			}
#else
			for (i=0; i<MEM_PER_TRANS; i++) {
				dmamem[idx][i]=lcdpal[myData[i]];
			}
			myData+=MEM_PER_TRANS;
#endif
			trans[idx].length=MEM_PER_TRANS*16;
			trans[idx].user=(void*)1;
			trans[idx].tx_buffer=dmamem[idx];
			ret=spi_device_queue_trans(spi, &trans[idx], portMAX_DELAY);
			assert(ret==ESP_OK);

			idx++;
			if (idx>=NO_SIM_TRANS) idx=0;

			if (inProgress==NO_SIM_TRANS-1) {
				ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
				assert(ret==ESP_OK);
			} else {
				inProgress++;
			}
		}
#ifndef DOUBLE_BUFFER
		xSemaphoreGive(dispDoneSem);
#endif
		while(inProgress) {
			ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
			assert(ret==ESP_OK);
			inProgress--;
		}
	}
}


Video Esp32-Doom quick demo



Заказ на плату отправлен на фабрику Jlcpcb.

Челендж запущен!
Tags:esp32watchcontrollerdoomeaglecad
Hubs: Programming microcontrollers Circuit design Manufacture and development of electronics DIY
+34
16.2k 68
Comments 22