DOOM Assista no ESP32. Parte 1

Tendo tentado o desenvolvimento com módulos ESP32 prontos, eu queria fazer algo pequeno e nativo. Eu decidi fazer um relógio. No começo, pensei no ESP32-PICO-D4 . Como possui apenas 4Mb de flash para o programa, decidi fazer uma versão completa com uma extensão de até 16Mb de flash e 8Mb de SRAM. Qualquer que seja o relógio, você pode executar o primeiro Doom. Em geral, estava tudo cheio!



O que não foi feito ou precisa ser aprimorado:

  1. Indicador de bateria
  2. Circuito de barreira de carregamento implementado no diodo Schottky
  3. A antena não está muito bem localizada em outra camada do ESP32

Não é um tutorial!



Por exibição




Eu apliquei uma tela colorida no controlador ST7789 com uma resolução de 240x240. É bastante compacto e barato. Mais e mais drivers e portas estão aparecendo na rede. Por exemplo, existe uma porta para o LittlevGL , mas não há carrinho de mão nesta exibição. Eu acho que pode ser comprado e colado. Talvez alguém tenha experiência? Compartilhe

: Desenvolvi uma placa no ST7789 e ela foi iniciada sem problemas.



LittlevGL esp32


Preenchendo programas e depurando


Usei o conversor USB-TO-UART BRIDGE CP2102. Em primeiro lugar, é compacto e, em segundo lugar, o diagrama de conexão é muito simples e quase nenhuma peça adicional é necessária.
Opção 2: Um capacitor de 4,7 μF pode ser adicionado se alimentar outros dispositivos a partir do regulador no chip.
Se você conectar o REGIN e o VBUS a uma fonte de alimentação USB de 5V, será necessário apenas um capacitor shunt na entrada. Embora eu ache que pode funcionar sem ele. VDD em um chip, neste caso, é a saída! Cometi um erro e conectei-o ao circuito de alimentação de 3.3V e não conseguia entender por que tenho 4.65V na fonte de alimentação ?!

O link na documentação abaixo tem opções para conectar a energia de 3,3V. Mas acho que não há absolutamente nenhuma necessidade de ativar o CP2102 quando não precisamos carregar ou depurar o dispositivo



Módulo de carregamento da bateria


O resistor no LTC4054 define a corrente de carregamento:



Nutrição


Alimentado por baterias de 3.7V com estabilizador HT7833. Corrente de saída 500mA. Possui uma pequena queda de tensão de ~ 300mV. LD1117-3.3 tem "um pouco" mais.

Uma observação sobre as conclusões de VDD_SDIO. Essa saída da fonte de alimentação de pinos é de 1,8V ou 3,3V, dependendo do estado do microcontrolador IO12 na inicialização . 3.3V GPIO12 é 0 (padrão)
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

Isso é muito conveniente se você tiver flash de 1,8V. Mas no meu caso, marquei essa conclusão e conectei meu flash 3V3 e PSRAM à fonte de alimentação geral.

Alguns módulos ESP32 usam VDD_SDIO, portanto, não consigo pendurar nada dos periféricos no IO12 na inicialização. Você pode, por exemplo, pressionar um botão. Em uma das minhas soluções, pendurei uma perna SPI no IO12 e o módulo não foi iniciado. Aparentemente, o IO12 recebeu uma unidade dessa porta SPI, mas precisava de 0 ou vice-versa. Isso deve ser levado em consideração!

Todos juntos:

imagem

8MB PSRAM


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


Antena pcb


Usei antena PCB de tamanho pequeno de 2,4 GHz . Está na biblioteca Eagle Autodesk e ocupa uma pequena área. Você provavelmente pode usar a ANTENA DIELÉTRICA CERÂMICA, mas precisa comprá-la, e o preço de uma antena PCB é um pouco mais ocupado. No entanto, uma antena de cerâmica é menos eficaz. Qualquer opção

Guia rápido de seleção de antena Guia de design de antena e layout de RF é adequado para verificar o conceito.

imagem



Um pouco sobre como combinar a antena




As Diretrizes de design de hardware do ESP32 na página 7 fornecem diretrizes para a implementação de um filtro de RF:
A impedância de saída dos pinos de RF do ESP32 (QFN 6 * 6) e ESP32 (QFN 5 * 5) são (30 + j10) Ω e (35 + j10) respectively, respectivamente
Para calcular, use a Online Smith Chart Tool . A idéia principal é chegar ao centro do círculo em (30 + j10). No entanto, esses dados são calculados e o uso real dos parâmetros pode ser afetado pela espessura das faixas e da placa de circuito impresso, bem como pela localização em relação a outros componentes do circuito.Este



não é o único circuito de correspondência da antena. Por exemplo, a correspondência na placa esp32-pic é um pouco diferente:

esp32-pico-kit-v4_schematic Correspondência de

gráfico e impedância de Smith A

localização da antena e a área livre ao redor dela também são importantes. Como escrevi anteriormente, no meu caso, a posição não é selecionada de maneira ideal. Porém, para a primeira iteração da placa e a verificação do conceito, a



segunda parte será dedicada à própria placa e à terceira portabilidade do software. Talvez tudo se encaixe em um.

Vou avançar um pouco na porta Doom da Espressif Systems. A porta usa ILI9341, temos ST7789. Mas como a inicialização e a saída do buffer são realizadas em um arquivo separado e divididas em métodos separados, a adaptação à minha exibição não deve causar grandes dificuldades.

  • Ili_init e displayTask são responsáveis ​​por inicializar a exibição
  • DisplayTask é responsável pela exibição.

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 Demonstração rápida do Esp32-Doom



O pedido do painel foi enviado à fábrica da Jlcpcb.

Desafio lançado!

All Articles