Montre DOOM sur ESP32. Partie 1

Ayant essayé le développement avec des modules ESP32 prêts à l'emploi, je voulais faire quelque chose de petit et de natif. J'ai décidé de faire une montre. Au début, j'ai pensé à l' ESP32-PICO-D4 . Puisqu'il n'a que 4 Mo de mémoire flash pour le programme, j'ai décidé de faire une version complète avec une extension allant jusqu'à 16 Mo de mémoire flash et 8 Mo de mémoire SRAM. Quelle que soit l'horloge, vous pouvez exécuter le premier Doom. En général, c'était tout à plein!



Ce qui n'a pas été fait ou doit être amélioré:

  1. Indicateur de batterie
  2. Circuit de barrière de charge implémenté sur la diode Schottky
  3. L'antenne n'est pas très bien située sur une autre couche d'ESP32

Pas un tutoriel!



Par affichage




J'ai appliqué un écran couleur sur le contrôleur ST7789 avec une résolution de 240x240. Il est assez compact et bon marché. De plus en plus de pilotes et de ports apparaissent sur le réseau. Par exemple, il y a un port pour LittlevGL , mais il n'y a pas de brouette sur cet affichage. Je pense qu'il peut être acheté et collé. Peut-être que quelqu'un a de l'expérience? Partager.

Je développé une carte sur ST7789 et il a commencé sans aucun problème.



LittlevGL esp32


En remplissant les programmes et en déboguant


J'ai utilisé le convertisseur CP2102 USB-TO-UART BRIDGE . Premièrement, il est compact et deuxièmement, le schéma de connexion est très simple et presque aucune pièce supplémentaire n'est requise.
Option 2: un condensateur de 4,7 μF peut être ajouté si vous alimentez d'autres appareils à partir du régulateur sur puce.
Si vous connectez REGIN et VBUS à une alimentation USB 5V, vous n'aurez besoin que d'un condensateur shunt à l'entrée. Bien que je pense que cela peut fonctionner sans lui. VDD sur une puce dans ce cas est la solution! J'ai fait une erreur et je l'ai connecté au circuit d'alimentation de 3,3 V et je ne pouvais pas comprendre pourquoi j'avais 4.65 V sur l'alimentation?!

Le lien dans la documentation ci-dessous propose des options de connexion à une alimentation de 3,3 V. Mais je pense qu'il n'est absolument pas nécessaire d'alimenter le CP2102 lorsque nous n'avons pas besoin de télécharger ou de déboguer l'appareil



Charge de la batterie Modulo


La résistance du LTC4054 définit le courant de charge:



Nutrition


Alimenté par des piles de 3,7 V avec stabilisateur HT7833. Courant de sortie 500mA. Il a une petite chute de tension de ~ 300mV. LD1117-3.3 en a «un peu» plus.

Une note sur les conclusions de VDD_SDIO. Cette sortie d'alimentation des broches est de 1,8 V ou 3,3 V, selon l'état du microcontrôleur IO12 au démarrage . 3,3 V GPIO12 est 0 (par défaut)
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

C'est très pratique si vous avez un flash 1.8V. Mais dans mon cas, j'ai marqué cette conclusion et connecté mon flash 3V3 et ma PSRAM à l'alimentation générale.

Certains modules ESP32 utilisent VDD_SDIO, donc je ne peux rien accrocher aux périphériques sur IO12 au démarrage. Vous pouvez, par exemple, accrocher un bouton. Dans l'une de mes solutions, j'ai accroché une jambe SPI sur IO12 et le module n'a pas démarré. Apparemment, IO12 a obtenu une unité de ce port SPI, mais j'avais besoin de 0 ou vice versa. Il faut en tenir compte!

Tous ensemble:

image

8 Mo de PSRAM


Prise en charge du module de mise à niveau PSRAM de 8 Mo
pour la RAM externe
PSRAM / CE (broche 1)> ESP32 GPIO 16
PSRAM SO (broche 2)> flash DO
PSRAM SIO [2] (broche 3)> flash WP
PSRAM SI (broche 5)> flash DI
PSRAM SCLK (broche 6)> ESP32 GPIO 17
PSRAM SIO [3] (broche 7)> flash HOLD
PSRAM Vcc (broche 8)> ESP32 VCC_SDIO


Antenne PCB


J'ai utilisé une antenne PCB de petite taille 2,4 GHz . Il se trouve dans la bibliothèque Eagle Autodesk et occupe une petite zone. Vous pouvez probablement utiliser une ANTENNE DIÉLECTRIQUE CÉRAMIQUE mais vous devez l'acheter, et le prix d'une antenne PCB est un peu plus occupé. Cependant, une antenne en céramique est moins efficace. Toute option

Guide de sélection rapide de l' antenne Les directives de conception d'antenne et de disposition RF conviennent pour vérifier le concept.

image



Un peu sur l'adaptation de l'antenne




Les directives de conception matérielle ESP32 à la page 7 fournissent des directives pour la mise en œuvre d'un filtre RF:
L'impédance de sortie des broches RF d'ESP32 (QFN 6 * 6) et d'ESP32 (QFN 5 * 5) est de (30 + j10) Ω et (35 + j10) Ω, respectivement
Pour calculer, utilisez l' Outil de graphique Smith en ligne . L'idée principale est d'arriver au centre du cercle à (30 + j10). Cependant, il s'agit de données calculées et l'utilisation réelle des paramètres peut être affectée par l'épaisseur des pistes et du PCB, ainsi que par rapport à d'autres composants du circuit.



Ce n'est pas le seul circuit d'adaptation d'antenne. Par exemple, l'adaptation sur la carte esp32-pic est un peu différente:

esp32-pico-kit-v4_schematic

Smith Chart and Impedance Matching L'

emplacement de l'antenne et la zone libre autour d'elle sont également importants. Comme je l'ai écrit plus tôt, dans mon cas, la position n'est pas sélectionnée de manière optimale. Mais pour la première itération de la carte et la vérification du concept, la



deuxième partie sera consacrée à la carte elle-même et au troisième portage du logiciel. Peut-être que tout tient en un.

Je vais prendre un peu d'avance sur le port Doom d'Espressif Systems. Le port utilise ILI9341, nous avons ST7789. Mais comme l'initialisation et la sortie du tampon sont extraites dans un fichier séparé et divisées en méthodes distinctes, l'adaptation à mon affichage ne devrait pas poser de grandes difficultés.

  • Ili_init et displayTask sont responsables de l'initialisation de l'affichage
  • DisplayTask est responsable de l'affichage.

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--;
		}
	}
}


Vidéo de démonstration rapide Esp32-Doom



La commande de la carte a été envoyée à l'usine Jlcpcb.

Le défi est lancé!

All Articles