DOOM Mira en ESP32. Parte 1

Después de haber intentado el desarrollo con módulos ESP32 listos para usar, quería hacer algo pequeño y nativo. Decidí hacer un reloj. Al principio pensé en el ESP32-PICO-D4 . Como solo tiene 4Mb flash para el programa, decidí hacer una versión completa con una extensión de hasta 16Mb flash y 8Mb SRAM. Cualquiera que sea el reloj, puedes ejecutar el primer Doom. En general, ¡todo eso estaba lleno!



Lo que no se ha hecho o necesita mejorar:

  1. Indicador de bateria
  2. Circuito de barrera de carga implementado en diodo Schottky
  3. La antena no está muy bien ubicada en otra capa de ESP32

No es un tutorial!



Por pantalla




Apliqué una pantalla a color en el controlador ST7789 con una resolución de 240x240. Es bastante compacto y barato. Cada vez aparecen más controladores y puertos en la red. Por ejemplo, hay un puerto para LittlevGL , pero no hay carretilla en esta pantalla. Creo que se puede comprar y pegar. Tal vez alguien tiene experiencia? Compartir

: desarrollé una placa en ST7789 y se inició sin ningún problema.



LittlevGL esp32


Al llenar programas y depurar


He utilizado el CP2102 USB a UART PUENTE convertidor. En primer lugar, es compacto y, en segundo lugar, el diagrama de conexión es muy simple y casi no se requieren piezas adicionales.
Opción 2: se puede agregar un condensador de 4.7 μF si alimenta otros dispositivos desde el regulador en chip.
Si conecta REGIN y VBUS a una fuente de alimentación USB de 5V, solo necesitará un condensador de derivación en la entrada. Aunque creo que puede funcionar sin él. ¡VDD en un chip en este caso es la salida! Cometí un error y lo conecté al circuito de alimentación de 3.3V y no podía entender por qué tengo 4.65V en la fuente de alimentación.

El enlace en la documentación a continuación tiene opciones para conectarse a una alimentación de 3.3V. Pero creo que no hay absolutamente ninguna necesidad de alimentar el CP2102 cuando no necesitamos cargar o depurar el dispositivo



Módulo de carga de la batería


La resistencia en el LTC4054 establece la corriente de carga:



Nutrición


Alimentado por baterías de 3.7V con estabilizador HT7833. Corriente de salida 500mA. Tiene una pequeña caída de voltaje de ~ 300mV. LD1117-3.3 tiene "un poco" más.

Una nota sobre las conclusiones de VDD_SDIO. Esta salida de la fuente de alimentación del pin es de 1.8V o 3.3V, dependiendo del estado del microcontrolador IO12 al inicio . 3.3V GPIO12 es 0 (predeterminado)
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

Esto es muy conveniente si tiene flash de 1.8V. Pero en mi caso, obtuve esta conclusión y conecté mi flash 3V3 y PSRAM a la fuente de alimentación general.

Algunos módulos ESP32 usan VDD_SDIO, por lo tanto, no puedo colgar nada de los periféricos en IO12 al inicio. Puede, por ejemplo, colgar un botón. En una de mis soluciones, colgué una pierna SPI en IO12 y el módulo no se inició. Aparentemente, IO12 obtuvo una unidad de este puerto SPI, pero necesitaba 0 o viceversa. ¡Esto debe tenerse en cuenta!

Todos juntos:

imagen

8MB PSRAM


8MB PSRAM Upgrade Mod
Support para RAM externa
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


Antena pcb


Utilicé una antena PCB de tamaño pequeño de 2,4 GHz . Está en la biblioteca de Eagle Autodesk y ocupa un área pequeña. Probablemente pueda usar ANTENA DIELÉCTRICA CERÁMICA, pero tiene que comprarla, y el precio de una antena PCB es un poco mayor. Sin embargo, una antena de cerámica es menos efectiva. Cualquier opción

Guía rápida de selección de antena Las pautas de diseño de antena y diseño de RF son adecuadas para verificar el concepto.

imagen



Un poco sobre hacer coincidir la antena




Las Pautas de diseño de hardware ESP32 en la página 7 proporcionan pautas para implementar un filtro de RF:
La impedancia de salida de los pines RF de ESP32 (QFN 6 * 6) y ESP32 (QFN 5 * 5) son (30 + j10) Ω y (35 + j10) Ω, respectivamente
Para calcular, use la herramienta en línea Smith Chart . La idea principal es llegar al centro del círculo en (30 + j10). Sin embargo, estos son datos calculados y el uso real de los parámetros puede verse afectado por el grosor de las pistas y la PCB, así como por la ubicación en relación con otros componentes del circuito.



Este no es el único circuito de adaptación de antena. Por ejemplo, la coincidencia en el tablero esp32-pic es un poco diferente:

esp32-pico-kit-v4_schematic

Smith Chart y Impedance Matching La

ubicación de la antena y el área libre a su alrededor también son importantes. Como escribí anteriormente, en mi caso, la posición no está seleccionada de manera óptima. Pero para la primera iteración de la placa y la verificación del concepto, la



segunda parte se dedicará a la placa misma y a la tercera portabilidad del software. Quizás todo encaja en uno.

Avanzaré un poco en el puerto Doom de Espressif Systems. El puerto usa ILI9341, tenemos ST7789. Pero dado que la inicialización y la salida del búfer se extraen en un archivo separado y se dividen en métodos separados, la adaptación a mi pantalla no debería causar grandes dificultades.

  • Ili_init y displayTask son responsables de inicializar la pantalla
  • DisplayTask es responsable de la pantalla.

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 de demostración rápida de Esp32-Doom



El pedido de la placa se ha enviado a la fábrica de Jlcpcb.

¡Desafío lanzado!

All Articles