feat(i18n): Spanish localization (phase 4)
Complete implementation of Spanish (es-419) language support: - Canonical catalogs and data: messages/es.json, data/es/**, lib/data/es/**, public/exemplos/es/** - Canonical slugs: /es/series, /es/catalogo, /es/comparacion, /es/componentes, /es/diagnostico, /es/frameworks, /es/glosario, /es/selector, /es/acerca - Dedicated search index at /api/busca/es with Spanish accent normalization - Strict exclusion of book references in Spanish routes and catalogs - Language selector and root negotiation with es active (ENABLED_LOCALES = ['pt', 'en', 'es']) - Extended verification suite: check-i18n, smoke-imagem and verifica-vazamentos Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
1 parent
0940814522
commit
660b28c09d
72 files changed
+17848
-947
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,700 @@
|
||||
/**
|
||||
* Base de datos estructurada para la guía de diagnóstico, errores comunes y solución de problemas en ESP32.
|
||||
* Cubre 6 categorías técnicas con causas raíz, comparación de buenas prácticas vs soluciones temporales y ejemplos de código
|
||||
* en Arduino C++, ESP-IDF (C) y MicroPython.
|
||||
*/
|
||||
|
||||
export const categoriasDiagnostico = [
|
||||
{
|
||||
id: "alimentacao",
|
||||
nome: "Alimentación y Hardware",
|
||||
icone: "Zap",
|
||||
cor: "amber",
|
||||
descricao: "Caídas de tensión por picos de RF Wi-Fi/BLE, pines de strapping en conflicto, ruido electromagnético y problemas de LDO.",
|
||||
},
|
||||
{
|
||||
id: "cpu-panics",
|
||||
nome: "Pánicos de CPU y Guru Meditation",
|
||||
icone: "Cpu",
|
||||
cor: "red",
|
||||
descricao: "Punteros nulos, violaciones de acceso a memoria (Load/StoreProhibited), instrucciones ilegales y pánicos de caché en ISRs.",
|
||||
},
|
||||
{
|
||||
id: "freertos",
|
||||
nome: "FreeRTOS y Multitarea",
|
||||
icone: "Layers",
|
||||
cor: "purple",
|
||||
descricao: "Task Watchdog (TWDT), Interrupt Watchdog (IWDT), desbordamiento de pila (Stack Overflow) y bloqueos del planificador.",
|
||||
},
|
||||
{
|
||||
id: "memoria",
|
||||
nome: "Memoria, Heap y PSRAM",
|
||||
icone: "Activity",
|
||||
cor: "blue",
|
||||
descricao: "Fragmentación del heap, fugas de memoria (Memory Leaks), asignaciones DMA y restricciones de velocidad en PSRAM.",
|
||||
},
|
||||
{
|
||||
id: "boot-flash",
|
||||
nome: "Bootloader y Grabación",
|
||||
icone: "Terminal",
|
||||
cor: "emerald",
|
||||
descricao: "Fallas de comunicación serie (DTR/RTS), errores de lectura en Flash SPI, discrepancia de reloj y particiones corruptas.",
|
||||
},
|
||||
{
|
||||
id: "conectividade",
|
||||
nome: "Conectividad y Protocolos",
|
||||
icone: "Wifi",
|
||||
cor: "cyan",
|
||||
descricao: "Timeouts de baliza Wi-Fi, fallos de handshake TLS/HTTPS por ausencia de reloj SNTP e inestabilidad de señal.",
|
||||
},
|
||||
];
|
||||
|
||||
export const sintomasRapidos = [
|
||||
{ id: "bootloop", rotulo: "🔄 Bucle de arranque (Crash loop)", categoria: "todos" },
|
||||
{ id: "wifi-crash", rotulo: "📶 Se reinicia al activar Wi-Fi/BLE", categoria: "alimentacao" },
|
||||
{ id: "upload-fail", rotulo: "🔌 Fallo al subir firmware (Error de grabación)", categoria: "boot-flash" },
|
||||
{ id: "random-freeze", rotulo: "⏱️ Se congela tras minutos u horas", categoria: "memoria" },
|
||||
{ id: "null-pointer", rotulo: "💥 Guru Meditation (Crash de CPU)", categoria: "cpu-panics" },
|
||||
{ id: "wdt-reset", rotulo: "🐕 Watchdog activado (Reset por TWDT)", categoria: "freertos" },
|
||||
{ id: "tls-fail", rotulo: "🔒 Fallo en conexión HTTPS / SSL", categoria: "conectividade" },
|
||||
];
|
||||
|
||||
export const errosCatalogo = [
|
||||
{
|
||||
id: "brownout-reset",
|
||||
titulo: "Reinicio por detector de Brownout (Caída de tensión)",
|
||||
categoria: "alimentacao",
|
||||
sintomas: ["bootloop", "wifi-crash"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)",
|
||||
resumo: "La tensión de alimentación del ESP32 cayó por debajo del umbral de seguridad (aproximadamente 2.8V ~ 2.43V).",
|
||||
causaRaiz:
|
||||
"Al inicializar las radios Wi-Fi o BLE, el amplificador de potencia (PA) demanda picos de corriente instantáneos superiores a 500 mA en menos de 1 ms. Si la fuente de alimentación, cables USB largos/delgados, pistas de protoboard o el regulador LDO no pueden suministrar esa corriente transitoria con baja impedancia, el voltaje en el riel de 3.3V colapsa momentáneamente, activando el circuito comparador interno de Brownout para evitar la corrupción de la memoria Flash y estados lógicos indefinidos.",
|
||||
gambiarra: {
|
||||
titulo: "Desactivar el detector de Brownout por software",
|
||||
descricao: "Llamar a WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) para suprimir el error en el código.",
|
||||
consequencia: "Extremadamente peligroso: el ESP32 continúa ejecutando instrucciones bajo subtensión, corrompiendo la memoria Flash SPI, bloqueando registros periféricos y causando fallos erráticos en campo sin previo aviso.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Dimensionamiento adecuado de hardware y capacitores de desacoplo",
|
||||
passos: [
|
||||
"Añadir un capacitor de tantalio o cerámico de baja ESR de 10 µF a 100 µF en paralelo con un capacitor cerámico de 100 nF lo más cerca posible de los pines 3V3 y GND del ESP32.",
|
||||
"Utilizar reguladores LDO diseñados para picos de al menos 600 mA a 1 A con excelente respuesta transitoria (ej.: AP2112K, ME6211, TPS73733 o XC6206 robusto). Evitar clones deficientes del AMS1117.",
|
||||
"Evitar alimentar el ESP32 a través de pistas largas de protoboard con cables jumper delgados cuando el Wi-Fi transmite a máxima potencia.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// ¡NO desactive el detector de Brownout! Si necesita reducir picos de corriente en pruebas de banco:
|
||||
#include <WiFi.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Opcional: Reducir ligeramente la potencia máxima de transmisión Wi-Fi de 20dBm a 17dBm recorta los picos de corriente un ~20%
|
||||
WiFi.setTxPower(WIFI_POWER_17dBm);
|
||||
WiFi.begin("SSID", "PASSWORD");
|
||||
}`,
|
||||
codigoEspIdf: `// Configuración en ESP-IDF:
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
void app_main(void) {
|
||||
// En menuconfig: Component config -> ESP32-specific -> Hardware Brownout Reset (Mantener ACTIVADO)
|
||||
// Para mitigar picos transitorios en diseños con restricciones de energía:
|
||||
esp_wifi_set_max_tx_power(68); // 68 = 17dBm (unidades de 0.25dBm)
|
||||
}`,
|
||||
codigoMicroPython: `# Conexión Wi-Fi segura en MicroPython con estabilización de rieles:
|
||||
import network
|
||||
import time
|
||||
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
|
||||
# Esperar a que se estabilicen los rieles antes de activar el transmisor
|
||||
time.sleep_ms(200)
|
||||
wlan.connect("SSID", "PASSWORD")
|
||||
|
||||
attempts = 0
|
||||
while not wlan.isconnected() and attempts < 30:
|
||||
time.sleep_ms(200)
|
||||
attempts += 1`,
|
||||
},
|
||||
{
|
||||
id: "strapping-pins",
|
||||
titulo: "Conflicto en pines de arranque (Strapping Pins) durante el encendido",
|
||||
categoria: "alimentacao",
|
||||
sintomas: ["bootloop", "upload-fail"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "rst:0x10 (RTCWDT_RTC_RESET),boot:0x3 (DOWNLOAD_BOOT(UART/SPI))\nwaiting for download",
|
||||
resumo: "El ESP32 entra inesperadamente en modo de descarga de firmware o falla al arrancar debido a niveles lógicos forzados en los pines de arranque.",
|
||||
causaRaiz:
|
||||
"Durante el reinicio por hardware, el circuito interno muestrea los niveles lógicos presentes en pines específicos (ej.: GPIO0, GPIO2, GPIO12, GPIO15 en ESP32 clásico; GPIO8, GPIO9 en ESP32-C3/C6). Si hay periféricos externos conectados (sensores I2C, tiras LED, relés) que fuerzan estos pines a niveles altos o bajos en el instante del arranque, el chip interpreta que debe entrar en modo de descarga UART o altera el voltaje interno del LDO de la memoria Flash (GPIO12 en 3.3V vs 1.8V), impidiendo la ejecución del código.",
|
||||
gambiarra: {
|
||||
titulo: "Desconectar los cables manualmente antes de cada encendido",
|
||||
descricao: "Retirar los módulos externos cada vez que se reinicia o programa la placa.",
|
||||
consequencia: "Inviable para cualquier producto en producción o gabinete cerrado, propenso a errores humanos y desgaste de conectores.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Aislamiento de pines de arranque o reasignación a GPIOs seguros",
|
||||
passos: [
|
||||
"Reservar los pines de arranque exclusivamente para funciones internas o dejarlos sin conexiones externas permanentes.",
|
||||
"En ESP32 clásico, evitar usar GPIO0, GPIO2, GPIO12 y GPIO15 para cargas externas que contengan resistencias pull-up o pull-down incorporadas.",
|
||||
"Utilizar transistores de aislamiento (búferes tri-state o conmutadores analógicos controlados por un GPIO libre tras el arranque) si es estrictamente necesario compartir esos pines.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Mapeo seguro de pines en Arduino para evitar interferir con strapping:
|
||||
// En ESP32 clásico: usar GPIO16, 17, 18, 19, 21, 22, 23 (libres de strapping)
|
||||
const int PIN_RELE = 22; // SEGURO: GPIO22 no es pin de arranque ni tiene restricciones de boot
|
||||
|
||||
void setup() {
|
||||
pinMode(PIN_RELE, OUTPUT);
|
||||
digitalWrite(PIN_RELE, LOW);
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Configuración de GPIOs fuera de strapping
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#define SAFE_GPIO_OUTPUT GPIO_NUM_22
|
||||
|
||||
void app_main(void) {
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << SAFE_GPIO_OUTPUT),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Asignación limpia a GPIO seguro
|
||||
from machine import Pin
|
||||
|
||||
# Usar GPIO seguro que no interfiera con el ciclo de arranque
|
||||
pin_rele = Pin(22, Pin.OUT, value=0)`,
|
||||
},
|
||||
{
|
||||
id: "guru-load-prohibited",
|
||||
titulo: "Guru Meditation: LoadProhibited / StoreProhibited (Acceso a puntero nulo)",
|
||||
categoria: "cpu-panics",
|
||||
sintomas: ["null-pointer", "bootloop"],
|
||||
gravidade: "Crítica",
|
||||
logSerial: "Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.\nCore 1 register dump:\nPC : 0x400d1234 PS : 0x00060030 A0 : 0x800d1567 A1 : 0x3ffb1230\nA2 : 0x00000000 A3 : 0x3ffb5000",
|
||||
resumo: "La aplicación intentó leer (LoadProhibited) o escribir (StoreProhibited) en una dirección de memoria protegida o puntero nulo (0x00000000).",
|
||||
causaRaiz:
|
||||
"Ocurre cuando el software desreferencia un puntero no inicializado, un puntero nulo devuelto por una función que falló (como malloc sin memoria suficiente o WiFiClient no conectado), o intenta acceder a una estructura de datos ya liberada (use-after-free). Al observar el volcado de registros, si A2 o A3 contienen 0x00000000 o valores cercanos a cero, se confirma la desreferencia nula.",
|
||||
gambiarra: {
|
||||
titulo: "Reinicio automático sin depuración mediante ESP.restart()",
|
||||
descricao: "Configurar el sistema para reiniciar ante fallos sin investigar la causa raíz del crash.",
|
||||
consequencia: "El error persiste en producción, provocando reinicios cíclicos en campo, pérdida de estado de usuario y posibles corrupciones de archivos.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Validación estricta de punteros y decodificación de la traza de llamadas (Backtrace)",
|
||||
passos: [
|
||||
"Comprobar siempre el retorno de funciones de asignación y conexión (ej.: if (ptr == NULL) return;).",
|
||||
"Utilizar la herramienta ESP Exception Decoder en Arduino IDE o 'idf.py monitor' en ESP-IDF para convertir la dirección del PC (Program Counter) y la traza de llamadas en el archivo y número de línea exactos del código fuente.",
|
||||
"Establecer los punteros a NULL tras invocar free() para evitar dobles liberaciones y accesos a memoria caducada.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Práctica segura: Comprobación defensiva de punteros
|
||||
void procesarMensaje(const char *mensaje) {
|
||||
if (mensaje == nullptr) {
|
||||
Serial.println(F("[ERROR] Puntero de mensaje nulo recibido. Operación abortada."));
|
||||
return;
|
||||
}
|
||||
// Procesamiento seguro garantizado
|
||||
Serial.printf("Longitud del mensaje: %d\n", strlen(mensaje));
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Verificación defensiva y aserciones
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
static const char *TAG = "APP_SAFETY";
|
||||
|
||||
esp_err_t inicializar_buffer(char **buf_out, size_t tamano) {
|
||||
ESP_RETURN_ON_FALSE(buf_out != NULL, ESP_ERR_INVALID_ARG, TAG, "Puntero de salida nulo");
|
||||
|
||||
*buf_out = (char *)malloc(tamano);
|
||||
ESP_RETURN_ON_FALSE(*buf_out != NULL, ESP_ERR_NO_MEM, TAG, "Fallo de memoria al asignar buffer");
|
||||
|
||||
return ESP_OK;
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython maneja excepciones en lugar de pánicos de bajo nivel:
|
||||
def procesar_datos(sensor):
|
||||
if sensor is None:
|
||||
print("[WARN] Objeto sensor no inicializado")
|
||||
return None
|
||||
try:
|
||||
return sensor.read()
|
||||
except Exception as e:
|
||||
print("Error en lectura:", e)
|
||||
return None`,
|
||||
},
|
||||
{
|
||||
id: "guru-iram-cache",
|
||||
titulo: "Fallo de caché e InstructionFetchError en rutinas de interrupción (ISRs)",
|
||||
categoria: "cpu-panics",
|
||||
sintomas: ["null-pointer", "random-freeze"],
|
||||
gravidade: "Crítica",
|
||||
logSerial: "Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)\nCore 0 register dump:\nPC : 0x40081234 PS : 0x00060034",
|
||||
resumo: "Ocurrió una interrupción (ISR) mientras la memoria Flash SPI estaba ocupada escribiendo o borrando datos con la caché desactivada.",
|
||||
causaRaiz:
|
||||
"Durante operaciones de escritura o borrado en la memoria Flash SPI (ej.: guardado en NVS, LittleFS o actualizaciones OTA), el controlador de hardware desactiva temporalmente la memoria caché de instrucciones. Si se dispara una interrupción por hardware y su rutina de atención (o cualquier función o constante de cadena a la que llame) reside en la memoria Flash en lugar de la memoria RAM interna (IRAM), la CPU no puede leer la siguiente instrucción y genera un pánico inmediato.",
|
||||
gambiarra: {
|
||||
titulo: "Desactivar interrupciones durante toda la escritura en Flash",
|
||||
descricao: "Bloquear globalmente las interrupciones durante períodos prolongados de escritura.",
|
||||
consequencia: "Genera desbordamientos en búferes de UART, pérdida de paquetes de red Wi-Fi y dispara el Interrupt Watchdog (IWDT).",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Colocar la ISR y sus datos en memoria IRAM y DRAM usando atributos",
|
||||
passos: [
|
||||
"Declarar todas las funciones de interrupción con el atributo IRAM_ATTR (en Arduino/ESP-IDF).",
|
||||
"Evitar llamar a funciones que residan en Flash (como Serial.print, sprintf, malloc o FreeRTOS API estándar sin sufijo FromISR) dentro de la ISR.",
|
||||
"Almacenar constantes accedidas por la ISR con DRAM_ATTR si están fuera de la pila local.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Rutina de interrupción correcta con IRAM_ATTR:
|
||||
volatile uint32_t contadorPulsos = 0;
|
||||
|
||||
void IRAM_ATTR manejarInterrupcion() {
|
||||
// Prohibido usar Serial.print() aquí adentro (reside en Flash)
|
||||
contadorPulsos++;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(4, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(4), manejarInterrupcion, FALLING);
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Rutina ISR segura en IRAM
|
||||
#include "esp_attr.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
static volatile uint32_t pulsos = 0;
|
||||
|
||||
static void IRAM_ATTR gpio_isr_handler(void* arg) {
|
||||
pulsos++;
|
||||
// Usar únicamente APIs de FreeRTOS terminadas en FromISR
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
|
||||
gpio_isr_handler_add(GPIO_NUM_4, gpio_isr_handler, NULL);
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Reservar memoria para excepciones en interrupciones
|
||||
import micropython
|
||||
from machine import Pin
|
||||
|
||||
micropython.alloc_emergency_exception_buf(100)
|
||||
|
||||
contador = 0
|
||||
def handler(p):
|
||||
global contador
|
||||
contador += 1 # Operaciones atómicas y simples únicamente
|
||||
|
||||
pin = Pin(4, Pin.IN, Pin.PULL_UP)
|
||||
pin.irq(trigger=Pin.IRQ_FALLING, handler=handler)`,
|
||||
},
|
||||
{
|
||||
id: "freertos-twdt",
|
||||
titulo: "Reinicio por Task Watchdog Timer (TWDT Timeout en Core 0 o Core 1)",
|
||||
categoria: "freertos",
|
||||
sintomas: ["wdt-reset", "bootloop"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "E (10543) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:\nE (10543) task_wdt: - loopTask (CPU 1)\nE (10543) task_wdt: Tasks currently running on other CPUs:\nE (10543) task_wdt: - IDLE0 (CPU 0)",
|
||||
resumo: "Una tarea de FreeRTOS acaparó la CPU de forma continua durante más de 5 segundos sin ceder tiempo a otras tareas.",
|
||||
causaRaiz:
|
||||
"El planificador de FreeRTOS requiere que las tareas de baja prioridad o la tarea IDLE del sistema se ejecuten periódicamente para alimentar el perro guardián (Watchdog). Si un bucle 'while(1)' o 'for' ejecuta cálculos intensivos o espera una condición sin llamar a vTaskDelay o ceder el procesador (yield), el temporizador del TWDT expira y reinicia el SoC para evitar congelamientos completos.",
|
||||
gambiarra: {
|
||||
titulo: "Aumentar el tiempo del Watchdog a 60 segundos o desactivarlo",
|
||||
descricao: "Elevar el umbral en menuconfig para ocultar el bloqueo de la tarea.",
|
||||
consequencia: "Si el código se congela realmente en campo, el sistema tardará minutos en recuperarse o quedará bloqueado indefinidamente consumiendo batería.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Introducir cesión explícita de CPU (vTaskDelay) o arquitectura dirigida por eventos",
|
||||
passos: [
|
||||
"Añadir al menos 'vTaskDelay(pdMS_TO_TICKS(1))' o 'delay(1)' dentro de cualquier bucle de procesamiento continuo.",
|
||||
"Sustituir bucles de espera activa (polling continuo) por colas de FreeRTOS (xQueueReceive) o semáforos binarios bloqueantes.",
|
||||
"Alimentar manualmente el perro guardián con esp_task_wdt_reset() si se realizan tareas largas inevitables.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Prevención del TWDT en Arduino:
|
||||
void loop() {
|
||||
// Procesamiento pesado:
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
// Procesar elemento...
|
||||
|
||||
// Ceder CPU a la tarea IDLE cada cierto intervalo:
|
||||
if (i % 500 == 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // O delay(1); alimenta el Watchdog
|
||||
}
|
||||
}
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Tarea bloqueante basada en colas (0% consumo de CPU en reposo)
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
static QueueHandle_t colaEventos;
|
||||
|
||||
void tarea_procesadora(void *pvParameters) {
|
||||
int evento;
|
||||
while (1) {
|
||||
// Bloquea indefinidamente hasta recibir datos, cediendo el 100% de la CPU:
|
||||
if (xQueueReceive(colaEventos, &evento, portMAX_DELAY) == pdTRUE) {
|
||||
// Procesar evento de forma segura
|
||||
}
|
||||
}
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Uso de asyncio para evitar bloqueos
|
||||
import uasyncio as asyncio
|
||||
|
||||
async def tarea_pesada():
|
||||
while True:
|
||||
# Ejecutar lógica
|
||||
await asyncio.sleep_ms(10) # Cede el bucle de eventos cooperativo`,
|
||||
},
|
||||
{
|
||||
id: "freertos-stack-overflow",
|
||||
titulo: "Desbordamiento de pila en tarea FreeRTOS (Stack Overflow)",
|
||||
categoria: "freertos",
|
||||
sintomas: ["bootloop", "random-freeze"],
|
||||
gravidade: "Crítica",
|
||||
logSerial: "***ERROR*** A stack overflow in task MiTarea has been detected.\nBacktrace:0x4008b123:0x3ffb7890 0x4008c456:0x3ffb78b0",
|
||||
resumo: "La tarea excedió el espacio de memoria de pila (stack) asignado en su creación, sobrescribiendo variables de otras tareas.",
|
||||
causaRaiz:
|
||||
"Cada tarea de FreeRTOS recibe un bloque fijo de memoria para su pila local. Declarar arreglos o búferes grandes dentro de funciones locales (ej.: char buffer[2048]), anidar llamadas a funciones con múltiples niveles de recursión o invocar bibliotecas pesadas de JSON/TLS puede consumir rápidamente el espacio asignado, rompiendo el centinela (canary) de seguridad al final de la pila.",
|
||||
gambiarra: {
|
||||
titulo: "Asignar 32 KB de pila a todas las tareas indiscriminadamente",
|
||||
descricao: "Colocar valores gigantescos en el parámetro usStackDepth de cada xTaskCreate.",
|
||||
consequencia: "Agotamiento prematuro de la memoria SRAM interna, imposibilitando inicializar conexiones Wi-Fi o crear nuevas tareas.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Medir el margen de pila con uxTaskGetStackHighWaterMark y alojar búferes en el heap",
|
||||
passos: [
|
||||
"Monitorizar periódicamente el remanente mínimo de pila mediante uxTaskGetStackHighWaterMark(NULL).",
|
||||
"Trasladar arreglos de más de 256 bytes fuera de la pila local, asignándolos dinámicamente en el heap (malloc) o de forma estática.",
|
||||
"Dimensionar la pila de tareas que utilicen TLS/HTTPS con un mínimo de 6 KB a 8 KB.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Comprobación de pila remanente en Arduino:
|
||||
void tareaMonitoreada(void *pvParameters) {
|
||||
while (1) {
|
||||
// Lógica de trabajo...
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// Devuelve el número mínimo de bytes libres que le quedaron a la pila:
|
||||
UBaseType_t remanente = uxTaskGetStackHighWaterMark(NULL);
|
||||
Serial.printf("Margen de seguridad de pila: %d bytes libres\n", remanente);
|
||||
}
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Creación con dimensionamiento y habilitación de verificación de pila
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// En menuconfig: Component config -> FreeRTOS -> Enable Stack Overflow Detection (Method 2)
|
||||
|
||||
void tarea_optimizada(void *pvParameters) {
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
UBaseType_t espacioLibre = uxTaskGetStackHighWaterMark(NULL);
|
||||
// Si espacioLibre < 512 bytes, aumente el stack en xTaskCreate
|
||||
}
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Consulta de estado de memoria
|
||||
import gc
|
||||
|
||||
gc.collect()
|
||||
print("Memoria libre en RAM:", gc.mem_free(), "bytes")`,
|
||||
},
|
||||
{
|
||||
id: "memoria-fragmentacao-heap",
|
||||
titulo: "Fragmentación del heap y fugas de memoria (Memory Leaks)",
|
||||
categoria: "memoria",
|
||||
sintomas: ["random-freeze", "wifi-crash"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "E (45210) esp_netif_lwip: Failed to allocate netif buffer\nE (45210) wifi: malloc 1420 failed, free heap: 42300, max allocable: 1200",
|
||||
resumo: "El sistema tiene memoria libre total, pero no puede asignar un bloque contiguo por estar fragmentado en fragmentos pequeños.",
|
||||
causaRaiz:
|
||||
"El uso recurrente de la clase 'String' en bucles rápidos en Arduino, la manipulación de cadenas grandes mediante concatenación (+), o llamadas a malloc sin su correspondiente free van partiendo la memoria dinámica en islas minúsculas. Cuando el driver de Wi-Fi o TLS solicita un búfer de 2 a 4 KB contiguos para recibir un paquete de red, la asignación falla a pesar de que el informe global indique decenas de kilobytes libres.",
|
||||
gambiarra: {
|
||||
titulo: "Reiniciar el microcontrolador preventivamente cada noche",
|
||||
descricao: "Configurar un temporizador para forzar ESP.restart() a intervalos regulares.",
|
||||
consequencia: "Interrupción de operaciones activas, pérdida de estados de conexión y desatención de la causa subyacente.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Uso de búferes estáticos, reserva de memoria previa y monitorización del bloque máximo asignable",
|
||||
passos: [
|
||||
"Sustituir objetos String dinámicos por arreglos de caracteres tradicionales (char buffer[128]) con snprintf.",
|
||||
"Si utiliza la clase String de Arduino, invocar 'str.reserve(tamañoMaximo)' de forma temprana para evitar continuas reasignaciones en el heap.",
|
||||
"Supervisar el estado con heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) en lugar de consultar únicamente el heap total.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Práctica recomendada en Arduino: Uso de snprintf y búfer fijo
|
||||
void formatearDatos(float temp, float hum) {
|
||||
char jsonBuffer[64];
|
||||
// Seguro, rápido y no produce fragmentación en el heap:
|
||||
snprintf(jsonBuffer, sizeof(jsonBuffer), "{\"t\":%.2f,\"h\":%.2f}", temp, hum);
|
||||
Serial.println(jsonBuffer);
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Inspección del bloque contiguo más grande
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
void verificar_salud_memoria(void) {
|
||||
size_t totalLibre = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t mayorBloque = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
|
||||
|
||||
ESP_LOGI("HEAP", "Total libre: %d bytes | Mayor bloque contiguo: %d bytes",
|
||||
totalLibre, mayorBloque);
|
||||
// Si mayorBloque es significativamente menor que totalLibre, existe fragmentación severa
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Recolección proactiva de basura
|
||||
import gc
|
||||
|
||||
def ciclo_mantenimiento():
|
||||
# Forzar compactación y recolección de basura antes de asignaciones grandes:
|
||||
gc.collect()
|
||||
print("Memoria disponible tras GC:", gc.mem_free())`,
|
||||
},
|
||||
{
|
||||
id: "memoria-dma-psram",
|
||||
titulo: "Fallo en asignaciones DMA con memoria externa (PSRAM)",
|
||||
categoria: "memoria",
|
||||
sintomas: ["null-pointer", "random-freeze"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "E (1234) spi_master: spi_bus_add_device(345): buffer not in DMA-capable memory\nE (1234) lcd: esp_lcd_panel_draw_bitmap failed (-1)",
|
||||
resumo: "Un controlador periférico (SPI, I2S, LCD) intentó transferir datos por DMA directamente desde o hacia una dirección de memoria PSRAM externa no compatible.",
|
||||
causaRaiz:
|
||||
"Los periféricos de alta velocidad utilizan controladores DMA que transfieren datos entre memorias y líneas de hardware de forma autónoma. En chips clásicos (como ESP32 y ESP32-S2), el motor DMA carece de acceso físico directo al bus SPI externo de la PSRAM. Intentar pasar un búfer alojado en PSRAM a funciones de dibujo LCD o transferencias SPI DMA produce un fallo inmediato de asignación.",
|
||||
gambiarra: {
|
||||
titulo: "Desactivar transferencias DMA y operar en modo polling por CPU",
|
||||
descricao: "Configurar los buses para transferir byte por byte mediante registros directos.",
|
||||
consequencia: "Caída catastrófica del rendimiento gráfico (de 30 FPS a menos de 5 FPS en pantallas a color) y uso total de la CPU.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Asignar búferes DMA en memoria interna SRAM con capacidades MALLOC_CAP_DMA",
|
||||
passos: [
|
||||
"Alojar siempre los descriptores y búferes activos de DMA en la memoria SRAM interna usando 'heap_caps_malloc(tamaño, MALLOC_CAP_DMA)'.",
|
||||
"Utilizar arquitecturas de doble búfer (ping-pong): mantener los recursos gráficos en PSRAM y copiar por bloques pequeños a un búfer interno DMA de SRAM antes del envío.",
|
||||
"En ESP32-S3 y ESP32-P4, verificar las versiones de revisión de silicio que admiten transferencias EDMA directas desde PSRAM.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Asignación segura de memoria compatible con DMA en Arduino:
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
uint8_t *bufferDma = nullptr;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Asignar exclusivamente en memoria interna con capacidad DMA:
|
||||
bufferDma = (uint8_t *)heap_caps_malloc(4096, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (bufferDma == nullptr) {
|
||||
Serial.println(F("[ERROR] Memoria SRAM interna insuficiente para DMA"));
|
||||
}
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Asignación de búfer para transacciones de bus SPI
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
uint8_t* asignar_buffer_spi(size_t len) {
|
||||
return (uint8_t*)heap_caps_aligned_alloc(32, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Asignación de búfer con alineación para periféricos
|
||||
import uctypes
|
||||
|
||||
# MicroPython gestiona la memoria DMA internamente al inicializar SPI o Display con drivers compilados`,
|
||||
},
|
||||
{
|
||||
id: "boot-failed-connect",
|
||||
titulo: "Failed to connect to ESP32: Timed out waiting for packet header (Fallo de conexión en subida)",
|
||||
categoria: "boot-flash",
|
||||
sintomas: ["upload-fail"],
|
||||
gravidade: "Media",
|
||||
logSerial: "Connecting........_____....._____....._____\nA fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header",
|
||||
resumo: "La herramienta esptool en la computadora host no pudo comunicarse con la ROM de arranque del ESP32 a través del puerto serie.",
|
||||
causaRaiz:
|
||||
"El circuito de reinicio automático formado por transistores y líneas DTR/RTS en la placa de desarrollo no logró colocar a tiempo el pin GPIO0 en nivel bajo en el instante en que el pin EN pasó de bajo a alto. Causas muy frecuentes incluyen: cables USB de solo carga (sin líneas de datos D+/D-), ausencia de capacitor de retardo entre EN y GND, o puertos serie bloqueados por otros programas de terminal abiertos en la computadora.",
|
||||
gambiarra: {
|
||||
titulo: "Mantener pulsado manualmente el botón BOOT en cada grabación",
|
||||
descricao: "Presionar con el dedo el botón físico de BOOT de la placa hasta que el esptool detecte el chip.",
|
||||
consequencia: "Tedioso durante sesiones prolongadas de desarrollo e inviable cuando el microcontrolador se ubica en un gabinete sellado o en un rack.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Capacitor de 10 µF entre EN y GND y cable USB de datos de calidad",
|
||||
passos: [
|
||||
"Soldar o conectar un capacitor cerámico o electrolítico de 1 µF a 10 µF entre el pin EN (CHIP_PU) y el pin GND de la placa DevKit para generar el retardo RC necesario.",
|
||||
"Asegurarse de cerrar cualquier monitor serie o software de depuración antes de iniciar el proceso de subida.",
|
||||
"Verificar con un polímetro la continuidad de las líneas D+ y D- del cable USB.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// No requiere código fuente en firmware: Este problema radica en la etapa de hardware y conexión serie.
|
||||
// Para placas basadas en ESP32-S3 o C3 con USB Serial/JTAG nativo:
|
||||
// En el menú Tools de Arduino IDE:
|
||||
// USB CDC On Boot: "Enabled"
|
||||
// Upload Mode: "UART0 / Hardware CDC"`,
|
||||
codigoEspIdf: `// Verificación rápida desde la consola de terminal con esptool:
|
||||
// idf.py -p /dev/ttyUSB0 flash monitor
|
||||
// Si falla, reducir la velocidad de baudios en el comando:
|
||||
// esptool.py -p /dev/ttyUSB0 -b 115200 chip_id`,
|
||||
codigoMicroPython: `# En caso de error de conexión al flashear el firmware binario de MicroPython:
|
||||
# esptool.py --port /dev/ttyUSB0 --baud 115200 erase_flash
|
||||
# esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-firmware.bin`,
|
||||
},
|
||||
{
|
||||
id: "tls-sntp-clock-fail",
|
||||
titulo: "Fallo en handshake TLS/HTTPS por reloj desincronizado (Año 1970)",
|
||||
categoria: "conectividade",
|
||||
sintomas: ["tls-fail"],
|
||||
gravidade: "Alta",
|
||||
logSerial: "E (5210) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x2700\nE (5210) esp-tls: Failed to verify peer certificate! (0x00000008 - BADCERT_EXPIRED / NOT_YET_VALID)",
|
||||
resumo: "Las solicitudes HTTPS, MQTTS o WebSockets seguros fallan al verificar el certificado de seguridad del servidor.",
|
||||
causaRaiz:
|
||||
"Al encenderse, el reloj de tiempo real (RTC) interno del ESP32 se inicializa en la época Unix estándar (01 de enero de 1970). Los certificados digitales SSL/TLS emitidos por autoridades certificadoras (como Let's Encrypt o DigiCert) definen un período de validez temporal estricto (ej.: válido de 2024 a 2026). Al comprobar la fecha del certificado con su reloj fijado en 1970, la pila MbedTLS rechaza la conexión con el error BADCERT_NOT_YET_VALID.",
|
||||
gambiarra: {
|
||||
titulo: "Desactivar la verificación de certificados con setInsecure()",
|
||||
descricao: "Configurar el cliente TLS para aceptar cualquier certificado sin validación.",
|
||||
consequencia: "Grave vulnerabilidad de seguridad: deja al dispositivo expuesto a ataques Man-in-the-Middle (MitM), donde un atacante en la red local puede interceptar credenciales y datos privados.",
|
||||
},
|
||||
solucaoEngenharia: {
|
||||
titulo: "Sincronizar la hora vía protocolo SNTP antes de iniciar conexiones seguras",
|
||||
passos: [
|
||||
"Iniciar el cliente SNTP inmediatamente después de que el ESP32 obtenga dirección IP de la red Wi-Fi.",
|
||||
"Esperar a que la hora del sistema sea posterior al año 2024 antes de instanciar clientes HTTP/MQTT seguros.",
|
||||
"Cargar los certificados de las Autoridades Certificadoras raíz (Root CA) de confianza en formato PEM.",
|
||||
],
|
||||
},
|
||||
codigoArduino: `// Sincronización horaria previa obligatoria antes de peticiones HTTPS:
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <time.h>
|
||||
|
||||
void sincronizarHora() {
|
||||
// Servidores NTP estándar globales:
|
||||
configTime(0, 0, "pool.ntp.org", "time.google.com");
|
||||
|
||||
Serial.print("Sincronizando reloj con servidores NTP");
|
||||
time_t ahora = time(nullptr);
|
||||
while (ahora < 1704067200) { // Umbral: 01 de enero de 2024
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
ahora = time(nullptr);
|
||||
}
|
||||
Serial.println("\nHora sincronizada correctamente. HTTPS listo.");
|
||||
}`,
|
||||
codigoEspIdf: `// ESP-IDF: Sincronización horaria mediante SNTP nativo
|
||||
#include "esp_sntp.h"
|
||||
#include "esp_log.h"
|
||||
#include <time.h>
|
||||
|
||||
void inicializar_sntp(void) {
|
||||
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||
esp_sntp_setservername(0, "pool.ntp.org");
|
||||
esp_sntp_init();
|
||||
|
||||
time_t now = 0;
|
||||
struct tm timeinfo = { 0 };
|
||||
int reintentos = 0;
|
||||
while (timeinfo.tm_year < (2024 - 1900) && ++reintentos < 20) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
}
|
||||
}`,
|
||||
codigoMicroPython: `# MicroPython: Ajuste de reloj mediante ntptime
|
||||
import network
|
||||
import ntptime
|
||||
import time
|
||||
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
if wlan.isconnected():
|
||||
try:
|
||||
ntptime.settime() # Sincroniza el RTC interno con servidores NTP
|
||||
print("Hora actual sincronizada:", time.localtime())
|
||||
except Exception as e:
|
||||
print("Fallo de sincronización NTP:", e)`,
|
||||
},
|
||||
];
|
||||
|
||||
export const ERROS_COMUNS = errosCatalogo;
|
||||
|
||||
export const analisarLogSerial = [
|
||||
{
|
||||
padrao: /Brownout detector was triggered/i,
|
||||
titulo: "Reinicio por subtensión (Brownout)",
|
||||
tipo: "Alimentación / Hardware",
|
||||
explicacao:
|
||||
"La tensión en el riel de 3.3V cayó por debajo del límite operativo seguro durante picos de corriente del módem RF.",
|
||||
acaoRecomendada:
|
||||
"Añada un capacitor de desacoplo de 10 µF a 100 µF entre 3V3 y GND, o sustituya el cable USB y la fuente de alimentación.",
|
||||
},
|
||||
{
|
||||
padrao: /Guru Meditation Error.*LoadProhibited/i,
|
||||
titulo: "Pánico de CPU: LoadProhibited",
|
||||
tipo: "Software / Puntero Nulo",
|
||||
explicacao:
|
||||
"El código intentó leer una dirección de memoria inválida o puntero desreferenciado con valor NULL.",
|
||||
acaoRecomendada:
|
||||
"Compruebe siempre los punteros antes de acceder a sus miembros y utilice el decodificador de excepciones para localizar la línea.",
|
||||
},
|
||||
{
|
||||
padrao: /Guru Meditation Error.*StoreProhibited/i,
|
||||
titulo: "Pánico de CPU: StoreProhibited",
|
||||
tipo: "Software / Escritura Inválida",
|
||||
explicacao:
|
||||
"El código intentó escribir en una dirección de memoria de solo lectura o en un puntero nulo.",
|
||||
acaoRecomendada:
|
||||
"Verifique las operaciones de escritura en cadenas de texto constantes y la asignación válida de búferes.",
|
||||
},
|
||||
{
|
||||
padrao: /Cache disabled but cached memory region accessed/i,
|
||||
titulo: "Fallo de caché en interrupción (ISR)",
|
||||
tipo: "Software / Flash & RAM",
|
||||
explicacao:
|
||||
"Una rutina de interrupción intentó ejecutar código alojado en Flash mientras la memoria caché estaba deshabilitada por escritura.",
|
||||
acaoRecomendada:
|
||||
"Declare la rutina de interrupción con la macro IRAM_ATTR y no invoque funciones que residan en Flash dentro de la ISR.",
|
||||
},
|
||||
{
|
||||
padrao: /Task watchdog got triggered/i,
|
||||
titulo: "Timeout del Task Watchdog (TWDT)",
|
||||
tipo: "FreeRTOS / Bloqueo de CPU",
|
||||
explicacao:
|
||||
"Una tarea ejecutó un bucle sin ceder tiempo al planificador del sistema durante más de 5 segundos.",
|
||||
acaoRecomendada:
|
||||
"Añada vTaskDelay(1) dentro de los bucles intensivos para permitir que la tarea IDLE alimente el perro guardián.",
|
||||
},
|
||||
{
|
||||
padrao: /A stack overflow in task/i,
|
||||
titulo: "Desbordamiento de pila (Stack Overflow)",
|
||||
tipo: "FreeRTOS / Memoria de Tarea",
|
||||
explicacao:
|
||||
"La tarea agotó el espacio de pila asignado en su creación, corrompiendo el centinela de seguridad.",
|
||||
acaoRecomendada:
|
||||
"Incremente el tamaño de pila en xTaskCreate (ej.: de 2048 a 4096 bytes) y traslade arreglos grandes al heap.",
|
||||
},
|
||||
{
|
||||
padrao: /Timed out waiting for packet header|Failed to connect to ESP32/i,
|
||||
titulo: "Fallo de conexión serie en subida de firmware",
|
||||
tipo: "Bootloader / Conexión",
|
||||
explicacao:
|
||||
"La computadora host no logró colocar el ESP32 en modo de descarga de firmware vía líneas DTR/RTS.",
|
||||
acaoRecomendada:
|
||||
"Conecte un capacitor de 10 µF entre EN y GND, verifique que el cable USB tenga líneas de datos o mantenga presionado el botón BOOT.",
|
||||
},
|
||||
{
|
||||
padrao: /The certificate is not yet valid|-0x2700/i,
|
||||
titulo: "Fallo de certificado SSL/TLS (Reloj en 1970)",
|
||||
tipo: "Conectividad / TLS",
|
||||
explicacao:
|
||||
"El ESP32 intentó validar un certificado HTTPS/TLS con su reloj interno desincronizado en la época de 1970.",
|
||||
acaoRecomendada:
|
||||
"Sincronice la hora mediante el protocolo SNTP (configTime en Arduino o ntptime en MicroPython) antes de iniciar peticiones TLS.",
|
||||
},
|
||||
{
|
||||
padrao: /rst:0x1 \(POWERON_RESET\),boot:0x[0-9a-fA-F]+/i,
|
||||
titulo: "Reinicio por encendido / Muestreo de Strapping Pins",
|
||||
tipo: "Hardware / Boot",
|
||||
explicacao:
|
||||
"El microcontrolador se reinició y registró sus pines de arranque. Si se congela de inmediato, un pin de strapping tiene un nivel incorrecto.",
|
||||
acaoRecomendada:
|
||||
"Compruebe que los pines de arranque GPIOs no estén forzados a niveles incompatibles por circuitos externos en el instante del arranque.",
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,408 @@
|
||||
/**
|
||||
* Base de datos estructurada y completa de términos técnicos del Glosario ESP32 en español.
|
||||
* Abarca todas las series de chips de Espressif (ESP32, S2, S3, S31, C2, C3, C5, C6, C61, H2, H4, P4)
|
||||
* y sus funciones de hardware, periféricos, radio, seguridad y software.
|
||||
*/
|
||||
|
||||
export const categoriasGlossario = [
|
||||
{
|
||||
"id": "processamento",
|
||||
"nome": "Procesamiento, CPU y Silicio",
|
||||
"icone": "Cpu",
|
||||
"emoji": "🧠",
|
||||
"cor": "blue",
|
||||
"descricao": "Arquitecturas Xtensa y RISC-V, núcleos, coprocesadores ULP, aceleradores vectoriales de IA y unidades de punto flotante.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "Arquitectura Xtensa vs RISC-V",
|
||||
"definicao": "Conjunto de instrucciones base del procesador. El ESP32 clásico, S2 y S3 utilizan núcleos propietarios Tensilica Xtensa (LX6/LX7). Las series modernas C (C2, C3, C5, C6, C61), H (H2, H4) y P (P4) adoptan la arquitectura abierta, modular y eficiente RISC-V (32 bits).",
|
||||
"exemplo": "El ESP32-S3 usa Xtensa LX7 dual-core, mientras que el ESP32-C6 usa RISC-V single-core y el ESP32-P4 usa RISC-V dual-core a 400 MHz."
|
||||
},
|
||||
{
|
||||
"termo": "Núcleos de CPU (Dual-Core vs Single-Core)",
|
||||
"definicao": "Unidades centrales de procesamiento independientes. Los chips dual-core permiten dedicar un núcleo (Core 0) exclusivamente a la radio Wi-Fi/Bluetooth y a la planificación de FreeRTOS, dejando el segundo núcleo (Core 1) 100% libre para la aplicación y cálculos del usuario.",
|
||||
"exemplo": "ESP32, ESP32-S3 y ESP32-P4 son dual-core; ESP32-S2, C2, C3, C6 y H2 son single-core."
|
||||
},
|
||||
{
|
||||
"termo": "Frecuencia de reloj (MHz)",
|
||||
"definicao": "Velocidad de procesamiento medida en Megahertz (MHz). El ESP-IDF ajusta dinámicamente la frecuencia (Dynamic Frequency Scaling - DFS) para ahorrar energía en momentos de inactividad.",
|
||||
"exemplo": "El ESP32-C2 opera hasta 120 MHz; ESP32, S2, S3 y C6 alcanzan 160/240 MHz; y el ESP32-P4 alcanza 400 MHz."
|
||||
},
|
||||
{
|
||||
"termo": "ULP (Coprocesador de ultra bajo consumo)",
|
||||
"definicao": "Procesador secundario independiente de ultra bajo consumo que continúa ejecutando instrucciones, leyendo sensores analógicos (ADC), I2C y pines GPIO mientras los núcleos principales permanecen apagados en Deep Sleep.",
|
||||
"exemplo": "El ESP32 original cuenta con ULP FSM; ESP32-S2, S3 y C6 disponen de ULP RISC-V programable en C; ESP32-P4 cuenta con ULP dedicado de bajo consumo."
|
||||
},
|
||||
{
|
||||
"termo": "Extensiones vectoriales de IA (Vector Extension / ESP-NN)",
|
||||
"definicao": "Instrucciones especializadas de silicio que ejecutan operaciones matemáticas vectoriales y matriciales con enteros (int8/int16) en paralelo, acelerando redes neuronales convolucionales (CNNs) y procesamiento de señales.",
|
||||
"exemplo": "ESP32-S3 y ESP32-P4 aceleran inferencias de reconocimiento facial, detección de voz y modelos TensorFlow Lite for Microcontrollers."
|
||||
},
|
||||
{
|
||||
"termo": "FPU (Unidad de punto flotante)",
|
||||
"definicao": "Unidad de procesamiento de punto flotante por hardware que realiza sumas, multiplicaciones y divisiones con números decimales (`float`) en un único ciclo de reloj, sin sobrecarga por emulación de software.",
|
||||
"exemplo": "Presente en los núcleos Xtensa del ESP32 y ESP32-S3, y en los núcleos RISC-V de alto rendimiento del ESP32-P4."
|
||||
},
|
||||
{
|
||||
"termo": "PPA (Pixel Processing Accelerator)",
|
||||
"definicao": "Acelerador gráfico 2D por hardware exclusivo del ESP32-P4 para manipulación acelerada de imágenes: rotación de fotogramas, escalado (scaling), mezcla alfa (alpha blending) y conversión de espacios de color (RGB565, ARGB8888, YUV420).",
|
||||
"exemplo": "Renderizado de interfaces gráficas complejas (LVGL) a 60 FPS sin sobrecargar los núcleos de CPU principales."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "seguranca",
|
||||
"nome": "Seguridad, Criptografía y eFuses",
|
||||
"icone": "ShieldCheck",
|
||||
"emoji": "🔒",
|
||||
"cor": "red",
|
||||
"descricao": "eFuses inviolables, Secure Boot V2, cifrado de flash XTS-AES, Key Manager, ECC y protección contra DPA.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "eFuse (Fusibles electrónicos)",
|
||||
"definicao": "Conjunto de fusibles microscópicos de silicio de grabación única e irreversible (One-Time Programmable - OTP). Almacenan claves secretas de cifrado, la dirección MAC de fábrica y bloquean interfaces de depuración en productos comerciales.",
|
||||
"exemplo": "Utilizado con la herramienta `espefuse.py` para grabar claves de Secure Boot y desactivar puertos JTAG antes del envío al usuario final."
|
||||
},
|
||||
{
|
||||
"termo": "Secure Boot (V1 y V2)",
|
||||
"definicao": "Protocolo de arranque seguro en el que el código de la ROM verifica criptográficamente la firma RSA-3072 o ECDSA del bootloader y del firmware antes de permitir su ejecución, impidiendo la inyección de código manipulado.",
|
||||
"exemplo": "ESP32 clásico usa Secure Boot V1; del ESP32-S2 en adelante todos adoptan Secure Boot V2 con múltiples claves de firma."
|
||||
},
|
||||
{
|
||||
"termo": "Cifrado de flash (Flash Encryption)",
|
||||
"definicao": "Mecanismo de hardware que cifra y descifra en tiempo real el contenido de la memoria Flash SPI externa utilizando el algoritmo XTS-AES. Impide la lectura física del firmware en caso de robo de la placa o desoldado del chip de memoria.",
|
||||
"exemplo": "XTS-AES-128 en la mayoría de los chips; ESP32-S3, C5, P4 y H4 también admiten XTS-AES-256."
|
||||
},
|
||||
{
|
||||
"termo": "Key Manager",
|
||||
"definicao": "Módulo de seguridad avanzada que aprovisiona, almacena y opera claves criptográficas en silicio sin exponerlas jamás a la memoria SRAM o al firmware, impidiendo la extracción de claves incluso ante vulnerabilidades de software.",
|
||||
"exemplo": "Presente en series de alta seguridad como ESP32-S31, ESP32-C5 y ESP32-P4."
|
||||
},
|
||||
{
|
||||
"termo": "ECC y ECDSA en hardware",
|
||||
"definicao": "Aceleradores de curvas elípticas (como P-256 y P-384) y algoritmos de firma digital ECDSA en silicio, fundamentales para una conexión rápida y segura a la nube y para los requisitos de atestación del estándar Matter.",
|
||||
"exemplo": "ESP32-S31, C5, C61, P4, H2 y H4 disponen de acelerador de hardware para ECDSA."
|
||||
},
|
||||
{
|
||||
"termo": "HMAC y Firma Digital (DS)",
|
||||
"definicao": "Periféricos de autenticación criptográfica que calculan códigos HMAC y firman mensajes con claves secretas grabadas en eFuses de forma invisible para el firmware.",
|
||||
"exemplo": "Permite autenticación rápida y segura con AWS IoT Core y Microsoft Azure IoT sin almacenar certificados en texto plano."
|
||||
},
|
||||
{
|
||||
"termo": "TRNG (Generador de números aleatorios verdaderos)",
|
||||
"definicao": "Generador de números aleatorios verdaderos basado en el ruido térmico analógico de los circuitos de radio y silicio, esencial para generar claves de sesión en handshakes TLS/HTTPS.",
|
||||
"exemplo": "Disponible en todas las series de ESP32 para garantizar entropía segura en conexiones HTTPS/MbedTLS."
|
||||
},
|
||||
{
|
||||
"termo": "Protección contra DPA (Differential Power Analysis)",
|
||||
"definicao": "Mecanismo físico de hardware que añade ruido y balanceo en el consumo de corriente eléctrica del chip para evitar que atacantes descubran claves criptográficas midiendo el consumo con osciloscopios.",
|
||||
"exemplo": "Presente en las series ESP32-C5, C6, C61 y H2."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "memoria",
|
||||
"nome": "Memoria, Buses y Almacenamiento",
|
||||
"icone": "Database",
|
||||
"emoji": "💾",
|
||||
"cor": "purple",
|
||||
"descricao": "SRAM, PSRAM externa, buses QSPI y Octal SPI, ROM de arranque, memoria RTC y sistemas de archivos.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "SRAM interna (Static RAM)",
|
||||
"definicao": "Memoria de acceso aleatorio de ultra alta velocidad integrada en el silicio, dividida en IRAM (instrucciones) y DRAM (datos). No pierde datos mientras el chip esté alimentado en modo activo.",
|
||||
"exemplo": "El ESP32 dispone de 520 KB de SRAM, mientras que el ESP32-P4 ofrece 768 KB de SRAM de alto rendimiento."
|
||||
},
|
||||
{
|
||||
"termo": "ROM de arranque (Boot ROM)",
|
||||
"definicao": "Memoria de solo lectura grabada durante la fabricación del silicio. Contiene el código de arranque primario (First-Stage Bootloader), rutinas de descarga serie y funciones criptográficas básicas.",
|
||||
"exemplo": "No puede ser alterada por el usuario ni infectada por malware; es la raíz de confianza de todo el chip."
|
||||
},
|
||||
{
|
||||
"termo": "Flash SPI (Quad-SPI vs Octal-SPI)",
|
||||
"definicao": "Interfaz de comunicación con memorias Flash externas. Quad-SPI (QSPI) usa 4 líneas de datos, mientras que Octal SPI (OPI) usa 8 líneas simultáneas con soporte DDR, duplicando la tasa de transferencia.",
|
||||
"exemplo": "Octal SPI en ESP32-S3 y ESP32-P4 permite tasas de lectura superiores a 120 MB/s para código y recursos multimedia."
|
||||
},
|
||||
{
|
||||
"termo": "PSRAM (Pseudo-Static RAM externa)",
|
||||
"definicao": "Memoria RAM dinámica externa empaquetada junto al chip (SiP) o conectada vía bus SPI/QSPI/OPI que expande la memoria disponible para buffers gráficos, audio y modelos de IA.",
|
||||
"exemplo": "Módulos ESP32-WROVER y ESP32-S3 disponen de 2 MB a 16 MB de PSRAM; ESP32-P4 admite hasta 32 MB."
|
||||
},
|
||||
{
|
||||
"termo": "SRAM RTC Fast y Slow",
|
||||
"definicao": "Pequeños bloques de memoria SRAM (típicamente 8 KB a 32 KB) ubicados en el dominio de energía de bajo consumo (RTC / Low Power). Conservan su contenido durante el Deep Sleep.",
|
||||
"exemplo": "Variables declaradas con `RTC_DATA_ATTR` mantienen su valor entre reinicios tras despertar de Deep Sleep."
|
||||
},
|
||||
{
|
||||
"termo": "Asignación DMA (MALLOC_CAP_DMA)",
|
||||
"definicao": "Solicitud de bloques de memoria RAM con direccionamiento físico continuo y accesibles por controladores DMA (Direct Memory Access) para transmisiones de alta velocidad sin intervención de la CPU.",
|
||||
"exemplo": "Necesario para buffers de pantallas SPI/I8080, audio I2S, transceptores Wi-Fi y lecturas de tarjetas SD."
|
||||
},
|
||||
{
|
||||
"termo": "Fragmentación del heap",
|
||||
"definicao": "Degradación del espacio libre de memoria dinámica en múltiples bloques pequeños dispersos debido a asignaciones y liberaciones sucesivas (malloc/free), impidiendo asignar bloques grandes contiguos.",
|
||||
"exemplo": "Causa común de fallos en conexiones TLS o asignación de buffers de cámara tras horas de funcionamiento."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "conectividade",
|
||||
"nome": "Conectividad Inalámbrica y Protocolos",
|
||||
"icone": "Wifi",
|
||||
"emoji": "📡",
|
||||
"cor": "emerald",
|
||||
"descricao": "Wi-Fi 4/6, Bluetooth Classic, BLE 5.x, Zigbee 3.0, Thread 1.3, Matter y redes ESP-NOW.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "Wi-Fi 6 (802.11ax)",
|
||||
"definicao": "Nueva generación del estándar Wi-Fi que aporta mayor eficiencia espectral, menor latencia y menor consumo energético en entornos saturados mediante OFDMA y Target Wake Time (TWT).",
|
||||
"exemplo": "ESP32-C6 y ESP32-C5 soportan Wi-Fi 6 en 2.4 GHz; el ESP32-C5 añade compatibilidad con la banda de 5 GHz."
|
||||
},
|
||||
{
|
||||
"termo": "Wi-Fi Dual-Band (2.4 GHz y 5 GHz)",
|
||||
"definicao": "Capacidad de operar tanto en la banda tradicional de 2.4 GHz como en la banda más descongestionada y de mayor ancho de banda de 5 GHz.",
|
||||
"exemplo": "El ESP32-C5 es el primer chip de Espressif con radio Wi-Fi 6 de doble banda simultánea (2.4 GHz y 5 GHz)."
|
||||
},
|
||||
{
|
||||
"termo": "OFDMA (Acceso múltiple por división de frecuencias ortogonales)",
|
||||
"definicao": "Tecnología de modulación de Wi-Fi 6 que divide los canales de radio en subcanales diminutos (Resource Units - RU), permitiendo transmitir datos hacia y desde múltiples dispositivos en un mismo instante.",
|
||||
"exemplo": "Reduce drásticamente la latencia en redes con cientos de sensores IoT conectados al mismo punto de acceso Wi-Fi 6."
|
||||
},
|
||||
{
|
||||
"termo": "TWT (Target Wake Time)",
|
||||
"definicao": "Mecanismo de ahorro de energía de Wi-Fi 6 que permite al punto de acceso y al dispositivo acordar ventanas de comunicación específicas, manteniendo el microcontrolador dormido durante horas entre transmisiones.",
|
||||
"exemplo": "Sensores a batería basados en ESP32-C6 multiplican su autonomía al conectarse a enrutadores Wi-Fi 6 con soporte TWT."
|
||||
},
|
||||
{
|
||||
"termo": "Bluetooth Classic (BR/EDR)",
|
||||
"definicao": "Modo tradicional de Bluetooth optimizado para streaming de audio continuo (perfil A2DP), transferencia de archivos y puertos serie SPP a tasas de datos de 2 a 3 Mbps.",
|
||||
"exemplo": "Disponible en el ESP32 original y en el ESP32-S31 para recepción y reproducción de música Bluetooth."
|
||||
},
|
||||
{
|
||||
"termo": "Bluetooth Low Energy (BLE 5.0 a 5.4)",
|
||||
"definicao": "Versión optimizada para consumo ultra bajo con soporte para modo de alta velocidad (2 Mbps), largo alcance (Coded PHY de 125/500 kbps) y extensiones publicitarias periódicas.",
|
||||
"exemplo": "Soportado en ESP32, S3, C3, C6, H2 y H4 para balizas, sensores corporales y aprovisionamiento de credenciales Wi-Fi."
|
||||
},
|
||||
{
|
||||
"termo": "Bluetooth LE Audio y Auracast",
|
||||
"definicao": "Nueva generación de audio Bluetooth basada en el códec LC3 de alta fidelidad y bajo consumo. Auracast permite transmitir audio en broadcast a un número ilimitado de receptores simultáneos.",
|
||||
"exemplo": "Soportado nativamente por el SoC ESP32-H4 para auriculares inalámbricos y sistemas de transmisión de audio accesible."
|
||||
},
|
||||
{
|
||||
"termo": "IEEE 802.15.4 (Zigbee 3.0 y Thread)",
|
||||
"definicao": "Estándar de radio de baja potencia y baja tasa de transferencia en 2.4 GHz que sirve de base física para redes en malla de automatización del hogar (Zigbee 3.0 y Thread 1.3).",
|
||||
"exemplo": "Chips como ESP32-H2 y ESP32-C6 cuentan con radio 802.15.4 para comunicación directa sin necesidad de Wi-Fi."
|
||||
},
|
||||
{
|
||||
"termo": "Matter (Estándar unificado de hogar inteligente)",
|
||||
"definicao": "Protocolo unificador de capa de aplicación respaldado por Apple, Google y la CSA. Funciona sobre Wi-Fi, Thread y Ethernet, garantizando interoperabilidad directa sin bridges propietarios.",
|
||||
"exemplo": "Un enchufe inteligente programado con ESP-Matter funciona simultáneamente en Apple HomeKit, Google Home y Home Assistant."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "perifericos",
|
||||
"nome": "Entradas, Salidas y Periféricos",
|
||||
"icone": "Sliders",
|
||||
"emoji": "🔌",
|
||||
"cor": "amber",
|
||||
"descricao": "GPIO, ADC, DAC, PWM (LEDC/MCPWM), UART, SPI, I2C, I2S y pines táctiles capacitivos.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "GPIO (Entradas y salidas de propósito general)",
|
||||
"definicao": "Pines digitales configurables como entradas (lectura de botones y sensores lógicos) o salidas (control de relés, LEDs y actuadores). Cuentan con resistencias pull-up y pull-down configurables por software.",
|
||||
"exemplo": "El ESP32 cuenta con hasta 34 GPIOs, mientras que el ESP32-S3 dispone de hasta 45 GPIOs multifuncionales."
|
||||
},
|
||||
{
|
||||
"termo": "Pines de arranque (Strapping Pins)",
|
||||
"definicao": "Pines GPIO específicos muestreados por el hardware durante el ciclo de reinicio (reset) para determinar el modo de arranque: ejecución normal desde Flash SPI, modo de descarga de firmware o configuración de voltajes LDO.",
|
||||
"exemplo": "GPIO0 y GPIO2 en ESP32, o GPIO8 y GPIO9 en ESP32-C3/C6. Circuitos externos no deben forzar niveles no deseados durante el arranque."
|
||||
},
|
||||
{
|
||||
"termo": "ADC (Convertidor analógico-digital)",
|
||||
"definicao": "Convertidor que transforma tensiones analógicas continuas en valores numéricos digitales (resolución de 12 bits, o 13 bits en ESP32-S2), con atenuaciones ajustables para rangos de hasta ~3.1V.",
|
||||
"exemplo": "ADC1 puede utilizarse simultáneamente con Wi-Fi, mientras que ADC2 comparte recursos de hardware con el subsistema de radio en algunos modelos."
|
||||
},
|
||||
{
|
||||
"termo": "DAC (Convertidor digital-analógico)",
|
||||
"definicao": "Convertidor por hardware que transforma números digitales en tensiones analógicas reales continuas (resolución de 8 bits), permitiendo generar ondas de sonido o voltajes de control.",
|
||||
"exemplo": "Presente en los pines GPIO25 y GPIO26 del ESP32 clásico y en el ESP32-S2 (los chips RISC-V prescinden de DAC analógico directo)."
|
||||
},
|
||||
{
|
||||
"termo": "LEDC (Controlador LED PWM)",
|
||||
"definicao": "Periférico por hardware diseñado para modulación por ancho de pulso (PWM) de alta precisión con desvanecimiento automático (fading) por hardware, configurable en múltiples canales y resoluciones de hasta 20 bits.",
|
||||
"exemplo": "Regulación de intensidad de tiras LED RGBW y servomotores sin ocupar tiempo de ejecución de la CPU."
|
||||
},
|
||||
{
|
||||
"termo": "MCPWM (PWM para control de motores)",
|
||||
"definicao": "Generador avanzado de PWM concebido para conmutación de puentes H, motores de corriente continua (DC), motores sin escobillas (BLDC) e inversores solares, con control de tiempo muerto (dead-time) y entradas de fallo (fault capture).",
|
||||
"exemplo": "Presente en ESP32, S3, C6 y P4 para accionamiento preciso de servomotores y robótica."
|
||||
},
|
||||
{
|
||||
"termo": "RMT (Periférico de control remoto)",
|
||||
"definicao": "Transmisor y receptor de trenes de pulsos precisos con temporización exacta de microsegundos, ideal para protocolos infrarrojos (NEC, RC5, Sony) y control de LEDs direccionables WS2812B (NeoPixel).",
|
||||
"exemplo": "Control de tiras de LEDs WS2812B con temporizaciones estrictas de 800 kHz sin bloquear interrupciones de la CPU."
|
||||
},
|
||||
{
|
||||
"termo": "PCNT (Contador de pulsos)",
|
||||
"definicao": "Periférico de hardware dedicado a contar flancos de subida y bajada de señales digitales de forma autónoma, sin generar interrupciones por cada pulso.",
|
||||
"exemplo": "Lectura de codificadores rotativos en cuadratura (rotary encoders), medidores de caudal de agua y anemómetros."
|
||||
},
|
||||
{
|
||||
"termo": "TWAI® (Interfaz automotriz de dos hilos / Bus CAN)",
|
||||
"definicao": "Controlador de red automotriz e industrial compatible con la especificación CAN 2.0B y CAN FD, resistente al ruido electromagnético severo con confirmación por hardware de tramas.",
|
||||
"exemplo": "Lectura de datos de telemetría de vehículos mediante conector OBD-II y comunicación en maquinaria pesada."
|
||||
},
|
||||
{
|
||||
"termo": "Pines táctiles capacitivos (Touch)",
|
||||
"definicao": "Circuitos analógicos integrados que miden variaciones diminutas de capacitancia eléctrica cuando un dedo humano se aproxima a una pista de cobre o almohadilla conductora.",
|
||||
"exemplo": "Permite crear botones táctiles detrás de vidrio o plástico y despertar el chip de Deep Sleep mediante toque."
|
||||
},
|
||||
{
|
||||
"termo": "PARLIO (Controlador de I/O paralelo)",
|
||||
"definicao": "Interfaz paralela flexible de alta velocidad de Espressif con soporte para transmisión y recepción de datos de 1 a 16 bits sincronizados con reloj externo o interno.",
|
||||
"exemplo": "Presente en ESP32-C6 y P4 para comunicación de alta velocidad con memorias externas, cámaras y pantallas LCD."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "multimidia",
|
||||
"nome": "Multimedia, USB e Interfaces Avanzadas",
|
||||
"icone": "Sparkles",
|
||||
"emoji": "✨",
|
||||
"cor": "pink",
|
||||
"descricao": "Interfaces de cámara DVP y MIPI CSI, pantallas LCD RGB y MIPI DSI, USB OTG nativo y USB Serial/JTAG.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "USB OTG (On-The-Go) nativo",
|
||||
"definicao": "Controlador USB integrado que permite al chip actuar tanto como periférico USB (teclado HID, ratón, puerto serie CDC, almacenamiento masivo) como puerto Host USB para conectar memorias USB o cámaras.",
|
||||
"exemplo": "Soportado en ESP32-S2 y S3 a 12 Mbps (Full-Speed); ESP32-P4 cuenta con controlador USB 2.0 High-Speed a 480 Mbps."
|
||||
},
|
||||
{
|
||||
"termo": "USB Serial/JTAG nativo",
|
||||
"definicao": "Periférico de hardware que conecta directamente el puerto USB de la PC a los pines de depuración JTAG y consola serie del chip, eliminando la necesidad de chips conversores externos (como CP2102 o CH340).",
|
||||
"exemplo": "Disponible en ESP32-C3, C6, S3, C5 y H2 para carga de firmware y depuración con OpenOCD sin sondas adicionales."
|
||||
},
|
||||
{
|
||||
"termo": "USB 2.0 High-Speed (480 Mbps)",
|
||||
"definicao": "Controlador USB de alta velocidad con capa física integrada (PHY High-Speed) que multiplica por 40 la velocidad de transferencia frente al USB Full-Speed (12 Mbps).",
|
||||
"exemplo": "Exclusivo del ESP32-P4 para transmisión de video en tiempo real y transferencia masiva de archivos."
|
||||
},
|
||||
{
|
||||
"termo": "MIPI CSI y MIPI DSI",
|
||||
"definicao": "Interfaces serie diferenciales de ultra alta velocidad estándar de la industria móvil para sensores de cámara (CSI) y pantallas gráficas (DSI) de alta resolución.",
|
||||
"exemplo": "Presentes en el ESP32-P4 con soporte de hasta 2 carriles a 1.5 Gbps por carril para video 1080p."
|
||||
},
|
||||
{
|
||||
"termo": "Codificador de video H.264 por hardware",
|
||||
"definicao": "Acelerador de compresión de video por hardware capaz de codificar secuencias de fotogramas en formato H.264 (AVC) a resoluciones de hasta 1080p a 30 FPS.",
|
||||
"exemplo": "Exclusivo del ESP32-P4 para cámaras de seguridad IP y videoporteros sin sobrecargar la CPU."
|
||||
},
|
||||
{
|
||||
"termo": "Ethernet MAC 10/100 Mbps",
|
||||
"definicao": "Controlador de capa de enlace Ethernet integrado en silicio que requiere únicamente un chip transceptor físico externo (PHY como LAN8720 o IP101) conectado vía bus RMII.",
|
||||
"exemplo": "Disponible en el ESP32 clásico y en el ESP32-P4 para conexiones de red por cable ultra estables sin interferencias de RF."
|
||||
},
|
||||
{
|
||||
"termo": "Interfaz de cámara DVP (8 bits / 16 bits)",
|
||||
"definicao": "Interfaz de cámara paralela de 8 a 16 bits sincronizada por reloj de píxel (PCLK), sincronización horizontal (HREF) y vertical (VSYNC), diseñada para sensores de imagen tipo OV2640 y OV5640.",
|
||||
"exemplo": "Utilizada en placas como ESP32-CAM y ESP32-S3-EYE para captura y streaming de video MJPEG."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "energia",
|
||||
"nome": "Gestión de Energía y Modos de Suspensión",
|
||||
"icone": "BatteryCharging",
|
||||
"emoji": "🔋",
|
||||
"cor": "teal",
|
||||
"descricao": "Modo activo, Modem Sleep, Light Sleep, Deep Sleep, fuentes de activación y detección de brownout.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "Modo activo (Active Mode)",
|
||||
"definicao": "Estado de funcionamiento pleno en el que todos los núcleos de CPU, buses, periféricos y subsistemas de radio Wi-Fi/Bluetooth operan a su frecuencia nominal.",
|
||||
"exemplo": "Consumo típico de 30 a 60 mA en cómputo puro, con picos de 200 a 400 mA durante transmisiones RF."
|
||||
},
|
||||
{
|
||||
"termo": "Modem Sleep",
|
||||
"definicao": "Modo de ahorro de energía en el que la CPU continúa funcionando activamente pero el subsistema de radio Wi-Fi o Bluetooth apaga sus circuitos entre intervalos de baliza (DTIM).",
|
||||
"exemplo": "El ESP32 permanece asociado al router Wi-Fi consumiendo solo 20 a 40 mA mientras procesa datos locales."
|
||||
},
|
||||
{
|
||||
"termo": "Light Sleep",
|
||||
"definicao": "Modo en el que el reloj de la CPU se detiene y la mayor parte de los periféricos digitales se suspenden, pero la memoria RAM interna se preserva íntegramente. El retorno al modo activo es prácticamente instantáneo (< 1 ms).",
|
||||
"exemplo": "Consumo de corriente reducido a 0.8–2.0 mA; puede despertarse por temporizador, pines GPIO, UART o eventos Wi-Fi."
|
||||
},
|
||||
{
|
||||
"termo": "Deep Sleep",
|
||||
"definicao": "Modo de suspensión profunda en el que la CPU principal, periféricos y SRAM estándar se desenergizan por completo. Solo el dominio RTC/LP y su memoria de bajo consumo permanecen activos.",
|
||||
"exemplo": "Consumo de corriente diminuto de 5 a 150 µA, permitiendo que sensores autónomos operen durante años con una única batería."
|
||||
},
|
||||
{
|
||||
"termo": "Hibernación (Hibernation Mode)",
|
||||
"definicao": "El modo de consumo más bajo posible del chip: todos los osciladores internos y memorias se apagan, manteniendo solo un temporizador ultralento o un pin de reactivación externo.",
|
||||
"exemplo": "Consumo residual tan bajo como 5 µA; al despertar, el chip ejecuta un reinicio completo (reboot)."
|
||||
},
|
||||
{
|
||||
"termo": "Fuentes de activación (Wakeup Sources)",
|
||||
"definicao": "Eventos de hardware configurados para reactivar el microcontrolador desde Light Sleep o Deep Sleep.",
|
||||
"exemplo": "Temporizador RTC (Timer), interrupción por pin táctil (Touch), cambio de nivel lógico en pines GPIO (ext0/ext1) o eventos del coprocesador ULP."
|
||||
},
|
||||
{
|
||||
"termo": "Detector de subtensión (Brownout Detector)",
|
||||
"definicao": "Circuito comparador analógico interno que monitorea continuamente la tensión del riel de 3.3V y reinicia el chip de forma segura si el voltaje cae por debajo del umbral crítico (~2.43V).",
|
||||
"exemplo": "Evita la corrupción de datos en la memoria Flash SPI durante caídas transitorias de tensión provocadas por picos de transmisión Wi-Fi."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "desenvolvimento",
|
||||
"nome": "Firmware, Arranque y Sistema Operativo",
|
||||
"icone": "Code2",
|
||||
"emoji": "🚀",
|
||||
"cor": "rose",
|
||||
"descricao": "Bootloader, tabla de particiones, FreeRTOS, ESP-IDF, IDF Component Manager y actualizaciones OTA.",
|
||||
"termos": [
|
||||
{
|
||||
"termo": "Bootloader (Primera y segunda etapa)",
|
||||
"definicao": "Proceso de arranque en dos fases: la ROM interna (1ª etapa) verifica los pines de arranque e inicia el Second-Stage Bootloader ubicado en la Flash, el cual carga la tabla de particiones y transfiere el control a la aplicación.",
|
||||
"exemplo": "Permite seleccionar entre múltiples particiones de firmware (fábrica, OTA_0, OTA_1) según el estado del sistema."
|
||||
},
|
||||
{
|
||||
"termo": "FreeRTOS (Sistema operativo de tiempo real)",
|
||||
"definicao": "Sistema operativo de tiempo real adaptado por Espressif para multitarea simétrica multinúcleo (Symmetric Multiprocessing - SMP), administrando colas, semáforos, mutexes y prioridades de tareas en ambos núcleos.",
|
||||
"exemplo": "Creación de tareas independientes con `xTaskCreatePinnedToCore()` fijadas específicamente al Core 0 o al Core 1."
|
||||
},
|
||||
{
|
||||
"termo": "Atributos IRAM_ATTR y DRAM_ATTR",
|
||||
"definicao": "Macros de compilación del ESP-IDF que fuerzan la ubicación de funciones en la memoria interna IRAM (en lugar de la Flash SPI) o datos en DRAM, requisito indispensable para rutinas de interrupción (ISRs).",
|
||||
"exemplo": "Previene caídas por Guru Meditation si ocurre una interrupción mientras la memoria Flash SPI se encuentra ocupada escribiendo datos."
|
||||
},
|
||||
{
|
||||
"termo": "Tabla de particiones (partitions.csv)",
|
||||
"definicao": "Archivo de configuración que divide el espacio de la memoria Flash SPI en sectores lógicos con propósitos específicos: bootloader, datos de calibración NVS, aplicaciones de firmware y sistemas de archivos.",
|
||||
"exemplo": "Configuración esencial para habilitar particiones duales de actualización inalámbrica OTA (`ota_0` y `ota_1`)."
|
||||
},
|
||||
{
|
||||
"termo": "Actualizaciones OTA con Rollback",
|
||||
"definicao": "Mecanismo que permite actualizar el firmware de dispositivos conectados vía Wi-Fi, Ethernet o BLE, escribiendo la nueva versión en una partición secundaria y alternando el puntero de arranque de forma atómica.",
|
||||
"exemplo": "Cuenta con soporte para reversión automática (rollback) si el nuevo firmware falla en su primera ejecución."
|
||||
},
|
||||
{
|
||||
"termo": "NVS (Non-Volatile Storage) y cifrado NVS",
|
||||
"definicao": "Biblioteca y partición de almacenamiento en memoria Flash organizada en pares clave-valor. Incluye balanceo de desgaste (wear leveling) y cifrado con claves basadas en eFuses para datos sensibles de configuración.",
|
||||
"exemplo": "Utilizada por el ESP-IDF para guardar credenciales Wi-Fi (SSID/contraseña) y claves criptográficas de forma segura."
|
||||
},
|
||||
{
|
||||
"termo": "Sistemas de archivos (LittleFS y SPIFFS)",
|
||||
"definicao": "Estructuras de archivos sobre memoria Flash SPI. LittleFS es el estándar moderno, más rápido, resistente a fallos de alimentación y con menor sobrecarga de RAM que el obsoleto SPIFFS.",
|
||||
"exemplo": "Almacenamiento de páginas web (HTML/CSS/JS), imágenes de interfaz y certificados SSL en la memoria Flash local."
|
||||
},
|
||||
{
|
||||
"termo": "JTAG y OpenOCD",
|
||||
"definicao": "Estándar de depuración por hardware que permite pausar la ejecución de la CPU, inspeccionar el valor de registros, recorrer el código paso a paso y evaluar puntos de interrupción en tiempo real.",
|
||||
"exemplo": "Depuración integrada mediante USB Serial/JTAG en ESP32-S3/C3/C6 o mediante sondas externas como ESP-PROG."
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Conocimiento de dominio para la búsqueda inteligente en español.
|
||||
*
|
||||
* Sin dependencias ni alias de import: se ejecuta en el servidor (montando el índice),
|
||||
* en el navegador (interpretando la consulta) y en scripts de prueba en Node.
|
||||
*
|
||||
* Todos los textos de `termos` ya están normalizados (minúsculas, sin acentos).
|
||||
*/
|
||||
|
||||
export const normalizar = (s = "") =>
|
||||
String(s)
|
||||
.toLowerCase()
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "");
|
||||
|
||||
/**
|
||||
* Reconoce pines ocupados por flash/PSRAM según la descripción del diagrama.
|
||||
* "forte": el pin es consumido por la memoria (o es su alimentación).
|
||||
* "fraco": solo se ve afectado en ciertos modos (ej.: SPI de 8 líneas/octal).
|
||||
*/
|
||||
const nivelMemoria = (palabra) => (p) => {
|
||||
const citam = p._avs.filter((a) => a.includes(palabra) && !/^para chips (con|sin|com|sem)/i.test(a));
|
||||
if (citam.some((a) => /(utilizad|dedicad|conectad)/i.test(a) && !/a menos que/i.test(a))) return "forte";
|
||||
if (p._fn.some((f) => /alimentacion|alimentacao/i.test(f) && f.includes(palabra))) return "forte";
|
||||
if (citam.length) return "fraco";
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Temas que el usuario puede consultar en español.
|
||||
*/
|
||||
export const TOPICOS = [
|
||||
{ id: "flash", nome: "Flash", termos: ["flash", "memoria flash", "spi flash", "almacenamiento", "firmware", "rom externa"], pinoNivel: nivelMemoria("flash"), pinoRotulo: "conectados a la memoria flash" },
|
||||
{ id: "psram", nome: "PSRAM", termos: ["psram", "ram externa", "spiram"], pinoNivel: nivelMemoria("psram"), pinoRotulo: "conectados a la PSRAM" },
|
||||
{ id: "memoria", nome: "Memoria", termos: ["memoria", "sram", "heap", "rtc ram", "kb de ram", "memoria interna", "ram", "memory"], pinoRotulo: "" },
|
||||
{ id: "wifi", nome: "Wi-Fi", termos: ["wifi", "wi-fi", "inalambrico", "wireless", "sin cable", "802.11", "wifi6", "wifi 6", "wi-fi 6"], pinoCats: ["Antena"], pinoRotulo: "de antena y radio" },
|
||||
{ id: "bluetooth", nome: "Bluetooth", termos: ["bluetooth", "ble", "bt", "bluetooth le", "mesh"], pinoCats: ["Antena"], pinoRotulo: "de antena y radio" },
|
||||
{ id: "zigbee", nome: "Zigbee/Thread", termos: ["zigbee", "thread", "802.15.4", "ieee 802.15.4"], pinoRotulo: "" },
|
||||
{ id: "matter", nome: "Matter", termos: ["matter", "hogar inteligente", "smart home", "casa inteligente"], pinoRotulo: "" },
|
||||
{ id: "ethernet", nome: "Ethernet", termos: ["ethernet", "rmii", "cable de red", "lan"], pinoCats: ["Ethernet"], pinoRotulo: "de Ethernet" },
|
||||
{ id: "can", nome: "CAN / TWAI", termos: ["can", "twai", "can bus", "canbus", "can fd"], pinoRe: /twai|\bcan\b/, pinoRotulo: "de CAN/TWAI" },
|
||||
{ id: "usb", nome: "USB", termos: ["usb", "otg", "usb serial", "usb otg", "hid", "cdc"], pinoCats: ["USB"], pinoRotulo: "de USB" },
|
||||
{ id: "jtag", nome: "JTAG / Depuración", termos: ["jtag", "debug", "depuracion", "depurar", "openocd", "gdb"], pinoCats: ["JTAG"], pinoRotulo: "de JTAG" },
|
||||
{ id: "adc", nome: "ADC", termos: ["adc", "analogico", "entrada analogica", "convertidor analogico", "analogread", "saradc"], pinoCats: ["ADC"], pinoRotulo: "con ADC" },
|
||||
{ id: "dac", nome: "DAC", termos: ["dac", "salida analogica", "convertidor digital"], pinoCats: ["DAC"], pinoRotulo: "con DAC" },
|
||||
{ id: "touch", nome: "Táctil capacitivo", termos: ["touch", "capacitivo", "tactil", "toque", "touchpad", "sensor tactil"], pinoCats: ["Touch"], pinoRotulo: "de táctil capacitivo" },
|
||||
{ id: "uart", nome: "UART", termos: ["uart", "serial", "tx", "rx", "txd", "rxd", "puerto serie"], pinoCats: ["UART"], pinoRotulo: "de UART" },
|
||||
{ id: "spi", nome: "SPI", termos: ["spi", "mosi", "miso", "sclk", "bus spi"], pinoCats: ["SPI"], pinoRotulo: "de SPI" },
|
||||
{ id: "i2c", nome: "I2C", termos: ["i2c", "sda", "scl", "twi", "iic"], pinoCats: ["I2C"], pinoRotulo: "de I2C" },
|
||||
{ id: "i2s", nome: "I2S", termos: ["i2s", "audio", "sonido", "microfono", "pdm", "codec"], pinoRe: /i2s|\bpdm\b/, pinoRotulo: "de I2S / audio" },
|
||||
{ id: "pwm", nome: "PWM", termos: ["pwm", "ledc", "mcpwm", "servo", "dimmer"], pinoRe: /ledc|pwm/, pinoRotulo: "de PWM" },
|
||||
{ id: "sd", nome: "Tarjeta SD / SDIO", termos: ["sd", "sdio", "sd card", "sdcard", "tarjeta sd", "microsd", "sdmmc", "mmc"], pinoCats: ["SD"], pinoRe: /sdio|sdmmc|\bsd\b/, pinoRotulo: "de tarjeta SD/SDIO" },
|
||||
{ id: "camera", nome: "Cámara", termos: ["camera", "camara", "cam", "dvp", "csi", "mipi csi", "ov2640", "video"], pinoCats: ["CSI"], pinoRe: /\bcam\b|dvp|cam_/, pinoRotulo: "de cámara" },
|
||||
{ id: "lcd", nome: "Pantalla / LCD", termos: ["lcd", "display", "pantalla", "dsi", "mipi dsi", "oled", "tft", "lvgl", "rgb"], pinoCats: ["DSI"], pinoRe: /lcd/, pinoRotulo: "de pantalla/LCD" },
|
||||
{ id: "strapping", nome: "Boot / Strapping", termos: ["strapping", "boot", "bootstrap", "modo de boot", "modo de arranque", "download mode", "modo de grabacion", "arranque"], pinoCats: ["Strapping"], pinoRotulo: "de strapping (modo de arranque)" },
|
||||
{ id: "energia_pinos", nome: "Alimentación", termos: ["alimentacion", "vdd", "3v3", "3.3v", "tension", "regulador", "ldo", "fuente"], pinoCats: ["Power"], pinoRotulo: "de alimentación" },
|
||||
{ id: "clock", nome: "Reloj / Cristal", termos: ["clock", "reloj", "xtal", "cristal", "oscilador", "32khz", "40mhz"], pinoCats: ["Clock"], pinoRotulo: "de reloj/cristal" },
|
||||
{ id: "gpio", nome: "GPIO", termos: ["gpio", "entradas y salidas", "pines"], pinoCats: ["GPIO"], pinoRotulo: "de GPIO" },
|
||||
{ id: "baixo_consumo", nome: "Bajo consumo / ULP", termos: ["ulp", "lp core", "lp cpu", "coprocesador", "lp gpio", "low power", "rtc gpio", "bajo consumo"], pinoCats: ["Low Power"], pinoRotulo: "de bajo consumo (LP/RTC)" },
|
||||
{ id: "antena", nome: "Antena / RF", termos: ["antena", "rf", "radiofrecuencia", "ipex"], pinoCats: ["Antena"], pinoRotulo: "de antena/RF" },
|
||||
{ id: "seguranca", nome: "Seguridad", termos: ["seguridad", "seguranca", "secure boot", "criptografia", "cifrado", "aes", "sha", "rsa", "hmac", "ecdsa", "efuse", "tee", "trng", "rng", "hsm", "proteccion"], pinoRotulo: "" },
|
||||
{ id: "consumo", nome: "Consumo de energía", termos: ["consumo", "bateria", "deep sleep", "light sleep", "sleep", "modem sleep", "corriente", "miliamperios", "autonomia", "ahorro de energia", "modo bajo consumo"], pinoRotulo: "" },
|
||||
{ id: "temperatura", nome: "Temperatura", termos: ["temperatura", "calor", "grados", "rango de temperatura", "industrial"], pinoRotulo: "" },
|
||||
{ id: "ia", nome: "IA / Aceleración", termos: ["ia", "ai", "machine learning", "ml", "tinyml", "vectorial", "inteligencia artificial", "red neuronal", "esp-nn", "esp-dl"], pinoRotulo: "" },
|
||||
{ id: "processador", nome: "Procesador", termos: ["procesador", "cpu", "nucleo", "nucleos", "core", "dual core", "single core", "arquitectura", "xtensa", "risc-v", "riscv"], pinoRotulo: "" },
|
||||
{ id: "frequencia", nome: "Frecuencia", termos: ["frecuencia", "mhz", "velocidad", "rendimiento", "performance"], pinoRotulo: "" },
|
||||
{ id: "ferramentas", nome: "Herramientas / SDK", termos: ["esp-idf", "idf", "arduino", "sdk", "toolchain", "cadena de herramientas", "version de idf"], pinoRotulo: "" },
|
||||
{ id: "encapsulamento", nome: "Módulos y encapsulado", termos: ["modulo", "modulos", "encapsulado", "package", "qfn", "wroom", "wrover", "mini-1"], pinoRotulo: "" },
|
||||
];
|
||||
|
||||
/**
|
||||
* Campos de datos que responden a cada tema en español.
|
||||
*/
|
||||
export const SPEC_CAMPOS = [
|
||||
{ campo: "arquitetura", label: "Arquitectura", secao: "processador", topicos: ["processador"] },
|
||||
{ campo: "nucleos", label: "Núcleos", secao: "processador", topicos: ["processador"] },
|
||||
{ campo: "frequencia", label: "Frecuencia", secao: "processador", topicos: ["frequencia", "processador"] },
|
||||
{ campo: "coprocessador_ulp", label: "Coprocesador ULP", secao: "processador", topicos: ["baixo_consumo"] },
|
||||
{ campo: "aceleradores_ia", label: "Aceleradores de IA", secao: "processador", topicos: ["ia"] },
|
||||
|
||||
{ campo: "wifi", label: "Wi-Fi", secao: "conectividade", topicos: ["wifi"] },
|
||||
{ campo: "bluetooth", label: "Bluetooth", secao: "conectividade", topicos: ["bluetooth"] },
|
||||
{ campo: "zigbee_thread", label: "Zigbee/Thread", secao: "conectividade", topicos: ["zigbee"] },
|
||||
{ campo: "matter", label: "Matter", secao: "conectividade", topicos: ["matter"] },
|
||||
{ campo: "ethernet", label: "Ethernet", secao: "conectividade", topicos: ["ethernet"] },
|
||||
{ campo: "ethernet_mac", label: "Ethernet MAC", secao: "conectividade", topicos: ["ethernet"] },
|
||||
{ campo: "can", label: "CAN", secao: "conectividade", topicos: ["can"] },
|
||||
|
||||
{ campo: "memoria_sram", label: "SRAM", secao: "memoria", topicos: ["memoria"] },
|
||||
{ campo: "memoria_sram_rtc", label: "SRAM RTC", secao: "memoria", topicos: ["memoria", "baixo_consumo"] },
|
||||
{ campo: "memoria_rom", label: "ROM", secao: "memoria", topicos: ["memoria"] },
|
||||
{ campo: "flash_externa", label: "Flash externa", secao: "memoria", topicos: ["flash", "memoria"] },
|
||||
{ campo: "psram_externa", label: "PSRAM externa", secao: "memoria", topicos: ["psram", "memoria"] },
|
||||
|
||||
{ campo: "gpio", label: "GPIO", secao: "perifericos", topicos: ["gpio"] },
|
||||
{ campo: "adc", label: "ADC", secao: "perifericos", topicos: ["adc"] },
|
||||
{ campo: "dac", label: "DAC", secao: "perifericos", topicos: ["dac"] },
|
||||
{ campo: "touch", label: "Táctil capacitivo", secao: "perifericos", topicos: ["touch"] },
|
||||
{ campo: "uart", label: "UART", secao: "perifericos", topicos: ["uart"] },
|
||||
{ campo: "spi", label: "SPI", secao: "perifericos", topicos: ["spi", "flash"] },
|
||||
{ campo: "i2c", label: "I2C", secao: "perifericos", topicos: ["i2c"] },
|
||||
{ campo: "i2s", label: "I2S", secao: "perifericos", topicos: ["i2s"] },
|
||||
{ campo: "pwm", label: "PWM", secao: "perifericos", topicos: ["pwm"] },
|
||||
{ campo: "usb", label: "USB", secao: "perifericos", topicos: ["usb"] },
|
||||
{ campo: "lcd", label: "LCD", secao: "interfaces", topicos: ["lcd"] },
|
||||
{ campo: "camera", label: "Cámara", secao: "interfaces", topicos: ["camera"] },
|
||||
{ campo: "mipi_csi", label: "MIPI CSI", secao: "interfaces", topicos: ["camera"] },
|
||||
{ campo: "mipi_dsi", label: "MIPI DSI", secao: "interfaces", topicos: ["lcd"] },
|
||||
{ campo: "sdio", label: "SDIO", secao: "interfaces", topicos: ["sd"] },
|
||||
{ campo: "sensor_temperatura", label: "Sensor de temperatura", secao: "interfaces", topicos: ["temperatura"] },
|
||||
|
||||
{ campo: "seguranca.aes", label: "AES", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.sha", label: "SHA", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.rsa", label: "RSA", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.ecc", label: "ECC", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.ecdsa", label: "ECDSA", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.hmac", label: "HMAC", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.assinatura_digital", label: "Firma digital", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.rng", label: "Generador de números aleatorios", secao: "seguranca", topicos: ["seguranca"] },
|
||||
{ campo: "seguranca.criptografia_flash", label: "Cifrado de flash", secao: "seguranca", topicos: ["seguranca", "flash"] },
|
||||
{ campo: "seguranca.secure_boot", label: "Secure Boot", secao: "seguranca", topicos: ["seguranca", "strapping"] },
|
||||
|
||||
{ campo: "temperatura_operacao", label: "Temperatura de operación", secao: "temperatura", topicos: ["temperatura"] },
|
||||
{ campo: "temperatura_armazenamento", label: "Temperatura de almacenamiento", secao: "temperatura", topicos: ["temperatura"] },
|
||||
|
||||
{ campo: "esp_idf_minimo", label: "ESP-IDF mínimo", secao: "ferramentas", topicos: ["ferramentas"] },
|
||||
{ campo: "arduino_core", label: "Arduino Core", secao: "ferramentas", topicos: ["ferramentas"] },
|
||||
{ campo: "depuracao", label: "Depuración", secao: "ferramentas", topicos: ["jtag", "ferramentas"] },
|
||||
{ campo: "encapsulamento", label: "Encapsulado", secao: "ferramentas", topicos: ["encapsulamento"] },
|
||||
{ campo: "modulos", label: "Módulos", secao: "ferramentas", topicos: ["encapsulamento"] },
|
||||
];
|
||||
|
||||
const ROTULOS_ENERGIA = {
|
||||
active: "Activo",
|
||||
modem_sleep: "Modem Sleep",
|
||||
light_sleep: "Light Sleep",
|
||||
deep_sleep: "Deep Sleep",
|
||||
hibernation: "Hibernación",
|
||||
};
|
||||
|
||||
const pegar = (obj, caminho) => caminho.split(".").reduce((o, k) => (o == null ? o : o[k]), obj);
|
||||
|
||||
/**
|
||||
* Monta la lista plana de especificaciones para cada serie en español.
|
||||
*/
|
||||
export function montarConhecimento(series, conexoes) {
|
||||
const saida = {};
|
||||
for (const [chave, s] of Object.entries(series)) {
|
||||
const specs = [];
|
||||
for (const c of SPEC_CAMPOS) {
|
||||
const valor = pegar(s, c.campo);
|
||||
if (valor == null || valor === "") continue;
|
||||
specs.push({ label: c.label, valor: String(valor), secao: c.secao, topicos: c.topicos });
|
||||
}
|
||||
for (const [modo, valor] of Object.entries(s.consumo_energia ?? {})) {
|
||||
const base = modo.replace(/_cpu.*|_wifi.*/, "");
|
||||
const label = ROTULOS_ENERGIA[modo] ?? ROTULOS_ENERGIA[base] ?? modo.replace(/_/g, " ");
|
||||
specs.push({ label: `Consumo: ${label}`, valor: String(valor), secao: "energia", topicos: ["consumo"] });
|
||||
}
|
||||
saida[chave] = {
|
||||
nome: s.nome_completo ?? chave,
|
||||
specs,
|
||||
pinos: (conexoes[chave] ?? []).map((p) => ({
|
||||
n: String(p.numero),
|
||||
nome: p.nome,
|
||||
f: p.funcoes ?? [],
|
||||
c: p.categorias ?? [],
|
||||
a: p.avisos ?? [],
|
||||
})),
|
||||
};
|
||||
}
|
||||
return saida;
|
||||
}
|
||||
+56
-12
@@ -12,6 +12,13 @@ import { errosCatalogo as errosEn } from "@/lib/data/en/diagnostico";
|
||||
import { COMPONENTES_REGISTRY as componentesEn } from "@/lib/data/en/componentes";
|
||||
import { montarConhecimento as montarConhecimentoEn } from "@/lib/data/en/topicos";
|
||||
|
||||
import seriesDataEs from "@/data/es/series.json";
|
||||
import frameworksDataEs from "@/data/es/frameworks.json";
|
||||
import { categoriasGlossario as glossarioEs } from "@/lib/data/es/glossario";
|
||||
import { errosCatalogo as errosEs } from "@/lib/data/es/diagnostico";
|
||||
import { COMPONENTES_REGISTRY as componentesEs } from "@/lib/data/es/componentes";
|
||||
import { montarConhecimento as montarConhecimentoEs } from "@/lib/data/es/topicos";
|
||||
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
@@ -50,24 +57,57 @@ const PAGINAS_EN = [
|
||||
{ titulo: "About the Project", descricao: "History, author and open source", href: "/en/about", keywords: "author contact" },
|
||||
];
|
||||
|
||||
const PAGINAS_ES = [
|
||||
{ titulo: "Inicio", descricao: "Página de inicio de ESPDocs", href: "/es", keywords: "home inicio" },
|
||||
{ titulo: "Todas las Series", descricao: "Distribución de pines, especificaciones y restricciones de cada serie ESP32", href: "/es/series", keywords: "chips distribución de pines especificaciones" },
|
||||
{ titulo: "Comparador de Series", descricao: "Compare hasta 4 modelos lado a lado", href: "/es/comparacion", keywords: "comparar comparación versus" },
|
||||
{ titulo: "Catálogo de Placas", descricao: "Placas de desarrollo, conectores y compras", href: "/es/catalogo", keywords: "placas dev boards comprar devkit" },
|
||||
{ titulo: "Selector Inteligente", descricao: "Descubra el chip ideal para su proyecto", href: "/es/selector", keywords: "quiz elegir recomendar selector" },
|
||||
{ titulo: "Diagnóstico de Errores", descricao: "Solucione brownout, bucles de arranque, WDT y fallos", href: "/es/diagnostico", keywords: "error problema fallo crash" },
|
||||
{ titulo: "Frameworks y SDKs", descricao: "ESP-IDF, Arduino, Rust, RainMaker y más", href: "/es/frameworks", keywords: "sdk" },
|
||||
{ titulo: "Component Registry", descricao: "Catálogo de controladores y generador de idf_component.yml", href: "/es/componentes", keywords: "bibliotecas controladores drivers yml" },
|
||||
{ titulo: "Glosario Técnico", descricao: "Conceptos esenciales de hardware y software", href: "/es/glosario", keywords: "términos diccionario significado" },
|
||||
{ titulo: "Acerca del Proyecto", descricao: "Historia, autor y código abierto", href: "/es/acerca", keywords: "autor contacto código abierto" },
|
||||
];
|
||||
|
||||
const cortar = (texto = "", max = 140) => (texto.length > max ? `${texto.slice(0, max - 1).trimEnd()}…` : texto);
|
||||
|
||||
export function construirIndiceBusca(locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const paginas = isEn ? PAGINAS_EN : PAGINAS_PT;
|
||||
const seriesData = isEn ? seriesDataEn : seriesDataPt;
|
||||
const frameworksData = isEn ? frameworksDataEn : frameworksDataPt;
|
||||
const categoriasGlossario = isEn ? glossarioEn : glossarioPt;
|
||||
const errosCatalogo = isEn ? errosEn : errosPt;
|
||||
const componentes = isEn ? componentesEn : componentesPt;
|
||||
const montarConhecimento = isEn ? montarConhecimentoEn : montarConhecimentoPt;
|
||||
const isEs = locale === "es";
|
||||
|
||||
const prefixo = isEn ? "/en" : "";
|
||||
let paginas = PAGINAS_PT;
|
||||
let seriesData = seriesDataPt;
|
||||
let frameworksData = frameworksDataPt;
|
||||
let categoriasGlossario = glossarioPt;
|
||||
let errosCatalogo = errosPt;
|
||||
let componentes = componentesPt;
|
||||
let montarConhecimento = montarConhecimentoPt;
|
||||
|
||||
if (isEn) {
|
||||
paginas = PAGINAS_EN;
|
||||
seriesData = seriesDataEn;
|
||||
frameworksData = frameworksDataEn;
|
||||
categoriasGlossario = glossarioEn;
|
||||
errosCatalogo = errosEn;
|
||||
componentes = componentesEn;
|
||||
montarConhecimento = montarConhecimentoEn;
|
||||
} else if (isEs) {
|
||||
paginas = PAGINAS_ES;
|
||||
seriesData = seriesDataEs;
|
||||
frameworksData = frameworksDataEs;
|
||||
categoriasGlossario = glossarioEs;
|
||||
errosCatalogo = errosEs;
|
||||
componentes = componentesEs;
|
||||
montarConhecimento = montarConhecimentoEs;
|
||||
}
|
||||
|
||||
const prefixo = isEn ? "/en" : isEs ? "/es" : "";
|
||||
const slugSeries = `${prefixo}/series`;
|
||||
const slugFrameworks = `${prefixo}/frameworks`;
|
||||
const slugGlossario = isEn ? "/en/glossary" : "/glossario";
|
||||
const slugDiagnostico = isEn ? "/en/diagnostics" : "/diagnostico";
|
||||
const slugComponentes = isEn ? "/en/components" : "/componentes";
|
||||
const slugGlossario = isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const slugDiagnostico = isEn ? "/en/diagnostics" : isEs ? "/es/diagnostico" : "/diagnostico";
|
||||
const slugComponentes = isEn ? "/en/components" : isEs ? "/es/componentes" : "/componentes";
|
||||
|
||||
const itens = [];
|
||||
|
||||
@@ -130,7 +170,11 @@ export function construirIndiceBusca(locale = "pt") {
|
||||
|
||||
const conexoes = {};
|
||||
for (const chave of Object.keys(seriesData)) {
|
||||
const pastaConexoes = isEn ? path.join(process.cwd(), "data", "en", "conexoes") : path.join(process.cwd(), "public", "conexoes");
|
||||
const pastaConexoes = isEn
|
||||
? path.join(process.cwd(), "data", "en", "conexoes")
|
||||
: isEs
|
||||
? path.join(process.cwd(), "data", "es", "conexoes")
|
||||
: path.join(process.cwd(), "public", "conexoes");
|
||||
const arquivo = path.join(pastaConexoes, `${chave}.json`);
|
||||
if (existsSync(arquivo)) {
|
||||
conexoes[chave] = JSON.parse(readFileSync(arquivo, "utf8"));
|
||||
|
||||
+51
-29
@@ -40,7 +40,7 @@ export function paginaMeta({ titulo, descricao, caminho, keywords = [], tipo = "
|
||||
for (const loc of ENABLED_LOCALES) {
|
||||
if (basePath === "/livro" && loc !== "pt") continue;
|
||||
const locHref = getLocalizedHref(`/pt${basePath}`, loc);
|
||||
const langKey = loc === "pt" ? "pt-BR" : loc;
|
||||
const langKey = loc === "pt" ? "pt-BR" : loc === "es" ? "es-419" : loc;
|
||||
languages[langKey] = `${SITE.url}${locHref}`;
|
||||
}
|
||||
if (ENABLED_LOCALES.includes("en") && basePath !== "/livro") {
|
||||
@@ -94,6 +94,9 @@ export function paginaMeta({ titulo, descricao, caminho, keywords = [], tipo = "
|
||||
export const jsonLd = {
|
||||
siteESociedade(locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const orgAnchor = isEn ? "organization" : isEs ? "organizacion" : "organizacao";
|
||||
const authorAnchor = isEn ? "author" : "autor";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
@@ -102,15 +105,17 @@ export const jsonLd = {
|
||||
"@id": `${SITE.url}/#site`,
|
||||
url: `${SITE.url}/${locale}`,
|
||||
name: SITE.nome,
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
description: isEn
|
||||
? "ESP32 ecosystem documentation: specifications, pinouts, comparison, and series selection."
|
||||
: isEs
|
||||
? "Documentación del ecosistema ESP32: especificaciones, patillaje, comparación y selección de series."
|
||||
: "Documentação do ecossistema ESP32 em português brasileiro: especificações, pinagem, comparação e seleção de séries.",
|
||||
publisher: { "@id": `${SITE.url}/#${isEn ? "organization" : "organizacao"}` },
|
||||
publisher: { "@id": `${SITE.url}/#${orgAnchor}` },
|
||||
},
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": `${SITE.url}/#${isEn ? "organization" : "organizacao"}`,
|
||||
"@id": `${SITE.url}/#${orgAnchor}`,
|
||||
name: "Ciência Embarcada",
|
||||
url: SITE.blog,
|
||||
logo: {
|
||||
@@ -124,7 +129,7 @@ export const jsonLd = {
|
||||
},
|
||||
{
|
||||
"@type": "Person",
|
||||
"@id": `${SITE.url}/#${isEn ? "author" : "autor"}`,
|
||||
"@id": `${SITE.url}/#${authorAnchor}`,
|
||||
name: SITE.autor,
|
||||
url: SITE.autorUrl,
|
||||
email: SITE.autorEmail,
|
||||
@@ -151,45 +156,51 @@ export const jsonLd = {
|
||||
/** Documentação e ficha técnica da série como TechArticle para o Google. */
|
||||
serie(chave, serie, locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const prop = (nome, valor) =>
|
||||
valor ? { "@type": "PropertyValue", name: nome, value: String(valor) } : null;
|
||||
|
||||
const propriedades = [
|
||||
prop(isEn ? "Manufacturer" : "Fabricante", "Espressif Systems"),
|
||||
prop(isEn ? "Architecture" : "Arquitetura", serie.arquitetura),
|
||||
prop(isEn ? "Cores" : "Núcleos", serie.nucleos),
|
||||
prop(isEn ? "Max frequency" : "Frequência máxima", serie.frequencia),
|
||||
prop(isEn ? "Manufacturer" : isEs ? "Fabricante" : "Fabricante", "Espressif Systems"),
|
||||
prop(isEn ? "Architecture" : isEs ? "Arquitectura" : "Arquitetura", serie.arquitetura),
|
||||
prop(isEn ? "Cores" : isEs ? "Núcleos" : "Núcleos", serie.nucleos),
|
||||
prop(isEn ? "Max frequency" : isEs ? "Frecuencia máxima" : "Frequência máxima", serie.frequencia),
|
||||
prop("SRAM", serie.memoria_sram),
|
||||
prop("RTC SRAM", serie.memoria_sram_rtc),
|
||||
prop(isEn ? "Supported Flash" : "Flash suportada", serie.flash_suportada),
|
||||
prop(isEn ? "Supported PSRAM" : "PSRAM suportada", serie.psram_suportada),
|
||||
prop(isEn ? "Supported Flash" : isEs ? "Flash soportada" : "Flash suportada", serie.flash_suportada),
|
||||
prop(isEn ? "Supported PSRAM" : isEs ? "PSRAM soportada" : "PSRAM suportada", serie.psram_suportada),
|
||||
prop("GPIO", serie.gpio),
|
||||
prop("Wi-Fi", serie.wifi),
|
||||
prop("Bluetooth", serie.bluetooth),
|
||||
prop("Zigbee / Thread / 802.15.4", serie.zigbee_thread),
|
||||
prop(isEn ? "Package" : "Encapsulamento", serie.encapsulamento),
|
||||
prop(isEn ? "Minimum ESP-IDF" : "ESP-IDF mínimo", serie.esp_idf_minimo),
|
||||
prop(isEn ? "Package" : isEs ? "Encapsulado" : "Encapsulamento", serie.encapsulamento),
|
||||
prop(isEn ? "Minimum ESP-IDF" : isEs ? "ESP-IDF mínimo" : "ESP-IDF mínimo", serie.esp_idf_minimo),
|
||||
].filter(Boolean);
|
||||
|
||||
const imagem = serie.placa
|
||||
? `${SITE.url}${serie.placa}`
|
||||
: `${SITE.url}/opengraph-image.png`;
|
||||
|
||||
const basePath = isEn ? `/en/series/${chave}` : `/series/${chave}`;
|
||||
const basePath = isEn ? `/en/series/${chave}` : isEs ? `/es/series/${chave}` : `/series/${chave}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : "artigo";
|
||||
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
"@id": `${SITE.url}${basePath}#${isEn ? "article" : "artigo"}`,
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
headline: isEn
|
||||
? `${serie.nome_completo || chave}: specifications and pinout`
|
||||
: isEs
|
||||
? `${serie.nome_completo || chave}: especificaciones y patillaje`
|
||||
: `${serie.nome_completo || chave}: especificações e pinagem`,
|
||||
name: isEn
|
||||
? `${serie.nome_completo || chave} - Technical Documentation and Specifications`
|
||||
: isEs
|
||||
? `${serie.nome_completo || chave} - Documentación técnica y especificaciones`
|
||||
: `${serie.nome_completo || chave} - Documentação Técnica e Especificações`,
|
||||
description: serie.descricao,
|
||||
image: [imagem],
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
datePublished: "2026-08-25T00:00:00.000Z",
|
||||
dateModified: new Date().toISOString(),
|
||||
mainEntityOfPage: `${SITE.url}${basePath}`,
|
||||
@@ -222,20 +233,24 @@ export const jsonLd = {
|
||||
/** Documentação técnica de framework. */
|
||||
framework(chave, framework, locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const basePath = isEn ? `/en/frameworks/${encodeURIComponent(chave)}` : `/frameworks/${encodeURIComponent(chave)}`;
|
||||
const isEs = locale === "es";
|
||||
const basePath = isEn ? `/en/frameworks/${encodeURIComponent(chave)}` : isEs ? `/es/frameworks/${encodeURIComponent(chave)}` : `/frameworks/${encodeURIComponent(chave)}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : "artigo";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
"@id": `${SITE.url}${basePath}#${isEn ? "article" : "artigo"}`,
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
headline: isEn
|
||||
? `${framework.nome} for ESP32: Guide and Documentation`
|
||||
: isEs
|
||||
? `${framework.nome} para ESP32: Guía y documentación`
|
||||
: `${framework.nome} para ESP32: Guia e Documentação`,
|
||||
name: isEn
|
||||
? `${framework.nome_completo || framework.nome} for ESP32`
|
||||
: `${framework.nome_completo || framework.nome} para ESP32`,
|
||||
description: framework.descricao,
|
||||
image: [`${SITE.url}/opengraph-image.png`],
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
datePublished: "2026-08-25T00:00:00.000Z",
|
||||
dateModified: new Date().toISOString(),
|
||||
mainEntityOfPage: `${SITE.url}${basePath}`,
|
||||
@@ -270,19 +285,21 @@ export const jsonLd = {
|
||||
/** Glossário: marca cada verbete como termo definido. */
|
||||
glossario(categorias, locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const basePath = isEn ? "/en/glossary" : "/glossario";
|
||||
const isEs = locale === "es";
|
||||
const basePath = isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const anchor = isEn ? "glossary" : isEs ? "glosario" : "glossario";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "DefinedTermSet",
|
||||
"@id": `${SITE.url}${basePath}#${isEn ? "glossary" : "glossario"}`,
|
||||
name: isEn ? "ESP32 Technical Glossary" : "Glossário Técnico do ESP32",
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
name: isEn ? "ESP32 Technical Glossary" : isEs ? "Glosario técnico de ESP32" : "Glossário Técnico do ESP32",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
hasDefinedTerm: categorias.flatMap((cat) =>
|
||||
cat.termos.map((t) => ({
|
||||
"@type": "DefinedTerm",
|
||||
name: t.termo,
|
||||
description: t.definicao,
|
||||
inDefinedTermSet: `${SITE.url}${basePath}#${isEn ? "glossary" : "glossario"}`,
|
||||
inDefinedTermSet: `${SITE.url}${basePath}#${anchor}`,
|
||||
}))
|
||||
),
|
||||
};
|
||||
@@ -304,6 +321,7 @@ export const jsonLd = {
|
||||
/** Aplicação web / ferramenta interativa (Seletor, Comparador, Catálogo). */
|
||||
aplicacaoWeb({ nome, descricao, caminho, locale = "pt" }) {
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
@@ -314,7 +332,7 @@ export const jsonLd = {
|
||||
applicationCategory: "DeveloperApplication",
|
||||
operatingSystem: "All",
|
||||
browserRequirements: "Requires JavaScript",
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
author: {
|
||||
"@type": "Person",
|
||||
name: SITE.autor,
|
||||
@@ -396,17 +414,21 @@ export const jsonLd = {
|
||||
/** Página Sobre com metadados E-E-A-T de autoria e reputação. */
|
||||
paginaSobre(locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const basePath = isEn ? "/en/about" : "/sobre";
|
||||
const isEs = locale === "es";
|
||||
const basePath = isEn ? "/en/about" : isEs ? "/es/acerca" : "/sobre";
|
||||
const anchor = isEn ? "about" : isEs ? "acerca" : "sobre";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "AboutPage",
|
||||
"@id": `${SITE.url}${basePath}#${isEn ? "about" : "sobre"}`,
|
||||
name: isEn ? "About ESPDocs" : "Sobre o ESPDocs",
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
name: isEn ? "About ESPDocs" : isEs ? "Acerca de ESPDocs" : "Sobre o ESPDocs",
|
||||
description: isEn
|
||||
? "ESPDocs is an independent platform organizing technical documentation of the ESP32 ecosystem."
|
||||
: isEs
|
||||
? "ESPDocs es una plataforma independiente que reúne la documentación técnica del ecosistema ESP32."
|
||||
: "O ESPDocs é uma plataforma independente que reúne a documentação do ecossistema ESP32 em português brasileiro.",
|
||||
url: `${SITE.url}${basePath}`,
|
||||
inLanguage: isEn ? "en" : "pt-BR",
|
||||
inLanguage: isEn ? "en" : isEs ? "es-419" : "pt-BR",
|
||||
mainEntity: {
|
||||
"@type": "Person",
|
||||
name: SITE.autor,
|
||||
|
||||
Reference in new issue
Block a user